├── .gitignore ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── iot │ │ ├── ClientApplication.java │ │ ├── device │ │ ├── entity │ │ │ └── Device.java │ │ ├── mapper │ │ │ └── DeviceMapper.java │ │ └── service │ │ │ ├── DeviceService.java │ │ │ └── serviceImpl │ │ │ └── DeviceServiceImpl.java │ │ └── mqtt │ │ ├── InitCallback.java │ │ ├── MQTTConnect.java │ │ └── MQTTListener.java └── resources │ ├── config │ ├── application-dev.yml │ ├── application-prod.yml │ └── application.yml │ ├── logback │ ├── logback-dev.xml │ └── logback-prod.xml │ └── mapper │ └── DeviceMapper.xml └── test └── java └── com └── iot └── ClientApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IoT 2 | 物联网平台 3 | 采用emq x作为mqtt服务器,运行代码时,注意修改配置文件中mysql参数、mqtt参数. 4 | 5 | [link]: https://blog.csdn.net/qq_37949192 -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.2.6.RELEASE 10 | 11 | 12 | com.iot 13 | AM 14 | 1.0.0 15 | AM 16 | mqtt client 17 | 18 | 19 | 1.8 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-web 26 | 27 | 28 | org.mybatis.spring.boot 29 | mybatis-spring-boot-starter 30 | 2.1.2 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter 35 | 36 | 37 | org.mybatis.spring.boot 38 | mybatis-spring-boot-starter 39 | 2.1.2 40 | 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-devtools 45 | runtime 46 | true 47 | 48 | 49 | mysql 50 | mysql-connector-java 51 | runtime 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-configuration-processor 56 | true 57 | 58 | 59 | org.projectlombok 60 | lombok 61 | true 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-starter-test 66 | test 67 | 68 | 69 | org.junit.vintage 70 | junit-vintage-engine 71 | 72 | 73 | 74 | 75 | 76 | 77 | org.springframework.integration 78 | spring-integration-mqtt 79 | 80 | 81 | 82 | 83 | com.alibaba 84 | fastjson 85 | 1.2.62 86 | 87 | 88 | 89 | 90 | 91 | 92 | org.springframework.boot 93 | spring-boot-maven-plugin 94 | 95 | 96 | 97 | 98 | 99 | 100 | src/main/resources 101 | true 102 | 103 | 104 | application.yml 105 | application-dev.yml 106 | application-prod.yml 107 | 108 | 109 | 110 | 111 | src/main/resources 112 | true 113 | 114 | 115 | application.yml 116 | application-${spring.profiles.active}.yml 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | dev 125 | 126 | 127 | true 128 | 129 | 130 | dev 131 | 132 | 133 | 134 | 135 | 136 | prod 137 | 138 | prod 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /src/main/java/com/iot/ClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.iot; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @SpringBootApplication 8 | @MapperScan({"com.iot.**.mapper"}) 9 | public class ClientApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(ClientApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/iot/device/entity/Device.java: -------------------------------------------------------------------------------- 1 | package com.iot.device.entity; 2 | 3 | import java.io.Serializable; 4 | import lombok.Data; 5 | import lombok.experimental.Accessors; 6 | 7 | /** 8 | * TODO 9 | * 10 | * @author Mr.Qu 11 | * @title: Device 12 | * @since 2020/11/17 15:42 13 | */ 14 | @Data 15 | @Accessors(chain = true) 16 | public class Device implements Serializable { 17 | 18 | private String username; 19 | 20 | private long ts; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/iot/device/mapper/DeviceMapper.java: -------------------------------------------------------------------------------- 1 | package com.iot.device.mapper; 2 | 3 | import com.iot.device.entity.Device; 4 | import org.springframework.stereotype.Repository; 5 | 6 | /** 7 | * TODO 8 | * 9 | * @author Mr.Qu 10 | * @title: DeviceMapper 11 | * @since 2020/11/17 15:56 12 | */ 13 | @Repository 14 | public interface DeviceMapper { 15 | 16 | boolean updateDeviceStatus(Device param); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/iot/device/service/DeviceService.java: -------------------------------------------------------------------------------- 1 | package com.iot.device.service; 2 | 3 | import com.iot.device.entity.Device; 4 | 5 | /** 6 | * TODO 7 | * 8 | * @author Mr.Qu 9 | * @title: DeviceService 10 | * @since 2020/11/17 15:35 11 | */ 12 | public interface DeviceService { 13 | 14 | boolean updateDeviceStatus(Device param); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/iot/device/service/serviceImpl/DeviceServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.iot.device.service.serviceImpl; 2 | 3 | import com.iot.device.entity.Device; 4 | import com.iot.device.mapper.DeviceMapper; 5 | import com.iot.device.service.DeviceService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | * TODO 11 | * 12 | * @author Mr.Qu 13 | * @title: DeviceServiceImpl 14 | * @since 2020/11/17 15:55 15 | */ 16 | @Service 17 | public class DeviceServiceImpl implements DeviceService { 18 | 19 | @Autowired 20 | private DeviceMapper deviceMapper; 21 | 22 | @Override 23 | public boolean updateDeviceStatus(Device param) { 24 | return deviceMapper.updateDeviceStatus(param); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/iot/mqtt/InitCallback.java: -------------------------------------------------------------------------------- 1 | package com.iot.mqtt; 2 | 3 | import com.iot.device.entity.Device; 4 | import com.iot.device.service.DeviceService; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; 7 | import org.eclipse.paho.client.mqttv3.MqttCallback; 8 | import org.eclipse.paho.client.mqttv3.MqttMessage; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Component; 11 | 12 | /** 13 | * MQTT回调函数 14 | * 15 | * @author Mr.Qu 16 | * @since 2020/11/18 17 | */ 18 | @Slf4j 19 | @Component 20 | public class InitCallback implements MqttCallback { 21 | 22 | @Autowired 23 | private DeviceService deviceService; 24 | 25 | /** 26 | * MQTT 断开连接会执行此方法 27 | */ 28 | @Override 29 | public void connectionLost(Throwable cause) { 30 | log.error(cause.getMessage(), cause); 31 | } 32 | 33 | /** 34 | * publish发布成功后会执行到这里 35 | */ 36 | @Override 37 | public void deliveryComplete(IMqttDeliveryToken token) { 38 | } 39 | 40 | /** 41 | * subscribe订阅后得到的消息会执行到这里 42 | */ 43 | @Override 44 | public void messageArrived(String topic, MqttMessage message) { 45 | log.info("[{}] : {}", topic, new String(message.getPayload())); 46 | deviceService 47 | .updateDeviceStatus(new Device().setUsername("qbb").setTs(System.currentTimeMillis())); 48 | /*try { 49 | JSONObject jsonObject = JSON.parseObject(msg); 50 | String clientId = String.valueOf(jsonObject.get("clientid")); 51 | if (topic.endsWith("/disconnected")) { 52 | log.info("客户端已掉线:{}", clientId); 53 | } else { 54 | log.info("客户端已上线:{}", clientId); 55 | } 56 | } catch (JSONException e) { 57 | log.error("JSON Format Parsing Exception : {}", msg); 58 | }*/ 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/iot/mqtt/MQTTConnect.java: -------------------------------------------------------------------------------- 1 | package com.iot.mqtt; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.eclipse.paho.client.mqttv3.*; 5 | import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * MQTT工具类操作 11 | * 12 | * @author Mr.Qu 13 | * @since 2020/11/18 14 | */ 15 | @Slf4j 16 | @Component 17 | public class MQTTConnect { 18 | 19 | @Value("${mqtt.host}") 20 | private String HOST; 21 | private final String clientId = "Client" + (int) (Math.random() * 100000000); 22 | private MqttClient mqttClient; 23 | 24 | /** 25 | * 客户端connect连接mqtt服务器 26 | * 27 | * @param username 用户名 28 | * @param password 密码 29 | * @param mqttCallback 回调函数 30 | **/ 31 | public void setMqttClient(String username, String password, MqttCallback mqttCallback) 32 | throws MqttException { 33 | MqttConnectOptions options = mqttConnectOptions(username, password); 34 | /*if (mqttCallback == null) { 35 | mqttClient.setCallback(new Callback()); 36 | } else { 37 | }*/ 38 | mqttClient.setCallback(mqttCallback); 39 | mqttClient.connect(options); 40 | } 41 | 42 | /** 43 | * MQTT连接参数设置 44 | */ 45 | private MqttConnectOptions mqttConnectOptions(String userName, String passWord) 46 | throws MqttException { 47 | mqttClient = new MqttClient(HOST, clientId, new MemoryPersistence()); 48 | MqttConnectOptions options = new MqttConnectOptions(); 49 | options.setUserName(userName); 50 | options.setPassword(passWord.toCharArray()); 51 | options.setConnectionTimeout(10);///默认:30 52 | options.setAutomaticReconnect(true);//默认:false 53 | options.setCleanSession(false);//默认:true 54 | //options.setKeepAliveInterval(20);//默认:60 55 | return options; 56 | } 57 | 58 | /** 59 | * 关闭MQTT连接 60 | */ 61 | public void close() throws MqttException { 62 | mqttClient.close(); 63 | mqttClient.disconnect(); 64 | } 65 | 66 | /** 67 | * 向某个主题发布消息 默认qos:1 68 | */ 69 | public void pub(String topic, String msg) throws MqttException { 70 | MqttMessage mqttMessage = new MqttMessage(); 71 | //mqttMessage.setQos(2); 72 | mqttMessage.setPayload(msg.getBytes()); 73 | MqttTopic mqttTopic = mqttClient.getTopic(topic); 74 | MqttDeliveryToken token = mqttTopic.publish(mqttMessage); 75 | token.waitForCompletion(); 76 | } 77 | 78 | /** 79 | * 向某个主题发布消息 80 | * 81 | * @param topic: 发布的主题 82 | * @param msg: 发布的消息 83 | * @param qos: 消息质量 Qos:0、1、2 84 | */ 85 | public void pub(String topic, String msg, int qos) throws MqttException { 86 | MqttMessage mqttMessage = new MqttMessage(); 87 | mqttMessage.setQos(qos); 88 | mqttMessage.setPayload(msg.getBytes()); 89 | MqttTopic mqttTopic = mqttClient.getTopic(topic); 90 | MqttDeliveryToken token = mqttTopic.publish(mqttMessage); 91 | token.waitForCompletion(); 92 | } 93 | 94 | /** 95 | * 订阅某一个主题 ,此方法默认的的Qos等级为:1 96 | * 97 | * @param topic 主题 98 | */ 99 | public void sub(String topic) throws MqttException { 100 | mqttClient.subscribe(topic); 101 | } 102 | 103 | /** 104 | * 订阅某一个主题,可携带Qos 105 | * 106 | * @param topic 所要订阅的主题 107 | * @param qos 消息质量:0、1、2 108 | */ 109 | public void sub(String topic, int qos) throws MqttException { 110 | mqttClient.subscribe(topic, qos); 111 | } 112 | 113 | public static void main(String[] args) throws MqttException { 114 | MQTTConnect mqttConnect = new MQTTConnect(); 115 | String msg = "Mr.Qu" + (int) (Math.random() * 100000000); 116 | mqttConnect.setMqttClient("admin", "public", new InitCallback()); 117 | mqttConnect.sub("com/iot/init"); 118 | mqttConnect.pub("com/iot/init", msg); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/com/iot/mqtt/MQTTListener.java: -------------------------------------------------------------------------------- 1 | package com.iot.mqtt; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.eclipse.paho.client.mqttv3.MqttException; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.context.ApplicationListener; 8 | import org.springframework.context.event.ContextRefreshedEvent; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * 项目启动 监听主题 13 | * 14 | * @author Mr.Qu 15 | * @since 2020/11/18 0018 16 | */ 17 | @Slf4j 18 | @Component 19 | public class MQTTListener implements ApplicationListener { 20 | 21 | @Value("${mqtt.username}") 22 | private String username; 23 | @Value("${mqtt.password}") 24 | private String password; 25 | private final MQTTConnect server; 26 | private final InitCallback initCallback; 27 | 28 | @Autowired 29 | public MQTTListener(MQTTConnect server, InitCallback initCallback) { 30 | this.server = server; 31 | this.initCallback = initCallback; 32 | } 33 | 34 | @Override 35 | public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { 36 | try { 37 | server.setMqttClient(username, password, initCallback); 38 | server.sub("com/iot/init"); 39 | } catch (MqttException e) { 40 | log.error(e.getMessage(), e); 41 | } 42 | } 43 | } 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/main/resources/config/application-dev.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:mysql://localhost:3306/iotdb?useSSL=false&useUnicode=true&characterEncoding=utf8&allowMultiQueries=true 4 | username: root 5 | password: root 6 | 7 | server: 8 | port: 8082 9 | 10 | mqtt: 11 | host: tcp://broker.emqx.io:1883 12 | username: admin 13 | password: public 14 | -------------------------------------------------------------------------------- /src/main/resources/config/application-prod.yml: -------------------------------------------------------------------------------- 1 | logging: 2 | path: /opt/iot/logs 3 | 4 | server: 5 | port: 8084 6 | 7 | mqtt: 8 | host: tcp://broker.emqx.io:1883 9 | username: admin 10 | password: public -------------------------------------------------------------------------------- /src/main/resources/config/application.yml: -------------------------------------------------------------------------------- 1 | logging: 2 | config: classpath:logback/logback-@spring.profiles.active@.xml 3 | 4 | spring: 5 | application: 6 | name: DC 7 | profiles: 8 | active: @spring.profiles.active@ 9 | 10 | datasource: 11 | driver-class-name: com.mysql.cj.jdbc.Driver 12 | type: com.zaxxer.hikari.HikariDataSource 13 | hikari: 14 | minimum-idle: 5 15 | maximum-pool-size: 15 16 | auto-commit: true 17 | idle-timeout: 30000 18 | pool-name: DatebookHikariCP 19 | max-lifetime: 1800000 20 | connection-timeout: 30000 21 | connection-test-query: SELECT 1 FROM DUAL 22 | 23 | jackson: 24 | default-property-inclusion: non_null 25 | 26 | mybatis: 27 | mapper-locations: mapper/**/*.xml -------------------------------------------------------------------------------- /src/main/resources/logback/logback-dev.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | logback 9 | 10 | 11 | 12 | 13 | 15 | 17 | 18 | 20 | 21 | 22 | 23 | ${CONSOLE_LOG_PATTERN} 24 | UTF-8 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/main/resources/logback/logback-prod.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | logback 9 | 10 | 11 | 12 | 13 | 14 | 15 | ${log.path}/log_info.log 16 | 17 | 18 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 19 | UTF-8 20 | 21 | 22 | 23 | 24 | ${log.path}/web-info-%d{yyyy-MM-dd}.%i.log 25 | 26 | 60MB 27 | 28 | 29 | 15 30 | 31 | 32 | 33 | info 34 | ACCEPT 35 | DENY 36 | 37 | 38 | 39 | 40 | 41 | ${log.path}/log_warn.log 42 | 43 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 44 | UTF-8 45 | 46 | 47 | ${log.path}/web-warn-%d{yyyy-MM-dd}.%i.log 48 | 49 | 60MB 50 | 51 | 15 52 | 53 | 54 | warn 55 | ACCEPT 56 | DENY 57 | 58 | 59 | 60 | 61 | 62 | ${log.path}/log_error.log 63 | 64 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 65 | UTF-8 66 | 67 | 68 | ${log.path}/web-error-%d{yyyy-MM-dd}.%i.log 69 | 70 | 60MB 71 | 72 | 15 73 | 74 | 75 | ERROR 76 | ACCEPT 77 | DENY 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /src/main/resources/mapper/DeviceMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | insert into device 8 | values (#{username}, #{ts}) 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/test/java/com/iot/ClientApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.iot; 2 | 3 | import com.iot.device.entity.Device; 4 | import com.iot.device.service.DeviceService; 5 | import org.junit.jupiter.api.Test; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | 9 | @SpringBootTest 10 | class ClientApplicationTests { 11 | 12 | @Autowired 13 | private DeviceService deviceService; 14 | 15 | @Test 16 | void contextLoads() { 17 | deviceService 18 | .updateDeviceStatus(new Device().setUsername("qbb").setTs(System.currentTimeMillis())); 19 | } 20 | 21 | } 22 | --------------------------------------------------------------------------------