订单服务发送指令到充电桩
public class MqttConstants{
/*
订单给设备发送 开始充电 指令的topic前缀
*/
public static final String TOPIC_START_GHARGING_PREFIX = "/topic/start/";
/*
订单给设备发送 开始充电 指令的topic前缀
*/
public static final String TOPIC_CHARGING_RESULT="/topic/charging/result";
}
OrderServiceImpl
startChargin()
定义Topic
开始充电指令是发送的充电桩上的,topic应该包含桩的信息
Topic 设计 有两种 维度
枪维度 一个枪 一个Topic
MqttConstant.TOPIC_START_CHARGING_PREFIX+pileId+gunId
桩维度 消息体包含枪信息 桩上有可能不止一个枪,一个桩一个topic
MqttConstant.TOPIC_START_CHARGING_PREFIX + pileId
Topic包含枪的信息也可以,但是会导致topic的数量相对 桩的维度 过多
占用更多的资源
MqttConstant.TOPIC_START_CHARGING_PREFIX + pileId
定义消息体ChargingDto
订单服务和设备之间的传输数据对象
订单服务 开始充电 指令 的 目的是 告诉设备 请你 用哪个设备(枪id搞定) 帮它(订单号搞定)开始充电
@Data
@FieldDefaults(level=AccessLevel.PRIVATE)
public class ChargingDto{
//订单号
String orderNo;
//桩id
Integer pileId;
//枪id
Integer gunId;
/*
指令
1 开始充电
2 结束充电
*/
String msg;
}
消息体的序列化
把ChargingDto转换为JSON
消息体的序列化Spring-boot自动做的序列化 对象转json ,json转对象
需要我们手动序列化 不能toString 应该把 对象转换为JSON
需要一个JSON库JackSon Gson FastJson
Spring-boot怎么干的 ? 默认使用JackSon实现
在charging-common 项目中定义JsonUtils
JsonUtils工具类把业务和json转换工具具体实现隔离 解耦
加依赖
在父项目和子项目charging-common分别增加依赖
父项目
<properties>
<jackson-version>2.13.1</jackson-version>
</properties>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-version}</version>
</dependency>
子项目 charging-common
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
JsonUtils
/*
Json工具类
对象转换为Json
Json转对象
*/
public class JsonUtils{
/*
定义对象转换工具类 SpringBoot默认 jackson ObjectMapper
static 表示静态 jvm在加载的时候 会创建 还能保证只创建一个
*/
private static ObejectMapper mapper = new ObjectMapper();
/*java对象转换为json*/
public static String toJson(Object object){
//没有必要每次调用toJson都创建 ObjectMapper
//占用jvm的内存空间,可以搞成单例
//ObjectMapper mapper = new ObjectMapper();
try{
return mapper.writeValueAsString(object);
}catch(JsonProcessingException e){
throw new RuntimeException(e);
}
}
}
发送消息到EMQX
修改 OrderServiceImpl
注入mqttProducer通过mqttProducer发送消息到emqx
具体实现OrderServiceImpl startCharging()
@Autowired
private MqttProducer mqttProducer;
/*发送开始充电指令*/
private void startCharging(String orderNo,Integer pileId,Integer gunId){
//Topic设计
//一种是枪的维度 或者 一种是桩的维度 消息体包含枪的信息
//从业务上将都可以 ,如果是枪的维度 topic 的数量会比 桩的维度 的数量多
///占用 更多的资源
String topic = MqttConstants.TOPIC_START_CHARGING_PREFIX + pileId;
//消息设计
//类似于接口的入参,思考业务如果缺少哪个入参,业务无法完成,这些入参是就是核心参数
//首先得明确业务目标 给设备发送开始充电指令给一个用户的订单开始充电,
//参数应该包含 订单信息的唯一标识 订单id ,设备信息 ,告诉具体哪个设备开始充电
ChargingDto chargingDto = new ChargingDto();
chargingDto.setOrderNo(orderNo);
chargingDto.setPileId(pileId);
chargingDto.setGunId(gunId);
chargingDto.setMsg(ChargingConstants.START_CHARGING);
log.debug("订单服务发送开始充电指令到设备:{},消息:{}",topic,chargingDto);
//String string = chargingDto.toString();
//消息体的序列化 Spring-boot自动做的序列化 对象转json ,json转对象
//需要我们手动序列化,不能toString ,应该把 对象转换为JSON
//需要一个库Jackson(Spring默认的)Gson Spring-boot怎么干的?
String json = JsonUtils.toJson(chargingDto);
Boolean success = mqttProducer.publish(topic,json);
log.debug("订单服务发送开始充电指令到设备:{},消息:{},结果:{}",topic,chargingDto,success);
///如果发送,重试几次,如果实在不行通知用户,记录日志,接入告警系统
}
结果验证
发送消息
启动订单服务,调用创建订单接口
订单服务发送开始充电消息到设备
接口入参
{
"gunId": 1,
"pileId": 666,
"userId": 1
}
设备接收消息
启动mqttfx 模拟设备软件
Mqfftx 启动后,先点击 connect 连接 emqx 消息中间件 地址:端口 127.0.0.1:1883
点击 Subscribe (订阅) 输入 正确的topic
/topic/start/666
topic = 前缀 + 桩id
{
"orderNo":"666","pileId":666,"gunId":1,"msg":"start_charging"}