├── .gitee ├── ISSUE_TEMPLATE.zh-CN.md └── PULL_REQUEST_TEMPLATE.zh-CN.md ├── .gitignore ├── LICENSE ├── README.md ├── docker ├── app.Dockerfile ├── base.Dockerfile ├── docker-compose.kafka.yml ├── docker-compose.monolith.yml ├── docker-compose.postgres.yml ├── docker-compose.redis-cluster.yml ├── docker-compose.redis-sentinel.yml ├── docker-compose.redis-standalone.yml ├── kafka.env ├── protocol.Dockerfile ├── schema │ └── schema-postgres.sql └── start.sh ├── jcpp-app-bootstrap ├── pom.xml └── src │ ├── layers.xml │ ├── main │ ├── java │ │ └── sanbing │ │ │ └── jcpp │ │ │ └── JCPPServerApplication.java │ └── resources │ │ ├── app-service.yml │ │ ├── banner.txt │ │ └── log4j2.xml │ └── test │ ├── java │ └── sanbing │ │ └── jcpp │ │ ├── AbstractTestBase.java │ │ ├── app │ │ └── dal │ │ │ └── mapper │ │ │ ├── GunMapperIT.java │ │ │ ├── OrderMapperIT.java │ │ │ ├── PileMapperIT.java │ │ │ ├── StationMapperIT.java │ │ │ └── UserMapperIT.java │ │ └── infrastructure │ │ └── cache │ │ └── RedisCacheConfigurationIT.java │ └── resources │ └── app-service-test.properties ├── jcpp-app ├── pom.xml └── src │ └── main │ └── java │ └── sanbing │ └── jcpp │ └── app │ ├── adapter │ └── TestController.java │ ├── dal │ ├── config │ │ ├── DalConfig.java │ │ └── ibatis │ │ │ ├── enums │ │ │ ├── GunOptStatusEnum.java │ │ │ ├── GunRunStatusEnum.java │ │ │ ├── OrderStatusEnum.java │ │ │ ├── OrderTypeEnum.java │ │ │ ├── OwnerTypeEnum.java │ │ │ ├── PileStatusEnum.java │ │ │ ├── PileTypeEnum.java │ │ │ ├── StationStatusEnum.java │ │ │ └── UserStatusEnum.java │ │ │ └── typehandlers │ │ │ ├── JsonbTypeHandler.java │ │ │ └── UUIDTypeHandler.java │ ├── entity │ │ ├── Gun.java │ │ ├── Order.java │ │ ├── Pile.java │ │ ├── Station.java │ │ └── User.java │ └── mapper │ │ ├── GunMapper.java │ │ ├── OrderMapper.java │ │ ├── PileMapper.java │ │ ├── StationMapper.java │ │ └── UserMapper.java │ ├── data │ └── PileSession.java │ ├── repository │ ├── AbstractCachedEntityRepository.java │ ├── AbstractEntityRepository.java │ ├── CachedVersionedEntityRepository.java │ ├── PileRepository.java │ └── PileRepositoryImpl.java │ └── service │ ├── DownlinkCallService.java │ ├── PileProtocolService.java │ ├── cache │ ├── pile │ │ ├── PileCacheEvictEvent.java │ │ ├── PileCacheKey.java │ │ ├── PileCaffeineCache.java │ │ └── PileRedisCache.java │ └── session │ │ ├── PileSessionCacheKey.java │ │ ├── PileSessionCaffeineCache.java │ │ └── PileSessionRedisCache.java │ ├── config │ └── DownlinkRestTemplateConfiguration.java │ ├── grpc │ └── DownlinkGrpcClient.java │ ├── impl │ ├── DefaultPileProtocolService.java │ ├── GrpcDownlinkCallService.java │ └── RestDownlinkCallService.java │ └── queue │ ├── AbstractConsumerService.java │ ├── AppConsumerStats.java │ ├── AppQueueConsumerManager.java │ ├── QueueConsumerManagerTask.java │ ├── QueueConsumerTask.java │ ├── QueueEvent.java │ └── consumer │ └── ProtocolUplinkConsumerService.java ├── jcpp-infrastructure-cache ├── pom.xml └── src │ └── main │ └── java │ └── sanbing │ └── jcpp │ └── infrastructure │ └── cache │ ├── CacheConstants.java │ ├── CacheSpecs.java │ ├── CacheSpecsMap.java │ ├── CacheTransaction.java │ ├── CacheValueWrapper.java │ ├── CaffeineCacheTransaction.java │ ├── CaffeineTransactionalCache.java │ ├── HasVersion.java │ ├── JCPPCaffeineCacheConfiguration.java │ ├── JCPPJCPPRedisClusterConfiguration.java │ ├── JCPPJCPPRedisSentinelConfiguration.java │ ├── JCPPJCPPRedisStandaloneConfiguration.java │ ├── JCPPRedisCacheConfiguration.java │ ├── JCPPRedisSerializer.java │ ├── RedisCacheTransaction.java │ ├── RedisTransactionalCache.java │ ├── SimpleCacheValueWrapper.java │ ├── TransactionalCache.java │ ├── VersionedCache.java │ ├── VersionedCacheKey.java │ ├── VersionedCaffeineCache.java │ └── VersionedRedisCache.java ├── jcpp-infrastructure-proto ├── pom.xml └── src │ └── main │ ├── java │ └── sanbing │ │ └── jcpp │ │ └── infrastructure │ │ └── proto │ │ ├── ProtoConverter.java │ │ └── model │ │ └── PricingModel.java │ └── proto │ ├── cluster.proto │ └── protocol.proto ├── jcpp-infrastructure-queue ├── pom.xml └── src │ └── main │ └── java │ └── sanbing │ └── jcpp │ └── infrastructure │ └── queue │ ├── AbstractQueueConsumerTemplate.java │ ├── Callback.java │ ├── DefaultQueueMsg.java │ ├── DefaultQueueMsgHeaders.java │ ├── KafkaQueueMsg.java │ ├── PackCallback.java │ ├── PackProcessingContext.java │ ├── ProtoQueueMsg.java │ ├── QueueAdmin.java │ ├── QueueCallback.java │ ├── QueueConsumer.java │ ├── QueueMsg.java │ ├── QueueMsgHeaders.java │ ├── QueueMsgMetadata.java │ ├── QueueProducer.java │ ├── common │ ├── QueueConfig.java │ ├── QueueConstants.java │ └── TopicPartitionInfo.java │ ├── discovery │ ├── DefaultServiceInfoProvider.java │ ├── DiscoveryProvider.java │ ├── DummyDiscoveryProvider.java │ ├── HashPartitionProvider.java │ ├── PartitionProvider.java │ ├── QueueKey.java │ ├── ServiceInfoProvider.java │ ├── ServiceType.java │ ├── ZkDiscoveryProvider.java │ └── event │ │ ├── JCPPApplicationEvent.java │ │ ├── JCPPApplicationEventListener.java │ │ ├── OtherServiceShutdownEvent.java │ │ └── PartitionChangeEvent.java │ ├── kafka │ ├── KafkaAdmin.java │ ├── KafkaConsumerStatisticConfig.java │ ├── KafkaConsumerStatsService.java │ ├── KafkaConsumerTemplate.java │ ├── KafkaDecoder.java │ ├── KafkaProducerTemplate.java │ ├── KafkaQueueMsgMetadata.java │ ├── KafkaSettings.java │ └── KafkaTopicConfigs.java │ ├── memory │ ├── DefaultInMemoryStorage.java │ ├── InMemoryQueueConsumer.java │ ├── InMemoryQueueProducer.java │ └── InMemoryStorage.java │ ├── processing │ └── IdMsgPair.java │ ├── provider │ ├── AppQueueFactory.java │ ├── InMemoryAppQueueFactory.java │ └── KafkaAppQueueFactory.java │ └── settings │ └── QueueAppSettings.java ├── jcpp-infrastructure-stats ├── pom.xml └── src │ └── main │ └── java │ └── sanbing │ └── jcpp │ └── infrastructure │ └── stats │ ├── DefaultCounter.java │ ├── DefaultMessagesStats.java │ ├── DefaultStatsFactory.java │ ├── MessagesStats.java │ ├── StatsCounter.java │ ├── StatsFactory.java │ └── StatsTimer.java ├── jcpp-infrastructure-util ├── pom.xml └── src │ ├── main │ └── java │ │ └── sanbing │ │ └── jcpp │ │ └── infrastructure │ │ └── util │ │ ├── JCPPHashUtil.java │ │ ├── JCPPPair.java │ │ ├── SystemUtil.java │ │ ├── annotation │ │ ├── AfterStartUp.java │ │ ├── AppComponent.java │ │ └── ProtocolComponent.java │ │ ├── async │ │ ├── JCPPAsynchron.java │ │ ├── JCPPExecutors.java │ │ ├── JCPPForkJoinWorkerThreadFactory.java │ │ ├── JCPPThreadFactory.java │ │ └── JCPPVirtualThreadFactory.java │ │ ├── codec │ │ ├── BCDUtil.java │ │ ├── ByteUtil.java │ │ └── CP56Time2aUtil.java │ │ ├── config │ │ ├── ConstraintValidator.java │ │ ├── ScheduledTaskConfig.java │ │ ├── ShardingThreadPool.java │ │ └── ThreadPoolConfiguration.java │ │ ├── exception │ │ ├── DataValidationException.java │ │ ├── DownlinkException.java │ │ └── IncorrectParameterException.java │ │ ├── jackson │ │ ├── BigNumberSerializer.java │ │ ├── DataTypeModule.java │ │ ├── DateDeserializer.java │ │ ├── DateSerializer.java │ │ ├── InstantDeserializer.java │ │ ├── InstantSerializer.java │ │ ├── JacksonUtil.java │ │ ├── LocalDateTimeDeserializer.java │ │ ├── LocalDateTimeSerializer.java │ │ ├── LocalTimeDeserializer.java │ │ ├── LocalTimeSerializer.java │ │ ├── LongTimestampDeserializer.java │ │ ├── SqlDateDeserializer.java │ │ ├── SqlDateSerializer.java │ │ ├── TimestampDeserializer.java │ │ └── TimestampSerializer.java │ │ ├── mdc │ │ └── MDCUtils.java │ │ ├── property │ │ ├── JCPPProperty.java │ │ └── PropertyUtils.java │ │ ├── trace │ │ ├── TraceIdGenerator.java │ │ ├── Tracer.java │ │ ├── TracerCallable.java │ │ ├── TracerContextUtil.java │ │ └── TracerRunnable.java │ │ └── validation │ │ ├── Length.java │ │ ├── StringLengthValidator.java │ │ └── Validator.java │ └── test │ └── java │ └── sanbing │ └── jcpp │ └── infrastructure │ └── util │ ├── async │ └── JCPPExecutorsTest.java │ └── codec │ ├── BCDUtilTest.java │ └── CP56Time2aUtilTest.java ├── jcpp-protocol-api ├── pom.xml └── src │ └── main │ └── java │ └── sanbing │ └── jcpp │ └── protocol │ ├── ProtocolBootstrap.java │ ├── ProtocolContext.java │ ├── ProtocolMessageProcessor.java │ ├── adapter │ ├── DownlinkController.java │ ├── DownlinkGrpcService.java │ └── config │ │ ├── TracerInterceptor.java │ │ ├── UndertowServletWebServerCustomizer.java │ │ └── WebMvcConfiguration.java │ ├── cfg │ ├── ForwarderCfg.java │ ├── KafkaCfg.java │ ├── ListenerCfg.java │ ├── MemoryCfg.java │ ├── ProtocolCfg.java │ ├── TcpCfg.java │ ├── TcpHandlerCfg.java │ └── enums │ │ ├── ForwarderType.java │ │ └── TcpHandlerType.java │ ├── domain │ ├── DownlinkCmdEnum.java │ ├── ListenerToHandlerMsg.java │ ├── ProtocolSession.java │ ├── ProtocolUplinkMsg.java │ ├── SessionCloseReason.java │ └── SessionToHandlerMsg.java │ ├── forwarder │ ├── Forwarder.java │ ├── KafkaForwarder.java │ └── MemoryForwarder.java │ ├── listener │ ├── ChannelHandlerInitializer.java │ ├── ChannelHandlerParameter.java │ ├── Listener.java │ └── tcp │ │ ├── TcpChannelHandler.java │ │ ├── TcpListener.java │ │ ├── TcpSession.java │ │ ├── configs │ │ ├── BinaryHandlerConfiguration.java │ │ ├── HandlerConfiguration.java │ │ ├── JsonHandlerConfiguration.java │ │ └── TextHandlerConfiguration.java │ │ ├── decoder │ │ ├── JCPPHeadTailFrameDecoder.java │ │ ├── JCPPLengthFieldBasedFrameDecoder.java │ │ └── TcpMsgDecoder.java │ │ ├── enums │ │ ├── ReadAct.java │ │ └── SequenceNumberLength.java │ │ └── handler │ │ ├── ConnectionLimitHandler.java │ │ ├── IdleEventHandler.java │ │ └── TracerHandler.java │ └── provider │ ├── ProtocolSessionRegistryProvider.java │ ├── ProtocolsConfigProvider.java │ └── impl │ ├── DefaultProtocolSessionRegistryProvider.java │ └── DefaultProtocolsConfigProvider.java ├── jcpp-protocol-bootstrap ├── pom.xml └── src │ ├── layers.xml │ ├── main │ ├── java │ │ └── sanbing │ │ │ └── jcpp │ │ │ └── protocol │ │ │ └── JCPPProtocolServiceApplication.java │ └── resources │ │ ├── banner.txt │ │ ├── log4j2.xml │ │ └── protocol-service.yml │ └── test │ └── java │ └── sanbing │ └── jcpp │ └── protocol │ ├── AbstractProtocolTestBase.java │ └── adapter │ └── DownlinkControllerIT.java ├── jcpp-protocol-yunkuaichong ├── READMD.md ├── pom.xml └── src │ └── main │ └── java │ └── sanbing │ └── jcpp │ └── protocol │ └── yunkuaichong │ ├── AbstractYunKuaiChongCmdExe.java │ ├── YunKuaiChongDownlinkCmdExe.java │ ├── YunKuaiChongDwonlinkMessage.java │ ├── YunKuaiChongProtocolMessageProcessor.java │ ├── YunKuaiChongUplinkCmdExe.java │ ├── YunKuaiChongUplinkMessage.java │ ├── annotation │ └── YunKuaiChongCmd.java │ ├── enums │ └── YunKuaiChongDownlinkCmdEnum.java │ ├── v150 │ ├── YunkuaichongV150ProtocolBootstrap.java │ └── cmd │ │ ├── YunKuaiChongV150BmsHandshakeULCmd.java │ │ ├── YunKuaiChongV150HeartbeatULCmd.java │ │ ├── YunKuaiChongV150LoginAckDLCmd.java │ │ ├── YunKuaiChongV150LoginULCmd.java │ │ ├── YunKuaiChongV150QueryPricingModelAckDLCmd.java │ │ ├── YunKuaiChongV150QueryPricingModelULCmd.java │ │ ├── YunKuaiChongV150RealTimeDataULCmd.java │ │ ├── YunKuaiChongV150RemoteStartDLCmd.java │ │ ├── YunKuaiChongV150RemoteStartResultULCmd.java │ │ ├── YunKuaiChongV150RemoteStopDLCmd.java │ │ ├── YunKuaiChongV150RemoteStopResultULCmd.java │ │ ├── YunKuaiChongV150SetPricingModelAckULCmd.java │ │ ├── YunKuaiChongV150SetPricingModelDLCmd.java │ │ ├── YunKuaiChongV150TransactionRecordAckDLCmd.java │ │ ├── YunKuaiChongV150TransactionRecordULCmd.java │ │ ├── YunKuaiChongV150VerifyPricingModelAckDLCmd.java │ │ └── YunKuaiChongV150VerifyPricingModelULCmd.java │ └── v160 │ ├── YunkuaichongV160ProtocolBootstrap.java │ └── cmd │ ├── YunKuaiChongV160RemoteParallelStartDLCmd.java │ └── YunKuaiChongV160RemoteParallelStartResultULCmd.java ├── jcpp-testing └── pom.xml ├── license-header-template.txt └── pom.xml /.gitee/ISSUE_TEMPLATE.zh-CN.md: -------------------------------------------------------------------------------- 1 | ### 该问题是怎么引起的? 2 | 3 | 4 | 5 | ### 重现步骤 6 | 7 | 8 | 9 | ### 报错信息 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md: -------------------------------------------------------------------------------- 1 | ### 相关的Issue 2 | 3 | 4 | ### 原因(目的、解决的问题等) 5 | 6 | 7 | ### 描述(做了什么,变更了什么) 8 | 9 | 10 | ### 测试用例(新增、改动、可能影响的功能) 11 | 12 | 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | HELP.md 4 | target/ 5 | !.mvn/wrapper/maven-wrapper.jar 6 | !**/src/main/**/target/ 7 | !**/src/test/**/target/ 8 | 9 | # Log file 10 | *.log 11 | 12 | # BlueJ files 13 | *.ctxt 14 | 15 | # Mobile Tools for Java (J2ME) 16 | .mtj.tmp/ 17 | 18 | # Package Files # 19 | *.jar 20 | *.war 21 | *.nar 22 | *.ear 23 | *.zip 24 | *.tar.gz 25 | *.rar 26 | 27 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 28 | hs_err_pid* 29 | 30 | ### STS ### 31 | .apt_generated 32 | .classpath 33 | .factorypath 34 | .project 35 | .settings 36 | .springBeans 37 | .sts4-cache 38 | 39 | ### IntelliJ IDEA ### 40 | .idea 41 | *.iws 42 | *.iml 43 | *.ipr 44 | 45 | ### NetBeans ### 46 | /nbproject/private/ 47 | /nbbuild/ 48 | /dist/ 49 | /nbdist/ 50 | /.nb-gradle/ 51 | build/ 52 | !**/src/main/**/build/ 53 | !**/src/test/**/build/ 54 | 55 | ### VS Code ### 56 | .vscode/ 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JChargePointProtocol 2 | 3 | ###### 一个高性能、分布式、支持海量并发量的充电桩JAVA服务端,计划支持100种协议,为充电应用提供基础能力。 4 | 5 |

6 | 9 | GitHub License 10 | 11 | 12 | Static Badge 13 | 14 |

15 | 16 | ------------------------------ 17 | #### 当前支持的充电桩协议 18 | | 协议名 | 版本号 | 19 | |---|------------| 20 | | 云快充 | 1.5.0、1.6.0 | 21 | 22 | ------------------------------ 23 | #### 充电桩协议文档 24 | 百度网盘: https://pan.baidu.com/s/1xT8xWty1XRUHDzTZM_8aLw?pwd=jcpp 25 | 26 | ------------------------------ 27 | 28 | ##### 文档请到联系作者加入社群 29 | 30 | 31 | ------------------------------ 32 | #### 参与贡献 33 | 34 | 1. Fork 本仓库 35 | 2. 新建 Feat_xxx 分支 36 | 3. 提交代码 37 | 4. 加入社群 38 | 5. 新建 Pull Request 39 | 40 | #### 版权 41 | 开源部分,仅供学习和交流研究使用 42 | 43 | -------------------------------------------------------------------------------- /docker/app.Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | # 微信:mohan_88888 4 | # 抖音:程序员三丙 5 | # 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | # 7 | 8 | 9 | FROM registry.cn-hangzhou.aliyuncs.com/sanbing/jcpp-base:1.0 AS base 10 | WORKDIR /app 11 | COPY . . 12 | RUN mvn -U -B -T 0.8C clean install -DskipTests 13 | 14 | #分层 15 | FROM registry.cn-hangzhou.aliyuncs.com/sanbing/openjdk:21-jdk-slim-bullseye AS builder 16 | WORKDIR /app 17 | COPY --from=base /app/jcpp-app-bootstrap/target/application.jar application.jar 18 | RUN java -Djarmode=tools -jar application.jar extract --layers --destination extracted 19 | 20 | # 执行 21 | FROM registry.cn-hangzhou.aliyuncs.com/sanbing/openjdk:21-jdk-slim-bullseye 22 | RUN useradd -m sanbing 23 | WORKDIR /home/sanbing 24 | 25 | COPY --from=builder /app/extracted/dependencies/ ./ 26 | COPY --from=builder /app/extracted/spring-boot-loader/ ./ 27 | COPY --from=builder /app/extracted/snapshot-dependencies/ ./ 28 | COPY --from=builder /app/extracted/application/ ./ 29 | COPY --from=base /app/jcpp-app-bootstrap/target/conf ./config 30 | COPY --from=base /app/docker/start.sh . 31 | 32 | RUN chmod a+x start.sh \ 33 | && mkdir -p /home/sanbing/logs/jcpp \ 34 | && mkdir -p /home/sanbing/logs/accesslog \ 35 | && mkdir -p /home/sanbing/logs/gc \ 36 | && mkdir -p /home/sanbing/logs/heapdump \ 37 | && chmod 700 -R /home/sanbing/logs/* \ 38 | && chown -R sanbing:sanbing /home/sanbing 39 | 40 | EXPOSE 8080 8080 41 | 42 | ENV APP_LOG_LEVEL=INFO 43 | ENV PROTOCOLS_LOG_LEVEL=INFO 44 | 45 | USER sanbing 46 | CMD ["/bin/bash", "start.sh"] 47 | -------------------------------------------------------------------------------- /docker/base.Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | # 微信:mohan_88888 4 | # 抖音:程序员三丙 5 | # 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | # 7 | 8 | 9 | FROM registry.cn-hangzhou.aliyuncs.com/sanbing/mvn:3.9.9-jdk21 AS base 10 | WORKDIR /app 11 | COPY . . 12 | RUN mvn -U -B -T 0.8C clean install -DskipTests \ 13 | && rm -rf /app 14 | 15 | -------------------------------------------------------------------------------- /docker/docker-compose.kafka.yml: -------------------------------------------------------------------------------- 1 | # 2 | # 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | # 微信:mohan_88888 4 | # 抖音:程序员三丙 5 | # 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | # 7 | 8 | 9 | networks: 10 | sanbing-network: 11 | driver: bridge 12 | name: sanbing-network 13 | ipam: 14 | config: 15 | - subnet: 10.10.0.0/24 16 | 17 | services: 18 | zookeeper: 19 | image: registry.cn-hangzhou.aliyuncs.com/sanbing/zookeeper:3.9 20 | restart: always 21 | networks: 22 | - sanbing-network 23 | ports: 24 | - "2181:2181" 25 | environment: 26 | ALLOW_ANONYMOUS_LOGIN: true 27 | kafka: 28 | image: registry.cn-hangzhou.aliyuncs.com/sanbing/kafka:3.7.1 29 | restart: always 30 | depends_on: 31 | - zookeeper 32 | networks: 33 | - sanbing-network 34 | ports: 35 | - "9092:9092" 36 | env_file: 37 | - kafka.env 38 | kafka-exporter: 39 | image: registry.cn-hangzhou.aliyuncs.com/sanbing/kafka-exporter:latest 40 | restart: always 41 | depends_on: 42 | - kafka 43 | networks: 44 | - sanbing-network 45 | ports: 46 | - "9308:9308" 47 | command: 48 | - '--kafka.server=kafka:9092' 49 | -------------------------------------------------------------------------------- /docker/docker-compose.monolith.yml: -------------------------------------------------------------------------------- 1 | # 2 | # 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | # 微信:mohan_88888 4 | # 抖音:程序员三丙 5 | # 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | # 7 | 8 | 9 | networks: 10 | sanbing-network: 11 | driver: bridge 12 | name: sanbing-network 13 | ipam: 14 | config: 15 | - subnet: 10.10.0.0/24 16 | 17 | services: 18 | jcpp-node-0: 19 | restart: always 20 | build: 21 | context: .. 22 | dockerfile: docker/app.Dockerfile 23 | networks: 24 | - sanbing-network 25 | ports: 26 | - "8080:8080" 27 | - "38001:38001" 28 | environment: 29 | HTTP_BIND_PORT: 8080 -------------------------------------------------------------------------------- /docker/docker-compose.postgres.yml: -------------------------------------------------------------------------------- 1 | # 2 | # 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | # 微信:mohan_88888 4 | # 抖音:程序员三丙 5 | # 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | # 7 | 8 | 9 | volumes: 10 | postgresql_data: {} 11 | 12 | networks: 13 | sanbing-network: 14 | driver: bridge 15 | name: sanbing-network 16 | ipam: 17 | config: 18 | - subnet: 10.10.0.0/24 19 | 20 | services: 21 | postgres: 22 | image: registry.cn-hangzhou.aliyuncs.com/sanbing/postgresql:17 23 | restart: always 24 | networks: 25 | - sanbing-network 26 | ports: 27 | - "5432:5432" 28 | environment: 29 | - 'POSTGRES_DB=jcpp' 30 | - 'POSTGRES_PASSWORD=postgres' 31 | - 'POSTGRESQL_MAX_CONNECTIONS=1000' 32 | - 'POSTGRESQL_DEFAULT_TRANSACTION_ISOLATION=read committed' 33 | - 'TZ=Asia/Shanghai' 34 | volumes: 35 | - postgresql_data:/bitnami/postgresql 36 | - ./schema/schema-postgres.sql:/docker-entrypoint-initdb.d/init.sql -------------------------------------------------------------------------------- /docker/docker-compose.redis-sentinel.yml: -------------------------------------------------------------------------------- 1 | # 2 | # 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | # 微信:mohan_88888 4 | # 抖音:程序员三丙 5 | # 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | # 7 | 8 | 9 | networks: 10 | sanbing-network: 11 | driver: bridge 12 | name: sanbing-network 13 | ipam: 14 | config: 15 | - subnet: 10.10.0.0/24 16 | 17 | services: 18 | redis-master: 19 | image: registry.cn-hangzhou.aliyuncs.com/sanbing/redis:7.4 20 | restart: always 21 | networks: 22 | - sanbing-network 23 | environment: 24 | - 'REDIS_REPLICATION_MODE=master' 25 | - 'REDIS_PASSWORD=sanbing' 26 | 27 | redis-slave: 28 | image: registry.cn-hangzhou.aliyuncs.com/sanbing/redis:7.4 29 | restart: always 30 | networks: 31 | - sanbing-network 32 | environment: 33 | - 'REDIS_REPLICATION_MODE=slave' 34 | - 'REDIS_MASTER_HOST=redis-master' 35 | - 'REDIS_MASTER_PASSWORD=sanbing' 36 | - 'REDIS_PASSWORD=sanbing' 37 | depends_on: 38 | - redis-master 39 | 40 | redis-sentinel: 41 | image: registry.cn-hangzhou.aliyuncs.com/sanbing/redis-sentinel:7.4 42 | restart: always 43 | networks: 44 | - sanbing-network 45 | environment: 46 | - 'REDIS_MASTER_HOST=redis-master' 47 | - 'REDIS_MASTER_SET=mymaster' 48 | - 'REDIS_SENTINEL_PASSWORD=sanbing' 49 | - 'REDIS_MASTER_PASSWORD=sanbing' 50 | depends_on: 51 | - redis-master 52 | - redis-slave 53 | -------------------------------------------------------------------------------- /docker/docker-compose.redis-standalone.yml: -------------------------------------------------------------------------------- 1 | # 2 | # 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | # 微信:mohan_88888 4 | # 抖音:程序员三丙 5 | # 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | # 7 | 8 | 9 | networks: 10 | sanbing-network: 11 | driver: bridge 12 | name: sanbing-network 13 | ipam: 14 | config: 15 | - subnet: 10.10.0.0/24 16 | 17 | services: 18 | redis: 19 | image: registry.cn-hangzhou.aliyuncs.com/sanbing/redis:7.4 20 | restart: always 21 | networks: 22 | - sanbing-network 23 | ports: 24 | - '6379:6379' 25 | environment: 26 | - 'REDIS_PASSWORD=sanbing' 27 | -------------------------------------------------------------------------------- /docker/kafka.env: -------------------------------------------------------------------------------- 1 | KAFKA_CFG_NODE_ID=0 2 | ALLOW_PLAINTEXT_LISTENER=yes 3 | KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181 4 | KAFKA_CFG_LISTENERS=INSIDE://:9093,OUTSIDE://:9092 5 | KAFKA_CFG_ADVERTISED_LISTENERS=INSIDE://:9093,OUTSIDE://kafka:9092 6 | KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT 7 | KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE=true 8 | KAFKA_CFG_INTER_BROKER_LISTENER_NAME=INSIDE 9 | KAFKA_CFG_LOG_RETENTION_BYTES=1073741824 10 | KAFKA_CFG_SEGMENT_BYTES=268435456 11 | KAFKA_CFG_LOG_RETENTION_MS=300000 12 | KAFKA_CFG_LOG_CLEANUP_POLICY=delete 13 | 14 | 15 | -------------------------------------------------------------------------------- /docker/protocol.Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | # 微信:mohan_88888 4 | # 抖音:程序员三丙 5 | # 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | # 7 | 8 | 9 | FROM registry.cn-hangzhou.aliyuncs.com/sanbing/jcpp-base:1.0 AS base 10 | WORKDIR /app 11 | COPY . . 12 | RUN mvn -U -B -T 0.8C clean install -DskipTests 13 | 14 | #分层 15 | FROM registry.cn-hangzhou.aliyuncs.com/sanbing/openjdk:21-jdk-slim-bullseye AS builder 16 | WORKDIR /app 17 | COPY --from=base /app/jcpp-protocol-bootstrap/target/application.jar application.jar 18 | RUN java -Djarmode=tools -jar application.jar extract --layers --destination extracted 19 | 20 | # 执行 21 | FROM registry.cn-hangzhou.aliyuncs.com/sanbing/openjdk:21-jdk-slim-bullseye 22 | RUN useradd -m sanbing 23 | WORKDIR /home/sanbing 24 | 25 | COPY --from=builder /app/extracted/dependencies/ ./ 26 | COPY --from=builder /app/extracted/spring-boot-loader/ ./ 27 | COPY --from=builder /app/extracted/snapshot-dependencies/ ./ 28 | COPY --from=builder /app/extracted/application/ ./ 29 | COPY --from=base /app/jcpp-app-bootstrap/target/conf ./config 30 | COPY --from=base /app/docker/start.sh . 31 | 32 | RUN chmod a+x start.sh \ 33 | && mkdir -p /home/sanbing/logs/jcpp \ 34 | && mkdir -p /home/sanbing/logs/accesslog \ 35 | && mkdir -p /home/sanbing/logs/gc \ 36 | && mkdir -p /home/sanbing/logs/heapdump \ 37 | && chmod 700 -R /home/sanbing/logs/* \ 38 | && chown -R sanbing:sanbing /home/sanbing 39 | 40 | EXPOSE 8080 8080 41 | 42 | ENV PROTOCOLS_LOG_LEVEL=INFO 43 | 44 | USER sanbing 45 | CMD ["/bin/bash", "start.sh"] 46 | 47 | -------------------------------------------------------------------------------- /docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # 开源代码,仅供学习和交流研究使用,商用请联系三丙 4 | # 微信:mohan_88888 5 | # 抖音:程序员三丙 6 | # 付费课程知识星球:https://t.zsxq.com/aKtXo 7 | # 8 | 9 | 10 | echo "Starting Server ..." 11 | 12 | export JAVA_APP_OPTS="-XX:+UseContainerSupport -XX:InitialRAMPercentage=50 -XX:MaxRAMPercentage=90 \ 13 | -Xlog:gc*,heap*,age*,safepoint=debug:file=/home/sanbing/logs/gc/gc.log:time,uptime,level,tags:filecount=10,filesize=10M \ 14 | -XX:+HeapDumpOnOutOfMemoryError \ 15 | -XX:HeapDumpPath=/home/sanbing/logs/heapdump/ \ 16 | -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark \ 17 | -XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:MaxTenuringThreshold=10 \ 18 | -Xss512k -XX:G1ReservePercent=20 \ 19 | -XX:-OmitStackTraceInFastThrow \ 20 | -Dlogging.config=/home/sanbing/config/log4j2.xml" 21 | 22 | #export JAVA_OPTS_EXTEND="-Xdebug -Xrunjdwp:transport=dt_socket,address=0.0.0.0:8000,server=y,suspend=n" 23 | 24 | exec java $JAVA_APP_OPTS $JAVA_OPTS_EXTEND $JAVA_OPTS -Dnetworkaddress.cache.ttl=60 -jar application.jar 25 | -------------------------------------------------------------------------------- /jcpp-app-bootstrap/src/layers.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 14 | 15 | 16 | org/springframework/boot/loader/** 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | *:*:*SNAPSHOT 26 | 27 | 28 | 29 | 30 | dependencies 31 | spring-boot-loader 32 | snapshot-dependencies 33 | application 34 | 35 | 36 | -------------------------------------------------------------------------------- /jcpp-app-bootstrap/src/main/java/sanbing/jcpp/JCPPServerApplication.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp; 8 | 9 | import org.springframework.boot.Banner; 10 | import org.springframework.boot.autoconfigure.SpringBootApplication; 11 | import org.springframework.boot.builder.SpringApplicationBuilder; 12 | import org.springframework.scheduling.annotation.EnableAsync; 13 | import org.springframework.scheduling.annotation.EnableScheduling; 14 | 15 | import java.util.Arrays; 16 | 17 | /** 18 | * @author baigod 19 | */ 20 | @SpringBootApplication 21 | @EnableAsync 22 | @EnableScheduling 23 | public class JCPPServerApplication { 24 | 25 | private static final String SPRING_CONFIG_NAME_KEY = "--spring.config.name"; 26 | private static final String DEFAULT_SPRING_CONFIG_PARAM = SPRING_CONFIG_NAME_KEY + "=" + "app-service"; 27 | 28 | public static void main(String[] args) { 29 | new SpringApplicationBuilder(JCPPServerApplication.class).bannerMode(Banner.Mode.LOG).run(updateArguments(args)); 30 | } 31 | 32 | private static String[] updateArguments(String[] args) { 33 | if (Arrays.stream(args).noneMatch(arg -> arg.startsWith(SPRING_CONFIG_NAME_KEY))) { 34 | String[] modifiedArgs = new String[args.length + 1]; 35 | System.arraycopy(args, 0, modifiedArgs, 0, args.length); 36 | modifiedArgs[args.length] = DEFAULT_SPRING_CONFIG_PARAM; 37 | return modifiedArgs; 38 | } 39 | return args; 40 | } 41 | } -------------------------------------------------------------------------------- /jcpp-app-bootstrap/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | 2 | ___ ________ ________ ________ 3 | |\ \|\ ____\|\ __ \|\ __ \ 4 | \ \ \ \ \___|\ \ \|\ \ \ \|\ \ 5 | __ \ \ \ \ \ \ \ ____\ \ ____\ 6 | |\ \\_\ \ \ \____\ \ \___|\ \ \___| 7 | \ \________\ \_______\ \__\ \ \__\ 8 | \|________|\|_______|\|__| \|__| 9 | 10 | =================================================== 11 | :: ${application.title} :: ${application.formatted-version} 12 | =================================================== -------------------------------------------------------------------------------- /jcpp-app-bootstrap/src/test/java/sanbing/jcpp/AbstractTestBase.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp; 8 | 9 | import org.junit.jupiter.api.MethodOrderer; 10 | import org.junit.jupiter.api.TestMethodOrder; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.boot.test.context.SpringBootTest; 14 | import org.springframework.test.context.ActiveProfiles; 15 | 16 | /** 17 | * @author baigod 18 | */ 19 | @ActiveProfiles("test") 20 | @SpringBootTest(classes = JCPPServerApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 21 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 22 | public class AbstractTestBase { 23 | 24 | static { 25 | System.setProperty("spring.config.name", "app-service"); 26 | } 27 | 28 | protected final Logger log = LoggerFactory.getLogger(this.getClass()); 29 | } -------------------------------------------------------------------------------- /jcpp-app-bootstrap/src/test/java/sanbing/jcpp/app/dal/mapper/StationMapperIT.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.mapper; 8 | 9 | import com.baomidou.mybatisplus.core.toolkit.Wrappers; 10 | import jakarta.annotation.Resource; 11 | import org.junit.jupiter.api.Test; 12 | import sanbing.jcpp.AbstractTestBase; 13 | import sanbing.jcpp.app.dal.config.ibatis.enums.OwnerTypeEnum; 14 | import sanbing.jcpp.app.dal.config.ibatis.enums.StationStatusEnum; 15 | import sanbing.jcpp.app.dal.entity.Station; 16 | import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil; 17 | 18 | import java.time.LocalDateTime; 19 | import java.util.UUID; 20 | 21 | import static sanbing.jcpp.app.dal.mapper.UserMapperIT.NORMAL_USER_ID; 22 | 23 | /** 24 | * @author baigod 25 | */ 26 | class StationMapperIT extends AbstractTestBase { 27 | static final UUID NORMAL_STATION_ID = UUID.fromString("07d80c81-fe99-4a1f-a6aa-dc4d798b5626"); 28 | 29 | @Resource 30 | StationMapper stationMapper; 31 | 32 | @Test 33 | void curdTest() { 34 | stationMapper.delete(Wrappers.lambdaQuery()); 35 | 36 | Station station = Station.builder() 37 | .id(NORMAL_STATION_ID) 38 | .createdTime(LocalDateTime.now()) 39 | .additionalInfo(JacksonUtil.newObjectNode()) 40 | .stationName("三丙家专属充电站") 41 | .stationCode("S20241001001") 42 | .ownerId(NORMAL_USER_ID) 43 | .longitude(120.107936F) 44 | .latitude(30.267014F) 45 | .ownerType(OwnerTypeEnum.C) 46 | .province("浙江省") 47 | .city("杭州市") 48 | .county("西湖区") 49 | .address("西溪路552-1号") 50 | .status(StationStatusEnum.OPERATIONAL) 51 | .build(); 52 | 53 | stationMapper.insertOrUpdate(station); 54 | 55 | log.info("{}", stationMapper.selectById(NORMAL_STATION_ID)); 56 | } 57 | } -------------------------------------------------------------------------------- /jcpp-app-bootstrap/src/test/java/sanbing/jcpp/app/dal/mapper/UserMapperIT.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.mapper; 8 | 9 | import com.baomidou.mybatisplus.core.toolkit.Wrappers; 10 | import jakarta.annotation.Resource; 11 | import org.junit.jupiter.api.Test; 12 | import sanbing.jcpp.AbstractTestBase; 13 | import sanbing.jcpp.app.dal.config.ibatis.enums.UserStatusEnum; 14 | import sanbing.jcpp.app.dal.entity.User; 15 | import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil; 16 | 17 | import java.time.LocalDateTime; 18 | import java.util.UUID; 19 | 20 | /** 21 | * @author baigod 22 | */ 23 | class UserMapperIT extends AbstractTestBase { 24 | static final UUID NORMAL_USER_ID = UUID.fromString("21cbf909-a23a-4396-840a-f34061f59f95"); 25 | 26 | @Resource 27 | private UserMapper userMapper; 28 | 29 | @Test 30 | void curdTest() { 31 | userMapper.delete(Wrappers.lambdaQuery()); 32 | 33 | User user = User.builder() 34 | .id(NORMAL_USER_ID) 35 | .createdTime(LocalDateTime.now()) 36 | .additionalInfo(JacksonUtil.newObjectNode()) 37 | .status(UserStatusEnum.ENABLE) 38 | .userName("sanbing") 39 | .userCredentials(JacksonUtil.newObjectNode()) 40 | .build(); 41 | 42 | userMapper.insertOrUpdate(user); 43 | 44 | log.info("{}", userMapper.selectById(NORMAL_USER_ID)); 45 | } 46 | } -------------------------------------------------------------------------------- /jcpp-app-bootstrap/src/test/resources/app-service-test.properties: -------------------------------------------------------------------------------- 1 | service.protocols.yunkuaichongV150.listener.tcp.bind-port=0 2 | service.protocols.yunkuaichongV160.listener.tcp.bind-port=0 3 | service.protocol.rpc.port=0 -------------------------------------------------------------------------------- /jcpp-app/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 13 | 14 | sanbing 15 | jcpp-parent 16 | 1.0.0-SNAPSHOT 17 | ../pom.xml 18 | 19 | 4.0.0 20 | 21 | jcpp-app 22 | jar 23 | JChargePointProtocol App Module 24 | 应用模块 25 | 26 | 27 | ${basedir}/.. 28 | 29 | 30 | 31 | 32 | sanbing 33 | jcpp-protocol-api 34 | 35 | 36 | sanbing 37 | jcpp-infrastructure-queue 38 | 39 | 40 | sanbing 41 | jcpp-infrastructure-cache 42 | 43 | 44 | org.postgresql 45 | postgresql 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-starter-jdbc 50 | 51 | 52 | com.baomidou 53 | mybatis-plus-spring-boot3-starter 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/GunOptStatusEnum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.config.ibatis.enums; 8 | 9 | import com.baomidou.mybatisplus.annotation.IEnum; 10 | 11 | /** 12 | * @author baigod 13 | */ 14 | public enum GunOptStatusEnum implements IEnum { 15 | AVAILABLE, // 可用状态 16 | IN_MAINTENANCE, // 维护中状态 17 | OUT_OF_SERVICE, // 停用状态 18 | RESERVED; // 已预约状态 19 | 20 | @Override 21 | public String getValue() { 22 | return name(); 23 | } 24 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/GunRunStatusEnum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.config.ibatis.enums; 8 | 9 | import com.baomidou.mybatisplus.annotation.IEnum; 10 | 11 | /** 12 | * @author baigod 13 | */ 14 | public enum GunRunStatusEnum implements IEnum { 15 | IDLE, // 空闲 16 | INSERTED, // 已插枪 17 | CHARGING, // 充电中 18 | CHARGE_COMPLETE, // 充电完成 19 | DISCHARGE_READY, // 放电准备 20 | DISCHARGING, // 放电中 21 | DISCHARGE_COMPLETE, // 放电完成 22 | RESERVED, // 预约 23 | FAULT; // 故障 24 | 25 | @Override 26 | public String getValue() { 27 | return name(); 28 | } 29 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/OrderStatusEnum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.config.ibatis.enums; 8 | 9 | import com.baomidou.mybatisplus.annotation.IEnum; 10 | 11 | public enum OrderStatusEnum implements IEnum { 12 | PENDING, 13 | IN_CHARGING, 14 | COMPLETED, 15 | CANCELLED, 16 | TERMINATED, 17 | FAILED, 18 | REFUNDED; 19 | 20 | 21 | @Override 22 | public String getValue() { 23 | return name(); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/OrderTypeEnum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.config.ibatis.enums; 8 | 9 | import com.baomidou.mybatisplus.annotation.IEnum; 10 | 11 | /** 12 | * @author baigod 13 | */ 14 | public enum OrderTypeEnum implements IEnum { 15 | CHARGE, 16 | 17 | DISCHARGE; 18 | 19 | @Override 20 | public String getValue() { 21 | return name(); 22 | } 23 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/OwnerTypeEnum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.config.ibatis.enums; 8 | 9 | import com.baomidou.mybatisplus.annotation.IEnum; 10 | 11 | /** 12 | * @author baigod 13 | */ 14 | public enum OwnerTypeEnum implements IEnum { 15 | C, 16 | B, 17 | G; 18 | 19 | @Override 20 | public String getValue() { 21 | return name(); 22 | } 23 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/PileStatusEnum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.config.ibatis.enums; 8 | 9 | import com.baomidou.mybatisplus.annotation.IEnum; 10 | 11 | /** 12 | * @author baigod 13 | */ 14 | public enum PileStatusEnum implements IEnum { 15 | IDLE, // 空闲 16 | WORKING, // 工作中 17 | FAULT, // 故障 18 | MAINTENANCE, // 维护中 19 | OFFLINE, // 离线 20 | ; 21 | 22 | @Override 23 | public String getValue() { 24 | return name(); 25 | } 26 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/PileTypeEnum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.config.ibatis.enums; 8 | 9 | import com.baomidou.mybatisplus.annotation.IEnum; 10 | 11 | /** 12 | * @author baigod 13 | */ 14 | public enum PileTypeEnum implements IEnum { 15 | AC, // 交流充电桩 16 | DC, // 直流充电桩 17 | ; 18 | 19 | @Override 20 | public String getValue() { 21 | return name(); 22 | } 23 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/StationStatusEnum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.config.ibatis.enums; 8 | 9 | import com.baomidou.mybatisplus.annotation.IEnum; 10 | 11 | /** 12 | * @author baigod 13 | */ 14 | public enum StationStatusEnum implements IEnum { 15 | OPERATIONAL, // 正常运营 16 | PARTIAL_FAILURE, // 部分故障 17 | FULLY_LOADED, // 满载 18 | MAINTENANCE, // 维护中 19 | CLOSED, // 关闭 20 | WAITING_FOR_OPEN; // 待开放 21 | 22 | @Override 23 | public String getValue() { 24 | return name(); 25 | } 26 | 27 | 28 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/UserStatusEnum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.config.ibatis.enums; 8 | 9 | import com.baomidou.mybatisplus.annotation.IEnum; 10 | 11 | /** 12 | * @author baigod 13 | */ 14 | public enum UserStatusEnum implements IEnum { 15 | ENABLE, 16 | DISABLE; 17 | 18 | @Override 19 | public String getValue() { 20 | return name(); 21 | } 22 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/typehandlers/JsonbTypeHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.config.ibatis.typehandlers; 8 | 9 | import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; 10 | import com.fasterxml.jackson.databind.JsonNode; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.apache.ibatis.type.JdbcType; 13 | import org.apache.ibatis.type.MappedTypes; 14 | import org.postgresql.util.PGobject; 15 | import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil; 16 | 17 | import java.lang.reflect.Field; 18 | import java.sql.PreparedStatement; 19 | import java.sql.SQLException; 20 | 21 | @Slf4j 22 | @MappedTypes({JsonNode.class}) 23 | public class JsonbTypeHandler extends JacksonTypeHandler { 24 | 25 | public JsonbTypeHandler(Class type) { 26 | super(type); 27 | } 28 | 29 | public JsonbTypeHandler(Class type, Field field) { 30 | super(type, field); 31 | } 32 | 33 | @Override 34 | public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException { 35 | if (ps != null) { 36 | PGobject jsonObject = new PGobject(); 37 | jsonObject.setType("jsonb"); 38 | jsonObject.setValue(JacksonUtil.toString(parameter)); 39 | ps.setObject(i, jsonObject); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/typehandlers/UUIDTypeHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.config.ibatis.typehandlers; 8 | 9 | import org.apache.ibatis.type.BaseTypeHandler; 10 | import org.apache.ibatis.type.JdbcType; 11 | 12 | import java.sql.CallableStatement; 13 | import java.sql.PreparedStatement; 14 | import java.sql.ResultSet; 15 | import java.sql.SQLException; 16 | import java.util.UUID; 17 | 18 | /** 19 | * mysql UUID 类型转 varchar 20 | */ 21 | public class UUIDTypeHandler extends BaseTypeHandler { 22 | 23 | @Override 24 | public void setNonNullParameter(PreparedStatement ps, int i, UUID parameter, JdbcType jdbcType) throws SQLException { 25 | ps.setObject(i, parameter); 26 | } 27 | 28 | @Override 29 | public UUID getNullableResult(ResultSet rs, String columnName) throws SQLException { 30 | return rs.getObject(columnName, UUID.class); 31 | } 32 | 33 | @Override 34 | public UUID getNullableResult(ResultSet rs, int columnIndex) throws SQLException { 35 | return rs.getObject(columnIndex, UUID.class); 36 | } 37 | 38 | @Override 39 | public UUID getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { 40 | return cs.getObject(columnIndex, UUID.class); 41 | } 42 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.entity; 8 | 9 | import com.baomidou.mybatisplus.annotation.IdType; 10 | import com.baomidou.mybatisplus.annotation.TableId; 11 | import com.baomidou.mybatisplus.annotation.TableName; 12 | import com.fasterxml.jackson.databind.JsonNode; 13 | import lombok.AllArgsConstructor; 14 | import lombok.Builder; 15 | import lombok.Data; 16 | import lombok.NoArgsConstructor; 17 | import sanbing.jcpp.app.dal.config.ibatis.enums.GunOptStatusEnum; 18 | import sanbing.jcpp.app.dal.config.ibatis.enums.GunRunStatusEnum; 19 | import sanbing.jcpp.app.dal.config.ibatis.enums.OwnerTypeEnum; 20 | import sanbing.jcpp.infrastructure.cache.HasVersion; 21 | 22 | import java.io.Serializable; 23 | import java.time.LocalDateTime; 24 | import java.util.UUID; 25 | 26 | 27 | @Data 28 | @TableName("jcpp_gun") 29 | @Builder 30 | @AllArgsConstructor 31 | @NoArgsConstructor 32 | public class Gun implements Serializable, HasVersion { 33 | 34 | @TableId(type = IdType.INPUT) 35 | private UUID id; 36 | 37 | private LocalDateTime createdTime; 38 | 39 | private JsonNode additionalInfo; 40 | 41 | private String gunNo; 42 | 43 | private String gunName; 44 | 45 | private String gunCode; 46 | 47 | private UUID stationId; 48 | 49 | private UUID pileId; 50 | 51 | private UUID ownerId; 52 | 53 | private OwnerTypeEnum ownerType; 54 | 55 | private GunRunStatusEnum runStatus; 56 | 57 | private LocalDateTime runStatusUpdatedTime; 58 | 59 | private GunOptStatusEnum optStatus; 60 | 61 | private Integer version; 62 | 63 | } 64 | -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Order.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.entity; 8 | 9 | import com.baomidou.mybatisplus.annotation.IdType; 10 | import com.baomidou.mybatisplus.annotation.TableId; 11 | import com.baomidou.mybatisplus.annotation.TableName; 12 | import com.fasterxml.jackson.databind.JsonNode; 13 | import lombok.AllArgsConstructor; 14 | import lombok.Builder; 15 | import lombok.Data; 16 | import lombok.NoArgsConstructor; 17 | import sanbing.jcpp.app.dal.config.ibatis.enums.OrderStatusEnum; 18 | import sanbing.jcpp.app.dal.config.ibatis.enums.OrderTypeEnum; 19 | 20 | import java.io.Serializable; 21 | import java.math.BigDecimal; 22 | import java.time.LocalDateTime; 23 | import java.util.UUID; 24 | 25 | 26 | @Data 27 | @TableName("jcpp_order") 28 | @Builder 29 | @AllArgsConstructor 30 | @NoArgsConstructor 31 | public class Order implements Serializable { 32 | 33 | @TableId(type = IdType.INPUT) 34 | private UUID id; 35 | 36 | private String internalOrderNo; 37 | 38 | private String externalOrderNo; 39 | 40 | private String pileOrderNo; 41 | 42 | private LocalDateTime createdTime; 43 | 44 | private JsonNode additionalInfo; 45 | 46 | private LocalDateTime updatedTime; 47 | 48 | private LocalDateTime cancelledTime; 49 | 50 | private OrderStatusEnum status; 51 | 52 | private OrderTypeEnum type; 53 | 54 | private UUID creatorId; 55 | 56 | private UUID stationId; 57 | 58 | private UUID pileId; 59 | 60 | private UUID gunId; 61 | 62 | private String plateNo; 63 | 64 | private BigDecimal settlementAmount; 65 | 66 | private JsonNode settlementDetails; 67 | 68 | private BigDecimal electricityQuantity; 69 | 70 | 71 | } 72 | -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.entity; 8 | 9 | import com.baomidou.mybatisplus.annotation.IdType; 10 | import com.baomidou.mybatisplus.annotation.TableId; 11 | import com.baomidou.mybatisplus.annotation.TableName; 12 | import com.fasterxml.jackson.databind.JsonNode; 13 | import lombok.AllArgsConstructor; 14 | import lombok.Builder; 15 | import lombok.Data; 16 | import lombok.NoArgsConstructor; 17 | import sanbing.jcpp.app.dal.config.ibatis.enums.OwnerTypeEnum; 18 | import sanbing.jcpp.app.dal.config.ibatis.enums.PileStatusEnum; 19 | import sanbing.jcpp.app.dal.config.ibatis.enums.PileTypeEnum; 20 | import sanbing.jcpp.infrastructure.cache.HasVersion; 21 | 22 | import java.io.Serializable; 23 | import java.time.LocalDateTime; 24 | import java.util.UUID; 25 | 26 | @Data 27 | @TableName(value = "jcpp_pile", autoResultMap = true) 28 | @Builder 29 | @AllArgsConstructor 30 | @NoArgsConstructor 31 | public class Pile implements Serializable, HasVersion { 32 | 33 | @TableId(type = IdType.INPUT) 34 | private UUID id; 35 | 36 | private LocalDateTime createdTime; 37 | 38 | private JsonNode additionalInfo; 39 | 40 | private String pileName; 41 | 42 | private String pileCode; 43 | 44 | private String protocol; 45 | 46 | private UUID stationId; 47 | 48 | private UUID ownerId; 49 | 50 | private OwnerTypeEnum ownerType; 51 | 52 | private String brand; 53 | 54 | private String model; 55 | 56 | private String manufacturer; 57 | 58 | private PileStatusEnum status; 59 | 60 | private PileTypeEnum type; 61 | 62 | private Integer version; 63 | } 64 | -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Station.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.entity; 8 | 9 | import com.baomidou.mybatisplus.annotation.IdType; 10 | import com.baomidou.mybatisplus.annotation.TableId; 11 | import com.baomidou.mybatisplus.annotation.TableName; 12 | import com.fasterxml.jackson.databind.JsonNode; 13 | import lombok.AllArgsConstructor; 14 | import lombok.Builder; 15 | import lombok.Data; 16 | import lombok.NoArgsConstructor; 17 | import sanbing.jcpp.app.dal.config.ibatis.enums.OwnerTypeEnum; 18 | import sanbing.jcpp.app.dal.config.ibatis.enums.StationStatusEnum; 19 | import sanbing.jcpp.infrastructure.cache.HasVersion; 20 | 21 | import java.io.Serializable; 22 | import java.time.LocalDateTime; 23 | import java.util.UUID; 24 | 25 | 26 | @Data 27 | @TableName("jcpp_station") 28 | @Builder 29 | @AllArgsConstructor 30 | @NoArgsConstructor 31 | public class Station implements Serializable, HasVersion { 32 | 33 | @TableId(type = IdType.INPUT) 34 | private UUID id; 35 | 36 | private LocalDateTime createdTime; 37 | 38 | private JsonNode additionalInfo; 39 | 40 | private String stationName; 41 | 42 | private String stationCode; 43 | 44 | private UUID ownerId; 45 | 46 | private Float longitude; 47 | 48 | private Float latitude; 49 | 50 | private OwnerTypeEnum ownerType; 51 | 52 | private String province; 53 | 54 | private String city; 55 | 56 | private String county; 57 | 58 | private String address; 59 | 60 | private StationStatusEnum status; 61 | 62 | private Integer version; 63 | 64 | } 65 | -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/User.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.entity; 8 | 9 | import com.baomidou.mybatisplus.annotation.IdType; 10 | import com.baomidou.mybatisplus.annotation.TableId; 11 | import com.baomidou.mybatisplus.annotation.TableName; 12 | import com.fasterxml.jackson.databind.JsonNode; 13 | import lombok.AllArgsConstructor; 14 | import lombok.Builder; 15 | import lombok.Data; 16 | import lombok.NoArgsConstructor; 17 | import sanbing.jcpp.app.dal.config.ibatis.enums.UserStatusEnum; 18 | import sanbing.jcpp.infrastructure.cache.HasVersion; 19 | 20 | import java.io.Serializable; 21 | import java.time.LocalDateTime; 22 | import java.util.UUID; 23 | 24 | 25 | @Data 26 | @TableName("jcpp_user") 27 | @Builder 28 | @AllArgsConstructor 29 | @NoArgsConstructor 30 | public class User implements Serializable, HasVersion { 31 | 32 | @TableId(type = IdType.INPUT) 33 | private UUID id; 34 | 35 | private LocalDateTime createdTime; 36 | 37 | private JsonNode additionalInfo; 38 | 39 | private UserStatusEnum status; 40 | 41 | private String userName; 42 | 43 | private JsonNode userCredentials; 44 | 45 | private Integer version; 46 | 47 | } 48 | -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/GunMapper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.mapper; 8 | 9 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 10 | import sanbing.jcpp.app.dal.entity.Gun; 11 | 12 | /** 13 | * @author baigod 14 | */ 15 | public interface GunMapper extends BaseMapper { 16 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/OrderMapper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.mapper; 8 | 9 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 10 | import sanbing.jcpp.app.dal.entity.Order; 11 | 12 | /** 13 | * @author baigod 14 | */ 15 | public interface OrderMapper extends BaseMapper { 16 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/PileMapper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.mapper; 8 | 9 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 10 | import org.apache.ibatis.annotations.Select; 11 | import sanbing.jcpp.app.dal.entity.Pile; 12 | 13 | /** 14 | * @author baigod 15 | */ 16 | public interface PileMapper extends BaseMapper { 17 | 18 | @Select("SELECT " + 19 | " * " + 20 | "FROM " + 21 | " jcpp_pile " + 22 | "WHERE " + 23 | " pile_code = #{pileCode}") 24 | Pile selectByCode(String pileCode); 25 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/StationMapper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.mapper; 8 | 9 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 10 | import sanbing.jcpp.app.dal.entity.Station; 11 | 12 | /** 13 | * @author baigod 14 | */ 15 | public interface StationMapper extends BaseMapper { 16 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.dal.mapper; 8 | 9 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 10 | import sanbing.jcpp.app.dal.entity.User; 11 | 12 | /** 13 | * @author baigod 14 | */ 15 | public interface UserMapper extends BaseMapper { 16 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/repository/AbstractCachedEntityRepository.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.repository; 8 | 9 | import org.springframework.transaction.support.TransactionSynchronizationManager; 10 | 11 | import java.io.Serializable; 12 | 13 | public abstract class AbstractCachedEntityRepository extends AbstractEntityRepository { 14 | 15 | protected void publishEvictEvent(E event) { 16 | if (TransactionSynchronizationManager.isActualTransactionActive()) { 17 | eventPublisher.publishEvent(event); 18 | } else { 19 | handleEvictEvent(event); 20 | } 21 | } 22 | 23 | public abstract void handleEvictEvent(E event); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/repository/AbstractEntityRepository.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.repository; 8 | 9 | import jakarta.annotation.Resource; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.context.ApplicationEventPublisher; 12 | 13 | @Slf4j 14 | public abstract class AbstractEntityRepository { 15 | 16 | @Resource 17 | protected ApplicationEventPublisher eventPublisher; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/repository/CachedVersionedEntityRepository.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.repository; 8 | 9 | import jakarta.annotation.Resource; 10 | import sanbing.jcpp.infrastructure.cache.HasVersion; 11 | import sanbing.jcpp.infrastructure.cache.VersionedCache; 12 | import sanbing.jcpp.infrastructure.cache.VersionedCacheKey; 13 | 14 | import java.io.Serializable; 15 | 16 | public abstract class CachedVersionedEntityRepository extends AbstractCachedEntityRepository { 17 | 18 | @Resource 19 | protected VersionedCache cache; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/repository/PileRepository.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.repository; 8 | 9 | import sanbing.jcpp.app.dal.entity.Pile; 10 | 11 | /** 12 | * @author baigod 13 | */ 14 | public interface PileRepository { 15 | 16 | Pile findPileByCode(String pileCode); 17 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/repository/PileRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.repository; 8 | 9 | import jakarta.annotation.Resource; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.stereotype.Repository; 12 | import org.springframework.transaction.event.TransactionalEventListener; 13 | import sanbing.jcpp.app.dal.entity.Pile; 14 | import sanbing.jcpp.app.dal.mapper.PileMapper; 15 | import sanbing.jcpp.app.service.cache.pile.PileCacheEvictEvent; 16 | import sanbing.jcpp.app.service.cache.pile.PileCacheKey; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | import static sanbing.jcpp.infrastructure.util.validation.Validator.validateString; 22 | 23 | /** 24 | * @author baigod 25 | */ 26 | @Repository 27 | @Slf4j 28 | public class PileRepositoryImpl extends CachedVersionedEntityRepository implements PileRepository { 29 | 30 | @Resource 31 | PileMapper pileMapper; 32 | 33 | @TransactionalEventListener(classes = PileCacheEvictEvent.class) 34 | @Override 35 | public void handleEvictEvent(PileCacheEvictEvent event) { 36 | // 如果修改或删除充电桩,需要在这里消费删除事件 37 | List toEvict = new ArrayList<>(3); 38 | toEvict.add(new PileCacheKey(event.getPileId())); 39 | toEvict.add(new PileCacheKey(event.getPileCode())); 40 | cache.evict(toEvict); 41 | } 42 | 43 | @Override 44 | public Pile findPileByCode(String pileCode) { 45 | validateString(pileCode, code -> "无效的桩编号" + pileCode); 46 | return cache.get(new PileCacheKey(pileCode), 47 | () -> pileMapper.selectByCode(pileCode)); 48 | } 49 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/pile/PileCacheEvictEvent.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.service.cache.pile; 8 | 9 | import lombok.Data; 10 | 11 | import java.util.UUID; 12 | 13 | @Data 14 | public class PileCacheEvictEvent { 15 | 16 | private UUID pileId; 17 | private String pileCode; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/pile/PileCacheKey.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.service.cache.pile; 8 | 9 | import lombok.Builder; 10 | import lombok.EqualsAndHashCode; 11 | import lombok.Getter; 12 | import lombok.RequiredArgsConstructor; 13 | import sanbing.jcpp.infrastructure.cache.VersionedCacheKey; 14 | 15 | import java.io.Serial; 16 | import java.util.Optional; 17 | import java.util.UUID; 18 | 19 | @Getter 20 | @EqualsAndHashCode 21 | @RequiredArgsConstructor 22 | @Builder 23 | public class PileCacheKey implements VersionedCacheKey { 24 | 25 | @Serial 26 | private static final long serialVersionUID = 6366389552842340207L; 27 | 28 | private final UUID pileId; 29 | private final String pileCode; 30 | 31 | public PileCacheKey(UUID pileId) { 32 | this(pileId, null); 33 | } 34 | 35 | public PileCacheKey(String pileCode) { 36 | this(null, pileCode); 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return Optional.ofNullable(pileId).map(UUID::toString).orElse(pileCode); 42 | } 43 | 44 | @Override 45 | public boolean isVersioned() { 46 | return pileId != null; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/pile/PileCaffeineCache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.service.cache.pile; 8 | 9 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 10 | import org.springframework.cache.CacheManager; 11 | import org.springframework.stereotype.Service; 12 | import sanbing.jcpp.app.dal.entity.Pile; 13 | import sanbing.jcpp.infrastructure.cache.CacheConstants; 14 | import sanbing.jcpp.infrastructure.cache.VersionedCaffeineCache; 15 | 16 | @ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) 17 | @Service("PileCache") 18 | public class PileCaffeineCache extends VersionedCaffeineCache { 19 | 20 | public PileCaffeineCache(CacheManager cacheManager) { 21 | super(cacheManager, CacheConstants.PILE_CACHE); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/pile/PileRedisCache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.service.cache.pile; 8 | 9 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 10 | import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; 11 | import org.springframework.data.redis.serializer.SerializationException; 12 | import org.springframework.stereotype.Service; 13 | import sanbing.jcpp.app.dal.entity.Pile; 14 | import sanbing.jcpp.infrastructure.cache.*; 15 | import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil; 16 | 17 | @ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") 18 | @Service("PileCache") 19 | public class PileRedisCache extends VersionedRedisCache { 20 | 21 | public PileRedisCache(JCPPRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, LettuceConnectionFactory connectionFactory) { 22 | super(CacheConstants.PILE_CACHE, cacheSpecsMap, connectionFactory, configuration, new JCPPRedisSerializer<>() { 23 | 24 | @Override 25 | public byte[] serialize(Pile pile) throws SerializationException { 26 | return JacksonUtil.writeValueAsBytes(pile); 27 | } 28 | 29 | @Override 30 | public Pile deserialize(PileCacheKey key, byte[] bytes) throws SerializationException { 31 | return JacksonUtil.fromBytes(bytes, Pile.class); 32 | } 33 | }); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/session/PileSessionCacheKey.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.service.cache.session; 8 | 9 | import lombok.Builder; 10 | import lombok.EqualsAndHashCode; 11 | import lombok.Getter; 12 | 13 | import java.io.Serializable; 14 | 15 | /** 16 | * @author baigod 17 | */ 18 | @Getter 19 | @EqualsAndHashCode 20 | @Builder 21 | public class PileSessionCacheKey implements Serializable { 22 | 23 | private final String pileCode; 24 | 25 | public PileSessionCacheKey(String pileCode) { 26 | this.pileCode = pileCode; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return pileCode; 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/session/PileSessionCaffeineCache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.service.cache.session; 8 | 9 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 10 | import org.springframework.cache.CacheManager; 11 | import org.springframework.stereotype.Service; 12 | import sanbing.jcpp.app.data.PileSession; 13 | import sanbing.jcpp.infrastructure.cache.CacheConstants; 14 | import sanbing.jcpp.infrastructure.cache.CaffeineTransactionalCache; 15 | 16 | /** 17 | * @author baigod 18 | */ 19 | @ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) 20 | @Service("PileSessionCache") 21 | public class PileSessionCaffeineCache extends CaffeineTransactionalCache { 22 | 23 | public PileSessionCaffeineCache(CacheManager cacheManager) { 24 | super(cacheManager, CacheConstants.PILE_SESSION_CACHE); 25 | } 26 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/session/PileSessionRedisCache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.service.cache.session; 8 | 9 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 10 | import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; 11 | import org.springframework.data.redis.serializer.SerializationException; 12 | import org.springframework.stereotype.Service; 13 | import sanbing.jcpp.app.data.PileSession; 14 | import sanbing.jcpp.infrastructure.cache.*; 15 | import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil; 16 | 17 | /** 18 | * @author baigod 19 | */ 20 | @ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") 21 | @Service("PileSessionCache") 22 | public class PileSessionRedisCache extends RedisTransactionalCache { 23 | 24 | public PileSessionRedisCache(JCPPRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, LettuceConnectionFactory connectionFactory) { 25 | super(CacheConstants.PILE_SESSION_CACHE, cacheSpecsMap, connectionFactory, configuration, new JCPPRedisSerializer<>() { 26 | 27 | @Override 28 | public byte[] serialize(PileSession pileSession) throws SerializationException { 29 | return JacksonUtil.writeValueAsBytes(pileSession); 30 | } 31 | 32 | @Override 33 | public PileSession deserialize(PileSessionCacheKey key, byte[] bytes) throws SerializationException { 34 | return JacksonUtil.fromBytes(bytes, PileSession.class); 35 | } 36 | }); 37 | } 38 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/service/config/DownlinkRestTemplateConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.service.config; 8 | 9 | import org.springframework.boot.web.client.RestTemplateBuilder; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter; 13 | import org.springframework.web.client.RestTemplate; 14 | 15 | import java.time.Duration; 16 | import java.time.temporal.ChronoUnit; 17 | import java.util.Collections; 18 | 19 | /** 20 | * @author baigod 21 | */ 22 | @Configuration 23 | public class DownlinkRestTemplateConfiguration { 24 | 25 | @Bean("downlinkRestTemplate") 26 | public RestTemplate downlinkRestTemplate() { 27 | RestTemplate restTemplate = new RestTemplateBuilder() 28 | .setConnectTimeout(Duration.of(3, ChronoUnit.SECONDS)) 29 | .setReadTimeout(Duration.of(3, ChronoUnit.SECONDS)) 30 | .build(); 31 | restTemplate.setMessageConverters(Collections.singletonList(new ProtobufHttpMessageConverter())); 32 | return restTemplate; 33 | } 34 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/GrpcDownlinkCallService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.service.impl; 8 | 9 | import com.google.common.net.HostAndPort; 10 | import jakarta.annotation.Resource; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 13 | import org.springframework.stereotype.Service; 14 | import sanbing.jcpp.app.service.DownlinkCallService; 15 | import sanbing.jcpp.app.service.grpc.DownlinkGrpcClient; 16 | import sanbing.jcpp.proto.gen.ProtocolProto.DownlinkRequestMessage; 17 | import sanbing.jcpp.proto.gen.ProtocolProto.RequestMsg; 18 | 19 | import static sanbing.jcpp.infrastructure.proto.ProtoConverter.toTracerProto; 20 | 21 | /** 22 | * @author baigod 23 | */ 24 | @Service 25 | @Slf4j 26 | @ConditionalOnExpression("'${service.downlink.rpc.type:null}'=='grpc'") 27 | public class GrpcDownlinkCallService extends DownlinkCallService { 28 | 29 | @Resource 30 | DownlinkGrpcClient downlinkGrpcClient; 31 | 32 | @Override 33 | protected int determinePort(int restPort, int grpcPort) { 34 | return grpcPort; 35 | } 36 | 37 | @Override 38 | protected void _sendDownlinkMessage(DownlinkRequestMessage downlinkMessage, String nodeIp, int port) { 39 | try { 40 | RequestMsg requestMsg = RequestMsg.newBuilder() 41 | .setTs(System.currentTimeMillis()) 42 | .setTracer(toTracerProto()) 43 | .setDownlinkRequestMessage(downlinkMessage) 44 | .build(); 45 | 46 | downlinkGrpcClient.sendDownlinkRequest(HostAndPort.fromParts(nodeIp, port), requestMsg); 47 | } catch (Exception e) { 48 | log.error("下行消息发送异常", e); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/QueueConsumerManagerTask.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.service.queue; 8 | 9 | import lombok.AllArgsConstructor; 10 | import lombok.Getter; 11 | import lombok.ToString; 12 | import sanbing.jcpp.infrastructure.queue.common.QueueConfig; 13 | import sanbing.jcpp.infrastructure.queue.common.TopicPartitionInfo; 14 | 15 | import java.util.Set; 16 | 17 | @Getter 18 | @ToString 19 | @AllArgsConstructor 20 | public class QueueConsumerManagerTask { 21 | 22 | private final QueueEvent event; 23 | private QueueConfig config; 24 | private Set partitions; 25 | private boolean drainQueue; 26 | 27 | public static QueueConsumerManagerTask delete(boolean drainQueue) { 28 | return new QueueConsumerManagerTask(QueueEvent.DELETE, null, null, drainQueue); 29 | } 30 | 31 | public static QueueConsumerManagerTask configUpdate(QueueConfig config) { 32 | return new QueueConsumerManagerTask(QueueEvent.CONFIG_UPDATE, config, null, false); 33 | } 34 | 35 | public static QueueConsumerManagerTask partitionChange(Set partitions) { 36 | return new QueueConsumerManagerTask(QueueEvent.PARTITION_CHANGE, null, partitions, false); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/QueueEvent.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.app.service.queue; 8 | 9 | import java.io.Serializable; 10 | 11 | public enum QueueEvent implements Serializable { 12 | 13 | PARTITION_CHANGE, CONFIG_UPDATE, DELETE 14 | 15 | } 16 | -------------------------------------------------------------------------------- /jcpp-infrastructure-cache/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 13 | 14 | sanbing 15 | jcpp-parent 16 | 1.0.0-SNAPSHOT 17 | ../pom.xml 18 | 19 | 4.0.0 20 | 21 | jcpp-infrastructure-cache 22 | jar 23 | JChargePointProtocol Infrastructure Cache Module 24 | 基础缓存管理模块 25 | 26 | 27 | ${basedir}/.. 28 | 29 | 30 | 31 | 32 | org.springframework.data 33 | spring-data-redis 34 | 35 | 36 | io.lettuce 37 | lettuce-core 38 | 39 | 40 | org.apache.commons 41 | commons-pool2 42 | 43 | 44 | sanbing 45 | jcpp-infrastructure-util 46 | 47 | 48 | com.github.ben-manes.caffeine 49 | caffeine 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/CacheConstants.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.cache; 8 | 9 | public final class CacheConstants { 10 | 11 | public static final String PILE_CACHE = "piles"; 12 | 13 | public static final String PILE_SESSION_CACHE = "pileSessions"; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/CacheSpecs.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.cache; 8 | 9 | import lombok.Data; 10 | 11 | @Data 12 | public class CacheSpecs { 13 | private Integer timeToLiveInMinutes; 14 | private Integer maxSize; 15 | } 16 | -------------------------------------------------------------------------------- /jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/CacheSpecsMap.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.cache; 8 | 9 | import lombok.Data; 10 | import lombok.Getter; 11 | import org.springframework.boot.context.properties.ConfigurationProperties; 12 | import org.springframework.context.annotation.Configuration; 13 | 14 | import java.util.Map; 15 | 16 | @Configuration 17 | @ConfigurationProperties(prefix = "cache") 18 | @Data 19 | public class CacheSpecsMap { 20 | 21 | @Getter 22 | private Map specs; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/CacheTransaction.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.cache; 8 | 9 | public interface CacheTransaction { 10 | 11 | void put(K key, V value); 12 | 13 | boolean commit(); 14 | 15 | void rollback(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/CacheValueWrapper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.cache; 8 | 9 | public interface CacheValueWrapper { 10 | 11 | T get(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/CaffeineCacheTransaction.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.cache; 8 | 9 | import lombok.Getter; 10 | import lombok.RequiredArgsConstructor; 11 | import lombok.Setter; 12 | import lombok.extern.slf4j.Slf4j; 13 | 14 | import java.io.Serializable; 15 | import java.util.LinkedHashMap; 16 | import java.util.List; 17 | import java.util.Map; 18 | import java.util.UUID; 19 | 20 | @Slf4j 21 | @RequiredArgsConstructor 22 | public class CaffeineCacheTransaction implements CacheTransaction { 23 | @Getter 24 | private final UUID id = UUID.randomUUID(); 25 | private final CaffeineTransactionalCache cache; 26 | @Getter 27 | private final List keys; 28 | @Getter 29 | @Setter 30 | private boolean failed; 31 | 32 | private final Map pendingPuts = new LinkedHashMap<>(); 33 | 34 | @Override 35 | public void put(K key, V value) { 36 | pendingPuts.put(key, value); 37 | } 38 | 39 | @Override 40 | public boolean commit() { 41 | return cache.commit(id, pendingPuts); 42 | } 43 | 44 | @Override 45 | public void rollback() { 46 | cache.rollback(id); 47 | } 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/HasVersion.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.cache; 8 | 9 | public interface HasVersion { 10 | 11 | Integer getVersion(); 12 | 13 | default void setVersion(Integer version) { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/JCPPRedisSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.cache; 8 | 9 | import org.springframework.data.redis.serializer.SerializationException; 10 | import org.springframework.lang.Nullable; 11 | 12 | public interface JCPPRedisSerializer { 13 | 14 | @Nullable 15 | byte[] serialize(@Nullable T t) throws SerializationException; 16 | 17 | @Nullable 18 | T deserialize(K key, @Nullable byte[] bytes) throws SerializationException; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/RedisCacheTransaction.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.cache; 8 | 9 | import lombok.RequiredArgsConstructor; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.data.redis.connection.RedisConnection; 12 | 13 | import java.io.Serializable; 14 | import java.util.Objects; 15 | 16 | @Slf4j 17 | @RequiredArgsConstructor 18 | public class RedisCacheTransaction implements CacheTransaction { 19 | 20 | private final RedisTransactionalCache cache; 21 | private final RedisConnection connection; 22 | 23 | @Override 24 | public void put(K key, V value) { 25 | cache.put(key, value, connection); 26 | } 27 | 28 | @Override 29 | public boolean commit() { 30 | try { 31 | var execResult = connection.exec(); 32 | return execResult.stream().anyMatch(Objects::nonNull); 33 | } finally { 34 | connection.close(); 35 | } 36 | } 37 | 38 | @Override 39 | public void rollback() { 40 | try { 41 | connection.discard(); 42 | } finally { 43 | connection.close(); 44 | } 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/SimpleCacheValueWrapper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.cache; 8 | 9 | import lombok.AccessLevel; 10 | import lombok.RequiredArgsConstructor; 11 | import lombok.ToString; 12 | import org.springframework.cache.Cache; 13 | 14 | @ToString 15 | @RequiredArgsConstructor(access = AccessLevel.PRIVATE) 16 | public class SimpleCacheValueWrapper implements CacheValueWrapper { 17 | 18 | private final T value; 19 | 20 | @Override 21 | public T get() { 22 | return value; 23 | } 24 | 25 | public static SimpleCacheValueWrapper empty() { 26 | return new SimpleCacheValueWrapper<>(null); 27 | } 28 | 29 | public static SimpleCacheValueWrapper wrap(T value) { 30 | return new SimpleCacheValueWrapper<>(value); 31 | } 32 | 33 | @SuppressWarnings("unchecked") 34 | public static SimpleCacheValueWrapper wrap(Cache.ValueWrapper source) { 35 | return source == null ? null : new SimpleCacheValueWrapper<>((T) source.get()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/VersionedCache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.cache; 8 | 9 | 10 | import java.io.Serializable; 11 | import java.util.Collection; 12 | import java.util.Optional; 13 | import java.util.function.Supplier; 14 | 15 | public interface VersionedCache extends TransactionalCache { 16 | 17 | CacheValueWrapper get(K key); 18 | 19 | default V get(K key, Supplier supplier) { 20 | return get(key, supplier, true); 21 | } 22 | 23 | default V get(K key, Supplier supplier, boolean putToCache) { 24 | return Optional.ofNullable(get(key)) 25 | .map(CacheValueWrapper::get) 26 | .orElseGet(() -> { 27 | V value = supplier.get(); 28 | if (putToCache) { 29 | put(key, value); 30 | } 31 | return value; 32 | }); 33 | } 34 | 35 | void put(K key, V value); 36 | 37 | void evict(K key); 38 | 39 | void evict(Collection keys); 40 | 41 | void evict(K key, Integer version); 42 | 43 | default Integer getVersion(V value) { 44 | if (value == null) { 45 | return 0; 46 | } else if (value.getVersion() != null) { 47 | return value.getVersion(); 48 | } else { 49 | return null; 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/VersionedCacheKey.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.cache; 8 | 9 | import java.io.Serializable; 10 | 11 | public interface VersionedCacheKey extends Serializable { 12 | 13 | default boolean isVersioned() { 14 | return false; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /jcpp-infrastructure-proto/src/main/java/sanbing/jcpp/infrastructure/proto/model/PricingModel.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.proto.model; 8 | 9 | import lombok.*; 10 | import sanbing.jcpp.proto.gen.ProtocolProto.PricingModelFlag; 11 | import sanbing.jcpp.proto.gen.ProtocolProto.PricingModelRule; 12 | import sanbing.jcpp.proto.gen.ProtocolProto.PricingModelType; 13 | 14 | import java.math.BigDecimal; 15 | import java.time.LocalTime; 16 | import java.util.List; 17 | import java.util.Map; 18 | import java.util.UUID; 19 | 20 | @Data 21 | public class PricingModel { 22 | 23 | private UUID id; 24 | 25 | // 计数器,供充电桩协议使用 26 | private int sequenceNumber; 27 | 28 | private String pileCode; 29 | 30 | private PricingModelType type; 31 | 32 | private PricingModelRule rule; 33 | 34 | /** 35 | * 标准电价(单位元) 36 | */ 37 | private BigDecimal standardElec; 38 | 39 | /** 40 | * 标准服务费(单位元) 41 | */ 42 | private BigDecimal standardServ; 43 | 44 | /** 45 | * 分时电价 46 | */ 47 | private Map flagPriceList; 48 | 49 | /** 50 | * 分时时段 51 | */ 52 | private List periodsList; 53 | 54 | @Setter 55 | @Getter 56 | public static class Period { 57 | private int sn; 58 | 59 | // 起始时间 60 | private LocalTime begin; 61 | 62 | // 结束时间 63 | private LocalTime end; 64 | 65 | // 尖峰平谷标识 66 | private PricingModelFlag flag; 67 | } 68 | 69 | @Data 70 | @AllArgsConstructor 71 | @NoArgsConstructor 72 | public static class FlagPrice { 73 | 74 | // 分时电价,单位元 75 | private BigDecimal elec; 76 | 77 | // 分时服务费,单位元 78 | private BigDecimal serv; 79 | } 80 | 81 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-proto/src/main/proto/cluster.proto: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | syntax = "proto3"; 8 | 9 | package infrastructureProto; 10 | 11 | option java_package = "sanbing.jcpp.proto.gen"; 12 | option java_outer_classname = "ClusterProto"; 13 | 14 | message ServiceInfo { 15 | string serviceId = 1; 16 | repeated string serviceTypes = 2; 17 | SystemInfoProto systemInfo = 10; 18 | } 19 | 20 | message SystemInfoProto { 21 | int64 cpuUsage = 1; 22 | int64 cpuCount = 2; 23 | int64 memoryUsage = 3; 24 | int64 totalMemory = 4; 25 | int64 diskUsage = 5; 26 | int64 totalDiscSpace = 6; 27 | } 28 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 13 | 14 | sanbing 15 | jcpp-parent 16 | 1.0.0-SNAPSHOT 17 | ../pom.xml 18 | 19 | 4.0.0 20 | 21 | jcpp-infrastructure-queue 22 | jar 23 | JChargePointProtocol Infrastructure Queue Module 24 | 基础MQ管理模块 25 | 26 | 27 | ${basedir}/.. 28 | 29 | 30 | 31 | 32 | org.apache.kafka 33 | kafka-clients 34 | 35 | 36 | sanbing 37 | jcpp-infrastructure-util 38 | 39 | 40 | sanbing 41 | jcpp-infrastructure-proto 42 | 43 | 44 | sanbing 45 | jcpp-infrastructure-stats 46 | 47 | 48 | org.apache.curator 49 | curator-recipes 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/Callback.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue; 8 | 9 | public interface Callback { 10 | 11 | Callback EMPTY = new Callback() { 12 | 13 | @Override 14 | public void onSuccess() { 15 | 16 | } 17 | 18 | @Override 19 | public void onFailure(Throwable t) { 20 | 21 | } 22 | }; 23 | 24 | void onSuccess(); 25 | 26 | void onFailure(Throwable t); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/DefaultQueueMsg.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue; 8 | 9 | import lombok.Data; 10 | 11 | @Data 12 | public class DefaultQueueMsg implements QueueMsg { 13 | private final String key; 14 | private final byte[] data; 15 | private final DefaultQueueMsgHeaders headers; 16 | 17 | public DefaultQueueMsg(QueueMsg msg) { 18 | this.key = msg.getKey(); 19 | this.data = msg.getData(); 20 | DefaultQueueMsgHeaders headers = new DefaultQueueMsgHeaders(); 21 | msg.getHeaders().getData().forEach(headers::put); 22 | this.headers = headers; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/DefaultQueueMsgHeaders.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue; 8 | 9 | 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | public class DefaultQueueMsgHeaders implements QueueMsgHeaders { 14 | 15 | protected final Map data = new HashMap<>(); 16 | 17 | @Override 18 | public byte[] put(String key, byte[] value) { 19 | return data.put(key, value); 20 | } 21 | 22 | @Override 23 | public byte[] get(String key) { 24 | return data.get(key); 25 | } 26 | 27 | @Override 28 | public Map getData() { 29 | return data; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/KafkaQueueMsg.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue; 8 | 9 | import org.apache.kafka.clients.consumer.ConsumerRecord; 10 | 11 | public class KafkaQueueMsg implements QueueMsg { 12 | private final String key; 13 | private final QueueMsgHeaders headers; 14 | private final byte[] data; 15 | 16 | public KafkaQueueMsg(ConsumerRecord record) { 17 | this.key = record.key(); 18 | QueueMsgHeaders headers = new DefaultQueueMsgHeaders(); 19 | record.headers().forEach(header -> { 20 | headers.put(header.key(), header.value()); 21 | }); 22 | this.headers = headers; 23 | this.data = record.value(); 24 | } 25 | 26 | @Override 27 | public String getKey() { 28 | return key; 29 | } 30 | 31 | @Override 32 | public QueueMsgHeaders getHeaders() { 33 | return headers; 34 | } 35 | 36 | @Override 37 | public byte[] getData() { 38 | return data; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/PackCallback.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue; 8 | 9 | import lombok.extern.slf4j.Slf4j; 10 | 11 | import java.util.UUID; 12 | 13 | @Slf4j 14 | public class PackCallback implements Callback { 15 | private final PackProcessingContext ctx; 16 | private final UUID id; 17 | 18 | public PackCallback(UUID id, PackProcessingContext ctx) { 19 | this.id = id; 20 | this.ctx = ctx; 21 | } 22 | 23 | @Override 24 | public void onSuccess() { 25 | log.trace("[{}] ON SUCCESS", id); 26 | ctx.onSuccess(id); 27 | } 28 | 29 | @Override 30 | public void onFailure(Throwable t) { 31 | log.trace("[{}] ON FAILURE", id, t); 32 | ctx.onFailure(id, t); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/ProtoQueueMsg.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue; 8 | 9 | import com.google.protobuf.GeneratedMessage; 10 | import lombok.Data; 11 | 12 | @Data 13 | public class ProtoQueueMsg implements QueueMsg { 14 | 15 | private final String key; 16 | protected final T value; 17 | private final QueueMsgHeaders headers; 18 | 19 | public ProtoQueueMsg(String key, T value) { 20 | this(key, value, new DefaultQueueMsgHeaders()); 21 | } 22 | 23 | public ProtoQueueMsg(String key, T value, QueueMsgHeaders headers) { 24 | this.key = key; 25 | this.value = value; 26 | this.headers = headers; 27 | } 28 | 29 | @Override 30 | public String getKey() { 31 | return key; 32 | } 33 | 34 | @Override 35 | public QueueMsgHeaders getHeaders() { 36 | return headers; 37 | } 38 | 39 | @Override 40 | public byte[] getData() { 41 | return value.toByteArray(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/QueueAdmin.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue; 8 | 9 | public interface QueueAdmin { 10 | 11 | default void createTopicIfNotExists(String topic) { 12 | createTopicIfNotExists(topic, null); 13 | } 14 | 15 | void createTopicIfNotExists(String topic, String properties); 16 | 17 | void destroy(); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/QueueCallback.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue; 8 | 9 | public interface QueueCallback { 10 | 11 | void onSuccess(QueueMsgMetadata metadata); 12 | 13 | void onFailure(Throwable t); 14 | } 15 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/QueueConsumer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue; 8 | 9 | 10 | 11 | import sanbing.jcpp.infrastructure.queue.common.TopicPartitionInfo; 12 | 13 | import java.util.List; 14 | import java.util.Set; 15 | 16 | public interface QueueConsumer { 17 | 18 | String getTopic(); 19 | 20 | void subscribe(); 21 | 22 | void subscribe(Set partitions); 23 | 24 | void stop(); 25 | 26 | void unsubscribe(); 27 | 28 | List poll(long durationInMillis); 29 | 30 | void commit(); 31 | 32 | boolean isStopped(); 33 | 34 | List getFullTopicNames(); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/QueueMsg.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue; 8 | 9 | public interface QueueMsg { 10 | 11 | String getKey(); 12 | 13 | QueueMsgHeaders getHeaders(); 14 | 15 | byte[] getData(); 16 | } 17 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/QueueMsgHeaders.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue; 8 | 9 | import java.util.Map; 10 | 11 | public interface QueueMsgHeaders { 12 | 13 | byte[] put(String key, byte[] value); 14 | 15 | byte[] get(String key); 16 | 17 | Map getData(); 18 | } 19 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/QueueMsgMetadata.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue; 8 | 9 | public interface QueueMsgMetadata { 10 | } 11 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/QueueProducer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue; 8 | 9 | 10 | import sanbing.jcpp.infrastructure.queue.common.TopicPartitionInfo; 11 | 12 | public interface QueueProducer { 13 | 14 | void init(); 15 | 16 | String getTopic(); 17 | 18 | void send(TopicPartitionInfo tpi, T msg, QueueCallback callback); 19 | 20 | void stop(); 21 | } 22 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/common/QueueConfig.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.common; 8 | 9 | public interface QueueConfig { 10 | 11 | boolean isConsumerPerPartition(); 12 | 13 | int getPollInterval(); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/common/QueueConstants.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.common; 8 | 9 | import static sanbing.jcpp.infrastructure.util.trace.TracerContextUtil.*; 10 | 11 | /** 12 | * @author baigod 13 | */ 14 | public final class QueueConstants { 15 | 16 | public static final String MSG_MD_PREFIX = "jcpp_"; 17 | 18 | public static final String MSG_MD_TRACER_ID = MSG_MD_PREFIX + JCPP_TRACER_ID; 19 | 20 | public static final String MSG_MD_TRACER_ORIGIN = MSG_MD_PREFIX + JCPP_TRACER_ORIGIN; 21 | 22 | public static final String MSG_MD_TRACER_TS = MSG_MD_PREFIX + JCPP_TRACER_TS; 23 | 24 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/common/TopicPartitionInfo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.common; 8 | 9 | import lombok.Builder; 10 | import lombok.Getter; 11 | import lombok.ToString; 12 | 13 | import java.util.Objects; 14 | import java.util.Optional; 15 | 16 | @ToString 17 | public class TopicPartitionInfo { 18 | 19 | @Getter 20 | private final String topic; 21 | private final Integer partition; 22 | @Getter 23 | private final String fullTopicName; 24 | @Getter 25 | private final boolean myPartition; 26 | 27 | @Builder 28 | public TopicPartitionInfo(String topic, Integer partition, boolean myPartition) { 29 | this.topic = topic; 30 | this.partition = partition; 31 | this.myPartition = myPartition; 32 | String tmp = topic; 33 | if (partition != null) { 34 | tmp += "." + partition; 35 | } 36 | this.fullTopicName = tmp; 37 | } 38 | 39 | public TopicPartitionInfo newByTopic(String topic) { 40 | return new TopicPartitionInfo(topic, this.partition, this.myPartition); 41 | } 42 | 43 | public Optional getPartition() { 44 | return Optional.ofNullable(partition); 45 | } 46 | 47 | @Override 48 | public boolean equals(Object o) { 49 | if (this == o) return true; 50 | if (o == null || getClass() != o.getClass()) return false; 51 | TopicPartitionInfo that = (TopicPartitionInfo) o; 52 | return topic.equals(that.topic) && 53 | Objects.equals(partition, that.partition) && 54 | fullTopicName.equals(that.fullTopicName); 55 | } 56 | 57 | @Override 58 | public int hashCode() { 59 | return Objects.hash(fullTopicName); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/discovery/DiscoveryProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.discovery; 8 | 9 | import sanbing.jcpp.proto.gen.ClusterProto.ServiceInfo; 10 | 11 | import java.util.List; 12 | 13 | public interface DiscoveryProvider { 14 | 15 | List getOtherServers(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/discovery/DummyDiscoveryProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.discovery; 8 | 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 11 | import org.springframework.boot.context.event.ApplicationReadyEvent; 12 | import org.springframework.stereotype.Service; 13 | import sanbing.jcpp.infrastructure.util.annotation.AfterStartUp; 14 | import sanbing.jcpp.proto.gen.ClusterProto.ServiceInfo; 15 | 16 | import java.util.Collections; 17 | import java.util.List; 18 | 19 | @Service 20 | @ConditionalOnProperty(prefix = "zk", value = "enabled", havingValue = "false", matchIfMissing = true) 21 | @Slf4j 22 | public class DummyDiscoveryProvider implements DiscoveryProvider { 23 | 24 | private final ServiceInfoProvider serviceInfoProvider; 25 | private final PartitionProvider partitionProvider; 26 | 27 | public DummyDiscoveryProvider(ServiceInfoProvider serviceInfoProvider, PartitionProvider partitionProvider) { 28 | this.serviceInfoProvider = serviceInfoProvider; 29 | this.partitionProvider = partitionProvider; 30 | } 31 | 32 | 33 | @AfterStartUp(order = AfterStartUp.DISCOVERY_SERVICE) 34 | public void onApplicationEvent(ApplicationReadyEvent event) { 35 | partitionProvider.recalculatePartitions(serviceInfoProvider.getServiceInfo(), Collections.emptyList()); 36 | } 37 | 38 | @Override 39 | public List getOtherServers() { 40 | return Collections.emptyList(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/discovery/PartitionProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.discovery; 8 | 9 | 10 | import sanbing.jcpp.infrastructure.queue.common.TopicPartitionInfo; 11 | import sanbing.jcpp.proto.gen.ClusterProto.ServiceInfo; 12 | 13 | import java.util.List; 14 | import java.util.UUID; 15 | 16 | public interface PartitionProvider { 17 | 18 | TopicPartitionInfo resolve(ServiceType serviceType,String queueName, UUID entityId); 19 | 20 | TopicPartitionInfo resolve(ServiceType serviceType,String queueName, String pileCode); 21 | 22 | void recalculatePartitions(ServiceInfo currentService, List otherServices); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/discovery/QueueKey.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.discovery; 8 | 9 | import lombok.Data; 10 | import lombok.With; 11 | 12 | @Data 13 | public class QueueKey { 14 | public static final String MAIN_QUEUE_NAME = "Main"; 15 | 16 | private final ServiceType type; 17 | @With 18 | private final String queueName; 19 | 20 | public QueueKey(ServiceType type, String queueName) { 21 | this.type = type; 22 | this.queueName = queueName; 23 | } 24 | 25 | public QueueKey(ServiceType type) { 26 | this.type = type; 27 | this.queueName = MAIN_QUEUE_NAME; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return "QK(" + queueName + "," + type + ")"; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/discovery/ServiceInfoProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.discovery; 8 | 9 | 10 | import sanbing.jcpp.proto.gen.ClusterProto; 11 | 12 | /** 13 | * @author baigod 14 | */ 15 | public interface ServiceInfoProvider { 16 | String getServiceId(); 17 | 18 | String getHostAddress(); 19 | 20 | int getRestPort(); 21 | 22 | int getGrpcPort(); 23 | 24 | String getServiceType(); 25 | 26 | boolean isMonolith(); 27 | 28 | ClusterProto.ServiceInfo getServiceInfo(); 29 | 30 | ClusterProto.ServiceInfo generateNewServiceInfoWithCurrentSystemInfo(); 31 | 32 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/discovery/ServiceType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.discovery; 8 | 9 | import lombok.Getter; 10 | import lombok.RequiredArgsConstructor; 11 | 12 | @RequiredArgsConstructor 13 | @Getter 14 | public enum ServiceType { 15 | 16 | APP("app"), 17 | PROTOCOL("protocol"); 18 | 19 | private final String label; 20 | 21 | public static ServiceType of(String serviceType) { 22 | return ServiceType.valueOf(serviceType.toUpperCase()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/discovery/event/JCPPApplicationEvent.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.discovery.event; 8 | 9 | import lombok.Getter; 10 | import lombok.ToString; 11 | import org.springframework.context.ApplicationEvent; 12 | 13 | import java.util.concurrent.atomic.AtomicInteger; 14 | 15 | @ToString 16 | public class JCPPApplicationEvent extends ApplicationEvent { 17 | 18 | private static final AtomicInteger sequence = new AtomicInteger(); 19 | 20 | @Getter 21 | private final int sequenceNumber; 22 | 23 | public JCPPApplicationEvent(Object source) { 24 | super(source); 25 | sequenceNumber = sequence.incrementAndGet(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/discovery/event/OtherServiceShutdownEvent.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.discovery.event; 8 | 9 | import lombok.Getter; 10 | 11 | public class OtherServiceShutdownEvent extends JCPPApplicationEvent { 12 | 13 | @Getter 14 | private final String serviceId; 15 | 16 | public OtherServiceShutdownEvent(Object source, String serviceId) { 17 | super(source); 18 | this.serviceId = serviceId; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/discovery/event/PartitionChangeEvent.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.discovery.event; 8 | 9 | import lombok.Getter; 10 | import lombok.ToString; 11 | import sanbing.jcpp.infrastructure.queue.common.TopicPartitionInfo; 12 | import sanbing.jcpp.infrastructure.queue.discovery.QueueKey; 13 | import sanbing.jcpp.infrastructure.queue.discovery.ServiceType; 14 | 15 | import java.io.Serial; 16 | import java.util.Map; 17 | import java.util.Set; 18 | import java.util.stream.Collectors; 19 | 20 | import static sanbing.jcpp.infrastructure.queue.discovery.QueueKey.MAIN_QUEUE_NAME; 21 | 22 | @ToString(callSuper = true) 23 | public class PartitionChangeEvent extends JCPPApplicationEvent { 24 | 25 | @Serial 26 | private static final long serialVersionUID = -8731788167026510559L; 27 | 28 | @Getter 29 | private final Map> partitionsMap; 30 | 31 | public PartitionChangeEvent(Object source, ServiceType serviceType, Map> partitionsMap) { 32 | super(source); 33 | this.partitionsMap = partitionsMap; 34 | } 35 | 36 | public Set getAppPartitions() { 37 | return getPartitionsByServiceTypeAndQueueName(ServiceType.APP, MAIN_QUEUE_NAME); 38 | } 39 | 40 | private Set getPartitionsByServiceTypeAndQueueName(ServiceType serviceType, String queueName) { 41 | return partitionsMap.entrySet() 42 | .stream() 43 | .filter(entry -> serviceType.equals(entry.getKey().getType()) && queueName.equals(entry.getKey().getQueueName())) 44 | .flatMap(entry -> entry.getValue().stream()) 45 | .collect(Collectors.toSet()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaConsumerStatisticConfig.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.kafka; 8 | 9 | import lombok.AllArgsConstructor; 10 | import lombok.Getter; 11 | import lombok.NoArgsConstructor; 12 | import org.springframework.beans.factory.annotation.Value; 13 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 14 | import org.springframework.stereotype.Component; 15 | 16 | @Component 17 | @ConditionalOnProperty(prefix = "queue", value = "type", havingValue = "kafka") 18 | @Getter 19 | @AllArgsConstructor 20 | @NoArgsConstructor 21 | public class KafkaConsumerStatisticConfig { 22 | 23 | @Value("${queue.kafka.consumer-stats.enabled:true}") 24 | private Boolean enabled; 25 | 26 | @Value("${queue.kafka.consumer-stats.print-interval-ms:60000}") 27 | private Long printIntervalMs; 28 | 29 | @Value("${queue.kafka.consumer-stats.kafka-response-timeout-ms:1000}") 30 | private Long kafkaResponseTimeoutMs; 31 | } 32 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.kafka; 8 | 9 | 10 | import sanbing.jcpp.infrastructure.queue.QueueMsg; 11 | 12 | import java.io.IOException; 13 | 14 | public interface KafkaDecoder { 15 | 16 | T decode(QueueMsg msg) throws IOException; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaQueueMsgMetadata.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.kafka; 8 | 9 | import lombok.AllArgsConstructor; 10 | import lombok.Data; 11 | import org.apache.kafka.clients.producer.RecordMetadata; 12 | import sanbing.jcpp.infrastructure.queue.QueueMsgMetadata; 13 | 14 | @Data 15 | @AllArgsConstructor 16 | public class KafkaQueueMsgMetadata implements QueueMsgMetadata { 17 | 18 | private RecordMetadata metadata; 19 | } 20 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaTopicConfigs.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.kafka; 8 | 9 | import jakarta.annotation.PostConstruct; 10 | import lombok.Getter; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 13 | import org.springframework.stereotype.Component; 14 | import sanbing.jcpp.infrastructure.util.property.PropertyUtils; 15 | 16 | import java.util.Map; 17 | 18 | @Component 19 | @ConditionalOnProperty(prefix = "queue", value = "type", havingValue = "kafka") 20 | public class KafkaTopicConfigs { 21 | public static final String NUM_PARTITIONS_SETTING = "partitions"; 22 | 23 | @Value("${queue.kafka.topic-properties.app:}") 24 | private String appProperties; 25 | 26 | @Getter 27 | private Map appConfigs; 28 | 29 | @PostConstruct 30 | private void init() { 31 | this.appConfigs = PropertyUtils.getProps(appProperties); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/memory/InMemoryQueueProducer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.memory; 8 | 9 | import lombok.Data; 10 | import sanbing.jcpp.infrastructure.queue.QueueCallback; 11 | import sanbing.jcpp.infrastructure.queue.QueueMsg; 12 | import sanbing.jcpp.infrastructure.queue.QueueProducer; 13 | import sanbing.jcpp.infrastructure.queue.common.TopicPartitionInfo; 14 | 15 | @Data 16 | public class InMemoryQueueProducer implements QueueProducer { 17 | private final InMemoryStorage storage; 18 | 19 | private final String topic; 20 | 21 | public InMemoryQueueProducer(InMemoryStorage storage, String topic) { 22 | this.storage = storage; 23 | this.topic = topic; 24 | } 25 | 26 | @Override 27 | public void init() { 28 | 29 | } 30 | 31 | @Override 32 | public void send(TopicPartitionInfo tpi, T msg, QueueCallback callback) { 33 | boolean result = storage.put(tpi.getFullTopicName(), msg); 34 | if (result) { 35 | if (callback != null) { 36 | callback.onSuccess(null); 37 | } 38 | } else { 39 | if (callback != null) { 40 | callback.onFailure(new RuntimeException("Failure add msg to InMemoryQueue")); 41 | } 42 | } 43 | } 44 | 45 | @Override 46 | public void stop() { 47 | 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/memory/InMemoryStorage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.memory; 8 | 9 | 10 | import sanbing.jcpp.infrastructure.queue.QueueMsg; 11 | 12 | import java.util.List; 13 | 14 | public interface InMemoryStorage { 15 | 16 | void printStats(); 17 | 18 | int getLagTotal(); 19 | 20 | int getLag(String topic); 21 | 22 | boolean put(String topic, QueueMsg msg); 23 | 24 | List get(String topic) throws InterruptedException; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/processing/IdMsgPair.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.processing; 8 | 9 | import com.google.protobuf.GeneratedMessage; 10 | import lombok.Getter; 11 | import sanbing.jcpp.infrastructure.queue.ProtoQueueMsg; 12 | 13 | import java.util.UUID; 14 | 15 | public class IdMsgPair { 16 | @Getter 17 | final UUID uuid; 18 | @Getter 19 | final ProtoQueueMsg msg; 20 | 21 | public IdMsgPair(UUID uuid, ProtoQueueMsg msg) { 22 | this.uuid = uuid; 23 | this.msg = msg; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/provider/AppQueueFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.provider; 8 | 9 | 10 | import sanbing.jcpp.infrastructure.queue.ProtoQueueMsg; 11 | import sanbing.jcpp.infrastructure.queue.QueueConsumer; 12 | import sanbing.jcpp.infrastructure.queue.QueueProducer; 13 | import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage; 14 | 15 | public interface AppQueueFactory { 16 | 17 | QueueConsumer> createProtocolUplinkMsgConsumer(); 18 | 19 | QueueProducer> createProtocolUplinkMsgProducer(String topic); 20 | } 21 | -------------------------------------------------------------------------------- /jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/settings/QueueAppSettings.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.queue.settings; 8 | 9 | import lombok.Data; 10 | import org.springframework.beans.factory.annotation.Value; 11 | import org.springframework.context.annotation.Lazy; 12 | import org.springframework.stereotype.Component; 13 | 14 | @Lazy 15 | @Data 16 | @Component 17 | public class QueueAppSettings { 18 | 19 | @Value("${queue.app.topic}") 20 | private String topic; 21 | 22 | @Value("${queue.app.partitions}") 23 | private int partitions; 24 | 25 | @Value("${queue.app.decoder:protobuf}") 26 | private DecoderType decoder; 27 | 28 | public enum DecoderType { 29 | protobuf, 30 | json 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/DefaultCounter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.stats; 8 | 9 | import io.micrometer.core.instrument.Counter; 10 | 11 | import java.util.concurrent.atomic.AtomicInteger; 12 | 13 | public class DefaultCounter { 14 | private final AtomicInteger aiCounter; 15 | private final Counter micrometerCounter; 16 | 17 | public DefaultCounter(AtomicInteger aiCounter, Counter micrometerCounter) { 18 | this.aiCounter = aiCounter; 19 | this.micrometerCounter = micrometerCounter; 20 | } 21 | 22 | public void increment() { 23 | aiCounter.incrementAndGet(); 24 | micrometerCounter.increment(); 25 | } 26 | 27 | public void clear() { 28 | aiCounter.set(0); 29 | } 30 | 31 | public int get() { 32 | return aiCounter.get(); 33 | } 34 | 35 | public void add(int delta){ 36 | aiCounter.addAndGet(delta); 37 | micrometerCounter.increment(delta); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/DefaultMessagesStats.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.stats; 8 | 9 | public class DefaultMessagesStats implements MessagesStats { 10 | private final StatsCounter totalCounter; 11 | private final StatsCounter successfulCounter; 12 | private final StatsCounter failedCounter; 13 | 14 | public DefaultMessagesStats(StatsCounter totalCounter, StatsCounter successfulCounter, StatsCounter failedCounter) { 15 | this.totalCounter = totalCounter; 16 | this.successfulCounter = successfulCounter; 17 | this.failedCounter = failedCounter; 18 | } 19 | 20 | @Override 21 | public void incrementTotal(int amount) { 22 | totalCounter.add(amount); 23 | } 24 | 25 | @Override 26 | public void incrementSuccessful(int amount) { 27 | successfulCounter.add(amount); 28 | } 29 | 30 | @Override 31 | public void incrementFailed(int amount) { 32 | failedCounter.add(amount); 33 | } 34 | 35 | @Override 36 | public int getTotal() { 37 | return totalCounter.get(); 38 | } 39 | 40 | @Override 41 | public int getSuccessful() { 42 | return successfulCounter.get(); 43 | } 44 | 45 | @Override 46 | public int getFailed() { 47 | return failedCounter.get(); 48 | } 49 | 50 | @Override 51 | public void reset() { 52 | totalCounter.clear(); 53 | successfulCounter.clear(); 54 | failedCounter.clear(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/MessagesStats.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.stats; 8 | 9 | public interface MessagesStats { 10 | default void incrementTotal() { 11 | incrementTotal(1); 12 | } 13 | 14 | void incrementTotal(int amount); 15 | 16 | default void incrementSuccessful() { 17 | incrementSuccessful(1); 18 | } 19 | 20 | void incrementSuccessful(int amount); 21 | 22 | default void incrementFailed() { 23 | incrementFailed(1); 24 | } 25 | 26 | void incrementFailed(int amount); 27 | 28 | int getTotal(); 29 | 30 | int getSuccessful(); 31 | 32 | int getFailed(); 33 | 34 | void reset(); 35 | } 36 | -------------------------------------------------------------------------------- /jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/StatsCounter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.stats; 8 | 9 | import io.micrometer.core.instrument.Counter; 10 | 11 | import java.util.concurrent.atomic.AtomicInteger; 12 | 13 | public class StatsCounter extends DefaultCounter { 14 | private final String name; 15 | 16 | public StatsCounter(AtomicInteger aiCounter, Counter micrometerCounter, String name) { 17 | super(aiCounter, micrometerCounter); 18 | this.name = name; 19 | } 20 | 21 | public String getName() { 22 | return name; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/StatsFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.stats; 8 | 9 | import io.micrometer.core.instrument.Timer; 10 | 11 | public interface StatsFactory { 12 | 13 | /** 14 | * 创建状态计数器,默认带一个statsName的Tag,并可以自定义扩展其他Tag 15 | * 16 | * @param key 指标名 17 | * @param statsName statsName的标签值 18 | * @param otherTags 其他Tag键值对,参数个数需要是偶数 19 | * @return 20 | */ 21 | StatsCounter createStatsCounter(String key, String statsName, String... otherTags); 22 | 23 | /** 24 | * 创建计数器,可自定义Tag 25 | * 26 | * @param key 指标名 27 | * @param tags 自定义Tag键值对,参数个数需要是偶数 28 | * @return 29 | */ 30 | DefaultCounter createDefaultCounter(String key, String... tags); 31 | 32 | /** 33 | * 创建消息计数器,消息计数器默认包含三种状态(总数、成功数、失败数) 34 | * 35 | * @param key 指标名 36 | * @param tags 自定义Tag键值对,参数个数需要是偶数 37 | * @return 38 | */ 39 | MessagesStats createMessagesStats(String key, String... tags); 40 | 41 | /** 42 | * 创建计时器 43 | * 44 | * @param key 指标名 45 | * @param tags 自定义Tag键值对,参数个数需要是偶数 46 | * @return 47 | */ 48 | Timer createTimer(String key, String... tags); 49 | 50 | /** 51 | * 创建计量器,用于记录某个值的当前状态,可以是瞬时数值 52 | * 53 | * @param key 指标名 54 | * @param number 初始值 55 | * @param tags 自定义Tag键值对,参数个数需要是偶数 56 | * @return 57 | * @param 58 | */ 59 | T createGauge(String key, T number, String... tags); 60 | 61 | } 62 | -------------------------------------------------------------------------------- /jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/StatsTimer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.stats; 8 | 9 | import io.micrometer.core.instrument.Timer; 10 | import lombok.Getter; 11 | 12 | import java.util.concurrent.TimeUnit; 13 | 14 | public class StatsTimer { 15 | 16 | @Getter 17 | private final String name; 18 | private final Timer timer; 19 | 20 | private int count; 21 | private long totalTime; 22 | 23 | public StatsTimer(String name, Timer micrometerTimer) { 24 | this.name = name; 25 | this.timer = micrometerTimer; 26 | } 27 | 28 | public void record(long timeMs) { 29 | count++; 30 | totalTime += timeMs; 31 | timer.record(timeMs, TimeUnit.MILLISECONDS); 32 | } 33 | 34 | public double getAvg() { 35 | if (count == 0) { 36 | return 0.0; 37 | } 38 | return (double) totalTime / count; 39 | } 40 | 41 | public void reset() { 42 | count = 0; 43 | totalTime = 0; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/JCPPHashUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util; 8 | 9 | import com.google.common.hash.HashFunction; 10 | import com.google.common.hash.Hashing; 11 | 12 | import java.nio.charset.StandardCharsets; 13 | import java.util.UUID; 14 | 15 | /** 16 | * @author baigod 17 | */ 18 | public class JCPPHashUtil { 19 | public static HashFunction forName(String name) { 20 | return switch (name) { 21 | case "murmur3_32" -> Hashing.murmur3_32_fixed(); 22 | case "murmur3_128" -> Hashing.murmur3_128(); 23 | case "sha256" -> Hashing.sha256(); 24 | default -> throw new IllegalArgumentException("Can't find hash function with name " + name); 25 | }; 26 | } 27 | 28 | public static int hash(HashFunction hashFunction, String key) { 29 | return hashFunction.hashString(key, StandardCharsets.UTF_8).asInt(); 30 | } 31 | 32 | public static int hash(HashFunction hashFunction, UUID key) { 33 | return hashFunction.hashString(key.toString(), StandardCharsets.UTF_8).asInt(); 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/JCPPPair.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util; 8 | 9 | import lombok.AllArgsConstructor; 10 | import lombok.Data; 11 | 12 | @Data 13 | @AllArgsConstructor 14 | public class JCPPPair { 15 | private S first; 16 | private T second; 17 | 18 | public static JCPPPair of(S first, T second) { 19 | return new JCPPPair<>(first, second); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/annotation/AfterStartUp.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.annotation; 8 | 9 | import org.springframework.boot.context.event.ApplicationReadyEvent; 10 | import org.springframework.context.event.EventListener; 11 | import org.springframework.core.annotation.AliasFor; 12 | import org.springframework.core.annotation.Order; 13 | 14 | import java.lang.annotation.ElementType; 15 | import java.lang.annotation.Retention; 16 | import java.lang.annotation.RetentionPolicy; 17 | import java.lang.annotation.Target; 18 | 19 | @Retention(RetentionPolicy.RUNTIME) 20 | @Target(ElementType.METHOD) 21 | @EventListener(ApplicationReadyEvent.class) 22 | @Order 23 | public @interface AfterStartUp { 24 | 25 | int DISCOVERY_SERVICE = 1; 26 | int REGULAR_SERVICE = 2; 27 | 28 | @AliasFor(annotation = Order.class, attribute = "value") 29 | int order(); 30 | } 31 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/annotation/AppComponent.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.annotation; 8 | 9 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 10 | import org.springframework.stereotype.Component; 11 | 12 | import java.lang.annotation.ElementType; 13 | import java.lang.annotation.Retention; 14 | import java.lang.annotation.RetentionPolicy; 15 | import java.lang.annotation.Target; 16 | 17 | /** 18 | * @author baigod 19 | */ 20 | @Retention(RetentionPolicy.RUNTIME) 21 | @Target(ElementType.TYPE) 22 | @ConditionalOnExpression("'${service.type:null}'=='monolith' || '${service.type:null}'=='app'") 23 | @Component 24 | public @interface AppComponent { 25 | 26 | 27 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/annotation/ProtocolComponent.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.annotation; 8 | 9 | import org.springframework.context.annotation.Condition; 10 | import org.springframework.context.annotation.ConditionContext; 11 | import org.springframework.context.annotation.Conditional; 12 | import org.springframework.core.annotation.AliasFor; 13 | import org.springframework.core.type.AnnotatedTypeMetadata; 14 | import org.springframework.stereotype.Component; 15 | import sanbing.jcpp.infrastructure.util.annotation.ProtocolComponent.ProtocolCondition; 16 | 17 | import java.lang.annotation.ElementType; 18 | import java.lang.annotation.Retention; 19 | import java.lang.annotation.RetentionPolicy; 20 | import java.lang.annotation.Target; 21 | 22 | /** 23 | * @author baigod 24 | */ 25 | @Retention(RetentionPolicy.RUNTIME) 26 | @Target(ElementType.TYPE) 27 | @Conditional(ProtocolCondition.class) 28 | @Component 29 | public @interface ProtocolComponent { 30 | 31 | @AliasFor(annotation = Component.class) 32 | String value() default ""; 33 | 34 | class ProtocolCondition implements Condition { 35 | 36 | @Override 37 | public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { 38 | if (!metadata.isAnnotated(ProtocolComponent.class.getName())) { 39 | return true; 40 | } 41 | 42 | String serviceType = context.getEnvironment().getProperty("service.type", "null"); 43 | 44 | String protocolName = (String) metadata.getAnnotationAttributes(ProtocolComponent.class.getName()).get("value"); 45 | 46 | String enabled = context.getEnvironment().getProperty("service.protocols." + protocolName + ".enabled", "false"); 47 | 48 | return ("monolith".equals(serviceType) || "protocol".equals(serviceType)) && "true".equals(enabled); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/async/JCPPExecutors.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.async; 8 | 9 | import java.util.concurrent.ExecutorService; 10 | import java.util.concurrent.Executors; 11 | import java.util.concurrent.ForkJoinPool; 12 | 13 | public class JCPPExecutors { 14 | 15 | public static ExecutorService newWorkStealingPool(int parallelism, String namePrefix) { 16 | return new ForkJoinPool(parallelism, 17 | new JCPPForkJoinWorkerThreadFactory(namePrefix), 18 | null, true); 19 | } 20 | 21 | public static ExecutorService newWorkStealingPool(int parallelism, Class clazz) { 22 | return newWorkStealingPool(parallelism, clazz.getSimpleName()); 23 | } 24 | 25 | public static ExecutorService newVirtualThreadPool(String namePrefix) { 26 | return Executors.newThreadPerTaskExecutor(new JCPPVirtualThreadFactory(namePrefix)); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/async/JCPPForkJoinWorkerThreadFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.async; 8 | 9 | import lombok.NonNull; 10 | import lombok.ToString; 11 | 12 | import java.util.concurrent.ForkJoinPool; 13 | import java.util.concurrent.ForkJoinWorkerThread; 14 | import java.util.concurrent.atomic.AtomicLong; 15 | 16 | @ToString 17 | public class JCPPForkJoinWorkerThreadFactory implements ForkJoinPool.ForkJoinWorkerThreadFactory { 18 | private final String namePrefix; 19 | private final AtomicLong threadNumber = new AtomicLong(1); 20 | 21 | public JCPPForkJoinWorkerThreadFactory(@NonNull String namePrefix) { 22 | this.namePrefix = namePrefix; 23 | } 24 | 25 | @Override 26 | public final ForkJoinWorkerThread newThread(ForkJoinPool pool) { 27 | ForkJoinWorkerThread thread = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool); 28 | thread.setContextClassLoader(this.getClass().getClassLoader()); 29 | thread.setName(namePrefix + "-" + thread.getPoolIndex() + "-" + threadNumber.getAndIncrement()); 30 | return thread; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/async/JCPPThreadFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.async; 8 | 9 | import com.google.common.util.concurrent.ThreadFactoryBuilder; 10 | 11 | import java.util.concurrent.ThreadFactory; 12 | 13 | public class JCPPThreadFactory { 14 | public static final String THREAD_TOPIC_SEPARATOR = " | "; 15 | 16 | public static ThreadFactory forName(String name) { 17 | return new ThreadFactoryBuilder() 18 | .setNameFormat(name) 19 | .setDaemon(true) 20 | .setPriority(Thread.NORM_PRIORITY) 21 | .build(); 22 | } 23 | 24 | public static ThreadFactory forName(String name, int priority) { 25 | return new ThreadFactoryBuilder() 26 | .setNameFormat(name) 27 | .setDaemon(true) 28 | .setPriority(priority) 29 | .build(); 30 | } 31 | public static void updateCurrentThreadName(String threadSuffix) { 32 | String name = Thread.currentThread().getName(); 33 | int spliteratorIndex = name.indexOf(THREAD_TOPIC_SEPARATOR); 34 | if (spliteratorIndex > 0) { 35 | name = name.substring(0, spliteratorIndex); 36 | } 37 | name = name + THREAD_TOPIC_SEPARATOR + threadSuffix; 38 | Thread.currentThread().setName(name); 39 | } 40 | 41 | public static void addThreadNamePrefix(String prefix) { 42 | String name = Thread.currentThread().getName(); 43 | name = prefix + "-" + name; 44 | Thread.currentThread().setName(name); 45 | } 46 | 47 | 48 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/async/JCPPVirtualThreadFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.async; 8 | 9 | import java.util.concurrent.ThreadFactory; 10 | import java.util.concurrent.atomic.AtomicLong; 11 | 12 | public class JCPPVirtualThreadFactory implements ThreadFactory { 13 | private final String namePrefix; 14 | private final AtomicLong threadNumber = new AtomicLong(1); 15 | 16 | public JCPPVirtualThreadFactory(String namePrefix) { 17 | this.namePrefix = namePrefix; 18 | } 19 | 20 | @Override 21 | public Thread newThread(Runnable r) { 22 | return Thread.ofVirtual().name(namePrefix + "-" + threadNumber.getAndIncrement()).unstarted(r); 23 | } 24 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/config/ScheduledTaskConfig.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.config; 8 | 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.scheduling.TaskScheduler; 12 | import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; 13 | 14 | @Configuration 15 | public class ScheduledTaskConfig { 16 | 17 | @Bean 18 | public TaskScheduler taskScheduler() { 19 | ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); 20 | scheduler.setPoolSize(Runtime.getRuntime().availableProcessors()); 21 | scheduler.setThreadNamePrefix("scheduled-task-"); 22 | scheduler.initialize(); 23 | return scheduler; 24 | } 25 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/config/ThreadPoolConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.config; 8 | 9 | import jakarta.annotation.PreDestroy; 10 | import org.springframework.context.annotation.Configuration; 11 | import sanbing.jcpp.infrastructure.util.async.JCPPExecutors; 12 | import sanbing.jcpp.infrastructure.util.async.JCPPThreadFactory; 13 | 14 | import java.util.concurrent.ExecutorService; 15 | import java.util.concurrent.Executors; 16 | import java.util.concurrent.ScheduledExecutorService; 17 | import java.util.concurrent.TimeUnit; 18 | 19 | /** 20 | * @author baigod 21 | */ 22 | @Configuration 23 | public class ThreadPoolConfiguration { 24 | 25 | public static final ExecutorService JCPP_COMMON_THREAD_POOL = JCPPExecutors.newVirtualThreadPool("jcpp-common-virtual"); 26 | 27 | public static final ScheduledExecutorService PROTOCOL_SESSION_SCHEDULED = Executors.newSingleThreadScheduledExecutor(JCPPThreadFactory.forName("protocol-session-schedule")); 28 | 29 | @PreDestroy 30 | public void destroy() { 31 | PROTOCOL_SESSION_SCHEDULED.shutdownNow(); 32 | 33 | JCPP_COMMON_THREAD_POOL.shutdown(); 34 | 35 | try { 36 | if (!JCPP_COMMON_THREAD_POOL.awaitTermination(5, TimeUnit.SECONDS)) { 37 | JCPP_COMMON_THREAD_POOL.shutdownNow(); 38 | } 39 | } catch (InterruptedException e) { 40 | JCPP_COMMON_THREAD_POOL.shutdownNow(); 41 | Thread.currentThread().interrupt(); 42 | } 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/exception/DataValidationException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.exception; 8 | 9 | public class DataValidationException extends RuntimeException { 10 | 11 | public DataValidationException(String message) { 12 | super(message); 13 | } 14 | 15 | public DataValidationException(String message, Throwable cause) { 16 | super(message, cause); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/exception/DownlinkException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.exception; 8 | 9 | /** 10 | * @author baigod 11 | */ 12 | public class DownlinkException extends RuntimeException { 13 | 14 | public DownlinkException(String message) { 15 | super(message); 16 | } 17 | 18 | public DownlinkException(String message, Throwable cause) { 19 | super(message, cause); 20 | } 21 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/exception/IncorrectParameterException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.exception; 8 | 9 | 10 | public class IncorrectParameterException extends RuntimeException { 11 | 12 | public IncorrectParameterException(String message) { 13 | super(message); 14 | } 15 | 16 | public IncorrectParameterException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/jackson/BigNumberSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.jackson; 8 | 9 | import com.fasterxml.jackson.core.JsonGenerator; 10 | import com.fasterxml.jackson.databind.SerializerProvider; 11 | import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; 12 | import com.fasterxml.jackson.databind.ser.std.NumberSerializer; 13 | 14 | import java.io.IOException; 15 | 16 | @JacksonStdImpl 17 | public class BigNumberSerializer extends NumberSerializer { 18 | 19 | private static final long JS_NUM_MAX = 9007199254740992L; 20 | private static final long JS_NUM_MIN = -9007199254740992L; 21 | public static final BigNumberSerializer instance = new BigNumberSerializer(Number.class); 22 | 23 | public BigNumberSerializer(Class rawType) { 24 | super(rawType); 25 | } 26 | 27 | @Override 28 | public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException { 29 | long longValue = value.longValue(); 30 | if (longValue >= JS_NUM_MIN && longValue <= JS_NUM_MAX) { 31 | super.serialize(value, gen, provider); 32 | } else { 33 | gen.writeString(value.toString()); 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/jackson/DateDeserializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.jackson; 8 | 9 | import com.fasterxml.jackson.core.JsonParser; 10 | import com.fasterxml.jackson.databind.DeserializationContext; 11 | import com.fasterxml.jackson.databind.JsonDeserializer; 12 | 13 | import java.io.IOException; 14 | import java.time.LocalDateTime; 15 | import java.time.ZoneOffset; 16 | import java.time.format.DateTimeFormatter; 17 | import java.util.Date; 18 | 19 | /** 20 | * 时间反序列化 21 | * 22 | * @author baigod 23 | */ 24 | public class DateDeserializer extends JsonDeserializer { 25 | public static final DateDeserializer INSTANCE = new DateDeserializer(); 26 | private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); 27 | private static final DateTimeFormatter DATE_TIME_FORMATTER_MS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); 28 | 29 | private DateDeserializer() { 30 | } 31 | 32 | @Override 33 | public Date deserialize(JsonParser p, DeserializationContext ctx) throws IOException { 34 | String dateString = p.getText(); 35 | 36 | return dateString.length() > 19 37 | ? Date.from(LocalDateTime.parse(dateString, DATE_TIME_FORMATTER_MS).atZone(ZoneOffset.systemDefault()).toInstant()) 38 | : Date.from(LocalDateTime.parse(dateString, DATE_TIME_FORMATTER).atZone(ZoneOffset.systemDefault()).toInstant()); 39 | } 40 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/jackson/DateSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.jackson; 8 | 9 | import com.fasterxml.jackson.core.JsonGenerator; 10 | import com.fasterxml.jackson.databind.SerializerProvider; 11 | import com.fasterxml.jackson.databind.ser.std.StdSerializer; 12 | import org.apache.commons.lang3.time.FastDateFormat; 13 | 14 | import java.io.IOException; 15 | import java.util.Date; 16 | 17 | /** 18 | * 时间序列化 19 | * 20 | * @author baigod 21 | */ 22 | public class DateSerializer extends StdSerializer { 23 | public static final DateSerializer INSTANCE = new DateSerializer(); 24 | private static final FastDateFormat FAST_DATE_FORMAT_MS = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS"); 25 | 26 | private DateSerializer() { 27 | super(Date.class); 28 | } 29 | 30 | @Override 31 | public void serialize(Date value, JsonGenerator gen, SerializerProvider provider) throws IOException { 32 | gen.writeString(FAST_DATE_FORMAT_MS.format(value)); 33 | } 34 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/jackson/InstantDeserializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.jackson; 8 | 9 | 10 | import com.fasterxml.jackson.core.JsonParser; 11 | import com.fasterxml.jackson.databind.DeserializationContext; 12 | import lombok.SneakyThrows; 13 | import org.apache.commons.lang3.time.FastDateFormat; 14 | 15 | import java.time.Instant; 16 | import java.time.format.DateTimeFormatter; 17 | 18 | /** 19 | * Instant 反序列化 20 | * 21 | * @author baigod 22 | */ 23 | public class InstantDeserializer extends com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer { 24 | public static final InstantDeserializer INSTANCE = new InstantDeserializer(); 25 | 26 | private final FastDateFormat FAST_DATE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss"); 27 | private final FastDateFormat FAST_DATE_FORMAT_MS = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS"); 28 | 29 | private InstantDeserializer() { 30 | super(InstantDeserializer.INSTANT, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")); 31 | } 32 | 33 | @SneakyThrows 34 | @Override 35 | public Instant deserialize(JsonParser parser, DeserializationContext context) { 36 | String timestamp = parser.getText(); 37 | 38 | return timestamp.length() > 19 39 | ? FAST_DATE_FORMAT_MS.parse(timestamp).toInstant() 40 | : FAST_DATE_FORMAT.parse(timestamp).toInstant(); 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/jackson/InstantSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.jackson; 8 | 9 | import java.time.format.DateTimeFormatter; 10 | 11 | /** 12 | * Instant 序列化 13 | * 14 | * @author baigod 15 | */ 16 | public class InstantSerializer extends com.fasterxml.jackson.datatype.jsr310.ser.InstantSerializer { 17 | public static final InstantSerializer INSTANCE = new InstantSerializer(); 18 | 19 | private InstantSerializer() { 20 | super(com.fasterxml.jackson.datatype.jsr310.ser.InstantSerializer.INSTANCE, true,false, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/jackson/LocalDateTimeDeserializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.jackson; 8 | 9 | import com.fasterxml.jackson.core.JsonParser; 10 | import com.fasterxml.jackson.databind.DeserializationContext; 11 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer; 12 | 13 | import java.io.IOException; 14 | import java.time.LocalDateTime; 15 | import java.time.format.DateTimeFormatter; 16 | 17 | /** 18 | * LocalDateTime类型反序列化 19 | * 需要用到的字段上加 @JsonDeserialize(using = LocalDateTimeDeserializer.class) 20 | */ 21 | public class LocalDateTimeDeserializer extends StdDeserializer { 22 | public static final LocalDateTimeDeserializer INSTANCE = new LocalDateTimeDeserializer(); 23 | 24 | private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); 25 | private static final DateTimeFormatter DATE_TIME_FORMATTER_MS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); 26 | 27 | private LocalDateTimeDeserializer() { 28 | super(LocalDateTime.class); 29 | } 30 | 31 | @Override 32 | public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext context) 33 | throws IOException { 34 | 35 | String dateString = jsonParser.getText(); 36 | return dateString.length() > 19 37 | ? LocalDateTime.parse(dateString, DATE_TIME_FORMATTER_MS) 38 | : LocalDateTime.parse(dateString, DATE_TIME_FORMATTER); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/jackson/LocalDateTimeSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.jackson; 8 | 9 | import com.fasterxml.jackson.core.JsonGenerator; 10 | import com.fasterxml.jackson.databind.JsonSerializer; 11 | import com.fasterxml.jackson.databind.SerializerProvider; 12 | 13 | import java.io.IOException; 14 | import java.time.LocalDateTime; 15 | import java.time.format.DateTimeFormatter; 16 | 17 | /** 18 | * 时间类型序列化工具 19 | * 20 | * @author baigod 21 | */ 22 | public class LocalDateTimeSerializer extends JsonSerializer { 23 | public static final LocalDateTimeSerializer INSTANCE = new LocalDateTimeSerializer(); 24 | 25 | private static final DateTimeFormatter DATE_TIME_FORMATTER_MS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); 26 | 27 | private LocalDateTimeSerializer() { 28 | } 29 | 30 | @Override 31 | public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException { 32 | gen.writeString(value.format(DATE_TIME_FORMATTER_MS)); 33 | } 34 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/jackson/LocalTimeDeserializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.jackson; 8 | 9 | import com.fasterxml.jackson.core.JsonParser; 10 | import com.fasterxml.jackson.databind.DeserializationContext; 11 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer; 12 | 13 | import java.io.IOException; 14 | import java.time.LocalDateTime; 15 | import java.time.LocalTime; 16 | import java.time.format.DateTimeFormatter; 17 | 18 | /** 19 | * LocalDateTime类型反序列化 20 | * 需要用到的字段上加 @JsonDeserialize(using = EnergyLocalTimeDeserializer.class) 21 | */ 22 | public class LocalTimeDeserializer extends StdDeserializer { 23 | public static final LocalTimeDeserializer INSTANCE = new LocalTimeDeserializer(); 24 | 25 | private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss"); 26 | private static final DateTimeFormatter DATE_TIME_FORMATTER_MS = DateTimeFormatter.ofPattern("HH:mm:ss.SSS"); 27 | 28 | 29 | private LocalTimeDeserializer() { 30 | super(LocalDateTime.class); 31 | } 32 | 33 | @Override 34 | public LocalTime deserialize(JsonParser jsonParser, DeserializationContext context) 35 | throws IOException { 36 | 37 | String dateString = jsonParser.getText(); 38 | return dateString.length() > 8 39 | ? LocalTime.parse(dateString, DATE_TIME_FORMATTER_MS) 40 | : LocalTime.parse(dateString, DATE_TIME_FORMATTER); 41 | 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/jackson/LocalTimeSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.jackson; 8 | 9 | import com.fasterxml.jackson.core.JsonGenerator; 10 | import com.fasterxml.jackson.databind.JsonSerializer; 11 | import com.fasterxml.jackson.databind.SerializerProvider; 12 | 13 | import java.io.IOException; 14 | import java.time.LocalTime; 15 | import java.time.format.DateTimeFormatter; 16 | 17 | /** 18 | * 时间类型序列化工具 19 | * 20 | * @author baigod 21 | */ 22 | public class LocalTimeSerializer extends JsonSerializer { 23 | public static final LocalTimeSerializer INSTANCE = new LocalTimeSerializer(); 24 | 25 | private LocalTimeSerializer() { 26 | } 27 | 28 | private static final DateTimeFormatter DATE_TIME_FORMATTER_MS = DateTimeFormatter.ofPattern("HH:mm:ss.SSS"); 29 | 30 | @Override 31 | public void serialize(LocalTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException { 32 | gen.writeString(value.format(DATE_TIME_FORMATTER_MS)); 33 | } 34 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/jackson/LongTimestampDeserializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.jackson; 8 | 9 | import com.fasterxml.jackson.core.JsonParser; 10 | import com.fasterxml.jackson.databind.DeserializationContext; 11 | import com.fasterxml.jackson.databind.JsonDeserializer; 12 | 13 | import java.io.IOException; 14 | import java.time.LocalDateTime; 15 | import java.time.ZoneId; 16 | 17 | /** 18 | * 13位时间戳反序列化器 19 | * @author baigod 20 | */ 21 | public class LongTimestampDeserializer extends JsonDeserializer { 22 | 23 | @Override 24 | public Long deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { 25 | 26 | // 判定是否是long类型 27 | if ("LONG".equals(jsonParser.getNumberType().name())) { 28 | return jsonParser.getLongValue(); 29 | } 30 | LocalDateTime localDateTime = LocalDateTime.parse(jsonParser.getValueAsString().replace(" ", "T").replace("Z", "")); 31 | ZoneId systemDefaultZone = ZoneId.systemDefault(); 32 | return localDateTime.atZone(systemDefaultZone).toInstant().toEpochMilli(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/jackson/SqlDateDeserializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.jackson; 8 | 9 | import com.fasterxml.jackson.core.JsonParser; 10 | import com.fasterxml.jackson.databind.DeserializationContext; 11 | import com.fasterxml.jackson.databind.JsonDeserializer; 12 | 13 | import java.io.IOException; 14 | import java.sql.Date; 15 | import java.time.LocalDateTime; 16 | import java.time.ZoneOffset; 17 | import java.time.format.DateTimeFormatter; 18 | 19 | /** 20 | * sqlDate 反序列化 21 | * 22 | * @author baigod 23 | */ 24 | public class SqlDateDeserializer extends JsonDeserializer { 25 | 26 | public static final SqlDateDeserializer INSTANCE = new SqlDateDeserializer(); 27 | private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); 28 | private static final DateTimeFormatter DATE_TIME_FORMATTER_MS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); 29 | 30 | private SqlDateDeserializer() { 31 | } 32 | 33 | @Override 34 | public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { 35 | String dateString = p.getText(); 36 | 37 | return dateString.length() > 19 38 | ? new Date(LocalDateTime.parse(dateString, DATE_TIME_FORMATTER_MS).atZone(ZoneOffset.systemDefault()).toInstant().toEpochMilli()) 39 | : new Date(LocalDateTime.parse(dateString, DATE_TIME_FORMATTER).atZone(ZoneOffset.systemDefault()).toInstant().toEpochMilli()); 40 | } 41 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/jackson/SqlDateSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.jackson; 8 | 9 | import com.fasterxml.jackson.core.JsonGenerator; 10 | import com.fasterxml.jackson.databind.SerializerProvider; 11 | import com.fasterxml.jackson.databind.ser.std.StdSerializer; 12 | import org.apache.commons.lang3.time.FastDateFormat; 13 | 14 | import java.io.IOException; 15 | import java.sql.Date; 16 | 17 | /** 18 | * sqlDate序列化 19 | * 20 | * @author baigod 21 | */ 22 | public class SqlDateSerializer extends StdSerializer { 23 | public static final SqlDateSerializer INSTANCE = new SqlDateSerializer(); 24 | 25 | private static final FastDateFormat FAST_DATE_FORMAT_MS = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS"); 26 | 27 | private SqlDateSerializer() { 28 | super(Date.class); 29 | } 30 | 31 | @Override 32 | public void serialize(Date value, JsonGenerator gen, SerializerProvider provider) throws IOException { 33 | gen.writeString(FAST_DATE_FORMAT_MS.format(value)); 34 | } 35 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/jackson/TimestampDeserializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.jackson; 8 | 9 | import com.fasterxml.jackson.core.JsonParser; 10 | import com.fasterxml.jackson.databind.DeserializationContext; 11 | import com.fasterxml.jackson.databind.JsonDeserializer; 12 | 13 | import java.io.IOException; 14 | import java.sql.Timestamp; 15 | import java.time.LocalDateTime; 16 | import java.time.ZoneOffset; 17 | import java.time.format.DateTimeFormatter; 18 | 19 | /** 20 | * timestamp 反序列化 21 | * @author baigod 22 | */ 23 | public class TimestampDeserializer extends JsonDeserializer { 24 | 25 | public static final TimestampDeserializer INSTANCE = new TimestampDeserializer(); 26 | private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); 27 | private static final DateTimeFormatter DATE_TIME_FORMATTER_MS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); 28 | 29 | private TimestampDeserializer() { 30 | } 31 | 32 | @Override 33 | public Timestamp deserialize(JsonParser p, DeserializationContext ctx) throws IOException { 34 | String dateString = p.getText(); 35 | 36 | return dateString.length() > 19 37 | ? Timestamp.from(LocalDateTime.parse(dateString, DATE_TIME_FORMATTER_MS).atZone(ZoneOffset.systemDefault()).toInstant()) 38 | : Timestamp.from(LocalDateTime.parse(dateString, DATE_TIME_FORMATTER).atZone(ZoneOffset.systemDefault()).toInstant()); 39 | } 40 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/jackson/TimestampSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.jackson; 8 | 9 | import com.fasterxml.jackson.core.JsonGenerator; 10 | import com.fasterxml.jackson.databind.SerializerProvider; 11 | import com.fasterxml.jackson.databind.ser.std.StdSerializer; 12 | import org.apache.commons.lang3.time.FastDateFormat; 13 | 14 | import java.io.IOException; 15 | import java.sql.Timestamp; 16 | 17 | /** 18 | * timestamp 序列化 19 | * 20 | * @author baigod 21 | */ 22 | public class TimestampSerializer extends StdSerializer { 23 | public static final TimestampSerializer INSTANCE = new TimestampSerializer(); 24 | 25 | private static final FastDateFormat FAST_DATE_FORMAT_MS = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS"); 26 | 27 | private TimestampSerializer() { 28 | super(Timestamp.class); 29 | } 30 | 31 | @Override 32 | public void serialize(Timestamp value, JsonGenerator gen, SerializerProvider provider) throws IOException { 33 | gen.writeString(FAST_DATE_FORMAT_MS.format(value)); 34 | } 35 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/mdc/MDCUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.mdc; 8 | 9 | import org.apache.commons.lang3.StringUtils; 10 | import org.slf4j.MDC; 11 | import sanbing.jcpp.infrastructure.util.trace.Tracer; 12 | import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil; 13 | 14 | 15 | public class MDCUtils { 16 | 17 | private static final String TRACE_ID = "TRACE_ID"; 18 | 19 | public static String putIfAbsentTracer() { 20 | String traceId = MDC.get(TRACE_ID); 21 | 22 | if (StringUtils.isEmpty(traceId)) { 23 | return recordTracer(); 24 | } 25 | 26 | return traceId; 27 | } 28 | 29 | public static String recordTracer() { 30 | Tracer tracer = TracerContextUtil.getCurrentTracer(); 31 | 32 | if (!StringUtils.isEmpty(tracer.getTraceId())) { 33 | MDC.put(TRACE_ID, tracer.getTraceId()); 34 | } else { 35 | MDC.remove(TRACE_ID); 36 | } 37 | 38 | return tracer.getTraceId(); 39 | } 40 | 41 | public static void cleanTracer() { 42 | MDC.remove(TRACE_ID); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/property/JCPPProperty.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.property; 8 | 9 | import lombok.Data; 10 | 11 | @Data 12 | public class JCPPProperty { 13 | 14 | private String key; 15 | private String value; 16 | } 17 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/property/PropertyUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.property; 8 | 9 | 10 | import org.apache.commons.lang3.StringUtils; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | import java.util.function.Function; 15 | 16 | public class PropertyUtils { 17 | 18 | public static Map getProps(String properties) { 19 | Map configs = new HashMap<>(); 20 | if (StringUtils.isNotEmpty(properties)) { 21 | for (String property : properties.split(";")) { 22 | if (StringUtils.isNotEmpty(property)) { 23 | int delimiterPosition = property.indexOf(":"); 24 | String key = property.substring(0, delimiterPosition); 25 | String value = property.substring(delimiterPosition + 1); 26 | configs.put(key, value); 27 | } 28 | } 29 | } 30 | return configs; 31 | } 32 | 33 | public static Map getProps(Map defaultProperties, String propertiesStr) { 34 | return getProps(defaultProperties, propertiesStr, PropertyUtils::getProps); 35 | } 36 | 37 | public static Map getProps(Map defaultProperties, String propertiesStr, Function> parser) { 38 | Map properties = defaultProperties; 39 | if (StringUtils.isNotBlank(propertiesStr)) { 40 | properties = new HashMap<>(properties); 41 | properties.putAll(parser.apply(propertiesStr)); 42 | } 43 | return properties; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/trace/Tracer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.trace; 8 | 9 | import lombok.Data; 10 | 11 | import java.io.Serializable; 12 | 13 | @Data 14 | public class Tracer implements Serializable { 15 | 16 | private String traceId; 17 | 18 | private String origin; 19 | 20 | private final long tracerTs; 21 | 22 | public Tracer(String traceId, String origin) { 23 | this.traceId = traceId; 24 | this.origin = origin; 25 | this.tracerTs = System.currentTimeMillis(); 26 | } 27 | 28 | public Tracer(String traceId, String origin, long tracerTs) { 29 | this.traceId = traceId; 30 | this.origin = origin; 31 | this.tracerTs = tracerTs; 32 | } 33 | 34 | public Tracer(String traceId, long tracerTs) { 35 | this.traceId = traceId; 36 | this.origin = "JCPP"; 37 | this.tracerTs = tracerTs; 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/trace/TracerCallable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.trace; 8 | 9 | 10 | import sanbing.jcpp.infrastructure.util.mdc.MDCUtils; 11 | 12 | import java.util.concurrent.Callable; 13 | 14 | public class TracerCallable implements Callable { 15 | 16 | private Tracer tracer; 17 | private final Callable callable; 18 | 19 | public TracerCallable(Callable callable) { 20 | this.tracer = TracerContextUtil.getCurrentTracer(); 21 | this.callable = callable; 22 | } 23 | 24 | @Override 25 | public T call() throws Exception { 26 | try { 27 | if (this.tracer != null) { 28 | TracerContextUtil.newTracer(tracer.getTraceId(), tracer.getOrigin(), tracer.getTracerTs()); 29 | 30 | MDCUtils.recordTracer(); 31 | } 32 | 33 | return this.callable.call(); 34 | } finally { 35 | TracerContextUtil.cleanTracer(); 36 | 37 | MDCUtils.cleanTracer(); 38 | 39 | this.tracer = null; 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/trace/TracerRunnable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.trace; 8 | 9 | 10 | import sanbing.jcpp.infrastructure.util.mdc.MDCUtils; 11 | 12 | public class TracerRunnable implements Runnable { 13 | 14 | private Tracer tracer; 15 | private final Runnable runnable; 16 | 17 | public TracerRunnable(Runnable runnable) { 18 | this.tracer = TracerContextUtil.getCurrentTracer(); 19 | this.runnable = runnable; 20 | } 21 | 22 | @Override 23 | public void run() { 24 | try { 25 | if (this.tracer != null) { 26 | TracerContextUtil.newTracer(tracer.getTraceId(), tracer.getOrigin(), tracer.getTracerTs()); 27 | 28 | MDCUtils.recordTracer(); 29 | } 30 | 31 | this.runnable.run(); 32 | } finally { 33 | TracerContextUtil.cleanTracer(); 34 | 35 | MDCUtils.cleanTracer(); 36 | 37 | this.tracer = null; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/validation/Length.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.validation; 8 | 9 | import jakarta.validation.Constraint; 10 | import jakarta.validation.Payload; 11 | 12 | import java.lang.annotation.ElementType; 13 | import java.lang.annotation.Retention; 14 | import java.lang.annotation.RetentionPolicy; 15 | import java.lang.annotation.Target; 16 | 17 | @Retention(RetentionPolicy.RUNTIME) 18 | @Target({ElementType.FIELD, ElementType.METHOD}) 19 | @Constraint(validatedBy = {}) 20 | public @interface Length { 21 | String message() default "length must be equal or less than {max}"; 22 | 23 | String fieldName() default ""; 24 | 25 | int max() default 255; 26 | 27 | Class[] groups() default {}; 28 | 29 | Class[] payload() default {}; 30 | } 31 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/validation/StringLengthValidator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.validation; 8 | 9 | import com.fasterxml.jackson.databind.JsonNode; 10 | import jakarta.validation.ConstraintValidator; 11 | import jakarta.validation.ConstraintValidatorContext; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.apache.commons.lang3.StringUtils; 14 | 15 | @Slf4j 16 | public class StringLengthValidator implements ConstraintValidator { 17 | private int max; 18 | 19 | @Override 20 | public boolean isValid(Object value, ConstraintValidatorContext context) { 21 | String stringValue; 22 | if (value instanceof CharSequence || value instanceof JsonNode) { 23 | stringValue = value.toString(); 24 | } else { 25 | return true; 26 | } 27 | if (StringUtils.isEmpty(stringValue)) { 28 | return true; 29 | } 30 | return stringValue.length() <= max; 31 | } 32 | 33 | @Override 34 | public void initialize(Length constraintAnnotation) { 35 | this.max = constraintAnnotation.max(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/validation/Validator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.validation; 8 | 9 | import sanbing.jcpp.infrastructure.util.exception.IncorrectParameterException; 10 | 11 | import java.util.UUID; 12 | import java.util.function.Function; 13 | 14 | public class Validator { 15 | 16 | public static void validateString(String val, String errorMessage) { 17 | if (val == null || val.isEmpty()) { 18 | throw new IncorrectParameterException(errorMessage); 19 | } 20 | } 21 | 22 | public static void validateString(String val, Function errorMessageFunction) { 23 | if (val == null || val.isEmpty()) { 24 | throw new IncorrectParameterException(errorMessageFunction.apply(val)); 25 | } 26 | } 27 | 28 | public static void validatePositiveNumber(long val, String errorMessage) { 29 | if (val <= 0) { 30 | throw new IncorrectParameterException(errorMessage); 31 | } 32 | } 33 | 34 | public static void validateId(UUID id, Function errorMessageFunction) { 35 | if (id == null) { 36 | throw new IncorrectParameterException(errorMessageFunction.apply(id)); 37 | } 38 | } 39 | 40 | public static void checkNotNull(Object reference, String errorMessage) { 41 | if (reference == null) { 42 | throw new IncorrectParameterException(errorMessage); 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/test/java/sanbing/jcpp/infrastructure/util/async/JCPPExecutorsTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.async; 8 | 9 | import org.junit.jupiter.api.Test; 10 | import org.slf4j.MDC; 11 | import sanbing.jcpp.infrastructure.util.mdc.MDCUtils; 12 | import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil; 13 | import sanbing.jcpp.infrastructure.util.trace.TracerRunnable; 14 | 15 | import java.util.concurrent.ExecutorService; 16 | 17 | class JCPPExecutorsTest { 18 | 19 | @Test 20 | void newVirtualThreadPool() { 21 | ExecutorService executorService = JCPPExecutors.newVirtualThreadPool("test-consumer-virtual"); 22 | 23 | TracerContextUtil.newTracer(); 24 | MDCUtils.recordTracer(); 25 | 26 | System.out.println(MDC.get("TRACE_ID")); 27 | 28 | executorService.submit(new TracerRunnable(() -> { 29 | System.out.println(MDC.get("TRACE_ID")); 30 | })); 31 | } 32 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/test/java/sanbing/jcpp/infrastructure/util/codec/BCDUtilTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.codec; 8 | 9 | import cn.hutool.core.util.HexUtil; 10 | import org.junit.jupiter.api.Test; 11 | 12 | import static org.junit.jupiter.api.Assertions.assertArrayEquals; 13 | 14 | class BCDUtilTest { 15 | 16 | @Test 17 | void toBytesTest() { 18 | String pileCodeHex = "20231212000010"; 19 | 20 | byte[] bytes = HexUtil.decodeHex(pileCodeHex); 21 | 22 | String pileCode = BCDUtil.toString(bytes); 23 | 24 | assert pileCodeHex.equals(pileCode); 25 | 26 | byte[] pileCodeBytes = BCDUtil.toBytes(pileCodeHex); 27 | 28 | assertArrayEquals(pileCodeBytes, bytes); 29 | } 30 | } -------------------------------------------------------------------------------- /jcpp-infrastructure-util/src/test/java/sanbing/jcpp/infrastructure/util/codec/CP56Time2aUtilTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.infrastructure.util.codec; 8 | 9 | import cn.hutool.core.util.HexUtil; 10 | import org.junit.jupiter.api.Test; 11 | 12 | import java.time.LocalDateTime; 13 | import java.time.ZoneId; 14 | import java.util.Arrays; 15 | 16 | class CP56Time2aUtilTest { 17 | 18 | @Test 19 | void encodeTest() { 20 | LocalDateTime time = LocalDateTime.of(2025, 1, 22, 14, 30, 45, 123_000_000); 21 | 22 | byte[] bytes = CP56Time2aUtil.encode(time); 23 | 24 | System.out.println(Arrays.toString(bytes)); 25 | System.out.println(HexUtil.encodeHex(bytes)); 26 | System.out.println(time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); 27 | 28 | LocalDateTime decode = CP56Time2aUtil.decode(bytes); 29 | System.out.println(decode.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); 30 | 31 | assert time.equals(decode); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 13 | 14 | sanbing 15 | jcpp-parent 16 | 1.0.0-SNAPSHOT 17 | ../pom.xml 18 | 19 | 4.0.0 20 | 21 | jcpp-protocol-api 22 | jar 23 | JChargePointProtocol Protocol Api Module 24 | 协议API 25 | 26 | 27 | ${basedir}/.. 28 | 29 | 30 | 31 | 32 | sanbing 33 | jcpp-infrastructure-util 34 | 35 | 36 | sanbing 37 | jcpp-infrastructure-queue 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-reactor-netty 42 | 43 | 44 | com.github.ben-manes.caffeine 45 | caffeine 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/config/TracerInterceptor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.adapter.config; 8 | 9 | import jakarta.servlet.http.HttpServletRequest; 10 | import jakarta.servlet.http.HttpServletResponse; 11 | import org.springframework.stereotype.Component; 12 | import org.springframework.web.servlet.HandlerInterceptor; 13 | import sanbing.jcpp.infrastructure.util.mdc.MDCUtils; 14 | import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil; 15 | 16 | import static sanbing.jcpp.infrastructure.util.trace.TracerContextUtil.*; 17 | 18 | @Component 19 | public class TracerInterceptor implements HandlerInterceptor { 20 | 21 | @Override 22 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { 23 | String tracerId = request.getHeader(JCPP_TRACER_ID); 24 | String tracerOrigin = request.getHeader(JCPP_TRACER_ORIGIN); 25 | String tracerTsStr = request.getHeader(JCPP_TRACER_TS); 26 | 27 | long tracerTs; 28 | if (tracerTsStr != null) { 29 | try { 30 | tracerTs = Long.parseLong(tracerTsStr); 31 | } catch (NumberFormatException e) { 32 | tracerTs = System.currentTimeMillis(); 33 | } 34 | } else { 35 | tracerTs = System.currentTimeMillis(); 36 | } 37 | 38 | TracerContextUtil.newTracer(tracerId, tracerOrigin, tracerTs); 39 | MDCUtils.recordTracer(); 40 | 41 | return true; 42 | } 43 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/config/UndertowServletWebServerCustomizer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.adapter.config; 8 | 9 | import io.undertow.server.DefaultByteBufferPool; 10 | import io.undertow.websockets.jsr.WebSocketDeploymentInfo; 11 | import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; 12 | import org.springframework.boot.web.server.WebServerFactoryCustomizer; 13 | import org.springframework.stereotype.Component; 14 | 15 | 16 | @Component 17 | public class UndertowServletWebServerCustomizer implements WebServerFactoryCustomizer { 18 | @Override 19 | public void customize(UndertowServletWebServerFactory factory) { 20 | factory.addDeploymentInfoCustomizers(deploymentInfo -> { 21 | WebSocketDeploymentInfo webSocketDeploymentInfo = new WebSocketDeploymentInfo(); 22 | webSocketDeploymentInfo.setBuffers(new DefaultByteBufferPool(true, 128 * 1024 * 1024)); 23 | deploymentInfo.addServletContextAttribute("io.undertow.websockets.jsr.WebSocketDeploymentInfo", webSocketDeploymentInfo); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/config/WebMvcConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.adapter.config; 8 | 9 | import jakarta.annotation.Resource; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.http.converter.HttpMessageConverter; 12 | import org.springframework.http.converter.StringHttpMessageConverter; 13 | import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; 14 | import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter; 15 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 16 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 17 | 18 | import java.nio.charset.StandardCharsets; 19 | import java.util.List; 20 | 21 | @Configuration 22 | public class WebMvcConfiguration implements WebMvcConfigurer { 23 | 24 | @Resource 25 | private TracerInterceptor tracerInterceptor; 26 | 27 | @Override 28 | public void configureMessageConverters(List> converters) { 29 | for (HttpMessageConverter converter : converters) { 30 | if (converter instanceof StringHttpMessageConverter) { 31 | ((StringHttpMessageConverter) converter).setDefaultCharset(StandardCharsets.UTF_8); 32 | } 33 | 34 | if (converter instanceof MappingJackson2HttpMessageConverter) { 35 | ((MappingJackson2HttpMessageConverter) converter).setDefaultCharset(StandardCharsets.UTF_8); 36 | } 37 | } 38 | 39 | // protobuf 序列化 40 | converters.add( new ProtobufHttpMessageConverter()); 41 | } 42 | 43 | @Override 44 | public void addInterceptors(InterceptorRegistry registry) { 45 | registry.addInterceptor(tracerInterceptor).addPathPatterns("/**"); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/cfg/ForwarderCfg.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.cfg; 8 | 9 | import jakarta.validation.Valid; 10 | import jakarta.validation.constraints.NotNull; 11 | import lombok.Getter; 12 | import lombok.Setter; 13 | import sanbing.jcpp.protocol.cfg.enums.ForwarderType; 14 | 15 | @Setter 16 | @Getter 17 | public class ForwarderCfg { 18 | 19 | @NotNull 20 | private ForwarderType type; 21 | 22 | private MemoryCfg memory; 23 | 24 | @Valid 25 | private KafkaCfg kafka; 26 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/cfg/KafkaCfg.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.cfg; 8 | 9 | import lombok.Getter; 10 | import lombok.Setter; 11 | import sanbing.jcpp.infrastructure.util.property.PropertyUtils; 12 | 13 | import java.util.Map; 14 | 15 | @Getter 16 | @Setter 17 | public class KafkaCfg { 18 | 19 | private String topic; 20 | 21 | private boolean jcppPartition; 22 | 23 | private String bootstrapServers; 24 | 25 | private String acks; 26 | 27 | private EncoderType encoder; 28 | 29 | private int retries; 30 | 31 | private String compressionType; // none, gzip, snappy, lz4, zstd 32 | 33 | private int batchSize; 34 | 35 | private int lingerMs; 36 | 37 | private long bufferMemory; 38 | 39 | private Map otherProperties; // Other inline properties if necessary 40 | 41 | private String topicProperties; 42 | 43 | public void setOtherProperties(String otherProperties) { 44 | this.otherProperties = PropertyUtils.getProps(otherProperties); 45 | } 46 | 47 | public enum EncoderType { 48 | protobuf, 49 | json 50 | } 51 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/cfg/ListenerCfg.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.cfg; 8 | 9 | import jakarta.validation.Valid; 10 | import lombok.Getter; 11 | import lombok.Setter; 12 | 13 | @Getter 14 | @Setter 15 | public class ListenerCfg { 16 | 17 | @Valid 18 | private TcpCfg tcp; 19 | } 20 | -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/cfg/MemoryCfg.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.cfg; 8 | 9 | import lombok.Getter; 10 | import lombok.Setter; 11 | 12 | /** 13 | * @author baigod 14 | */ 15 | @Getter 16 | @Setter 17 | public class MemoryCfg { 18 | 19 | private String topic; 20 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/cfg/ProtocolCfg.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.cfg; 8 | 9 | import jakarta.validation.Valid; 10 | import jakarta.validation.constraints.NotNull; 11 | import lombok.Getter; 12 | import lombok.Setter; 13 | 14 | @Getter 15 | @Setter 16 | public class ProtocolCfg { 17 | 18 | private boolean enabled; 19 | 20 | @NotNull 21 | @Valid 22 | private ListenerCfg listener; 23 | 24 | @NotNull 25 | @Valid 26 | private ForwarderCfg forwarder; 27 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/cfg/TcpCfg.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.cfg; 8 | 9 | import jakarta.validation.Valid; 10 | import jakarta.validation.constraints.Max; 11 | import jakarta.validation.constraints.Min; 12 | import lombok.Getter; 13 | import lombok.Setter; 14 | 15 | @Getter 16 | @Setter 17 | public class TcpCfg { 18 | 19 | private String bindAddress; 20 | 21 | @Max(65000) 22 | private int bindPort; 23 | 24 | @Min(1) 25 | private int bossGroupThreadCount; 26 | 27 | @Min(1) 28 | private int workerGroupThreadCount; 29 | 30 | private boolean soKeepAlive; 31 | 32 | @Min(1) 33 | @Max(65500) 34 | private int soBacklog; 35 | 36 | @Min(1) 37 | private int soRcvbuf; 38 | 39 | @Min(1) 40 | private int soSndbuf; 41 | 42 | private boolean nodelay; 43 | 44 | @Valid 45 | private TcpHandlerCfg handler; 46 | 47 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/cfg/enums/ForwarderType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.cfg.enums; 8 | 9 | public enum ForwarderType { 10 | 11 | memory, // 本地队列模式 12 | 13 | kafka // Kafka模式 - 发送到外部 14 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/cfg/enums/TcpHandlerType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.cfg.enums; 8 | 9 | /** 10 | * @author baigod 11 | */ 12 | public enum TcpHandlerType { 13 | TEXT, 14 | BINARY, 15 | JSON 16 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/DownlinkCmdEnum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.domain; 8 | 9 | /** 10 | * @author baigod 11 | */ 12 | public enum DownlinkCmdEnum { 13 | 14 | LOGIN_ACK, 15 | 16 | VERIFY_PRICING_ACK, 17 | 18 | QUERY_PRICING_ACK, 19 | 20 | SET_PRICING, 21 | 22 | REMOTE_START_CHARGING, 23 | 24 | TRANSACTION_RECORD, 25 | 26 | REMOTE_PARALLEL_START_CHARGING, 27 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/ListenerToHandlerMsg.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.domain; 8 | 9 | import java.util.UUID; 10 | 11 | public record ListenerToHandlerMsg(UUID id, byte[] msg, ProtocolSession session) { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/ProtocolUplinkMsg.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.domain; 8 | 9 | import io.netty.buffer.ByteBufUtil; 10 | 11 | import java.net.SocketAddress; 12 | import java.util.UUID; 13 | 14 | public record ProtocolUplinkMsg(SocketAddress address, UUID id, T data, int size) { 15 | 16 | @Override 17 | public String toString() { 18 | if (data instanceof byte[] bytes) { 19 | return ByteBufUtil.hexDump(bytes); 20 | } else { 21 | return data.toString(); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/SessionCloseReason.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.domain; 8 | 9 | /** 10 | * @author baigod 11 | */ 12 | public enum SessionCloseReason { 13 | /** 14 | * 自然销毁 15 | */ 16 | DESTRUCTION, 17 | 18 | /** 19 | * 失活 20 | */ 21 | INACTIVE, 22 | 23 | /** 24 | * 手动销毁 25 | */ 26 | MANUALLY 27 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/SessionToHandlerMsg.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.domain; 8 | 9 | import sanbing.jcpp.proto.gen.ProtocolProto.DownlinkRequestMessage; 10 | 11 | /** 12 | * @author baigod 13 | */ 14 | public record SessionToHandlerMsg(DownlinkRequestMessage downlinkMsg, ProtocolSession session) { 15 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/ChannelHandlerParameter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.listener; 8 | 9 | import io.micrometer.core.instrument.Timer; 10 | import sanbing.jcpp.infrastructure.stats.MessagesStats; 11 | import sanbing.jcpp.protocol.ProtocolMessageProcessor; 12 | 13 | import java.util.concurrent.atomic.AtomicInteger; 14 | 15 | public record ChannelHandlerParameter(String protocolName, 16 | ProtocolMessageProcessor protocolMessageProcessor, 17 | AtomicInteger connectionsGauge, 18 | MessagesStats uplinkMsgStats, 19 | MessagesStats downlinkMsgStats, 20 | Timer downlinkTimer) { 21 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/configs/BinaryHandlerConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.listener.tcp.configs; 8 | 9 | import io.netty.handler.codec.ByteToMessageDecoder; 10 | import lombok.Data; 11 | import lombok.EqualsAndHashCode; 12 | import lombok.ToString; 13 | import sanbing.jcpp.protocol.cfg.enums.TcpHandlerType; 14 | 15 | import static sanbing.jcpp.protocol.cfg.enums.TcpHandlerType.BINARY; 16 | 17 | @Data 18 | @ToString 19 | @EqualsAndHashCode 20 | public class BinaryHandlerConfiguration implements HandlerConfiguration { 21 | public static final String LITTLE_ENDIAN_BYTE_ORDER = "LITTLE_ENDIAN"; 22 | 23 | /** 24 | * 拆包器 25 | */ 26 | private Class decoder; 27 | 28 | /** 29 | * 大小端(共用) 30 | */ 31 | private String byteOrder; 32 | 33 | /** 34 | * 起始域HEX字符串 35 | */ 36 | private String head; 37 | 38 | /** 39 | * 结束域(HeadTailFrameDecoder) 40 | */ 41 | private String tail; 42 | 43 | /** 44 | * 最大帧长(LengthFieldBasedFrameDecoder) 45 | */ 46 | private int maxFrameLength; 47 | 48 | /** 49 | * 长度域位置(共用) 50 | */ 51 | private int lengthFieldOffset; 52 | 53 | /** 54 | * 长度域长度(共用) 55 | */ 56 | private int lengthFieldLength; 57 | 58 | /** 59 | * 长度调整(共用) 60 | */ 61 | private int lengthAdjustment; 62 | 63 | /** 64 | * 初始跳过字节数(共用) 65 | */ 66 | private int initialBytesToStrip; 67 | 68 | /** 69 | * 快速失败(LengthFieldBasedFrameDecoder) 70 | */ 71 | private boolean failFast; 72 | 73 | public TcpHandlerType getType() { 74 | return BINARY; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/configs/HandlerConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.listener.tcp.configs; 8 | 9 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 10 | import com.fasterxml.jackson.annotation.JsonSubTypes; 11 | import com.fasterxml.jackson.annotation.JsonSubTypes.Type; 12 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 13 | import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; 14 | import sanbing.jcpp.protocol.cfg.enums.TcpHandlerType; 15 | 16 | @JsonTypeInfo( 17 | use = Id.NAME, 18 | property = "type" 19 | ) 20 | @JsonSubTypes({ 21 | @Type( 22 | value = TextHandlerConfiguration.class, 23 | name = "TEXT" 24 | ), 25 | @Type( 26 | value = BinaryHandlerConfiguration.class, 27 | name = "BINARY" 28 | ), 29 | @Type( 30 | value = JsonHandlerConfiguration.class, 31 | name = "JSON" 32 | ) 33 | }) 34 | @JsonIgnoreProperties( 35 | ignoreUnknown = true 36 | ) 37 | public interface HandlerConfiguration { 38 | TcpHandlerType getType(); 39 | } 40 | -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/configs/JsonHandlerConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.listener.tcp.configs; 8 | 9 | import lombok.Data; 10 | import lombok.EqualsAndHashCode; 11 | import lombok.ToString; 12 | import sanbing.jcpp.protocol.cfg.enums.TcpHandlerType; 13 | 14 | import static sanbing.jcpp.protocol.cfg.enums.TcpHandlerType.JSON; 15 | 16 | @Data 17 | @ToString 18 | @EqualsAndHashCode 19 | public class JsonHandlerConfiguration implements HandlerConfiguration { 20 | public TcpHandlerType getType() { 21 | return JSON; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/configs/TextHandlerConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.listener.tcp.configs; 8 | 9 | import lombok.Data; 10 | import lombok.EqualsAndHashCode; 11 | import lombok.ToString; 12 | import sanbing.jcpp.protocol.cfg.enums.TcpHandlerType; 13 | 14 | import static sanbing.jcpp.protocol.cfg.enums.TcpHandlerType.TEXT; 15 | 16 | @Data 17 | @ToString 18 | @EqualsAndHashCode 19 | public class TextHandlerConfiguration implements HandlerConfiguration { 20 | public static final String SYSTEM_LINE_SEPARATOR = "SYSTEM_LINE_SEPARATOR"; 21 | 22 | private int maxFrameLength; 23 | 24 | private boolean stripDelimiter; 25 | 26 | private String messageSeparator; 27 | 28 | private String charsetName; 29 | 30 | public TcpHandlerType getType() { 31 | return TEXT; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/decoder/TcpMsgDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.listener.tcp.decoder; 8 | 9 | import com.fasterxml.jackson.databind.JsonNode; 10 | import io.netty.buffer.ByteBuf; 11 | import io.netty.channel.ChannelHandlerContext; 12 | import io.netty.handler.codec.MessageToMessageDecoder; 13 | import lombok.RequiredArgsConstructor; 14 | import lombok.extern.slf4j.Slf4j; 15 | import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil; 16 | import sanbing.jcpp.protocol.domain.ProtocolUplinkMsg; 17 | 18 | import java.nio.charset.Charset; 19 | import java.util.List; 20 | import java.util.UUID; 21 | import java.util.function.Function; 22 | 23 | @RequiredArgsConstructor 24 | @Slf4j 25 | public class TcpMsgDecoder extends MessageToMessageDecoder { 26 | private final String protocolName; 27 | private final Function transformer; 28 | 29 | @Override 30 | public void decode(ChannelHandlerContext ctx, ByteBuf msg, List out) { 31 | try { 32 | out.add(new ProtocolUplinkMsg<>(ctx.pipeline().channel().remoteAddress(), UUID.randomUUID(), this.transformer.apply(msg), msg.readableBytes())); 33 | } catch (Exception e) { 34 | log.error("[{}][{}] Exception during of decoding message", protocolName, ctx.channel(), e); 35 | throw new RuntimeException(e); 36 | } 37 | } 38 | 39 | public static byte[] toByteArray(ByteBuf buffer) { 40 | byte[] bytes = new byte[buffer.readableBytes()]; 41 | buffer.readBytes(bytes); 42 | return bytes; 43 | } 44 | 45 | public static String toString(ByteBuf buffer, String charsetName) { 46 | return buffer.toString(Charset.forName(charsetName)); 47 | } 48 | 49 | public static JsonNode toJson(ByteBuf buffer) { 50 | return JacksonUtil.fromBytes(toByteArray(buffer)); 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/enums/ReadAct.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.listener.tcp.enums; 8 | 9 | /** 10 | * 读取动作,辅助枚举 11 | * 12 | * @author baigod 13 | */ 14 | public enum ReadAct { 15 | BREAK, 16 | CONTINUE 17 | } 18 | -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/enums/SequenceNumberLength.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.listener.tcp.enums; 8 | 9 | /** 10 | * @author baigod 11 | */ 12 | public enum SequenceNumberLength { 13 | 14 | // 1字节 15 | BYTE, 16 | 17 | // 2字节 18 | SHORT, 19 | 20 | // 4字节 21 | INT, 22 | 23 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/handler/IdleEventHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.listener.tcp.handler; 8 | 9 | import io.netty.channel.ChannelHandlerContext; 10 | import io.netty.channel.ChannelInboundHandlerAdapter; 11 | import io.netty.handler.timeout.IdleState; 12 | import io.netty.handler.timeout.IdleStateEvent; 13 | import lombok.RequiredArgsConstructor; 14 | import lombok.extern.slf4j.Slf4j; 15 | 16 | /** 17 | * 心跳检测 18 | * 19 | * @author baigod 20 | */ 21 | @Slf4j 22 | @RequiredArgsConstructor 23 | public class IdleEventHandler extends ChannelInboundHandlerAdapter { 24 | 25 | private final String protocolName; 26 | 27 | @Override 28 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { 29 | if (evt instanceof IdleStateEvent event) { 30 | if (event.state() == IdleState.READER_IDLE) { 31 | ctx.close(); 32 | log.info("[{}]{} 检测到空闲连接,连接关闭", protocolName, ctx.channel()); 33 | } 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/handler/TracerHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.listener.tcp.handler; 8 | 9 | import io.netty.channel.ChannelHandlerContext; 10 | import io.netty.channel.ChannelInboundHandlerAdapter; 11 | import sanbing.jcpp.infrastructure.util.mdc.MDCUtils; 12 | import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil; 13 | 14 | /** 15 | * @author baigod 16 | */ 17 | public class TracerHandler extends ChannelInboundHandlerAdapter { 18 | @Override 19 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 20 | 21 | TracerContextUtil.newTracer("jcpp-protocol"); 22 | 23 | MDCUtils.recordTracer(); 24 | 25 | super.channelRead(ctx, msg); 26 | } 27 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/provider/ProtocolSessionRegistryProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.provider; 8 | 9 | import sanbing.jcpp.protocol.domain.ProtocolSession; 10 | 11 | import java.util.UUID; 12 | 13 | /** 14 | * @author baigod 15 | */ 16 | public interface ProtocolSessionRegistryProvider { 17 | 18 | /** 19 | * 注册会话 20 | */ 21 | void register(ProtocolSession protocolSession); 22 | 23 | void unregister(UUID sessionId); 24 | 25 | ProtocolSession get(UUID sessionId); 26 | 27 | /** 28 | * 活跃会话 29 | */ 30 | void activate(ProtocolSession protocolSession); 31 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/provider/ProtocolsConfigProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.provider; 8 | 9 | import sanbing.jcpp.protocol.cfg.ProtocolCfg; 10 | 11 | /** 12 | * @author baigod 13 | */ 14 | public interface ProtocolsConfigProvider { 15 | 16 | ProtocolCfg loadConfig(String protocol); 17 | } -------------------------------------------------------------------------------- /jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/provider/impl/DefaultProtocolsConfigProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.provider.impl; 8 | 9 | import lombok.Setter; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.boot.context.properties.ConfigurationProperties; 12 | import org.springframework.stereotype.Service; 13 | import sanbing.jcpp.infrastructure.util.config.ConstraintValidator; 14 | import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil; 15 | import sanbing.jcpp.protocol.cfg.ProtocolCfg; 16 | import sanbing.jcpp.protocol.provider.ProtocolsConfigProvider; 17 | 18 | import java.util.Map; 19 | 20 | @Setter 21 | @Service 22 | @Slf4j 23 | @ConfigurationProperties("service") 24 | public class DefaultProtocolsConfigProvider implements ProtocolsConfigProvider { 25 | 26 | private Map protocols; 27 | 28 | @Override 29 | public ProtocolCfg loadConfig(String protocol) { 30 | 31 | ProtocolCfg protocolCfg = protocols.get(protocol); 32 | 33 | log.info("load {}'s configuration: \n{}", protocol, JacksonUtil.toPrettyString(protocolCfg)); 34 | 35 | ConstraintValidator.validateFields(protocolCfg, "'" + protocol + "' configuration is invalid:"); 36 | 37 | return protocolCfg; 38 | } 39 | } -------------------------------------------------------------------------------- /jcpp-protocol-bootstrap/src/layers.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 14 | 15 | 16 | org/springframework/boot/loader/** 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | *:*:*SNAPSHOT 26 | 27 | 28 | 29 | 30 | dependencies 31 | spring-boot-loader 32 | snapshot-dependencies 33 | application 34 | 35 | 36 | -------------------------------------------------------------------------------- /jcpp-protocol-bootstrap/src/main/java/sanbing/jcpp/protocol/JCPPProtocolServiceApplication.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol; 8 | 9 | import org.springframework.boot.Banner; 10 | import org.springframework.boot.autoconfigure.SpringBootApplication; 11 | import org.springframework.boot.builder.SpringApplicationBuilder; 12 | import org.springframework.scheduling.annotation.EnableAsync; 13 | import org.springframework.scheduling.annotation.EnableScheduling; 14 | 15 | import java.util.Arrays; 16 | 17 | /** 18 | * @author baigod 19 | */ 20 | @SpringBootApplication(scanBasePackages = {"sanbing.jcpp.protocol", 21 | "sanbing.jcpp.infrastructure.stats", 22 | "sanbing.jcpp.infrastructure.queue", 23 | "sanbing.jcpp.infrastructure.util"}) 24 | @EnableAsync 25 | @EnableScheduling 26 | public class JCPPProtocolServiceApplication { 27 | 28 | private static final String SPRING_CONFIG_NAME_KEY = "--spring.config.name"; 29 | private static final String DEFAULT_SPRING_CONFIG_PARAM = SPRING_CONFIG_NAME_KEY + "=" + "protocol-service"; 30 | 31 | public static void main(String[] args) { 32 | new SpringApplicationBuilder(JCPPProtocolServiceApplication.class).bannerMode(Banner.Mode.LOG).run(updateArguments(args)); 33 | } 34 | 35 | private static String[] updateArguments(String[] args) { 36 | if (Arrays.stream(args).noneMatch(arg -> arg.startsWith(SPRING_CONFIG_NAME_KEY))) { 37 | String[] modifiedArgs = new String[args.length + 1]; 38 | System.arraycopy(args, 0, modifiedArgs, 0, args.length); 39 | modifiedArgs[args.length] = DEFAULT_SPRING_CONFIG_PARAM; 40 | return modifiedArgs; 41 | } 42 | return args; 43 | } 44 | } -------------------------------------------------------------------------------- /jcpp-protocol-bootstrap/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | 2 | ___ ________ ________ ________ 3 | |\ \|\ ____\|\ __ \|\ __ \ 4 | \ \ \ \ \___|\ \ \|\ \ \ \|\ \ 5 | __ \ \ \ \ \ \ \ ____\ \ ____\ 6 | |\ \\_\ \ \ \____\ \ \___|\ \ \___| 7 | \ \________\ \_______\ \__\ \ \__\ 8 | \|________|\|_______|\|__| \|__| 9 | 10 | =================================================== 11 | :: ${application.title} :: ${application.formatted-version} 12 | =================================================== -------------------------------------------------------------------------------- /jcpp-protocol-bootstrap/src/test/java/sanbing/jcpp/protocol/AbstractProtocolTestBase.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol; 8 | 9 | import org.junit.jupiter.api.MethodOrderer; 10 | import org.junit.jupiter.api.TestMethodOrder; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 15 | import org.springframework.boot.test.context.SpringBootTest; 16 | import org.springframework.core.env.Environment; 17 | import org.springframework.test.context.ActiveProfiles; 18 | import org.springframework.test.web.servlet.MockMvc; 19 | 20 | /** 21 | * @author baigod 22 | */ 23 | @ActiveProfiles("test") 24 | @SpringBootTest(classes = JCPPProtocolServiceApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) 25 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 26 | @AutoConfigureMockMvc 27 | public class AbstractProtocolTestBase { 28 | 29 | static { 30 | System.setProperty("spring.config.name", "protocol-service"); 31 | } 32 | 33 | protected final Logger log = LoggerFactory.getLogger(this.getClass()); 34 | 35 | 36 | @Autowired 37 | protected MockMvc mockMvc; 38 | 39 | @Autowired 40 | protected Environment environment; 41 | } -------------------------------------------------------------------------------- /jcpp-protocol-yunkuaichong/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 13 | 14 | sanbing 15 | jcpp-parent 16 | 1.0.0-SNAPSHOT 17 | ../pom.xml 18 | 19 | 4.0.0 20 | 21 | jcpp-protocol-yunkuaichong 22 | jar 23 | JChargePointProtocol Yunkuaichong Protocol Module 24 | 云快充1.5 25 | 26 | 27 | ${basedir}/.. 28 | 29 | 30 | 31 | 32 | sanbing 33 | jcpp-protocol-api 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongDownlinkCmdExe.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.yunkuaichong; 8 | 9 | import sanbing.jcpp.protocol.ProtocolContext; 10 | import sanbing.jcpp.protocol.listener.tcp.TcpSession; 11 | 12 | /** 13 | * @author baigod 14 | */ 15 | public abstract class YunKuaiChongDownlinkCmdExe extends AbstractYunKuaiChongCmdExe { 16 | 17 | public abstract void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage yunKuaiChongDwonlinkMessage, ProtocolContext ctx); 18 | 19 | } -------------------------------------------------------------------------------- /jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongDwonlinkMessage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.yunkuaichong; 8 | 9 | import lombok.Data; 10 | import lombok.NoArgsConstructor; 11 | import lombok.experimental.Accessors; 12 | import sanbing.jcpp.proto.gen.ProtocolProto.DownlinkRequestMessage; 13 | 14 | import java.io.Serializable; 15 | import java.util.UUID; 16 | 17 | /** 18 | * @author baigod 19 | */ 20 | @Data 21 | @Accessors(chain = true) 22 | @NoArgsConstructor 23 | public class YunKuaiChongDwonlinkMessage implements Serializable { 24 | public static final byte SUCCESS_BYTE = 0x00; 25 | public static final byte FAILURE_BYTE = 0x01; 26 | 27 | // 消息ID 28 | private UUID id; 29 | 30 | // 请求ID(如有) 31 | private UUID requestId; 32 | 33 | // 指令 34 | private int cmd; 35 | 36 | // 消息体 37 | private DownlinkRequestMessage msg; 38 | 39 | // 上行消息 40 | private YunKuaiChongUplinkMessage requestData; 41 | 42 | } -------------------------------------------------------------------------------- /jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongUplinkCmdExe.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.yunkuaichong; 8 | 9 | import com.google.protobuf.ByteString; 10 | import lombok.extern.slf4j.Slf4j; 11 | import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil; 12 | import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage; 13 | import sanbing.jcpp.protocol.ProtocolContext; 14 | import sanbing.jcpp.protocol.listener.tcp.TcpSession; 15 | 16 | /** 17 | * @author baigod 18 | */ 19 | @Slf4j 20 | public abstract class YunKuaiChongUplinkCmdExe extends AbstractYunKuaiChongCmdExe { 21 | 22 | public abstract void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx); 23 | 24 | protected UplinkQueueMessage.Builder uplinkMessageBuilder(String messageKey, TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage) { 25 | return UplinkQueueMessage.newBuilder() 26 | .setMessageIdMSB(yunKuaiChongUplinkMessage.getId().getMostSignificantBits()) 27 | .setMessageIdLSB(yunKuaiChongUplinkMessage.getId().getLeastSignificantBits()) 28 | .setSessionIdMSB(tcpSession.getId().getMostSignificantBits()) 29 | .setSessionIdLSB(tcpSession.getId().getLeastSignificantBits()) 30 | .setRequestData(ByteString.copyFrom(JacksonUtil.writeValueAsBytes(yunKuaiChongUplinkMessage))) 31 | .setMessageKey(messageKey) 32 | .setProtocolName(tcpSession.getProtocolName()); 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongUplinkMessage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.yunkuaichong; 8 | 9 | import lombok.Data; 10 | import lombok.experimental.Accessors; 11 | 12 | import java.io.Serializable; 13 | import java.util.UUID; 14 | 15 | @Data 16 | @Accessors(chain = true) 17 | public class YunKuaiChongUplinkMessage implements Serializable { 18 | // 消息ID 19 | private final UUID id; 20 | 21 | // 起始域 22 | private int head; 23 | 24 | // 数据长度 25 | private int dataLength; 26 | 27 | // 序列号 28 | private int sequenceNumber; 29 | 30 | // 加密标识 31 | private int encryptionFlag; 32 | 33 | // 指令 34 | private int cmd; 35 | 36 | // 消息体 37 | private byte[] msgBody; 38 | 39 | // 校验和 40 | private int checkSum; 41 | 42 | // 真实报文 43 | private byte[] rawFrame; 44 | 45 | public YunKuaiChongUplinkMessage(UUID id) { 46 | this.id = id; 47 | } 48 | 49 | public YunKuaiChongUplinkMessage() { 50 | this(UUID.randomUUID()); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/annotation/YunKuaiChongCmd.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.yunkuaichong.annotation; 8 | 9 | import java.lang.annotation.*; 10 | 11 | /** 12 | * @author baigod 13 | */ 14 | @Target(ElementType.TYPE) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Documented 17 | public @interface YunKuaiChongCmd { 18 | 19 | int value(); 20 | 21 | } -------------------------------------------------------------------------------- /jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/enums/YunKuaiChongDownlinkCmdEnum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.yunkuaichong.enums; 8 | 9 | import lombok.AllArgsConstructor; 10 | import lombok.Getter; 11 | 12 | /** 13 | * @author baigod 14 | */ 15 | @AllArgsConstructor 16 | @Getter 17 | public enum YunKuaiChongDownlinkCmdEnum { 18 | 19 | LOGIN_ACK(0x02), 20 | 21 | SYNC_TIME(0x56), 22 | 23 | HEARTBEAT(0x04), 24 | 25 | VERIFY_PRICING_ACK(0x06), 26 | 27 | QUERY_PRICING_ACK(0X0A), 28 | 29 | SET_PRICING(0x58), 30 | 31 | REMOTE_START_CHARGING(0x34), 32 | 33 | REMOTE_STOP_CHARGING(0x36), 34 | 35 | TRANSACTION_RECORD(0x40), 36 | 37 | REMOTE_PARALLEL_START_CHARGING(0xA4); 38 | 39 | private final Integer cmd; 40 | 41 | } -------------------------------------------------------------------------------- /jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.yunkuaichong.v150; 8 | 9 | import lombok.extern.slf4j.Slf4j; 10 | import sanbing.jcpp.infrastructure.util.annotation.ProtocolComponent; 11 | import sanbing.jcpp.protocol.ProtocolBootstrap; 12 | import sanbing.jcpp.protocol.ProtocolMessageProcessor; 13 | import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolMessageProcessor; 14 | 15 | import static sanbing.jcpp.protocol.yunkuaichong.v150.YunkuaichongV150ProtocolBootstrap.PROTOCOL_NAME; 16 | 17 | /** 18 | * @author baigod 19 | */ 20 | 21 | @ProtocolComponent(PROTOCOL_NAME) 22 | @Slf4j 23 | public class YunkuaichongV150ProtocolBootstrap extends ProtocolBootstrap { 24 | 25 | public static final String PROTOCOL_NAME = "yunkuaichongV150"; 26 | 27 | @Override 28 | protected String getProtocolName() { 29 | return PROTOCOL_NAME; 30 | } 31 | 32 | @Override 33 | protected void _init() { 34 | // do nothing 35 | } 36 | 37 | @Override 38 | protected void _destroy() { 39 | // do nothing 40 | } 41 | 42 | @Override 43 | protected ProtocolMessageProcessor messageProcessor() { 44 | return new YunKuaiChongProtocolMessageProcessor(forwarder, protocolContext); 45 | } 46 | 47 | 48 | } -------------------------------------------------------------------------------- /jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150RemoteStopDLCmd.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.yunkuaichong.v150.cmd; 8 | 9 | import io.netty.buffer.ByteBuf; 10 | import io.netty.buffer.Unpooled; 11 | import lombok.extern.slf4j.Slf4j; 12 | import sanbing.jcpp.proto.gen.ProtocolProto.RemoteStopChargingRequest; 13 | import sanbing.jcpp.protocol.ProtocolContext; 14 | import sanbing.jcpp.protocol.listener.tcp.TcpSession; 15 | import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe; 16 | import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage; 17 | import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd; 18 | 19 | import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.REMOTE_STOP_CHARGING; 20 | 21 | /** 22 | * 云快充1.5.0 运营平台远程停机 23 | * 24 | * @author baigod 25 | */ 26 | @Slf4j 27 | @YunKuaiChongCmd(0x36) 28 | public class YunKuaiChongV150RemoteStopDLCmd extends YunKuaiChongDownlinkCmdExe { 29 | @Override 30 | public void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage yunKuaiChongDwonlinkMessage, ProtocolContext ctx) { 31 | log.info("{} 云快充1.5.0运营平台远程停机", tcpSession); 32 | 33 | if (!yunKuaiChongDwonlinkMessage.getMsg().hasRemoteStopChargingRequest()) { 34 | return; 35 | } 36 | 37 | RemoteStopChargingRequest remoteStopChargingRequest = yunKuaiChongDwonlinkMessage.getMsg().getRemoteStopChargingRequest(); 38 | String pileCode = remoteStopChargingRequest.getPileCode(); 39 | String gunCode = remoteStopChargingRequest.getGunCode(); 40 | 41 | ByteBuf msgBody = Unpooled.buffer(44); 42 | // 桩编码 43 | msgBody.writeBytes(encodePileCode(pileCode)); 44 | // 枪号 45 | msgBody.writeBytes(encodeGunCode(gunCode)); 46 | 47 | encodeAndWriteFlush(REMOTE_STOP_CHARGING, 48 | msgBody, 49 | tcpSession); 50 | } 51 | } -------------------------------------------------------------------------------- /jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v160/YunkuaichongV160ProtocolBootstrap.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开源代码,仅供学习和交流研究使用,商用请联系三丙 3 | * 微信:mohan_88888 4 | * 抖音:程序员三丙 5 | * 付费课程知识星球:https://t.zsxq.com/aKtXo 6 | */ 7 | package sanbing.jcpp.protocol.yunkuaichong.v160; 8 | 9 | import lombok.extern.slf4j.Slf4j; 10 | import sanbing.jcpp.infrastructure.util.annotation.ProtocolComponent; 11 | import sanbing.jcpp.protocol.ProtocolBootstrap; 12 | import sanbing.jcpp.protocol.ProtocolMessageProcessor; 13 | import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolMessageProcessor; 14 | 15 | import static sanbing.jcpp.protocol.yunkuaichong.v160.YunkuaichongV160ProtocolBootstrap.PROTOCOL_NAME; 16 | 17 | /** 18 | * @author baigod 19 | */ 20 | 21 | @ProtocolComponent(PROTOCOL_NAME) 22 | @Slf4j 23 | public class YunkuaichongV160ProtocolBootstrap extends ProtocolBootstrap { 24 | 25 | public static final String PROTOCOL_NAME = "yunkuaichongV160"; 26 | 27 | @Override 28 | protected String getProtocolName() { 29 | return PROTOCOL_NAME; 30 | } 31 | 32 | @Override 33 | protected void _init() { 34 | // do nothing 35 | } 36 | 37 | @Override 38 | protected void _destroy() { 39 | // do nothing 40 | } 41 | 42 | @Override 43 | protected ProtocolMessageProcessor messageProcessor() { 44 | return new YunKuaiChongProtocolMessageProcessor(forwarder, protocolContext); 45 | } 46 | 47 | 48 | } -------------------------------------------------------------------------------- /license-header-template.txt: -------------------------------------------------------------------------------- 1 | 开源代码,仅供学习和交流研究使用,商用请联系三丙 2 | 微信:mohan_88888 3 | 抖音:${owner} 4 | 付费课程知识星球:https://t.zsxq.com/aKtXo --------------------------------------------------------------------------------