eclipse paho java实现mqtt消息的发送与订阅

博客主要介绍了MQTT的Java代码实现,包含发送端和客户端。发送端可通过线程池循环发送消息测试;客户端先创建连接再发起订阅,订阅多个主题可用通配符。回调类中做了重连处理,重连成功会重新订阅,发送端和客户端的回调类与配置类可共用。

eclipse paho java实现mqtt消息的发送与订阅

1.mqtt定义

mqtt是什么这里就不做解释了,自行百度。这里直接上代码。

2.java代码实现

2.1发送端

发送端工具类:

public class SendMQTT {
	private static Logger logger = LoggerFactory.getLogger(SendMQTT.class);
	  // 配置类,自动读取properties中的配置信息,例如:url,用户民,密码等 
	private static MqttConfig mqttConfig;
	
	static{
		ApplicationContext a = WebApplicationContext.getApplicationContext();
		mqttConfig = WebApplicationContext.getBean(MqttConfig.class);
	}
	// 客户端
	private static MqttClient client;
	private static MqttTopic topic11;

	// 创建链接
	public static void connect(MqttConfig mqttConfig){
		try {
			// MemoryPersistence设置clientid的保存形式,默认为以内存保存
			if(client == null){
				synchronized (MqttClient.class) {
					if(client == null){
							// 建立链接,mqttConfig.getHost()获得服务器地址,mqttConfig.getSendId()获取clientId,客户端唯一标示,new MemoryPersistence()设置clientId的保存形式,默认为以内存保存
							
							client = new MqttClient(mqttConfig.getHost(), mqttConfig.getSendId(), new MemoryPersistence());
							// 设置回调类,后面会有详细说明
							client.setCallback(new PushCallback());
					}
				}
			}
			MqttConnectOptions options = getOption();
			client.connect(options);
			logger.info("成功链接服务器。。。");
			topic11 = client.getTopic(mqttConfig.getSendTopic());
		} catch (MqttException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 推送消息
	 * @param topic
	 * @param message
	 * @throws MqttPersistenceException
	 * @throws MqttException
	 */
	public static void publish(String body)
			throws MqttPersistenceException, MqttException {
		MqttMessage message = new MqttMessage();
		message.setQos(1);// 消息质量
		message.setRetained(true);// 断开链接是否保存消息,true保存
		message.setPayload(body.getBytes());
		MqttDeliveryToken token = topic11.publish(message);
		token.waitForCompletion();
		System.out.println("message is published completely! "
				+ token.isComplete());
	}
	
	// 重连
	public static void reconnect(){
		try {
			client.reconnect();
		} catch (MqttException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private static MqttConnectOptions getOption(){
		MqttConnectOptions options = new MqttConnectOptions();
		options.setCleanSession(false);
		options.setUserName(mqttConfig.getUserName());
		options.setPassword(mqttConfig.getPassWord().toCharArray());
		// 设置超时时间
		options.setConnectionTimeout(10);
		// 设置会话心跳时间
		options.setKeepAliveInterval(20);
		return options;
	}

}

回调函数:

public class PushCallback implements MqttCallbackExtended{
	
	Logger logger = LoggerFactory.getLogger(PushCallback.class);

	@Override
	public void connectionLost(Throwable cause) {
		logger.info("=======================连接断开,进行重连");
		SendMQTT.reconnect();
		
	}
    	  
	@Override
	public void deliveryComplete(IMqttDeliveryToken token) {
      //		logger.info("======================推送成功触发该方法");
		
	}

	@Override
	public void connectComplete(boolean reconnect, String serverURI) {
	//		logger.info("======================链接成功后触发该方法");	   		
		logger.info("断开重连成功");
		
	}
	
	@Override
	public void messageArrived(String topic, MqttMessage message)
			throws Exception {
	  //		logger.info("======================这里是客户端接受消息的地方");	   		
	}
}

测试:

可以写一个线程池循环发送消息进行测试。

 public void testMqtt() {
	 String topic = "topic/gj/respirator_data";
	 mqttConfig.setSendTopic(topic);
	 SendMQTT.connect(mqttConfig);
 	 ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor();
	 Task timerTask = new Task(topic); // 任务需要 2000 ms 才能执行完毕
	 // 延时 1 秒后,按 3 秒的周期执行任务
	 timer.scheduleAtFixedRate(timerTask, 1000, 5000, TimeUnit.MILLISECONDS);
		
}
 

public class Task implements Runnable{
@Override
		public void run() {
			SendMQTT.publish(“消息内容。。。。。。”);
		}
}

2.2客户端

客户端订阅入口:

ClientMQTT .connect(); ,调用完改法会触发回调函数进行订阅,详情看PushCallback.connectComplete()类的实现。

客户端工具类:

public class ClientMQTT {
    	
    	private static Logger logger = LoggerFactory.getLogger(ClientMQTT.class);
    	
    	// 订阅主题
    	private static String[] topic = {"topic/gj/#"};
    	// 消息质量
    	private static int[] Qos  = {1};
    	// 配置类,读取properties文件配置,包括:url,用户名,密码等信息
    	private static MqttConfig mqttConfig;
    	
    	static{
    		ApplicationContext a = WebApplicationContext.getApplicationContext();
    		mqttConfig = WebApplicationContext.getBean(MqttConfig.class);
    	}
    	
    	private static MqttClient client = null;
    	
    	// 连接mqtt服务器
    	public static void connect(){
    	    try {
    	    	if(client == null){
    	    		synchronized (MqttClient.class) {
    	    			if(client == null){
    	    				// host为主机名,clientid即连接MQTT的客户端ID,一般以唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
    				        client = new MqttClient(mqttConfig.getHost(), mqttConfig.getClientId(), new MemoryPersistence());
    				        // 设置回调
    				        client.setCallback(new PushCallback());
    	    			}
    				}
    	    	}
    	    	MqttConnectOptions options = getOption();
    	    	if (!client.isConnected()) {
    	    		client.connect(options);
    	    		logger.info("客户端成功建立连接。。。");
    	    	}else {//这里的逻辑是如果连接成功就重新连接
    	    		client.disconnect();
    	    		client.connect(options);
    	    		logger.info("客户端成功建立连接。。。");
    	    	}
    	        
    	    } catch (Exception e) {
    	        e.printStackTrace();
    	    }
    	    
    	}
    	
    	// 订阅
    	public static void subscribe() {
    		try {
    			client.subscribe(topic, Qos);
    			logger.info("客户端成功订阅。。。");
    		} catch (MqttException e) {
    			e.printStackTrace();
    		}
           
         }
    	
    	// 重新链接
    	public static void reconnect(){
    		try {
    			client.reconnect();
    		} catch (MqttException e) {
    			e.printStackTrace();
    		}
    	}
    	        	      	
    	private static MqttConnectOptions getOption(){
    		// MQTT的连接设置
    		MqttConnectOptions options = new MqttConnectOptions();
            // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
            options.setCleanSession(true);
            options.setUserName(mqttConfig.getUserName());
            options.setPassword(mqttConfig.getPassWord().toCharArray());
            // 设置超时时间 单位为秒
            options.setConnectionTimeout(10);
            // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
            options.setKeepAliveInterval(20);
            //设置断开后重新连接 
            options.setAutomaticReconnect(true);
            return options;
    	}
    }

详细的过程都在注释里说明,大致就是先创建链接,然后发起订阅。我的订阅放在回调方法PushCallback.connectComplete()中调用的,每当连接建立,都会触发该方法。并且回调类中做了重连的处理connectionLost(),如果重连成功,同样会调用connectComplete()方法,重新订阅。
注意,订阅多个主题,则是通过通配符#(表示n层)或+(表示一层)来实现,例如:"topic/#"可以订阅:“topic” ,“topic/data_1”,“topic/data_2”,“topic/secod/data_3”

回调类:

public class PushCallback implements MqttCallbackExtended{
	
	Logger logger = LoggerFactory.getLogger(PushCallback.class);

	@Override
	public void connectionLost(Throwable cause) {
		logger.info("=======================连接断开,进行重连");
		ClientMQTT.reconnect();
		
	}

	@Override
	public void messageArrived(String topic, MqttMessage message)
			throws Exception {
//		logger.info("接收消息主题 : " + topic);
//    	logger.info("接收消息Qos : " + message.getQos());
    	logger.info("接收消息内容 : " + new String(message.getPayload()));
    	Message mess = JsonUtil.fromJson(new String(message.getPayload()), Message.class);
    	logger.info(mess.getDeviceId());
		
	}

	@Override
	public void deliveryComplete(IMqttDeliveryToken token) {
		
		
	}

	@Override
	public void connectComplete(boolean reconnect, String serverURI) {
		ClientMQTT.subscribe();//具体订阅代码
		
	}

}

配置类:

@Configuration
@PropertySource(value={"classpath:mqtt.properties"})
public class MqttConfig {

	@Value("${mqtt.host}")
	private String host;
	
	@Value("${mqtt.userName}")
	private String userName;

	@Value("${mqtt.passWord}")
	private String passWord;
	
	@Value("${mqtt.clientId}")
	private String clientId;

	@Value("${mqtt.receiveTopic}")
	private String receiveTopic;


	@Bean
	public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
		return new PropertySourcesPlaceholderConfigurer();
	}


	public String getHost() {
		return host;
	}


	public void setHost(String host) {
		this.host = host;
	}


	public String getUserName() {
		return userName;
	}


	public void setUserName(String userName) {
		this.userName = userName;
	}


	public String getPassWord() {
		return passWord;
	}


	public void setPassWord(String passWord) {
		this.passWord = passWord;
	}


	public String getClientId() {
		return clientId;
	}


	public void setClientId(String clientId) {
		this.clientId = clientId;
	}


	public String getReceiveTopic() {
		return receiveTopic;
	}


	public void setReceiveTopic(String receiveTopic) {
		this.receiveTopic = receiveTopic;
	}
	
}

其实发送端和客户端的回调类和配置类是可以共用的,我这里是分开写的,起了两个服务来分别作为发送端和客户端。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值