Browse Source

功能完善

Yumin 5 years ago
parent
commit
dfc21f27ac

+ 7 - 0
pom.xml

@@ -152,6 +152,13 @@
             <artifactId>lombok</artifactId>
             <optional>true</optional>
         </dependency>
+
+        <!-- 腾讯云短信 -->
+        <dependency>
+            <groupId>com.github.qcloudsms</groupId>
+            <artifactId>qcloudsms</artifactId>
+            <version>1.0.6</version>
+        </dependency>
     </dependencies>
 
     <build>

+ 3 - 0
src/main/java/cn/minbb/iot/IoTServerApplication.java

@@ -1,14 +1,17 @@
 package cn.minbb.iot;
 
+import cn.minbb.iot.controller.UniqueNameGenerator;
 import org.springframework.boot.Banner;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.builder.SpringApplicationBuilder;
 import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import org.springframework.context.annotation.ComponentScan;
 import org.springframework.scheduling.annotation.EnableScheduling;
 
 @EnableScheduling
 @SpringBootApplication
+@ComponentScan(nameGenerator = UniqueNameGenerator.class)
 public class IoTServerApplication extends SpringBootServletInitializer {
 
     public static void main(String[] args) {

+ 2 - 0
src/main/java/cn/minbb/iot/config/Const.java

@@ -6,4 +6,6 @@ public class Const {
     public static final String MQTT_TOPIC_CAR = "iot.car";
     public static final String MQTT_TOPIC_CAR_DATA = "iot.car.data";
     public static final String MQTT_TOPIC_CAR_CTRL = "iot.car.ctrl";
+    public static final String MQTT_TOPIC_CAR_HEART = "iot.car.heart";
+    public static final String MQTT_TOPIC_CAR_ALARM = "iot.car.alarm";
 }

+ 27 - 2
src/main/java/cn/minbb/iot/config/MqttSenderConfig.java

@@ -1,6 +1,11 @@
 package cn.minbb.iot.config;
 
+import cn.minbb.iot.model.Device;
 import cn.minbb.iot.model.DeviceData;
+import cn.minbb.iot.model.User;
+import cn.minbb.iot.service.DeviceService;
+import cn.minbb.iot.service.SmsService;
+import cn.minbb.iot.service.UserService;
 import cn.minbb.iot.service.WebSocketService;
 import cn.minbb.iot.util.Application;
 import com.alibaba.fastjson.JSONObject;
@@ -49,6 +54,16 @@ public class MqttSenderConfig {
     @Value("${spring.mqtt.completionTimeout}")
     private int completionTimeout;
 
+    private SmsService smsService;
+    private UserService userService;
+    private DeviceService deviceService;
+
+    public MqttSenderConfig(SmsService smsService, UserService userService, DeviceService deviceService) {
+        this.smsService = smsService;
+        this.userService = userService;
+        this.deviceService = deviceService;
+    }
+
     @Bean
     public MqttConnectOptions getMqttConnectOptions() {
         MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
@@ -93,7 +108,8 @@ public class MqttSenderConfig {
     public MessageProducer inbound() {
         MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(
                 clientId + "_inbound", mqttClientFactory(), defaultTopic,
-                Const.MQTT_TOPIC_ALL, Const.MQTT_TOPIC_CAR, Const.MQTT_TOPIC_CAR_DATA);
+                Const.MQTT_TOPIC_ALL, Const.MQTT_TOPIC_CAR, Const.MQTT_TOPIC_CAR_DATA,
+                Const.MQTT_TOPIC_CAR_HEART, Const.MQTT_TOPIC_CAR_ALARM);
         adapter.setCompletionTimeout(completionTimeout);
         adapter.setConverter(new DefaultPahoMessageConverter());
         adapter.setQos(1);
@@ -109,7 +125,7 @@ public class MqttSenderConfig {
             Object object = message.getHeaders().get("mqtt_receivedTopic");
             String topic = null != object ? object.toString() : "";
             String msg = message.getPayload().toString();
-            logger.info("收到消息 = 主题 = {}  信息 = {}", topic, msg);
+            logger.info("收到消息 / 主题 = {}  信息 = {}", topic, msg);
             switch (topic) {
                 case Const.MQTT_TOPIC_CAR_DATA:
                     try {
@@ -127,6 +143,15 @@ public class MqttSenderConfig {
                         logger.info("非JSON格式字符串 | {}", e.getMessage());
                     }
                     break;
+                case Const.MQTT_TOPIC_CAR_ALARM:
+                    Device device = deviceService.findOneBySerialNumber(msg);
+                    if (null != device && null != device.getUserId()) {
+                        User user = userService.findUserById(device.getUserId());
+                        if (null != user && !user.getPhone().isEmpty()) {
+                            smsService.sendSingleSms(user.getPhone(), user.getName(), device.getName(), Application.getCurrentStringTime());
+                        }
+                    }
+                    break;
                 default:
             }
         };

+ 13 - 0
src/main/java/cn/minbb/iot/controller/UniqueNameGenerator.java

@@ -0,0 +1,13 @@
+package cn.minbb.iot.controller;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.context.annotation.AnnotationBeanNameGenerator;
+
+public class UniqueNameGenerator extends AnnotationBeanNameGenerator {
+    @Override
+    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
+        // 全限定类名
+        return definition.getBeanClassName();
+    }
+}

+ 84 - 0
src/main/java/cn/minbb/iot/controller/rest/DeviceController.java

@@ -0,0 +1,84 @@
+package cn.minbb.iot.controller.rest;
+
+import cn.minbb.iot.data.ResponseResult;
+import cn.minbb.iot.model.Device;
+import cn.minbb.iot.model.User;
+import cn.minbb.iot.service.DeviceService;
+import cn.minbb.iot.service.UserService;
+import com.alibaba.fastjson.JSONObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("device")
+public class DeviceController {
+
+    @Autowired
+    DeviceService deviceService;
+
+    @Autowired
+    UserService userService;
+
+    @PostMapping("search")
+    public ResponseResult<Device> search(@RequestBody String params) {
+        JSONObject jsonObject = JSONObject.parseObject(params);
+        Device device = deviceService.findOneBySerialNumber(jsonObject.getString("serial"));
+        if (device == null) {
+            return ResponseResult.create().success(false).message("没有查询到设备").dataNone();
+        }
+        return ResponseResult.create().success(true).message("OK").data(device);
+    }
+
+    @PostMapping("bind")
+    public ResponseResult<Device> bind(@RequestBody String params) {
+        JSONObject jsonObject = JSONObject.parseObject(params);
+        Device device = JSONObject.parseObject(jsonObject.getString("device"), Device.class);
+        User user = JSONObject.parseObject(jsonObject.getString("user"), User.class);
+        Device deviceServer = deviceService.findOneBySerialNumber(device.getSerialNumber());
+        User userServer = userService.findUserByUsername(user.getUsername());
+        if (userServer != null && deviceServer != null) {
+            if (deviceServer.getUserId() != null) {
+                return ResponseResult.create().success(false).message("设备已绑定").dataNone();
+            } else {
+                deviceServer.setUserId(userServer.getId());
+                return ResponseResult.create().success(true).message("OK").data(deviceService.save(deviceServer));
+            }
+        } else {
+            return ResponseResult.create().success(false).message("参数缺失").dataNone();
+        }
+    }
+
+    @PostMapping("all")
+    public ResponseResult<Device> all(@RequestBody String params) {
+        JSONObject jsonObject = JSONObject.parseObject(params);
+        User user = JSONObject.parseObject(jsonObject.getString("user"), User.class);
+        if (user == null) {
+            return ResponseResult.create().success(false).message("参数缺失").dataNone();
+        } else {
+            return ResponseResult.create().success(true).message("OK").dataset(deviceService.findAllByUserId(user.getId()));
+        }
+    }
+
+    @PostMapping("unbind")
+    public ResponseResult<Device> unbind(@RequestBody String params) {
+        JSONObject jsonObject = JSONObject.parseObject(params);
+        Device device = JSONObject.parseObject(jsonObject.getString("device"), Device.class);
+        User user = JSONObject.parseObject(jsonObject.getString("user"), User.class);
+        Device deviceServer = deviceService.findOneBySerialNumber(device.getSerialNumber());
+        User userServer = userService.findUserByUsername(user.getUsername());
+        if (userServer != null && deviceServer != null) {
+            if (deviceServer.getUserId() != null) {
+                deviceServer.setUserId(null);
+                deviceService.save(deviceServer);
+                return ResponseResult.create().success(true).message("解绑设备" + deviceServer.getSerialNumber() + "成功").dataNone();
+            } else {
+                return ResponseResult.create().success(false).message("设备未绑定").dataNone();
+            }
+        } else {
+            return ResponseResult.create().success(false).message("参数缺失").dataNone();
+        }
+    }
+}

+ 13 - 3
src/main/java/cn/minbb/iot/model/Device.java

@@ -22,6 +22,11 @@ public class Device implements Serializable {
     @Column(name = "id", nullable = false, columnDefinition = "INT COMMENT '设备实体ID'")
     private Integer id;
 
+    @Getter
+    @Setter
+    @Column(name = "image", nullable = false, columnDefinition = "VARCHAR(512) COMMENT '名称'")
+    private String image;
+
     @Getter
     @Setter
     @Column(name = "name", nullable = false, columnDefinition = "VARCHAR(64) COMMENT '名称'")
@@ -34,8 +39,13 @@ public class Device implements Serializable {
 
     @Getter
     @Setter
-    @Column(name = "user_id", nullable = false, columnDefinition = "BIGINT COMMENT '关联用户'")
-    private Long userId;
+    @Column(name = "is_enabled", nullable = false, columnDefinition = "TINYINT DEFAULT '1' COMMENT '启用'")
+    private Boolean isEnabled;
+
+    @Getter
+    @Setter
+    @Column(name = "user_id", columnDefinition = "INT COMMENT '关联用户'")
+    private Integer userId;
 
     @Getter
     @Setter
@@ -50,6 +60,6 @@ public class Device implements Serializable {
     private Date updatedAt;
 
     @Version
-    @Column(name = "version", columnDefinition = "BIGINT COMMENT '版本号'")
+    @Column(name = "version", columnDefinition = "INT COMMENT '版本号'")
     public Integer version;
 }

+ 1 - 1
src/main/java/cn/minbb/iot/model/DeviceData.java

@@ -63,7 +63,7 @@ public class DeviceData implements Serializable {
 
     @Getter
     @Setter
-    @Column(name = "device_id", nullable = false, columnDefinition = "BIGINT COMMENT '关联设备'")
+    @Column(name = "device_id", nullable = false, columnDefinition = "INT COMMENT '关联设备'")
     private Long deviceId;
 
     @Getter

+ 6 - 0
src/main/java/cn/minbb/iot/model/repository/DeviceRepository.java

@@ -1,7 +1,13 @@
 package cn.minbb.iot.model.repository;
 
 import cn.minbb.iot.model.Device;
+import org.springframework.data.domain.Sort;
 import org.springframework.data.jpa.repository.JpaRepository;
 
+import java.util.List;
+
 public interface DeviceRepository extends JpaRepository<Device, Integer> {
+    Device findOneBySerialNumber(String serialNumber);
+
+    List<Device> findAllByUserId(Integer userId, Sort sort);
 }

+ 2 - 0
src/main/java/cn/minbb/iot/model/repository/UserRepository.java

@@ -4,5 +4,7 @@ import cn.minbb.iot.model.User;
 import org.springframework.data.jpa.repository.JpaRepository;
 
 public interface UserRepository extends JpaRepository<User, Integer> {
+    User findOneById(Integer id);
+
     User findOneByUsername(String username);
 }

+ 9 - 0
src/main/java/cn/minbb/iot/service/DeviceService.java

@@ -1,4 +1,13 @@
 package cn.minbb.iot.service;
 
+import cn.minbb.iot.model.Device;
+
+import java.util.List;
+
 public interface DeviceService {
+    Device save(Device device);
+
+    Device findOneBySerialNumber(String serialNumber);
+
+    List<Device> findAllByUserId(Integer userId);
 }

+ 84 - 0
src/main/java/cn/minbb/iot/service/SmsService.java

@@ -0,0 +1,84 @@
+package cn.minbb.iot.service;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.qcloudsms.SmsMultiSender;
+import com.github.qcloudsms.SmsMultiSenderResult;
+import com.github.qcloudsms.SmsSingleSender;
+import com.github.qcloudsms.SmsSingleSenderResult;
+import com.github.qcloudsms.httpclient.HTTPException;
+import org.json.JSONException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+
+/**
+ * 腾讯云短信服务
+ */
+@Service
+public class SmsService {
+
+    private static Logger logger = LoggerFactory.getLogger(SmsService.class);
+
+    private final ObjectMapper objectMapper;
+
+    // 短信应用SDK AppID
+    private int appid = 1400220297;
+    // 短信应用SDK AppKey
+    private String appkey = "271645b0861c24747aa83e27085e022d";
+    // 短信模板ID
+    private int templateId = 350485;
+    // 签名 NOTE: 签名需要在短信控制台中申请,签名参数使用的是`签名内容`,而不是`签名ID`
+    private String smsSign = "王育民开发";
+
+    @Autowired
+    public SmsService(ObjectMapper objectMapper) {
+        this.objectMapper = objectMapper;
+    }
+
+    /**
+     * 指定模板 ID 单发短信
+     *
+     * @param phoneNumber
+     * @param name
+     * @param date
+     * @param deviceName
+     * @return
+     */
+    public boolean sendSingleSms(String phoneNumber, String name, String deviceName, String date) {
+        boolean success = false;
+        try {
+            // 设备报警提醒:尊敬的用户{1}您好,您所绑定的设备{2}于{3}触发了报警装置,请您及时关注并检查设备状态。
+            String[] params = {name, deviceName, date};
+            SmsSingleSender sender = new SmsSingleSender(appid, appkey);
+            SmsSingleSenderResult result = sender.sendWithParam("86", phoneNumber, templateId, params, smsSign, "", "");
+            logger.info("发送短信 = {}", objectMapper.writeValueAsString(result));
+            if (result != null) {
+                success = true;
+            }
+        } catch (HTTPException | JSONException | IOException e) {
+            // HTTP响应码错误 | JSON解析错误 | 网络IO错误
+            logger.error("{} - {}", e.getCause(), e.getMessage());
+        }
+        return success;
+    }
+
+    /**
+     * 指定模板 ID 群发短信
+     *
+     * @param phoneNumbers
+     */
+    public void sendMSms(String[] phoneNumbers) {
+        try {
+            String[] params = {"5678"};//数组具体的元素个数和模板中变量个数必须一致,例如事例中templateId:5678对应一个变量,参数数组中元素个数也必须是一个
+            SmsMultiSender sender = new SmsMultiSender(appid, appkey);
+            SmsMultiSenderResult result = sender.sendWithParam("86", phoneNumbers, templateId, params, smsSign, "", "");  // 签名参数未提供或者为空时,会使用默认签名发送短信
+            logger.info("提醒短信发送成功 = {}", objectMapper.writeValueAsString(result));
+        } catch (HTTPException | JSONException | IOException e) {
+            // HTTP响应码错误 | JSON解析错误 | 网络IO错误
+            logger.error("{} - {}", e.getCause(), e.getMessage());
+        }
+    }
+}

+ 2 - 0
src/main/java/cn/minbb/iot/service/UserService.java

@@ -6,5 +6,7 @@ import org.springframework.security.core.userdetails.UserDetailsService;
 public interface UserService extends UserDetailsService {
     User saveOne(User user);
 
+    User findUserById(Integer id);
+
     User findUserByUsername(String username);
 }

+ 28 - 2
src/main/java/cn/minbb/iot/service/impl/ConsumeCallBackImpl.java

@@ -1,11 +1,37 @@
 package cn.minbb.iot.service.impl;
 
+import cn.minbb.iot.config.Const;
 import cn.minbb.iot.service.ConsumeCallback;
+import cn.minbb.iot.service.DeviceService;
+import cn.minbb.iot.service.SmsService;
+import cn.minbb.iot.service.UserService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
 
+@Service
 public class ConsumeCallBackImpl implements ConsumeCallback {
+
+    private Logger logger = LoggerFactory.getLogger(ConsumeCallBackImpl.class);
+    private SmsService smsService;
+    private UserService userService;
+    private DeviceService deviceService;
+
+    @Autowired
+    public ConsumeCallBackImpl(SmsService smsService, UserService userService, DeviceService deviceService) {
+        this.smsService = smsService;
+        this.userService = userService;
+        this.deviceService = deviceService;
+    }
+
     @Override
     public void onReceived(String topic, String message) {
-        System.out.println("topic:" + topic);
-        System.out.println("message:" + message);
+        logger.info("收到消息 / 主题 = {}, 信息 = {}", topic, message);
+        switch (topic) {
+            case Const.MQTT_TOPIC_CAR_ALARM:
+
+                break;
+        }
     }
 }

+ 24 - 0
src/main/java/cn/minbb/iot/service/impl/DeviceServiceImpl.java

@@ -1,8 +1,32 @@
 package cn.minbb.iot.service.impl;
 
+import cn.minbb.iot.model.Device;
+import cn.minbb.iot.model.repository.DeviceRepository;
 import cn.minbb.iot.service.DeviceService;
+import cn.minbb.iot.util.SortTools;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.List;
+
 @Service
 public class DeviceServiceImpl implements DeviceService {
+
+    @Autowired
+    DeviceRepository deviceRepository;
+
+    @Override
+    public Device save(Device device) {
+        return deviceRepository.save(device);
+    }
+
+    @Override
+    public Device findOneBySerialNumber(String serialNumber) {
+        return serialNumber == null ? null : deviceRepository.findOneBySerialNumber(serialNumber);
+    }
+
+    @Override
+    public List<Device> findAllByUserId(Integer userId) {
+        return deviceRepository.findAllByUserId(userId, SortTools.basicSort("desc", "updatedAt"));
+    }
 }

+ 5 - 0
src/main/java/cn/minbb/iot/service/impl/UserServiceImpl.java

@@ -31,6 +31,11 @@ public class UserServiceImpl implements UserService {
         return userRepository.save(user);
     }
 
+    @Override
+    public User findUserById(Integer id) {
+        return null == id ? null : userRepository.findOneById(id);
+    }
+
     @Override
     public User findUserByUsername(String username) {
         return null == username ? null : userRepository.findOneByUsername(username);

+ 3 - 3
src/main/resources/application-pro.properties

@@ -1,6 +1,6 @@
 # Éú²ú»·¾³
 server.servlet.context-path=
 # MySQL
-spring.datasource.url=jdbc:mysql://www.minbb.cn:3306/iot?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT
-spring.datasource.username=Yumin
-spring.datasource.password=Wang19970305
+spring.datasource.url=jdbc:mysql://rm-uf64guljnha668n05io.mysql.rds.aliyuncs.com:3306/iot?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
+spring.datasource.username=root
+spring.datasource.password=Yumin1997

+ 1 - 1
src/main/resources/application.properties

@@ -1,6 +1,6 @@
 server.port=80
 # Ö¸¶¨ÔËÐл·¾³
-spring.profiles.active=dev
+spring.profiles.active=pro
 server.servlet.context-path=
 spring.mvc.favicon.enabled=true
 spring.http.encoding.charset=UTF-8

BIN
src/main/resources/static/images/clouds.png


BIN
src/main/resources/static/images/index-background.jpg


File diff suppressed because it is too large
+ 25 - 909
src/main/resources/templates/index.html


Some files were not shown because too many files changed in this diff