1.导入依赖:
<!-- mqttv3 --> <dependency> <groupId>org.eclipse.paho</groupId> <artifactId>org.eclipse.paho.client.mqttv3</artifactId> <version>1.2.2</version> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> <scope>provided</scope> </dependency>
2. 可以配置mqtt的基本属性(也可以从数据库中取【根据自己的需求来】)
注意:密码要和在EMQX 中设置的一样才能连的上
server: port: 8991 spring: application: name: emq_demo #配置mqtt的基础配置 mqtt: broker_url: tcp://127.0.0.1:1883 client_id: admin username: admin password: admin
3.建一个实体类:来调用mqtt的基本配置
package com.zeng.emp_demo.entity; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration @ConfigurationProperties(prefix = "mqtt") @Data public class MqttEntity { /** * IP * */ private String broker_url; /** * client_id * */ private String client_id; /** * 用户名 * */ private String username; /** * 密码 * */ private String password; }
4.下面的代码就是:Mqtt的连接,重连,发布,订阅等方法
package com.zeng.emp_demo.controller.mqttv3; import com.zeng.emp_demo.controller.enums.QosEnum; import com.zeng.emp_demo.controller.mqtt.ConnectEmp; import com.zeng.emp_demo.entity.MqttEntity; import org.eclipse.paho.client.mqttv3.*; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.annotation.Resource; /** * @author曾文斌 */ @Component public class EmqClient { //日志 private static final Logger log= LoggerFactory.getLogger(ConnectEmp.class); private IMqttClient mqttClient; @Resource private MqttEntity mqttEntity; @Resource private MqttCallback mqttCallback; //初始化 @PostConstruct public void init(){ try { //持久化内存 MqttClientPersistence clientPersistence=new MemoryPersistence(); mqttClient=new MqttClient(mqttEntity.getBroker_url(),mqttEntity.getClient_id(),clientPersistence); } catch (MqttException e) { log.error("MQTT初始化异常Broker_url={},Client_id={},"+e.getMessage(),mqttEntity.getBroker_url(),mqttEntity.getClient_id()); } } /** * 连接brober服务端 * @param Password * @param Username * */ public void connect(String Username,String Password){ /** * Mqtt的连接设置 * */ MqttConnectOptions mqttConnectOptions=new MqttConnectOptions(); //客户端重新连接服务端 mqttConnectOptions.setAutomaticReconnect(true); //用户名 mqttConnectOptions.setUserName(Username); //密码 mqttConnectOptions.setPassword(Password.toCharArray()); //客户端和服务端的回话连接时间 //todo 如果CleanSession为false:表示持久的会话(客户端断开了,服务端还会继续发送主题等消息,直到Session超时) //todo 如果CleanSession为true,表示是临时会话(客户端断开,服务器也会断开) mqttConnectOptions.setCleanSession(true); //连接的超时时间 mqttConnectOptions.setConnectionTimeout(30000); //方法的回掉 //todo Callback是执行业务的重要方法 mqttClient.setCallback(mqttCallback); try { //连接 mqttClient.connect(mqttConnectOptions); } catch (MqttException e) { log.error("Mqtt连接失败,失败原因={}"+e.getMessage()); } } /** * 断开brober服务端失败 * */ @PreDestroy //在对象消亡之前执行 public void disconnect(){ try { //断了 mqttClient.disconnect(); } catch (MqttException e) { log.error("断开MQTT客户端失败,失败原因={}"+e.getMessage()); } } /** *重连的方法 * */ public void reConnect() { try { //重连 mqttClient.reconnect(); } catch (MqttException e) { log.error("MQTT客户端重连失败,失败原因={}",e.getMessage()); } } /** * 发布消息 * @param msg 消息 * @param qos 服务质量 * @param retain 保留 * @param topic 主题 * */ public void publish(String topic, String msg, QosEnum qos,boolean retain){ MqttMessage mqttMessage=new MqttMessage(); //负载 mqttMessage.setPayload(msg.getBytes()); //调动 mqttMessage.setQos(qos.value()); //存储 mqttMessage.setRetained(retain); try { //发布 mqttClient.publish(topic,mqttMessage); } catch (MqttException e) { log.error("MQTT发布失败,失败原因={},topic={},msg={},qos={},retain={}"+e.getMessage(),topic,mqttMessage,msg.getBytes(),qos.value(),retain); } } /** * 订阅消息 * @param qos * @param topicFilter * */ public void subscribe(String topicFilter,QosEnum qos){ try { //消息订阅 mqttClient.subscribe(topicFilter,qos.value); } catch (MqttException e) { log.error("MQTT订阅消息失败,失败原因={},topicFilter={},qos={}"+e.getMessage(),topicFilter,qos.value); } } /** * * 取消订阅 * @param topicFilter * */ public void unsubscribe(String topicFilter) { try { //取消订阅 mqttClient.unsubscribe(topicFilter); } catch (MqttException e) { log.error("MQTT取消订阅失败,失败原因={},topicFilter={}",e.getMessage(),topicFilter); } } }
MqttClientPersistence clientPersistence=new MemoryPersistence(); //表示持久化内存
MemoryPersistence:是将数据储存在硬盘上的 (如上图)
MqttDefaultFilePersistence:是将数据存储在文件中的(如上图)
MqttConnectOptions mqttConnectOptions=new MqttConnectOptions(); //MQTT的连接对象
mqttConnectOptions.setCleanSession(true);//如果是true表示(表示1):领时会话
mqttConnectOptions.setCleanSession(false);//如果是false表示(表示0):持久会话
MqttCallback mqttCallback; //是业务逻辑执行的关键(消息回调)
5.消息回调(接口是MqttCallback)
package com.zeng.emp_demo.controller.mqttv3; import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; import org.eclipse.paho.client.mqttv3.MqttCallback; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; /** * @author曾文斌 * 消息的回调 * */ @Component public class MessageCallback implements MqttCallback { private final Logger log= LoggerFactory.getLogger(MessageCallback.class); /** * 连接中断 * @param throwable * */ @Override public void connectionLost(Throwable throwable) { //可以调用重连的方法 log.info("连接中断========"+throwable); } /** * 订阅到消息后的回调 * 该方法由mqtt客户端同步调用(非异步调用),在此方法未正确返回之前,不会发送ack确认消息到broker * 一旦该方法向外抛出了异常客户端将异常关闭,当再次连接时,所以QoS1,QoS2且客户端未进行ack确认的消息都将由:brober服务器再次发送到客户端 * @param topic * @param mqttMessage * */ @Override public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception { log.info("订阅到了消息&&&&&&&&&&:topic={},getQos={},getId={},Payload={}"+ topic, mqttMessage.getQos(), mqttMessage.getId(), new String(mqttMessage.getPayload())); } /** * 消息发布完成且收到ack确认的回调 * QOs0:消息被网络发出后触发一次 * Qos1:当收到broker的PUBACK消息后触发 * QoS2:当收到broerd的 PUCOMP消息后触发 * @param iMqttDeliveryToken * */ @Override public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { int messageId=iMqttDeliveryToken.getMessageId();//消息ID String[] topics = iMqttDeliveryToken.getTopics();//主题 log.info("消息发布完成》》》》》》messageId={},topics={}"+messageId,topics); } }
测试:
package com.zeng.emp_demo; import com.zeng.emp_demo.controller.enums.QosEnum; import com.zeng.emp_demo.controller.mqttv3.EmqClient; import com.zeng.emp_demo.entity.MqttEntity; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.concurrent.TimeUnit; @SpringBootApplication public class EmpDemoApplication { @Resource private EmqClient emqClient; @Resource private MqttEntity mqttEntity; public static void main(String[] args) { SpringApplication.run(EmpDemoApplication.class, args); } /** * 测试 * */ @PostConstruct public void init(){ //连接服务器 emqClient.connect(mqttEntity.getUsername(),mqttEntity.getPassword()); //订阅一个主题 emqClient.subscribe("testtopic/#", QosEnum.Qos2); //开启一个新的线程,每隔5秒向testtopic/#(主题)发送消息 new Thread(()->{ while (true){ emqClient.publish("testtopic/123","曾文斌好帅"+ LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME) ,QosEnum.Qos2,false); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { throw new RuntimeException(e); } } }).start(); } }