ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/ServiceNameConstants.java
@@ -26,5 +26,6 @@ public static final String OTHER_SERVICE = "ruoyi-other"; public static final String ORDER_SERVICE = "ruoyi-order"; public static final String INTEGRATION_SERVICE = "ruoyi-integration"; public static final String JIANGUAN_SERVICE = "ruoyi-jianguan"; public static final String PAYMENT_SERVICE = "ruoyi-payment"; } ruoyi-service/pom.xml
@@ -15,6 +15,7 @@ <module>ruoyi-payment</module> <module>ruoyi-other</module> <module>ruoyi-integration</module> <module>ruoyi-jianguan</module> </modules> <artifactId>ruoyi-service</artifactId> ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/iotda/constant/SendTagConstant.java
@@ -7,6 +7,18 @@ */ public class SendTagConstant { /** * 推送充电设备接口状态信息 */ public static final String GUN_STATUS ="gun_status"; /** * 推送充电状态信息 */ public static final String ORDER_STATUS ="order_status"; /** * 推送充电订单信息 */ public static final String ORDER_INFO = "order_info"; /** * 充电桩登录认证 */ public static final String ONLINE ="online"; ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/rocket/model/ChargingMessage.java
@@ -1,12 +1,18 @@ package com.ruoyi.integration.rocket.model; import com.ruoyi.integration.drainage.model.ConnectorStatusInfo; import com.ruoyi.integration.drainage.model.SupChargeOrderInfo; import com.ruoyi.integration.drainage.model.SupEquipChargeStatus; import com.ruoyi.integration.rocket.base.BaseMessage; import lombok.Data; import org.apache.poi.ss.formula.functions.T; @Data public class ChargingMessage extends BaseMessage { // 充电设备状态message private GunStatusMessage gunStatusMessage; // 推送充电订单状态/充电订单信息message private ChargingOrderMessage orderMessage; private AcquisitionBillingModeMessage acquisitionBillingModeMessage; private BillingModeVerifyMessage billingModeVerifyMessage; private BmsAbortMessage bmsAbortMessage; ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/rocket/model/ChargingOrderMessage.java
New file @@ -0,0 +1,19 @@ package com.ruoyi.integration.rocket.model; import com.ruoyi.integration.rocket.base.BaseMessage; import lombok.Data; /** * 充电桩计费模型请求 **/ @Data public class ChargingOrderMessage extends BaseMessage { private String orderNumber;// 订单编号 private String soc;// soc } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/rocket/model/GunStatusMessage.java
New file @@ -0,0 +1,18 @@ package com.ruoyi.integration.rocket.model; import com.ruoyi.integration.rocket.base.BaseMessage; import lombok.Data; /** * 充电桩计费模型请求 **/ @Data public class GunStatusMessage extends BaseMessage { private String fullNumber;// 枪完整编码 } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/rocket/produce/ChargingMessageListener.java
@@ -133,7 +133,8 @@ @Resource private RedisTemplate redisTemplate; @Autowired private EnhanceProduce enhanceProduce; @@ -173,13 +174,6 @@ vo1.setPile_code(pingMessage.getCharging_pile_code()); vo1.setStatus(pingMessage.getCharging_gun_status()); chargingPileClient.updateChargingPileStatus(vo1); try { tcecPushUtil.pushSuperviseNotificationStationStatus(chargingGunClient.getChargingGunByFullNumber(pingMessage.getCharging_pile_code()+pingMessage.getCharging_gun_code()).getData()); }catch (Exception e){ e.printStackTrace(); System.out.println("设备状态推送监管平台失败:"+e.getMessage()); } } }); break; @@ -196,14 +190,28 @@ public void run() { // 业务处理 chargingOrderClient.endCharge(endCharge.getTransaction_serial_number()); try { TChargingOrder chargingOrder = chargingOrderClient.getOrderByCode(endCharge.getTransaction_serial_number()).getData(); tcecPushUtil.pushSuperviseNotificationChargeOrderInfo(chargingOrder); tcecPushUtil.pushSuperviseNotificationEquipChargeStatus(chargingOrder); }catch (Exception e){ e.printStackTrace(); System.out.println("充电结束推送监管平台失败:"+e.getMessage()); } // 订单id String transactionSerialNumber = endCharge.getTransaction_serial_number(); ChargingOrderMessage chargingOrderMessage = new ChargingOrderMessage(); chargingOrderMessage.setOrderNumber(transactionSerialNumber); // 推送充电订单信息 ChargingMessage chargingMessage1 = new ChargingMessage(); chargingMessage1.setServiceId(SendTagConstant.ORDER_INFO); chargingMessage1.setOrderMessage(chargingOrderMessage); enhanceProduce.orderInfoMessage(chargingMessage1); // 推送充电订单状态 ChargingMessage chargingMessage2 = new ChargingMessage(); chargingMessage2.setServiceId(SendTagConstant.ORDER_STATUS); chargingMessage2.setOrderMessage(chargingOrderMessage); enhanceProduce.orderStatusMessage(chargingMessage2); // try { // TChargingOrder chargingOrder = chargingOrderClient.getOrderByCode(endCharge.getTransaction_serial_number()).getData(); // tcecPushUtil.pushSuperviseNotificationChargeOrderInfo(chargingOrder); // tcecPushUtil.pushSuperviseNotificationEquipChargeStatus(chargingOrder); // }catch (Exception e){ // e.printStackTrace(); // System.out.println("充电结束推送监管平台失败:"+e.getMessage()); // } } }); break; @@ -276,8 +284,15 @@ BeanUtils.copyProperties(uploadRealTimeMonitoringData, query); chargingOrderClient.chargeMonitoring(query); chargingOrder.setEndSoc(uploadRealTimeMonitoringDataMessage.getSoc()+""); tcecPushUtil.pushSuperviseNotificationEquipChargeStatus(chargingOrder); ChargingOrderMessage chargingOrderMessage3 = new ChargingOrderMessage(); chargingOrderMessage3.setSoc(uploadRealTimeMonitoringDataMessage.getSoc()+""); chargingOrderMessage3.setOrderNumber(chargingOrder.getCode()); // 推送充电订单信息 ChargingMessage chargingMessage4 = new ChargingMessage(); chargingMessage4.setServiceId(SendTagConstant.ORDER_STATUS); chargingMessage4.setOrderMessage(chargingOrderMessage3); enhanceProduce.orderInfoMessage(chargingMessage4); // tcecPushUtil.pushSuperviseNotificationEquipChargeStatus(chargingOrder); } }); } catch (Exception e) { ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/rocket/produce/ChargingMessageUtil.java
@@ -5,6 +5,7 @@ import com.ruoyi.chargingPile.api.feignClient.ChargingGunClient; import com.ruoyi.chargingPile.api.feignClient.ChargingPileClient; import com.ruoyi.chargingPile.api.model.TAccountingStrategyDetail; import com.ruoyi.chargingPile.api.model.TChargingGun; import com.ruoyi.chargingPile.api.vo.UpdateChargingPileStatusVo; import com.ruoyi.integration.api.model.*; import com.ruoyi.integration.drainage.TCECPushUtil; @@ -20,6 +21,7 @@ import com.ruoyi.order.api.vo.SecurityDetectionVO; import com.ruoyi.order.api.vo.TransactionRecordMessageVO; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.spring.annotation.MessageModel; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; import org.apache.rocketmq.spring.core.RocketMQListener; @@ -105,8 +107,8 @@ private QrCodeDeliveryReplyService qrCodeDeliveryReplyService; @Autowired private SecurityDetectionService securityDetectionService; // @Autowired // private TCECPushUtil tcecPushUtil; @Autowired private TCECPushUtil tcecPushUtil; @Resource private ChargingPileClient chargingPileClient; @@ -115,7 +117,8 @@ @Resource private RedisTemplate redisTemplate; @Autowired private EnhanceProduce enhanceProduce; @@ -152,20 +155,16 @@ vo1.setPile_code(pingMessage.getCharging_pile_code()); vo1.setStatus(pingMessage.getCharging_gun_status()); chargingPileClient.updateChargingPileStatus(vo1); // 监管平台推送充电设备状态 SendResult sendResult; String gunCode = pingMessage.getCharging_pile_code() + pingMessage.getCharging_gun_code(); ChargingMessage chargingMessage = new ChargingMessage(); chargingMessage.setServiceId(SendTagConstant.GUN_STATUS); GunStatusMessage gunStatusMessage = new GunStatusMessage(); gunStatusMessage.setFullNumber(gunCode); chargingMessage.setGunStatusMessage(gunStatusMessage); sendResult = enhanceProduce.gunStatusMessage(chargingMessage); // ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); // threadPoolExecutor.execute(new Runnable() { // @Override // public void run() { // // try { //// tcecPushUtil.pushSuperviseNotificationStationStatus(chargingGunClient.getChargingGunByFullNumber(pingMessage.getCharging_pile_code()+pingMessage.getCharging_gun_code()).getData()); // }catch (Exception e){ // e.printStackTrace(); // System.out.println("设备状态推送监管平台失败:"+e.getMessage()); // } // } // }); break; case SendTagConstant.END_CHARGE: EndChargeMessage endChargeMessage = message.getEndChargeMessage(); @@ -176,6 +175,20 @@ endChargeService.create(endCharge); // 业务处理 chargingOrderClient.endCharge(endCharge.getTransaction_serial_number()); // 订单id String transactionSerialNumber = endCharge.getTransaction_serial_number(); ChargingOrderMessage chargingOrderMessage = new ChargingOrderMessage(); chargingOrderMessage.setOrderNumber(transactionSerialNumber); // 推送充电订单信息 ChargingMessage chargingMessage1 = new ChargingMessage(); chargingMessage1.setServiceId(SendTagConstant.ORDER_INFO); chargingMessage1.setOrderMessage(chargingOrderMessage); enhanceProduce.orderInfoMessage(chargingMessage1); // 推送充电订单状态 ChargingMessage chargingMessage2 = new ChargingMessage(); chargingMessage2.setServiceId(SendTagConstant.ORDER_STATUS); chargingMessage2.setOrderMessage(chargingOrderMessage); enhanceProduce.orderStatusMessage(chargingMessage2); // ThreadPoolExecutor threadPoolExecutor1 = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); // threadPoolExecutor1.execute(new Runnable() { // @Override @@ -255,6 +268,14 @@ UploadRealTimeMonitoringDataQuery query = new UploadRealTimeMonitoringDataQuery(); BeanUtils.copyProperties(uploadRealTimeMonitoringData, query); chargingOrderClient.chargeMonitoring(query); // 订单id ChargingOrderMessage chargingOrderMessage3 = new ChargingOrderMessage(); chargingOrderMessage3.setOrderNumber(chargingOrder.getCode()); // 推送充电订单信息 ChargingMessage chargingMessage4 = new ChargingMessage(); chargingMessage4.setServiceId(SendTagConstant.ORDER_STATUS); chargingMessage4.setOrderMessage(chargingOrderMessage3); enhanceProduce.orderInfoMessage(chargingMessage4); // ThreadPoolExecutor threadPoolExecutor2 = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); // threadPoolExecutor2.execute(new Runnable() { // @Override ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/rocket/produce/EnhanceProduce.java
@@ -26,6 +26,7 @@ private RocketMQEnhanceTemplate rocketMQEnhanceTemplate; private static final String TOPIC = "charge_"; private static final String TOPIC_JIANGUAN = "jianguan_"; /** * 充电桩登录认证 @@ -352,9 +353,40 @@ // 设置消息来源,便于查询 message.setSource(SendTagConstant.CHARGING_MESSAGE); return rocketMQEnhanceTemplate.send(TOPIC+SendTagConstant.CHARGING_MESSAGE, SendTagConstant.CHARGING_MESSAGE, message); } /** * 监管平台推送充电设备接口状态 */ public SendResult gunStatusMessage(ChargingMessage message) { // 设置业务key message.setKey(UUID.randomUUID().toString()); // 设置消息来源,便于查询 message.setSource(SendTagConstant.GUN_STATUS); return rocketMQEnhanceTemplate.send(TOPIC_JIANGUAN+SendTagConstant.GUN_STATUS, SendTagConstant.GUN_STATUS, message); } /** * 监管平台推送充电订单信息 */ public SendResult orderInfoMessage(ChargingMessage message) { // 设置业务key message.setKey(UUID.randomUUID().toString()); // 设置消息来源,便于查询 message.setSource(SendTagConstant.ORDER_INFO); return rocketMQEnhanceTemplate.send(TOPIC_JIANGUAN+SendTagConstant.ORDER_INFO, SendTagConstant.ORDER_INFO, message); } /** * 监管平台推送充电订单状态 */ public SendResult orderStatusMessage(ChargingMessage message) { // 设置业务key message.setKey(UUID.randomUUID().toString()); // 设置消息来源,便于查询 message.setSource(SendTagConstant.ORDER_STATUS); return rocketMQEnhanceTemplate.send(TOPIC_JIANGUAN+SendTagConstant.ORDER_STATUS, SendTagConstant.ORDER_STATUS, message); } } ruoyi-service/ruoyi-jianguan/pom.xml
New file @@ -0,0 +1,190 @@ <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-service</artifactId> <version>3.6.2</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>ruoyi-modules-jianguan</artifactId> <description> ruoyi-modules-jianguan监管平台数据上传模块 </description> <dependencies> <dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-api-integration</artifactId> </dependency> <!-- SpringCloud Alibaba Nacos --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- SpringCloud Alibaba Nacos Config --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!-- SpringCloud Alibaba Sentinel --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> </dependency> <!-- SpringBoot Actuator --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- Swagger UI --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>${swagger.fox.version}</version> </dependency> <!-- Mysql Connector --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- RuoYi Common DataSource --> <!-- <dependency>--> <!-- <groupId>com.ruoyi</groupId>--> <!-- <artifactId>ruoyi-common-datasource</artifactId>--> <!-- </dependency>--> <!-- <!– RuoYi Common DataScope –>--> <!-- <dependency>--> <!-- <groupId>com.ruoyi</groupId>--> <!-- <artifactId>ruoyi-common-datascope</artifactId>--> <!-- </dependency>--> <!-- RuoYi Common Log --> <dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-common-log</artifactId> </dependency> <!-- RuoYi Common Swagger --> <dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-common-swagger</artifactId> </dependency> <!-- 引入Druid依赖,阿里巴巴所提供的数据源 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>${druid.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> <!--mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--rocketmq--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-stream-rocketmq</artifactId> <version>2.2.2.RELEASE</version> <exclusions> <exclusion> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-client</artifactId> </exclusion> <exclusion> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-acl</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-client</artifactId> <version>4.7.1</version> </dependency> <dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-acl</artifactId> <version>4.7.1</version> </dependency> <!--mongodb--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> <dependency> <groupId>com.huaweicloud.sdk</groupId> <artifactId>huaweicloud-sdk-bundle</artifactId> <version>3.1.87</version> </dependency> <dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-api-order</artifactId> </dependency> <dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-api-chargingPile</artifactId> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> <resources> <resource> <directory>src/main/resources</directory> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build> </project> ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/RuoYiJianGuanApplication.java
New file @@ -0,0 +1,39 @@ package com.ruoyi.jianguan; import com.huaweicloud.sdk.thirdparty.okio.Sink; import com.ruoyi.common.security.annotation.EnableCustomConfig; import com.ruoyi.common.security.annotation.EnableRyFeignClients; import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.stream.annotation.EnableBinding; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.transaction.annotation.EnableTransactionManagement; import javax.xml.transform.Source; /** * 账户模块 * @author ruoyi */ @EnableCustomConfig @EnableCustomSwagger2 @EnableRyFeignClients @SpringBootApplication @EnableScheduling//开启定时任务 public class RuoYiJianGuanApplication { public static void main(String[] args) { SpringApplication.run(RuoYiJianGuanApplication.class, args); System.out.println("(♥◠‿◠)ノ゙ 监管平台模块启动成功 ლ(´ڡ`ლ)゙ \n" + " .-------. ____ __ \n" + " | _ _ \\ \\ \\ / / \n" + " | ( ' ) | \\ _. / ' \n" + " |(_ o _) / _( )_ .' \n" + " | (_,_).' __ ___(_ o _)' \n" + " | |\\ \\ | || |(_,_)' \n" + " | | \\ `' /| `-' / \n" + " | | \\ / \\ / \n" + " ''-' `'-' `-..-' "); } } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/BaseModel.java
New file @@ -0,0 +1,47 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.ruoyi.other.api.domain.Operator; import lombok.Data; import javax.validation.constraints.NotNull; /** * @author zhibing.pu * @Date 2025/1/23 18:33 */ @Data public class BaseModel { /** * 运营商标识 */ @NotNull @JsonProperty("OperatorID") private String operatorID; /** * 参数内容 */ @NotNull @JsonProperty("Data") private String data; /** * 时间戳 * yyyyMMddHHmmss */ @NotNull @JsonProperty("TimeStamp") private Long timeStamp; /** * 自增序列 * 4位自增序列取自时间戳,同一秒内按序列自增长,新秒重计。如 0001 */ @NotNull @JsonProperty("Seq") private String seq; /** * 运营商对象 */ @JsonIgnore private Operator operator; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/BaseModelJianGuan.java
New file @@ -0,0 +1,47 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.ruoyi.other.api.domain.Operator; import lombok.Data; import javax.validation.constraints.NotNull; /** * @author zhibing.pu * @Date 2025/1/23 18:33 */ @Data public class BaseModelJianGuan { /** * 运营商标识 */ @NotNull @JsonProperty("OperatorID") private String operatorID; /** * 参数内容 */ @NotNull @JsonProperty("Data") private String data; /** * 时间戳 * yyyyMMddHHmmss */ @NotNull @JsonProperty("TimeStamp") private String timeStamp; /** * 自增序列 * 4位自增序列取自时间戳,同一秒内按序列自增长,新秒重计。如 0001 */ @NotNull @JsonProperty("Seq") private String seq; /** * 运营商对象 */ @JsonIgnore private Operator operator; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/BaseRequest.java
New file @@ -0,0 +1,21 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 公共请求 * @author zhibing.pu * @Date 2025/1/21 17:08 */ @Data public class BaseRequest extends BaseModel { /** * 数字签名 */ @NotNull @JsonProperty("Sig") private String sig; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/BaseRequestJianGuan.java
New file @@ -0,0 +1,21 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 公共请求 * @author zhibing.pu * @Date 2025/1/21 17:08 */ @Data public class BaseRequestJianGuan extends BaseModelJianGuan { /** * 数字签名 */ @NotNull @JsonProperty("Sig") private String sig; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/BaseResult.java
New file @@ -0,0 +1,46 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import com.ruoyi.other.api.domain.Operator; import lombok.Data; import javax.validation.constraints.NotNull; /** * 公共返回结果 * @author zhibing.pu * @Date 2025/1/21 15:54 */ @Data public class BaseResult extends BaseModel { /** * 参数编码 * -1:系统繁忙,此时请求方稍后重试 * 0:请求成功 * 4001:签名错误 * 4002:Token错误 * 4003:POST参数不合法,缺少必需的 * 4004:请求的业务参数不合法 * 500:系统错误 */ @NotNull @JsonProperty("Ret") private Integer ret; /** * 错误信息描述 */ @NotNull @JsonProperty("Msg") private String msg; /** * 签名 */ @NotNull @JsonProperty("Sig") private String sig; /** * 运营商对象 */ private Operator operator; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/ChargeDetail.java
New file @@ -0,0 +1,61 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import javax.validation.constraints.Null; import java.math.BigDecimal; /** * 充电明细信息 * @author zhibing.pu * @Date 2025/1/21 16:40 */ @Data public class ChargeDetail { /** * 开始时间 * yyyy-MM-dd HH:mm:ss */ @NotNull @JsonProperty("DetailStartTime") private String detailStartTime; /** * 结束时间 * yyyy-MM-dd HH:mm:ss */ @NotNull @JsonProperty("DetailEndTime") private String detailEndTime; /** * 时段电价 */ @Null @JsonProperty("ElecPrice") private BigDecimal elecPrice; /** * 时段服务费价格 */ @Null @JsonProperty("SevicePrice") private BigDecimal sevicePrice; /** * 时段充电量 */ @Null @JsonProperty("DetailPower") private BigDecimal detailPower; /** * 时段电费 */ @Null @JsonProperty("DetailElecMoney") private BigDecimal detailElecMoney; /** * 时段服务费 */ @Null @JsonProperty("DetailSeviceMoney") private BigDecimal detailSeviceMoney; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/ConnectorInfo.java
New file @@ -0,0 +1,112 @@ package com.ruoyi.jianguan.model; import com.baomidou.mybatisplus.annotation.TableField; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import javax.validation.constraints.Null; import java.math.BigDecimal; /** * 充电设备接口 * @author zhibing.pu * @Date 2025/1/21 14:03 */ @Data public class ConnectorInfo { /** * 充电设备接口编码 */ @NotNull @JsonProperty("ConnectorID") private String connectorID; /** * 充电设备接口名称 */ @NotNull @JsonProperty("ConnectorName") private String connectorName; /** * 1:车辆充电设备接口 * 2:换电站内的电池箱充电设备接口 */ @Null @JsonProperty("EquipmentClassification") private Integer equipmentClassification; /** * 充电设备接口类型 */ @NotNull @JsonProperty("ConnectorType") private Integer connectorType; /** * 额定电压上限 */ @NotNull @JsonProperty("VoltageUpperLimits") private BigDecimal voltageUpperLimits; /** * 额定电压下限 */ @NotNull @JsonProperty("VoltageLowerLimits") private BigDecimal voltageLowerLimits; /** * 额定电流 */ @NotNull @JsonProperty("Current") private Integer current; /** * 额定功率 */ @NotNull @JsonProperty("Power") private BigDecimal power; /** * 车位号 */ @Null @JsonProperty("ParkNo") private String parkNo; /** * 国家标准 * 1:2011 * 2:2015 * 3:兼容2011和2015 */ @NotNull @JsonProperty("NationalStandard") private Integer nationalStandard; /** * 枪二维码 */ @Null @JsonProperty("QRCode") private String QRCode; @Null @JsonProperty("ConstantVoltageUpperLimits") private BigDecimal constantVoltageUpperLimits; @Null @JsonProperty("ConstantVoltageLowerLimits") private BigDecimal constantVoltageLowerLimits; @Null @JsonProperty("ConstantCurrentUpperLimits") private BigDecimal constantCurrentUpperLimits; @Null @JsonProperty("ConstantCurrentLowerLimits") private BigDecimal constantCurrentLowerLimits; @NotNull @JsonProperty("AuxPower") private Integer auxPower; @NotNull @TableField("OpreateStatus") private Integer opreateStatus; @Null @TableField("OpreateHours") private String opreateHours; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/ConnectorStatsInfo.java
New file @@ -0,0 +1,49 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import java.math.BigDecimal; /** * 充电设备接口统计信息 * @author zhibing.pu * @Date 2025/1/21 15:24 */ @Data public class ConnectorStatsInfo { /** * 充电设备接口编码 */ @NotNull @JsonProperty("ConnectorID") private String connectorID; /** * 充电设备接口累计电量 */ @NotNull @JsonProperty("ConnectorElectricity") private BigDecimal connectorElectricity; /** * 充电设备接口累 * 计充电时长 */ @NotNull @JsonProperty("ConnectorTotalChargeTime") private Integer ConnectorTotalChargeTime; /** * 充电设备接口累 * 计充电次数 */ @NotNull @JsonProperty("ConnectorTotalChargeNum") private Integer ConnectorTotalChargeNum; /** * 充电设备接口累 * 计告警数量 */ @NotNull @JsonProperty("ConnectorTotalWarningNum") private Integer ConnectorTotalWarningNum; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/ConnectorStatusInfo.java
New file @@ -0,0 +1,78 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import javax.validation.constraints.Null; /** * 充电设备接口状态 * @author zhibing.pu * @Date 2025/1/21 14:53 */ @Data public class ConnectorStatusInfo { /** * 充电设备接口编码 */ @NotNull @JsonProperty("ConnectorID") private String connectorID; /** * 充电设备接口状态 * 0:离网 * 1:空闲 * 2:占用(未充电) * 3:占用(充电中) * 4:占用(预约锁定) * 255:故障 */ @NotNull @JsonProperty("Status") private Integer status; /** * 车位状态 * 0:未知 * 10:空闲 * 50:占用 */ @Null @JsonProperty("ParkStatus") private Integer parkStatus; /** * 地锁状态 * 0:未知 * 10:已解锁 * 50:已上锁 */ @Null @JsonProperty("LookStatus") private Integer lookStatus; @JsonProperty("ConnectorStatusInfo") private ConnectorStatusInfo connectorStatusInfo; @JsonProperty("OperatorID") private String OperatorID; @JsonProperty("EquipmentOwnerID") private String EquipmentOwnerID; @JsonProperty("StationID") private String StationID; @JsonProperty("EquipmentID") private String EquipmentID; /** * 1:车辆充电设备接口 * 2:换电站内的电池箱充 * 电设备接口 */ @JsonProperty("EquipmentClassification") private Integer EquipmentClassification; /** * 本次状态变化的时间, * 格式“yyyy-MM-dd HH:mm:ss */ @JsonProperty("UpdateTime") private String UpdateTime; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/ConnectorStatusInfo1.java
New file @@ -0,0 +1,54 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import javax.validation.constraints.Null; /** * 充电设备接口状态 * @author zhibing.pu * @Date 2025/1/21 14:53 */ @Data public class ConnectorStatusInfo1 { /** * 充电设备接口编码 */ @NotNull @JsonProperty("ConnectorID") private String connectorID; /** * 充电设备接口状态 * 0:离网 * 1:空闲 * 2:占用(未充电) * 3:占用(充电中) * 4:占用(预约锁定) * 255:故障 */ @NotNull @JsonProperty("Status") private Integer status; /** * 车位状态 * 0:未知 * 10:空闲 * 50:占用 */ @Null @JsonProperty("ParkStatus") private Integer parkStatus; /** * 地锁状态 * 0:未知 * 10:已解锁 * 50:已上锁 */ @Null @JsonProperty("LookStatus") private Integer lookStatus; private ConnectorStatusInfo1 ConnectorStatusInfo; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/EquipmentInfo.java
New file @@ -0,0 +1,98 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import javax.validation.constraints.Null; import java.math.BigDecimal; import java.util.List; /** * 充电设备信息 * @author zhibing.pu * @Date 2025/1/21 13:51 */ @Data public class EquipmentInfo { /** * 设备编号 */ @NotNull @JsonProperty("EquipmentID") private String equipmentID; /** * 设备生产商组织机构代码 */ @Null @JsonProperty("ManufacturerID") private String manufacturerID; /** * 设备唯一 * 编码 */ @Null @JsonProperty("EquipmentUniqueNumber") private String equipmentUniqueNumber; /** * 设备生产商名称 */ @Null @JsonProperty("ManufacturerName") private String manufacturerName; /** * 设备型号 */ @Null @JsonProperty("EquipmentModel") private String equipmentModel; /** * 设备生产日期 * YYYY-MM-DD */ @Null @JsonProperty("ProductionDate") private String productionDate; /** * 设备类型 */ @NotNull @JsonProperty("EquipmentType") private Integer equipmentType; /** * 充电设备接口信息列表 */ @NotNull @JsonProperty("ConnectorInfos") private List<ConnectorInfo> connectorInfos; /** * 充电设备经度 */ @Null @JsonProperty("EquipmentLng") private BigDecimal equipmentLng; /** * 充电设备纬度 */ @Null @JsonProperty("EquipmentLat") private BigDecimal equipmentLat; /** * 充电设备总功率 */ @NotNull @JsonProperty("Power") private BigDecimal power; /** * 充电设备名称 */ @Null @JsonProperty("EquipmentName") private String equipmentName; /** * 设备分类 */ @NotNull @JsonProperty("EquipmentClassification") private Integer equipmentClassification; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/EquipmentStatsInfo.java
New file @@ -0,0 +1,64 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import java.math.BigDecimal; import java.util.List; /** * 充电设备统计信息 * @author zhibing.pu * @Date 2025/1/21 15:22 */ @Data public class EquipmentStatsInfo { /** * 设备编码 */ @NotNull @JsonProperty("EquipmentID") private String equipmentID; /** * 充电设备接口累计电量 */ @NotNull @JsonProperty("EquipmentElectricity") private BigDecimal equipmentElectricity; /** * 设备分类 1:车辆充电设备 * 2:换电站内的电池 * 箱充电设备 */ @NotNull @JsonProperty("EquipmentClassification") private Integer equipmentClassification; /** * 充电设备累计充电时长 单位分钟 */ @NotNull @JsonProperty("EquipmentTotalChargeTime") private Long equipmentTotalChargeTime; /** * 充电设备累计充 * 电次数 */ @NotNull @JsonProperty("EquipmentTotalChargeNum") private Integer equipmentTotalChargeNum; /** * 充电设备累计充 * 电次数 */ @NotNull @JsonProperty("EquipmentTotalWarningNum") private Integer equipmentTotalWarningNum; /** * 充电设备接口统计信息列表 */ @NotNull @JsonProperty("ConnectorStatsInfos") private List<ConnectorStatsInfo> connectorStatsInfos; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/NotificationChargeOrderInfo.java
New file @@ -0,0 +1,106 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import javax.validation.constraints.Null; import java.math.BigDecimal; import java.util.List; /** * 推送充电订单信息 * @author zhibing.pu * @Date 2025/1/21 15:39 */ @Data public class NotificationChargeOrderInfo { /** * 充电订单号 */ @NotNull @JsonProperty("StartChargeSeq") private String startChargeSeq; /** * 充电设备接口编码 */ @NotNull @JsonProperty("ConnectorID") private String connectorID; /** * 开始充电时间 * yyyy-MM-dd HH:mm:ss */ @NotNull @JsonProperty("StartTime") private String startTime; /** * 结束充电时间 * yyyy-MM-dd HH:mm:ss */ @NotNull @JsonProperty("EndTime") private String endTime; /** * 累计充电量 */ @NotNull @JsonProperty("TotalPower") private BigDecimal totalPower; /** * 总电费 */ @NotNull @JsonProperty("TotalElecMoney") private BigDecimal totalElecMoney; /** * 总服务费 */ @NotNull @JsonProperty("TotalSeviceMoney") private BigDecimal totalSeviceMoney; /** * 累计总金额 */ @NotNull @JsonProperty("TotalMoney") private BigDecimal totalMoney; /** * 充电结束原因 * 0:用户手动停止充电 * 1:客户归属地运营商平台停止充电 * 2:BMS停止充电 * 3:充电机设备故障 * 4:连接器断开 * 5·99:自定义 */ @NotNull @JsonProperty("StopReason") private Integer stopReason; /** * 时段数 N * 0·32 */ @Null @JsonProperty("SumPeriod") private Integer sumPeriod; /** * 充电明细信息 */ @Null @JsonProperty("ChargeDetails") private List<ChargeDetail> chargeDetails; /** * 占位费 */ @Null @JsonProperty("TotalDelayMoney") private BigDecimal totalDelayMoney; /** * 车辆识别码 */ @Null @JsonProperty("VIN") private String VIN; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/NotificationChargeOrderInfoResult.java
New file @@ -0,0 +1,35 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 推送充电订单信息返回记过 * @author zhibing.pu * @Date 2025/1/21 15:49 */ @Data public class NotificationChargeOrderInfoResult { /** * 充电订单号 */ @NotNull @JsonProperty("StartChargeSeq") private String startChargeSeq; /** * 充电设备接口编码 */ @NotNull @JsonProperty("ConnectorID") private String connectorID; /** * 确认结果 * 0;成功 * 1:争议交易 * 2·99:自定义 */ @JsonProperty("ConfirmResult") private Integer confirmResult; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/NotificationEquipChargeStatusResult.java
New file @@ -0,0 +1,29 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 推送充电状态结果 * @author zhibing.pu * @Date 2025/1/21 16:48 */ @Data public class NotificationEquipChargeStatusResult { /** * 充电订单号 */ @NotNull @JsonProperty("StartChargeSeq") private String startChargeSeq; /** * 操作结果 * 0:成功 * 1:失败 */ @NotNull @JsonProperty("SuccStat") private Integer succStat; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/NotificationStartCharge.java
New file @@ -0,0 +1,44 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 推送启动充电结果 * @author zhibing.pu * @Date 2025/1/22 18:40 */ @Data public class NotificationStartCharge { /** * 充电订单号 */ @NotNull @JsonProperty("StartChargeSeq") private String startChargeSeq; /** * 充电订单状态 * 1:启动中 * 2:充电中 * 3:停止中 * 4:已结束 * 5:未知 */ @NotNull @JsonProperty("StartChargeSeqStat") private Integer startChargeSeqStat; /** * 充电设别接口编码 */ @NotNull @JsonProperty("ConnectorID") private String connectorID; /** * 充电启动时间 */ @NotNull @JsonProperty("StartTime") private String startTime; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/NotificationStartChargeResult.java
New file @@ -0,0 +1,37 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 推送启动充电结果返回值 * @author zhibing.pu * @Date 2025/1/22 18:47 */ @Data public class NotificationStartChargeResult { /** * 充电订单号 */ @NotNull @JsonProperty("StartChargeSeq") private String startChargeSeq; /** * 操作结果 * 0:成功 * 1:失败 */ @NotNull @JsonProperty("SuccStat") private Integer succStat; /** * 失败原因 * 0:无 * 1:接收失败 */ @NotNull @JsonProperty("FailReason") private Integer failReason; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/NotificationStationStatusResult.java
New file @@ -0,0 +1,23 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 设备状态变化推动返回结果 * @author zhibing.pu * @Date 2025/1/21 14:58 */ @Data public class NotificationStationStatusResult { /** * 状态 * 0:接收 * 1:丢弃/忽略,不需要重试 */ @NotNull @JsonProperty("Status") private Integer status; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/NotificationStopCharge.java
New file @@ -0,0 +1,37 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 推送停止充电结果应答 * @author zhibing.pu * @Date 2025/1/23 9:17 */ @Data public class NotificationStopCharge { /** * 充电订单号 */ @NotNull @JsonProperty("StartChargeSeq") private String startChargeSeq; /** * 操作结果 * 0:成功 * 1:失败 */ @NotNull @JsonProperty("SuccStat") private Integer succStat; /** * 失败原因 * 0:无 * 1:接收失败 */ @NotNull @JsonProperty("FailReason") private Integer failReason; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/NotificationStopChargeResult.java
New file @@ -0,0 +1,57 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 推送停止充电结果 * @author zhibing.pu * @Date 2025/1/23 9:13 */ @Data public class NotificationStopChargeResult { /** * 充电订单号 */ @NotNull @JsonProperty("StartChargeSeq") private String startChargeSeq; /** * 充电订单状态 * 1:启动中 * 2:充电中 * 3:停止中 * 4:已结束 * 5:未知 */ @NotNull @JsonProperty("StartChargeSeqStat") private Integer startChargeSeqStat; /** * 充电设备接口编码 */ @NotNull @JsonProperty("ConnectorID") private String connectorID; /** * 操作结果 * 0:成功 * 1:失败 */ @NotNull @JsonProperty("SuccStat") private Integer succStat; /** * 失败原因 * 0:无 * 1:此设备不存在 * 2:此设备离线 * 3:此设备已停止充电 * 4`9:自定义 */ @NotNull @JsonProperty("FailReason") private Integer failReason; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/OperatorInfo.java
New file @@ -0,0 +1,52 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import javax.validation.constraints.Null; /** * 基础设施运营商信息 * @author zhibing.pu * @Date 2025/1/21 11:49 */ @Data public class OperatorInfo { /** * 运营商ID */ @NotNull @JsonProperty("OperatorID") private String operatorID; /** * 运营商名称 */ @NotNull @JsonProperty("OperatorName") private String operatorName; /** * 运营商电话1 */ @NotNull @JsonProperty("OperatorTel1") private String operatorTel1; /** * 运营商电话2 */ @Null @JsonProperty("OperatorTel2") private String operatorTel2; /** * 运营商注册地址 */ @Null @JsonProperty("OperatorRegAddress") private String operatorRegAddress; /** * 备注 */ @Null @JsonProperty("OperatorNote") private String operatorNote; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/PlaceHolder.java
New file @@ -0,0 +1,48 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import java.math.BigDecimal; import java.util.List; /** * 占位费信息 * @author zhibing.pu * @Date 2025/1/26 9:29 */ @Data public class PlaceHolder { /** * 免费时长 */ @NotNull @JsonProperty("FreeTime") private Integer freeTime; /** * 嘴阀占位费 */ @NotNull @JsonProperty("MaxFee") private BigDecimal maxFee; /** * 生效开始时间 * yyyy-MM-dd HH:mm:ss */ @NotNull @JsonProperty("EffectStartTime") private String effectStartTime; /** * 生效结束时间 */ @NotNull @JsonProperty("EffectEndTime") private String effectEndTime; /** * 占位费价格 */ @NotNull @JsonProperty("PlaceHolderPrices") private List<PlaceHolderPrice> placeHolderPrices; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/PlaceHolderPrice.java
New file @@ -0,0 +1,36 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import java.math.BigDecimal; /** * 占位费价格 * @author zhibing.pu * @Date 2025/1/26 9:33 */ @Data public class PlaceHolderPrice { /** * 开始时段 * HH:mm */ @NotNull @JsonProperty("StartTime") private String startTime; /** * 结束时段 * HH:mm */ @NotNull @JsonProperty("EndTime") private String endTime; /** * 单价 */ @NotNull @JsonProperty("Price") private BigDecimal price; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/PolicyInfo.java
New file @@ -0,0 +1,35 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import java.math.BigDecimal; /** * 计费信息 * @author zhibing.pu * @Date 2025/1/21 16:10 */ @Data public class PolicyInfo { /** * 时段起始时间点 * HHmmss */ @NotNull @JsonProperty("StartTime") private String startTime; /** * 时段电费 */ @NotNull @JsonProperty("ElecPrice") private BigDecimal elecPrice; /** * 时段服务费 */ @NotNull @JsonProperty("SevicePrice") private BigDecimal sevicePrice; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryEquipAuth.java
New file @@ -0,0 +1,27 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 请求设备认证 * @author zhibing.pu * @Date 2025/1/22 16:15 */ @Data public class QueryEquipAuth { /** * 设备认证流水 */ @NotNull @JsonProperty("EquipAuthSeq") private String equipAuthSeq; /** * 充电设备接口编码 */ @NotNull @JsonProperty("ConnectorID") private String connectorID; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryEquipAuthResult.java
New file @@ -0,0 +1,45 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 请求设备认证返回结果 * @author zhibing.pu * @Date 2025/1/22 16:16 */ @Data public class QueryEquipAuthResult { /** * 设备认证流水号 */ @NotNull @JsonProperty("EquipAuthSeq") private String equipAuthSeq; /** * 充电设备接口编码 */ @NotNull @JsonProperty("ConnectorID") private String connectorID; /** * 操作结果 * 0:成功 * 1:失败 */ @NotNull @JsonProperty("SuccStat") private Integer succStat; /** * 失败原因 * 0:无 * 1:此设备尚未插枪 * 2:设备检测失败 * 3·99:自定义 */ @NotNull @JsonProperty("FailReason") private Integer failReason; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryEquipBusinessPolicy.java
New file @@ -0,0 +1,28 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 查询业务策略信息 * @author zhibing.pu * @Date 2025/1/21 16:03 */ @Data public class QueryEquipBusinessPolicy { /** * 业务策略查询流水号 * 格式”运营商ID+唯一编号“。27字符 */ @NotNull @JsonProperty("EquipBizSeq") private String equipBizSeq; /** * 充电设备接口编码 */ @NotNull @JsonProperty("ConnectorID") private String connectorID; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryEquipBusinessPolicyResult.java
New file @@ -0,0 +1,58 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import java.util.List; /** * 查询业务策略信息结果 * @author zhibing.pu * @Date 2025/1/21 16:05 */ @Data public class QueryEquipBusinessPolicyResult { /** * 业务策略查询流水号 */ @NotNull @JsonProperty("EquipBizSeq") private String equipBizSeq; /** * 充电设备接口编码 */ @NotNull @JsonProperty("ConnectorID") private String connectorID; /** * 操作结果 * 0:成功 * 1:失败 */ @NotNull @JsonProperty("SuccStat") private Integer succStat; /** * 失败原因 * 0:无 * 1:此充电桩业务策略不存在 */ @NotNull @JsonProperty("FailReason") private Integer failReason; /** * 时段数N * 0`32 */ @NotNull @JsonProperty("SumPeriod") private Integer sumPeriod; /** * 计策信息 */ @NotNull @JsonProperty("PolicyInfos") private List<PolicyInfo> policyInfos; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryEquipChargeStatus.java
New file @@ -0,0 +1,34 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import javax.validation.constraints.Null; /** * 查询充电状态 * @author zhibing.pu * @Date 2025/1/21 16:17 */ @Data public class QueryEquipChargeStatus { /** * 充电订单号 */ @NotNull @JsonProperty("StartChargeSeq") private String startChargeSeq; /** * 抢号 */ @NotNull @JsonProperty("ConnectorID") private String connectorID; /** * 车辆识别码 */ @Null @JsonProperty("VIN") private String VIN; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryEquipChargeStatusResult.java
New file @@ -0,0 +1,150 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import javax.validation.constraints.Null; import java.math.BigDecimal; import java.util.List; /** * 查询充电状态结果 * @author zhibing.pu * @Date 2025/1/21 15:58 */ @Data public class QueryEquipChargeStatusResult { /** * 充电订单号 */ @NotNull @JsonProperty("StartChargeSeq") private String startChargeSeq; /** * 充电订单状态 * 1:启动中 * 2:充电中 * 3:停止中 * 4:已结束 * 5:未知 */ @NotNull @JsonProperty("StartChargeSeqStat") private Integer startChargeSeqStat; /** * 充电设备接口编号 */ @NotNull @JsonProperty("ConnectorID") private String connectorID; /** * 充电设备接口状态 * 1:空闲 * 2:占用(未充电) * 3:占用(充电中) * 4:占用(预约锁定) * 255:故障 */ @NotNull @JsonProperty("ConnectorStatus") private Integer connectorStatus; /** * A相电流 */ @NotNull @JsonProperty("CurrentA") private BigDecimal currentA; /** * B相电流 */ @Null @JsonProperty("CurrentB") private BigDecimal currentB; /** * C相电流 */ @Null @JsonProperty("CurrentC") private BigDecimal currentC; /** * A相电压 */ @NotNull @JsonProperty("VoltageA") private BigDecimal voltageA; /** * B相电压 */ @Null @JsonProperty("VoltageB") private BigDecimal voltageB; /** * C相电压 */ @Null @JsonProperty("VoltageC") private BigDecimal voltageC; /** * 电池剩余电量 */ @NotNull @JsonProperty("Soc") private BigDecimal soc; /** * 开始充电时间 */ @NotNull @JsonProperty("StartTime") private String startTime; /** * 本次采样时间 */ @NotNull @JsonProperty("EndTime") private String endTime; /** * 累计充电量 */ @NotNull @JsonProperty("TotalPower") private BigDecimal totalPower; /** * 累计电费 */ @Null @JsonProperty("ElecMoney") private BigDecimal elecMoney; /** * 累计服务费 */ @Null @JsonProperty("SeviceMoney") private BigDecimal seviceMoney; /** * 累计总金额 */ @Null @JsonProperty("TotalMoney") private BigDecimal totalMoney; /** * 时段数N * 0`32 */ @Null @JsonProperty("SumPeriod") private Integer sumPeriod; /** * 充电明细信息 */ @Null @JsonProperty("ChargeDetails") private List<ChargeDetail> chargeDetails; /** * 车辆识别码 */ @Null @JsonProperty("VIN") private String VIN; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryStartCharge.java
New file @@ -0,0 +1,47 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import javax.validation.constraints.Null; import java.math.BigDecimal; /** * 请求启动充电 * @author zhibing.pu * @Date 2025/1/22 16:59 */ @Data public class QueryStartCharge { /** * 充电订单号 */ @NotNull @JsonProperty("StartChargeSeq") private String startChargeSeq; /** * 充电设备接口编码 */ @NotNull @JsonProperty("ConnectorID") private String connectorID; /** * 二维码其他信息 */ @NotNull @JsonProperty("QRCode") private String QRCode; /** * 充电余额 */ @NotNull @JsonProperty("ChargingAmt") private BigDecimal chargingAmt; /** * 充电车牌号 */ @Null @JsonProperty("PlateNum") private String plateNum; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryStartChargeResult.java
New file @@ -0,0 +1,56 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 请求启动充电返回结果 * @author zhibing.pu * @Date 2025/1/22 17:02 */ @Data public class QueryStartChargeResult { /** * 充电订单号 */ @NotNull @JsonProperty("StartChargeSeq") private String startChargeSeq; /** * 充电订单状态 * 1:启动中 * 2:充电中 * 3:停止中 * 4:已结束 * 5:未知 */ @NotNull @JsonProperty("StartChargeSeqStat") private Integer startChargeSeqStat; /** * 充电设别接口编码 */ @NotNull @JsonProperty("ConnectorID") private String connectorID; /** * 操作结果 * 0:成功 * 1:失败 */ @NotNull @JsonProperty("SuccStat") private Integer succStat; /** * 失败原因 * 0:无 * 1:此设备不存在 * 2:此设备离线 * 3`9:自定义 */ @NotNull @JsonProperty("FailReason") private Integer failReason; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryStationStats.java
New file @@ -0,0 +1,35 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 查询统计信息 * @author zhibing.pu * @Date 2025/1/21 15:11 */ @Data public class QueryStationStats { /** * 充电站ID */ @NotNull @JsonProperty("StationID") private String stationID; /** * 统计开始时间 * yyyy-MM-dd */ @NotNull @JsonProperty("StartTime") private String startTime; /** * 统计结束时间 * yyyy-MM-dd */ @NotNull @JsonProperty("EndTime") private String endTime; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryStationStatsResult.java
New file @@ -0,0 +1,21 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 查询统计信息结果 * @author zhibing.pu * @Date 2025/1/21 15:16 */ @Data public class QueryStationStatsResult { /** * 充电站统计信息 */ @NotNull @JsonProperty("StationStats") private StationStatsInfo stationStats; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryStationStatus.java
New file @@ -0,0 +1,30 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import java.util.List; /** * 设备接口状态查询 * @author zhibing.pu * @Date 2025/1/21 15:01 */ @Data public class QueryStationStatus { /** * 充电站ID列表 * 数组长度不超过50 */ @NotNull @JsonProperty("StationIDs") private List<String> stationIDs; /** * 运营商服务平台ID,字符9位 * 数组长度不超过50 */ @NotNull @JsonProperty("OperatorID") private String operatorID; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryStationStatusResult.java
New file @@ -0,0 +1,25 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import java.util.List; /** * 设备接口状态查询返回结果 * @author zhibing.pu * @Date 2025/1/21 15:04 */ @Data public class QueryStationStatusResult { /** * 结果总数 */ @JsonProperty("Total") private Integer total; /** * 设备接口状态列表 */ @JsonProperty("StationStatusInfos") private List<StationStatusInfo> stationStatusInfos; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryStationsInfo.java
New file @@ -0,0 +1,49 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.Null; import java.util.List; /** * @author zhibing.pu * @Date 2025/1/21 14:41 */ @Data public class QueryStationsInfo { /** * 上次查询时间 * yyyy-MM-dd HH:mm:ss */ @Null @JsonProperty("LastQueryTime") private String lastQueryTime; /** * 查询页码 * 默认1 */ @Null @JsonProperty("PageNo") private Integer pageNo; /** * 每页数量 * 默认10 */ @Null @JsonProperty("PageSize") private Integer pageSize; /** * 运营商ID */ @Null @JsonProperty("OperatorID") private String OperatorID; /** * 充电站ID列表 */ @Null @JsonProperty("StationIDs") private List<String> StationIDs; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryStationsInfoResult.java
New file @@ -0,0 +1,40 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import java.util.List; /** * 公共返回结果 * @author zhibing.pu * @Date 2025/1/21 14:44 */ @Data public class QueryStationsInfoResult { /** * 当前页数 */ @NotNull @JsonProperty("PageNo") private Integer pageNo; /** * 页码总数 */ @NotNull @JsonProperty("PageCount") private Integer pageCount; /** * 总记录条数 */ @NotNull @JsonProperty("ItemSize") private Integer itemSize; /** * 充电站信息列表 */ @NotNull @JsonProperty("StationInfos") private List<StationInfo> stationInfos; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryStopCharge.java
New file @@ -0,0 +1,27 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 请求停止充电 * @author zhibing.pu * @Date 2025/1/22 19:56 */ @Data public class QueryStopCharge { /** * 充电订单号 */ @NotNull @JsonProperty("StartChargeSeq") private String startChargeSeq; /** * 充电设备接口编码 */ @NotNull @JsonProperty("ConnectorID") private String connectorID; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryStopChargeResult.java
New file @@ -0,0 +1,52 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 请求停止充电返回结果 * @author zhibing.pu * @Date 2025/1/22 19:58 */ @Data public class QueryStopChargeResult { /** * 充电订单号 */ @NotNull @JsonProperty("StartChargeSeq") private String startChargeSeq; /** * 充电订单状态 * 1:启动中 * 2:充电中 * 3:停止中 * 4:已结束 * 5:未知 */ @NotNull @JsonProperty("StartChargeSeqStat") private Integer startChargeSeqStat; /** * 操作结果 * 0:成功 * 1:失败 */ @NotNull @JsonProperty("SuccStat") private Integer succStat; /** * 失败原因 * 0:无 * 1:此设备不存在 * 2:此设备离线 * 3:此设备已停止充电 * 4`9:自定义 */ @NotNull @JsonProperty("FailReason") private Integer failReason; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryToken.java
New file @@ -0,0 +1,27 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 获取token * @author zhibing.pu * @Date 2025/1/23 17:13 */ @Data public class QueryToken { /** * 运营商标识 */ @NotNull @JsonProperty("OperatorID") private String operatorID; /** * 运营商秘钥 */ @NotNull @JsonProperty("OperatorSecret") private String operatorSecret; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/QueryTokenResult.java
New file @@ -0,0 +1,51 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; /** * 获取token返回结果 * @author zhibing.pu * @Date 2025/1/23 17:15 */ @Data public class QueryTokenResult { /** * 运营商标识 */ @NotNull @JsonProperty("OperatorID") private String operatorID; /** * 成功状态 * 0:成功 * 1:失败 */ @NotNull @JsonProperty("SuccStat") private Integer succStat; /** * 获取的凭证 */ @NotNull @JsonProperty("AccessToken") private String accessToken; /** * 凭证有效期,秒 */ @NotNull @JsonProperty("TokenAvailableTime") private Long tokenAvailableTime; /** * 失败原因 * 0:无 * 1:无此运营商 * 2:秘钥错误 * 3`9自定义 */ @NotNull @JsonProperty("FailReason") private Integer failReason; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/StationInfo.java
New file @@ -0,0 +1,375 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import javax.validation.constraints.Null; import java.math.BigDecimal; import java.util.List; /** * 充电站信息 * @author zhibing.pu * @Date 2025/1/21 11:54 */ @Data public class StationInfo { /** * 充电站ID */ @NotNull @JsonProperty("StationID") private String stationID; /** * 充电站唯一编码 */ @NotNull @JsonProperty("StationUniqueNumber") private String stationUniqueNumber; /** * 运营商ID */ @NotNull @JsonProperty("OperatorID") private String operatorID; /** * 设备所属方ID * 设备所属运营平台组织机构代码 */ @NotNull @JsonProperty("EquipmentOwnerID") private String equipmentOwnerID; /** * 充电站名称 */ @NotNull @JsonProperty("StationName") private String stationName; /** * 充电站国家代码 */ @NotNull @JsonProperty("CountryCode") private String countryCode; /** * 充电站省市辖区编码 */ @NotNull @JsonProperty("AreaCode") private String areaCode; /** * 充电站所在县以下行政区划代码 */ @NotNull @JsonProperty("AreaCodeCountryside") private String areaCodeCountryside; /** * 详细地址 */ @NotNull @JsonProperty("Address") private String address; /** * 站点电话 */ @Null @JsonProperty("StationTel") private String stationTel; /** * 站点电话 */ @NotNull @JsonProperty("ServiceTel") private String serviceTel; /** * 站点分类(1:充电站,2:换电站,3:充换电一体站) */ @NotNull @JsonProperty("StationClassification") private Integer stationClassification; /** * 通用类型(1:通用,2:非通用) */ @NotNull @JsonProperty("GeneralApplicationType") private Integer generalApplicationType; /** * 站点类型 */ @NotNull @JsonProperty("StationType") private Integer stationType; /** * 站点状态 */ @NotNull @JsonProperty("StationStatus") private Integer stationStatus; /** * 车位数量,0:未知 */ @NotNull @JsonProperty("ParkNums") private Integer parkNums; /** * 经度(保留6位小数) */ @NotNull @JsonProperty("StationLng") private BigDecimal stationLng; /** * 纬度(保留6位小数) */ @NotNull @JsonProperty("StationLat") private BigDecimal stationLat; /** * 站点引导 */ @Null @JsonProperty("SiteGuide") private String siteGuide; /** * 建设场所 */ @NotNull @JsonProperty("Construction") private Integer construction; /** * 站点照片 * 字符串数组 */ @Null @JsonProperty("Pictures") private List<String> pictures; /** * 使用车型描述 */ @Null @JsonProperty("MatchCars") private String matchCars; /** * 服务车型描述 */ @Null @JsonProperty("SwapMatchCars") private List<String> swapMatchCars; /** * 车位楼层及数量描述 */ @Null @JsonProperty("ParkInfo") private String parkInfo; /** * 营业时间 */ @Null @JsonProperty("BusineHours") private String busineHours; /** * 7*24小时营业 * 0:否 * 1:是 */ @Null @JsonProperty("RoundTheClock") private Integer roundTheClock; /** * 停车费类型 * 0:免费 * 1:不免费 * 2:限时免费停车 * 3:充电限时减免 * 255:参考场地实际收费标准 */ @Null @JsonProperty("ParkType") private Integer parkType; /** * 充电电费率描述 */ @Null @JsonProperty("ElectricityFee") private String electricityFee; /** * 服务费率描述 */ @Null @JsonProperty("ServiceFee") private String serviceFee; /** * 停车费率描述 */ @Null @JsonProperty("ParkFee") private String parkFee; /** * 支付方式:刷卡、线上、现金 */ @Null @JsonProperty("Payment") private String payment; /** * 是否支持预约 */ @Null @JsonProperty("SupportOrder") private Integer supportOrder; /** * 备注 */ @Null @JsonProperty("Remark") private String remark; /** * 电费类型 * 1:商业用电 * 2:普通工业用电 * 3:大工业用电 * 4:其他用电 */ @JsonProperty("ElectricityType") private Integer electricityType; /** * 报装类型,是否独立报装 * 0:否 * 1:是 */ @JsonProperty("BusinessExpandType") private Integer businessExpandType; /** * 报装电源容量 */ @JsonProperty("Capacity") private BigDecimal capacity; /** * 站点额定总功率 */ @JsonProperty("RatedPower") private BigDecimal ratedPower; /** * 峰谷分时 * 0:否 * 1:是 */ @JsonProperty("PeriodFee") private Integer periodFee; /** * 正式投运时间 yyyy-MM-dd */ @JsonProperty("OfficialRunTime") private String officialRunTime; /** * 充换电站方位 * 1:地面-停车场 * 2:地面-路侧 * 3:地下停车场 * 4:立体式停车楼 */ @JsonProperty("StationOrientation") private Integer stationOrientation; /** * 充换电站建设面积 */ @JsonProperty("StationArea") private BigDecimal stationArea; /** * 充换电站人工值守 * 0:无 * 1:有 */ @JsonProperty("HavePerson") private Integer havePerson; /** * 视频监控配套情况 * 0:无 * 1:有 */ @JsonProperty("VideoMonitor") private Integer videoMonitor; /** * 周边配套设施 * 1:卫生间 * 2:便利店 * 3:餐厅 * 4:休息室 * 5:雨棚 */ @JsonProperty("SupportingFacilities") private List<Integer> supportingFacilities; /** * 是否有小票机 * 0:无 * 1:有 */ @JsonProperty("PrinterFlag") private Integer printerFlag; /** * 是否有道闸 * 0:无 * 1:有 */ @JsonProperty("BarrierFlag") private Integer barrierFlag; /** * 是否有地锁 * 0:无 * 1:有 */ @JsonProperty("ParkingLockFlag") private Integer parkingLockFlag; /** * 充电设备信息列表 */ @NotNull @JsonProperty("EquipmentInfos") private List<EquipmentInfo> equipmentInfos; /** * 占位费描述 */ @Null @JsonProperty("OvertimeFee") private String overtimeFee; /** * 占位费信息 */ @Null @JsonProperty("PlaceHolder") private PlaceHolder placeHolder; /** * 设备所属方名称 */ @JsonProperty("EquipmentOwnerName") private String equipmentOwnerName; /** * 供电局用户编号 */ @JsonProperty("ResidentNo") private String residentNo; /** * 供电类型 * 1:直供电 * 2:转供电 */ @JsonProperty("SupplyType") private Integer supplyType; /** * 表号 */ @JsonProperty("WattHourMeterNo") private String wattHourMeterNo; /** * 外电功率 */ @JsonProperty("ForwardPower") private String forwardPower; /** * 充电站全省唯一备案号 */ @JsonProperty("RecordUniqueNo") private String recordUniqueNo; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/StationStatsInfo.java
New file @@ -0,0 +1,99 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import java.math.BigDecimal; import java.util.List; /** * 充电站统计信息 * @author zhibing.pu * @Date 2025/1/21 15:17 */ @Data public class StationStatsInfo { /** * 充电站ID */ @NotNull @JsonProperty("StationID") private String stationID; /** * 设备所属方ID * 设备所属运营平台组织机构代码 */ @NotNull @JsonProperty("EquipmentOwnerID") private String equipmentOwnerID; /** * 运营商ID */ @NotNull @JsonProperty("OperatorID") private String operatorID; /** * 站点分类 1:充电站 * 2:换电站 * 3:充换电一体站 */ @NotNull @JsonProperty("StationClassification") private Integer stationClassification; /** * 统计的开始时间 * yyyy-MM-dd */ @NotNull @JsonProperty("StartTime") private String startTime; /** * 统计的结束时间 * yyyy-MM-dd */ @NotNull @JsonProperty("EndTime") private String endTime; /** * 充电站累计电量 kw/h */ @NotNull @JsonProperty("StationElectricity") private BigDecimal stationElectricity; /** * 充换电站累计 * 充电量 */ @NotNull @JsonProperty("StationTotalChargeEnergy") private BigDecimal stationTotalChargeEnergy; /** * 充换电站累计 * 告警数量 */ @NotNull @JsonProperty("StationTotalWarningNum") private Integer stationTotalWarningNum; /** 充换电站累计 其他电量 */ @NotNull @JsonProperty("StationTotalOtherEnergy") private BigDecimal stationTotalOtherEnergy; /** 充换电站累计 充电次数 */ @NotNull @JsonProperty("StationTotalChargeNum") private Integer stationTotalChargeNum; /** * 充电设备统计信息列表 */ @NotNull @JsonProperty("EquipmentStatsInfos") private List<EquipmentStatsInfo> equipmentStatsInfos; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/StationStatsInfoResult.java
New file @@ -0,0 +1,15 @@ package com.ruoyi.jianguan.model; import lombok.Data; import java.util.List; /** * 充电站统计信息 * @author zhibing.pu * @Date 2025/1/21 15:17 */ @Data public class StationStatsInfoResult { private List<StationStatsInfo> stationStatsInfos; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/StationStatusInfo.java
New file @@ -0,0 +1,31 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import java.util.List; /** * 充电站状态信息 * @author zhibing.pu * @Date 2025/1/21 15:07 */ @Data public class StationStatusInfo { /** * 充电站ID */ @NotNull @JsonProperty("StationID") private String stationID; /** * 充电设备接口状态列表 */ @JsonProperty("ConnectorStatusInfos") private List<ConnectorStatusInfo> connectorStatusInfos; @JsonProperty("OperatorID") private String OperatorID; @JsonProperty("EquipmentOwnerID") private String EquipmentOwnerID; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/SupChargeOrderInfo.java
New file @@ -0,0 +1,145 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import java.math.BigDecimal; /** * 推送充电订单信息 * 此接口用于数据提供方向数据需求方推送充电订单信息;充电 * 订单在充电结束时实时推送,同一订单只可推送一次,禁止重复推 * 送;推送失败时将推送失败的数据按小时级频率重试推送,直到推 * 送成功。 */ @Data public class SupChargeOrderInfo { /** * 充换电平台运营商ID */ @NotNull @JsonProperty("OperatorID") private String OperatorID; /** * 充换电服务运营商ID, * 所属方为个人时填写 * 999999999 */ @NotNull @JsonProperty("EquipmentOwnerID") private String EquipmentOwnerID; /** * 充换电站ID */ @NotNull @JsonProperty("StationID") private String StationID; /** * 充电设备编码 */ @NotNull @JsonProperty("EquipmentID") private String EquipmentID; /** * 充电订单号 * 格式“运营商ID+唯一 * 编号”,不超过64个字 * 符 */ @NotNull @JsonProperty("OrderNo") private String OrderNo; /** * 充电订单状态 * 1、启动中 * 2、充电中 * 3、停止中 * 4、充电完成 * 5、订单挂起 * 6、充电异常结束 * 7、启动失败 */ @NotNull @JsonProperty("OrderStatus") private Integer OrderStatus; /** * 充电设备接口编码 */ @NotNull @JsonProperty("ConnectorID") private String ConnectorID; /** * 设备接口分类 * 1:车辆充电设备接口 * 2:换电站内的电池箱 * 充电设备接口 */ @NotNull @JsonProperty("EquipmentClassification") private Integer EquipmentClassification = 1; /** * 推送时间 * yyyy-MM-dd HH:mm:ss ,充电设备推送给运 */ @NotNull @JsonProperty("PushTimeStamp") private String PushTimeStamp; /** * 开始充电时间 */ @NotNull @JsonProperty("StartTime") private String StartTime; /** * 本次采样时间 */ @NotNull @JsonProperty("EndTime") private String EndTime; /** * 累计充电量 小数点后4位 */ @NotNull @JsonProperty("TotalPower") private BigDecimal TotalPower; /** * 总电费 */ @NotNull @JsonProperty("TotalElecMoney") private BigDecimal TotalElecMoney; /** * 总服务费 */ @NotNull @JsonProperty("TotalServiceMoney") private BigDecimal TotalServiceMoney; /** * 累计总金额 */ @NotNull @JsonProperty("TotalMoney") private BigDecimal TotalMoney; /** * 充电结束原因 * 0:用户手动停止充电 * 1:客户归属地运营商平台停止充电 * 2:BMS停止充电 * 3:充电机设备故障 * 4:连接器断开 * 5~99: 自定义 */ @NotNull @JsonProperty("StopReason") private Integer StopReason; /** * 充电结束原因描 * 述 */ @NotNull @JsonProperty("StopDesc") private String StopDesc; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/SupConnectorPowerInfo.java
New file @@ -0,0 +1,25 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import java.math.BigDecimal; /** * 充电设备接口功率信息 */ @Data public class SupConnectorPowerInfo { @JsonProperty("ConnectorID") private String ConnectorID; @JsonProperty("EquipmentClassification") private Integer EquipmentClassification; @JsonProperty("DataTime") private String DataTime; @JsonProperty("ConnectorRealTimePower") private BigDecimal ConnectorRealTimePower; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/SupEquipChargeStatus.java
New file @@ -0,0 +1,134 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import java.math.BigDecimal; /** * 推送充电状态信息 * 此接口用于数据提供方向数据需求方推送充电设备的充电状态 * 开始充电实时推送一次、充电过程中50-60秒推送一 * 次、充电结束实时推送一次 */ @Data public class SupEquipChargeStatus { /** * 充换电平台运营商ID */ @NotNull @JsonProperty("OperatorID") private String OperatorID; /** * 充换电服务运营商ID, * 所属方为个人时填写 * 999999999 */ @NotNull @JsonProperty("EquipmentOwnerID") private String EquipmentOwnerID; /** * 充换电站ID */ @NotNull @JsonProperty("StationID") private String StationID; /** * 充电设备编码 */ @NotNull @JsonProperty("EquipmentID") private String EquipmentID; /** * 充电订单号 * 格式“运营商ID+唯一 * 编号”,不超过64个字 * 符 */ @NotNull @JsonProperty("OrderNo") private String OrderNo; /** * 充电订单状态 * 1、启动中 * 2、充电中 * 3、停止中 * 4、充电完成 * 5、订单挂起 * 6、充电异常结束 * 7、启动失败 */ @NotNull @JsonProperty("OrderStatus") private Integer OrderStatus; /** * 充电设备接口编码 */ @NotNull @JsonProperty("ConnectorID") private String ConnectorID; /** * 设备接口分类 * 1:车辆充电设备接口 * 2:换电站内的电池箱 * 充电设备接口 */ @NotNull @JsonProperty("EquipmentClassification") private Integer EquipmentClassification = 1; /** * 推送时间 * yyyy-MM-dd HH:mm:ss ,充电设备推送给运 */ @NotNull @JsonProperty("PushTimeStamp") private String PushTimeStamp; /** * 充电设备接口状态 ConnectorStatus * 0:离网 * 1:空闲 * 2: 占用(未充电) * 3: 占用(充电中) * 4: 占用(预约锁定) * 255:故障 */ @NotNull @JsonProperty("ConnectorStatus") private Integer ConnectorStatus; /** * A相电流 * 小数点后4 * 位 */ @NotNull @JsonProperty("CurrentA") private BigDecimal CurrentA; /** * 电池剩余电量 小数点后1 * 位 */ @NotNull @JsonProperty("SOC") private BigDecimal SOC; /** * 开始充电时间 */ @NotNull @JsonProperty("StartTime") private String StartTime; /** * 本次采样时间 */ @NotNull @JsonProperty("EndTime") private String EndTime; /** * 累计充电量 小数点后4位 */ @NotNull @JsonProperty("TotalPower") private BigDecimal TotalPower; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/SupEquipmentPowerInfo.java
New file @@ -0,0 +1,28 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import java.math.BigDecimal; import java.util.List; /** * 充电设备功率信息 */ @Data public class SupEquipmentPowerInfo { @JsonProperty("EquipmentID") private String EquipmentID; @JsonProperty("EquipmentClassification") private Integer EquipmentClassification; @JsonProperty("DataTime") private String DataTime; @JsonProperty("EquipRealTimePower") private BigDecimal EquipRealTimePower; @JsonProperty("ConnectorPowerInfos") private List<SupConnectorPowerInfo> ConnectorPowerInfos; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/SupStationInfo.java
New file @@ -0,0 +1,210 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import com.ruoyi.integration.drainage.SupSwapEquipmentInfo; import lombok.Data; import java.math.BigDecimal; import java.util.List; /** * 充换电站信息 */ @Data public class SupStationInfo { // 充换电站ID @JsonProperty("StationID") private String StationID; // 充换电站唯一编码 @JsonProperty("StationUniqueNumber") private String StationUniqueNumber; //平台运营商 //ID @JsonProperty("OperatorID") private String OperatorID; //充换电服务 //运营商ID @JsonProperty("EquipmentOwnerID") private String EquipmentOwnerID; //充换电站名 //称 @JsonProperty("StationName") private String StationName; //充换电站国 //家代码 @JsonProperty("CountryCode") private String CountryCode; //充换电站省 //市辖区编码 @JsonProperty("AreaCode") private String AreaCode; //详细地址 @JsonProperty("Address") private String Address; //充换电站所 //在县以下行 //政区划代码 @JsonProperty("AreaCodeCountryside") private String AreaCodeCountryside; // 站点电话 @JsonProperty("StationTel") private String StationTel; // 服务电话 @JsonProperty("ServiceTel") private String ServiceTel; // 站点分类 @JsonProperty("StationClassification") private Integer StationClassification; //通用类型 @JsonProperty("GeneralApplicationType") private Integer GeneralApplicationType; //站点类型 @JsonProperty("StationType") private Integer StationType; //站点状态 @JsonProperty("StationStatus") private Integer StationStatus; //车位数量 @JsonProperty("ParkNums") private Integer ParkNums; //经度 @JsonProperty("StationLng") private BigDecimal StationLng; //纬度 @JsonProperty("StationLat") private BigDecimal StationLat; //站点引导 @JsonProperty("SiteGuide") private String SiteGuide; //建设场所 @JsonProperty("Construction") private Integer Construction; //站点照片 @JsonProperty("Pictures") private List<String> Pictures; //使用车型描 //述 @JsonProperty("MatchCars") private String MatchCars; //服务车型描 //述 @JsonProperty("SwapMatchCars") private List<String> SwapMatchCars; //车位楼层及 //数量描述 @JsonProperty("ParkInfo") private String ParkInfo; //营业时间 @JsonProperty("BusineHours") private String BusineHours; //7*24小时营 //业 @JsonProperty("RoundTheClock") private Integer RoundTheClock; //停车费类型 @JsonProperty("ParkType") private Integer ParkType; //停车费描述 @JsonProperty("ParkFee") private String ParkFee; //支付方式 @JsonProperty("Payment") private String Payment; //是否支持预 //约 @JsonProperty("SupportOrder") private Integer SupportOrder; //备注 @JsonProperty("Remark") private String Remark; //电费类型 @JsonProperty("ElectricityType") private Integer ElectricityType; //报装类型 @JsonProperty("BusinessExpandType") private Integer BusinessExpandType; //报装电源容 //量 @JsonProperty("Capacity") private BigDecimal Capacity; //站点额定总 //功率 @JsonProperty("RatedPower") private BigDecimal RatedPower; //峰谷分时 @JsonProperty("PeriodFee") private Integer PeriodFee; //正式投运时 //间 @JsonProperty("OfficialRunTime") private String OfficialRunTime; //充换电站方 //位 @JsonProperty("StationOrientation") private Integer StationOrientation; //充换电站建 //设面积 @JsonProperty("StationArea") private BigDecimal StationArea; //充换电站人 //工值守 @JsonProperty("HavePerson") private Integer HavePerson; //视频监控配 //套情况 @JsonProperty("VideoMonitor") private Integer VideoMonitor; //周边配套设 // 施 @JsonProperty("SupportingFacilities") private List<Integer> SupportingFacilities; //是否有小票 //机 @JsonProperty("PrinterFlag") private Integer PrinterFlag; //是否有道闸 @JsonProperty("BarrierFlag") private Integer BarrierFlag; //是否有地锁 @JsonProperty("ParkingLockFlag") private Integer ParkingLockFlag; //充电设备信 //息列表 @JsonProperty("EquipmentInfos") private List<EquipmentInfo> EquipmentInfos; //换电设备信 //息 @JsonProperty("SwapEquipmentInfos") private List<SupSwapEquipmentInfo> SwapEquipmentInfos; //充电电费描 //述 @JsonProperty("ElectricityFee") private String ElectricityFee; //设备所属方 //名称 @JsonProperty("EquipmentOwnerName") private String EquipmentOwnerName; //供电局用户 //编号 @JsonProperty("ResidentNo") private String ResidentNo; //供电类型 @JsonProperty("SupplyType") private Integer SupplyType; //表号 @JsonProperty("WattHourMeterNo") private String WattHourMeterNo; //外电功率 @JsonProperty("ForwardPower") private BigDecimal ForwardPower; //服务费描述 @JsonProperty("ServiceFee") private String ServiceFee; //充电站全省 //唯一备案号 @JsonProperty("RecordUniqueNo") private String RecordUniqueNo; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/SupStationInfoResult.java
New file @@ -0,0 +1,16 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; /** * 充换电站信息 */ @Data public class SupStationInfoResult { @JsonProperty("SupStationInfo") private StationInfo SupStationInfo; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/SupStationPowerInfo.java
New file @@ -0,0 +1,31 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import java.math.BigDecimal; import java.util.List; /** * 推送充换电站实时功率 */ @Data public class SupStationPowerInfo { @NotNull @JsonProperty("OperatorID") private String OperatorID; @JsonProperty("EquipmentOwnerID") private String EquipmentOwnerID; @JsonProperty("StationID") private String StationID; @JsonProperty("StationClassification") private Integer StationClassification; @JsonProperty("DataTime") private String DataTime; @JsonProperty("StationRealTimePower") private BigDecimal StationRealTimePower; @JsonProperty("EquipmentPowerInfos") private List<SupEquipmentPowerInfo> EquipmentPowerInfos; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/SupStationPowerInfoResult.java
New file @@ -0,0 +1,17 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import java.io.Serializable; import java.util.List; /** * 推送充换电站实时功率 */ @Data public class SupStationPowerInfoResult implements Serializable { @JsonProperty("SupStationPowerInfos") private List<SupStationPowerInfo> SupStationPowerInfos; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/SuperviseQueryOperatorInfo.java
New file @@ -0,0 +1,22 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; /** * @author zhibing.pu * @Date 2025/2/19 9:36 */ @Data public class SuperviseQueryOperatorInfo { /** * 查询页码 */ @JsonProperty("PageNo") private Integer pageNo; /** * 每页数量 */ @JsonProperty("PageSize") private Integer pageSize; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/SuperviseQueryOperatorInfoResult.java
New file @@ -0,0 +1,57 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; import javax.validation.constraints.Null; /** * @author zhibing.pu * @Date 2025/2/19 9:39 */ @Data public class SuperviseQueryOperatorInfoResult { /** * 运营商ID */ @NotNull @JsonProperty("OperatorID") private String operatorID; /** * 运营商统一社会信用代码 */ @NotNull @JsonProperty("OperatorUSCID") private String operatorUSCID; /** * 运营商名称 */ @NotNull @JsonProperty("OperatorName") private String operatorName; /** * 运营商电话1 */ @NotNull @JsonProperty("OperatorTel1") private String operatorTel1; /** * 运营商电话2 */ @Null @JsonProperty("OperatorTel2") private String operatorTel2; /** * 运营商注册地址 */ @Null @JsonProperty("OperatorRegAddress") private String operatorRegAddress; /** * 备注信息 */ @Null @JsonProperty("OperatorNote") private String operatorNote; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/model/SuperviseQueryOperatorInfoResultPage.java
New file @@ -0,0 +1,34 @@ package com.ruoyi.jianguan.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import java.util.List; /** * @author zhibing.pu * @Date 2025/2/19 9:39 */ @Data public class SuperviseQueryOperatorInfoResultPage { /** * 查询页码 */ @JsonProperty("PageNo") private Integer pageNo; /** * 每页数量 */ @JsonProperty("PageCount") private Integer pageCount; /** * 每页数量 */ @JsonProperty("ItemSize") private Integer itemSize; /** * 数据 */ @JsonProperty("OperatorInfos") private List<SuperviseQueryOperatorInfoResult> operatorInfos; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/rocket/base/BaseMessage.java
New file @@ -0,0 +1,35 @@ package com.ruoyi.jianguan.rocket.base; import lombok.Data; import java.time.LocalDateTime; /** * 消息实体,所有消息都需要继承此类 */ @Data public abstract class BaseMessage { /** * 业务键,用于RocketMQ控制台查看消费情况 */ protected String key; /** * 发送消息来源,用于排查问题 */ protected String source = ""; /** * 发送时间 */ protected LocalDateTime sendTime = LocalDateTime.now(); /** * 重试次数,用于判断重试次数,超过重试次数发送异常警告 */ protected Integer retryTimes = 0; /** * 服务id */ protected String serviceId; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/rocket/base/ChargingOrderMessage.java
New file @@ -0,0 +1,18 @@ package com.ruoyi.jianguan.rocket.base; import lombok.Data; /** * 充电桩计费模型请求 **/ @Data public class ChargingOrderMessage extends BaseMessage { private String orderNumber;// 订单编号 private String soc;// soc } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/rocket/base/GunStatusMessage.java
New file @@ -0,0 +1,17 @@ package com.ruoyi.jianguan.rocket.base; import lombok.Data; /** * 充电桩计费模型请求 **/ @Data public class GunStatusMessage extends BaseMessage { private String fullNumber;// 枪完整编码 } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/rocket/base/JianGuanMessage.java
New file @@ -0,0 +1,15 @@ package com.ruoyi.jianguan.rocket.base; import com.ruoyi.jianguan.model.ConnectorStatusInfo; import com.ruoyi.jianguan.model.SupChargeOrderInfo; import com.ruoyi.jianguan.model.SupEquipChargeStatus; import lombok.Data; @Data public class JianGuanMessage extends BaseMessage { // 充电设备状态message private GunStatusMessage gunStatusMessage; // 推送充电订单状态/充电订单信息message private ChargingOrderMessage orderMessage; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/rocket/configuration/EnvironmentIsolationConfig.java
New file @@ -0,0 +1,32 @@ package com.ruoyi.jianguan.rocket.configuration; import org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.util.StringUtils; public class EnvironmentIsolationConfig implements BeanPostProcessor { private RocketEnhanceProperties rocketEnhanceProperties; public EnvironmentIsolationConfig(RocketEnhanceProperties rocketEnhanceProperties) { this.rocketEnhanceProperties = rocketEnhanceProperties; } /** * 在装载Bean之前实现参数修改 */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof DefaultRocketMQListenerContainer) { DefaultRocketMQListenerContainer container = (DefaultRocketMQListenerContainer) bean; if (rocketEnhanceProperties.isEnabledIsolation() && StringUtils.hasText(rocketEnhanceProperties.getEnvironment())) { container.setTopic(String.join("_", container.getTopic(), rocketEnhanceProperties.getEnvironment())); } return container; } return bean; } } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/rocket/configuration/RocketEnhanceProperties.java
New file @@ -0,0 +1,13 @@ package com.ruoyi.jianguan.rocket.configuration; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "rocketmq.enhance") @Data public class RocketEnhanceProperties { private boolean enabledIsolation; private String environment; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/rocket/configuration/RocketMQEnhanceAutoConfiguration.java
New file @@ -0,0 +1,61 @@ package com.ruoyi.jianguan.rocket.configuration; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.ruoyi.jianguan.rocket.util.RocketMQEnhanceTemplate; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.messaging.converter.CompositeMessageConverter; import org.springframework.messaging.converter.MappingJackson2MessageConverter; import org.springframework.messaging.converter.MessageConverter; import java.util.List; @Configuration @EnableConfigurationProperties(RocketEnhanceProperties.class) public class RocketMQEnhanceAutoConfiguration { /** * 注入增强的RocketMQEnhanceTemplate */ @Bean public RocketMQEnhanceTemplate rocketMQEnhanceTemplate(RocketMQTemplate rocketMQTemplate){ return new RocketMQEnhanceTemplate(rocketMQTemplate); } /** * 解决RocketMQ Jackson不支持Java时间类型配置 * 源码参考:{@link org.apache.rocketmq.spring.autoconfigure} */ @Bean @Primary public RocketMQMessageConverter enhanceRocketMQMessageConverter(){ RocketMQMessageConverter converter = new RocketMQMessageConverter(); CompositeMessageConverter compositeMessageConverter = (CompositeMessageConverter) converter.getMessageConverter(); List<MessageConverter> messageConverterList = compositeMessageConverter.getConverters(); for (MessageConverter messageConverter : messageConverterList) { if(messageConverter instanceof MappingJackson2MessageConverter){ MappingJackson2MessageConverter jackson2MessageConverter = (MappingJackson2MessageConverter) messageConverter; ObjectMapper objectMapper = jackson2MessageConverter.getObjectMapper(); objectMapper.registerModules(new JavaTimeModule()); } } return converter; } /** * 环境隔离配置 */ @Bean @ConditionalOnProperty(name="rocketmq.enhance.enabledIsolation", havingValue="true") public EnvironmentIsolationConfig environmentSetup(RocketEnhanceProperties rocketEnhanceProperties){ return new EnvironmentIsolationConfig(rocketEnhanceProperties); } } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/rocket/configuration/RocketMQMessageConverter.java
New file @@ -0,0 +1,46 @@ package com.ruoyi.jianguan.rocket.configuration; import org.springframework.messaging.converter.*; import org.springframework.util.ClassUtils; import java.util.ArrayList; import java.util.List; public class RocketMQMessageConverter { private static final boolean JACKSON_PRESENT; private static final boolean FASTJSON_PRESENT; static { ClassLoader classLoader = RocketMQMessageConverter.class.getClassLoader(); JACKSON_PRESENT = ClassUtils.isPresent("com.fasterxml.jackson,databind.ObjectMapper", classLoader) && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader); FASTJSON_PRESENT = ClassUtils.isPresent("com.alibaba.fastjson.JSON", classLoader) && ClassUtils.isPresent("com.alibaba.fastjson.support.config.FastJsonConfig", classLoader); } private final CompositeMessageConverter messageConverter; public RocketMQMessageConverter(){ List<MessageConverter> messageConverters = new ArrayList<>(); ByteArrayMessageConverter byteArrayMessageConverter = new ByteArrayMessageConverter(); byteArrayMessageConverter.setContentTypeResolver(null); messageConverters.add(byteArrayMessageConverter); messageConverters.add(new StringMessageConverter()); if (JACKSON_PRESENT) { messageConverters.add(new MappingJackson2MessageConverter()); } if(FASTJSON_PRESENT) { try { messageConverters.add( (MessageConverter) ClassUtils.forName( "com.alibaba.fastjson.support.spring.messaging.MappingFastJsonMessageConverter", ClassUtils.getDefaultClassLoader()).newInstance()); } catch (ClassNotFoundException | IllegalAccessException | InstantiationException ignored) { } } messageConverter = new CompositeMessageConverter(messageConverters); } public MessageConverter getMessageConverter(){ return messageConverter; } } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/rocket/constant/EnhanceMessageConstant.java
New file @@ -0,0 +1,14 @@ package com.ruoyi.jianguan.rocket.constant; public class EnhanceMessageConstant { /** * 延时等级 */ public static final int FIVE_SECOND=5000; /** * 消息前缀 */ public static final String RETRY_PREFIX="retry_"; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/rocket/produce/ChargingMessageListener.java
New file @@ -0,0 +1,262 @@ package com.ruoyi.jianguan.rocket.produce; import com.ruoyi.chargingPile.api.feignClient.AccountingStrategyDetailClient; import com.ruoyi.chargingPile.api.feignClient.ChargingGunClient; import com.ruoyi.chargingPile.api.feignClient.ChargingPileClient; import com.ruoyi.chargingPile.api.model.TChargingGun; import com.ruoyi.integration.api.model.*; import com.ruoyi.jianguan.model.ConnectorStatusInfo; import com.ruoyi.jianguan.model.SupChargeOrderInfo; import com.ruoyi.jianguan.model.SupEquipChargeStatus; import com.ruoyi.jianguan.rocket.base.ChargingOrderMessage; import com.ruoyi.jianguan.rocket.base.GunStatusMessage; import com.ruoyi.jianguan.rocket.base.JianGuanMessage; import com.ruoyi.jianguan.rocket.util.EnhanceMessageHandler; import com.ruoyi.jianguan.util.SendTagConstant; import com.ruoyi.jianguan.util.TCECSuperviseUtil; import com.ruoyi.order.api.feignClient.ChargingOrderClient; import com.ruoyi.order.api.model.TChargingOrder; import com.ruoyi.other.api.domain.Operator; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.spring.annotation.MessageModel; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; import org.apache.rocketmq.spring.core.RocketMQListener; import org.springframework.beans.BeanUtils; import org.springframework.cloud.stream.annotation.StreamListener; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.annotation.Resource; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.time.format.DateTimeFormatter; import java.util.Date; @Slf4j @Component @RocketMQMessageListener( messageModel = MessageModel.CLUSTERING, consumerGroup = "jianguan_message", topic = "jianguan_message", selectorExpression = "jianguan_message", consumeThreadMax = 64 //默认是64个线程并发消息,配置 consumeThreadMax 参数指定并发消费线程数,避免太大导致资源不够 ) public class ChargingMessageListener extends EnhanceMessageHandler<JianGuanMessage> implements RocketMQListener<JianGuanMessage> { @Resource private ChargingOrderClient chargingOrderClient; @Resource private AccountingStrategyDetailClient accountingStrategyDetailClient; @Resource private ChargingPileClient chargingPileClient; @Resource private ChargingGunClient chargingGunClient; @Resource private RedisTemplate redisTemplate; @Resource private TCECSuperviseUtil tcecSuperviseUtil; private final static String operatorId = "906171535"; @StreamListener("input") @Override protected void handleMessage(JianGuanMessage message) throws Exception { log.info("rocket收到的消息内容:{}", message); String serviceId = message.getServiceId(); if (!StringUtils.hasLength(serviceId)) { return; } log.info("rocket收到的消息内容:{} {}", serviceId, message); switch (serviceId) { case SendTagConstant.GUN_STATUS: GunStatusMessage gunStatusMessage = message.getGunStatusMessage(); log.info("推送充电设备接口状态:{}", gunStatusMessage); TChargingGun chargingGun = chargingGunClient.getChargingGunByFullNumber(gunStatusMessage.getFullNumber()).getData(); if (chargingGun!=null){ ConnectorStatusInfo connectorStatusInfo = new ConnectorStatusInfo(); connectorStatusInfo.setOperatorID(operatorId); connectorStatusInfo.setEquipmentOwnerID(operatorId); connectorStatusInfo.setStationID(String.valueOf(chargingGun.getSiteId())); connectorStatusInfo.setEquipmentID(String.valueOf(chargingGun.getChargingPileId())); connectorStatusInfo.setConnectorID(chargingGun.getFullNumber()); if (chargingGun.getEquipmentClassification()!=null){ connectorStatusInfo.setEquipmentClassification(chargingGun.getEquipmentClassification()); }else { connectorStatusInfo.setEquipmentClassification(1); } switch (chargingGun.getStatus()){ case 1: connectorStatusInfo.setStatus(0); break; case 2: connectorStatusInfo.setStatus(1); break; case 3: connectorStatusInfo.setStatus(2); break; case 4: connectorStatusInfo.setStatus(3); break; case 5: connectorStatusInfo.setStatus(3); break; case 6: connectorStatusInfo.setStatus(4); break; case 7: connectorStatusInfo.setStatus(255); break; } connectorStatusInfo.setUpdateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); tcecSuperviseUtil.notificationStationStatus(new Operator(), connectorStatusInfo); } break; case SendTagConstant.ORDER_INFO: ChargingOrderMessage orderInfoMessage = message.getOrderMessage(); log.info("推送充电订单信息:{}", orderInfoMessage); TChargingOrder chargingOrder1 = chargingOrderClient.getOrderByCode(orderInfoMessage.getOrderNumber()).getData(); SupChargeOrderInfo supChargeOrderInfo = new SupChargeOrderInfo(); supChargeOrderInfo.setOperatorID(operatorId); supChargeOrderInfo.setEquipmentOwnerID(operatorId); supChargeOrderInfo.setStationID(String.valueOf(chargingOrder1.getSiteId())); supChargeOrderInfo.setEquipmentID(String.valueOf(chargingOrder1.getChargingPileId())); supChargeOrderInfo.setOrderNo(operatorId+chargingOrder1.getCode()); TChargingGun chargingGun1 = chargingGunClient.getChargingGunById(chargingOrder1.getChargingGunId()).getData(); supChargeOrderInfo.setConnectorID(chargingGun1.getFullNumber()); supChargeOrderInfo.setEquipmentClassification(1); supChargeOrderInfo.setPushTimeStamp(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); supChargeOrderInfo.setStartTime(chargingOrder1.getStartTime() != null ? chargingOrder1.getStartTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : ""); supChargeOrderInfo.setEndTime(chargingOrder1.getEndTime() != null ? chargingOrder1.getEndTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : ""); supChargeOrderInfo.setTotalPower(chargingOrder1.getElectrovalence()); supChargeOrderInfo.setTotalElecMoney(chargingOrder1.getElectrovalence()); supChargeOrderInfo.setTotalServiceMoney(chargingOrder1.getServiceCharge()); supChargeOrderInfo.setTotalMoney(chargingOrder1.getOrderAmount()); switch (chargingOrder1.getEndMode()){ case 0: supChargeOrderInfo.setStopReason(5); supChargeOrderInfo.setStopDesc("异常终止"); break; case 1: supChargeOrderInfo.setStopReason(0); supChargeOrderInfo.setStopDesc("用户手动停止充电"); break; case 2: supChargeOrderInfo.setStopReason(1); supChargeOrderInfo.setStopDesc("客户归属地运营商平台停止充电"); break; case 3: supChargeOrderInfo.setStopReason(1); supChargeOrderInfo.setStopDesc("费用不足中止"); break; } tcecSuperviseUtil.notificationChargeOrderInfo(new Operator(), supChargeOrderInfo); break; case SendTagConstant.ORDER_STATUS: ChargingOrderMessage orderStatusMessage = message.getOrderMessage(); log.info("推送充电订单状态:{}", orderStatusMessage); TChargingOrder chargingOrder2 = chargingOrderClient.getOrderByCode(orderStatusMessage.getOrderNumber()).getData(); SupEquipChargeStatus supEquipChargeStatus = new SupEquipChargeStatus(); supEquipChargeStatus.setOperatorID(operatorId); supEquipChargeStatus.setEquipmentOwnerID(operatorId); supEquipChargeStatus.setStationID(String.valueOf(chargingOrder2.getSiteId())); supEquipChargeStatus.setEquipmentID(String.valueOf(chargingOrder2.getChargingPileId())); supEquipChargeStatus.setOrderNo(operatorId+chargingOrder2.getCode()); switch (chargingOrder2.getStatus()){ case 2: supEquipChargeStatus.setConnectorStatus(1); break; case 3: supEquipChargeStatus.setConnectorStatus(2); break; case 4: supEquipChargeStatus.setConnectorStatus(3); break; case 5: supEquipChargeStatus.setConnectorStatus(4); break; } TChargingGun chargingGun2 = chargingGunClient.getChargingGunById(chargingOrder2.getChargingGunId()).getData(); supEquipChargeStatus.setConnectorID(chargingGun2.getFullNumber()); supEquipChargeStatus.setEquipmentClassification(1); supEquipChargeStatus.setPushTimeStamp(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); switch (chargingGun2.getStatus()){ case 1: supEquipChargeStatus.setConnectorStatus(0); break; case 2: supEquipChargeStatus.setConnectorStatus(1); break; case 3: supEquipChargeStatus.setConnectorStatus(2); break; case 4: supEquipChargeStatus.setConnectorStatus(3); break; case 5: supEquipChargeStatus.setConnectorStatus(3); break; case 6: supEquipChargeStatus.setConnectorStatus(4); break; case 7: supEquipChargeStatus.setConnectorStatus(255); break; } supEquipChargeStatus.setCurrentA(chargingOrder2.getCurrent()); supEquipChargeStatus.setSOC(StringUtils.hasLength(orderStatusMessage.getSoc())?new BigDecimal(orderStatusMessage.getSoc()):new BigDecimal("1")); supEquipChargeStatus.setStartTime(chargingOrder2.getStartTime() != null ? chargingOrder2.getStartTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : ""); supEquipChargeStatus.setEndTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); supEquipChargeStatus.setTotalPower(chargingOrder2.getElectrovalence()); tcecSuperviseUtil.notificationSupEquipChargeStatus(new Operator(), supEquipChargeStatus); break; } } @Override protected void handleMaxRetriesExceeded(JianGuanMessage message) { // 当超过指定重试次数消息时此处方法会被调用 // 生产中可以进行回退或其他业务操作 log.error("消息消费失败,请执行后续处理"); } /** * 是否执行重试机制 */ @Override protected boolean isRetry() { return true; } @Override protected boolean throwException() { // 是否抛出异常,false搭配retry自行处理异常 return false; } /** * 若需要处理消息过滤,在父级中进行统一处理,或者在此处实现之后,自行处理 * * @param message 待处理消息 * @return true: 本次消息被过滤,false:不过滤 */ @Override protected boolean filter(JianGuanMessage message) { // 此处可做消息过滤 return false; } /** * 监听消费消息,不需要执行业务处理,委派给父类做基础操作,父类做完基础操作后会调用子类的实际处理类型 */ @Override public void onMessage(JianGuanMessage message) { super.dispatchMessage(message); } } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/rocket/util/EnhanceMessageHandler.java
New file @@ -0,0 +1,151 @@ package com.ruoyi.jianguan.rocket.util; import com.alibaba.fastjson.JSONObject; import com.ruoyi.jianguan.rocket.base.BaseMessage; import com.ruoyi.jianguan.rocket.constant.EnhanceMessageConstant; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; import javax.annotation.Resource; @Slf4j public abstract class EnhanceMessageHandler<T extends BaseMessage> { /** * 默认重试次数 */ private static final int MAX_RETRY_TIMES = 3; /** * 延时等级 */ private static final int DELAY_LEVEL = EnhanceMessageConstant.FIVE_SECOND; @Resource private RocketMQEnhanceTemplate rocketMQEnhanceTemplate; /** * 消息处理 * * @param message 待处理消息 * @throws Exception 消费异常 */ protected abstract void handleMessage(T message) throws Exception; /** * 超过重试次数消息,需要启用isRetry * * @param message 待处理消息 */ protected abstract void handleMaxRetriesExceeded(T message); /** * 是否需要根据业务规则过滤消息,去重逻辑可以在此处处理 * @param message 待处理消息 * @return true: 本次消息被过滤,false:不过滤 */ protected boolean filter(T message) { return false; } /** * 是否异常时重复发送 * * @return true: 消息重试,false:不重试 */ protected abstract boolean isRetry(); /** * 消费异常时是否抛出异常 * 返回true,则由rocketmq机制自动重试 * false:消费异常(如果没有开启重试则消息会被自动ack) */ protected abstract boolean throwException(); /** * 最大重试次数 * * @return 最大重试次数,默认5次 */ protected int getMaxRetryTimes() { return MAX_RETRY_TIMES; } /** * isRetry开启时,重新入队延迟时间 * @return -1:立即入队重试 */ protected int getDelayLevel() { return DELAY_LEVEL; } /** * 使用模板模式构建消息消费框架,可自由扩展或删减 */ public void dispatchMessage(T message) { // 基础日志记录被父类处理了 log.info("消费者收到消息[{}]", JSONObject.toJSON(message)); if (filter(message)) { log.info("消息id{}不满足消费条件,已过滤。",message.getKey()); return; } // 超过最大重试次数时调用子类方法处理 if (message.getRetryTimes() > getMaxRetryTimes()) { handleMaxRetriesExceeded(message); return; } try { long now = System.currentTimeMillis(); handleMessage(message); long costTime = System.currentTimeMillis() - now; log.info("消息{}消费成功,耗时[{}ms]", message.getKey(),costTime); } catch (Exception e) { log.error("消息{}消费异常", message.getKey(),e); // 是捕获异常还是抛出,由子类决定 if (throwException()) { //抛出异常,由DefaultMessageListenerConcurrently类处理 throw new RuntimeException(e); } //此时如果不开启重试机制,则默认ACK了 if (isRetry()) { handleRetry(message); } } } protected void handleRetry(T message) { // 获取子类RocketMQMessageListener注解拿到topic和tag RocketMQMessageListener annotation = this.getClass().getAnnotation(RocketMQMessageListener.class); if (annotation == null) { return; } //重新构建消息体 String messageSource = message.getSource(); if(!messageSource.startsWith(EnhanceMessageConstant.RETRY_PREFIX)){ message.setSource(EnhanceMessageConstant.RETRY_PREFIX + messageSource); } message.setRetryTimes(message.getRetryTimes() + 1); SendResult sendResult; try { // 如果消息发送不成功,则再次重新发送,如果发送异常则抛出由MQ再次处理(异常时不走延迟消息) sendResult = rocketMQEnhanceTemplate.send(annotation.topic(), annotation.selectorExpression(), message, getDelayLevel()); } catch (Exception ex) { // 此处捕获之后,相当于此条消息被消息完成然后重新发送新的消息 //由生产者直接发送 throw new RuntimeException(ex); } // 发送失败的处理就是不进行ACK,由RocketMQ重试 if (sendResult.getSendStatus() != SendStatus.SEND_OK) { throw new RuntimeException("重试消息发送失败"); } } } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/rocket/util/RocketMQEnhanceTemplate.java
New file @@ -0,0 +1,82 @@ package com.ruoyi.jianguan.rocket.util; import com.alibaba.fastjson.JSONObject; import com.ruoyi.jianguan.rocket.base.BaseMessage; import com.ruoyi.jianguan.rocket.configuration.RocketEnhanceProperties; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.apache.rocketmq.spring.support.RocketMQHeaders; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.Message; import org.springframework.messaging.support.MessageBuilder; import org.springframework.util.StringUtils; import javax.annotation.Resource; @Slf4j @RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class RocketMQEnhanceTemplate { private final RocketMQTemplate template; @Resource private RocketEnhanceProperties rocketEnhanceProperties; public RocketMQTemplate getTemplate() { return template; } /** * 根据系统上下文自动构建隔离后的topic * 构建目的地 */ public String buildDestination(String topic, String tag) { topic = reBuildTopic(topic); return topic + ":" + tag; } /** * 根据环境重新隔离topic * @param topic 原始topic */ private String reBuildTopic(String topic) { if(rocketEnhanceProperties.isEnabledIsolation() && StringUtils.hasText(rocketEnhanceProperties.getEnvironment())){ return topic +"_" + rocketEnhanceProperties.getEnvironment(); } return topic; } /** * 发送同步消息 */ public <T extends BaseMessage> SendResult send(String topic, String tag, T message) { // 注意分隔符 return send(buildDestination(topic,tag), message); } public <T extends BaseMessage> SendResult send(String destination, T message) { // 设置业务键,此处根据公共的参数进行处理 // 更多的其它基础业务处理... Message<T> sendMessage = MessageBuilder.withPayload(message).setHeader(RocketMQHeaders.TAGS, message.getKey()).build(); SendResult sendResult = template.syncSend(destination, sendMessage); // 此处为了方便查看给日志转了json,根据选择选择日志记录方式,例如ELK采集 log.info("[{}]同步消息[{}]发送结果[{}]", destination, JSONObject.toJSON(message), JSONObject.toJSON(sendResult)); return sendResult; } /** * 发送延迟消息 */ public <T extends BaseMessage> SendResult send(String topic, String tag, T message, int delayLevel) { return send(buildDestination(topic,tag), message, delayLevel); } public <T extends BaseMessage> SendResult send(String destination, T message, int delayLevel) { Message<T> sendMessage = MessageBuilder.withPayload(message).setHeader(RocketMQHeaders.TAGS, message.getKey()).build(); SendResult sendResult = template.syncSend(destination, sendMessage, 3000, delayLevel); log.info("[{}]延迟等级[{}]消息[{}]发送结果[{}]", destination, delayLevel, JSONObject.toJSON(message), JSONObject.toJSON(sendResult)); return sendResult; } } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/util/AESUtil.java
New file @@ -0,0 +1,107 @@ package com.ruoyi.jianguan.util; import com.ruoyi.common.core.utils.StringUtils; import org.springframework.util.Base64Utils; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; /** * 定义AES加密解密工具类 */ public class AESUtil { private static final String KEY_ALGORITHM = "AES";//加密方式 private static final String DEFAULT_CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";//默认的加密算法 private static final String KEY = "1234567890abcdef";//密码 private static final String IV_PARAMETER = "1234567890abcdef";//偏移量 private static final String CHARSET = "UTF-8";//编码 /** * 加密操作 * @param content 待加密内容 * @return * @throws Exception */ public static String encrypt(String content) { return encrypt(content, KEY, IV_PARAMETER); } /** * 加密操作 * @param content 待加密内容 * @return * @throws Exception */ public static String encrypt(String content, String key, String iv_parameter) { try { if(StringUtils.isEmpty(content)){ return content; } Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM); byte[] raw = key.getBytes(CHARSET); SecretKeySpec skeySpec = new SecretKeySpec(raw, KEY_ALGORITHM); IvParameterSpec iv = new IvParameterSpec(iv_parameter.getBytes()); cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); byte[] encrypted = cipher.doFinal(content.getBytes(CHARSET)); return Base64Utils.encodeToString(encrypted); }catch (Exception e){ e.printStackTrace(); } return null; } public static String decrypt(String content) { return decrypt(content, KEY, IV_PARAMETER); } /** *解密操作 * @param content 待解密内容 * @return * @throws Exception */ public static String decrypt(String content, String key, String iv_parameter) { try { if(StringUtils.isEmpty(content)){ return content; } byte[] raw = key.getBytes(CHARSET); SecretKeySpec skeySpec = new SecretKeySpec(raw, KEY_ALGORITHM); Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM); IvParameterSpec iv = new IvParameterSpec(iv_parameter.getBytes()); cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); byte[] encrypted1 = Base64Utils.decodeFromString(content); byte[] original = cipher.doFinal(encrypted1); String originalString = new String(original, CHARSET); return originalString; } catch (Exception ex) { ex.printStackTrace(); } return null; } public static void main(String[] ages){ // String encrypt = AESUtil.encrypt("{\"OperatorSecret\":\"cn51EeFQDTSMsn11R1ZNsYSEYBxDYcKK\",\"OperatorID\":\"MA25CNM38\"}", "YPFVz1OvAS4nSwLW", "5tLoP60aR9QUB5Mx"); // System.err.println(encrypt); String travel = AESUtil.decrypt("9gVnNqAh9O7IuqqbyD8G1ukK86O3g0bUBLzM1LJL060bNjPJCtW0wWRjr756abxIm+nOuKkjMy7/DYScMcnl2KSYJJJb6Xc4Aza8L24Mp/UKQyW6Fe9m+ThDVUfMwvn7U2OxHDXniBUdmpNi2Ex9uHa/R18H2ka0DCv/bKCm/F4KTfz48Et/1L64JTTmj7l4the0Wr7KGiVewPIEE03LF5lF+h9j0W8czC6Gx5UJOMU=", "YPFVz1OvAS4nSwLW", "5tLoP60aR9QUB5Mx"); System.err.println(travel); } } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/util/AesEncryption.java
New file @@ -0,0 +1,55 @@ package com.ruoyi.jianguan.util; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; /** * 充电桩交互的数据的加密解密 */ public class AesEncryption { /** * 加密 * @param key * @param iv * @param data * @return */ public static String encrypt(String key, String iv, String data) { try { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "AES"); IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes()); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); byte[] encrypted = cipher.doFinal(data.getBytes()); return Base64.getEncoder().encodeToString(encrypted); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 解密 * @param key * @param iv * @param encryptedData * @return */ public static String decrypt(String key, String iv, String encryptedData) { try { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "AES"); IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes()); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedData)); return new String(decrypted); } catch (Exception e) { e.printStackTrace(); } return null; } } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/util/HMacMD5Util.java
New file @@ -0,0 +1,122 @@ package com.ruoyi.jianguan.util; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class HMacMD5Util { /** * 加签 * @param operatorId * @param timeStamp * @param data * @param seq * @param SigSecret * @return */ public static String getHMacMD5(String operatorId,String timeStamp, String data, String seq,String SigSecret) { String m = new StringBuilder(operatorId).append(data).append(timeStamp).append(seq).toString(); byte[] macMD5 = HMacMD5Util.getHMacMD5Bytes(SigSecret.getBytes(), m.getBytes()); return HMacMD5Util.bytesToHexString(macMD5); } /** * HmacMd5的计算公式为:HMAC(K,M) = H(K⊕opad∣H(K⊕ipad∣M)) * 其中:K是密钥(byte[] key),长度可为64字节(后面涉及描述都是以字节byte进行),若小于该长度,在密钥后面用0(即0x00)补齐。 * M是消息内容(byte[] m); * H是散列函数(此处采用MD5); * opad和ipad分别是由若干个0x5c和0x36组成的字符串; * ⊕表示异或运算; * ∣表示连接操作。 **/ private static byte[] getHMacMD5Bytes(byte[] key, byte[] m) { try { //定义长度 int length = 64; //定义opad和ipad byte[] opad = new byte[length]; byte[] ipad = new byte[length]; for (int i = 0; i < 64; i++) { opad[i] = 0x5C; ipad[i] = 0x36; } byte[] actualKey = key; byte[] keyArr = new byte[length]; //如果密钥长度,大于64字节,就使用MD5算法计算其散列值,作为密钥 if (key.length > length) { actualKey = md5(key); } for (int i = 0; i < actualKey.length; i++) { keyArr[i] = actualKey[i]; } //如果密钥长度不足64字节,就使用0x00补齐到64字节 if (actualKey.length < length) { for (int i = key.length; i < length; i++) keyArr[i] = 0x00; } //使用密钥和ipad进行异或运算【K⊕ipad】 byte[] kIpadXorResult = new byte[length]; for (int i = 0; i < length; i++) { kIpadXorResult[i] = (byte) (keyArr[i] ^ ipad[i]); } //将待加密数据M追加到kIpadXorResult后面【K⊕ipad∣M】 byte[] firstAppendResult = new byte[kIpadXorResult.length + m.length]; for (int i = 0; i < kIpadXorResult.length; i++) { firstAppendResult[i] = kIpadXorResult[i]; } for (int i = 0; i < m.length; i++) { firstAppendResult[i + keyArr.length] = m[i]; } //做MD5运算【H(K⊕ipad∣M)】 byte[] firstHashResult = md5(firstAppendResult); //使用密钥和opad进行异或运算【K⊕opad】 byte[] kOpadXorResult = new byte[length]; for (int i = 0; i < length; i++) { kOpadXorResult[i] = (byte) (keyArr[i] ^ opad[i]); } //将firstHashResult追加到kOpadXorResult后面【K⊕opad∣H(K⊕ipad∣M)】 byte[] secondAppendResult = new byte[kOpadXorResult.length + firstHashResult.length]; for (int i = 0; i < kOpadXorResult.length; i++) { secondAppendResult[i] = kOpadXorResult[i]; } for (int i = 0; i < firstHashResult.length; i++) { secondAppendResult[kOpadXorResult.length + i] = firstHashResult[i]; } //做MD5运算【H(K⊕opad∣H(K⊕ipad∣M))】 return md5(secondAppendResult); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } /** * MD5(产生出一个128位(16字节)的散列值) **/ private static byte[] md5(byte[] str) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(str); return md.digest(); } /** * HEX转化为字符串 **/ private static String bytesToHexString(byte[] m) { StringBuilder stringBuilder = new StringBuilder(); if (m == null || m.length <= 0) { return null; } for (int i = 0; i < m.length; i++) { int v = m[i] & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } return stringBuilder.toString().toUpperCase(); } } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/util/SendTagConstant.java
New file @@ -0,0 +1,22 @@ package com.ruoyi.jianguan.util; /** * @author xiaochen * @Date 2024/8/22 15:28 */ public class SendTagConstant { /** * 推送充电设备接口状态信息 */ public static final String GUN_STATUS ="gun_status"; /** * 推送充电状态信息 */ public static final String ORDER_STATUS ="order_status"; /** * 推送充电订单信息 */ public static final String ORDER_INFO = "order_info"; } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/util/SequenceGenerator.java
New file @@ -0,0 +1,56 @@ package com.ruoyi.jianguan.util; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; public class SequenceGenerator { private final ConcurrentHashMap<Long, AtomicInteger> counterMap = new ConcurrentHashMap<>(); public synchronized String getNextSequence() { long currentTimestamp = System.currentTimeMillis() / 1000; // 获取当前秒级时间戳 AtomicInteger counter = counterMap.get(currentTimestamp); if (counter == null) { counter = new AtomicInteger(1); // 新的一秒,初始化计数器为1 counterMap.put(currentTimestamp, counter); } else { counter.incrementAndGet(); // 同一秒内,计数器递增 } // 生成四位序列号 String sequence = String.format("%04d", counter.get()); return sequence; } public static void main(String[] args) { SequenceGenerator generator = new SequenceGenerator(); // 测试生成多个序列号 for (int i = 0; i < 10; i++) { System.out.println(generator.getNextSequence()); try { Thread.sleep(100); // 模拟同一秒内的多次调用 } catch (InterruptedException e) { e.printStackTrace(); } } // 模拟进入新的一秒 try { Thread.sleep(1100); // 等待超过1秒 } catch (InterruptedException e) { e.printStackTrace(); } // 再次生成序列号 for (int i = 0; i < 10; i++) { System.out.println(generator.getNextSequence()); try { Thread.sleep(100); // 模拟同一秒内的多次调用 } catch (InterruptedException e) { e.printStackTrace(); } } } } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/util/SignUtil.java
New file @@ -0,0 +1,205 @@ package com.ruoyi.jianguan.util; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; /** * 签名工具 * @author zhibing.pu * @Date 2025/1/23 11:30 */ public class SignUtil { /*************************************快电******************************************/ /** * 签名算法 * * @param aValue 加密的原文,即源数据 * @param aKey 密钥 这是针对一条字符串进行加密的方法 */ public static String hmacSign (String aValue, String aKey) { byte k_ipad[] = new byte[64]; byte k_opad[] = new byte[64]; byte keyb[]; byte value[]; try { keyb = aKey.getBytes("UTF-8"); value = aValue.getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { keyb = aKey.getBytes(); value = aValue.getBytes(); } Arrays.fill(k_ipad, keyb.length, 64, (byte) 54); Arrays.fill(k_opad, keyb.length, 64, (byte) 92); for (int i = 0; i < keyb.length; i++) { k_ipad[i] = (byte) (keyb[i] ^ 0x36); k_opad[i] = (byte) (keyb[i] ^ 0x5c); } MessageDigest md = null; try { md = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { return null; } md.update(k_ipad); md.update(value); byte dg[] = md.digest(); md.reset(); md.update(k_opad); md.update(dg, 0, 16); dg = md.digest(); return toHex(dg); } public static String toHex (byte input[]) { if (input == null) { return null; } StringBuffer output = new StringBuffer(input.length * 2); for (int i = 0; i < input.length; i++) { int current = input[i] & 0xff; if (current < 16) { output.append("0"); } output.append(Integer.toString(current, 16)); } return output.toString().toUpperCase(); } /*************************************新电途******************************************/ /** * HmacMd5的计算公式为:HMAC(K,M) = H(K⊕opad∣H(K⊕ipad∣M)) * 其中:K是密钥(byte[] key),长度可为64字节(后面涉及描述都是以字节byte进行),若小于该长度,在密钥后面用0(即0x00)补齐。 * M是消息内容(byte[] m); * H是散列函数(此处采用MD5); * opad和ipad分别是由若干个0x5c和0x36组成的字符串; * ⊕表示异或运算; * ∣表示连接操作。 **/ public static byte[] getHMacMD5Bytes(byte[] key, byte[] m) { try { //定义长度 int length = 64; //定义opad和ipad byte[] opad = new byte[length]; byte[] ipad = new byte[length]; for (int i = 0; i < length; i++) { opad[i] = 0x5C; ipad[i] = 0x36; } byte[] actualKey = key; byte[] keyArr = new byte[length]; //如果密钥长度,大于64字节,就使用MD5算法计算其散列值,作为密钥 if (key.length > length) { actualKey = md5(key); } for (int i = 0; i < actualKey.length; i++) { keyArr[i] = actualKey[i]; } //如果密钥长度不足64字节,就使用0x00补齐到64字节 if (actualKey.length < length) { for (int i = key.length; i < length; i++) { keyArr[i] = 0x00; } } //使用密钥和ipad进行异或运算【K⊕ipad】 byte[] kIpadXorResult = new byte[length]; for (int i = 0; i < length; i++) { kIpadXorResult[i] = (byte) (keyArr[i] ^ ipad[i]); } //将待加密数据M追加到kIpadXorResult后面【K⊕ipad∣M】 byte[] firstAppendResult = new byte[kIpadXorResult.length + m.length]; for (int i = 0; i < kIpadXorResult.length; i++) { firstAppendResult[i] = kIpadXorResult[i]; } for (int i = 0; i < m.length; i++) { firstAppendResult[i + keyArr.length] = m[i]; } //做MD5运算【H(K⊕ipad∣M)】 byte[] firstHashResult = md5(firstAppendResult); //使用密钥和opad进行异或运算【K⊕opad】 byte[] kOpadXorResult = new byte[length]; for (int i = 0; i < length; i++) { kOpadXorResult[i] = (byte) (keyArr[i] ^ opad[i]); } //将firstHashResult追加到kOpadXorResult后面【K⊕opad∣H(K⊕ipad∣M)】 byte[] secondAppendResult = new byte[kOpadXorResult.length + firstHashResult.length]; for (int i = 0; i < kOpadXorResult.length; i++) { secondAppendResult[i] = kOpadXorResult[i]; } for (int i = 0; i < firstHashResult.length; i++) { secondAppendResult[kOpadXorResult.length + i] = firstHashResult[i]; } //做MD5运算【H(K⊕opad∣H(K⊕ipad∣M))】 return md5(secondAppendResult); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } /** * MD5(产生出一个128位(16字节)的散列值) **/ private static byte[] md5(byte[] str) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(str); return md.digest(); } /** * HEX转化为字符串 **/ public static String bytesToHexString(byte[] m) { StringBuilder stringBuilder = new StringBuilder(); if (m == null || m.length <= 0) { return null; } for (int i = 0; i < m.length; i++) { int v = m[i] & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } //最后得到的签名,统一转化为大写 return stringBuilder.toString().toUpperCase(); } public static void main(String[] args) { // String encrypt = AESUtil.encrypt("{\"total\":1,\"stationStatusInfo\":{\"operationID\":\"123456789\",\"stationID\":\"111111111111111\",\"connectorStatusInfos\":{\"connectorID\":1,\"equipmentID\":\"10000000000000000000001\",\"status\":4,\"currentA\":0,\"currentB\":0,\"currentC\":0,\"voltageA\":0,\"voltageB\":0,\"voltageC\":0,\"soc\":10,}}}"); // String s = hmacSign(encrypt, "123456789abcdef"); // System.err.println(s); //签名秘钥SigSecret String key = "1234567890abcdef"; //运营商标识OperatorId String operatorId = "123456789"; //参数信息Data String data = "il7B0BSEjFdzpyKzfOFpvg/Se1CP802RItKYFPfSLRxJ3jf0bVl9hvYOEktPAYW2nd7S8MBcyHYyacHKbISq5iTmDzG+ivnR+SZJv3USNTYVMz9rCQVSxd0cLlqsJauko79NnwQJbzDTyLooYoIwz75qBOH2/xOMirpeEqRJrF/EQjWekJmGk9RtboXePu2rka+Xm51syBPhiXJAq0GfbfaFu9tNqs/e2Vjja/ltE1M0lqvxfXQ6da6HrThsm5id4ClZFIi0acRfrsPLRixS/IQYtksxghvJwbqOsbIsITail9Ayy4tKcogeEZiOO+4Ed264NSKmk7l3wKwJLAFjCFogBx8GE3OBz4pqcAn/ydA="; //时间戳TimeStamp(格式:年月日时分秒) String timeStamp = "20160729142400"; //自增序列Seq String seq = "0001"; //进行字符串拼接、计算 String m = new StringBuilder(operatorId).append(data).append(timeStamp).append(seq).toString(); byte[] hmacMd5 = getHMacMD5Bytes(key.getBytes(), m.getBytes()); // 打印计算得到的签名Sig System.out.println(bytesToHexString(hmacMd5)); } } ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/util/TCECSuperviseUtil.java
New file @@ -0,0 +1,373 @@ package com.ruoyi.jianguan.util; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpResponse; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.nacos.common.utils.JacksonUtils; import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.ruoyi.common.redis.service.RedisService; import com.ruoyi.jianguan.model.*; import com.ruoyi.other.api.domain.Operator; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; /** * 中电联TCEC标准 * @author zhibing.pu * @Date 2025/1/21 11:48 */ @Slf4j @Component public class TCECSuperviseUtil { // 测试环境 // private static final String OperatorID = "MA01H3BQ2"; // private static final String OperatorSecret = "f1331ef0b37c2d1b"; // private static final String SigSecret = "a6fedf0e1b27d6f7"; // private static final String DataSecret = "50a61b93919c9604"; // private static final String DataSecretIV = "7c8ac6861661d584"; // private final static String url = "https://dev-gov-hlht-sc.unievbj.com/evcs/v1.0.0"; // 正式环境 private static final String OperatorID = "MA01H3BQ2"; private static final String OperatorSecret = "a762796b2a8989b8"; private static final String SigSecret = "52cd107eb677c004"; private static final String DataSecret = "98f46ab6481d87c4"; private static final String DataSecretIV = "978170fd1c11a70e"; private final static String url = "https://hlht-dipper-sc.unievbj.com/evcs/v1.0.0"; private final static String query_token = "/query_token"; private static final String OurDataSecret = "50a61b93919c9605"; private static final String OurDataSecretIV = "7c8ac6861661d585"; private static final String OurSigSecret = "a6fedf0e1b27d6f6"; private static final String OurOperatorID = "MA01H3BQ3"; private static final String OurOperatorSecret = "f1331ef0b37c2d1a"; @Autowired private RedisService redisService; public static final String TOKEN_KEY = "charge_token:"; /** * 获取token */ /** * 推送充电设备接口状态信息 */ private final static String supervise_notification_station_status = "/supervise_notification_station_status"; /** *推送充电状态信息 */ private final static String supervise_notification_equip_charge_status = "/supervise_notification_equip_charge_status"; /** *推送充电订单信息 */ private final static String supervise_notification_charge_order_info = "/supervise_notification_charge_order_info"; private final static String supervise_notification_operation_stats_info = "/supervise_notification_operation_stats_info"; private final static String supervise_notification_realtime_power_info = "/supervise_notification_realtime_power_info"; private final static String supervise_notification_station_info = "/supervise_notification_station_info"; /** 获取token */ // public String queryToken(){ // String token = redisService.getCacheObject(TOKEN_KEY); // if(StringUtils.hasLength(token)){ // return token; // } // JSONObject jsonObject = new JSONObject(); // jsonObject.put("OperatorID", OperatorID); // jsonObject.put("OperatorSecret", OperatorSecret); // String params = jsonObject.toJSONString(); // // 参数加密 // String data = AesEncryption.encrypt(DataSecret, DataSecretIV, params); // // 获取签名 // String timeStamp = System.currentTimeMillis() + ""; // SequenceGenerator generator = new SequenceGenerator(); // String nextSequence = generator.getNextSequence(); // String hmacMD5 = HMacMD5Util.getHMacMD5(OperatorID,timeStamp, data,nextSequence,SigSecret); // jsonObject = new JSONObject(); // jsonObject.put("OperatorID", OperatorID); // jsonObject.put("Data", data); // jsonObject.put("TimeStamp", timeStamp); // jsonObject.put("Seq", nextSequence); // jsonObject.put("Sig", hmacMD5); // String result = HttpUtils.sendPost(url+query_token, jsonObject.toJSONString()); // String string = JSONObject.parseObject(result).getString("Data"); // String decrypt = AesEncryption.decrypt(DataSecret, DataSecretIV, string); // JSONObject tokenResult = JSONObject.parseObject(decrypt); // token = tokenResult.getString("AccessToken"); // Integer TokenAvailableTime = tokenResult.getInteger("TokenAvailableTime"); // redisService.setCacheObject(TOKEN_KEY,token, (long) (TokenAvailableTime - 60), TimeUnit.SECONDS); // return token; // } public String queryToken(){ HttpRequest post = HttpUtil.createPost(url + query_token); JSONObject info = new JSONObject(); info.put("OperatorID", "906171535"); info.put("OperatorSecret", OperatorSecret); Long timeStamp = Long.valueOf(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); post.contentType("application/json;charset=utf-8"); BaseRequestJianGuan baseRequest = new BaseRequestJianGuan(); baseRequest.setOperatorID("906171535"); baseRequest.setTimeStamp(timeStamp+""); baseRequest.setSeq("0001"); String jsonString = JacksonUtils.toJson(info); SequenceGenerator generator = new SequenceGenerator(); String nextSequence = generator.getNextSequence(); String data = AesEncryption.encrypt(DataSecret, DataSecretIV,jsonString); String hmacMD5 = HMacMD5Util.getHMacMD5("906171535",timeStamp+"", data,nextSequence,SigSecret); baseRequest.setData(data); baseRequest.setSig(hmacMD5); String request_json = JacksonUtils.toJson(baseRequest); log.info("获取三方平台授权token请求地址:" + post.getUrl()); log.info("获取三方平台授权token请求参数:" + request_json); log.info("获取三方平台授权token请求Data:" + jsonString); post.body(request_json); HttpResponse execute = post.execute(); if(200 != execute.getStatus()){ log.error("获取三方平台授权token失败:" + execute.body()); return null; } log.info("获取三方平台授权token响应参数:" + execute.body()); BaseResult baseResult = JSON.parseObject(execute.body(), BaseResult.class); Integer Ret = baseResult.getRet(); if(0 != Ret){ log.error("获取三方平台授权token失败:" + baseResult.getMsg()); return null; } //解密参数 String decrypt = AESUtil.decrypt(baseResult.getData(), DataSecret, DataSecretIV); log.info("获取三方平台授权token响应Data:" + decrypt); QueryTokenResult queryTokenResult = JSON.parseObject(decrypt, QueryTokenResult.class); String token = queryTokenResult.getAccessToken(); // Long tokenAvailableTime = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) + queryTokenResult.getTokenAvailab return token; } /** * 设备状态变化推送 * @param info */ public NotificationStationStatusResult notificationStationStatus(Operator operator, ConnectorStatusInfo info) { HttpRequest post = HttpUtil.createPost(url+supervise_notification_station_status); buildBody(post, info, operator); HttpResponse execute = post.execute(); if(200 != execute.getStatus()){ log.error("推送三方平台设备状态失败:" + execute.body()); return null; } log.info("推送三方平台设备状态响应:" + execute.body()); BaseResult baseResult = JSON.parseObject(execute.body(), BaseResult.class); Integer Ret = baseResult.getRet(); if(0 != Ret){ log.error("推送三方平台设备状态失败:" + baseResult.getMsg()); return null; } //解密参数 String decrypt = AESUtil.decrypt(baseResult.getData(), DataSecret, DataSecretIV); log.info("推送三方平台设备状态Data:" + decrypt); NotificationStationStatusResult notificationStationStatusResult = JSON.parseObject(decrypt, NotificationStationStatusResult.class); return notificationStationStatusResult; } /** * 推动充电状态 * @param info * @return */ public NotificationEquipChargeStatusResult notificationSupEquipChargeStatus(Operator operator, SupEquipChargeStatus info){ HttpRequest post = HttpUtil.createPost(url+supervise_notification_equip_charge_status); buildBody(post, info, operator); HttpResponse execute = post.execute(); if(200 != execute.getStatus()){ log.error("推送三方平台充电状态失败:" + execute.body()); return null; } log.info("推送三方平台充电状态响应:" + execute.body()); BaseResult baseResult = JSON.parseObject(execute.body(), BaseResult.class); Integer Ret = baseResult.getRet(); if(0 != Ret){ log.error("推送三方平台充电状态失败:" + baseResult.getMsg()); return null; } //解密参数 String decrypt = AESUtil.decrypt(baseResult.getData(), DataSecret, DataSecretIV); log.info("推送三方平台充电状态Data:" + decrypt); NotificationEquipChargeStatusResult notificationEquipChargeStatusResult = JSON.parseObject(decrypt, NotificationEquipChargeStatusResult.class); return notificationEquipChargeStatusResult; } /** * 推送充电订单信息 * @param info * @return */ public NotificationChargeOrderInfoResult notificationChargeOrderInfo(Operator operator, SupChargeOrderInfo info){ HttpRequest post = HttpUtil.createPost(url+supervise_notification_charge_order_info); if (info.getOrderStatus()!=null){ switch (info.getOrderStatus()){ case -1: info.setOrderStatus(7); break; case 0: info.setOrderStatus(7); break; case 1: info.setOrderStatus(1); break; case 2: info.setOrderStatus(1); break; case 3: info.setOrderStatus(2); break; case 4: info.setOrderStatus(3); break; case 5: info.setOrderStatus(4); break; } }else{ info.setOrderStatus(5); } buildBody(post, info, operator); HttpResponse execute = post.execute(); if(200 != execute.getStatus()){ log.error("推送三方平台充电订单信息失败:" + execute.body()); return null; } log.info("推送三方平台充电订单信息响应:" + execute.body()); BaseResult baseResult = JSON.parseObject(execute.body(), BaseResult.class); Integer Ret = baseResult.getRet(); if(0 != Ret){ log.error("推送三方平台充电订单信息失败:" + baseResult.getMsg()); return null; } //解密参数 String decrypt = AESUtil.decrypt(baseResult.getData(), DataSecret, DataSecretIV); log.info("推送三方平台充电订单信息Data:" + decrypt); NotificationChargeOrderInfoResult notificationChargeOrderInfoResult = JSON.parseObject(decrypt, NotificationChargeOrderInfoResult.class); return notificationChargeOrderInfoResult; } /** * 构建请求参数和消息头 * @param post * @param */ public void buildBody(HttpRequest post, Object o, Operator operator){ Long timeStamp = Long.valueOf(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); post.contentType("application/json;charset=utf-8"); post.header("Authorization", "Bearer " + queryToken()); BaseRequestJianGuan baseRequest = new BaseRequestJianGuan(); baseRequest.setOperatorID("906171535"); baseRequest.setTimeStamp(timeStamp+""); baseRequest.setSeq("0001"); // 使用 Jackson 转换为 JSON ObjectMapper objectMapper = new ObjectMapper(); objectMapper.enable(MapperFeature.USE_ANNOTATIONS); // 启用注解支持 String jsonString = null; try { jsonString = objectMapper.writeValueAsString(o); } catch (Exception e) { e.printStackTrace(); } String encrypt = AesEncryption.encrypt(DataSecret, DataSecretIV,jsonString); // String encrypt = AesEncryption.encrypt(DataSecret, DataSecretIV,jsonString); baseRequest.setData(encrypt); baseRequest.setOperator(operator); SequenceGenerator generator = new SequenceGenerator(); String nextSequence = generator.getNextSequence(); String hmacMD5 = HMacMD5Util.getHMacMD5("906171535",timeStamp+"", encrypt,nextSequence,SigSecret); // String hmacMD5 = HMacMD5Util.getHMacMD5(OperatorID,timeStamp, data,nextSequence,OurSigSecret); baseRequest.setSig(hmacMD5); String request_json = JacksonUtils.toJson(baseRequest); post.body(request_json); log.info("推送三方平台请求地址:" + post.getUrl()); log.info("推送三方平台请求参数:" + request_json); log.info("推送三方平台请求Data:" + jsonString); } /** * 构建请求参数和消息头 * @param post * @param */ public void buildBodyStatus(HttpRequest post, SupStationPowerInfoResult info, Operator operator){ Long timeStamp = Long.valueOf(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); post.contentType("application/json;charset=utf-8"); post.header("Authorization", "Bearer " + queryToken()); BaseRequestJianGuan baseRequest = new BaseRequestJianGuan(); baseRequest.setOperatorID("906171535"); baseRequest.setTimeStamp(timeStamp+""); baseRequest.setSeq("0001"); String request_json1 = JacksonUtils.toJson(info); String encrypt = AesEncryption.encrypt(DataSecret, DataSecretIV,request_json1); // String encrypt = AesEncryption.encrypt(DataSecret, DataSecretIV,jsonString); baseRequest.setData(encrypt); baseRequest.setOperator(operator); SequenceGenerator generator = new SequenceGenerator(); String nextSequence = generator.getNextSequence(); String hmacMD5 = HMacMD5Util.getHMacMD5("906171535",timeStamp+"", encrypt,nextSequence,SigSecret); // String hmacMD5 = HMacMD5Util.getHMacMD5(OperatorID,timeStamp, data,nextSequence,OurSigSecret); baseRequest.setSig(hmacMD5); String request_json = JacksonUtils.toJson(baseRequest); post.body(request_json); log.info("推送三方平台请求地址:" + post.getUrl()); log.info("推送三方平台请求参数:" + request_json); log.info("推送三方平台请求Data:" + request_json1); } public static void main(String[] args) { BaseModel model = new BaseModel(); model.setOperatorID("MA01H3BQ2"); model.setData("AoArdDDcmHcmOMkCLHodTpY1xLtt9yhLqxvKPyfdlmEOBj1LJnQM+Z4JOZllt3Pj9rubfgxJ51zMAfzquQegJzHGAT9Y7JrKFzFe6jGtXo0="); model.setTimeStamp(20250205120800L); model.setSeq("0001"); Operator operator = new Operator(); operator.setName("XinDianTu"); operator.setSigSecret("S94xUpTpOIlLJBk8"); model.setOperator(operator); String key = operator.getSigSecret(); String m = new StringBuilder(model.getOperatorID()).append(model.getData()).append(model.getTimeStamp()).append(model.getSeq()).toString(); byte[] hmacMd5 = SignUtil.getHMacMD5Bytes(key.getBytes(), m.getBytes()); // 打印计算得到的签名Sig String s = SignUtil.bytesToHexString(hmacMd5); System.err.println(s); // BaseModel model = new BaseModel(); // model.setOperatorID("MA25CNM38"); // model.setData("xQYYEPiwoc4JENnQsF50qP6Tmnj7uU/AshWn3QbIgrMIk8zvFpy6fWLIiLzQHcLPFCihqH1uzoNhGVNcS8Wvf5gIx9+cWJvYtjwtsjAGMEwNQ6y+rF1jjKnqCNcQbHbhqJ2l76sD54QCFKyenKxymrXri19bDV8hizn3nBw+jcHBtqKHWzjdSHwPDWPIw4rXnrbWLya2PXVgYtVg93WPtliw+0xsqW0BxJamE70/Ilbg4wB5fOAOvXmbLFI+v9jRjpcA7ImhprqPMYkXYAfa2QlICrJEBK7DfpJvRMzKzeT90kOAITqIqFvbfV0ti+greRqToLP6ni4o6w3ID42UmKasIpLTnx+qtR4bVTBTRuDzXvNXDA92RqHaJO21xbSen1eHN/yGfrchBIM0gmav7EpaYAerfU4ubnmJ6xujR6okYepJwBD5DiSIrObfS+GWVPRekvnjvm7BC02NXTrGKA=="); // model.setTimeStamp(20250205161426L); // model.setSeq("0001"); // Operator operator = new Operator(); // operator.setOurOperatorId("2921700136"); // operator.setOurSigSecret("KBm5J2fbGzyhX023"); // model.setOperator(operator); // String key = operator.getOurSigSecret(); // // String m = new StringBuilder(operator.getOurOperatorId()).append(model.getData()).append(model.getTimeStamp()).append(model.getSeq()).toString(); // byte[] hmacMd5 = SignUtil.getHMacMD5Bytes(key.getBytes(), m.getBytes()); // // 打印计算得到的签名Sig // String s = SignUtil.bytesToHexString(hmacMd5); // System.err.println(s); } } ruoyi-service/ruoyi-jianguan/src/main/resources/logback.xml
New file @@ -0,0 +1,222 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,比如: 如果设置为WARN,则低于WARN的信息都不会输出 --> <!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true --> <!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 --> <!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 --> <configuration scan="true" scanPeriod="10 seconds"> <contextName>logback</contextName> <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 --> <property name="log.path" value="/data/log/app/ruoyi-integration"/> <!--0. 日志格式和颜色渲染 --> <!-- 彩色日志依赖的渲染类 --> <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" /> <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" /> <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" /> <!-- 彩色日志格式 --> <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/> <!--1. 输出到控制台--> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息--> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>debug</level> </filter> <encoder> <Pattern>${CONSOLE_LOG_PATTERN}</Pattern> <!-- 设置字符集 --> <charset>UTF-8</charset> </encoder> </appender> <!--2. 输出到文档--> <!-- 2.1 level为 DEBUG 日志,时间滚动输出 --> <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 正在记录的日志文档的路径及文档名 --> <file>${log.path}/debug.log</file> <!--日志文档输出格式--> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> <charset>UTF-8</charset> <!-- 设置字符集 --> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 日志归档 --> <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文档保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> <!-- 此日志文档只记录debug级别的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>debug</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 2.2 level为 INFO 日志,时间滚动输出 --> <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 正在记录的日志文档的路径及文档名 --> <file>${log.path}/info.log</file> <!--日志文档输出格式--> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> <charset>UTF-8</charset> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 每天日志归档路径以及格式 --> <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文档保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> <!-- 此日志文档只记录info级别的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>info</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 2.3 level为 WARN 日志,时间滚动输出 --> <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 正在记录的日志文档的路径及文档名 --> <file>${log.path}/warn.log</file> <!--日志文档输出格式--> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> <charset>UTF-8</charset> <!-- 此处设置字符集 --> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文档保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> <!-- 此日志文档只记录warn级别的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>warn</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 2.4 level为 ERROR 日志,时间滚动输出 --> <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 正在记录的日志文档的路径及文档名 --> <file>${log.path}/error.log</file> <!--日志文档输出格式--> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> <charset>UTF-8</charset> <!-- 此处设置字符集 --> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文档保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> <!-- 此日志文档只记录ERROR级别的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 2.5 所有 除了DEBUG级别的其它高于DEBUG的 日志,记录到一个文件 --> <appender name="ALL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 正在记录的日志文档的路径及文档名 --> <file>${log.path}/all.log</file> <!--日志文档输出格式--> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> <charset>UTF-8</charset> <!-- 此处设置字符集 --> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/all-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文档保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> <!-- 此日志文档记录除了DEBUG级别的其它高于DEBUG的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>DEBUG</level> <onMatch>DENY</onMatch> <onMismatch>ACCEPT</onMismatch> </filter> </appender> <!-- <logger>用来设置某一个包或者具体的某一个类的日志打印级别、 以及指定<appender>。<logger>仅有一个name属性, 一个可选的level和一个可选的addtivity属性。 name:用来指定受此logger约束的某一个包或者具体的某一个类。 level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF, 还有一个特殊值INHERITED或者同义词NULL,代表强制执行上级的级别。 如果未设置此属性,那么当前logger将会继承上级的级别。 addtivity:是否向上级logger传递打印信息。默认是true。 <logger name="org.springframework.web" level="info"/> <logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/> --> <!-- root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性 level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF, 不能设置为INHERITED或者同义词NULL。默认是DEBUG 可以包含零个或多个元素,标识这个appender将会添加到这个logger。 --> <!-- 4 最终的策略: 基本策略(root级) + 根据profile在启动时, logger标签中定制化package日志级别(优先级高于上面的root级)--> <springProfile name="dev"> <root level="info"> <appender-ref ref="CONSOLE" /> <appender-ref ref="DEBUG_FILE" /> <appender-ref ref="INFO_FILE" /> <appender-ref ref="WARN_FILE" /> <appender-ref ref="ERROR_FILE" /> <appender-ref ref="ALL_FILE" /> </root> <logger name="com.stylefeng.guns.modular.system.dao" level="debug"/> </springProfile> <springProfile name="test"> <root level="info"> <appender-ref ref="CONSOLE" /> <appender-ref ref="DEBUG_FILE" /> <appender-ref ref="INFO_FILE" /> <appender-ref ref="WARN_FILE" /> <appender-ref ref="ERROR_FILE" /> <appender-ref ref="ALL_FILE" /> </root> </springProfile> <springProfile name="prod"> <root level="info"> <!-- 生产环境最好不配置console写文件 --> <appender-ref ref="DEBUG_FILE" /> <appender-ref ref="INFO_FILE" /> <appender-ref ref="WARN_FILE" /> <appender-ref ref="ERROR_FILE" /> <appender-ref ref="ALL_FILE" /> </root> </springProfile> </configuration> ruoyi-service/ruoyi-jianguan/src/main/resources/mybatis-config.xml
New file @@ -0,0 +1,25 @@ <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <!-- 打印查询语句 不会写入到日志文件中--> <setting name="logImpl" value="STDOUT_LOGGING"/> <!--<setting name="logImpl" value="LOG4J" />--> <!-- 控制全局缓存(二级缓存),按美团技术团队的说法,尽量别用缓存机制 emmmm.... --> <setting name="cacheEnabled" value="true"/> <!-- 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。默认 false --> <!-- <setting name="lazyLoadingEnabled" value="true"/> --> <setting name="mapUnderscoreToCamelCase" value="false"/><!--是否将map下划线方式转为驼峰式命名--> <!-- 当开启时,任何方法的调用都会加载该对象的所有属性。默认 false,可通过select标签的 fetchType来覆盖--> <!-- <setting name="aggressiveLazyLoading" value="false"/>--> <!-- Mybatis 创建具有延迟加载能力的对象所用到的代理工具,默认JAVASSIST --> <!--<setting name="proxyFactory" value="CGLIB" />--> <!-- 关于mybatis的一二级缓存 请参照:https://tech.meituan.com/2018/01/19/mybatis-cache.html --> <!-- 一级缓存范围默认:SESSION ,此范围在复杂应用场景中可能会出现脏读数据--> <!-- STATEMENT级别的缓存,使一级缓存,只针对当前执行的这一statement有效 --> <!--<setting name="localCacheScope" value="STATEMENT"/>--> <setting name="localCacheScope" value="STATEMENT"/> </settings> </configuration>