服务器下载emqx
1. Package安装
- 下载包
wget https://www.emqx.com/zh/downloads/broker/4.4.6/emqx-4.4.6-otp24.1.5-3-el8-amd64.rpm
- 安装 EMQX
sudo yum install -y emqx-4.4.6-otp24.1.5-3-el8-amd64.rpm
- 启动 EMQX
sudo emqx start
sudo systemctl start emqx
- 开机自启动
sudo systemctl enable emqx
# 重新加载某个服务的配置文件
sudo systemctl daemon-reload
2. 后台地址
http://服务器IP:18083/
初始账号:admin
初始密码:public
导入包
可以去阿里云仓库查看最新的包
compile 'org.springframework.boot:spring-boot-starter-integration'
compile 'org.springframework.integration:spring-integration-stream'
compile 'org.springframework.integration:spring-integration-mqtt:5.5.9'
application.yml配置
username和password这个用户名和密码是需要在服务器上配置
# /etc/emqx/plugins/emqx_auth_mnesia.conf
# 中间的1代表第一组
auth.user.1.username = admin
auth.user.1.password = public
mqtt:
username: admin
password: public
host-url:
- tcp://服务器IP:1883 # 不同的方式对应不同的端口 tcp对应的是1883
client-id: test # 客户端id,最好唯一
default-topic: /testtopic # 默认监听端口 可以用规则匹配 例如 /testtopic/# 可以监听到 以/testtopic/为前缀的所有端口 举例 /testtopic/1、 /testtopic/test/1等等
completionTimeout: 3000
代码
1. 配置文件:MqttProperties
@Data
@Component
@ConfigurationProperties("mqtt")
public class MqttProperties {
private String username;
private String password;
private String[] hostUrl;
private String clientId;
private String defaultTopic;
private int completionTimeout;
}
2. 监听文件:MqttConfig
包含消息接收和发送
@Configuration
@IntegrationComponentScan
public class MqttConfig {
@Autowired
MqttProperties mqttProperties;
@Autowired
MqttGateway mqttGateway;
private MqttPahoMessageDrivenChannelAdapter adapter;
/**
* 添加topic
*
* @param topic
*/
public void addTopic(String topic) {
adapter.addTopic(topic);
}
/**
* 删除topic
*
* @param topic
*/
public void removeTopic(String topic) {
adapter.removeTopic(topic);
}
@Bean
public MqttConnectOptions getMqttConnectOptions() {
// MQTT的连接设置
MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
// 设置连接的用户名
mqttConnectOptions.setUserName(mqttProperties.getUsername());
// 设置连接的密码
mqttConnectOptions.setPassword(mqttProperties.getPassword().toCharArray());
// 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,
// 把配置里的 cleanSession 设为false,客户端掉线后 服务器端不会清除session,
// 当重连后可以接收之前订阅主题的消息。当客户端上线后会接受到它离线的这段时间的消息
mqttConnectOptions.setCleanSession(true);
// 设置发布端地址
mqttConnectOptions.setServerURIs(mqttProperties.getHostUrl());
// 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
mqttConnectOptions.setKeepAliveInterval(20);
mqttConnectOptions.setAutomaticReconnect(true);
return mqttConnectOptions;
}
@Bean
public MqttPahoClientFactory mqttClientFactory() {
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
factory.setConnectionOptions(getMqttConnectOptions());
return factory;
}
/**
* 接收通道
*
* @return
*/
@Bean
public MessageChannel mqttInputChannel() {
return new DirectChannel();
}
/**
* 配置client,监听的topic
*
* @return
*/
@Bean
public MessageProducer inbound() {
adapter = new MqttPahoMessageDrivenChannelAdapter(mqttProperties.getClientId() + "_inbound", mqttClientFactory(), mqttProperties.getDefaultTopic());
adapter.setCompletionTimeout(mqttProperties.getCompletionTimeout());
adapter.setConverter(new DefaultPahoMessageConverter());
adapter.setQos(1);
adapter.setOutputChannel(mqttInputChannel());
return adapter;
}
/**
* 通过通道获取数据
*/
@Bean
@ServiceActivator(inputChannel = "mqttInputChannel")
@Transactional(rollbackFor = Exception.class)
public MessageHandler handler() {
return message -> {
String topic = Objects.requireNonNull(message.getHeaders().get("mqtt_receivedTopic")).toString();
/**
* 根据监听到的topic规则去处理/存储数据
* 接收到的数据是字符串,最好先转成实体类或Map再处理
*/
};
}
/**
* 通过通道发送数据
*/
@Bean
@ServiceActivator(inputChannel = "mqttOutboundChannel")
public MessageHandler mqttOutbound() {
MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(mqttProperties.getClientId(), mqttClientFactory());
messageHandler.setAsync(true);
messageHandler.setDefaultTopic(mqttProperties.getDefaultTopic());
return messageHandler;
}
/**
* 发送通道
*/
@Bean
public MessageChannel mqttOutboundChannel() {
return new DirectChannel();
}
}
3. 发送消息中间件:MqttGateway
@Component
@MessagingGateway(defaultRequestChannel = "mqttOutboundChannel")
public interface MqttGateway {
void sendToMqtt(String data, @Header(MqttHeaders.TOPIC) String topic);
}
4. 测试:MqttController
@RestController
public class MqttController {
@Autowired
private MqttGateway mqttGateway;
@Resource
private MqttConfig mqttConfig;
/**
* 发送消息
*/
@PostMapping("/send-message")
public String sendMessage(@ApiParam(value = "发送的内容", required = true) @RequestParam String payload, @ApiParam(value = "发送的主题", required = true) @RequestParam String topic) {
mqttGateway.sendToMqtt(payload, topic);
return "发送成功";
}
/**
* 订阅主题
*/
@PostMapping("/add-topic")
public String addTopic(@ApiParam(value = "要订阅的主题", required = true) @RequestParam String topic) throws MqttException {
mqttConfig.addTopic(topic);
return "订阅成功";
}
/**
* 取消订阅topic
*/
@PostMapping("/remove-topic")
public String removeTopic(@ApiParam(value = "要取消订阅的主题", required = true) @RequestParam String topic) throws MqttException {
mqttConfig.removeTopic(topic);
return "取消订阅成功";
}
}