优化调整

This commit is contained in:
andy 2026-02-05 09:27:47 +08:00
parent 6e3449a3bc
commit 2ffc8e79a8
51 changed files with 1678 additions and 721 deletions

View File

@ -5,33 +5,42 @@
</component>
<component name="ChangeListManager">
<list default="true" id="ec76006e-5a88-4766-9722-bc8eda172857" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MqttConfigOld.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/commoms/mongodb/src/main/java/com/evotech/hd/config/ElectricityMeterBoxProperties.java" beforeDir="false" afterPath="$PROJECT_DIR$/commoms/mongodb/src/main/java/com/evotech/hd/config/ElectricityMeterBoxProperties.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/commoms/mongodb/src/main/resources/application-mongo.yml" beforeDir="false" afterPath="$PROJECT_DIR$/commoms/mongodb/src/main/resources/application-mongo.yml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/commoms/core/src/main/java/com/evotech/hd/core/dtos/business/AccessStrategyDTO.java" beforeDir="false" afterPath="$PROJECT_DIR$/commoms/core/src/main/java/com/evotech/hd/core/dtos/business/AccessStrategyDTO.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/commoms/core/src/main/java/com/evotech/hd/core/dtos/business/BatteryCompartmentDTO.java" beforeDir="false" afterPath="$PROJECT_DIR$/commoms/core/src/main/java/com/evotech/hd/core/dtos/business/BatteryCompartmentDTO.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/commoms/core/src/main/java/com/evotech/hd/core/dtos/system/ParamsDTO.java" beforeDir="false" afterPath="$PROJECT_DIR$/commoms/core/src/main/java/com/evotech/hd/core/dtos/system/ParamsDTO.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/commoms/core/src/main/java/com/evotech/hd/core/entity/system/AccessStrategy.java" beforeDir="false" afterPath="$PROJECT_DIR$/commoms/core/src/main/java/com/evotech/hd/core/entity/system/AccessStrategy.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/commoms/core/src/main/java/com/evotech/hd/core/entity/system/Params.java" beforeDir="false" afterPath="$PROJECT_DIR$/commoms/core/src/main/java/com/evotech/hd/core/entity/system/Params.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/commoms/mongodb/src/main/resources/application-mongoDev.yml" beforeDir="false" afterPath="$PROJECT_DIR$/commoms/mongodb/src/main/resources/application-mongoDev.yml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/WebServerApplication.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/WebServerApplication.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MessageTopic.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MqttConfig.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/cnstant/ParamSysConstants.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/cnstant/ParamSysConstants.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/handler/GlobalExceptionHandler.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/handler/GlobalExceptionHandler.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MqttMessageCallback.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MqttMessageCallback.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MqttProperties.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MqttProperties.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MqttPublishMessage.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MqttPublishMessage.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/controller/ManualOperationController.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/controller/ManualOperationController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/controller/OrderSwapController.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/controller/OrderSwapController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/controller/TestController.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/controller/TestController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/job/BaseJob.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/job/BaseJob.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/JobConstant.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/JobConstant.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/job/CheckAlarmJob.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/job/CheckAlarmJob.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/job/charging/ChargingFullOfJob.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/job/charging/ChargingFullOfJob.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/service/ExecutionBatterySwapService.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/service/ExecutionBatterySwapService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mqtt/MessageTopic.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mqtt/MessageTopic.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mapper/BatteryCompartmentMapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mapper/BatteryCompartmentMapper.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mqtt/MessageUtilService.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mqtt/MessageUtilService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mqtt/MqttMessageHeader.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mqtt/MqttMessageHeader.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/OrderChargingService.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/OrderChargingService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/impl/OrderChargingServiceImpl.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/impl/OrderChargingServiceImpl.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mqtt/MqttMessageHandleService.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mqtt/MqttMessageHandleService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mqtt/MqttPublishUtils.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mqtt/MqttPublishUtils.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/BatteryCompartmentService.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/BatteryCompartmentService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/OrderSwapService.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/OrderSwapService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/ParamsService.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/ParamsService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/impl/BatteryCompartmentServiceImpl.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/impl/BatteryCompartmentServiceImpl.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/impl/OrderReservationServiceImpl.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/impl/OrderReservationServiceImpl.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/impl/OrderSwapServiceImpl.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/impl/OrderSwapServiceImpl.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/impl/ParamsServiceImpl.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/impl/ParamsServiceImpl.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/AccessStrategyUtil.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/AccessStrategyUtil.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/ParamUtils.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/ParamUtils.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/instruction/InstructionReadUtils.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/instruction/InstructionReadUtils.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/instruction/InstructionWriteUtils.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/instruction/InstructionWriteUtils.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/sendCloud/CloudSendInfoUtils.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/sendCloud/CloudSendInfoUtils.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/sendCloud/RsaEcbPkcsFullUtil.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/sendCloud/RsaEcbPkcsFullUtil.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/resources/application-dev.yml" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/resources/application-dev.yml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/resources/application-pro.yml" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/resources/application-pro.yml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/resources/application.yml" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/resources/application.yml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/resources/mapper/AccessStrategyMapper.xml" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/resources/mapper/AccessStrategyMapper.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/resources/mapper/BatteryCompartmentMapper.xml" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/resources/mapper/BatteryCompartmentMapper.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/resources/mapper/ParamsMapper.xml" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/resources/mapper/ParamsMapper.xml" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -81,6 +90,7 @@
&quot;Application.XmlRpcHttpDirectCall.executor&quot;: &quot;Run&quot;,
&quot;Application.test111.executor&quot;: &quot;Run&quot;,
&quot;Maven.commoms [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.commoms [install].executor&quot;: &quot;Run&quot;,
&quot;Maven.commoms [package].executor&quot;: &quot;Run&quot;,
&quot;Maven.core [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.core [install].executor&quot;: &quot;Run&quot;,
@ -97,7 +107,10 @@
&quot;Maven.web-server [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.web-server [compile].executor&quot;: &quot;Run&quot;,
&quot;Maven.web-server [dependency:resolve,-U].executor&quot;: &quot;Run&quot;,
&quot;Maven.web-server [install].executor&quot;: &quot;Run&quot;,
&quot;Maven.web-server [package].executor&quot;: &quot;Run&quot;,
&quot;Maven.web-server [validate].executor&quot;: &quot;Run&quot;,
&quot;Maven.web-server [verify].executor&quot;: &quot;Run&quot;,
&quot;RequestMappingsPanelOrder0&quot;: &quot;0&quot;,
&quot;RequestMappingsPanelOrder1&quot;: &quot;1&quot;,
&quot;RequestMappingsPanelWidth0&quot;: &quot;75&quot;,
@ -107,7 +120,7 @@
&quot;Spring Boot.WebServerApplication.executor&quot;: &quot;Debug&quot;,
&quot;git-widget-placeholder&quot;: &quot;master&quot;,
&quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
&quot;last_opened_file_path&quot;: &quot;D:/andy/ideaWorker/andy/blc/download/应用端/backend&quot;,
&quot;last_opened_file_path&quot;: &quot;D:/andy/ideaWorker/station-control/web-server/src/main/resources/mapper&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
@ -125,21 +138,21 @@
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="D:\andy\ideaWorker\station-control\web-server\src\main\resources\mapper" />
<recent name="D:\andy\ideaWorker\station-control\commoms\core\src\main\resources" />
<recent name="D:\andy\ideaWorker\station-control\commoms\mongodb\src\main\java\com\evotech\hd\config" />
<recent name="D:\andy\ideaWorker\my\station-control\web-server\src\main\resources" />
<recent name="D:\andy\ideaWorker\my\station-control\web-server\src\main\resources\mapper" />
<recent name="D:\andy\ideaWorker\my\station-control\commoms\mongodb\src\main\resources" />
<recent name="D:\andy\ideaWorker\my\station-control\web-server\src\main\java\com\evotech\hd\webserver\config\swagger" />
</key>
<key name="MoveFile.RECENT_KEYS">
<recent name="D:\andy\ideaWorker\my\station-control\web-server\src\main\resources" />
</key>
<key name="CopyClassDialog.RECENTS_KEY">
<recent name="com.evotech.hd.entity" />
<recent name="com.evotech.hd.core.dtos.mqtt" />
<recent name="com.evotech.hd.webserver.mqtt" />
<recent name="com.evotech.hd.webserver.config.mqtt" />
<recent name="com.evotech.hd.webserver.job.service" />
<recent name="com.evotech.hd.webserver.mqtt.enums" />
<recent name="com.evotech.hd.core.dtos.system" />
<recent name="com.evotech.hd.webserver.mapper" />
<recent name="com.evotech.hd.webserver.service.impl" />
<recent name="com.evotech.hd.webserver.service" />
</key>
</component>
<component name="RunAnythingCache">
@ -391,7 +404,14 @@
<workItem from="1765939118169" duration="98526000" />
<workItem from="1766623919531" duration="18086000" />
<workItem from="1766800226399" duration="599000" />
<workItem from="1766810719772" duration="1371000" />
<workItem from="1766810719772" duration="79701000" />
<workItem from="1767582650417" duration="76709000" />
<workItem from="1767939652097" duration="67647000" />
<workItem from="1768356164082" duration="15456000" />
<workItem from="1768809252266" duration="601000" />
<workItem from="1768955894610" duration="4133000" />
<workItem from="1768987212149" duration="43024000" />
<workItem from="1769503255745" duration="74993000" />
</task>
<servers />
</component>
@ -399,6 +419,15 @@
<option name="version" value="3" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/controller/TestController.java</url>
<line>1480</line>
<option name="timeStamp" value="3" />
</line-breakpoint>
</breakpoints>
</breakpoint-manager>
<watches-manager>
<configuration name="SpringBootApplicationConfigurationType">
<watch expression="import com.evotech.hd.entity.system.Params;&#10;" />

View File

@ -46,7 +46,8 @@ public class AccessStrategyDTO extends BaseDTO<AccessStrategyDTO> {
@ApiModelProperty("生效的Rgv编号")
String effectiveRgvNo;
@ApiModelProperty("电池预取, true是, false 否")
Boolean batteryPrefetching;
@ApiModelProperty(value = "数据是否有效: valid有效 invalid 无效", hidden = true)
String valid;

View File

@ -1,6 +1,8 @@
package com.evotech.hd.core.dtos.business;
import com.evotech.hd.core.dtos.BaseDTO;
import com.evotech.hd.query.Query;
import com.evotech.hd.query.QueryType;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ -26,9 +28,11 @@ public class BatteryCompartmentDTO extends BaseDTO<BatteryCompartmentDTO> {
String batteryCompartmentNo;
@ApiModelProperty("电池仓状态1-正常2-检修, 3-坏")
@Query(javaField = "status", tableColumn = "a.status", type = QueryType.EQ)
Integer status;
@ApiModelProperty("运行状态1正常, 2-禁用")
@Query(javaField = "state", tableColumn = "a.state", type = QueryType.EQ)
Integer state;
@ApiModelProperty("排序")

View File

@ -0,0 +1,59 @@
package com.evotech.hd.core.dtos.system;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.evotech.hd.core.dtos.BaseDTO;
import com.evotech.hd.query.Query;
import com.evotech.hd.query.QueryType;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
* mqtt消息
*
* @ClassName:Log
* @date: 2025年08月18日 10:06
* @author: andy.shi
* @contact: 17330188597
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@Data
@ApiModel("mqtt消息")
public class MessageMqttDTO extends BaseDTO<MessageMqttDTO> {
@ApiModelProperty( "换电站")
private String stationCode;
@ApiModelProperty("传送方向")
private String direction;
@ApiModelProperty("消息ID")
private String messageId;
@ApiModelProperty("qos")
private Integer qos;
@ApiModelProperty( "消息类型: 状态信息类、事件记录类、请求与响应类")
private String type;
@ApiModelProperty("方法 stationInfo")
private String messageFunction;
@ApiModelProperty("消息的topic")
private String topic;
@ApiModelProperty("内容,解密后的")
private String content;
@ApiModelProperty("创建时间")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date ctime;
}

View File

@ -30,6 +30,8 @@ public class ParamsDTO extends BaseDTO<ParamsDTO> {
@ApiModelProperty("参数值")
@Query(javaField = "paramValue", tableColumn = "a.param_value", type = QueryType.LIKE)
String paramValue;
@ApiModelProperty("是否影响换电, true 影响, false 不影响")
Boolean effectBatterySwapping;
@ApiModelProperty("预期结果, 不满足预期返回错误信息")
String expectedResults;

View File

@ -50,6 +50,10 @@ public class AccessStrategy extends BaseEntity {
*生效的RGV编号
*/
String effectiveRgvNo;
/***
*电池预取
*/
Boolean batteryPrefetching;
/***
* 数据是否有效: valid有效 invalid 无效
*/

View File

@ -0,0 +1,43 @@
package com.evotech.hd.core.entity.system;
import com.baomidou.mybatisplus.annotation.TableName;
import com.evotech.hd.core.entity.BaseEntity;
import lombok.Getter;
import lombok.Setter;
/**
* @author zrb
* @since 2024-11-06
*/
@Getter
@Setter
@TableName("sc_sys_message_mqtt")
public class MessageMqtt extends BaseEntity {
private String stationCode;
private String direction;
private String messageId;
private Integer qos;
private String type;
private String messageFunction;
private String topic;
private String content;
public MessageMqtt() {
}
public MessageMqtt(String stationCode, String direction, String type, String messageFunction) {
this.stationCode = stationCode;
this.direction = direction;
this.type = type;
this.messageFunction = messageFunction;
}
}

View File

@ -32,6 +32,8 @@ public class Params extends BaseEntity {
String expectedResults;
Boolean effectBatterySwapping;
Boolean verifyResult;
String errMessage;

View File

@ -0,0 +1,59 @@
package com.evotech.hd.utils;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* 全局属性配置
* @author andy.shi
* @ClassName:Global
* @date: 2026年01月10日 10:16
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@Configuration
@ConfigurationProperties(prefix = "ythd", ignoreInvalidFields = true)
@Data
public class Global{
/***
* 云平台私钥
*/
@Value("${ythd.cloud-private-key}")
public String cloudPrivateKey;
/***
* 云平台公钥
*/
@Value("${ythd.cloud-public-key}")
public String cloudPublicKey;
@Value("${ythd.static-public-key}")
public String staticPublicKey;
//单例模式全局属性
private static volatile Global global;
public static Global newInstance() {
if(global == null){
synchronized (Global.class){
if(global == null){
global = SpringUtils.getBean(Global.class);
}
}
}
return global;
}
public String getCloudPrivateKey() {
return cloudPrivateKey;
}
public String getCloudPublicKey() {
return cloudPublicKey;
}
public String getStaticPublicKey() {
return staticPublicKey;
}
}

View File

@ -0,0 +1,55 @@
package com.evotech.hd.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* SpringUtils
*
* @author andy.shi
* @ClassName:SpringUtils
* @date: 2026年01月10日 11:11
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
/**
* Spring容器启动时会自动调用这个方法注入上下文对象
*/
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
// 将Spring上下文赋值给静态变量
SpringUtils.applicationContext = context;
}
/**
* 静态方法根据Bean类型获取实例
* @param clazz Bean的类型
* @return 对应的Bean实例
*/
public static <T> T getBean(Class<T> clazz) {
// 校验上下文是否初始化完成
if (applicationContext == null) {
throw new RuntimeException("Spring上下文未初始化无法获取Bean");
}
return applicationContext.getBean(clazz);
}
/**
* 静态方法根据Bean名称获取实例备用优先用类型获取
* @param beanName Bean的名称
* @return 对应的Bean实例
*/
public static Object getBean(String beanName) {
if (applicationContext == null) {
throw new RuntimeException("Spring上下文未初始化无法获取Bean");
}
return applicationContext.getBean(beanName);
}
}

View File

@ -0,0 +1,5 @@
ythd:
cloud-private-key: MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALEbx7j2XmAo3NiviJIk8/Mo1RF4yT/MYmZdZRnB9iSh4koIiu/KKCGSwvViFGfmP/q8TNLWsvpTVo3MxWBFJkWaALuo/iPu5RJ+tU1l0YXA35zZNxMuiDbmnI7wODRePUY1g5fa1ZNy5oDUQumfrXhDCoFC2AMUBn9KiMr+QQ97AgMBAAECgYAk/lF8X/Gckkx28ktLg251Nu0yZhFbQxy2lwF8HNiGFE5I+nnS1l4FjTstuBvdC+oHPHerfm8J/IhSvBfqIOd6PulJyuh5s31cdc+2SDWUzh8sBm48YHlDfjltZG2ijgM7h/+uvw1gHwXH8JQGF7ZjWguD3TJfqZ/jPFsuxoLKOQJBAOsp+f7kS5VXg6ziKzCMlWOAEfrsAO5ZhLJNMtoirbMQZYUfYxUc3KFWQMT9i9O2M752NXoeUed8a1DjmfyxaX8CQQDAzPs5EPNfpfuGsvJ79lGsH8mZcw7VdjDzmwNVVLLnSOaJxQIPTusjEJ2YmBs+ifCF30VIDpkRd/DGaj4yNgAFAkEAorh1B+6objoUHviQshNU+3iO+HV9X3AJ5eaNHWuJjbH2zVqekOlbsTehsa1Pp7sXqt7YuhtoySjKiTo0PynzuQJBAJsvovsBANQ5VubJ/NH4py6je3LPIN6Cvs4mNJ2nikUN8bps38aQoEVeJ2ve6vcAsqAe4bYpQd3ErAIZHCzwOD0CQF8hDwEGx1S4nJQpB9rmSQhoNzaEJuJKXgpAxNCQ9g4kLRZE+hpZk1kPw+VjGalyyZkY5ilXkWnqsvrprn+wW7Y=
cloud-public-key: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxG8e49l5gKNzYr4iSJPPzKNUReMk/zGJmXWUZwfYkoeJKCIrvyighksL1YhRn5j/6vEzS1rL6U1aNzMVgRSZFmgC7qP4j7uUSfrVNZdGFwN+c2TcTLog25pyO8Dg0Xj1GNYOX2tWTcuaA1ELpn614QwqBQtgDFAZ/SojK/kEPewIDAQAB
static-public-key: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC32MZ8u1bK66Uj+Uh3eTfDLcGy4TosSLfksYvJBavX6fckS6vdV8VeYj9gQvTrB6b3VKIdsqf/uP4AjgiKlP34GVMfDr0bEPEccurEhs23QWSHGrVSJG5HPG0B1PBbRMMUwUkmQJxo65Ml6SSPyS/4ebdZ0qeY2/cWaK8laYj7sQIDAQAB

View File

@ -1,6 +1,6 @@
yt:
base_properties:
host: 192.168.16.128
host: 192.168.5.112
port: 27017
#用于账号密码验证的库
authentication-database: admin

View File

@ -11,10 +11,6 @@ package com.evotech.hd.webserver.cnstant;
public class ParamSysConstants {
/***
* 检查电池仓是否存在电池
*/
public final static String EXISTS_BATTERY = "BSL_BatExist";
/***
* 设置最大功率
*/

View File

@ -13,8 +13,6 @@ import javax.servlet.ServletException;
/**
* 全局异常处理器 Exception 翻译成 CommonResult + 对应的异常编号
*
* @author 芋道源码
*/
@RestControllerAdvice(basePackages = "com.evotech.hd")
@AllArgsConstructor

View File

@ -0,0 +1,127 @@
package com.evotech.hd.webserver.config.mqtt;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* MqttClientManager
*
* @author andy.shi
* @ClassName:MqttClientManager
* @date: 2025年12月23日 15:59
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@Configuration
@Component
@Slf4j
public class MqttConfig implements CommandLineRunner {
@Resource
MqttProperties mqttProperties;
static ConcurrentHashMap<String, MqttClient> mqttClientMap = new ConcurrentHashMap<>();
// 已重试次数
private final AtomicInteger retryCount = new AtomicInteger(0);
// 重连执行器
private final ScheduledExecutorService reconnectExecutor = Executors.newSingleThreadScheduledExecutor();
@Override
public void run(String... args) throws Exception {
new Thread(this::connectMqtt, "mqtt-connect-thread").start();
}
public MqttConnectOptions mqttConnectOptions() {
MqttConnectOptions options = new MqttConnectOptions();
// 设置服务器地址支持多个用数组
options.setServerURIs(new String[]{mqttProperties.getBroker()});
// 配置认证信息如果有
if (StringUtils.isNotEmpty(mqttProperties.getUsername())) {
options.setUserName(mqttProperties.getUsername());
}
if (StringUtils.isNotEmpty(mqttProperties.getPassword())) {
options.setPassword(mqttProperties.getPassword().toCharArray());
}
// 其他连接参数
options.setKeepAliveInterval(mqttProperties.getKeepAlive()); // 心跳间隔
options.setConnectionTimeout(10); // 连接超时时间
options.setAutomaticReconnect(true); // 自动重连
options.setCleanSession(true); // 断开后清除会话
return options;
}
/**
* 建立 MQTT 连接
*/
private void connectMqtt() {
try {
// 1. 创建 MQTT 连接选项
MqttConnectOptions connOpts = mqttConnectOptions();
// 2. 创建 MQTT 客户端
MqttClient client = new MqttClient(mqttProperties.getBroker(), mqttProperties.getClientId(), new MemoryPersistence());
// 3. 设置回调处理消息连接断开等事件
client.setCallback(new MqttMessageCallback());
// 4. 建立连接
if (!client.isConnected()) {
client.connect(connOpts);
mqttClientMap.put("cloudClient", client);
// 重置重试次数
retryCount.set(0);
}
} catch (MqttException e) {
log.error("MQTT 连接失败,错误码:{},原因:{}", e.getReasonCode(), e.getMessage(), e);
// 触发自定义重连逻辑
startReconnect();
}
}
/**
* 启动自动重连
*/
private void startReconnect() {
// 检查是否超过最大重试次数0 表示无限重试
if (mqttProperties.getMaxRetry() > 0 && retryCount.get() >= mqttProperties.getMaxRetry()) {
log.error("MQTT 重连次数已达上限({}次),停止重连", mqttProperties.getMaxRetry());
reconnectExecutor.shutdown();
return;
}
int currentRetry = retryCount.incrementAndGet();
log.info("将在 {} 秒后进行第 {} 次 MQTT 重连", mqttProperties.getRetryInterval(), currentRetry);
// 延迟执行重连避免频繁重试
reconnectExecutor.schedule(() -> {
if (mqttClientMap.get("cloudClient") == null || !mqttClientMap.get("cloudClient").isConnected()) {
connectMqtt();
}
}, mqttProperties.getRetryInterval(), TimeUnit.SECONDS);
}
@PreDestroy
public void PreDestroyComplete() {
log.info("===>>>程序要关闭了...");
MqttClient cloudClient = mqttClientMap.get("cloudClient");
try {
cloudClient.disconnect();
cloudClient.close();
log.info("=====>>>关闭了MQTT");
} catch (MqttException e) {
e.printStackTrace();
}
}
}

View File

@ -10,13 +10,22 @@ package com.evotech.hd.webserver.config.mqtt;
*/
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson2.JSONObject;
import com.evotech.hd.core.dtos.system.ParamsDTO;
import com.evotech.hd.utils.Collections;
import com.evotech.hd.utils.Global;
import com.evotech.hd.webserver.job.JobConstant;
import com.evotech.hd.webserver.job.service.QuartzJobService;
import com.evotech.hd.webserver.mqtt.MessageTopic;
import com.evotech.hd.webserver.mqtt.MqttMessageHandleService;
import com.evotech.hd.webserver.mqtt.MqttPublishUtils;
import com.evotech.hd.webserver.mqtt.enums.MqttMessageTypeEnum;
import com.evotech.hd.webserver.service.ParamsService;
import com.evotech.hd.webserver.utils.ParamUtils;
import com.evotech.hd.webserver.websocket.controller.WebSocketUtils;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
@ -32,9 +41,11 @@ public class MqttMessageCallback implements MqttCallbackExtended, ApplicationCo
private ApplicationContext applicationContext;
private MqttMessageHandleService mqttMessageHandleService;
private static String stationCode;
static String[] mqttMessageTypeArr = {"event","request", "state","keepalive"};
static String[] mqttMessageTypeArr = {MqttMessageTypeEnum.EVENT.getType(),MqttMessageTypeEnum.REQUEST.getType(), MqttMessageTypeEnum.STATE.getType(), MqttMessageTypeEnum.ENCRYRESP.getType()};
/**
* 建立连接后
@ -60,6 +71,15 @@ public class MqttMessageCallback implements MqttCallbackExtended, ApplicationCo
log.error("\r\n=====>>>MQTT订阅主题 {} 失败。。。", topic);
}
}
//订阅完成之后, 获取秘钥信息
MqttPublishUtils.sendEncryptKeyReq();
//开启与服务端的心跳检查, 注意, 这里不是客户端和mq的心跳检查, 所以需要手动开启
// try {
// SpringUtil.getBean(QuartzJobService.class).resumeJob(JobConstant.KEEPALIVE_JOB, JobConstant.GroupEnum.BASE_GROUP.getType());
// } catch (SchedulerException e) {
// throw new RuntimeException(e);
// }
}
/**
@ -70,6 +90,14 @@ public class MqttMessageCallback implements MqttCallbackExtended, ApplicationCo
cause.printStackTrace();
logger.error("MQTT连接已断开原因{}", cause.getMessage());
// 自动重连由MqttConnectOptions的automaticReconnect控制
//页面推送广播, 云平台连接丢失
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","alarm","data",JSONObject.toJSONString(Collections.asMap("MQTT服务", "连接丢失")))));
//如果链接丢失, 关闭与服务端的心跳检查, 注意, 这里不是客户端和mq的心跳检查, 所以需要手动关闭
// try {
// SpringUtil.getBean(QuartzJobService.class).pauseJob(JobConstant.KEEPALIVE_JOB, JobConstant.GroupEnum.BASE_GROUP.getType());
// } catch (SchedulerException e) {
// throw new RuntimeException(e);
// }
}
/**
@ -95,13 +123,6 @@ public class MqttMessageCallback implements MqttCallbackExtended, ApplicationCo
*/
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
// 消息成功发布后的回调可选处理
// try {
// logger.info("消息已成功发布到主题:{}", token.getMessageId());
// } catch (Exception e) {
// logger.error("消息发布确认失败", e);
// }
try {
// 核心安全获取主题优先用自定义 token 的主题兼容原生 token
String publishTopic = "未知主题";

View File

@ -1,17 +1,28 @@
package com.evotech.hd.webserver.config.mqtt;
import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.evotech.hd.core.dtos.Result;
import com.evotech.hd.utils.Collections;
import com.evotech.hd.utils.Global;
import com.evotech.hd.webserver.mqtt.MessageTopic;
import com.evotech.hd.webserver.mqtt.MessageUtilService;
import com.evotech.hd.webserver.mqtt.MqttMessageHeader;
import com.evotech.hd.webserver.mqtt.MyMqttMessage;
import com.evotech.hd.webserver.mqtt.enums.MqttMessageTypeEnum;
import com.evotech.hd.webserver.service.MessageMqttService;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Date;
@Component
@Slf4j
@ -19,8 +30,10 @@ public class MqttPublishMessage {
@Resource
MessageUtilService messageUtilService;
@Resource
MessageMqttService messageMqttService;
public MqttMessage publish(String message, String topic) {
private MqttMessage publish(String message, String topic) {
MqttClient cloudClient = MqttConfig.mqttClientMap.get("cloudClient");
MqttMessage mqttMessage = new MqttMessage();
/**
@ -50,6 +63,53 @@ public class MqttPublishMessage {
return mqttMessage;
}
/**
* 发送 心跳
*/
public void publishKeepaliveMessage() {
log.info("MQTT->>>>>>>>>>>>>请求发送心跳;");
MessageTopic topic = new MessageTopic();
topic.setMessageType(MqttMessageTypeEnum.KEEPALIVE.getType());
// 3. 发送MQTT消息
try {
MqttMessage mqttMessage = publish(DateUtil.formatDateTime(new Date()), topic.toString());
try {
messageMqttService.update(null, topic, mqttMessage.getId()+"", mqttMessage.getQos(), JSONUtil.parseObj(mqttMessage));
} catch (Exception e) {
log.error("MQTT->>>>>>>>>>>>>记录mqtt消息出现了错误{},topic:{}; message:{}",e.getMessage(),JSONUtil.toJsonStr(topic), JSONUtil.toJsonStr(mqttMessage));
throw new RuntimeException("记录mqtt消息出现了错误"+e.getMessage());
}
} catch (Exception e) {
log.error("MQTT->>>>>>>>>>>>>发送站端mqtt消息出现异常{},topic:{};",e.getMessage(),JSONUtil.toJsonStr(topic));
}
}
/**
* 发送 AES 加密消息
* @param topic
*/
public void publishRSAMessage(MessageTopic topic) {
log.info("MQTT->>>>>>>>>>>>>请求发送mqtt消息: topic:{};", JSONUtil.toJsonStr(topic));
RSA rsa = SecureUtil.rsa(null, Global.newInstance().getStaticPublicKey());
Result<Integer> addResult = messageMqttService.addResultId(topic.getStationCode());
Integer messageId = addResult.getData();
//数据加密
String encrypt = rsa.encryptBase64(JSON.toJSONString(Collections.asMap("messageId", messageId, "publicKey", Global.newInstance().getCloudPublicKey())), KeyType.PublicKey);
// 3. 发送MQTT消息
try {
MqttMessage mqttMessage = publish(encrypt, topic.toString());
try {
messageMqttService.update(messageId, topic, mqttMessage.getId()+"", mqttMessage.getQos(), JSONUtil.parseObj(mqttMessage));
} catch (Exception e) {
log.error("MQTT->>>>>>>>>>>>>记录mqtt消息出现了错误{},topic:{}; message:{}",e.getMessage(),JSONUtil.toJsonStr(topic), JSONUtil.toJsonStr(mqttMessage));
throw new RuntimeException("记录mqtt消息出现了错误"+e.getMessage());
}
} catch (Exception e) {
log.error("MQTT->>>>>>>>>>>>>发送站端mqtt消息出现异常{},topic:{};",e.getMessage(),JSONUtil.toJsonStr(topic));
}
}
/**
* 发送 AES 加密消息
* @param topic
@ -70,8 +130,7 @@ public class MqttPublishMessage {
try {
MqttMessage mqttMessage = publish(encrypt, topic.toString());
try {
//dataBody.set("header", JSONUtil.toJsonStr(header));
// addMqttMessage(topic, mqttMessage.getId()+"", mqttMessage.getQos(), JSONUtil.parseObj(message));
messageMqttService.update(null, topic, mqttMessage.getId()+"", mqttMessage.getQos(), JSONUtil.parseObj(message));
} catch (Exception e) {
log.error("MQTT->>>>>>>>>>>>>记录mqtt消息出现了错误{},topic:{}; header:{}, data:{}; message:{}",e.getMessage(),JSONUtil.toJsonStr(topic),JSONUtil.toJsonStr(header),JSONUtil.toJsonStr(dataBody), JSONUtil.toJsonStr(mqttMessage));
throw new RuntimeException("记录mqtt消息出现了错误"+e.getMessage());
@ -80,47 +139,4 @@ public class MqttPublishMessage {
log.error("MQTT->>>>>>>>>>>>>发送站端mqtt消息出现异常{},topic:{}; header:{}, data:{}",e.getMessage(),JSONUtil.toJsonStr(topic),JSONUtil.toJsonStr(header),JSONUtil.toJsonStr(dataBody));
}
}
// public SymmetricCrypto getAes(String stationCode) {
// JSONObject aesJo = getAESKey(stationCode);
// String aesSecretKey = aesJo.getStr("encryptKey");
// String aesIv = aesJo.getStr("encryptVector");
// SymmetricCrypto aes = new AES(Mode.CBC, Padding.PKCS5Padding, Base64.getDecoder().decode(aesSecretKey), aesIv.getBytes());
// return aes;
// }
// public JSONObject getAESKey(String stationCode) {
// JSONObject jo = new JSONObject();
// Object o1 = null;
// try {
// o1 = redisUtil.get(HDConstant.HD_STATION_SECRET_KEY_AES_PREFIX + stationCode + ":key");
// } catch (Exception e) {
// e.printStackTrace();
// }
// Object o2 = null;
// try {
// o2 = redisUtil.get(HDConstant.HD_STATION_SECRET_KEY_AES_PREFIX + stationCode + ":iv");
// } catch (Exception e) {
// e.printStackTrace();
// }
// if (!ObjectUtil.isEmpty(o1) && !ObjectUtil.isEmpty(o2)) {
//// jo.set("aesSecretKey", o1.toString());
//// jo.set("aesIv", o2.toString());
// jo.set("encryptKey", o1.toString());
// jo.set("encryptVector", o2.toString());
// return jo;
// }
// BatteryStationSecretKey bssk = batteryStationSecretKeyDao.selectOne(new QueryWrapper<BatteryStationSecretKey>().eq("type", 2).eq("station_code", stationCode));
// if (bssk == null) {
// throw new RuntimeException("AES秘钥未获取到请站端重新登陆");
//// return setAesKey(stationCode);
// }
// redisUtil.set(HDConstant.HD_STATION_SECRET_KEY_AES_PREFIX + stationCode + ":key", bssk.getPublicKey());
// redisUtil.set(HDConstant.HD_STATION_SECRET_KEY_AES_PREFIX + stationCode + ":iv", bssk.getPrivateKey());
//// jo.set("aesSecretKey", o1.toString());
//// jo.set("aesIv", o2.toString());
// jo.set("encryptKey", o1.toString());
// jo.set("encryptVector", o2.toString());
// return jo;
// }
}

View File

@ -76,9 +76,20 @@ public class OrderSwapController {
@ApiOperation("手动换电完成")
@PostMapping("/manualBatterySwappingCompleted")
@ApiLog(value = "手动换电完成", type=LogTypeEnum.OPERATION)
public Result<Boolean> ManualBatterySwappingCompleted(@RequestBody OrderSwapDTO orderSwapDTO) throws Exception {
public Result<Boolean> manualBatterySwappingCompleted(@RequestBody OrderSwapDTO orderSwapDTO) throws Exception {
return orderSwapService.updateOrderSwapDTO(orderSwapDTO);
}
/**
* 手动换电完成
* @return
*/
@ApiOperation("订单关闭")
@PostMapping("/close")
@ApiLog(value = "订单关闭", type=LogTypeEnum.OPERATION)
public Result<Boolean> close(@RequestBody OrderSwapDTO orderSwapDTO) throws Exception {
return orderSwapService.close(orderSwapDTO);
}
}

View File

@ -2,6 +2,7 @@ package com.evotech.hd.webserver.job;
import com.evotech.hd.core.enums.BaseEnum;
import com.evotech.hd.webserver.job.job.ArrivalSignalJob;
import com.evotech.hd.webserver.job.job.KeepaliveJob;
import com.evotech.hd.webserver.job.job.LicensePlateMachineJob;
import lombok.AllArgsConstructor;
import lombok.Getter;
@ -97,7 +98,10 @@ public class JobConstant {
*/
// public static String VEHICLE_ABDICATION_JOB = VehicleAbdicationJob.class.getSimpleName();
/***
* 客户端与服务端的心跳检查
*/
public static String KEEPALIVE_JOB = KeepaliveJob.class.getSimpleName();
}

View File

@ -1,18 +1,23 @@
package com.evotech.hd.webserver.job.job;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.evotech.hd.core.dtos.Result;
import com.evotech.hd.core.dtos.ResultUtil;
import com.evotech.hd.core.dtos.business.AccessStrategyDTO;
import com.evotech.hd.core.dtos.business.BatteryCompartmentDTO;
import com.evotech.hd.core.dtos.business.RunningInstructionsDetailDTO;
import com.evotech.hd.core.dtos.system.ParamsDTO;
import com.evotech.hd.exception.InstructionException;
import com.evotech.hd.utils.Collections;
import com.evotech.hd.webserver.controller.TestController;
import com.evotech.hd.webserver.mqtt.MqttPublishUtils;
import com.evotech.hd.webserver.service.ParamsService;
import com.evotech.hd.webserver.utils.AccessStrategyUtil;
import com.evotech.hd.webserver.utils.ParamUtils;
import com.evotech.hd.webserver.utils.instruction.InstructionReadUtils;
import com.evotech.hd.webserver.utils.instruction.InstructionUtils;
import com.evotech.hd.webserver.utils.query.QueryWrapperGenerator;
import com.evotech.hd.webserver.utils.sendCloud.CloudSendInfoUtils;
import com.evotech.hd.webserver.websocket.controller.WebSocketUtils;
import lombok.extern.slf4j.Slf4j;
@ -21,6 +26,7 @@ import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 首页告警扫描
@ -35,9 +41,11 @@ public class CheckAlarmJob implements BaseJob{
// 任务执行方法必须定义为public void run()
public void run(Map<String, Object> params) throws InstructionException {
public void run(Map<String, Object> params) throws Exception {
log.info("===== 执行检查报警任务 =====");
Map<String, String> alarmMessage = Collections.emptyMap();
//默认不影响
Boolean effectBatterySwapping = false;
//获取所有的异常指令
List<RunningInstructionsDetailDTO> instructions = getRunningInstructionsDetailService().findDictDetailDTOByTypeCode("check_alarm");
if(Collections.isNotEmpty(instructions)){
@ -51,20 +59,9 @@ public class CheckAlarmJob implements BaseJob{
for (String rgvNo : rgvArrays){
if(!InstructionUtils.getBoolean(paramsDTO, InstructionReadUtils.executionInteger(paramsDTO, rgvNo))){
alarmMessage.put(paramsDTO.getName().replace(":num", rgvNo), paramsDTO.getErrMessage().replace(":num", rgvNo));
}
}
}else{
alarmMessage.put("RGV连接", "没有可用的RGV设备");
}
}if("RGV_RB_ErrorCode".equals(paramsDTO.getParamCode())){
AccessStrategyDTO accessStrategyDTO = AccessStrategyUtil.getValidAccessStrategyDTO();
if(StringUtils.isNotEmpty(accessStrategyDTO.getEffectiveRgvNo())){
String[] rgvArrays = accessStrategyDTO.getEffectiveRgvNo().split(",");
for (String rgvNo : rgvArrays){
Map<String, Object> result = getExecutionBatterySwapService().executionErrorResult(rgvNo);
if(Collections.isNotEmpty(result)){
alarmMessage.put(paramsDTO.getName().replace(":num", rgvNo), String.valueOf(result.get("errorMsg")));
TestController.getInstance().stopRgv(rgvNo, rgvNo, String.valueOf(result.get("errorMsg")));
if(paramsDTO.getEffectBatterySwapping()){
effectBatterySwapping = true;
}
}
}
}else{
@ -73,9 +70,11 @@ public class CheckAlarmJob implements BaseJob{
}else{
if(!InstructionUtils.getBoolean(paramsDTO, InstructionReadUtils.executionInteger(paramsDTO, null))){
alarmMessage.put(paramsDTO.getName(), paramsDTO.getErrMessage());
if(paramsDTO.getEffectBatterySwapping()){
effectBatterySwapping = true;
}
}
}
}
}
//检查云平台链接
@ -85,10 +84,12 @@ public class CheckAlarmJob implements BaseJob{
alarmMessage.put("云平台", "连接丢失");
}
//检查电池仓,电池信号
alarmMessage = checkBatteryCompartmentSignal(alarmMessage);
//存在告警, 推送数据
if(Collections.isNotEmpty(alarmMessage)){
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","alarm","data",JSONObject.toJSONString(alarmMessage))));
if(keepalive != null && keepalive){
//推送数据
Map<String, Object> alarmMap = Collections.emptyMap();
@ -104,9 +105,47 @@ public class CheckAlarmJob implements BaseJob{
if(alarmMessage.containsKey("急停")){
alarmMap.put("stop", 2); //2为云平台现有的定义的站控的报警标识
}
CloudSendInfoUtils.sendAlarm(alarmMap);
CloudSendInfoUtils.sendAlarm(alarmMap, effectBatterySwapping);
}
}
log.info("检查报警任务执行完成");
}
BatteryCompartmentDTO params = new BatteryCompartmentDTO(){{
setStatus(1);
setState(1);
}};
//
public Map<String, String> checkBatteryCompartmentSignal(Map<String, String> alarmMessage) throws Exception {
//获取所有的仓位
List<BatteryCompartmentDTO> list = getBatteryCompartmentService().findList(QueryWrapperGenerator.buildQueryCondition(params, BatteryCompartmentDTO.class));
StringBuilder sb = new StringBuilder("");
//有电池,无信号
List<BatteryCompartmentDTO> existsBatteryList = list.stream().filter(BatteryCompartmentDTO::getExistsBattery).collect(Collectors.toList());
if(Collections.isNotEmpty(existsBatteryList)){
for (BatteryCompartmentDTO bc : existsBatteryList){
//如果有电池, 返回的无电池信号, 直接锁定电池仓, 做电池仓禁用
if(!InstructionReadUtils.checkExistsBattery(String.valueOf(bc.getId()))){
getBatteryCompartmentService().settingState(bc.getId(), 2);
sb.append("电池仓: ").append(bc.getId()).append("号, 电池信号丢失, 请确认;");
}
}
}
//没电池, 有信号
List<BatteryCompartmentDTO> notExistsBatteryList = list.stream().filter(data -> !data.getExistsBattery()).collect(Collectors.toList());
if(Collections.isNotEmpty(notExistsBatteryList)){
for (BatteryCompartmentDTO bc : notExistsBatteryList){
//如果有电池, 返回的无电池信号, 直接锁定电池仓, 做电池仓禁用
if(InstructionReadUtils.checkExistsBattery(String.valueOf(bc.getId()))){
getBatteryCompartmentService().settingState(bc.getId(), 2);
sb.append("电池仓: ").append(bc.getId()).append("号, 出现未知电池信号, 请确认;");
}
}
}
if(sb.length() > 0){
alarmMessage.put("电池仓", sb.toString());
}
return alarmMessage;
}
}

View File

@ -0,0 +1,26 @@
package com.evotech.hd.webserver.job.job;
import com.evotech.hd.webserver.mqtt.MqttPublishUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* KeepaliveJob
*
* @author andy.shi
* @ClassName:KeepaliveLob
* @date: 2026年01月13日 11:34
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@Slf4j
@Component
public class KeepaliveJob implements BaseJob{
@Override
public void run(Map<String, Object> params) throws Exception {
MqttPublishUtils.sendKeepalive();
}
}

View File

@ -1,6 +1,7 @@
package com.evotech.hd.webserver.job.service;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.evotech.hd.core.dtos.Result;
@ -109,6 +110,16 @@ public class ExecutionBatterySwapService {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","order","data",JSONObject.toJSONString(ResultUtil.getValue(runningOrderResult)))));
//下发物理接口, 抬杆放行 TODO
InstructionWriteUtils.openRolling(ParamUtils.getDoorParams("入口"));
//如果是双RGV, 并且开启了预取,
AccessStrategyDTO accessStrategyDTO = AccessStrategyUtil.getValidAccessStrategyDTO();
//如果开启了预存
if(accessStrategyDTO.getBatteryPrefetching() && AccessStrategyUtil.getEffectiveRgvNoList(accessStrategyDTO).size() > 1){
//获取仓位信息
Map<String, String> resultMap = calculationPosition(accessStrategyDTO);
RedisUtil.set("rgvInfo", JSONObject.toJSONString(resultMap));
//执行取点数据
buildTakeFuture(resultMap.get("loadingRgv"), Integer.valueOf(resultMap.get("takeNo")), runningOrderResult.getData().getId());
}
try {
//开启车辆到位扫秒
quartzJobService.resumeJob(new QuartzJobInfo(JobConstant.ARRIVAL_SIGNAL_JOB, JobConstant.GroupEnum.SWAP_GROUP.getType()));
@ -143,7 +154,12 @@ public class ExecutionBatterySwapService {
//打开开合门
if(buildOpenFuture().get()){
//获取仓位信息
Map<String, String> result = calculationPosition(accessStrategyDTO);
Map<String, String> result = Collections.emptyMap();
if(accessStrategyDTO.getBatteryPrefetching() && AccessStrategyUtil.getEffectiveRgvNoList(accessStrategyDTO).size() > 1){
result = JSON.to(Map.class, RedisUtil.get("rgvInfo"));
}else{
result = calculationPosition(accessStrategyDTO);
}
//查询当前运行订单
Result<OrderSwapDTO> running = orderSwapService.runningOrder();
OrderSwapDTO orderSwapDTO = running.getData();
@ -284,7 +300,27 @@ public class ExecutionBatterySwapService {
return false;
});
//
CompletableFuture<Boolean> takeFuture =buildTakeFuture(loadingRgv, takeNo, orderId);
CompletableFuture<Boolean> takeFuture;
if(AccessStrategyUtil.getValidAccessStrategyDTO().getBatteryPrefetching()){
takeFuture = CompletableFuture.supplyAsync(() -> {
try {
Boolean result = false;
//下发拆除命令
do {
if(result = Boolean.valueOf(String.valueOf(RedisUtil.get("buildTakeFuture")))){
return true;
}
}while (!result);
} catch (Exception e) {
log.error("预取失败, {}", e.getMessage(), e);
return false;
}
return false;
});
}else{
//
takeFuture =buildTakeFuture(loadingRgv, takeNo, orderId);
}
//. 依托于 ,
CompletableFuture<Boolean> loadingFuture = CompletableFuture.allOf(splitFuture, takeFuture).thenApplyAsync(voidResult->{
Boolean split = splitFuture.join();
@ -323,6 +359,7 @@ public class ExecutionBatterySwapService {
});
}
//启动对中机构
//对中机构启动速度过快, 无法短频查询, 所以取消sleep();
public CompletableFuture<Boolean> buildCenOpenFuture(){
return CompletableFuture.supplyAsync(()->{
try {
@ -333,12 +370,10 @@ public class ExecutionBatterySwapService {
if(checkCenError()){
return false;
}
sleep();
if (openResult = checkCenOpenExecutionResult()) {
log.info("对中机构正在运行, 当前时间为: "+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()));
Boolean result = false;
do {
sleep();
if(result = checkCenExecutionResult()){
log.info("对中机构执行完成, 当前时间为: "+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()));
// 推送云端, 并查询是否存在异常 没有异常, 开始启动换电
@ -494,6 +529,7 @@ public class ExecutionBatterySwapService {
public CompletableFuture<Boolean> buildTakeFuture(final String rgv, final Integer taskNo, final Integer orderId){
return CompletableFuture.supplyAsync(() -> {
try {
RedisUtil.set("buildTakeFuture", false);
OrderSwap orderSwap = orderSwapService.getById(orderId);
orderSwap.setRentBatNo(String.valueOf(taskNo));
Battery battery = batteryService.getBatteryByCompartmentId(taskNo);
@ -531,6 +567,7 @@ public class ExecutionBatterySwapService {
log.error("取新电池后, BMS下电出现错误", e);
e.printStackTrace();
}
RedisUtil.set("buildTakeFuture", true);
return true;
}
return false;
@ -795,9 +832,12 @@ public class ExecutionBatterySwapService {
orderSwapService.updateById(orderSwapWrapper.toEntity(orderSwapDTO));//更新换电完成状态
//执行换电完成
executionResultPush(orderSwapDTO, SwapBatteryStepEnum.COMPLETED, false, Collections.emptyMap());
//换电完成, 预取结果重置为false
RedisUtil.set("buildTakeFuture", false);
//重置rgv信息
RedisUtil.set("rgvInfo", JSONObject.toJSONString(Collections.emptyMap()));
//关闭开合门
if(buildCloseFuture().get()){
//释放对中机构
InstructionWriteUtils.closeCorrectInstitution();
//推送空对象推送websocket, 刷新首页数据

View File

@ -0,0 +1,12 @@
package com.evotech.hd.webserver.mapper;
/**
* BasicMapper
*
* @author andy.shi
* @ClassName:BasicMapper
* @date: 2026年01月12日 11:27
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
public interface BasicMapper {
}

View File

@ -27,6 +27,8 @@ public interface BatteryCompartmentMapper extends BaseMapper<BatteryCompartment>
*/
IPage<BatteryCompartmentDTO> findPage(Page<BatteryCompartmentDTO> page, @Param(Constants.WRAPPER) QueryWrapper queryWrapper);
List<BatteryCompartmentDTO> findList( @Param(Constants.WRAPPER) QueryWrapper queryWrapper);
BatteryCompartmentDTO getInfo(@Param("id")Integer id);
List<Integer> findChargingPositionIds(@Param("notAllPower") Boolean isNotAllPower);

View File

@ -0,0 +1,30 @@
package com.evotech.hd.webserver.mapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.evotech.hd.core.dtos.system.LogDTO;
import com.evotech.hd.core.dtos.system.MessageMqttDTO;
import com.evotech.hd.core.entity.system.Log;
import com.evotech.hd.core.entity.system.MessageMqtt;
import org.apache.ibatis.annotations.Param;
/**
* 接口
*
* @ClassName:LogMapper
* @date: 2025年08月18日 14:45
* @author: andy.shi
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
public interface MessageMqttMapper extends BaseMapper<MessageMqtt> {
/**
* 获日志列表
*
* @param queryWrapper
* @return
*/
IPage<MessageMqttDTO> findPage(Page<MessageMqttDTO> page, @Param(Constants.WRAPPER) QueryWrapper queryWrapper);
}

View File

@ -2,10 +2,14 @@ package com.evotech.hd.webserver.mqtt;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.evotech.hd.utils.Global;
import com.evotech.hd.webserver.config.redis.utils.RedisUtil;
import com.evotech.hd.webserver.utils.ParamUtils;
import lombok.extern.slf4j.Slf4j;
@ -22,6 +26,13 @@ public class MessageUtilService {
@Resource
private RedisUtil redisUtil;
public JSONObject decryptEncryptKeyReqMessage(MqttMessage message) {
byte[] payload = message.getPayload();
RSA rsa = SecureUtil.rsa(Global.newInstance().getCloudPrivateKey(), null);
byte[] decrypt = rsa.decrypt(new String(payload), KeyType.PrivateKey);
return JSONUtil.parseObj(new String(decrypt));
}
/**
* 解密AES类型的消息
* @param topic

View File

@ -3,8 +3,11 @@ package com.evotech.hd.webserver.mqtt;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.evotech.hd.webserver.job.service.ExecutionBatterySwapService;
import com.evotech.hd.webserver.mqtt.enums.MqttMessageTypeEnum;
import com.evotech.hd.webserver.service.BatteryStrategyService;
import com.evotech.hd.webserver.service.MessageMqttService;
import com.evotech.hd.webserver.service.OrderReservationService;
import com.evotech.hd.webserver.utils.ParamUtils;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.stereotype.Service;
@ -24,25 +27,42 @@ public class MqttMessageHandleService {
BatteryStrategyService batteryStrategyService;
@Resource
ExecutionBatterySwapService executionBatterySwapService;
@Resource
MessageMqttService messageMqttService;
public void handle(MessageTopic topic, MqttMessage message) throws Exception {
//获取秘钥
if (MqttMessageTypeEnum.ENCRYRESP.getType().equals(topic.getMessageType())) {
ParamUtils.encryptKeyReq(messageUtilService.decryptEncryptKeyReqMessage(message));
return;
}
// 2. keepalive不加密单独处理
if (MqttMessageTypeEnum.KEEPALIVE.getType().equals(topic.getMessageType())) {
JSONObject jo = JSONUtil.parseObj(message);
MqttMessageHeader header = new MqttMessageHeader();
header.setFunction(MqttMessageTypeEnum.KEEPALIVE.getType());
jo.set("header", JSONUtil.parseObj(header));
messageMqttService.update(null, topic, null, 2, jo);
return;
}
JSONObject jo = messageUtilService.decryptAesMessage(topic, message);
MqttMessageHeader header = JSONUtil.toBean(jo.getJSONObject("header"), MqttMessageHeader.class);
com.alibaba.fastjson2.JSONObject dataBody = com.alibaba.fastjson2.JSONObject.parseObject(jo.getStr("dataBody"));
//站端比较特殊, 只有2个mq消息, 1个是下发预约单, 一个是点击开始
//不做特殊设计, 直接if-else 判定就好了
if ("pushReservation".equalsIgnoreCase(header.getFunction())){
//接收云端订单
orderReservationService.acceptReservations(dataBody);
}else if("BatterySwapReq".equalsIgnoreCase(header.getFunction())){
//接收云端的开始换电, 启动对中机构
try {
executionBatterySwapService.activateAlignmentMechanism();
} catch (Exception e) {
e.printStackTrace();
}
}else if("chargingStrategy".equalsIgnoreCase(header.getFunction())){
batteryStrategyService.manageCloudData(dataBody);
MqttMessageHeader header = JSONUtil.toBean(jo.getJSONObject("header"), MqttMessageHeader.class);
com.alibaba.fastjson2.JSONObject dataBody = com.alibaba.fastjson2.JSONObject.parseObject(jo.getStr("dataBody"));
//站端比较特殊, 只有2个mq消息, 1个是下发预约单, 一个是点击开始
//不做特殊设计, 直接if-else 判定就好了
if ("pushReservation".equalsIgnoreCase(header.getFunction())){
//接收云端订单
orderReservationService.acceptReservations(dataBody);
}else if("BatterySwapReq".equalsIgnoreCase(header.getFunction())){
//接收云端的开始换电, 启动对中机构
try {
executionBatterySwapService.activateAlignmentMechanism();
} catch (Exception e) {
e.printStackTrace();
}
}else if("chargingStrategy".equalsIgnoreCase(header.getFunction())){
batteryStrategyService.manageCloudData(dataBody);
}
}
}

View File

@ -2,6 +2,7 @@ package com.evotech.hd.webserver.mqtt;
import cn.hutool.json.JSONObject;
import com.evotech.hd.webserver.config.mqtt.MqttPublishMessage;
import com.evotech.hd.webserver.mqtt.enums.MqttMessageTypeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -23,12 +24,22 @@ public class MqttPublishUtils {
this.mqttPublishMessage = mqttPublishMessage;
}
public static void sendKeepalive(){
mqttPublishMessage.publishKeepaliveMessage();
}
public static void sendEncryptKeyReq(){
MessageTopic topic = new MessageTopic();
topic.setMessageType(MqttMessageTypeEnum.ENCRYREQ.getType());
mqttPublishMessage.publishRSAMessage(topic);
}
public static void sendState(String messageType, JSONObject dataBody){
MessageTopic topic = new MessageTopic();
topic.setMessageType("state");
topic.setMessageType(MqttMessageTypeEnum.STATE.getType());
MqttMessageHeader header = new MqttMessageHeader();
header.setTimeStamp(String.valueOf(System.currentTimeMillis()));
header.setIndex("1");
header.setIndex(MqttMessageTypeEnum.STATE.getId());
header.setFunction(messageType);
mqttPublishMessage.publishAESMessage(topic,header, dataBody);
}

View File

@ -0,0 +1,45 @@
package com.evotech.hd.webserver.mqtt.enums;
/**
* 如下 8 种类型:
1)state 换电站状态类信息站控发送支持变化实时上送周期上送和查询上
送三种方式云平台无需回复云平台可根据需要随时向站控系统召唤状态类信息
2)event 事件类信息站控发送包括故障告警事件记录充换电事件记录等 事件发生时上送需接收者回复确认站控 15 秒内收不到回复则要重复发送直到收
到云平台的回复云平台可通过召唤历史事件流水号的方式检查事件是否丢失
3)confirm 事件确认回复云平台收到事件后的回复信息
4)request 主动请求云平台站控均可发起请求
5)response 收到请求后接收者的回复
6)keepalive 心跳报文站控周期发送周期30秒云平台收到后立即回复报文内容为当前时标字符串:yyyy-MM-dd hh:mm:ss云平台和站控连续 3 个周期收不到对方的任何报文则认为通信中断通信中断后站控不发送心跳外的任何报文直到收到心跳回复报文
7)encryptKeyReq 站控发送请求密钥
8)encryptKeyResp 云平台回复站控的密钥请求
*
*/
public enum MqttMessageTypeEnum {
STATE("1", "state"),
EVENT("2", "event"),
CONFIRM("3", "confirm"),
REQUEST("4", "request"),
RESPONSE("5", "response"),
KEEPALIVE("6", "keepalive"),
ENCRYREQ("7", "encryptKeyReq"),
ENCRYRESP("8", "encryptKeyResp");
String id;
String type;
public String getId() {
return id;
}
public String getType() {
return type;
}
MqttMessageTypeEnum(String id, String type) {
this.id = id;
this.type = type;
}
}

View File

@ -33,6 +33,8 @@ public interface BatteryCompartmentService extends IService<BatteryCompartment>
* @return
*/
IPage<BatteryCompartmentDTO> findPageList(Page<BatteryCompartmentDTO> page, QueryWrapper queryWrapper);
List<BatteryCompartmentDTO> findList( QueryWrapper queryWrapper);
/***
* 获取非全额充电中的仓位信息
* @return

View File

@ -0,0 +1,15 @@
package com.evotech.hd.webserver.service;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.extension.service.IService;
import com.evotech.hd.core.dtos.Result;
import com.evotech.hd.core.entity.system.MessageMqtt;
import com.evotech.hd.webserver.mqtt.MessageTopic;
public interface MessageMqttService extends IService<MessageMqtt> {
public Result<Integer> addResultId(String stationCode);
public Result<MessageMqtt> update(Integer id, MessageTopic topic, String messageId, int qos, JSONObject jo);
}

View File

@ -8,6 +8,7 @@ import com.evotech.hd.core.dtos.Result;
import com.evotech.hd.core.dtos.business.OrderSwapDTO;
import com.evotech.hd.core.entity.business.OrderReservation;
import com.evotech.hd.core.entity.business.OrderSwap;
import org.springframework.web.bind.annotation.RequestBody;
import java.io.Serializable;
@ -35,4 +36,6 @@ public interface OrderSwapService extends IService<OrderSwap> {
Result<Boolean> sendOrderCompleted(Serializable orderId);
Result<Boolean> updateOrderSwapDTO(OrderSwapDTO orderSwapDTO) throws Exception ;
Result<Boolean> close(OrderSwapDTO orderSwapDTO) throws Exception;
}

View File

@ -31,4 +31,6 @@ public interface ParamsService extends IService<Params> {
ParamsDTO getParamsDTOByCode(String code);
ParamsDTO saveParamsDTO(ParamsDTO paramsDTO);
ParamsDTO getOrUpdateParamsDTO(String name, String code, String defVal, String des);
}

View File

@ -77,6 +77,12 @@ public class BatteryCompartmentServiceImpl extends ServiceImpl<BatteryCompartmen
return getBaseMapper().findPage(page, queryWrapper);
}
@Override
public List<BatteryCompartmentDTO> findList(QueryWrapper queryWrapper) {
queryWrapper.orderByAsc("a.id");// 根据预约日期和预约时间段倒序排序
return getBaseMapper().findList( queryWrapper);
}
@Override
public List<Integer> findChargingPositionIds(Boolean isNotAllPower) {
return getBaseMapper().findChargingPositionIds(isNotAllPower);
@ -133,7 +139,7 @@ public class BatteryCompartmentServiceImpl extends ServiceImpl<BatteryCompartmen
//检查电池是否已经充满电
if (StringUtils.isEmpty(battery.getSoc()) || Integer.valueOf("100").compareTo(Integer.valueOf(battery.getSoc())) >0){
//检查充电机 PS: 这种情况是不会出现的, 但是以防万一, 做个处理, 不做数据调整, 但是需要返回异常信息,需要站控人员调整
if(!InstructionReadUtils.queryBatExist(id)){
if(!InstructionReadUtils.checkExistsBattery(String.valueOf(id))){
return Result.getInstance().build(Boolean.class).error("当前仓位返回没有电池, 请确认电池是否存在,或者是否对接到位", false);
}
//下发充电

View File

@ -0,0 +1,64 @@
package com.evotech.hd.webserver.service.impl;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evotech.hd.core.dtos.Result;
import com.evotech.hd.core.dtos.system.LogDTO;
import com.evotech.hd.core.entity.system.Log;
import com.evotech.hd.core.entity.system.MessageMqtt;
import com.evotech.hd.webserver.mapper.LogMapper;
import com.evotech.hd.webserver.mapper.MessageMqttMapper;
import com.evotech.hd.webserver.mqtt.MessageTopic;
import com.evotech.hd.webserver.mqtt.MqttMessageHeader;
import com.evotech.hd.webserver.service.LogService;
import com.evotech.hd.webserver.service.MessageMqttService;
import org.springframework.stereotype.Service;
/**
*
*
* @ClassName:LogServiceImpl
* @date: 2025年08月18日 14:44
* @author: andy.shi
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@Service
public class MessageMqttServiceImpl extends ServiceImpl<MessageMqttMapper, MessageMqtt> implements MessageMqttService {
@Override
public Result<Integer> addResultId(String stationCode) {
MessageMqtt messageMqtt = new MessageMqtt();
messageMqtt.setStationCode(stationCode);
if(save(messageMqtt)){
return Result.getInstance().build(Integer.class).success(messageMqtt.getId());
}
return Result.getInstance().build(Integer.class).error("保存失败");
}
@Override
public Result<MessageMqtt> update(Integer id, MessageTopic topic, String messageId, int qos, JSONObject jo) {
MqttMessageHeader header = JSONUtil.toBean(jo.getJSONObject("header"), MqttMessageHeader.class);
MessageMqtt mm = getById(id);
if(mm == null){
mm = new MessageMqtt();
}
mm.setContent(jo.toJSONString(0));
mm.setDirection(topic.getDataDirection());
if(header != null){
mm.setMessageFunction(header.getFunction());
}
mm.setMessageId(messageId);
mm.setQos(qos);
mm.setStationCode(topic.getStationCode());
mm.setTopic(topic.toString());
mm.setType(topic.getMessageType());
if(saveOrUpdate(mm)){
return Result.getInstance().build(MessageMqtt.class).success(mm);
}
return Result.getInstance().build(MessageMqtt.class).error("更改失败");
}
}

View File

@ -74,7 +74,8 @@ public class OrderReservationServiceImpl extends ServiceImpl<OrderReservationMap
orderReservationDTO.setSwapDay(swapDay);
orderReservationDTO.setSwapDuration(swapDuration);
orderReservationDTO.setStatus(1);
Result<JSONObject> result = CloudSendInfoUtils.sendOrderReservation(Collections.asMap("source",orderReservationDTO.getSource(),"stationCode",ParamUtils.findStationCode(),"stationName",ParamUtils.findStationName(),"reservationTime",orderReservationDTO.getReservationTime(),"swapDay",DateUtils.parseDateToStr("yyyyMMdd", reservationTime),"swapDuration",orderReservationDTO.getSwapDuration(),"uname",orderReservationDTO.getReservationName(),"phone",orderReservationDTO.getReservationPhone(),"plateNum",orderReservationDTO.getPlateNum()));
//"stationCode",ParamUtils.findStationCode(),"stationName",ParamUtils.findStationName(),
Result<JSONObject> result = CloudSendInfoUtils.sendOrderReservation(Collections.asMap("source",orderReservationDTO.getSource(),"reservationTime",orderReservationDTO.getReservationTime(),"swapDay",DateUtils.parseDateToStr("yyyyMMdd", reservationTime),"swapDuration",orderReservationDTO.getSwapDuration(),"uname",orderReservationDTO.getReservationName(),"phone",orderReservationDTO.getReservationPhone(),"plateNum",orderReservationDTO.getPlateNum()));
JSONObject cloudResult = ResultUtil.getValue(result);
if(cloudResult != null){
//防止并发, 停止车牌机扫描,

View File

@ -1,5 +1,6 @@
package com.evotech.hd.webserver.service.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@ -8,6 +9,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evotech.hd.core.dtos.Result;
import com.evotech.hd.core.dtos.ResultUtil;
import com.evotech.hd.core.dtos.business.AccessStrategyDTO;
import com.evotech.hd.core.dtos.business.BatterySwapStepDTO;
import com.evotech.hd.core.dtos.business.OrderSwapDTO;
import com.evotech.hd.core.entity.business.Battery;
@ -16,9 +18,14 @@ import com.evotech.hd.core.entity.business.OrderSwap;
import com.evotech.hd.core.enums.OrderStatusEnums;
import com.evotech.hd.core.enums.SwapBatteryStepEnum;
import com.evotech.hd.core.mapstruct.OrderSwapWrapper;
import com.evotech.hd.exception.InstructionException;
import com.evotech.hd.utils.Collections;
import com.evotech.hd.utils.CommonUtil;
import com.evotech.hd.webserver.config.redis.utils.RedisUtil;
import com.evotech.hd.webserver.job.JobConstant;
import com.evotech.hd.webserver.job.entity.QuartzJobInfo;
import com.evotech.hd.webserver.job.service.ExecutionBatterySwapService;
import com.evotech.hd.webserver.job.service.QuartzJobService;
import com.evotech.hd.webserver.mapper.OrderSwapMapper;
import com.evotech.hd.webserver.service.BatteryCompartmentService;
import com.evotech.hd.webserver.service.BatteryService;
@ -26,7 +33,10 @@ import com.evotech.hd.webserver.service.BatterySwapStepService;
import com.evotech.hd.webserver.service.OrderSwapService;
import com.evotech.hd.webserver.utils.AccessStrategyUtil;
import com.evotech.hd.webserver.utils.ParamUtils;
import com.evotech.hd.webserver.utils.instruction.InstructionReadUtils;
import com.evotech.hd.webserver.utils.instruction.InstructionWriteUtils;
import com.evotech.hd.webserver.utils.sendCloud.CloudSendInfoUtils;
import com.evotech.hd.webserver.websocket.controller.WebSocketUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
@ -35,8 +45,13 @@ import org.springframework.stereotype.Service;
import java.io.Serializable;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/**
@ -61,6 +76,8 @@ public class OrderSwapServiceImpl extends ServiceImpl<OrderSwapMapper, OrderSwap
OrderSwapWrapper orderSwapWrapper;
@Autowired
ExecutionBatterySwapService executionBatterySwapService;
@Autowired
QuartzJobService quartzJobService;
@Override
public IPage<OrderSwapDTO> findPageList(Page<OrderSwapDTO> page, QueryWrapper queryWrapper) {
@ -195,6 +212,60 @@ public class OrderSwapServiceImpl extends ServiceImpl<OrderSwapMapper, OrderSwap
return Result.getInstance().build(Boolean.class).success(true);
}
@Override
public Result<Boolean> close(OrderSwapDTO orderSwapDTO) throws Exception {
AccessStrategyDTO accessStrategyDTO = AccessStrategyUtil.getValidAccessStrategyDTO();
if(accessStrategyDTO.getBatteryPrefetching() && AccessStrategyUtil.getEffectiveRgvNoList(accessStrategyDTO).size() > 1){
//重置预取标识
RedisUtil.set("buildTakeFuture", false);
//将电池送回仓位
Map<String, String> resultMap = JSON.to(Map.class, RedisUtil.get("rgvInfo"));
//获取格位信息
if(executionBatterySwapService.buildPutFuture(resultMap.get("loadingRgv"), Integer.valueOf(resultMap.get("takeNo")), orderSwapDTO.getId()).join()){
//存完之后, 关闭订单信息
orderSwapDTO.setStatus(OrderStatusEnums.CANCLE.getCode());
if(updateById(orderSwapWrapper.toEntity(orderSwapDTO))){
//预取结果重置为false
RedisUtil.set("buildTakeFuture", false);
//重置rgv信息
RedisUtil.set("rgvInfo", JSONObject.toJSONString(Collections.emptyMap()));
//关闭车辆到位检查
quartzJobService.pauseJob(new QuartzJobInfo(JobConstant.ARRIVAL_SIGNAL_JOB, JobConstant.GroupEnum.SWAP_GROUP.getType()));
//打开出口闸门, 执行开门操作
InstructionWriteUtils.openRolling(ParamUtils.getDoorParams("出口"));
//打开车牌机扫描
quartzJobService.resumeJob(JobConstant.LICENSE_PLATE_MACHINE_JOB, JobConstant.GroupEnum.SWAP_GROUP.getType());
//推送云端, 订单关闭
CloudSendInfoUtils.closeOrderStatus(Collections.asMap("pkId", orderSwapDTO.getCloudOrderId(), "status", orderSwapDTO.getStatus()));
//推送空对象推送websocket, 刷新首页数据
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "order", "data", JSONObject.toJSONString(new OrderSwapDTO((AccessStrategyUtil.getEffectiveRgvNoList(accessStrategyDTO).size()))))));
//关门
CompletableFuture.runAsync(
() -> {
//关闭进门栏杆
try {
InstructionWriteUtils.closeRolling(ParamUtils.getDoorParams("出口"));
} catch (Exception e) {
throw new RuntimeException(e);
}
},
// 延迟执行器延迟 5 分钟
CompletableFuture.delayedExecutor(ParamUtils.getVehicleAbdicationWaitingMilliseconds(), TimeUnit.MILLISECONDS)
);
}
}
}
// else{
// result = calculationPosition(accessStrategyDTO);
// }
return Result.getInstance().build(Boolean.class).success(true);
}
// public static void sendCloud(final Integer id){
// CompletableFuture.runAsync(() -> {
// try {

View File

@ -10,6 +10,7 @@ import com.evotech.hd.core.entity.system.Params;
import com.evotech.hd.core.mapstruct.ParamsWrapper;
import com.evotech.hd.core.enums.CacheNames;
import com.evotech.hd.webserver.mapper.ParamsMapper;
import com.evotech.hd.webserver.mqtt.MqttPublishUtils;
import com.evotech.hd.webserver.service.ParamsService;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -64,7 +65,6 @@ public class ParamsServiceImpl extends ServiceImpl<ParamsMapper,Params> implemen
@Override
@Cacheable(cacheNames = CacheNames.SYSTEM_RUNNING_PARAMS, key = "#code")
// @CacheEvict(value = CacheNames.SYSTEM_RUNNING_PARAMS, key = "#code", allEntries = true)
public ParamsDTO getParamsDTOByCode(String code) {
Params param = getOne(new LambdaQueryWrapper<Params>().eq(Params::getParamCode, code), false);
return paramsWrapper.toDTO(param);
@ -75,12 +75,34 @@ public class ParamsServiceImpl extends ServiceImpl<ParamsMapper,Params> implemen
}
@Override
// @Cacheable(cacheNames = CacheNames.SYSTEM_RUNNING_PARAMS, key = "#paramsDTO.paramCode")
@CacheEvict(value = CacheNames.SYSTEM_RUNNING_PARAMS, allEntries = true)
public ParamsDTO saveParamsDTO(ParamsDTO paramsDTO) {
saveOrUpdate(paramsWrapper.toEntity(paramsDTO));
//如果当前是参数设置, 并且当前操作的是站点编码, 则更新秘钥
if(Integer.valueOf(1).equals(paramsDTO.getGroupId()) && "station_code".equals(paramsDTO.getParamCode())){
MqttPublishUtils.sendEncryptKeyReq();
}
return paramsDTO;
}
@Override
@CacheEvict(value = CacheNames.SYSTEM_RUNNING_PARAMS, allEntries = true)
@Cacheable(cacheNames = CacheNames.SYSTEM_RUNNING_PARAMS, key = "#code")
public ParamsDTO getOrUpdateParamsDTO(String name, String code, String defVal, String des) {
Params param = getOne(new LambdaQueryWrapper<Params>().eq(Params::getParamCode, code), false);
if(ObjectUtils.isEmpty(param)){
param = new Params();
param.setName(name);
param.setParamCode(code);
param.setParamValue(defVal);
param.setDescription(des);
save(param);
}else{
param.setParamValue(defVal);
updateById(param);
}
return paramsWrapper.toDTO(param);
}
}

View File

@ -7,6 +7,7 @@ import com.evotech.hd.webserver.service.AccessStrategyService;
import com.evotech.hd.webserver.utils.sendCloud.CloudSendInfoUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -44,4 +45,11 @@ public class AccessStrategyUtil {
return Collections.emptyList();
}
public static List<String> getEffectiveRgvNoList(@NotNull AccessStrategyDTO accessStrategyDTO){
if(StringUtils.isNotEmpty(accessStrategyDTO.getEffectiveRgvNo())){
return Collections.asList(accessStrategyDTO.getEffectiveRgvNo().split(","));
}
return Collections.emptyList();
}
}

View File

@ -54,11 +54,6 @@ public class ParamUtils {
* 站端私钥
*/
static final String STATION_SECRET_KEY = "station_secret_key";
/***
* 站端公钥
*/
static final String STATION_PUBLIC_KEY = "station_public_key";
/***
* 站端AES私钥
*/
@ -149,15 +144,6 @@ public class ParamUtils {
ParamsDTO param= paramService.getParamsDTO("站点私钥", ParamsConstant.STATION_SECRET_KEY,"MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAKXEG3/V8DUxpOzb8lJLkJaZGAHSfS+oHoPzZy+Xbr7mb8Jfc7tXRd+H1mmQOXz36HGdPiMP7nK1kPr+ddEJe+yofCkpr5y/Mavki9cLQ3Z/BHUH/t0E7mjyXKhlyn7pfudlW7rqNfQx3eboir+9ppgFe0knW6xHffFECIdfmrt9AgMBAAECgYARw9AMpbFeCgl6RuIT1rxSn2qWu2emJVbL3liHHawFMm30v0UIZUR8PbMJUicPEQRstKTVnh34ViQI+h9HPUR1/rmdI/jdM2n44ai+4AvT1iONgLS4JBBpc5a+ctV9uAgfSU65cRVAzKTzq3Etcqwgzrn8sWultKAyb3pHmjeYswJBANFHjh5LfGSSEpAOdfcNopNAGSaEhNKpm2/0f1VwEyM3/utpTMfHVo/M2OtdpU7JH0+BdtJfAEXtMOMAfzka6EcCQQDKxbuEeYit5zqTbsMLG9y016KjH6oySPnCL4RnA1eeCwK9j0LuYC+rhBg8Km2iLsDwoUDZUjaX/oipB1Ydc+QbAkEAjCG4tOpgucrhqRo1vR6hLK4v6Q21DoZJMXbqyF/KQLve8uzIX8FHYfSNj1ReO1oKoCcVVBoOycPgBzAvACLXQwJBAMCbyl8vwnDN74oT8BkhQihVnBsu/M//GZ8m27GuLw/kjZnZ903O9/kH5K1h7/naR1NLGPpVaZ4/HTjRyy724nkCQQDLEogix/P5ZwI6RmKKAkyyZkMPJIn9kA1j/zeFACdVBzar87GB4DNHiuwByzL4V/CLnQOEocpoq5PciXy2Nbi6","软件初始安装时, 直接初始化");
return param.getParamValue();
}
/***
* 站点公钥
* @return
*/
public static String findStationPublicKey(){
ParamsDTO param= paramService.getParamsDTO("站点公钥", ParamsConstant.STATION_PUBLIC_KEY,"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClxBt/1fA1MaTs2/JSS5CWmRgB0n0vqB6D82cvl26+5m/CX3O7V0Xfh9ZpkDl89+hxnT4jD+5ytZD6/nXRCXvsqHwpKa+cvzGr5IvXC0N2fwR1B/7dBO5o8lyoZcp+6X7nZVu66jX0Md3m6Iq/vaaYBXtJJ1usR33xRAiHX5q7fQIDAQAB","软件初始安装时, 直接初始化");
return param.getParamValue();
}
/***
* 站点对称AES私钥
* @return
@ -391,4 +377,20 @@ public class ParamUtils {
return paramService.getParamsDTOByCode(code);
}
public static void encryptKeyReq(cn.hutool.json.JSONObject jsonObject){
try {
String encryptVector = jsonObject.getStr("encryptVector");
if(StringUtils.isNotEmpty(encryptVector)){
paramService.getOrUpdateParamsDTO("站点AES私钥", ParamsConstant.STATION_AES_SECRET_KEY,encryptVector,"软件初始安装时, 直接初始化");
}
String encryptKey = jsonObject.getStr("encryptKey");
if(StringUtils.isNotEmpty(encryptKey)){
paramService.getOrUpdateParamsDTO("站点AES公钥", ParamsConstant.STATION_AES_PUBLIC_KEY,encryptKey,"软件初始安装时, 直接初始化");
}
} catch (Exception e) {
e.printStackTrace();
log.error("更新站控的AES秘钥出现异常", e.getMessage());
}
}
}

View File

@ -107,17 +107,6 @@ public class InstructionReadUtils {
return InstructionUtils.getJson(execution(paramsDTO, String.valueOf(batteryCompartmentNo)));
}
/*** 检查电池仓是否存在电池
* @param: batteryCompartmentNo
* @return true 存在 false 不存在
*/
public static Boolean queryBatExist(Integer batteryCompartmentNo) throws InstructionException {
ParamsDTO paramsDTO = ParamUtils.getParamsDTO(ParamSysConstants.EXISTS_BATTERY);
return InstructionUtils.getBoolean(paramsDTO, executionInteger(paramsDTO, String.valueOf(batteryCompartmentNo)));
}
/*** 检查空调是否连接
* @return true 连接 false 未连接
*/
@ -406,7 +395,9 @@ public class InstructionReadUtils {
}
/***消防设备是否连接
/*** 检查电池仓是否存在电池
* @param: batteryCompartmentNo
* @return true 存在 false 不存在
*/
public static Boolean checkExistsBattery(String batteryCompartmentNo) throws InstructionException {
ParamsDTO paramsDTO = ParamUtils.getParamsDTO(ParamSysConstants.BSL_BAT_EXIST);

View File

@ -1,5 +1,6 @@
package com.evotech.hd.webserver.utils.sendCloud;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
@ -7,6 +8,7 @@ import com.evotech.hd.core.dtos.Result;
import com.evotech.hd.utils.Collections;
import com.evotech.hd.webserver.logging.AsyncLogService;
import com.evotech.hd.webserver.logging.LogUtils;
import com.evotech.hd.webserver.mqtt.MqttPublishUtils;
import com.evotech.hd.webserver.utils.ParamUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.HttpClient;
@ -86,16 +88,6 @@ public class CloudSendInfoUtils {
return JSONObject.parseObject(result.toString(),Result.class);
}
/***
* 站端获取预约单数据
* @param map
* @return
*/
public static Result<JSONArray> findOrderReservationList(Map<String, Object> map){
JSONObject result = send("获取云端预约单数据", JSONObject.parseObject(JSONObject.toJSONString(buildBaseInfo(map,"orderSwapBatteryPreProcessor","findOrderSwapBatteryPre"))));
return JSONObject.parseObject(result.toString(),Result.class);
}
/***
* 站端推送预约单数据状态
* @param map
@ -121,19 +113,33 @@ public class CloudSendInfoUtils {
* @param map
* @return
*/
public static void sendAlarm(Map<String, Object> map){
public static void sendAlarm(Map<String, Object> map, Boolean effectBatterySwapping){
map.put("state", effectBatterySwapping ? 3 : (ParamUtils.findStationRunningStatus() ? 1 : 3));
MqttPublishUtils.sendState("stationState", JSONUtil.parseObj(map));
//结合云端接口增加站端运行状态
map.put("state", (ParamUtils.findStationRunningStatus() ? 1 : 3));
send("推送告警信息", JSONObject.parseObject(JSONObject.toJSONString(buildBaseInfo(map,"alarmProcessor","alarmMessage"))));
//如果影响换电, 直接给3 进入检修, 如果不影响, 则检查当前站端的运行状态
// map.put("state", effectBatterySwapping ? 3 : (ParamUtils.findStationRunningStatus() ? 1 : 3));
// send("推送告警信息", JSONObject.parseObject(JSONObject.toJSONString(buildBaseInfo(map,"alarmProcessor","alarmMessage"))));
}
/***
* 站端推送车辆到位信息
* 站端推送换电步骤信息
* @param map
* @return
*/
public static Result<Boolean> sendArrivalSignal(Map<String, Object> map){
JSONObject result = send("创建订单", JSONObject.parseObject(JSONObject.toJSONString(buildBaseInfo(map,"orderSwapProcessor","arrivalSignal"))));
JSONObject result = send("换电步骤", JSONObject.parseObject(JSONObject.toJSONString(buildBaseInfo(map,"orderSwapProcessor","arrivalSignal"))));
return JSONObject.parseObject(result.toString(),Result.class);
}
/***
* 订单关闭
* @param map
* @return
*/
public static Result<Boolean> closeOrderStatus(Map<String, Object> map){
JSONObject result = send("订单关闭", JSONObject.parseObject(JSONObject.toJSONString(buildBaseInfo(map,"orderSwapProcessor","closeOrderStatus"))));
return JSONObject.parseObject(result.toString(),Result.class);
}
@ -190,7 +196,7 @@ public class CloudSendInfoUtils {
}
public static void sendAlarmWx(Map<String, Object> map){
JSONObject result = doPost("https://api.evo-techina.com/cloud/alarm/send/hq_web", map, Collections.asMap("Content-Type", "application/json","Accept-Language", "zh-CN"));
doPost("https://api.evo-techina.com/cloud/alarm/send/hq_web", map, Collections.asMap("Content-Type", "application/json","Accept-Language", "zh-CN"));
}
private static JSONObject doPost(String url, Map<String, Object> map, Map<String, String> headersMap) {

View File

@ -1,18 +1,10 @@
package com.evotech.hd.webserver.utils.sendCloud;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.AsymmetricAlgorithm;
import cn.hutool.crypto.asymmetric.Sign;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
import com.evotech.hd.webserver.utils.ParamUtils;
import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
/**
@ -25,23 +17,6 @@ import java.util.Base64;
*/
public class RsaEcbPkcsFullUtil {
// 签名算法SHA256哈希 + RSA/ECB/PKCS1Padding
private static final String SIGNATURE_ALGORITHM = "SHA256withRSA/ECB/PKCS1Padding";
// RSA密钥算法
private static final String KEY_ALGORITHM = "RSA";
private static byte[] privateKeyStr = null;
private static PrivateKey privateKey = null;
private static PublicKey publicKey = null;
// static{
// try {
// privateKeyStr = Base64.getDecoder().decode(ParamUtils.findStationSecretKey());
// privateKey = base64ToPrivateKey();
// publicKey = base64ToPublicKey();
// } catch (Exception e) {
// throw new RuntimeException(e);
// }
// }
/**
* 用私钥对消息签名SHA256withRSA/ECB/PKCS1Padding
* @param message 原始消息
@ -52,92 +27,4 @@ public class RsaEcbPkcsFullUtil {
return Base64.getEncoder().encodeToString(sign.sign(message));
}
/***
* 私钥消息加密
* @param message
* @return
* @throws Exception
*/
public static String encrypt(String message) throws Exception {
// e.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(SecureUtil.desede(privateKeyStr).encrypt(message));
}
/**
* 用公钥验证签名SHA256withRSA/ECB/PKCS1Padding
* @param message 解密后的消息
* @param signature 接收的签名Base64编码
* @return 验证是否通过
*/
public static boolean verify(String message, String signature) throws Exception {
Signature verifier = Signature.getInstance(AsymmetricAlgorithm.RSA_ECB_PKCS1.getValue());
verifier.initVerify(publicKey); // 公钥验证模式
verifier.update(message.getBytes("UTF-8"));
byte[] signBytes = Base64.getDecoder().decode(signature);
return verifier.verify(signBytes);
}
/**
* 用私钥解密消息RSA/ECB/PKCS1Padding
* @param encryptedMessage 加密后的消息Base64编码
* @return 解密后的原始消息
*/
public static String decrypt(String encryptedMessage) throws Exception {
Cipher cipher = Cipher.getInstance(AsymmetricAlgorithm.RSA_ECB_PKCS1.getValue());
cipher.init(Cipher.DECRYPT_MODE, privateKey); // 私钥解密模式
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedMessage);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes, "UTF-8");
}
/***
* 私钥消息加密
* @param message
* @return
* @throws Exception
*/
public static String encryptWithPrivateKey(String message) throws Exception {
// Cipher cipher = Cipher.getInstance(AsymmetricAlgorithm.RSA_ECB_PKCS1.getValue());
// cipher.init(Cipher.ENCRYPT_MODE, privateKey); // 私钥加密模式
// // 3. 加密并返回Base64结果
// byte[] encryptedBytes = cipher.doFinal(message.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(SecureUtil.desede(privateKeyStr).encrypt(message));
}
/**
* 用公钥解密私钥加密的数据必须用对应公钥解密
* @param encryptedMessage 加密后的消息Base64
* @return 解密后的原始消息
*/
public static String decryptWithPublicKey(String encryptedMessage) throws Exception {
Cipher cipher = Cipher.getInstance(AsymmetricAlgorithm.RSA_ECB_PKCS1.getValue());
cipher.init(Cipher.DECRYPT_MODE, publicKey); // 公钥解密模式
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedMessage);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes, "UTF-8");
}
/**
* Base64字符串私钥转为PrivateKey对象PKCS#8格式
*/
private static PrivateKey base64ToPrivateKey() throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(ParamUtils.findStationSecretKey());
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); // 私钥用PKCS8规范
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
return keyFactory.generatePrivate(keySpec);
}
/**
* Base64字符串转为PublicKey对象X.509格式
*/
private static PublicKey base64ToPublicKey() throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(ParamUtils.findStationPublicKey());
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); // 公钥用X.509规范
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
return keyFactory.generatePublic(keySpec);
}
}

View File

@ -1,6 +1,6 @@
spring:
redis:
host: 192.168.16.128
host: 192.168.5.112
port: 6379
database: 13
password: hbyt2025
@ -17,7 +17,7 @@ spring:
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
mqtt:
broker: tcp://192.168.16.128:1883 # MQTT服务器地址如Mosquitto默认端口1883
broker: tcp://192.168.5.112:1883 # MQTT服务器地址如Mosquitto默认端口1883
client-id: springboot-mqtt-${random.value} # 客户端ID添加随机数确保唯一
username: admin # 可选MQTT服务器认证用户名
password: hbyt12345 # 可选MQTT服务器认证密码

View File

@ -27,7 +27,7 @@ spring:
initialize-schema: always
job-store-type: jdbc
profiles:
active: ${profiles.active:pro},mongo${profiles.active:},quartz #development
active: ${profiles.active:pro},mongo${profiles.active:},quartz,core #development
# 服务模块
devtools:
restart:
@ -141,6 +141,8 @@ jwt:
accessToken:
expireTime: 1000000
cloudPublicKey:
#
#mqtt:
# broker: tcp://192.168.16.128:1883 # MQTT服务器地址如Mosquitto默认端口1883

View File

@ -4,7 +4,7 @@
<sql id="Base_Column_List">
id, `name`, create_time, extendeds,
strategy,power_strategy, charging_strategy, instant_charge_power, minimum_safety_stock, effective_rgv_no, minimum_safety_stock,lowest_battery_swap_soc,full_of_limit_soc,
strategy,power_strategy, charging_strategy, instant_charge_power, minimum_safety_stock, effective_rgv_no, minimum_safety_stock,lowest_battery_swap_soc,full_of_limit_soc,battery_prefetching,
valid
</sql>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.evotech.hd.webserver.mapper.BasicMapper">
<sql id="Base_Column">
a.id, a.`name`, a.create_time, a.extendeds
</sql>
</mapper>

View File

@ -72,6 +72,14 @@
${ew.customSqlSegment}
</select>
<select id="findList" resultMap="BatteryCompartmentResultMap">
SELECT
<include refid="Base_Column_List"/>
from sc_battery_compartment a
left join sc_battery b on b.battery_compartment_id = a.id and b.storage_Status = 1
${ew.customSqlSegment}
</select>
<select id="getInfo" resultMap="BatteryCompartmentResultMap">
SELECT
<include refid="Base_Column_List"/>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.evotech.hd.webserver.mapper.MessageMqttMapper">
<sql id="Base_Column_List">
a.station_code,a.direction, a.message_id,a.qos,a.type,a.message_function,a.topic,a.content,
<include refid="com.evotech.hd.webserver.mapper.BasicMapper.Base_Column"/>
</sql>
<!-- 通用查询结果列 -->
<select id="findPage" resultType="com.evotech.hd.core.dtos.system.MessageMqttDTO">
SELECT
<include refid="Base_Column_List"/>
from sc_sys_message_mqtt a
${ew.customSqlSegment}
</select>
</mapper>

View File

@ -10,7 +10,8 @@ a.param_code,
a.description,
a.expected_results,
a.verify_result,
a.err_message
a.err_message,
a.effect_battery_swapping
</sql>
<!-- 通用查询结果列 -->