mqtt的服务端与客户端的角色是可以互相转换的,因为两者都能同时发送和接收消息。
一、创建mqtt服务
首先需要让mqtt的服务随项目启动,在webapp/WEB-INF/web.xml文件中添加以下内容。
<listener> <listener-class>com.ux.receive.impl.MqttListener</listener-class> </listener>
MqttListener类会在项目启动后自动创建与mqtt服务器的连接,监听订阅主题的消息。
其中的MqttThread类实现了线程的抽象方法,用来创建新的线程进行消息交互。
package com.ux.receive.impl;
import com.ux.receive.dao.BoxDectdata4DAO;
import com.ux.receive.utils.Comm;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttTopic;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MqttListener implements ServletContextListener {
protected final static Logger logger = LoggerFactory.getLogger(MqttListener.class);
private MqttThread mqttThread;
private String mqtt_app_ip;
private String mqtt_app_port;
private String mqtt_topic_sev;
private String mqtt_topic_client;
private String estr="Mqtt服务";
private MqttClient client;
private MqttConnectOptions options;
private String userName = "mqtt"; //非必须
private String passWord = "mqtt"; //非必须
@Override
public void contextInitialized(ServletContextEvent sce) {
WebApplicationContext context= WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
if(mqttThread==null){
mqttThread=new MqttThread();
mqttThread.start();
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
if(mqttThread!=null && mqttThread.isInterrupted()){
mqttThread.interrupt();
}
}
class MqttThread extends Thread{
public void run(){
String estr = "Mqtt服务端===:";
// 创建服务
try {
mqtt_app_ip = Comm.xmlReadConfig("sysconfig,mqtt_app_ip");
logger.debug(estr + "获取服务端IP:" + mqtt_app_ip);
mqtt_app_port = Comm.xmlReadConfig("sysconfig,mqtt_app_port");
logger.debug(estr + "获取服务端端口:" + mqtt_app_port);
mqtt_topic_sev = Comm.xmlReadConfig("sysconfig,mqtt_topic_sev");
logger.debug(estr + "获取发布主题:" + mqtt_topic_sev);
mqtt_topic_client = Comm.xmlReadConfig("sysconfig,mqtt_topic_client");
logger.debug(estr + "获取订阅主题:" + mqtt_topic_client);
Thread.sleep(2000);
// host为主机名,clientid即连接MQTT的客户端ID,一般以唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
String clientid=String.valueOf(System.currentTimeMillis());
client = new MqttClient(mqtt_app_ip, clientid, new MemoryPersistence());
// MQTT的连接设置
options = new MqttConnectOptions();
// 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,设置为true表示每次连接到服务器都以新的身份连接
options.setCleanSession(false);
// 设置连接的用户名
options.setUserName(userName);
// 设置连接的密码
options.setPassword(passWord.toCharArray());
// 设置超时时间 单位为秒
options.setConnectionTimeout(10);
// 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
options.setKeepAliveInterval(20);
//设置断开后重新连接
options.setAutomaticReconnect(true);
// 设置回调
client.setCallback(new MqttPushCallback(client,options,boxDectdata4DAO));
MqttTopic topic = client.getTopic(mqtt_topic_client);//获取主题
//setWill方法,如果项目中需要知道客户端是否掉线可以调用该方法。设置最终端口的通知消息
//遗嘱
options.setWill(topic,"close".getBytes(), 1, true);
client.connect(options);
//订阅消息
int[] Qos = {1};//0:最多一次 、1:最少一次 、2:只有一次
String[] topic1 = {mqtt_topic_client};
client.subscribe(topic1, Qos);//订阅主题
} catch (Exception e) {
logger.error(estr + e.getMessage());
e.printStackTrace();
return;
}
System.out.println(estr+"监听中:"+System.currentTimeMillis());
}
}
}