├── README.md ├── pom.xml └── src └── main ├── java └── com │ └── gaoyf │ └── mqtt │ ├── SpringbootMqttApplication.java │ ├── controller │ └── DemoRestController.java │ └── core │ ├── IMQTTPublisher.java │ ├── IMQTTSubscriber.java │ ├── MQTTConfig.java │ ├── MQTTPublisher.java │ └── MQTTSubscriber.java └── resources └── application.properties /README.md: -------------------------------------------------------------------------------- 1 | ## 结构 2 | 3 | Server side 构成 4 | 5 | - broker (mqtt核心:用于消息的发送管理) 6 | - Application Server用于处理RestFul的请求,转发为Mqtt消息 7 | - Publisher **本质是Mqtt client**用于发布server端消息 8 | - Subscriber **本质是Mqtt client**用于订阅client端消息,并显示 9 | - Client side 10 | - Publisher用于发布client端消息 11 | - Subscriber用于订阅server端的消息 12 | - Client 用于发送RestFul 请求给Application Server触发消息pub/sub 13 | 14 | **总结**:从结构上Broker算是Mqtt的本质上的Server端,从业务上讲封装了Mqtt Client pub/sub的Application server和Broker共同构成了业务上的Server端 15 | 16 | ### 构建springboot项目 17 | 18 | #### 1. 使用idea springboot initializer 初始化springboot工程 19 | 20 | 使用springboot版本**2.1.5.RELEASE** 21 | 22 | #### 2. pom中添加 23 | 24 | ```xml 25 | 26 | 27 | org.springframework.integration 28 | spring-integration-stream 29 | 30 | 31 | org.springframework.integration 32 | spring-integration-mqtt 33 | 34 | 35 | ``` 36 | 37 | #### 3. MQTT Configuration 38 | 39 | * 配置broker地址, 40 | * 端口号, 41 | * 是否使用ssl, 42 | * 用户名 43 | * 密码 44 | 45 | ~~~java 46 | public abstract class MQTTConfig { 47 | 48 | protected String ip = "127.0.0.1"; 49 | 50 | /** 51 | * qos0 对于client而言,有且仅发一次publish包,对于broker而言,有且仅发一次publish,简而言之,就是仅发一次包,是否收到完全不管,适合那些不是很重要的数据。 52 | * qos1 这个交互就是多了一次ack的作用,但是会有个问题,尽管我们可以通过确认来保证一定收到客户端或服务器的message,但是我们却不能保证message仅有一次, 53 | * 也就是当client没收到service的puback或者service没有收到client的puback,那么就会一直发送publisher 54 | * qos2可以实现仅仅接受一次message,其主要原理(对于publisher而言), 55 | * publisher和broker进行了缓存,其中publisher缓存了message和msgID,而broker缓存了msgID,两方都做记录所以可以保证消息不重复, 56 | * 但是由于记录是需要删除的,这个删除流程同样多了一倍 57 | */ 58 | protected int qos = 2; 59 | 60 | protected Boolean hasSSL = false; //默认SSL关闭 61 | 62 | protected Integer port = 1883; //默认端口 63 | 64 | protected String username = "账号"; 65 | 66 | protected String password = "密码"; 67 | 68 | protected String TCP = "tcp://"; 69 | 70 | protected String SSL = "ssl://"; 71 | 72 | 73 | /** 74 | * Custom Configuration 75 | */ 76 | protected abstract void config(String ip, Integer port, Boolean ssl, Boolean withUserNamePass); 77 | 78 | /** 79 | * Default Configuration 80 | */ 81 | protected abstract void config(); 82 | 83 | 84 | public String getIp() { 85 | return ip; 86 | } 87 | 88 | public void setIp(String ip) { 89 | this.ip = ip; 90 | } 91 | 92 | public int getQos() { 93 | return qos; 94 | } 95 | 96 | public void setQos(int qos) { 97 | this.qos = qos; 98 | } 99 | 100 | public Boolean getHasSSL() { 101 | return hasSSL; 102 | } 103 | 104 | public void setHasSSL(Boolean hasSSL) { 105 | this.hasSSL = hasSSL; 106 | } 107 | 108 | public Integer getPort() { 109 | return port; 110 | } 111 | 112 | public void setPort(Integer port) { 113 | this.port = port; 114 | } 115 | 116 | public String getUsername() { 117 | return username; 118 | } 119 | 120 | public void setUsername(String username) { 121 | this.username = username; 122 | } 123 | 124 | public String getPassword() { 125 | return password; 126 | } 127 | 128 | public void setPassword(String password) { 129 | this.password = password; 130 | } 131 | 132 | public String getTCP() { 133 | return TCP; 134 | } 135 | 136 | public void setTCP(String TCP) { 137 | this.TCP = TCP; 138 | } 139 | 140 | public String getSSL() { 141 | return SSL; 142 | } 143 | 144 | public void setSSL(String SSL) { 145 | this.SSL = SSL; 146 | } 147 | } 148 | 149 | ~~~ 150 | 151 | 152 | 153 | #### 4. Publisher推送者 154 | 155 | 定义接口 156 | 157 | ```java 158 | public interface IMQTTPublisher { 159 | /** 160 | * 发布消息 161 | * 162 | * @param topic 主题 163 | * @param message 消息 164 | */ 165 | public void publishMessage(String topic, String message); 166 | 167 | /** 168 | * 断开MQTT客户端 169 | */ 170 | public void disconnect(); 171 | } 172 | 173 | 174 | ``` 175 | 176 | 定义类 177 | 178 | ```java 179 | import org.eclipse.paho.client.mqttv3.*; 180 | import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; 181 | import org.slf4j.Logger; 182 | import org.slf4j.LoggerFactory; 183 | import org.springframework.stereotype.Component; 184 | 185 | /** 186 | * @author gaoyf 187 | * @since 2020/4/9 0009 16:02 188 | */ 189 | @Component 190 | public class MQTTPublisher extends MQTTConfig implements MqttCallback, IMQTTPublisher { 191 | 192 | private String ipUrl = null; 193 | 194 | final private String colon = ":";//冒号分隔符 195 | final private String clientId = "mqtt_server_pub";//客户端ID 这里可以随便定义 196 | 197 | private MqttClient mqttClient = null; 198 | private MqttConnectOptions connectionOptions = null; 199 | private MemoryPersistence persistence = null; 200 | 201 | private static final Logger logger = LoggerFactory.getLogger(MQTTPublisher.class); 202 | 203 | /** 204 | * Private default constructor 205 | */ 206 | private MQTTPublisher() { 207 | this.config(); 208 | } 209 | 210 | /** 211 | * Private constructor 212 | */ 213 | private MQTTPublisher(String ip, Integer port, Boolean ssl, Boolean withUserNamePass) { 214 | this.config(ip, port, ssl, withUserNamePass); 215 | } 216 | 217 | /** 218 | * Factory method to get instance of MQTTPublisher 219 | * 220 | * @return MQTTPublisher 221 | */ 222 | public static MQTTPublisher getInstance() { 223 | return new MQTTPublisher(); 224 | } 225 | 226 | /** 227 | * 获取MQTTPublisher实例的工厂方法 228 | * 229 | * @param ip ip地址 230 | * @param port 断开 231 | * @param ssl 是否ssl 232 | * @param withUserNamePass 用户名密码 233 | * @return MQTTPublisher 234 | */ 235 | public static MQTTPublisher getInstance(String ip, Integer port, Boolean ssl, Boolean withUserNamePass) { 236 | return new MQTTPublisher(ip, port, ssl, withUserNamePass); 237 | } 238 | 239 | 240 | protected void config() { 241 | 242 | this.ipUrl = this.TCP + this.ip + colon + this.port; 243 | this.persistence = new MemoryPersistence(); 244 | this.connectionOptions = new MqttConnectOptions(); 245 | try { 246 | this.mqttClient = new MqttClient(ipUrl, clientId, persistence); 247 | this.connectionOptions.setCleanSession(true); 248 | this.mqttClient.connect(this.connectionOptions); 249 | this.mqttClient.setCallback(this); 250 | } catch (MqttException me) { 251 | logger.error("ERROR", me); 252 | } 253 | } 254 | 255 | 256 | protected void config(String ip, Integer port, Boolean ssl, Boolean withUserNamePass) { 257 | String protocal = this.TCP; 258 | if (ssl) { 259 | protocal = this.SSL; 260 | } 261 | this.ipUrl = protocal + this.ip + colon + port; 262 | this.persistence = new MemoryPersistence(); 263 | this.connectionOptions = new MqttConnectOptions(); 264 | 265 | try { 266 | this.mqttClient = new MqttClient(ipUrl, clientId, persistence); 267 | this.connectionOptions.setCleanSession(true); 268 | if (withUserNamePass) { 269 | if (password != null) { 270 | this.connectionOptions.setPassword(this.password.toCharArray()); 271 | } 272 | if (username != null) { 273 | this.connectionOptions.setUserName(this.username); 274 | } 275 | } 276 | this.mqttClient.connect(this.connectionOptions); 277 | this.mqttClient.setCallback(this); 278 | } catch (MqttException me) { 279 | logger.error("ERROR", me); 280 | } 281 | } 282 | 283 | 284 | @Override 285 | public void publishMessage(String topic, String message) { 286 | 287 | try { 288 | MqttMessage mqttmessage = new MqttMessage(message.getBytes()); 289 | mqttmessage.setQos(this.qos); 290 | this.mqttClient.publish(topic, mqttmessage); 291 | } catch (MqttException me) { 292 | logger.error("ERROR", me); 293 | } 294 | 295 | } 296 | 297 | @Override 298 | public void connectionLost(Throwable arg0) { 299 | logger.info("Connection Lost"); 300 | 301 | } 302 | 303 | 304 | @Override 305 | public void deliveryComplete(IMqttDeliveryToken arg0) { 306 | logger.info("delivery completed"); 307 | 308 | } 309 | 310 | 311 | @Override 312 | public void messageArrived(String arg0, MqttMessage arg1) { 313 | // Leave it blank for Publisher 314 | 315 | } 316 | 317 | @Override 318 | public void disconnect() { 319 | try { 320 | this.mqttClient.disconnect(); 321 | } catch (MqttException me) { 322 | logger.error("ERROR", me); 323 | } 324 | } 325 | } 326 | 327 | ``` 328 | 329 | 330 | 331 | #### 5. Subscriber 订阅者 332 | 333 | 定义接口 334 | 335 | ```java 336 | public interface IMQTTSubscriber { 337 | 338 | /** 339 | * 订阅消息 340 | * 341 | * @param topic 342 | */ 343 | public void subscribeMessage(String topic); 344 | 345 | /** 346 | * 断开MQTT客户端 347 | */ 348 | public void disconnect(); 349 | } 350 | 351 | ``` 352 | 353 | 类定义 354 | 355 | ```java 356 | 357 | import org.eclipse.paho.client.mqttv3.*; 358 | import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; 359 | import org.slf4j.Logger; 360 | import org.slf4j.LoggerFactory; 361 | import org.springframework.stereotype.Component; 362 | 363 | import java.sql.Timestamp; 364 | 365 | /** 366 | * @author gaoyf 367 | * @since 2020/4/9 0009 16:05 368 | */ 369 | @Component 370 | public class MQTTSubscriber extends MQTTConfig implements MqttCallback, IMQTTSubscriber { 371 | 372 | private String brokerUrl = null; 373 | final private String colon = ":";//冒号分隔符 374 | final private String clientId = "mqtt_server_sub";//客户端ID 这里可以随便定义 375 | 376 | private MqttClient mqttClient = null; 377 | private MqttConnectOptions connectionOptions = null; 378 | private MemoryPersistence persistence = null; 379 | 380 | private static final Logger logger = LoggerFactory.getLogger(MQTTSubscriber.class); 381 | 382 | public MQTTSubscriber() { 383 | this.config(); 384 | } 385 | 386 | @Override 387 | public void connectionLost(Throwable cause) { 388 | logger.info("Connection Lost"); 389 | 390 | } 391 | 392 | @Override 393 | public void messageArrived(String topic, MqttMessage message) { 394 | // Called when a message arrives from the server that matches any subscription made by the client 395 | String time = new Timestamp(System.currentTimeMillis()).toString(); 396 | System.out.println(); 397 | System.out.println("***********************************************************************"); 398 | System.out.println("消息到达时间:" + time + " Topic: " + topic + " Message: " 399 | + new String(message.getPayload())); 400 | System.out.println("***********************************************************************"); 401 | System.out.println(); 402 | } 403 | 404 | @Override 405 | public void deliveryComplete(IMqttDeliveryToken token) { 406 | // Leave it blank for subscriber 407 | 408 | } 409 | 410 | @Override 411 | public void subscribeMessage(String topic) { 412 | try { 413 | this.mqttClient.subscribe(topic, this.qos); 414 | } catch (MqttException me) { 415 | me.printStackTrace(); 416 | } 417 | } 418 | 419 | public void disconnect() { 420 | try { 421 | this.mqttClient.disconnect(); 422 | } catch (MqttException me) { 423 | logger.error("ERROR", me); 424 | } 425 | } 426 | 427 | protected void config(String ip, Integer port, Boolean ssl, Boolean withUserNamePass) { 428 | String protocal = this.TCP; 429 | if (ssl) { 430 | protocal = this.SSL; 431 | } 432 | this.brokerUrl = protocal + this.ip + colon + port; 433 | this.persistence = new MemoryPersistence(); 434 | this.connectionOptions = new MqttConnectOptions(); 435 | try { 436 | this.mqttClient = new MqttClient(brokerUrl, clientId, persistence); 437 | this.connectionOptions.setCleanSession(true); 438 | if (withUserNamePass) { 439 | if (password != null) { 440 | this.connectionOptions.setPassword(this.password.toCharArray()); 441 | } 442 | if (username != null) { 443 | this.connectionOptions.setUserName(this.username); 444 | } 445 | } 446 | this.mqttClient.connect(this.connectionOptions); 447 | this.mqttClient.setCallback(this); 448 | } catch (MqttException me) { 449 | me.printStackTrace(); 450 | } 451 | 452 | } 453 | 454 | protected void config() { 455 | 456 | this.brokerUrl = this.TCP + this.ip + colon + this.port; 457 | this.persistence = new MemoryPersistence(); 458 | this.connectionOptions = new MqttConnectOptions(); 459 | try { 460 | this.mqttClient = new MqttClient(brokerUrl, clientId, persistence); 461 | this.connectionOptions.setCleanSession(true); 462 | this.mqttClient.connect(this.connectionOptions); 463 | this.mqttClient.setCallback(this); 464 | } catch (MqttException me) { 465 | me.printStackTrace(); 466 | } 467 | 468 | } 469 | 470 | } 471 | 472 | ``` 473 | 474 | #### 6. 构建 RestFul接口 475 | 476 | 构建Controller 477 | 478 | ```java 479 | import com.gaoyf.mqtt.core.IMQTTPublisher; 480 | import com.gaoyf.mqtt.core.IMQTTSubscriber; 481 | import org.springframework.beans.factory.annotation.Autowired; 482 | import org.springframework.web.bind.annotation.RequestBody; 483 | import org.springframework.web.bind.annotation.RequestMapping; 484 | import org.springframework.web.bind.annotation.RequestMethod; 485 | import org.springframework.web.bind.annotation.RestController; 486 | 487 | import javax.annotation.PostConstruct; 488 | 489 | /** 490 | * @author gaoyf 491 | * @since 2020/4/9 0009 16:14 492 | *

493 | * 测试controller 494 | */ 495 | @RestController 496 | public class DemoRestController { 497 | public static String TOPIC_LOOP_TEST = "mqtt/loop/message"; 498 | 499 | @Autowired 500 | IMQTTPublisher publisher; 501 | 502 | @Autowired 503 | IMQTTSubscriber subscriber; 504 | 505 | /** 506 | * 被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。 507 | * PostConstruct在构造函数之后执行,init()方法之前执行。PreDestroy()方法在destroy()方法知性之后执行 508 | * 这里初始化订阅一个主题 509 | */ 510 | @PostConstruct 511 | public void init() { 512 | subscriber.subscribeMessage(TOPIC_LOOP_TEST); 513 | } 514 | 515 | 516 | /** 517 | * 向指定主题发送消息 518 | * 519 | * @param data 数据 520 | * @return 响应 521 | */ 522 | @RequestMapping(value = "/mqtt/loop/message", method = RequestMethod.POST) 523 | public String index(@RequestBody String data) { 524 | publisher.publishMessage(TOPIC_LOOP_TEST, data); 525 | return "Success"; 526 | } 527 | 528 | } 529 | ``` 530 | 531 | #### 7. 使用postman 调用8080 端口调试或者使用MQTTX工具进行调试。 532 | [MQTTX 下载地址]( https://github.com/emqx/MQTTX/releases/tag/v1.3.0) 533 | 534 | 535 | 536 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.6.RELEASE 9 | 10 | 11 | com.gaoyf 12 | springboot-mqtt 13 | 0.0.1-SNAPSHOT 14 | springboot-mqtt 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | 28 | 29 | org.springframework.integration 30 | spring-integration-stream 31 | 32 | 33 | org.springframework.integration 34 | spring-integration-mqtt 35 | 36 | 37 | 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-maven-plugin 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/main/java/com/gaoyf/mqtt/SpringbootMqttApplication.java: -------------------------------------------------------------------------------- 1 | package com.gaoyf.springbootmqtt; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SpringbootMqttApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SpringbootMqttApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/gaoyf/mqtt/controller/DemoRestController.java: -------------------------------------------------------------------------------- 1 | package com.gaoyf.mqtt.controller; 2 | 3 | import com.gaoyf.mqtt.core.IMQTTPublisher; 4 | import com.gaoyf.mqtt.core.IMQTTSubscriber; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.RequestBody; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | import javax.annotation.PostConstruct; 12 | 13 | /** 14 | * @author gaoyf 15 | * @since 2020/4/9 0009 16:14 16 | *

17 | * 测试controller 18 | */ 19 | @RestController 20 | public class DemoRestController { 21 | public static String TOPIC_LOOP_TEST = "mqtt/loop/message"; 22 | 23 | @Autowired 24 | IMQTTPublisher publisher; 25 | 26 | @Autowired 27 | IMQTTSubscriber subscriber; 28 | 29 | /** 30 | * 被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。 31 | * PostConstruct在构造函数之后执行,init()方法之前执行。PreDestroy()方法在destroy()方法知性之后执行 32 | * 这里初始化订阅一个主题 33 | */ 34 | @PostConstruct 35 | public void init() { 36 | subscriber.subscribeMessage(TOPIC_LOOP_TEST); 37 | } 38 | 39 | 40 | /** 41 | * 向指定主题发送消息 42 | * 43 | * @param data 数据 44 | * @return 响应 45 | */ 46 | @RequestMapping(value = "/mqtt/loop/message", method = RequestMethod.POST) 47 | public String index(@RequestBody String data) { 48 | publisher.publishMessage(TOPIC_LOOP_TEST, data); 49 | return "Success"; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/gaoyf/mqtt/core/IMQTTPublisher.java: -------------------------------------------------------------------------------- 1 | package com.gaoyf.mqtt.core; 2 | 3 | /** 4 | * @author gaoyf 5 | * @since 2020/4/9 0009 16:02 6 | *

7 | * 发布者接口 8 | */ 9 | public interface IMQTTPublisher { 10 | /** 11 | * 发布消息 12 | * 13 | * @param topic 主题 14 | * @param message 消息 15 | */ 16 | public void publishMessage(String topic, String message); 17 | 18 | /** 19 | * 断开MQTT客户端 20 | */ 21 | public void disconnect(); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/main/java/com/gaoyf/mqtt/core/IMQTTSubscriber.java: -------------------------------------------------------------------------------- 1 | package com.gaoyf.mqtt.core; 2 | 3 | /** 4 | * @author gaoyf 5 | * @since 2020/4/9 0009 16:04 6 | *

7 | * 订阅者接口 8 | */ 9 | public interface IMQTTSubscriber { 10 | 11 | /** 12 | * 订阅消息 13 | * 14 | * @param topic 15 | */ 16 | public void subscribeMessage(String topic); 17 | 18 | /** 19 | * 断开MQTT客户端 20 | */ 21 | public void disconnect(); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/gaoyf/mqtt/core/MQTTConfig.java: -------------------------------------------------------------------------------- 1 | package com.gaoyf.mqtt.core; 2 | 3 | /** 4 | * mqtt配置文件 5 | */ 6 | public abstract class MQTTConfig { 7 | 8 | protected String ip = "127.0.0.1"; 9 | 10 | /** 11 | * qos0 对于client而言,有且仅发一次publish包,对于broker而言,有且仅发一次publish,简而言之,就是仅发一次包,是否收到完全不管,适合那些不是很重要的数据。 12 | * qos1 这个交互就是多了一次ack的作用,但是会有个问题,尽管我们可以通过确认来保证一定收到客户端或服务器的message,但是我们却不能保证message仅有一次, 13 | * 也就是当client没收到service的puback或者service没有收到client的puback,那么就会一直发送publisher 14 | * qos2可以实现仅仅接受一次message,其主要原理(对于publisher而言), 15 | * publisher和broker进行了缓存,其中publisher缓存了message和msgID,而broker缓存了msgID,两方都做记录所以可以保证消息不重复, 16 | * 但是由于记录是需要删除的,这个删除流程同样多了一倍 17 | */ 18 | protected int qos = 2; 19 | 20 | protected Boolean hasSSL = false; /* By default SSL is disabled */ 21 | 22 | protected Integer port = 1883; /* Default port */ 23 | 24 | protected String username = "账号"; 25 | 26 | protected String password = "密码"; 27 | 28 | protected String TCP = "tcp://"; 29 | 30 | protected String SSL = "ssl://"; 31 | 32 | 33 | /** 34 | * Custom Configuration 35 | */ 36 | protected abstract void config(String ip, Integer port, Boolean ssl, Boolean withUserNamePass); 37 | 38 | /** 39 | * Default Configuration 40 | */ 41 | protected abstract void config(); 42 | 43 | 44 | public String getIp() { 45 | return ip; 46 | } 47 | 48 | public void setIp(String ip) { 49 | this.ip = ip; 50 | } 51 | 52 | public int getQos() { 53 | return qos; 54 | } 55 | 56 | public void setQos(int qos) { 57 | this.qos = qos; 58 | } 59 | 60 | public Boolean getHasSSL() { 61 | return hasSSL; 62 | } 63 | 64 | public void setHasSSL(Boolean hasSSL) { 65 | this.hasSSL = hasSSL; 66 | } 67 | 68 | public Integer getPort() { 69 | return port; 70 | } 71 | 72 | public void setPort(Integer port) { 73 | this.port = port; 74 | } 75 | 76 | public String getUsername() { 77 | return username; 78 | } 79 | 80 | public void setUsername(String username) { 81 | this.username = username; 82 | } 83 | 84 | public String getPassword() { 85 | return password; 86 | } 87 | 88 | public void setPassword(String password) { 89 | this.password = password; 90 | } 91 | 92 | public String getTCP() { 93 | return TCP; 94 | } 95 | 96 | public void setTCP(String TCP) { 97 | this.TCP = TCP; 98 | } 99 | 100 | public String getSSL() { 101 | return SSL; 102 | } 103 | 104 | public void setSSL(String SSL) { 105 | this.SSL = SSL; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/com/gaoyf/mqtt/core/MQTTPublisher.java: -------------------------------------------------------------------------------- 1 | package com.gaoyf.mqtt.core; 2 | 3 | import org.eclipse.paho.client.mqttv3.*; 4 | import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * @author gaoyf 11 | * @since 2020/4/9 0009 16:02 12 | */ 13 | @Component 14 | public class MQTTPublisher extends MQTTConfig implements MqttCallback, IMQTTPublisher { 15 | 16 | private String ipUrl = null; 17 | 18 | final private String colon = ":";//冒号分隔符 19 | final private String clientId = "mqtt_server_pub";//客户端ID 这里可以随便定义 20 | 21 | private MqttClient mqttClient = null; 22 | private MqttConnectOptions connectionOptions = null; 23 | private MemoryPersistence persistence = null; 24 | 25 | private static final Logger logger = LoggerFactory.getLogger(MQTTPublisher.class); 26 | 27 | /** 28 | * Private default constructor 29 | */ 30 | private MQTTPublisher() { 31 | this.config(); 32 | } 33 | 34 | /** 35 | * Private constructor 36 | */ 37 | private MQTTPublisher(String ip, Integer port, Boolean ssl, Boolean withUserNamePass) { 38 | this.config(ip, port, ssl, withUserNamePass); 39 | } 40 | 41 | /** 42 | * Factory method to get instance of MQTTPublisher 43 | * 44 | * @return MQTTPublisher 45 | */ 46 | public static MQTTPublisher getInstance() { 47 | return new MQTTPublisher(); 48 | } 49 | 50 | /** 51 | * 获取MQTTPublisher实例的工厂方法 52 | * 53 | * @param ip ip地址 54 | * @param port 断开 55 | * @param ssl 是否ssl 56 | * @param withUserNamePass 用户名密码 57 | * @return MQTTPublisher 58 | */ 59 | public static MQTTPublisher getInstance(String ip, Integer port, Boolean ssl, Boolean withUserNamePass) { 60 | return new MQTTPublisher(ip, port, ssl, withUserNamePass); 61 | } 62 | 63 | 64 | protected void config() { 65 | 66 | this.ipUrl = this.TCP + this.ip + colon + this.port; 67 | this.persistence = new MemoryPersistence(); 68 | this.connectionOptions = new MqttConnectOptions(); 69 | try { 70 | this.mqttClient = new MqttClient(ipUrl, clientId, persistence); 71 | this.connectionOptions.setCleanSession(true); 72 | this.mqttClient.connect(this.connectionOptions); 73 | this.mqttClient.setCallback(this); 74 | } catch (MqttException me) { 75 | logger.error("ERROR", me); 76 | } 77 | } 78 | 79 | 80 | protected void config(String ip, Integer port, Boolean ssl, Boolean withUserNamePass) { 81 | String protocal = this.TCP; 82 | if (ssl) { 83 | protocal = this.SSL; 84 | } 85 | this.ipUrl = protocal + this.ip + colon + port; 86 | this.persistence = new MemoryPersistence(); 87 | this.connectionOptions = new MqttConnectOptions(); 88 | 89 | try { 90 | this.mqttClient = new MqttClient(ipUrl, clientId, persistence); 91 | this.connectionOptions.setCleanSession(true); 92 | if (withUserNamePass) { 93 | if (password != null) { 94 | this.connectionOptions.setPassword(this.password.toCharArray()); 95 | } 96 | if (username != null) { 97 | this.connectionOptions.setUserName(this.username); 98 | } 99 | } 100 | this.mqttClient.connect(this.connectionOptions); 101 | this.mqttClient.setCallback(this); 102 | } catch (MqttException me) { 103 | logger.error("ERROR", me); 104 | } 105 | } 106 | 107 | 108 | @Override 109 | public void publishMessage(String topic, String message) { 110 | 111 | try { 112 | MqttMessage mqttmessage = new MqttMessage(message.getBytes()); 113 | mqttmessage.setQos(this.qos); 114 | this.mqttClient.publish(topic, mqttmessage); 115 | } catch (MqttException me) { 116 | logger.error("ERROR", me); 117 | } 118 | 119 | } 120 | 121 | @Override 122 | public void connectionLost(Throwable arg0) { 123 | logger.info("Connection Lost"); 124 | 125 | } 126 | 127 | 128 | @Override 129 | public void deliveryComplete(IMqttDeliveryToken arg0) { 130 | logger.info("delivery completed"); 131 | 132 | } 133 | 134 | 135 | @Override 136 | public void messageArrived(String arg0, MqttMessage arg1) { 137 | // Leave it blank for Publisher 138 | 139 | } 140 | 141 | @Override 142 | public void disconnect() { 143 | try { 144 | this.mqttClient.disconnect(); 145 | } catch (MqttException me) { 146 | logger.error("ERROR", me); 147 | } 148 | } 149 | 150 | } -------------------------------------------------------------------------------- /src/main/java/com/gaoyf/mqtt/core/MQTTSubscriber.java: -------------------------------------------------------------------------------- 1 | package com.gaoyf.mqtt.core; 2 | 3 | import org.eclipse.paho.client.mqttv3.*; 4 | import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.sql.Timestamp; 10 | 11 | /** 12 | * @author gaoyf 13 | * @since 2020/4/9 0009 16:05 14 | */ 15 | @Component 16 | public class MQTTSubscriber extends MQTTConfig implements MqttCallback, IMQTTSubscriber { 17 | 18 | private String brokerUrl = null; 19 | final private String colon = ":";//冒号分隔符 20 | final private String clientId = "mqtt_server_sub";//客户端ID 这里可以随便定义 21 | 22 | private MqttClient mqttClient = null; 23 | private MqttConnectOptions connectionOptions = null; 24 | private MemoryPersistence persistence = null; 25 | 26 | private static final Logger logger = LoggerFactory.getLogger(MQTTSubscriber.class); 27 | 28 | public MQTTSubscriber() { 29 | this.config(); 30 | } 31 | 32 | @Override 33 | public void connectionLost(Throwable cause) { 34 | logger.info("Connection Lost"); 35 | 36 | } 37 | 38 | @Override 39 | public void messageArrived(String topic, MqttMessage message) { 40 | // Called when a message arrives from the server that matches any subscription made by the client 41 | String time = new Timestamp(System.currentTimeMillis()).toString(); 42 | System.out.println(); 43 | System.out.println("***********************************************************************"); 44 | System.out.println("消息到达时间:" + time + " Topic: " + topic + " Message: " 45 | + new String(message.getPayload())); 46 | System.out.println("***********************************************************************"); 47 | System.out.println(); 48 | } 49 | 50 | @Override 51 | public void deliveryComplete(IMqttDeliveryToken token) { 52 | // Leave it blank for subscriber 53 | 54 | } 55 | 56 | @Override 57 | public void subscribeMessage(String topic) { 58 | try { 59 | this.mqttClient.subscribe(topic, this.qos); 60 | } catch (MqttException me) { 61 | me.printStackTrace(); 62 | } 63 | } 64 | 65 | public void disconnect() { 66 | try { 67 | this.mqttClient.disconnect(); 68 | } catch (MqttException me) { 69 | logger.error("ERROR", me); 70 | } 71 | } 72 | 73 | protected void config(String ip, Integer port, Boolean ssl, Boolean withUserNamePass) { 74 | String protocal = this.TCP; 75 | if (ssl) { 76 | protocal = this.SSL; 77 | } 78 | this.brokerUrl = protocal + this.ip + colon + port; 79 | this.persistence = new MemoryPersistence(); 80 | this.connectionOptions = new MqttConnectOptions(); 81 | try { 82 | this.mqttClient = new MqttClient(brokerUrl, clientId, persistence); 83 | this.connectionOptions.setCleanSession(true); 84 | if (withUserNamePass) { 85 | if (password != null) { 86 | this.connectionOptions.setPassword(this.password.toCharArray()); 87 | } 88 | if (username != null) { 89 | this.connectionOptions.setUserName(this.username); 90 | } 91 | } 92 | this.mqttClient.connect(this.connectionOptions); 93 | this.mqttClient.setCallback(this); 94 | } catch (MqttException me) { 95 | me.printStackTrace(); 96 | } 97 | 98 | } 99 | 100 | protected void config() { 101 | 102 | this.brokerUrl = this.TCP + this.ip + colon + this.port; 103 | this.persistence = new MemoryPersistence(); 104 | this.connectionOptions = new MqttConnectOptions(); 105 | try { 106 | this.mqttClient = new MqttClient(brokerUrl, clientId, persistence); 107 | this.connectionOptions.setCleanSession(true); 108 | this.mqttClient.connect(this.connectionOptions); 109 | this.mqttClient.setCallback(this); 110 | } catch (MqttException me) { 111 | me.printStackTrace(); 112 | } 113 | 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gaoyf95/springboot-mqtt/69510ce09c6d85b75b10b9ed969abb6a7a5806e0/src/main/resources/application.properties --------------------------------------------------------------------------------