本文章使用 spring boot3、 java21、maven工程
1、引入mqtt依赖
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mqtt</artifactId>
<version>5.5.10</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.4.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、yml配置
server:
port: 31001
servlet:
context-path: /dataCapture
spring:
mqtt:
url: tcp://192.168.1.60:1883
username: admin
password: public
client:
id: myProvider
default:
datasource:
jsdb:
driver-class-name: com.taosdata.jdbc.TSDBDriver
url: jdbc:TAOS://192.168.1.60:6030/data_capture?charset=utf8
username: root
password: taosdata
kbdb:
driver-class-name: com.taosdata.jdbc.TSDBDriver
url: jdbc:TAOS://192.168.1.60:6030/data_capture_kb?charset=utf8
username: root
password: taosdata
type: com.alibaba.druid.pool.DruidDataSource
druid:
initial-size: 2
max-active: 30
min-idle: 2
max-wait: 5000
pool-prepared-statements: true
validation-query: select 1
validation-query-timeout: 1
test-on-borrow: false
test-on-return: true
test-while-idle: true
time-between-eviction-runs-millis: 10000
min-evictable-idle-time-millis: 30001
filters: stat
data:
redis:
host: xxx.xxx.xxx.xxx
port: 6379
database: 0
jedis:
pool:
max-active: 1000
max-wait: -1ms
max-idle: 10
min-idle: 5
mybatis-plus:
type-aliases-package: com.hiabr.web
mapper-locations: classpath:mapper/**/*Mapper.xml
configuration:
default-statement-timeout: 120
map-underscore-to-camel-case: true
cache-enabled: false
call-setters-on-nulls: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
logging:
config: classpath:logback-dev.xml
3、redis配置
import com.hiabr.web.utils.ObjectRedisSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.io.Serializable;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<Serializable, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Serializable, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
template.afterPropertiesSet();
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new ObjectRedisSerializer());
return template;
}
}
4、mqtt核心配置 通过通配符订阅消息 /+单层匹配 /#多层匹配 参考官网 MQTT 主题与通配符(Topics & Wildcards)入门手册 | EMQ
win部署mqtt服务:Windows 本地部署 MQTT服务_windows安装mqtt-CSDN博客
docker部署mqtt服务:docker 部署 MQTT_docker mqtt-CSDN博客
不同channel 可以通过不同的服务类通过自定义注解实现数据存储到不同数据库,多数据源参考文章:spring boot 集成mqtt,动态数据源,时序数据库TDengine (一)-CSDN博客
import com.hiabr.web.service.mqtt.JinShanMessageService;
import com.hiabr.web.service.mqtt.KaiBangMessageService;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.endpoint.MessageProducerSupport;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import java.util.UUID;
/**
* @description:
* @author: hanwei
* @date: 2025/5/8
*/
@Configuration
@EnableIntegration
public class MqttIntegrationConfig {
@Value("${spring.mqtt.username}")
private String username;
@Value("${spring.mqtt.password}")
private String password;
@Value("${spring.mqtt.url}")
private String hostUrl;
@Autowired
private JinShanMessageService jinShanMessageService;
@Autowired
private KaiBangMessageService kaiBangMessageService;
/** ============================================================ */
@Bean
public MqttConnectOptions mqttConnectOptions() {
MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
// mqtt服务ip:端口
mqttConnectOptions.setServerURIs(new String[]{hostUrl});
// Mqtt服务账号
mqttConnectOptions.setUserName(username);
// Mqtt服务密码
mqttConnectOptions.setPassword(password.toCharArray());
// 设置是否清除会话。如果设置为false,表示服务器会保留客户端的连接记录;设置为true表示每次连接到服务器都以新的身份连接
mqttConnectOptions.setCleanSession(true);
// 设置是否自动重连
mqttConnectOptions.setAutomaticReconnect(true);
// 设置连接超时时间,单位为秒
mqttConnectOptions.setConnectionTimeout(100);
// 设置心跳间隔,单位为秒
mqttConnectOptions.setKeepAliveInterval(30);
return mqttConnectOptions;
}
@Bean
public MessageChannel jinShanChannel() {
return new DirectChannel();
}
@Bean
public MessageChannel kaiBangChannel() {
return new DirectChannel();
}
@Bean
public MqttPahoClientFactory mqttPahoClientFactory(MqttConnectOptions mqttConnectOptions) {
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
factory.setConnectionOptions(mqttConnectOptions);
return factory;
}
// 单层匹配
@Bean
public MessageProducerSupport jinShanAdapter(MqttPahoClientFactory mqttPahoClientFactory) {
String[] topics = new String[]{"SBOX/4d5b1a02d36a/+/device/data/push","SBOX/e3379cb4a610/+/device/data/push"};
MqttPahoMessageDrivenChannelAdapter adapter =
new MqttPahoMessageDrivenChannelAdapter(UUID.randomUUID().toString(),
mqttPahoClientFactory,
topics);
adapter.setOutputChannelName("jinShanChannel");
return adapter;
}
// 多层级匹配
@Bean
public MessageProducerSupport kaiBangAdapter(MqttPahoClientFactory mqttPahoClientFactory) {
MqttPahoMessageDrivenChannelAdapter adapter =
new MqttPahoMessageDrivenChannelAdapter(UUID.randomUUID().toString(),
mqttPahoClientFactory,
"SBOX/#");
adapter.setOutputChannelName("kaiBangChannel");
return adapter;
}
@ServiceActivator(inputChannel = "jinShanChannel")
public void handleJinShanData(Message<String> message) {
jinShanMessageService.handleMessage(message);
}
@ServiceActivator(inputChannel = "kaiBangChannel")
public void handleKaiBang(Message<String> message) {
kaiBangMessageService.handleMessage(message);
}
}
7、处理消息服务
import com.alibaba.fastjson.JSONObject;
import com.hiabr.web.annaotation.TargetDataSource;
import com.hiabr.web.dto.MqttMessageDTO;
import com.hiabr.web.enums.DataSourceKey;
import com.hiabr.web.service.DeviceStatusService;
import com.hiabr.web.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.stereotype.Service;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
/**
* @description:
* @author: hanwei
* @date: 2025/5/8
*/
@Slf4j
@Service("jinShanMessageService")
public class JinShanMessageService implements MessageHandler {
@Autowired
private RedisUtil redisUtil;
@Autowired
private DeviceStatusService deviceStatusService;
@Override
public void handleMessage(Message<?> message) {
// 处理message
String payload = message.getPayload().toString();
JSONObject jsonObject = JSONObject.parseObject(payload);
String topic = message.getHeaders().get("mqtt_receivedTopic", String.class);
log.info("主题:{}",topic);
log.info("消息内容:{}",jsonObject.toJSONString());
}
}