智能设备上下线案例
需求
1、智能设备上线以后向MQTT服务端发送消息,后端服务从MQTT中获取消息记录设备信息到数据库中
2、后端服务向MQTT服务端发送开启或者关闭消息,设备端从MQTT中获取消息控制设备的开和关
数据库表
- 自行创建库:
iot_demo
- 创建表
-- 智能设备表
CREATE TABLE `tb_device` (
`id` bigint NOT NULL AUTO_INCREMENT,
`device_id` varchar(50) DEFAULT NULL,
`status` int DEFAULT NULL COMMENT '1:上线 0:下线',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB ;
引入数据库依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>
项目配置
- 增加数据相关配置信息
- 修改订阅主题为通配模式:
lq/iot/demo/
=>lq/iot/demo/#
spring:
mqtt:
# mqtt 服务器地址
url: tcp://192.168.40.128:1883
# 订阅客户端ID
subClientId: sub_client_id_1
# 订阅主题
# subTopic: lq/iot/demo/
subTopic: lq/iot/demo/#
# 发布客户端ID
pubClientId: pub_client_id_1
# 用户名
username: admin
# 密码
password: admin123456
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3307/iot_demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
mapper-locations: classpath*:mapper/*Mapper.xml
代码
- 设备实体类
DeviceEntity.java
package com.study.mqtt.demo.entitiy;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
@TableName("tb_device")
@Data
public class DeviceEntity {
private Integer id;
private String deviceId;
private Integer status;
private Date createTime;
private Date updateTime;
}
- 设备实体Mapper类
DeviceMapper.java
package com.study.mqtt.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.study.mqtt.demo.entitiy.DeviceEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DeviceMapper extends BaseMapper<DeviceEntity> {
}
- 启动类开启mapper扫描
MqttDemoApplication.java
package com.study.mqtt.demo;
import com.study.mqtt.demo.domain.MqttConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@EnableConfigurationProperties(value = MqttConfig.class)
@MapperScan("com.study.mqtt.demo.mapper")
public class MqttDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MqttDemoApplication.class, args);
}
}
- 设备服务类
DeviceService.java
package com.study.mqtt.demo.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.study.mqtt.demo.entitiy.DeviceEntity;
import org.springframework.stereotype.Service;
@Service
public interface DeviceService extends IService<DeviceEntity> {
void updateDeviceOnlineStatus(String jsonInfo);
}
- 设备服务实现类
DeviceServiceImpl.java
package com.study.mqtt.demo.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.study.mqtt.demo.entitiy.DeviceEntity;
import com.study.mqtt.demo.mapper.DeviceMapper;
import com.study.mqtt.demo.service.DeviceService;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.Map;
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, DeviceEntity> implements DeviceService {
@Override
public void updateDeviceOnlineStatus(String jsonInfo) {
// 解析消息获取设备id和上线状态
Map<String , Object> map = JSON.parseObject(jsonInfo, Map.class);
String deviceId = map.get("deviceId").toString();
Integer status = Integer.parseInt(map.get("online").toString());
// 根据设备的id查询设备数据
LambdaQueryWrapper<DeviceEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>() ;
lambdaQueryWrapper.eq(DeviceEntity::getDeviceId , deviceId) ;
DeviceEntity deviceEntity = this.getOne(lambdaQueryWrapper);
if(deviceEntity == null) {
// 设备不存在,新增设备
deviceEntity = new DeviceEntity() ;
deviceEntity.setDeviceId(deviceId);
}
deviceEntity.setStatus(status);
deviceEntity.setUpdateTime(new Date());
this.saveOrUpdate(deviceEntity);
}
}
- 消息接收类
- 增加 设备上下线主题的消息接收
lq/iot/demo/device/online
- 更新 设备表中对应的记录状态
tb_device
- 增加 设备上下线主题的消息接收
ReceiveMsgHandler.java
package com.study.mqtt.demo.handler;
import com.study.mqtt.demo.service.DeviceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.MessagingException;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class ReceiveMsgHandler implements MessageHandler {
@Autowired
private DeviceService deviceService;
@Override
public void handleMessage(Message<?> message) throws MessagingException {
System.out.println("当前时间:" + new Date());
System.out.println("接收到消息对象:" + message);
// 消息内容
Object payload = message.getPayload();
MessageHeaders headers = message.getHeaders();
Object mqttReceivedTopic = headers.get("mqtt_receivedTopic");
System.out.println("接收的消息主题:" + mqttReceivedTopic);
System.out.println("接收的消息内容:" + payload);
if("lq/iot/demo/device/online".equals(mqttReceivedTopic)) {
// 更新设备的上线状态
deviceService.updateDeviceOnlineStatus(message.getPayload().toString());
}
}
}
测试
- 启动项目
- 发布者发布消息
- 利用 发布者模拟设备上线
- 发布主题
lq/iot/demo/device/online
- 消息内容
{ "deviceId": "device-xxx-1", "online": 0 }
- 后台服务接收到消息
- 设备信息入库
- 更新设备状态
- 利用 发布者模拟设备
- 发布主题
lq/iot/demo/device/online
- 消息内容
{ "deviceId": "device-xxx-1", "online": 1 }
- 后台服务接收到消息
- 接收到的时间:
Mon May 26 12:50:21 GMT+08:00 2025
- 接收到的时间:
- 设备状态更新入库
- 记录更新时间:
2025-05-26 12:50:22
- 记录更新时间: