浏览代码

首次提交

wuweihao 5 年之前
父节点
当前提交
bbc6afa84d
共有 100 个文件被更改,包括 7381 次插入2 次删除
  1. 8 2
      README.md
  2. 178 0
      jm-smart-city.sql
  3. 369 0
      pom.xml
  4. 58 0
      wsm-admin-dao/pom.xml
  5. 16 0
      wsm-admin-dao/src/main/java/com/wsm/admin/dao/IDataDictionaryDao.java
  6. 13 0
      wsm-admin-dao/src/main/java/com/wsm/admin/dao/IDeviceDao.java
  7. 26 0
      wsm-admin-dao/src/main/java/com/wsm/admin/dao/IDeviceEventDao.java
  8. 12 0
      wsm-admin-dao/src/main/java/com/wsm/admin/dao/IResourceDao.java
  9. 12 0
      wsm-admin-dao/src/main/java/com/wsm/admin/dao/IRoleDao.java
  10. 16 0
      wsm-admin-dao/src/main/java/com/wsm/admin/dao/IUserDao.java
  11. 15 0
      wsm-admin-dao/src/main/java/com/wsm/admin/mapper/ResourceMapper.java
  12. 9 0
      wsm-admin-dao/src/main/java/com/wsm/admin/mapper/RoleMapper.java
  13. 10 0
      wsm-admin-dao/src/main/java/com/wsm/admin/mapper/UserMapper.java
  14. 88 0
      wsm-admin-dao/src/main/java/com/wsm/admin/model/DataDictionary.java
  15. 125 0
      wsm-admin-dao/src/main/java/com/wsm/admin/model/Device.java
  16. 82 0
      wsm-admin-dao/src/main/java/com/wsm/admin/model/DeviceEvent.java
  17. 105 0
      wsm-admin-dao/src/main/java/com/wsm/admin/model/Resource.java
  18. 63 0
      wsm-admin-dao/src/main/java/com/wsm/admin/model/Role.java
  19. 83 0
      wsm-admin-dao/src/main/java/com/wsm/admin/model/User.java
  20. 35 0
      wsm-admin-service/pom.xml
  21. 138 0
      wsm-admin-service/src/main/java/com/wsm/admin/dto/ResourceTree.java
  22. 36 0
      wsm-admin-service/src/main/java/com/wsm/admin/service/IDataDictionaryService.java
  23. 22 0
      wsm-admin-service/src/main/java/com/wsm/admin/service/IDeviceEventService.java
  24. 11 0
      wsm-admin-service/src/main/java/com/wsm/admin/service/IDeviceService.java
  25. 20 0
      wsm-admin-service/src/main/java/com/wsm/admin/service/IResourceService.java
  26. 14 0
      wsm-admin-service/src/main/java/com/wsm/admin/service/IRoleService.java
  27. 18 0
      wsm-admin-service/src/main/java/com/wsm/admin/service/IUserService.java
  28. 59 0
      wsm-admin-service/src/main/java/com/wsm/admin/service/impl/DataDictionaryServiceImpl.java
  29. 41 0
      wsm-admin-service/src/main/java/com/wsm/admin/service/impl/DeviceEventServiceImpl.java
  30. 31 0
      wsm-admin-service/src/main/java/com/wsm/admin/service/impl/DeviceServiceImpl.java
  31. 75 0
      wsm-admin-service/src/main/java/com/wsm/admin/service/impl/ResourceServiceImpl.java
  32. 39 0
      wsm-admin-service/src/main/java/com/wsm/admin/service/impl/RoleServiceImpl.java
  33. 51 0
      wsm-admin-service/src/main/java/com/wsm/admin/service/impl/UserServiceImpl.java
  34. 102 0
      wsm-admin-service/src/main/java/com/wsm/admin/util/ResourceTreeUtil.java
  35. 66 0
      wsm-admin-web/pom.xml
  36. 249 0
      wsm-admin-web/src/main/java/com/wsm/admin/api/ApiDeviceController.java
  37. 89 0
      wsm-admin-web/src/main/java/com/wsm/admin/api/DataDictionaryController.java
  38. 123 0
      wsm-admin-web/src/main/java/com/wsm/admin/api/DeviceController.java
  39. 123 0
      wsm-admin-web/src/main/java/com/wsm/admin/api/DeviceEventController.java
  40. 81 0
      wsm-admin-web/src/main/java/com/wsm/admin/api/FileController.java
  41. 87 0
      wsm-admin-web/src/main/java/com/wsm/admin/api/IndexController.java
  42. 71 0
      wsm-admin-web/src/main/java/com/wsm/admin/api/KaptchaController.java
  43. 111 0
      wsm-admin-web/src/main/java/com/wsm/admin/api/LiveController.java
  44. 160 0
      wsm-admin-web/src/main/java/com/wsm/admin/api/ResourceController.java
  45. 133 0
      wsm-admin-web/src/main/java/com/wsm/admin/api/RoleController.java
  46. 32 0
      wsm-admin-web/src/main/java/com/wsm/admin/api/TestController.java
  47. 211 0
      wsm-admin-web/src/main/java/com/wsm/admin/api/UserController.java
  48. 9 0
      wsm-admin-web/src/main/java/com/wsm/admin/constant/MsgCode.java
  49. 262 0
      wsm-admin-web/src/main/java/com/wsm/admin/handle/UdpServerHandler.java
  50. 41 0
      wsm-admin-web/src/main/java/com/wsm/admin/init/StartupUdpEvent.java
  51. 86 0
      wsm-admin-web/src/main/java/com/wsm/admin/init/TaskSchedule.java
  52. 251 0
      wsm-admin-web/src/main/java/com/wsm/admin/init/TcpServer.java
  53. 46 0
      wsm-admin-web/src/main/java/com/wsm/admin/init/UdpServer.java
  54. 85 0
      wsm-admin-web/src/main/java/com/wsm/admin/mqtt/ClientMQTT.java
  55. 149 0
      wsm-admin-web/src/main/java/com/wsm/admin/mqtt/PushCallback.java
  56. 36 0
      wsm-admin-web/src/main/java/com/wsm/admin/mqtt/TopicCode.java
  57. 89 0
      wsm-admin-web/src/main/java/com/wsm/admin/shiro/MyShiroRealm.java
  58. 139 0
      wsm-admin-web/src/main/java/com/wsm/admin/shiro/ShiroConfig.java
  59. 60 0
      wsm-admin-web/src/main/java/com/wsm/admin/tcp/NettyServer.java
  60. 83 0
      wsm-admin-web/src/main/java/com/wsm/admin/tcp/init/ConvertData.java
  61. 62 0
      wsm-admin-web/src/main/java/com/wsm/admin/tcp/init/CoverTcpServer.java
  62. 285 0
      wsm-admin-web/src/main/java/com/wsm/admin/tcp/init/NettyServerHandler.java
  63. 39 0
      wsm-admin-web/src/main/java/com/wsm/admin/tcp/init/Rule.java
  64. 42 0
      wsm-admin-web/src/main/java/com/wsm/admin/thread/TaskExecutePool.java
  65. 59 0
      wsm-admin-web/src/main/resources/static/css/login.css
  66. 45 0
      wsm-admin-web/src/main/resources/static/css/main.css
  67. 二进制
      wsm-admin-web/src/main/resources/static/css/metroStyle/img/line_conn.png
  68. 二进制
      wsm-admin-web/src/main/resources/static/css/metroStyle/img/loading.gif
  69. 二进制
      wsm-admin-web/src/main/resources/static/css/metroStyle/img/metro.gif
  70. 二进制
      wsm-admin-web/src/main/resources/static/css/metroStyle/img/metro.png
  71. 383 0
      wsm-admin-web/src/main/resources/static/css/metroStyle/metroStyle.css
  72. 78 0
      wsm-admin-web/src/main/resources/static/css/public.css
  73. 二进制
      wsm-admin-web/src/main/resources/static/img/avater.jpg
  74. 二进制
      wsm-admin-web/src/main/resources/static/img/cloud10.png
  75. 二进制
      wsm-admin-web/src/main/resources/static/img/favicon.ico
  76. 二进制
      wsm-admin-web/src/main/resources/static/img/lockBg.jpg
  77. 66 0
      wsm-admin-web/src/main/resources/static/js/Detector.js
  78. 19 0
      wsm-admin-web/src/main/resources/static/js/index.js
  79. 2 0
      wsm-admin-web/src/main/resources/static/js/jquery.min.js
  80. 165 0
      wsm-admin-web/src/main/resources/static/js/jquery.ztree.all.min.js
  81. 103 0
      wsm-admin-web/src/main/resources/static/js/map.js
  82. 699 0
      wsm-admin-web/src/main/resources/static/js/three.min.js
  83. 189 0
      wsm-admin-web/src/main/resources/static/plugins/diyUpload/css/diyUpload.css
  84. 45 0
      wsm-admin-web/src/main/resources/static/plugins/diyUpload/css/webuploader.css
  85. 二进制
      wsm-admin-web/src/main/resources/static/plugins/diyUpload/images/bgblack.png
  86. 二进制
      wsm-admin-web/src/main/resources/static/plugins/diyUpload/images/check_alt.png
  87. 二进制
      wsm-admin-web/src/main/resources/static/plugins/diyUpload/images/x_alt.png
  88. 236 0
      wsm-admin-web/src/main/resources/static/plugins/diyUpload/js/diyUpload.js
  89. 2 0
      wsm-admin-web/src/main/resources/static/plugins/diyUpload/js/webuploader.js
  90. 2 0
      wsm-admin-web/src/main/resources/static/plugins/layui/css/layui.css
  91. 2 0
      wsm-admin-web/src/main/resources/static/plugins/layui/css/layui.mobile.css
  92. 2 0
      wsm-admin-web/src/main/resources/static/plugins/layui/css/modules/code.css
  93. 2 0
      wsm-admin-web/src/main/resources/static/plugins/layui/css/modules/laydate/default/laydate.css
  94. 二进制
      wsm-admin-web/src/main/resources/static/plugins/layui/css/modules/layer/default/icon-ext.png
  95. 二进制
      wsm-admin-web/src/main/resources/static/plugins/layui/css/modules/layer/default/icon.png
  96. 2 0
      wsm-admin-web/src/main/resources/static/plugins/layui/css/modules/layer/default/layer.css
  97. 二进制
      wsm-admin-web/src/main/resources/static/plugins/layui/css/modules/layer/default/loading-0.gif
  98. 二进制
      wsm-admin-web/src/main/resources/static/plugins/layui/css/modules/layer/default/loading-1.gif
  99. 二进制
      wsm-admin-web/src/main/resources/static/plugins/layui/css/modules/layer/default/loading-2.gif
  100. 0 0
      wsm-admin-web/src/main/resources/static/plugins/layui/font/iconfont.eot

+ 8 - 2
README.md

@@ -1,3 +1,9 @@
-# jm_smart_city
+江门市智慧城市管理系统(一平方公里,传感器)
 
-江门智慧城市一平方公里(传感器)
+问题
+1. 当警情超过24小时没有处理,传感器又没有心跳,心跳检测会把当前传感器设置为离线状态。
+
+
+# dev
+ 公网访问:
+ 221.4.210.172:2001/api/device/cover

+ 178 - 0
jm-smart-city.sql

@@ -0,0 +1,178 @@
+/*
+Navicat MySQL Data Transfer
+
+Source Server         : localhost
+Source Server Version : 50720
+Source Host           : localhost:3306
+Source Database       : mood-wall
+
+Target Server Type    : MYSQL
+Target Server Version : 50720
+File Encoding         : 65001
+
+Date: 2018-12-04 11:25:29
+*/
+
+SET FOREIGN_KEY_CHECKS=0;
+
+-- ----------------------------
+-- Table structure for tb_data_dictionary
+-- ----------------------------
+DROP TABLE IF EXISTS `tb_data_dictionary`;
+CREATE TABLE `tb_data_dictionary` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
+  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+  `rec_status` varchar(2) DEFAULT NULL COMMENT '记录的状态,A: 生效,I: 禁用',
+  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+  `code` varchar(24) DEFAULT NULL COMMENT '数据字典code',
+  `data_key` varchar(255) DEFAULT NULL COMMENT '数据字典key',
+  `data_value` varchar(255) DEFAULT NULL COMMENT '数据字典value',
+  `description` varchar(255) DEFAULT NULL COMMENT '描述',
+  `param1` varchar(255) DEFAULT NULL COMMENT '备用,参数1',
+  `param2` varchar(255) DEFAULT NULL COMMENT '备用,参数2',
+  `param3` varchar(255) DEFAULT NULL COMMENT '备用,参数3',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据字典表';
+
+-- ----------------------------
+-- Records of tb_data_dictionary
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for tb_resource
+-- ----------------------------
+DROP TABLE IF EXISTS `tb_resource`;
+CREATE TABLE `tb_resource` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
+  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+  `description` varchar(255) DEFAULT NULL COMMENT '资源描述',
+  `icon` varchar(10) DEFAULT NULL COMMENT '图标',
+  `name` varchar(50) DEFAULT NULL COMMENT '资源名称',
+  `url` varchar(255) DEFAULT NULL COMMENT '资源地址',
+  `parent_id` bigint(20) DEFAULT NULL COMMENT '父资源id',
+  `resource_type` enum('menu','button') DEFAULT NULL COMMENT '资源类型',
+  `resource_key` varchar(255) DEFAULT NULL COMMENT '资源key',
+  `rec_status` varchar(2) DEFAULT NULL COMMENT '记录的状态,A: 生效,I: 禁用',
+  `sort` tinyint(4) DEFAULT NULL COMMENT '排序',
+  PRIMARY KEY (`id`),
+  KEY `FKf5ra2gn0xedeida2op8097sr5` (`parent_id`),
+  CONSTRAINT `FKf5ra2gn0xedeida2op8097sr5` FOREIGN KEY (`parent_id`) REFERENCES `tb_resource` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COMMENT='资源表';
+
+-- ----------------------------
+-- Records of tb_resource
+-- ----------------------------
+INSERT INTO `tb_resource` VALUES ('1', '2018-05-10 17:18:36', '2018-05-10 17:22:42', null, '&#xe716', '系统管理', 'javascript:void(0);', null, 'menu', 'system', 'A', '1');
+INSERT INTO `tb_resource` VALUES ('2', '2018-05-11 10:05:41', '2018-12-04 11:22:02', null, '&#xe66f', '用户管理', '/admin/user/list', '1', 'menu', 'admin:user:list', 'A', '2');
+INSERT INTO `tb_resource` VALUES ('3', '2018-05-14 09:38:43', '2018-05-14 09:38:46', null, '&#xe66f', '用户添加', '/admin/user/add', '2', 'button', 'admin:user:add', 'A', '3');
+INSERT INTO `tb_resource` VALUES ('4', '2018-05-14 10:46:32', '2018-05-14 10:46:36', null, '&#xe66f', '用户编辑', '/admin/user/edit', '2', 'button', 'admin:user:edit', 'A', '4');
+INSERT INTO `tb_resource` VALUES ('5', '2018-05-14 12:03:20', '2018-05-14 12:03:30', null, '&#xe66f', '用户重置密码', '/admin/user/resetPass', '2', 'button', 'admin:user:resetPass', 'A', '5');
+INSERT INTO `tb_resource` VALUES ('6', '2018-05-14 14:08:16', '2018-05-14 14:08:20', null, '&#xe66f', '用户删除', '/admin/user/remove', '2', 'button', 'admin:user:remove', 'A', '6');
+INSERT INTO `tb_resource` VALUES ('7', '2018-05-14 14:09:07', '2018-05-14 14:09:10', null, '&#xe770', '角色管理', '/admin/role/list', '1', 'menu', 'admin:role:list', 'A', '7');
+INSERT INTO `tb_resource` VALUES ('8', '2018-05-14 15:06:59', '2018-05-14 15:07:01', null, '&#xe770', '角色添加', '/admin/role/add', '7', 'button', 'admin:role:add', 'A', '8');
+INSERT INTO `tb_resource` VALUES ('9', '2018-05-14 15:06:59', '2018-05-14 15:07:01', null, '&#xe770', '角色编辑', '/admin/role/edit', '7', 'button', 'admin:role:edit', 'A', '9');
+INSERT INTO `tb_resource` VALUES ('10', '2018-05-14 15:08:06', '2018-05-14 15:08:08', null, '&#xe770', '角色删除', '/admin/role/remove', '7', 'button', 'admin:role:remove', 'A', '10');
+INSERT INTO `tb_resource` VALUES ('11', '2018-05-14 15:08:06', '2018-05-14 15:08:08', null, '&#xe671', '资源管理', '/admin/resource/list', '1', 'menu', 'admin:resource:list', 'A', '11');
+INSERT INTO `tb_resource` VALUES ('12', '2018-05-15 09:51:49', '2018-05-15 09:51:51', null, '&#xe671', '资源添加', '/admin/resource/add', '11', 'button', 'admin:resource:add', 'A', '12');
+INSERT INTO `tb_resource` VALUES ('13', '2018-05-15 09:51:49', '2018-05-15 09:51:51', null, '&#xe671', '资源编辑', '/admin/resource/edit', '11', 'button', 'admin:resource:edit', 'A', '13');
+INSERT INTO `tb_resource` VALUES ('14', '2018-05-15 09:51:49', '2018-12-04 11:20:29', null, '&#xe671', '资源删除', '/admin/resource/remove', '11', 'button', 'admin:resource:remove', 'A', '14');
+INSERT INTO `tb_resource` VALUES ('15', '2018-07-27 16:30:51', '2018-07-27 16:30:51', null, '&#xe66e', '数据字典管理', '/admin/dataDictionary/list', '1', 'menu', 'admin:dataDictionary:list', 'A', '40');
+INSERT INTO `tb_resource` VALUES ('16', '2018-07-27 16:31:57', '2018-07-27 16:31:57', null, '&#xe66e', '数据字典添加', '/admin/dataDictionary/add', '15', 'button', 'admin:dataDictionary:add', 'A', '41');
+INSERT INTO `tb_resource` VALUES ('17', '2018-07-27 16:35:59', '2018-07-27 16:35:59', null, '&#xe66e', '数据字典编辑', '/admin/dataDictionary/edit', '15', 'button', 'admin:dataDictionary:edit', 'A', '42');
+INSERT INTO `tb_resource` VALUES ('18', '2018-07-27 16:36:56', '2018-07-27 16:36:56', null, '&#xe66e', '数据字典删除', '/admin/dataDictionary/remove', '15', 'button', 'admin:dataDictionary:remove', 'A', '43');
+
+-- ----------------------------
+-- Table structure for tb_role
+-- ----------------------------
+DROP TABLE IF EXISTS `tb_role`;
+CREATE TABLE `tb_role` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
+  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+  `role_desc` varchar(255) DEFAULT NULL COMMENT '角色描述',
+  `role_name` varchar(50) DEFAULT NULL COMMENT '角色名',
+  `role_key` varchar(255) DEFAULT NULL COMMENT '角色key',
+  `rec_status` varchar(2) DEFAULT NULL COMMENT '记录的状态,A: 生效,I: 禁用',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色表';
+
+-- ----------------------------
+-- Records of tb_role
+-- ----------------------------
+INSERT INTO `tb_role` VALUES ('1', '2018-05-11 10:02:27', '2018-12-04 10:50:43', '超级管理员', '超级管理员', 'administrator', 'A');
+
+-- ----------------------------
+-- Table structure for tb_role_resource
+-- ----------------------------
+DROP TABLE IF EXISTS `tb_role_resource`;
+CREATE TABLE `tb_role_resource` (
+  `role_id` bigint(20) NOT NULL COMMENT '角色表id',
+  `resource_id` bigint(20) NOT NULL COMMENT '资源表id',
+  PRIMARY KEY (`role_id`,`resource_id`),
+  KEY `FK868kc8iic48ilv5npa80ut6qo` (`resource_id`),
+  CONSTRAINT `FK7ffc7h6obqxflhj1aq1mk20jk` FOREIGN KEY (`role_id`) REFERENCES `tb_role` (`id`),
+  CONSTRAINT `FK868kc8iic48ilv5npa80ut6qo` FOREIGN KEY (`resource_id`) REFERENCES `tb_resource` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色资源关系表';
+
+-- ----------------------------
+-- Records of tb_role_resource
+-- ----------------------------
+INSERT INTO `tb_role_resource` VALUES ('1', '1');
+INSERT INTO `tb_role_resource` VALUES ('1', '2');
+INSERT INTO `tb_role_resource` VALUES ('1', '3');
+INSERT INTO `tb_role_resource` VALUES ('1', '4');
+INSERT INTO `tb_role_resource` VALUES ('1', '5');
+INSERT INTO `tb_role_resource` VALUES ('1', '6');
+INSERT INTO `tb_role_resource` VALUES ('1', '7');
+INSERT INTO `tb_role_resource` VALUES ('1', '8');
+INSERT INTO `tb_role_resource` VALUES ('1', '9');
+INSERT INTO `tb_role_resource` VALUES ('1', '10');
+INSERT INTO `tb_role_resource` VALUES ('1', '11');
+INSERT INTO `tb_role_resource` VALUES ('1', '12');
+INSERT INTO `tb_role_resource` VALUES ('1', '13');
+INSERT INTO `tb_role_resource` VALUES ('1', '14');
+INSERT INTO `tb_role_resource` VALUES ('1', '15');
+INSERT INTO `tb_role_resource` VALUES ('1', '16');
+INSERT INTO `tb_role_resource` VALUES ('1', '17');
+INSERT INTO `tb_role_resource` VALUES ('1', '18');
+
+-- ----------------------------
+-- Table structure for tb_user
+-- ----------------------------
+DROP TABLE IF EXISTS `tb_user`;
+CREATE TABLE `tb_user` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
+  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+  `rec_status` varchar(2) DEFAULT NULL COMMENT '记录的状态,A: 生效,I: 禁用',
+  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+  `password` varchar(100) DEFAULT NULL COMMENT '登录密码',
+  `real_name` varchar(50) DEFAULT NULL COMMENT '真实姓名',
+  `user_name` varchar(50) DEFAULT NULL COMMENT '用户名',
+  `avatar` varchar(255) DEFAULT NULL COMMENT '头像地址',
+  `status` tinyint(4) DEFAULT NULL COMMENT '状态,0:激活,1:禁用',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='用户表';
+
+-- ----------------------------
+-- Records of tb_user
+-- ----------------------------
+INSERT INTO `tb_user` VALUES ('1', '2018-05-10 15:12:42', 'A', '2018-12-04 10:58:51', '8ca1e641c2bc5040', '超级管理员', 'admin', '/img/avater.jpg', '0');
+
+-- ----------------------------
+-- Table structure for tb_user_role
+-- ----------------------------
+DROP TABLE IF EXISTS `tb_user_role`;
+CREATE TABLE `tb_user_role` (
+  `user_id` bigint(20) NOT NULL COMMENT '用户表id',
+  `role_id` bigint(20) NOT NULL COMMENT '角色表id',
+  PRIMARY KEY (`user_id`,`role_id`),
+  KEY `FKea2ootw6b6bb0xt3ptl28bymv` (`role_id`),
+  CONSTRAINT `FK7vn3h53d0tqdimm8cp45gc0kl` FOREIGN KEY (`user_id`) REFERENCES `tb_user` (`id`),
+  CONSTRAINT `FKea2ootw6b6bb0xt3ptl28bymv` FOREIGN KEY (`role_id`) REFERENCES `tb_role` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户角色关系表';
+
+-- ----------------------------
+-- Records of tb_user_role
+-- ----------------------------
+INSERT INTO `tb_user_role` VALUES ('1', '1');

+ 369 - 0
pom.xml

@@ -0,0 +1,369 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.wsm</groupId>
+    <artifactId>wsm-base</artifactId>
+    <version>1.0.0</version>
+    <packaging>pom</packaging>
+
+    <name>wsm-base</name>
+    <description>wsm base project</description>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>1.5.12.RELEASE</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+
+    <!-- 模块说明:这里声明多个子模块 -->
+    <modules>
+        <module>wsm-application</module>
+        <module>wsm-common</module>
+        <module>wsm-admin-web</module>
+        <module>wsm-admin-service</module>
+        <module>wsm-admin-dao</module>
+    </modules>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <java.version>1.8</java.version>
+        <wsm.version>1.0.0</wsm.version>
+        <!-- 在properties中统一控制依赖包的版本,更清晰-->
+        <nekohtml.version>1.9.22</nekohtml.version>
+        <thymeleaf.shiro.version>1.0.2</thymeleaf.shiro.version>
+        <spring.mybatis.version>1.3.2</spring.mybatis.version>
+        <tk.mybatis.version>2.0.2</tk.mybatis.version>
+        <mysql.version>5.1.46</mysql.version>
+        <druid.version>1.0.15</druid.version>
+        <kaptcha.version>2.3.2</kaptcha.version>
+        <lombok.version>1.16.20</lombok.version>
+        <commons-lang3.version>3.3.2</commons-lang3.version>
+        <fastjson.version>1.2.15</fastjson.version>
+        <shiro.version>1.2.4</shiro.version>
+        <spring.boot.version>1.5.12.RELEASE</spring.boot.version>
+        <redis.version>2.0.0.RELEASE</redis.version>
+        <jackson.version>2.9.2</jackson.version>
+        <httpclient.version>4.5.3</httpclient.version>
+        <commons.codec.version>1.10</commons.codec.version>
+        <javax.servlet-api.version>3.1.0</javax.servlet-api.version>
+        <jedis.version>2.9.0</jedis.version>
+        <eureka.version>1.4.0.RELEASE</eureka.version>
+        <feign.version>1.4.0.RELEASE</feign.version>
+        <spring-cloud.version>Dalston.SR3</spring-cloud.version>
+        <swagger-annotations.version>1.5.13</swagger-annotations.version>
+        <feign-httpclient.version>8.18.0</feign-httpclient.version>
+        <feign-jackson.version>8.18.0</feign-jackson.version>
+        <joda-time.version>2.9.9</joda-time.version>
+        <zxing.version>2.1</zxing.version>
+        <spring-boot-starter-websocket.version>2.1.3.RELEASE</spring-boot-starter-websocket.version>
+        <poi.version>3.17</poi.version>
+        <!--<client.mqttv3.version>1.2.0</client.mqttv3.version>-->
+
+    </properties>
+
+    <!--dependencyManagement用于管理依赖版本号-->
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>com.wsm</groupId>
+                <artifactId>wsm-application</artifactId>
+                <version>${wsm.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.wsm</groupId>
+                <artifactId>wsm-common</artifactId>
+                <version>${wsm.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.wsm</groupId>
+                <artifactId>wsm-admin-web</artifactId>
+                <version>${wsm.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.wsm</groupId>
+                <artifactId>wsm-admin-service</artifactId>
+                <version>${wsm.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.wsm</groupId>
+                <artifactId>wsm-admin-dao</artifactId>
+                <version>${wsm.version}</version>
+            </dependency>
+            <!--spring boot -->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-web</artifactId>
+                <version>${spring.boot.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-test</artifactId>
+                <version>${spring.boot.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot</artifactId>
+                <version>${spring.boot.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-autoconfigure</artifactId>
+                <version>${spring.boot.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-tomcat</artifactId>
+                <version>${spring.boot.version}</version>
+                <scope>provided</scope>
+            </dependency>
+
+
+
+            <!--thymeleaf -->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-thymeleaf</artifactId>
+                <version>${spring.boot.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.github.theborakompanioni</groupId>
+                <artifactId>thymeleaf-extras-shiro</artifactId>
+                <version>${thymeleaf.shiro.version}</version>
+            </dependency>
+            <!-- JPA -->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-data-jpa</artifactId>
+                <version>${spring.boot.version}</version>
+            </dependency>
+
+            <!-- mybatis -->
+            <dependency>
+                <groupId>org.mybatis.spring.boot</groupId>
+                <artifactId>mybatis-spring-boot-starter</artifactId>
+                <version>${spring.mybatis.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>tk.mybatis</groupId>
+                <artifactId>mapper-spring-boot-starter</artifactId>
+                <version>${tk.mybatis.version}</version>
+            </dependency>
+
+            <!-- mysql -->
+            <dependency>
+                <groupId>mysql</groupId>
+                <artifactId>mysql-connector-java</artifactId>
+                <version>${mysql.version}</version>
+                <scope>runtime</scope>
+            </dependency>
+
+            <!-- druid -->
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>druid</artifactId>
+                <version>${druid.version}</version>
+            </dependency>
+
+            <!-- shiro -->
+            <dependency>
+                <groupId>org.apache.shiro</groupId>
+                <artifactId>shiro-core</artifactId>
+                <version>${shiro.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.shiro</groupId>
+                <artifactId>shiro-spring</artifactId>
+                <version>${shiro.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.shiro</groupId>
+                <artifactId>shiro-web</artifactId>
+                <version>${shiro.version}</version>
+            </dependency>
+
+            <!-- redis -->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-data-redis</artifactId>
+                <version>${redis.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>redis.clients</groupId>
+                <artifactId>jedis</artifactId>
+                <version>${jedis.version}</version>
+            </dependency>
+
+            <!-- nekohtml -->
+            <dependency>
+                <groupId>net.sourceforge.nekohtml</groupId>
+                <artifactId>nekohtml</artifactId>
+                <version>${nekohtml.version}</version>
+            </dependency>
+
+            <!-- kaptcha -->
+            <dependency>
+                <groupId>com.github.penggle</groupId>
+                <artifactId>kaptcha</artifactId>
+                <version>${kaptcha.version}</version>
+            </dependency>
+
+            <!-- lombok -->
+            <dependency>
+                <groupId>org.projectlombok</groupId>
+                <artifactId>lombok</artifactId>
+                <version>${lombok.version}</version>
+            </dependency>
+
+            <!-- commons -->
+            <dependency>
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-lang3</artifactId>
+                <version>${commons-lang3.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-codec</groupId>
+                <artifactId>commons-codec</artifactId>
+                <version>${commons.codec.version}</version>
+            </dependency>
+
+            <!-- fastjson -->
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>fastjson</artifactId>
+                <version>${fastjson.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.fasterxml.jackson.core</groupId>
+                <artifactId>jackson-databind</artifactId>
+                <version>${jackson.version}</version>
+            </dependency>
+
+            <!-- httpclient -->
+            <dependency>
+                <groupId>org.apache.httpcomponents</groupId>
+                <artifactId>httpclient</artifactId>
+                <version>${httpclient.version}</version>
+            </dependency>
+
+            <!-- servlet -->
+            <dependency>
+                <groupId>javax.servlet</groupId>
+                <artifactId>javax.servlet-api</artifactId>
+                <version>${javax.servlet-api.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>io.swagger</groupId>
+                <artifactId>swagger-annotations</artifactId>
+                <version>${swagger-annotations.version}</version>
+            </dependency>
+
+            <!-- spring cloud -->
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-starter-eureka</artifactId>
+                <version>${eureka.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-starter-feign</artifactId>
+                <version>${feign.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-dependencies</artifactId>
+                <version>${spring-cloud.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>com.netflix.feign</groupId>
+                <artifactId>feign-httpclient</artifactId>
+                <version>${feign-httpclient.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.netflix.feign</groupId>
+                <artifactId>feign-jackson</artifactId>
+                <version>${feign-jackson.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>joda-time</groupId>
+                <artifactId>joda-time</artifactId>
+                <version>${joda-time.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.google.zxing</groupId>
+                <artifactId>core</artifactId>
+                <version>${zxing.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.google.zxing</groupId>
+                <artifactId>javase</artifactId>
+                <version>${zxing.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.apache.poi</groupId>
+                <artifactId>poi-ooxml</artifactId>
+                <version>${poi.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.poi</groupId>
+                <artifactId>poi-ooxml-schemas</artifactId>
+                <version>${poi.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.poi</groupId>
+                <artifactId>poi</artifactId>
+                <version>${poi.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-websocket</artifactId>
+                <version>${spring-boot-starter-websocket.version}</version>
+            </dependency>
+
+
+            <!--mqtt包-->
+            <!-- https://mvnrepository.com/artifact/org.eclipse.paho/org.eclipse.paho.client.mqttv3 -->
+            <!--<dependency>-->
+                <!--<groupId>org.eclipse.paho</groupId>-->
+                <!--<artifactId>org.eclipse.paho.client.mqttv3</artifactId>-->
+                <!--<version>${client.mqttv3.version}}</version>-->
+            <!--</dependency>-->
+
+        </dependencies>
+    </dependencyManagement>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.1</version>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>2.19.1</version>
+                <configuration>
+                    <skipTests>true</skipTests>    <!--默认关掉单元测试 -->
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 58 - 0
wsm-admin-dao/pom.xml

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.wsm</groupId>
+    <artifactId>wsm-admin-dao</artifactId>
+    <version>1.0.0</version>
+    <packaging>jar</packaging>
+
+    <name>wsm-admin-dao</name>
+    <description>wsm-admin-dao project</description>
+
+    <parent>
+        <groupId>com.wsm</groupId>
+        <artifactId>wsm-base</artifactId>
+        <version>1.0.0</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.wsm</groupId>
+            <artifactId>wsm-common</artifactId>
+        </dependency>
+
+        <!-- JPA -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
+        </dependency>
+
+        <!-- mybatis -->
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>tk.mybatis</groupId>
+            <artifactId>mapper-spring-boot-starter</artifactId>
+        </dependency>
+
+        <!-- mysql -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid</artifactId>
+        </dependency>
+
+    </dependencies>
+
+
+</project>

+ 16 - 0
wsm-admin-dao/src/main/java/com/wsm/admin/dao/IDataDictionaryDao.java

@@ -0,0 +1,16 @@
+package com.wsm.admin.dao;
+
+import java.util.List;
+
+import com.wsm.admin.model.DataDictionary;
+import com.wsm.common.dao.IBaseDao;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface IDataDictionaryDao extends IBaseDao<DataDictionary, Long> {
+
+	DataDictionary findByCodeAndDataKey(String code, String dataKey);
+
+	List<DataDictionary> findByCode(String code);
+
+}

+ 13 - 0
wsm-admin-dao/src/main/java/com/wsm/admin/dao/IDeviceDao.java

@@ -0,0 +1,13 @@
+package com.wsm.admin.dao;
+
+import com.wsm.admin.model.Device;
+import com.wsm.common.dao.IBaseDao;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface IDeviceDao extends IBaseDao<Device, Long> {
+
+    Device findByDeviceId16Hex(String deviceId16Hex);
+
+    Device findByDeviceId(String deviceId);
+}

+ 26 - 0
wsm-admin-dao/src/main/java/com/wsm/admin/dao/IDeviceEventDao.java

@@ -0,0 +1,26 @@
+package com.wsm.admin.dao;
+
+import com.wsm.admin.model.DeviceEvent;
+import com.wsm.common.dao.IBaseDao;
+import org.apache.ibatis.annotations.Update;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+import java.util.List;
+
+@Repository
+public interface IDeviceEventDao extends IBaseDao<DeviceEvent, Long> {
+
+    List<DeviceEvent> findByContentAndPostTime(String content, Date postTime);
+
+    @Query(value = "SELECT * from tb_device_event where device_id = ?1 and rec_status = 'A' order by update_time desc LIMIT 0,1", nativeQuery = true)
+    DeviceEvent findByDeviceIdTop(Long id);
+
+    @Transactional
+    @Modifying
+    @Query(value = "update tb_device_event set rec_status = ?2 where device_id = ?1 ", nativeQuery = true)
+    void setRecStatuBydeviceId(Long dbId, String recStatus);
+}

+ 12 - 0
wsm-admin-dao/src/main/java/com/wsm/admin/dao/IResourceDao.java

@@ -0,0 +1,12 @@
+package com.wsm.admin.dao;
+
+import com.wsm.admin.model.Resource;
+import com.wsm.common.dao.IBaseDao;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface IResourceDao extends IBaseDao<Resource, Long> {
+
+    public boolean existsByResourceKey(String resourceKey);
+
+}

+ 12 - 0
wsm-admin-dao/src/main/java/com/wsm/admin/dao/IRoleDao.java

@@ -0,0 +1,12 @@
+package com.wsm.admin.dao;
+
+import com.wsm.admin.model.Role;
+import com.wsm.common.dao.IBaseDao;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface IRoleDao extends IBaseDao<Role, Long> {
+
+    public boolean existsByRoleKey(String roleKey);
+
+}

+ 16 - 0
wsm-admin-dao/src/main/java/com/wsm/admin/dao/IUserDao.java

@@ -0,0 +1,16 @@
+package com.wsm.admin.dao;
+
+import com.wsm.admin.model.User;
+import com.wsm.common.dao.IBaseDao;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface IUserDao extends IBaseDao<User, Long> {
+
+    public User findByUserNameAndPassword(String userName, String password);
+
+    public User findByUserName(String userName);
+
+    public boolean existsByUserName(String userName);
+
+}

+ 15 - 0
wsm-admin-dao/src/main/java/com/wsm/admin/mapper/ResourceMapper.java

@@ -0,0 +1,15 @@
+package com.wsm.admin.mapper;
+
+import com.wsm.admin.model.Resource;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+@Mapper
+public interface ResourceMapper extends tk.mybatis.mapper.common.Mapper<Resource> {
+
+    @Select("select distinct f from Menu f,RoleMenu rf,AdminUserRole ru  where ru.role.id=rf.role.id and rf.menu.id=f.id and ru.adminUser.id=#{userId} ")
+    List<Resource> getUserMenu(Long userId);
+
+}

+ 9 - 0
wsm-admin-dao/src/main/java/com/wsm/admin/mapper/RoleMapper.java

@@ -0,0 +1,9 @@
+package com.wsm.admin.mapper;
+
+import com.wsm.admin.model.Role;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface RoleMapper extends tk.mybatis.mapper.common.Mapper<Role> {
+
+}

+ 10 - 0
wsm-admin-dao/src/main/java/com/wsm/admin/mapper/UserMapper.java

@@ -0,0 +1,10 @@
+package com.wsm.admin.mapper;
+
+import com.wsm.admin.model.User;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface UserMapper extends tk.mybatis.mapper.common.Mapper<User> {
+
+
+}

+ 88 - 0
wsm-admin-dao/src/main/java/com/wsm/admin/model/DataDictionary.java

@@ -0,0 +1,88 @@
+package com.wsm.admin.model;
+
+import com.wsm.common.model.BaseModel;
+import org.hibernate.annotations.Where;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import java.io.Serializable;
+
+@Entity
+@Table(name = "tb_data_dictionary")
+@Where(clause = "rec_status='A'")
+public class DataDictionary extends BaseModel implements Serializable {
+
+    private static final long serialVersionUID = 8143168783985917525L;
+
+    @Column(length = 100)
+    private String code;
+
+    private String dataKey;
+
+    private String dataValue;
+
+    private String description;
+
+    private String param1;
+
+    private String param2;
+
+    private String param3;
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getDataKey() {
+        return dataKey;
+    }
+
+    public void setDataKey(String dataKey) {
+        this.dataKey = dataKey;
+    }
+
+    public String getDataValue() {
+        return dataValue;
+    }
+
+    public void setDataValue(String dataValue) {
+        this.dataValue = dataValue;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getParam1() {
+        return param1;
+    }
+
+    public void setParam1(String param1) {
+        this.param1 = param1;
+    }
+
+    public String getParam2() {
+        return param2;
+    }
+
+    public void setParam2(String param2) {
+        this.param2 = param2;
+    }
+
+    public String getParam3() {
+        return param3;
+    }
+
+    public void setParam3(String param3) {
+        this.param3 = param3;
+    }
+}

+ 125 - 0
wsm-admin-dao/src/main/java/com/wsm/admin/model/Device.java

@@ -0,0 +1,125 @@
+package com.wsm.admin.model;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.wsm.common.model.BaseModel;
+import org.hibernate.annotations.Where;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Entity
+@Table(name = "tb_device")
+@Where(clause = "rec_status='A'")
+public class Device extends BaseModel implements Serializable {
+
+    private static final long serialVersionUID = -3685268556334774675L;
+    /**
+     * 设备id
+     */
+    @Column(length = 50)
+    private String deviceId;
+    /**
+     * 设备id 16进制码(烟感专用字段)
+     */
+    @JSONField(serialize = false)
+    @Column(length = 50)
+    private String deviceId16Hex;
+    /**
+     * 设备类型
+     */
+    @Column(columnDefinition = "enum('YG','JG')")
+    private String deviceType;
+    /**
+     * 经度
+     */
+    @Column(precision = 10, scale = 7)
+    private BigDecimal longitude;
+    /**
+     * 纬度
+     */
+    @Column(precision = 10, scale = 7)
+    private BigDecimal latitude;
+    /**
+     * 地址
+     */
+    private String address;
+    /**
+     * 状态类型:0-正常  1-报警  2-低压  3-故障
+     */
+    @Column(length = 2)
+    private Byte status;
+
+    public String getDeviceId() {
+        return deviceId;
+    }
+
+    public void setDeviceId(String deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    public String getDeviceType() {
+        return deviceType;
+    }
+
+    public void setDeviceType(String deviceType) {
+        this.deviceType = deviceType;
+    }
+
+    public BigDecimal getLongitude() {
+        return longitude;
+    }
+
+    public void setLongitude(BigDecimal longitude) {
+        this.longitude = longitude;
+    }
+
+    public BigDecimal getLatitude() {
+        return latitude;
+    }
+
+    public void setLatitude(BigDecimal latitude) {
+        this.latitude = latitude;
+    }
+
+    public String getDeviceId16Hex() {
+        return deviceId16Hex;
+    }
+
+    public void setDeviceId16Hex(String deviceId16Hex) {
+        this.deviceId16Hex = deviceId16Hex;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public Byte getStatus() {
+        return status;
+    }
+
+    public void setStatus(Byte status) {
+        this.status = status;
+    }
+
+
+    @Override
+    public String toString() {
+        return "Device{" +
+                "deviceId='" + deviceId + '\'' +
+                ", deviceId16Hex='" + deviceId16Hex + '\'' +
+                ", deviceType='" + deviceType + '\'' +
+                ", longitude=" + longitude +
+                ", latitude=" + latitude +
+                ", address='" + address + '\'' +
+                ", status=" + status +
+                '}';
+    }
+}

+ 82 - 0
wsm-admin-dao/src/main/java/com/wsm/admin/model/DeviceEvent.java

@@ -0,0 +1,82 @@
+package com.wsm.admin.model;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.wsm.common.model.BaseModel;
+import net.minidev.json.annotate.JsonIgnore;
+import org.hibernate.annotations.Where;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 设备事件表
+ */
+@Entity
+@Table(name = "tb_device_event")
+@Where(clause = "rec_status='A'")
+public class DeviceEvent extends BaseModel implements Serializable {
+
+    private static final long serialVersionUID = 5512725645194142786L;
+
+    @ManyToOne(fetch = FetchType.EAGER)
+    private Device device;
+    /**
+     * 事件内容
+     */
+    private String content;
+    /**
+     * 处理状态:0-待解决, 1-已立案,2-出警中,3-已解决
+     */
+    @Column(length = 2)
+    private Byte handleStatus;
+
+    /**
+     * 上报时间 作去重校验
+     */
+    @Temporal(TemporalType.TIMESTAMP)
+    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
+    private Date postTime;
+
+    public Device getDevice() {
+        return device;
+    }
+
+    public void setDevice(Device device) {
+        this.device = device;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public Byte getHandleStatus() {
+        return handleStatus;
+    }
+
+    public void setHandleStatus(Byte handleStatus) {
+        this.handleStatus = handleStatus;
+    }
+
+    public Date getPostTime() {
+        return postTime;
+    }
+
+    public void setPostTime(Date postTime) {
+        this.postTime = postTime;
+    }
+
+    @Override
+    public String toString() {
+        return "DeviceEvent{" +
+                "device=" + device +
+                ", content='" + content + '\'' +
+                ", handleStatus=" + handleStatus +
+                ", postTime=" + postTime +
+                '}';
+    }
+}

+ 105 - 0
wsm-admin-dao/src/main/java/com/wsm/admin/model/Resource.java

@@ -0,0 +1,105 @@
+package com.wsm.admin.model;
+
+import com.wsm.common.model.BaseModel;
+import org.hibernate.annotations.Where;
+
+import javax.persistence.*;
+import java.io.Serializable;
+
+@Entity
+@Table(name = "tb_resource")
+@Where(clause = "rec_status='A'")
+public class Resource extends BaseModel implements Serializable {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = -293343757324080501L;
+
+    @Column(length = 50)
+    private String name;
+
+    private String description;
+
+    private String url;
+
+    @Column(length = 10)
+    private String icon;
+
+    private String resourceKey;
+
+    @Column(columnDefinition = "enum('menu','button')")
+    private String resourceType;
+
+    @Column(length = 2)
+    private Byte sort;
+
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "parentId")
+    private Resource parentId;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getIcon() {
+        return icon;
+    }
+
+    public void setIcon(String icon) {
+        this.icon = icon;
+    }
+
+    public String getResourceType() {
+        return resourceType;
+    }
+
+    public void setResourceType(String resourceType) {
+        this.resourceType = resourceType;
+    }
+
+    public Resource getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(Resource parentId) {
+        this.parentId = parentId;
+    }
+
+    public String getResourceKey() {
+        return resourceKey;
+    }
+
+    public void setResourceKey(String resourceKey) {
+        this.resourceKey = resourceKey;
+    }
+
+    public Byte getSort() {
+        return sort;
+    }
+
+    public void setSort(Byte sort) {
+        this.sort = sort;
+    }
+
+}

+ 63 - 0
wsm-admin-dao/src/main/java/com/wsm/admin/model/Role.java

@@ -0,0 +1,63 @@
+package com.wsm.admin.model;
+
+import com.wsm.common.model.BaseModel;
+import org.hibernate.annotations.Where;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Set;
+
+@Entity
+@Table(name = "tb_role")
+@Where(clause = "rec_status='A'")
+public class Role extends BaseModel implements Serializable {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = -8093446477843493946L;
+
+    @Column(length = 50)
+    private String roleName;
+
+    private String roleDesc;
+
+    private String roleKey;
+
+    @ManyToMany(fetch = FetchType.LAZY)
+    @JoinTable(name = "tb_role_resource", joinColumns = {@JoinColumn(name = "role_id")}, inverseJoinColumns = {@JoinColumn(name = "resource_id")})
+    @OrderBy("sort ASC")
+    private Set<Resource> resources;
+
+    public String getRoleName() {
+        return roleName;
+    }
+
+    public void setRoleName(String roleName) {
+        this.roleName = roleName;
+    }
+
+    public String getRoleDesc() {
+        return roleDesc;
+    }
+
+    public void setRoleDesc(String roleDesc) {
+        this.roleDesc = roleDesc;
+    }
+
+    public String getRoleKey() {
+        return roleKey;
+    }
+
+    public void setRoleKey(String roleKey) {
+        this.roleKey = roleKey;
+    }
+
+    public Set<Resource> getResources() {
+        return resources;
+    }
+
+    public void setResources(Set<Resource> resources) {
+        this.resources = resources;
+    }
+}

+ 83 - 0
wsm-admin-dao/src/main/java/com/wsm/admin/model/User.java

@@ -0,0 +1,83 @@
+package com.wsm.admin.model;
+
+import com.wsm.common.model.BaseModel;
+import org.hibernate.annotations.Where;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Set;
+
+@Entity
+@Table(name = "tb_user")
+@Where(clause = "rec_status='A'")
+public class User extends BaseModel implements Serializable {
+
+    private static final long serialVersionUID = -853504493430501564L;
+
+    @Column(length = 50)
+    private String userName;
+
+    @Column(length = 100)
+    private String password;
+
+    @Column(length = 50)
+    private String realName;
+
+    @Column(length = 1)
+    private byte status;
+
+    private String avatar;
+
+    @ManyToMany(cascade = {CascadeType.REFRESH}, fetch = FetchType.LAZY)
+    @JoinTable(name = "tb_user_role", joinColumns = {@JoinColumn(name = "user_id")}, inverseJoinColumns = {@JoinColumn(name = "role_id")})
+    @Where(clause = "rec_status='A'")
+    private Set<Role> roles;
+
+    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 getRealName() {
+        return realName;
+    }
+
+    public void setRealName(String realName) {
+        this.realName = realName;
+    }
+
+    public byte getStatus() {
+        return status;
+    }
+
+    public void setStatus(byte status) {
+        this.status = status;
+    }
+
+    public Set<Role> getRoles() {
+        return roles;
+    }
+
+    public void setRoles(Set<Role> roles) {
+        this.roles = roles;
+    }
+
+    public String getAvatar() {
+        return avatar;
+    }
+
+    public void setAvatar(String avatar) {
+        this.avatar = avatar;
+    }
+}

+ 35 - 0
wsm-admin-service/pom.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.wsm</groupId>
+    <artifactId>wsm-admin-service</artifactId>
+    <version>1.0.0</version>
+    <packaging>jar</packaging>
+
+    <name>wsm-admin-service</name>
+    <description>wsm admin service project</description>
+
+    <parent>
+        <groupId>com.wsm</groupId>
+        <artifactId>wsm-base</artifactId>
+        <version>1.0.0</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.wsm</groupId>
+            <artifactId>wsm-common</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.wsm</groupId>
+            <artifactId>wsm-admin-dao</artifactId>
+        </dependency>
+
+    </dependencies>
+
+
+</project>

+ 138 - 0
wsm-admin-service/src/main/java/com/wsm/admin/dto/ResourceTree.java

@@ -0,0 +1,138 @@
+package com.wsm.admin.dto;
+
+import java.util.List;
+
+public class ResourceTree {
+
+    private Long id;
+
+    private String name;
+
+    private Long parentId;
+
+    private boolean checked = false;
+
+    private boolean spread = false;
+
+    private String isHeader = "0";
+
+    private String url;
+
+    private String icon;
+
+    private String resourceKey;
+
+    private String resourceType;
+
+    private String order = "1";
+
+    private List<ResourceTree> children;
+
+    private int level;
+
+    public Long getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public List<ResourceTree> getChildren() {
+        return children;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setChildren(List<ResourceTree> children) {
+        this.children = children;
+    }
+
+    public Long getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(Long parentId) {
+        this.parentId = parentId;
+    }
+
+    public boolean isChecked() {
+        return checked;
+    }
+
+    public void setChecked(boolean checked) {
+        this.checked = checked;
+        this.spread = checked;
+    }
+
+    public boolean isSpread() {
+        return spread;
+    }
+
+    public void setSpread(boolean spread) {
+        this.spread = spread;
+    }
+
+
+    public String getIsHeader() {
+        return isHeader;
+    }
+
+    public void setIsHeader(String isHeader) {
+        this.isHeader = isHeader;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getIcon() {
+        return icon;
+    }
+
+    public void setIcon(String icon) {
+        this.icon = icon;
+    }
+
+    public String getOrder() {
+        return order;
+    }
+
+    public void setOrder(String order) {
+        this.order = order;
+    }
+
+    public int getLevel() {
+        return level;
+    }
+
+    public void setLevel(int level) {
+        this.level = level;
+    }
+
+    public String getResourceType() {
+        return resourceType;
+    }
+
+    public void setResourceType(String resourceType) {
+        this.resourceType = resourceType;
+    }
+
+    public String getResourceKey() {
+        return resourceKey;
+    }
+
+    public void setResourceKey(String resourceKey) {
+        this.resourceKey = resourceKey;
+    }
+}

+ 36 - 0
wsm-admin-service/src/main/java/com/wsm/admin/service/IDataDictionaryService.java

@@ -0,0 +1,36 @@
+package com.wsm.admin.service;
+
+import java.util.List;
+
+import com.wsm.admin.model.DataDictionary;
+import com.wsm.common.service.IBaseService;
+
+/**
+ * <p>
+ * 数据字典服务类
+ * </p>
+ *
+ * @author ajay peng
+ * @since 2018-05-02
+ */
+public interface IDataDictionaryService extends IBaseService<DataDictionary, Long> {
+	
+    /**
+     * 修改或者新增资源
+     *
+     */
+    void saveOrUpdate(DataDictionary dataDictionary);
+    
+    /**
+     * 根据code和dateKey查找
+     *
+     */
+    DataDictionary findByCodeAndDataKey(String code, String dataKey);
+
+    /**
+     * 根据code查找
+     *
+     */
+	List<DataDictionary> findByCode(String code);
+
+}

+ 22 - 0
wsm-admin-service/src/main/java/com/wsm/admin/service/IDeviceEventService.java

@@ -0,0 +1,22 @@
+package com.wsm.admin.service;
+
+import com.wsm.admin.model.Device;
+import com.wsm.admin.model.DeviceEvent;
+import com.wsm.common.service.IBaseService;
+
+import java.util.Date;
+import java.util.List;
+
+public interface IDeviceEventService extends IBaseService<DeviceEvent, Long> {
+
+    List<DeviceEvent> findByContentAndPostTime(String content, Date postTime);
+
+    /**
+     * 查询最新的一条
+     * @param deviceId
+     * @return
+     */
+    DeviceEvent findByDeviceIdTop(Long deviceId);
+
+    void setRecStatuBydeviceId(Long dbId, String recStatus);
+}

+ 11 - 0
wsm-admin-service/src/main/java/com/wsm/admin/service/IDeviceService.java

@@ -0,0 +1,11 @@
+package com.wsm.admin.service;
+
+import com.wsm.admin.model.Device;
+import com.wsm.common.service.IBaseService;
+
+public interface IDeviceService extends IBaseService<Device, Long> {
+
+    Device findByDeviceId16Hex(String deviceId16Hex);
+
+    Device findByDeviceId(String deviceId);
+}

+ 20 - 0
wsm-admin-service/src/main/java/com/wsm/admin/service/IResourceService.java

@@ -0,0 +1,20 @@
+package com.wsm.admin.service;
+
+import com.wsm.admin.dto.ResourceTree;
+import com.wsm.admin.model.Resource;
+import com.wsm.admin.model.User;
+import com.wsm.common.service.IBaseService;
+
+import java.util.List;
+
+public interface IResourceService extends IBaseService<Resource, Long> {
+
+    public List<ResourceTree> getResourcesByUser(User user) throws Exception;
+
+    public List<Resource> getAllResources() throws Exception;
+
+    public List<ResourceTree> getTree() throws Exception;
+
+    public boolean existsByResourceKey(String resourceKey) throws Exception;
+
+}

+ 14 - 0
wsm-admin-service/src/main/java/com/wsm/admin/service/IRoleService.java

@@ -0,0 +1,14 @@
+package com.wsm.admin.service;
+
+import com.wsm.admin.model.Role;
+import com.wsm.common.service.IBaseService;
+
+import java.util.List;
+
+public interface IRoleService extends IBaseService<Role, Long> {
+
+    public List<Role> find(Role role) throws Exception;
+
+    public boolean existsByRoleKey(String roleKey) throws Exception;
+
+}

+ 18 - 0
wsm-admin-service/src/main/java/com/wsm/admin/service/IUserService.java

@@ -0,0 +1,18 @@
+package com.wsm.admin.service;
+
+import com.wsm.admin.model.User;
+import com.wsm.common.service.IBaseService;
+
+import java.util.List;
+
+public interface IUserService extends IBaseService<User, Long> {
+
+    public List<User> find(User user) throws Exception;
+
+    public User findByUserNameAndPassword(String userName, String password) throws Exception;
+
+    public User findByUserName(String userName);
+
+    public boolean existsByUserName(String userName) throws Exception;
+
+}

+ 59 - 0
wsm-admin-service/src/main/java/com/wsm/admin/service/impl/DataDictionaryServiceImpl.java

@@ -0,0 +1,59 @@
+package com.wsm.admin.service.impl;
+
+import java.util.Date;
+import java.util.List;
+
+import com.wsm.admin.dao.IDataDictionaryDao;
+import com.wsm.admin.model.DataDictionary;
+import com.wsm.admin.service.IDataDictionaryService;
+import com.wsm.common.dao.IBaseDao;
+import com.wsm.common.service.impl.BaseServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  数据字典 服务实现类
+ * </p>
+ *
+ * @author SPPan
+ * @since 2016-12-28
+ */
+@Service
+public class DataDictionaryServiceImpl extends BaseServiceImpl<DataDictionary, Long> implements IDataDictionaryService {
+
+    @Autowired
+    private IDataDictionaryDao dataDictionaryDao;
+
+    @Override
+    public IBaseDao<DataDictionary, Long> getBaseDao() {
+        return this.dataDictionaryDao;
+    }
+    
+    @Override
+    public void saveOrUpdate(DataDictionary dataDictionary) {
+        if (dataDictionary.getId() != null) {
+        	DataDictionary dbDictionary = find(dataDictionary.getId());
+        	dbDictionary.setDataKey(dataDictionary.getDataKey());
+        	dbDictionary.setDataValue(dataDictionary.getDataValue());
+        	dbDictionary.setCode(dataDictionary.getCode());
+        	dbDictionary.setDescription(dataDictionary.getDescription());
+        	dbDictionary.setParam1(dataDictionary.getParam1());
+        	dbDictionary.setParam2(dataDictionary.getParam2());
+        	dbDictionary.setParam3(dataDictionary.getParam3());
+            update(dbDictionary);
+        } else {
+            save(dataDictionary);
+        }
+    }
+
+	@Override
+	public DataDictionary findByCodeAndDataKey(String code, String dataKey) {
+		return dataDictionaryDao.findByCodeAndDataKey(code, dataKey);
+	}
+	
+	@Override
+	public List<DataDictionary> findByCode(String code){
+		return dataDictionaryDao.findByCode(code);
+	}
+}

+ 41 - 0
wsm-admin-service/src/main/java/com/wsm/admin/service/impl/DeviceEventServiceImpl.java

@@ -0,0 +1,41 @@
+package com.wsm.admin.service.impl;
+
+import com.wsm.admin.dao.IDeviceEventDao;
+import com.wsm.admin.model.Device;
+import com.wsm.admin.model.DeviceEvent;
+import com.wsm.admin.service.IDeviceEventService;
+import com.wsm.common.dao.IBaseDao;
+import com.wsm.common.service.impl.BaseServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.List;
+
+@Service
+public class DeviceEventServiceImpl extends BaseServiceImpl<DeviceEvent, Long> implements IDeviceEventService {
+
+    @Autowired
+    private IDeviceEventDao deviceEventDao;
+
+    @Override
+    public IBaseDao<DeviceEvent, Long> getBaseDao() {
+        return this.deviceEventDao;
+    }
+
+
+    @Override
+    public List<DeviceEvent> findByContentAndPostTime(String content, Date postTime) {
+        return deviceEventDao.findByContentAndPostTime(content, postTime);
+    }
+
+    @Override
+    public DeviceEvent findByDeviceIdTop(Long deviceId) {
+        return deviceEventDao.findByDeviceIdTop(deviceId);
+    }
+
+    @Override
+    public void setRecStatuBydeviceId(Long dbId, String recStatus) {
+        deviceEventDao.setRecStatuBydeviceId(dbId, recStatus);
+    }
+}

+ 31 - 0
wsm-admin-service/src/main/java/com/wsm/admin/service/impl/DeviceServiceImpl.java

@@ -0,0 +1,31 @@
+package com.wsm.admin.service.impl;
+
+import com.wsm.admin.dao.IDeviceDao;
+import com.wsm.admin.model.Device;
+import com.wsm.admin.service.IDeviceService;
+import com.wsm.common.dao.IBaseDao;
+import com.wsm.common.service.impl.BaseServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class DeviceServiceImpl extends BaseServiceImpl<Device, Long> implements IDeviceService {
+
+    @Autowired
+    private IDeviceDao deviceDao;
+
+    @Override
+    public IBaseDao<Device, Long> getBaseDao() {
+        return this.deviceDao;
+    }
+
+    @Override
+    public Device findByDeviceId16Hex(String deviceId16Hex) {
+        return deviceDao.findByDeviceId16Hex(deviceId16Hex);
+    }
+
+    @Override
+    public Device findByDeviceId(String deviceId) {
+        return deviceDao.findByDeviceId(deviceId);
+    }
+}

+ 75 - 0
wsm-admin-service/src/main/java/com/wsm/admin/service/impl/ResourceServiceImpl.java

@@ -0,0 +1,75 @@
+package com.wsm.admin.service.impl;
+
+import com.wsm.admin.dao.IResourceDao;
+import com.wsm.admin.dto.ResourceTree;
+import com.wsm.admin.mapper.ResourceMapper;
+import com.wsm.admin.model.Resource;
+import com.wsm.admin.model.Role;
+import com.wsm.admin.model.User;
+import com.wsm.admin.service.IResourceService;
+import com.wsm.admin.util.ResourceTreeUtil;
+import com.wsm.common.dao.IBaseDao;
+import com.wsm.common.service.impl.BaseServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+@Service("resourceService")
+@Transactional
+public class ResourceServiceImpl extends BaseServiceImpl<Resource, Long> implements IResourceService {
+
+    @Autowired
+    private IResourceDao resourceDao;
+
+    @Autowired
+    private ResourceMapper resourceMapper;
+
+    @Override
+    public IBaseDao<Resource, Long> getBaseDao() {
+        return this.resourceDao;
+    }
+
+    @Override
+    public List<Resource> getAllResources() throws Exception {
+        return resourceMapper.selectAll();
+    }
+
+    @Override
+    @Cacheable(value = "resourcesUserCache", key = "#root.caches[0].name + ':' + #user.id")
+    public List<ResourceTree> getResourcesByUser(User user) throws Exception {
+        //Get user menu
+        Set<Role> roles = user.getRoles();
+        List<Resource> resources = new ArrayList<>();
+        roles.forEach(role -> {
+            for (Resource resource : role.getResources()) {
+                if ("menu".equals(resource.getResourceType())) {
+                    resources.add(resource);
+                }
+            }
+        });
+//		List<Resource> resources = getAllResources();
+        ResourceTreeUtil tree = new ResourceTreeUtil(resources);
+        List<ResourceTree> listTree = tree.buildTree();
+        return listTree;
+    }
+
+    @Override
+    @Cacheable(value = "resourcesCache")
+    public List<ResourceTree> getTree() throws Exception {
+        List<Resource> resources = resourceDao.findAll();
+        ResourceTreeUtil tree = new ResourceTreeUtil(resources);
+        return tree.buildTree();
+    }
+
+    @Override
+    public boolean existsByResourceKey(String resourceKey) throws Exception {
+        return resourceDao.existsByResourceKey(resourceKey);
+    }
+
+}

+ 39 - 0
wsm-admin-service/src/main/java/com/wsm/admin/service/impl/RoleServiceImpl.java

@@ -0,0 +1,39 @@
+package com.wsm.admin.service.impl;
+
+import com.wsm.admin.dao.IRoleDao;
+import com.wsm.admin.mapper.RoleMapper;
+import com.wsm.admin.model.Role;
+import com.wsm.admin.service.IRoleService;
+import com.wsm.common.dao.IBaseDao;
+import com.wsm.common.service.impl.BaseServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@Service("roleService")
+@Transactional
+public class RoleServiceImpl extends BaseServiceImpl<Role, Long> implements IRoleService {
+
+    @Autowired
+    private IRoleDao roleDao;
+
+    @Autowired
+    private RoleMapper roleMapper;
+
+    @Override
+    public IBaseDao<Role, Long> getBaseDao() {
+        return this.roleDao;
+    }
+
+    @Override
+    public List<Role> find(Role role) throws Exception {
+        return roleMapper.select(role);
+    }
+
+    @Override
+    public boolean existsByRoleKey(String roleKey) throws Exception {
+        return roleDao.existsByRoleKey(roleKey);
+    }
+}

+ 51 - 0
wsm-admin-service/src/main/java/com/wsm/admin/service/impl/UserServiceImpl.java

@@ -0,0 +1,51 @@
+package com.wsm.admin.service.impl;
+
+import com.wsm.admin.dao.IUserDao;
+import com.wsm.admin.mapper.UserMapper;
+import com.wsm.admin.model.User;
+import com.wsm.admin.service.IUserService;
+import com.wsm.common.dao.IBaseDao;
+import com.wsm.common.service.impl.BaseServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@Service("userService")
+@Transactional
+public class UserServiceImpl extends BaseServiceImpl<User, Long> implements IUserService {
+
+    @Autowired
+    private IUserDao userDao;
+
+    @Autowired
+    private UserMapper userMapper;
+
+    @Override
+    public IBaseDao<User, Long> getBaseDao() {
+        return this.userDao;
+    }
+
+    @Override
+    public List<User> find(User user) throws Exception {
+        return userMapper.select(user);
+    }
+
+    @Override
+    public User findByUserName(String userName) {
+        return userDao.findByUserName(userName);
+    }
+
+    @Override
+    public User findByUserNameAndPassword(String userName, String password) throws Exception {
+        return userDao.findByUserNameAndPassword(userName, password);
+    }
+
+    @Override
+    public boolean existsByUserName(String userName) throws Exception {
+        return userDao.existsByUserName(userName);
+    }
+
+
+}

+ 102 - 0
wsm-admin-service/src/main/java/com/wsm/admin/util/ResourceTreeUtil.java

@@ -0,0 +1,102 @@
+package com.wsm.admin.util;
+
+import com.wsm.admin.dto.ResourceTree;
+import com.wsm.admin.model.Resource;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ResourceTreeUtil {
+
+    private List<ResourceTree> resultNodes = new ArrayList<ResourceTree>();//树形结构排序之后list内容
+
+    private List<ResourceTree> nodes = new ArrayList<ResourceTree>();
+    //传入list参数
+
+    public ResourceTreeUtil(List<Resource> nodesList) {//通过构造函数初始化
+        for (Resource n : nodesList) {
+            ResourceTree treeGrid = new ResourceTree();
+            treeGrid.setId(n.getId());
+            treeGrid.setName(n.getName());
+            treeGrid.setIcon(n.getIcon());
+            treeGrid.setUrl(n.getUrl());
+            treeGrid.setResourceKey(n.getResourceKey());
+            treeGrid.setResourceType(n.getResourceType());
+            if (n.getParentId() != null) {
+                treeGrid.setParentId(n.getParentId().getId());
+            }
+            nodes.add(treeGrid);
+        }
+    }
+
+    public ResourceTreeUtil() {
+    }
+
+    /**
+     * 构建树形结构list
+     *
+     * @return 返回树形结构List列表
+     */
+    public List<ResourceTree> buildTree() {
+        for (ResourceTree node : nodes) {
+            Long id = node.getParentId();
+            if (node.getParentId() == null) {//通过循环一级节点 就可以通过递归获取二级以下节点
+                resultNodes.add(node);//添加一级节点
+//                node.setLevel(1);
+                build(node, node.getLevel());//递归获取二级、三级、。。。节点
+            }
+        }
+        return resultNodes;
+    }
+
+    /**
+     * 递归循环子节点
+     *
+     * @param node 当前节点
+     */
+    private void build(ResourceTree node, int level) {
+        List<ResourceTree> children = getChildren(node);
+        if (!children.isEmpty()) {//如果存在子节点
+            node.setChildren(children);
+//        	level++;
+            for (ResourceTree child : children) {//将子节点遍历加入返回值中
+//        		child.setLevel(level);
+                build(child, child.getLevel());
+            }
+        }
+    }
+
+    /**
+     * @param node
+     * @return 返回
+     */
+    private List<ResourceTree> getChildren(ResourceTree node) {
+        List<ResourceTree> children = new ArrayList<ResourceTree>();
+        Long id = node.getId();
+        for (ResourceTree child : nodes) {
+            if (id.equals(child.getParentId())) {//如果id等于父id
+                children.add(child);//将该节点加入循环列表中
+            }
+        }
+        return children;
+    }
+
+    public List<ResourceTree> buildTree(List<Resource> all, List<Resource> in) {
+        for (Resource n : all) {
+            ResourceTree treeGrid = new ResourceTree();
+            treeGrid.setId(n.getId());
+            treeGrid.setName(n.getName());
+            for (Resource nin : in) {
+                if (nin.getId().equals(n.getId())) {
+                    treeGrid.setChecked(true);
+                }
+            }
+            if (n.getParentId() != null) {
+                treeGrid.setParentId(n.getParentId().getId());
+            }
+            nodes.add(treeGrid);
+        }
+        return buildTree();
+    }
+
+}

+ 66 - 0
wsm-admin-web/pom.xml

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.wsm</groupId>
+    <artifactId>wsm-admin-web</artifactId>
+    <version>1.0.0</version>
+    <packaging>jar</packaging>
+    <repositories>
+        <repository>
+            <id>nexus-aliyun</id>
+            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
+        </repository>
+    </repositories>
+
+    <name>wsm-admin-web</name>
+    <description>wsm admin web project</description>
+
+    <parent>
+        <groupId>com.wsm</groupId>
+        <artifactId>wsm-base</artifactId>
+        <version>1.0.0</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <java.version>1.8</java.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.wsm</groupId>
+            <artifactId>wsm-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.wsm</groupId>
+            <artifactId>wsm-admin-dao</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.wsm</groupId>
+            <artifactId>wsm-admin-service</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.github.theborakompanioni</groupId>
+            <artifactId>thymeleaf-extras-shiro</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse.paho</groupId>
+            <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
+            <version>1.2.0</version>
+        </dependency>
+
+    </dependencies>
+
+
+
+</project>

+ 249 - 0
wsm-admin-web/src/main/java/com/wsm/admin/api/ApiDeviceController.java

@@ -0,0 +1,249 @@
+package com.wsm.admin.api;
+
+import com.alibaba.fastjson.JSONObject;
+import com.wsm.admin.constant.MsgCode;
+import com.wsm.admin.model.Device;
+import com.wsm.admin.model.DeviceEvent;
+import com.wsm.admin.service.IDeviceEventService;
+import com.wsm.admin.service.IDeviceService;
+import com.wsm.common.api.BaseController;
+import com.wsm.common.constant.ConstantType;
+import com.wsm.common.util.AjaxJson;
+import com.wsm.common.util.PasswordUtils;
+import com.wsm.common.util.RedisUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.BoundGeoOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@RestController
+@RequestMapping("/api/device")
+public class ApiDeviceController extends BaseController {
+
+    private Logger logger = LoggerFactory.getLogger(getClass());
+
+    @Autowired
+    private IDeviceService deviceService;
+
+    @Autowired
+    private IDeviceEventService deviceEventService;
+
+
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+
+    @Autowired
+    private RedisUtil redisUtil;
+
+    /**
+     * 获取所有的设备信息
+     * @return
+     */
+    @RequestMapping(value = {"/list"})
+    public AjaxJson list() {
+        List<Device> list = (List) redisTemplate.opsForValue().get(MsgCode.REDIS_CYCLE_DEVICE_LIST);
+        if (list == null) {
+            logger.info("list size: ");
+            list = deviceService.findAll();
+            redisTemplate.opsForValue().set(MsgCode.REDIS_CYCLE_DEVICE_LIST, list, 24, TimeUnit.HOURS);
+
+        }
+       return AjaxJson.success(list);
+    }
+
+
+
+    /**
+     * 潮庭-海康烟感接口
+     * 物联网平台主动推数据给我们
+     * 221.4.210.172:2001/api/device/smoke
+     * appId:a36dff423b9365be
+     *
+     *
+     * {"devid": "609290399","pid": "NP-FDY100-N","pname": "YD100N烟感","a_name": "港湾1号港11栋”,”time": "2020-07-08 09:23:04""reported": { "batteryPower": "100%","smokeScope":"27%","dirtyPercent":"1%", "signalSNR":120,"signalECL":0, "rsrp":-90,}}
+     *
+     * 7:59     15:59     23:59   三次心跳 一天三次心跳
+     * @return
+     */
+    @PostMapping("smoke")
+    public AjaxJson smokeInfo(String xKey, String deviceData) {
+        logger.info("run smokeInfo");
+        logger.info("xKey: {}" , xKey);
+        logger.info("deviceData: {}",  deviceData);
+
+        if (xKey == null) {
+            logger.error("xKey is null");
+            return AjaxJson.failure("xKey is null");
+        }
+
+        // 验证xKey
+        String plaintext = PasswordUtils.decrypt(xKey, ConstantType.COVER_PASSWORD, PasswordUtils.getStaticSalt());
+        if (!ConstantType.COVER_USERNAME.equals(plaintext)) {
+            logger.error("xKey is invalid");
+            return AjaxJson.failure("xKey is invalid");
+        }
+
+        if (deviceData == null) {
+            logger.error("deviceData is null");
+            return AjaxJson.failure("deviceData is null");
+        }
+
+        // 解析json数据
+        JSONObject jsonObject = JSONObject.parseObject(deviceData);
+
+        String deviceId = jsonObject.getString("devid");
+        Date date = jsonObject.getDate("time");
+
+        Device device = deviceService.findByDeviceId(deviceId);
+
+                if (device == null) {
+            logger.error("设备不存在: {}", deviceId );
+            return AjaxJson.failure("设备不存在");
+        }
+
+        String reported = jsonObject.getString("reported");
+
+        DeviceEvent entity = new DeviceEvent();
+        entity.setDevice(device);
+        entity.setPostTime(date);
+        // 0:报警
+        entity.setHandleStatus((byte) 0);
+
+        // reported != null 自检
+        if (reported != null) {
+            logger.info("设备心跳检测");
+            // 用来心跳检测
+            redisUtil.set(deviceId,"heartbeat", Long.parseLong("25"));
+
+            JSONObject reportedJaon = jsonObject.getJSONObject("reported");
+            String batteryPower = reportedJaon.getString("batteryPower");
+            String replace = batteryPower.replace(batteryPower, "%");
+            Integer power = Integer.valueOf(replace);
+
+
+
+            if (power < 10) {
+                logger.info("烟感低电压");
+                entity.setContent(ConstantType.EVENT_POWER);
+                deviceEventService.save(entity);
+            }
+
+            return AjaxJson.success();
+
+            // reported == null 报警(报警类型:1 火灾,2 故障)
+        } else {
+
+            String alarmTypeName = jsonObject.getString("alarm_type_name");
+            entity.setContent(alarmTypeName);
+            deviceEventService.save(entity);
+        }
+        logger.info("end smokeInfo");
+        return AjaxJson.success();
+    }
+
+
+    /**
+     * 旗云井盖传感器接口
+     * 物联网平台主动推数据给我们
+     * 221.4.210.172:2001/api/device/cover
+     * appId:a36dff423b9365be
+     *
+     * 7:59     15:59     23:59   三次心跳 一天三次心跳
+     * @return
+     */
+    @PostMapping(value = {"/cover"})
+    public AjaxJson coverInfo(String xKey, String deviceData) {
+        logger.info("run coverInfo");
+        logger.info("xKey: {}" , xKey);
+        logger.info("deviceData: {}",  deviceData);
+
+        if (xKey == null) {
+            logger.error("xKey is null");
+            return AjaxJson.failure("xKey is null");
+        }
+
+        // 验证xKey
+        String plaintext = PasswordUtils.decrypt(xKey, ConstantType.COVER_PASSWORD, PasswordUtils.getStaticSalt());
+        if (!ConstantType.COVER_USERNAME.equals(plaintext)) {
+            logger.error("xKey is invalid");
+            return AjaxJson.failure("xKey is invalid");
+        }
+
+        if (deviceData == null) {
+            logger.error("deviceData is null");
+            return AjaxJson.failure("deviceData is null");
+        }
+
+        // 解析json数据
+        JSONObject jsonObject = JSONObject.parseObject(deviceData);
+        Integer status = jsonObject.getInteger("status");
+        String deviceCode = jsonObject.getString("deviceCode");
+
+        if (status == 2) {
+            logger.info("设备心跳检测");
+            // 用来心跳检测
+            redisUtil.set(deviceCode,"heartbeat", Long.parseLong("25"));
+            return AjaxJson.success();
+        }
+
+
+        Integer AngleWarn = jsonObject.getInteger("AngleWarn");
+        Date date = jsonObject.getDate("date");
+        Device device = deviceService.findByDeviceId(deviceCode);
+        if (device == null) {
+            logger.error("设备不存在: {}", deviceCode );
+            return AjaxJson.failure("设备不存在");
+        }
+        // 设备角度大于30度,报警
+        DeviceEvent entity = new DeviceEvent();
+        entity.setDevice(device);
+        entity.setPostTime(date);
+
+        if (AngleWarn > 0) {
+            logger.info("井盖被开启");
+
+            entity.setHandleStatus((byte)0);
+            entity.setContent(ConstantType.JG_EVENT_OPEN);
+
+
+        }
+
+        deviceEventService.save(entity);
+
+
+        Integer electric = jsonObject.getInteger("electric");
+        if (electric < 10) {
+            logger.info("井盖传感器低电压: {}", deviceCode );
+
+            entity.setHandleStatus((byte)0);
+            entity.setContent(ConstantType.EVENT_POWER);
+
+
+        }
+
+        deviceEventService.save(entity);
+
+
+        logger.info("end coverInfo");
+        return AjaxJson.success();
+    }
+
+    public static void main(String[] args) {
+//        String key = PasswordUtils.encrypt(ConstantType.COVER_USERNAME, ConstantType.COVER_PASSWORD, PasswordUtils.getStaticSalt());
+//        System.out.println(key);
+        String key = "a36dff423b9365be";
+        String admin = PasswordUtils.decrypt(key, ConstantType.COVER_PASSWORD, PasswordUtils.getStaticSalt());
+        System.out.println(admin);
+
+
+    }
+}

+ 89 - 0
wsm-admin-web/src/main/java/com/wsm/admin/api/DataDictionaryController.java

@@ -0,0 +1,89 @@
+package com.wsm.admin.api;
+
+import com.wsm.admin.model.DataDictionary;
+import com.wsm.admin.service.IDataDictionaryService;
+import com.wsm.common.api.BaseController;
+import com.wsm.common.util.AjaxJson;
+import com.wsm.common.util.ConstantUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Sort;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 数据字典管理
+ */
+@Controller
+@RequestMapping("/admin/dataDictionary")
+public class DataDictionaryController extends BaseController {
+	
+	private Logger logger = LoggerFactory.getLogger(getClass());
+
+	@Autowired
+    private IDataDictionaryService dataDictionaryService;
+
+    @RequestMapping(value = {"/list"})
+    public String index(Model model) {
+        Page<DataDictionary> dataDictionaryList = dataDictionaryService.findAll(getPageRequest(
+                new Sort(Sort.Direction.DESC, "id")));
+        model.addAttribute("dataDictionaryList", dataDictionaryList);
+        return "/admin/dataDictionary/list";
+    }
+
+    @RequestMapping(value = {"/detail"}, method = RequestMethod.GET)
+    public String detail(@RequestParam(required = false) String dataDictionaryId, Model model) {
+        DataDictionary dataDictionary = new DataDictionary();
+        if (dataDictionaryId != null) {
+            dataDictionary = dataDictionaryService.find(Long.valueOf(dataDictionaryId));
+        }
+        model.addAttribute("dataDictionary", dataDictionary);
+        return "/admin/dataDictionary/form";
+    }
+
+    @RequestMapping(value = {"/save"}, method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxJson edit(DataDictionary dataDictionary) {
+        try {
+        	if (dataDictionary.getId() == null) {
+        		DataDictionary dbDictionary = dataDictionaryService.findByCodeAndDataKey(dataDictionary.getCode(), dataDictionary.getDataKey());
+        		if (dbDictionary != null){
+                    return AjaxJson.failure("您所输入的数据类型代码和数据键已存在,请修改后再提交!");
+        		}
+        	}
+            dataDictionaryService.saveOrUpdate(dataDictionary);
+        } catch (Exception e) {
+        	logger.error("系统异常:", e);
+            return AjaxJson.failure("系统异常:"+e);
+        }
+        return AjaxJson.success();
+    }
+    
+    /**
+     * 删除
+     */
+    @RequestMapping(value = {"/remove"}, method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxJson remove(String dataDictionaryId) {
+        AjaxJson ajaxJson = null;
+        try {
+            if (!StringUtils.isEmpty(dataDictionaryId)) {
+                DataDictionary dbDataDictionary = dataDictionaryService.find(Long.valueOf(dataDictionaryId));
+                dbDataDictionary.setRecStatus("I");
+                dataDictionaryService.update(dbDataDictionary);
+                ajaxJson =  AjaxJson.success(ConstantUtils.SUCCESS_MSG);
+            }else{
+                ajaxJson = AjaxJson.failure("新闻id不能为空");
+            }
+        } catch (Exception e) {
+            logger.error("系统异常:", e);
+            return AjaxJson.failure("系统异常:" + e);
+        }
+        return ajaxJson;
+    }
+
+}

+ 123 - 0
wsm-admin-web/src/main/java/com/wsm/admin/api/DeviceController.java

@@ -0,0 +1,123 @@
+package com.wsm.admin.api;
+
+import com.wsm.admin.constant.MsgCode;
+import com.wsm.admin.model.Device;
+import com.wsm.admin.service.IDeviceEventService;
+import com.wsm.admin.service.IDeviceService;
+import com.wsm.common.api.BaseController;
+import com.wsm.common.util.AjaxJson;
+import com.wsm.common.util.ConstantUtils;
+import com.wsm.common.util.RedisUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * 设备管理
+ */
+@Controller
+@RequestMapping("/admin/device")
+public class DeviceController extends BaseController {
+
+    private Logger logger = LoggerFactory.getLogger(getClass());
+
+    @Autowired
+    private IDeviceService deviceService;
+
+    @Autowired
+    private IDeviceEventService deviceEventService;
+
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+    @RequestMapping(value = {"/list"})
+    public String index(Model model) {
+        Page<Device> deviceList = deviceService.findAll(getPageRequest(
+                new Sort(Sort.Direction.DESC, "id")));
+        model.addAttribute("deviceList", deviceList);
+        return "/admin/device/list";
+    }
+
+    @RequestMapping(value = {"/detail"}, method = RequestMethod.GET)
+    public String detail(@RequestParam(required = false) String deviceId, Model model) {
+        Device device = new Device();
+        if (deviceId != null) {
+            device = deviceService.find(Long.valueOf(deviceId));
+        }
+        model.addAttribute("device", device);
+        return "/admin/device/form";
+    }
+
+    @RequestMapping(value = {"/save"}, method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxJson edit(Device device) {
+        try {
+
+            if (device.getId() != null) {
+                Device dbDevice = deviceService.find(Long.valueOf(device.getId()));
+                dbDevice.setDeviceId16Hex(device.getDeviceId16Hex());
+                dbDevice.setDeviceId(device.getDeviceId());
+                dbDevice.setDeviceType(device.getDeviceType());
+                dbDevice.setLongitude(device.getLongitude());
+                dbDevice.setLatitude(device.getLatitude());
+                dbDevice.setAddress(device.getAddress());
+                deviceService.update(dbDevice);
+            }else{
+                device.setStatus((byte)0);
+                deviceService.save(device);
+            }
+
+            // 删除缓存
+            redisTemplate.delete(MsgCode.REDIS_CYCLE_DEVICE_LIST);
+
+        } catch (Exception e) {
+            logger.error("系统异常:", e);
+            return AjaxJson.failure("系统异常:"+e);
+        }
+        return AjaxJson.success();
+    }
+
+    /**
+     * 删除
+     */
+    @RequestMapping(value = {"/remove"}, method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxJson remove(String deviceId) {
+        AjaxJson ajaxJson = null;
+        try {
+            if (!StringUtils.isEmpty(deviceId)) {
+                Device dbDevice = deviceService.find(Long.valueOf(deviceId));
+                dbDevice.setRecStatus("I");
+
+                // 将设备对应的事件设置为禁用状态
+                Long id = dbDevice.getId();
+                deviceEventService.setRecStatuBydeviceId(id, "I");
+
+                deviceService.update(dbDevice);
+
+                ajaxJson =  AjaxJson.success(ConstantUtils.SUCCESS_MSG);
+            }else{
+                ajaxJson = AjaxJson.failure("id不能为空");
+            }
+
+            // 删除缓存
+            redisTemplate.delete(MsgCode.REDIS_CYCLE_DEVICE_LIST);
+        } catch (Exception e) {
+            logger.error("系统异常:", e);
+            return AjaxJson.failure("系统异常:" + e);
+        }
+        return ajaxJson;
+    }
+
+}
+

+ 123 - 0
wsm-admin-web/src/main/java/com/wsm/admin/api/DeviceEventController.java

@@ -0,0 +1,123 @@
+package com.wsm.admin.api;
+
+import com.wsm.admin.constant.MsgCode;
+import com.wsm.admin.model.Device;
+import com.wsm.admin.model.DeviceEvent;
+import com.wsm.admin.service.IDeviceEventService;
+import com.wsm.admin.service.IDeviceService;
+import com.wsm.common.api.BaseController;
+import com.wsm.common.util.AjaxJson;
+import com.wsm.common.util.ConstantUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.Date;
+
+/**
+ * 设备警告管理
+ */
+
+@Controller
+@RequestMapping("/admin/deviceEvent")
+public class DeviceEventController extends BaseController {
+
+    private Logger logger = LoggerFactory.getLogger(getClass());
+
+    @Autowired
+    private IDeviceEventService deviceEventService;
+
+    @Autowired
+    private IDeviceService deviceService;
+
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+    @RequestMapping(value = {"/list"})
+    public String index(Model model) {
+        Page<DeviceEvent> deviceEventList = deviceEventService.findAll(getPageRequest(
+                new Sort(Sort.Direction.DESC, "id")));
+        model.addAttribute("deviceEventList", deviceEventList);
+        return "/admin/deviceEvent/list";
+    }
+
+    @RequestMapping(value = {"/detail"}, method = RequestMethod.GET)
+    public String detail(@RequestParam(required = false) String deviceEventId, Model model) {
+        DeviceEvent deviceEvent = new DeviceEvent();
+        if (deviceEventId != null) {
+            deviceEvent = deviceEventService.find(Long.valueOf(deviceEventId));
+        }
+        logger.info("device: {}", deviceEvent.getDevice().toString());
+        model.addAttribute("deviceEvent", deviceEvent);
+        model.addAttribute("device", deviceEvent.getDevice());
+        return "/admin/deviceEvent/form";
+    }
+
+    /**
+     * 删除
+     */
+    @RequestMapping(value = {"/remove"}, method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxJson remove(String deviceEventId) {
+        AjaxJson ajaxJson = null;
+        try {
+            if (!StringUtils.isEmpty(deviceEventId)) {
+                DeviceEvent dbDeviceEvent = deviceEventService.find(Long.valueOf(deviceEventId));
+                dbDeviceEvent.setRecStatus("I");
+                deviceEventService.update(dbDeviceEvent);
+                ajaxJson =  AjaxJson.success(ConstantUtils.SUCCESS_MSG);
+            }else{
+                ajaxJson = AjaxJson.failure("id不能为空");
+            }
+        } catch (Exception e) {
+            logger.error("系统异常:", e);
+            return AjaxJson.failure("系统异常:" + e);
+        }
+        return ajaxJson;
+    }
+
+
+    /**
+     * 修改
+     * @param
+     * @return
+     */
+    @RequestMapping(value = {"/save"}, method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxJson edit(DeviceEvent deviceEvent) {
+        logger.info("dto: {}", deviceEvent.toString());
+        DeviceEvent event = deviceEventService.find(deviceEvent.getId());
+        if (event != null){
+          event.setUpdateTime(new Date());
+          event.setHandleStatus(deviceEvent.getHandleStatus());
+//          deviceEventService.save(event)
+          event = deviceEventService.update(event);
+
+          // 3: 已处理
+          if (event.getHandleStatus() == 3) {
+              Device device = event.getDevice();
+              device.setStatus((byte)0);
+              device.setUpdateTime(new Date());
+              deviceService.update(device);
+
+              // 删除缓存
+              redisTemplate.delete(MsgCode.REDIS_CYCLE_DEVICE_LIST);
+          }
+        }
+
+
+
+        return AjaxJson.success();
+    }
+
+}

+ 81 - 0
wsm-admin-web/src/main/java/com/wsm/admin/api/FileController.java

@@ -0,0 +1,81 @@
+package com.wsm.admin.api;
+
+import com.alibaba.fastjson.JSONObject;
+import com.wsm.common.api.BaseController;
+import com.wsm.common.util.AjaxJson;
+import com.wsm.common.util.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.UUID;
+
+@Controller
+public class FileController extends BaseController {
+
+    @Value("${web.upload.file.path}")
+    private String path;
+
+    private Logger logger = LoggerFactory.getLogger(getClass());
+
+    @RequestMapping(value = "/upload/file", method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxJson uploadFile(HttpServletRequest req, MultipartFile file) {
+        String newFileName = null;
+        try {
+            newFileName = FileUtils.uploadFile(req, file, path);
+        } catch (Exception e) {
+            logger.error("系统异常:", e);
+            return AjaxJson.failure("系统异常:" + e);
+        }
+        return AjaxJson.success("SUCCESS", newFileName);
+    }
+
+    @RequestMapping(value = "/upload/audio", method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxJson uploadAudio(HttpServletRequest req, MultipartFile file) {
+        String fileName= null;
+        try {
+            fileName = FileUtils.uploadFile(req, file, path + "audio/");
+            fileName = "/audio" + fileName;
+        } catch (Exception e) {
+            logger.error("系统异常:", e);
+            return AjaxJson.failure("系统异常:" + e);
+        }
+        return AjaxJson.success("SUCCESS", fileName);
+    }
+
+    @RequestMapping(value = "/upload/image", method = RequestMethod.POST)
+    @ResponseBody
+    public JSONObject uploadImage(HttpServletRequest req, MultipartFile upfile) {
+        String newFileName = null;
+        try {
+            newFileName = FileUtils.uploadFile(req, upfile, path);
+        } catch (Exception e) {
+            logger.error("系统异常:", e);
+            JSONObject error = new JSONObject();
+            error.put("code", -1);
+            return error;
+        }
+//        String src = server + newFileName;
+        JSONObject data = new JSONObject();
+        data.put("name", newFileName);
+        data.put("originalName", upfile.getOriginalFilename());
+        data.put("size", upfile.getSize());
+        data.put("state", "SUCCESS");
+        data.put("type", getFileExt(upfile.getOriginalFilename()));
+        data.put("url", newFileName);
+
+        return data;
+    }
+
+    private String getFileExt(String fileName) {
+        return fileName.substring(fileName.lastIndexOf("."));
+    }
+}

+ 87 - 0
wsm-admin-web/src/main/java/com/wsm/admin/api/IndexController.java

@@ -0,0 +1,87 @@
+package com.wsm.admin.api;
+
+import com.wsm.admin.model.User;
+import com.wsm.admin.service.IResourceService;
+import com.wsm.admin.service.IUserService;
+import com.wsm.common.api.BaseController;
+import com.wsm.common.util.AjaxJson;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.subject.Subject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.http.HttpServletRequest;
+
+@Controller
+public class IndexController extends BaseController {
+
+    @Autowired
+    private IUserService userService;
+    @Autowired
+    private IResourceService resourceService;
+
+    @RequestMapping(value = {"/admin", "/admin/login"}, method = RequestMethod.GET)
+    public String login(Model model) {
+        return "login";
+    }
+
+    @RequestMapping(value = {"/admin/index"}, method = RequestMethod.GET)
+    public String index(Model model) {
+        Subject subject = SecurityUtils.getSubject();
+        Object principal = subject.getPrincipal();
+        User user = (User) principal;
+
+
+        User dbUser = userService.findByUserName(user.getUserName());
+        model.addAttribute("user", dbUser);
+
+
+        model.addAttribute("user", user);
+        try {
+            model.addAttribute("resources", resourceService.getResourcesByUser(dbUser));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+
+        return "index";
+    }
+
+    @RequestMapping("/home")
+    public String home() {
+        return "home";
+    }
+
+    @ResponseBody
+    @RequestMapping(value = {"/admin/login"}, method = RequestMethod.POST)
+    public AjaxJson login(User user, String randomcode, boolean rememberMe, Model model) {
+        AjaxJson ajaxJson = null;
+        try {
+        	String validateCode = (String) request.getSession().getAttribute("validateCode");
+			if (randomcode != null && validateCode != null && !randomcode.equals(validateCode)) {
+				throw new AuthenticationException("验证码错误");
+	        }
+            Subject subject = SecurityUtils.getSubject();
+            UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), user.getPassword(), rememberMe);
+            subject.login(token);
+            ajaxJson = AjaxJson.success();
+        } catch (Exception e) {
+            ajaxJson = AjaxJson.failure(e.getMessage());
+        }
+        return ajaxJson;
+    }
+    
+    @RequestMapping(value = {"/admin/logout"}, method = RequestMethod.POST)
+    public String logout() {
+        Subject subject = SecurityUtils.getSubject();
+        subject.logout();
+        return redirect("admin/login");
+    }
+}

+ 71 - 0
wsm-admin-web/src/main/java/com/wsm/admin/api/KaptchaController.java

@@ -0,0 +1,71 @@
+package com.wsm.admin.api;
+
+import com.google.code.kaptcha.Producer;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import javax.imageio.ImageIO;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+@Controller
+public class KaptchaController {
+
+    @Autowired
+    private Producer captchaProducer;
+
+    /**
+     * 后台登录验证码
+     * @param request
+     * @param response
+     * @throws Exception
+     */
+    @RequestMapping("/kaptcha")
+    public void kaptcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
+        generateKaptcha(request, response, "validateCode");
+    }
+
+    /**
+     * 官网登录验证码
+     * @param request
+     * @param response
+     * @throws Exception
+     */
+    @RequestMapping("/api/kaptcha")
+    public void apiKaptcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
+        generateKaptcha(request, response, "apiValidateCode");
+    }
+
+    private void generateKaptcha(HttpServletRequest request, HttpServletResponse response, String apiValidateCode) throws IOException {
+        byte[] captchaChallengeAsJpeg;
+        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
+        try {
+            //生产验证码字符串并保存到session中
+            String createText = captchaProducer.createText();
+            request.getSession().setAttribute(apiValidateCode, createText);
+            //使用生产的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中
+            BufferedImage challenge = captchaProducer.createImage(createText);
+            ImageIO.write(challenge, "jpg", jpegOutputStream);
+        } catch (IllegalArgumentException e) {
+            response.sendError(HttpServletResponse.SC_NOT_FOUND);
+            return;
+        }
+
+        //定义response输出类型为image/jpeg类型,使用response输出流输出图片的byte数组
+        captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
+        response.setHeader("Cache-Control", "no-store");
+        response.setHeader("Pragma", "no-cache");
+        response.setDateHeader("Expires", 0);
+        response.setContentType("image/jpeg");
+        ServletOutputStream responseOutputStream = response.getOutputStream();
+        responseOutputStream.write(captchaChallengeAsJpeg);
+        responseOutputStream.flush();
+        responseOutputStream.close();
+    }
+
+}

+ 111 - 0
wsm-admin-web/src/main/java/com/wsm/admin/api/LiveController.java

@@ -0,0 +1,111 @@
+package com.wsm.admin.api;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.wsm.common.util.AjaxJson;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by Hb_zzZ on 2019/3/29.
+ */
+@RestController
+public class LiveController {
+
+    private Logger logger = LoggerFactory.getLogger(getClass());
+
+    @Value("${live.key}")
+    private String liveKey;
+
+    @Value("${live.number.url}")
+    private String numberUrl;
+
+    @Value("${live.info.url}")
+    private String infoUrl;
+
+    @Value("${yingshi.live.key}")
+    private String key;
+
+    @Value("${yingshi.live.secret}")
+    private String secret;
+
+    @Value("${yingshi.token.url}")
+    private String tokenUrl;
+
+    @Value("${yingshi.info.url}")
+    private String infoList;
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+    @RequestMapping(value = {"/live/getLiveUrlList"})
+    public AjaxJson getLiveUrlList() {
+
+        List<String> urlList = new ArrayList<>();
+
+        JSONObject postData = new JSONObject();
+        postData.put("key", liveKey);
+        JSONObject json = restTemplate.postForObject(numberUrl, postData, JSONObject.class);
+        logger.info("接口数据:" + json.toString());
+
+        if(json.containsKey("sessions")){
+            JSONArray numberArray = json.getJSONArray("sessions");
+            for(int i = 0; i < numberArray.size(); i++){
+                JSONObject job = numberArray.getJSONObject(i);  // 遍历 jsonarray 数组,把每一个对象转成 json 对象
+                if(job.containsKey("serial_number")){
+                    postData.put("serial_number", job.get("serial_number"));
+                    JSONObject jsonObj = restTemplate.postForObject(infoUrl, postData, JSONObject.class);
+                    logger.info("直播url数据:" + jsonObj.get("hlsUrl").toString());
+                    urlList.add(jsonObj.get("hlsUrl").toString());
+                }
+            }
+        }
+
+        HttpHeaders headers = new HttpHeaders();
+        //  请勿轻易改变此提交方部分的情况下,提交方式都是表单提交
+        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+        //  封装参数,千万不要替换为Map与HashMap,否则参数无法传递
+        MultiValueMap<String, String> params= new LinkedMultiValueMap<String, String>();
+        //  也支持中文
+        params.add("appKey", key);
+        params.add("appSecret", secret);
+        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String, String>>(params, headers);
+        //  执行HTTP请求
+        ResponseEntity<String> response = restTemplate.postForEntity(tokenUrl, params, String.class);
+
+        JSONObject yingShiToken = JSONObject.parseObject(response.getBody());
+        if("200".equals(yingShiToken.get("code").toString())){
+            String token = yingShiToken.getJSONObject("data").get("accessToken").toString();
+
+            params= new LinkedMultiValueMap<String, String>();
+            params.add("accessToken", token);
+            response = restTemplate.postForEntity(infoList, params, String.class);
+            JSONObject yingShiList = JSONObject.parseObject(response.getBody());
+            if("200".equals(yingShiList.get("code").toString())){
+                JSONArray list = yingShiList.getJSONArray("data");
+                for(int i = 0; i < list.size(); i++){
+                    JSONObject job = list.getJSONObject(i);  // 遍历 jsonarray 数组,把每一个对象转成 json 对象
+                    urlList.add(job.get("hdAddress").toString());
+                }
+            }
+        }
+        return AjaxJson.success(urlList);
+    }
+}

+ 160 - 0
wsm-admin-web/src/main/java/com/wsm/admin/api/ResourceController.java

@@ -0,0 +1,160 @@
+package com.wsm.admin.api;
+
+import com.wsm.admin.dto.ResourceTree;
+import com.wsm.admin.model.Resource;
+import com.wsm.admin.model.Role;
+import com.wsm.admin.service.IResourceService;
+import com.wsm.admin.service.IRoleService;
+import com.wsm.admin.util.ResourceTreeUtil;
+import com.wsm.common.api.BaseController;
+import com.wsm.common.util.AjaxJson;
+import com.wsm.common.util.ConstantUtils;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import java.util.ArrayList;
+import java.util.List;
+
+@Controller
+@RequestMapping("/admin/resource")
+public class ResourceController extends BaseController {
+
+    private Logger logger = LoggerFactory.getLogger(getClass());
+
+    @Autowired
+    private IResourceService resourceService;
+
+    @Autowired
+    private IRoleService roleService;
+
+    @RequestMapping("/list")
+    public String list(Model model) {
+        try {
+            List<ResourceTree> listTree = resourceService.getTree();
+            model.addAttribute("resourceTree", listTree);
+
+            Subject subject = SecurityUtils.getSubject();
+            model.addAttribute("editCheck", subject.isPermitted("admin:resource:edit"));
+            model.addAttribute("removeCheck", subject.isPermitted("admin:resource:remove"));
+        } catch (Exception e) {
+            logger.error("系统异常:", e);
+        }
+        return "/admin/resource/list";
+    }
+
+    @RequestMapping(value = {"/detail"}, method = RequestMethod.GET)
+    public String detail(@RequestParam(required = false) String resourceId, Model model) {
+        Resource resource = new Resource();
+        if (resourceId != null) {
+            resource = resourceService.find(Long.valueOf(resourceId));
+        }
+        model.addAttribute("parentName", resource.getParentId() != null ? resource.getParentId().getName() : "");
+        model.addAttribute("resource", resource);
+        return "/admin/resource/form";
+    }
+
+    /**
+     * 新增或修改角色信息
+     */
+    @RequestMapping(value = {"/save"}, method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxJson save(Resource resource, String parentResourceId, Model model) {
+        try {
+            if (!StringUtils.isEmpty(resource.getId())) {
+                Resource dbResource = resourceService.find(resource.getId());
+                if (!dbResource.getResourceKey().equals(resource.getResourceKey())) {
+                    boolean exists = resourceService.existsByResourceKey(resource.getResourceKey());
+                    if (exists) {
+                        return AjaxJson.failure("该权限标识已存在");
+                    }
+                }
+                dbResource.setName(resource.getName());
+                dbResource.setResourceKey(resource.getResourceKey());
+                dbResource.setResourceType(resource.getResourceType());
+                dbResource.setUrl(resource.getUrl());
+                dbResource.setSort(resource.getSort());
+                dbResource.setDescription(resource.getDescription());
+                resourceService.update(dbResource);
+            } else {
+                boolean exists = resourceService.existsByResourceKey(resource.getResourceKey());
+                if (exists) {
+                    return AjaxJson.failure("该权限标识已存在");
+                }
+                if (!StringUtils.isEmpty(parentResourceId)) {
+                    Resource parentResource = resourceService.find(Long.valueOf(parentResourceId));
+                    resource.setParentId(parentResource);
+                }
+                resourceService.save(resource);
+            }
+            return AjaxJson.success(ConstantUtils.SUCCESS_MSG);
+        } catch (Exception e) {
+            logger.error("系统异常:", e);
+            return AjaxJson.failure("系统异常:" + e);
+        }
+    }
+
+    /**
+     * 删除角色
+     */
+    @RequestMapping(value = {"/remove"}, method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxJson remove(String resourceId, Model model) {
+        try {
+            if (!StringUtils.isEmpty(resourceId)) {
+                Resource resource = resourceService.find(Long.valueOf(resourceId));
+                Sort sort = new Sort(Sort.Direction.DESC, "createTime");
+                List<Resource> childResource = resourceService.findList(new Specification<Resource>() {
+                    @Override
+                    public Predicate toPredicate(Root<Resource> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
+                        List<Predicate> predicates = new ArrayList<Predicate>();
+                        predicates.add(cb.equal(root.get("parentId").as(Resource.class), resource));
+                        return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+                    }
+                }, sort);
+
+                if (childResource != null && childResource.size() > 0) {
+                    return AjaxJson.failure("该资源拥有子资源,不能删除");
+                }
+                resource.setParentId(null);
+                resource.setRecStatus("I");
+                resourceService.update(resource);
+                return AjaxJson.success(ConstantUtils.SUCCESS_MSG);
+            }
+            return AjaxJson.failure("资源id不能为空");
+        } catch (Exception e) {
+            logger.error("系统异常:", e);
+            return AjaxJson.failure("系统异常:" + e);
+        }
+    }
+
+    @RequestMapping(value = {"/getByRoleId"}, method = RequestMethod.GET)
+    @ResponseBody
+    public List<ResourceTree> getResourcesByRoleId(String roleId) {
+        Role role = new Role();
+        List<Resource> all = resourceService.findAll();
+        List<Resource> in = new ArrayList<>();
+        if (roleId != null) {
+            role = roleService.find(Long.valueOf(roleId));
+            role.getResources().forEach(resource -> in.add(resource));
+        }
+        ResourceTreeUtil resourceTreeUtil = new ResourceTreeUtil();
+        return resourceTreeUtil.buildTree(all, in);
+    }
+
+}

+ 133 - 0
wsm-admin-web/src/main/java/com/wsm/admin/api/RoleController.java

@@ -0,0 +1,133 @@
+package com.wsm.admin.api;
+
+import com.wsm.admin.model.Resource;
+import com.wsm.admin.model.Role;
+import com.wsm.admin.service.IRoleService;
+import com.wsm.common.api.BaseController;
+import com.wsm.common.util.AjaxJson;
+import com.wsm.common.util.ConstantUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Sort;
+import org.springframework.stereotype.Controller;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.ui.Model;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+@Controller
+@RequestMapping("/admin/role")
+public class RoleController extends BaseController {
+
+    private Logger logger = LoggerFactory.getLogger(getClass());
+
+    @Autowired
+    private IRoleService roleService;
+
+    @RequestMapping("/list")
+    @Transactional(readOnly = true)
+    public String list(Model model) {
+        Page<Role> roleList = roleService.findAll(getPageRequest(new Sort(Sort.Direction.DESC, "createTime")));
+        /*if (roleList != null){
+            for (Role role : roleList){
+                role.setResources(null);
+            }
+        }*/
+        model.addAttribute("roles", roleList);
+        return "/admin/role/list";
+    }
+
+    @RequestMapping(value = {"/detail"}, method = RequestMethod.GET)
+    public String detail(@RequestParam(required = false) String roleId, Model model) throws Exception {
+        Role role = new Role();
+        if (roleId != null) {
+            role = roleService.find(Long.valueOf(roleId));
+            Set<Resource> resources = role.getResources();
+            StringBuffer sb = new StringBuffer();
+            int i = 1;
+            for (Iterator<Resource> it = resources.iterator(); it.hasNext(); ++i) {
+                sb.append(it.next().getName()).append(i == resources.size() ? "" : ",");
+            }
+            model.addAttribute("checkNodesName", sb.toString());
+        }
+        model.addAttribute("role", role);
+        return "/admin/role/form";
+    }
+
+    /**
+     * 新增或修改角色信息
+     */
+    @RequestMapping(value = {"/save"}, method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxJson save(Role role, String resourceIds, Model model) {
+        try {
+            Set<Resource> resources = new HashSet<>();
+            if (resourceIds != null) {
+                String[] resourceIdArr = resourceIds.split(",");
+                for (String id : resourceIdArr) {
+                    Resource resource = new Resource();
+                    resource.setId(Long.valueOf(id));
+                    resources.add(resource);
+                }
+            }
+
+            if (!StringUtils.isEmpty(role.getId())) {
+                Role dbRole = roleService.find(role.getId());
+                if (!dbRole.getRoleKey().equals(role.getRoleKey())) {
+                    boolean exists = roleService.existsByRoleKey(role.getRoleKey());
+                    if (exists) {
+                        return AjaxJson.failure("该标识符已存在");
+                    }
+                }
+                dbRole.setRoleName(role.getRoleName());
+                dbRole.setRoleKey(role.getRoleKey());
+                dbRole.setRoleDesc(role.getRoleDesc());
+
+                dbRole.setResources(resources);
+                roleService.update(dbRole);
+            } else {
+                boolean exists = roleService.existsByRoleKey(role.getRoleKey());
+                if (exists) {
+                    return AjaxJson.failure("该标识符已存在");
+                }
+                role.setResources(resources);
+                roleService.save(role);
+            }
+            return AjaxJson.success(ConstantUtils.SUCCESS_MSG);
+        } catch (Exception e) {
+            logger.error("系统异常:", e);
+            return AjaxJson.failure("系统异常:" + e);
+        }
+    }
+
+    /**
+     * 删除角色
+     */
+    @RequestMapping(value = {"/remove"}, method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxJson remove(String roleId, Model model) {
+        try {
+            if (!StringUtils.isEmpty(roleId)) {
+                Role dbRole = roleService.find(Long.valueOf(roleId));
+                dbRole.setResources(null);
+                dbRole.setRecStatus("I");
+                roleService.update(dbRole);
+                return AjaxJson.success(ConstantUtils.SUCCESS_MSG);
+            }
+            return AjaxJson.failure("角色id不能为空");
+        } catch (Exception e) {
+            logger.error("系统异常:", e);
+            return AjaxJson.failure("系统异常:" + e);
+        }
+    }
+
+}

+ 32 - 0
wsm-admin-web/src/main/java/com/wsm/admin/api/TestController.java

@@ -0,0 +1,32 @@
+package com.wsm.admin.api;
+
+import com.wsm.admin.model.Device;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Created by Owen on 2019/12/5 0005 18:31
+ */
+@RestController
+@RequestMapping
+public class TestController {
+
+    @Autowired
+    private RedisTemplate<String, Object> redisTemplate;
+
+    @RequestMapping(value = {"/test"})
+    public String index() {
+        redisTemplate.opsForValue().set("owen","hao133",2, TimeUnit.HOURS);
+//        redisTemplate.expire("owen", 2, TimeUnit.HOURS);
+
+        return "2132132";
+    }
+}

+ 211 - 0
wsm-admin-web/src/main/java/com/wsm/admin/api/UserController.java

@@ -0,0 +1,211 @@
+package com.wsm.admin.api;
+
+import com.wsm.admin.model.Role;
+import com.wsm.admin.model.User;
+import com.wsm.admin.service.IRoleService;
+import com.wsm.admin.service.IUserService;
+import com.wsm.common.api.BaseController;
+import com.wsm.common.util.AjaxJson;
+import com.wsm.common.util.ConstantUtils;
+import com.wsm.common.util.PasswordUtils;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Sort;
+import org.springframework.stereotype.Controller;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.ui.Model;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Controller
+@RequestMapping("/admin/user")
+public class UserController extends BaseController {
+
+    private Logger logger = LoggerFactory.getLogger(getClass());
+
+    @Autowired
+    private IUserService userService;
+
+    @Autowired
+    private IRoleService roleService;
+
+    @RequestMapping("/list")
+    @Transactional(readOnly = true)
+    public String list(Model model) {
+        Page<User> userList = userService.findAll(getPageRequest(new Sort(Sort.Direction.DESC, "createTime")));
+        /*if (userList.getContent() != null){
+            for (User user : userList){
+                user.setRoles(null);
+            }
+        }*/
+        model.addAttribute("users", userList);
+        return "/admin/user/list";
+    }
+
+    /**
+     * 修改管理员信息
+     */
+    @RequestMapping(value = {"/detail"}, method = RequestMethod.GET)
+    public String detail(@RequestParam(required = false) String userId, Model model) throws Exception {
+        User dbUser = new User();
+        Subject subject = SecurityUtils.getSubject();
+        Object principal = subject.getPrincipal();
+        User user = (User) principal;
+
+        List<String> checkRoleIds = new ArrayList<>();
+        if (userId != null) {
+            dbUser = userService.find(Long.valueOf(userId));
+
+            for (Role role : dbUser.getRoles()) {
+                checkRoleIds.add(role.getId().toString());
+            }
+        }
+
+        Role role = new Role();
+        role.setRecStatus("A");
+
+        model.addAttribute("currentId", user.getId());
+        model.addAttribute("user", dbUser);
+        //待选角色列表
+        model.addAttribute("roles", roleService.find(role));
+        //已勾选角色ID
+        model.addAttribute("checkRoleId", String.join(",", checkRoleIds));
+        return "/admin/user/form";
+    }
+
+    /**
+     * 新增或修改管理员信息
+     */
+    @RequestMapping(value = {"/save"}, method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxJson save(User user, int[] roleIds, Model model) {
+        try {
+            if (!StringUtils.isEmpty(user.getId())) {
+                User dbUser = userService.find(user.getId());
+                dbUser.setUserName(user.getUserName());
+                dbUser.setRealName(user.getRealName());
+                dbUser.setStatus(user.getStatus());
+                dbUser.setAvatar(user.getAvatar());
+
+                Set<Role> roles = null;
+                if (roleIds != null && roleIds.length > 0) {
+                    roles = new HashSet<>();
+                    for (int i : roleIds) {
+                        roles.add(roleService.find(Long.valueOf(i)));
+                    }
+                }
+                dbUser.setRoles(roles);
+                userService.update(dbUser);
+            } else {
+                boolean exists = userService.existsByUserName(user.getUserName());
+                if (exists) {
+                    return AjaxJson.failure("该用户名已存在");
+                }
+                user.setPassword(PasswordUtils.encrypt("123456", user.getUserName(), PasswordUtils.getStaticSalt()));
+
+                Set<Role> roles = null;
+                if (roleIds != null && roleIds.length > 0) {
+                    roles = new HashSet<>();
+                    for (int i : roleIds) {
+                        roles.add(roleService.find(Long.valueOf(i)));
+                    }
+                }
+                user.setRoles(roles);
+                userService.save(user);
+            }
+            return AjaxJson.success(ConstantUtils.SUCCESS_MSG);
+        } catch (Exception e) {
+            logger.error("系统异常:", e);
+            return AjaxJson.failure("系统异常:" + e);
+        }
+    }
+
+    /**
+     * 重置密码
+     */
+    @RequestMapping(value = {"/resetPass"}, method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxJson resetPass(String userId, Model model) {
+        try {
+            if (!StringUtils.isEmpty(userId)) {
+                User dbUser = userService.find(Long.valueOf(userId));
+                dbUser.setPassword(PasswordUtils.encrypt("123456", dbUser.getUserName(), PasswordUtils.getStaticSalt()));
+                userService.update(dbUser);
+                return AjaxJson.success(ConstantUtils.SUCCESS_MSG);
+            }
+            return AjaxJson.failure("用户id不能为空");
+        } catch (Exception e) {
+            logger.error("系统异常:", e);
+            return AjaxJson.failure("系统异常:" + e);
+        }
+    }
+
+    /**
+     * 删除用户
+     */
+    @RequestMapping(value = {"/remove"}, method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxJson remove(String userId, Model model) {
+        try {
+            if (!StringUtils.isEmpty(userId)) {
+                User dbUser = userService.find(Long.valueOf(userId));
+                dbUser.setRoles(null);
+                dbUser.setRecStatus("I");
+                userService.update(dbUser);
+                return AjaxJson.success(ConstantUtils.SUCCESS_MSG);
+            }
+            return AjaxJson.failure("用户id不能为空");
+        } catch (Exception e) {
+            logger.error("系统异常:", e);
+            return AjaxJson.failure("系统异常:" + e);
+        }
+    }
+
+    /**
+     * 修改密码页面
+     *
+     * @return
+     */
+    @RequestMapping("/altPwd")
+    public String altPwd() {
+        return "/admin/user/updatePwd";
+    }
+
+    /**
+     * 修改密码
+     */
+    @RequestMapping("/updatePwd")
+    @ResponseBody
+    public AjaxJson updatePwd(@RequestParam String oldPassword, @RequestParam String password) {
+        try {
+            Subject subject = SecurityUtils.getSubject();
+            Object principal = subject.getPrincipal();
+            User user = (User) principal;
+
+            if (!PasswordUtils.encrypt(oldPassword, user.getUserName(), PasswordUtils.getStaticSalt()).equals(user.getPassword())) {
+                return AjaxJson.failure("原密码错误");
+            }
+
+            user.setPassword(PasswordUtils.encrypt(password, user.getUserName(), PasswordUtils.getStaticSalt()));
+            userService.update(user);
+            return AjaxJson.success(ConstantUtils.SUCCESS_MSG);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return AjaxJson.failure("操作异常");
+        }
+    }
+
+
+}

+ 9 - 0
wsm-admin-web/src/main/java/com/wsm/admin/constant/MsgCode.java

@@ -0,0 +1,9 @@
+package com.wsm.admin.constant;
+
+/**
+ * Created by Owen on 2019/12/13 0013 15:33
+ */
+public class MsgCode {
+
+    public static String REDIS_CYCLE_DEVICE_LIST = "cycleDeviceList";
+}

+ 262 - 0
wsm-admin-web/src/main/java/com/wsm/admin/handle/UdpServerHandler.java

@@ -0,0 +1,262 @@
+package com.wsm.admin.handle;
+
+import com.alibaba.fastjson.JSONObject;
+import com.wsm.admin.model.Device;
+import com.wsm.admin.model.DeviceEvent;
+import com.wsm.admin.service.IDeviceService;
+import com.wsm.admin.service.IDeviceEventService;
+import com.wsm.admin.service.impl.DeviceServiceImpl;
+import com.wsm.admin.service.impl.DeviceEventServiceImpl;
+import com.wsm.common.util.DeviceUtil;
+import com.wsm.common.util.ByteUtil;
+import com.wsm.common.util.SpringContext;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.socket.DatagramPacket;
+import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
+import org.joda.time.format.DateTimeFormat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.messaging.simp.SimpMessagingTemplate;
+
+import java.sql.Timestamp;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static java.lang.Long.parseLong;
+
+/**
+ * 接受UDP消息并且处理
+ *
+ */
+public class UdpServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {
+
+    private static final Logger log= LoggerFactory.getLogger(UdpServerHandler.class);
+
+    private IDeviceEventService deviceEventService;
+    private IDeviceService deviceService;
+    private SimpMessagingTemplate messagingTemplate;
+
+    public UdpServerHandler(){
+        if (deviceService == null){
+            deviceService = SpringContext.getBean(DeviceServiceImpl.class);
+        }
+        if (deviceEventService == null){
+            deviceEventService = SpringContext.getBean(DeviceEventServiceImpl.class);
+        }
+        if (messagingTemplate == null){
+            messagingTemplate = SpringContext.getBean(SimpMessagingTemplate.class);
+        }
+    }
+
+    private static final Map<String, String> jgDeviceStatusMap = new HashMap<>();
+
+    private static final String LOW_PRESSURE_CODE = "ERC40";
+
+    static {
+        jgDeviceStatusMap.put(LOW_PRESSURE_CODE, "电池电压");
+        jgDeviceStatusMap.put("ERC52", "水浸事件");
+        jgDeviceStatusMap.put("ERC51", "井盖掀翻");
+        jgDeviceStatusMap.put("ERC50", "井盖倾斜/抬起");
+    }
+
+    @Override
+    public void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
+        ByteBuf buf = packet.copy().content();
+        //通过ByteBuf的readableBytes方法可以获取缓冲区可读的字节数,
+        //根据可读的字节数创建byte数组
+        byte[] req = new byte[buf.readableBytes()];
+        buf.readBytes(req);
+        String receiveMsg = ByteUtil.bytesToHexString(req).toUpperCase();
+        log.warn("\nReceived UDP Msg :" + receiveMsg);
+
+        if (StringUtils.isNotEmpty(receiveMsg)){
+            String feedback = handleJG(receiveMsg);
+            // 由于数据报的数据是以字符数组传的形式存储的,所以传转数据
+            byte[] bytes = feedback.getBytes("UTF-8");
+            //在这里可以返回一个UDP消息给对方
+            ctx.write(new DatagramPacket(Unpooled.copiedBuffer(bytes), packet.sender()));
+        }else{
+            log.error("Received Error UDP Message:" + receiveMsg);
+        }
+    }
+
+    private String handleJG(String receiveMsg) {
+        StringBuffer feedback = new StringBuffer();
+        // 第1个字节起始字符(68H)
+        feedback.append("68");
+        StringBuffer lStr = new StringBuffer();
+        // 第7个字节控制字  主站下发报文固定为4B
+        lStr.append("4B");
+
+        log.warn("======接收到井盖传感器推送信息======");
+        String[] str = DeviceUtil.turnToArray(receiveMsg);
+        String afn  = str[12];
+        String fn = str[14]+str[15]+str[16]+str[17];
+        String frameNumber = str[13];
+        String deviceId = DeviceUtil.getJGDeviceID(str);
+        log.warn("设备号:"+deviceId);
+        // 第8-12个字节地址域,其中8-11是通信地址 将20160138按照(2.1主站回复报文的组织格式)中新终端地址格式转换,转为16 20 38 10 (每两字节高低位颠倒)再加上固定的04
+        lStr.append(DeviceUtil.getFeedBackJGDeviceID(str)).append("04");
+        // 第13个字节
+        lStr.append(afn);
+        // 第14个字节帧序号 按照终端上报报文的帧序号原样回复
+        lStr.append(frameNumber);
+        // 第15-18个字节
+        lStr.append(fn);
+
+        String body = receiveMsg.substring(36, receiveMsg.length()-4);
+        String[] bodyStr = DeviceUtil.turnToArray(body);
+        log.warn("数据体是:" + body);
+        if (StringUtils.isNotEmpty(body)){
+            log.warn("推送的是心跳、告警数据");
+            // 返回数据体
+            StringBuffer feedbackBody = new StringBuffer();
+            //上报失败重试次数(弃用)
+            feedbackBody.append("00");
+            //重发上报时间间隔(弃用)
+            feedbackBody.append("00");
+            //对时开关: 01-开 EE-关
+            feedbackBody.append("EE");
+            // 对时数据体
+            feedbackBody.append("32131031C318");
+            // 同步开关及数据(弃用)
+            feedbackBody.append("00000000000000000000000000000000000000");
+            // IP端口设置开关 01-开 EE-关
+            feedbackBody.append("EE");
+            // IP地址段1
+            feedbackBody.append("C0");
+            // IP地址段2
+            feedbackBody.append("A8");
+            // IP地址段3
+            feedbackBody.append("01");
+            // IP地址段4
+            feedbackBody.append("E1");
+            // IP地址段5
+            feedbackBody.append("2008");
+            // 通讯地址修改开关 01-开 EE-关
+            feedbackBody.append("EE");
+            // 新通讯地址
+            feedbackBody.append(DeviceUtil.getFeedBackJGDeviceID(str));
+            // 布防撤防状态: 55为布防  AA为撤防 其他终端不理会
+            feedbackBody.append("55");
+            // 预留(弃用)
+            feedbackBody.append("00000000");
+            // 上报时间设置开关 01-开 EE-关
+            feedbackBody.append("EE");
+            // 上报基准时间
+            feedbackBody.append("1008");
+            // 预留(弃用)
+            feedbackBody.append("00000000000000000000");
+            lStr.append(feedbackBody);
+
+            int count = (int) parseLong(bodyStr[0], 16);
+            log.warn("总共是:"+count + "个事件");
+
+            for (int i = 0, length = 26; i < count; i++){
+                String eventStr = body.substring(8 + i*length, (8 + i*length)+26);
+                log.warn("=======第"+(i+1)+"个事件:"+eventStr+"=======");
+                String[] eventStrArr = DeviceUtil.turnToArray(eventStr);
+                String type = "ERC" + parseLong(eventStrArr[0], 16);
+                if (jgDeviceStatusMap.get(type) != null){
+                    // 事件时间,作去重校验
+                    String dateStr = eventStrArr[6]+eventStrArr[5]+eventStrArr[4]+eventStrArr[3]+eventStrArr[2];
+                    DateTime dateTime = DateTime.parse(dateStr, DateTimeFormat.forPattern("yyMMddHHmm"));
+                    log.warn("=======事件:"+jgDeviceStatusMap.get(type)+";时间:"+ new DateTime().toString("yyyy-MM-dd HH:mm")+"=======\n");
+                    Device device = deviceService.findByDeviceId(deviceId);
+                    String content = jgDeviceStatusMap.get(type);
+                    boolean needEvent = false;
+                    if (device != null){
+                        if (LOW_PRESSURE_CODE.equals(type)){
+                            String warnPressure = eventStrArr[11];
+                            String currentPressure = eventStrArr[9];
+                            // 低压
+                            if (Integer.valueOf(currentPressure) <= Integer.valueOf(warnPressure)){
+                                device.setStatus((byte)2);
+                                needEvent = true;
+                            }
+                        }else {
+                            // 报警
+                            device.setStatus((byte)1);
+                            needEvent = true;
+                        }
+                        deviceService.update(device);
+
+                        if (needEvent){
+
+                            List<DeviceEvent> deviceEventList = deviceEventService.findByContentAndPostTime(content, dateTime.toDate());
+                            if (deviceEventList != null && deviceEventList.size() > 0){
+                                continue;
+                            }
+
+                            DeviceEvent event = new DeviceEvent();
+                            event.setDevice(device);
+                            event.setContent(content);
+                            event.setHandleStatus((byte)0);
+                            event.setCreateTime(new DateTime().toDate());
+                            event.setUpdateTime(new DateTime().toDate());
+                            event.setPostTime(dateTime.toDate());
+                            deviceEventService.save(event);
+                            log.warn(device.getDeviceId() + ":"+ event.getContent());
+
+                            JSONObject result = new JSONObject();
+                            result.put("id", device.getId());
+                            result.put("deviceType", device.getDeviceType());
+                            result.put("status", type);
+                            // 推送信息到前端
+                            messagingTemplate.convertAndSend("/topic/device", result.toJSONString());
+                        }
+                    }
+                }
+            }
+        }else{
+            log.warn("推送的是上报完毕报文");
+        }
+        // ===== 计算长度L start =====
+        StringBuffer countLength = new StringBuffer(ByteUtil.toBinary(lStr.toString().length()/2)).append("10");
+        StringBuffer zeroStr = new StringBuffer();
+        for (int i = 0; i < 16-countLength.length(); i++){
+            zeroStr.append("0");
+        }
+        zeroStr.append(countLength);
+        String ab = ByteUtil.binaryString2hexString(zeroStr.toString());
+        String[] abArr = DeviceUtil.turnToArray(ab);
+        // ===== 计算长度L end =====
+
+        // 第2-3个字节(长度L) 预留待替换
+        feedback.append(abArr[1]).append(abArr[0]);
+        // 第4-5个字节(长度L) 预留待替换
+        feedback.append(abArr[1]).append(abArr[0]);
+        // 第6个字节起始字符(68H)
+        feedback.append("68");
+        // 倒数第2个字节校验和CS  预留待替换
+        lStr.append(ByteUtil.makeChecksum(lStr.toString()));
+        // 最后一个字节结束字符(16H)
+        lStr.append("16");
+        feedback.append(lStr);
+        return feedback.toString().toUpperCase();
+    }
+
+    @Override
+    public void channelReadComplete(ChannelHandlerContext ctx) {
+        ctx.flush();
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+        cause.printStackTrace();
+        // We don't close the channel because we can keep serving requests.
+    }
+
+    public Timestamp getTime(){
+        Date date = new Date();
+        Timestamp time = new Timestamp(date.getTime());
+        return time;
+    }
+
+}

+ 41 - 0
wsm-admin-web/src/main/java/com/wsm/admin/init/StartupUdpEvent.java

@@ -0,0 +1,41 @@
+package com.wsm.admin.init;
+
+import com.wsm.admin.mqtt.ClientMQTT;
+import com.wsm.admin.tcp.init.CoverTcpServer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextRefreshedEvent;
+
+public class StartupUdpEvent implements ApplicationListener<ContextRefreshedEvent> {
+
+    private static final Logger log = LoggerFactory.getLogger(StartupUdpEvent.class);
+
+    private static ApplicationContext context;
+
+    @Override
+    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
+        try {
+            context = contextRefreshedEvent.getApplicationContext();
+
+
+//            CoverTcpServer tcpServer = (CoverTcpServer)StartupUdpEvent.getBean(CoverTcpServer.class);
+//            tcpServer.run(2000);
+//            log.warn("启动井盖TCP线程,接收TCP消息,端口:2000");
+//
+//
+//            ClientMQTT clientMQTT = new ClientMQTT();
+//            clientMQTT.start();
+//            log.warn("启动烟雾传感器MQTT");
+
+
+        } catch (Exception e) {
+            log.error("Exception", e);
+        }
+    }
+
+    public static Object getBean(Class beanName) {
+        return context != null ? context.getBean(beanName) : null;
+    }
+}

+ 86 - 0
wsm-admin-web/src/main/java/com/wsm/admin/init/TaskSchedule.java

@@ -0,0 +1,86 @@
+package com.wsm.admin.init;
+
+import java.util.Date;
+import java.util.List;
+
+import com.wsm.admin.constant.MsgCode;
+import com.wsm.admin.model.Device;
+import com.wsm.admin.model.DeviceEvent;
+import com.wsm.admin.service.IDeviceEventService;
+import com.wsm.admin.service.IDeviceService;
+import com.wsm.common.util.RedisUtil;
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+
+/**
+ * Created by owen on 2018/8/24.
+ *
+ * 定时任务,检测设备状态
+ */
+
+@Component
+public class TaskSchedule {
+
+    /** The logger. */
+    private Logger logger = Logger.getLogger(TaskSchedule.class);
+
+    @Autowired
+    private IDeviceService deviceService;
+
+    @Autowired
+    private RedisUtil redisUtil;
+
+    @Autowired
+    private IDeviceEventService deviceEventService;
+
+
+    /**
+     * 每天24点检查未开始的活动
+     * 每天24点执行一次  @Scheduled(cron=" 0 0 0 * * ? ") @Scheduled(cron=" * 1  * * ? ")
+     *
+     * Scheduled(cron=" 10 0/5 * * * ? ")   //每五分钟执行一次
+     */
+    @Scheduled(cron=" 10 0 0 * * ? ")
+//    @Scheduled(cron=" 10 0/5 * * * ? ")
+    public void checkDeviceId(){
+        logger.info("run checkDeviceId");
+
+        List<Device> list = deviceService.findAll();
+
+        for (Device d : list) {
+            boolean b = redisUtil.hasKey(d.getDeviceId());
+            // 如果不存在
+            if (!b) {
+                logger.info("离线设备号:" + d.getDeviceId());
+                DeviceEvent event = new DeviceEvent();
+                    event.setCreateTime(new Date());
+                    event.setDevice(d);
+                    event.setPostTime(new Date());
+
+                // 0:报警 待解决
+                event.setHandleStatus((byte)0);
+                event.setContent("设备离线");
+                event.setUpdateTime(new Date());
+                deviceEventService.save(event);
+
+                //修改设备状态
+                // 3:故障
+                d.setStatus((byte)3);
+                d.setUpdateTime(new Date());
+                deviceService.update(d);
+                redisUtil.delete(MsgCode.REDIS_CYCLE_DEVICE_LIST);
+
+
+            }
+
+        }
+        logger.info("end checkDeviceId");
+
+
+    }
+
+
+}

+ 251 - 0
wsm-admin-web/src/main/java/com/wsm/admin/init/TcpServer.java

@@ -0,0 +1,251 @@
+package com.wsm.admin.init;
+
+import com.alibaba.fastjson.JSONObject;
+import com.wsm.admin.model.Device;
+import com.wsm.admin.model.DeviceEvent;
+import com.wsm.admin.service.IDeviceService;
+import com.wsm.admin.service.IDeviceEventService;
+import com.wsm.common.util.ByteUtil;
+import com.wsm.common.util.DeviceUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.messaging.simp.SimpMessagingTemplate;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.charset.Charset;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 假如要启动,需要把@Component注释去掉
+ */
+//@Component
+public class TcpServer {
+    private static final Logger log = LoggerFactory.getLogger(TcpServer.class);
+
+    //解码buffer
+    private Charset cs = Charset.forName("UTF-8");
+    //发送数据缓冲区
+    private static ByteBuffer sBuffer = ByteBuffer.allocate(1024);
+    //接受数据缓冲区
+    private static ByteBuffer rBuffer = ByteBuffer.allocate(1024);
+    //选择器(叫监听器更准确些吧应该)
+    private static Selector selector;
+
+    @Autowired
+    private IDeviceEventService deviceEventService;
+    @Autowired
+    private IDeviceService deviceService;
+    @Autowired
+    private SimpMessagingTemplate messagingTemplate;
+
+    private static final String LOW_PRESSURE_CODE = "384";
+    private static final String SMOKE_CODE = "111";
+
+    private static final Map<String, String> deviceStatusMap = new HashMap<>();
+
+    static {
+        deviceStatusMap.put("08", "硬件版本号");
+        deviceStatusMap.put("15", "SIM 卡CCID 号码");
+        deviceStatusMap.put("05", "NB/GPRS 信号强度");
+        deviceStatusMap.put("2A00", "电池:低压");
+        deviceStatusMap.put("3500", "NB底座的电池:低压");
+        deviceStatusMap.put("3600", "烟感底座上的烟感电池:低压");
+        deviceStatusMap.put("3701", "消防门状态:打开");
+        deviceStatusMap.put("3801", "消防手报状态:弹起");
+        deviceStatusMap.put("3E01", "喷淋状态:打开");
+
+        deviceStatusMap.put(SMOKE_CODE, "烟雾报警");
+        deviceStatusMap.put(LOW_PRESSURE_CODE, "低压报警");
+        deviceStatusMap.put("993", "底座上的烟感低压");
+        deviceStatusMap.put("992", "NB 底座低压报警 ");
+        deviceStatusMap.put("991", "燃气报警");
+        deviceStatusMap.put("990", "消防手报按钮报警");
+        deviceStatusMap.put("989", "消防门打开");
+        deviceStatusMap.put("988", "消防门关闭");
+        deviceStatusMap.put("987", "消防门长时间未关闭");
+        deviceStatusMap.put("986", "高温报警");
+        deviceStatusMap.put("985", "漏电报警");
+        deviceStatusMap.put("984", "温感低压");
+        deviceStatusMap.put("966", "喷淋打开");
+        deviceStatusMap.put("965", "喷淋关闭");
+
+    }
+
+    /**
+     * 启动socket服务,开启监听
+     *
+     * @param port
+     * @throws IOException
+     */
+    @Async("updAsyncPool")
+    public void startSocketServer(int port) {
+        try {
+            //打开通信信道
+            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
+            //设置为非阻塞
+            serverSocketChannel.configureBlocking(false);
+            //获取套接字
+            ServerSocket serverSocket = serverSocketChannel.socket();
+            //绑定端口号
+            serverSocket.bind(new InetSocketAddress(port));
+            //打开监听器
+            selector = Selector.open();
+            //将通信信道注册到监听器
+            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
+
+            //监听器会一直监听,如果客户端有请求就会进入相应的事件处理
+            while (true) {
+                selector.select();//select方法会一直阻塞直到有相关事件发生或超时
+                Set<SelectionKey> selectionKeys = selector.selectedKeys();//监听到的事件
+                for (SelectionKey key : selectionKeys) {
+                    handle(key);
+                }
+                selectionKeys.clear();//清除处理过的事件
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 处理不同的事件
+     *
+     * @param selectionKey
+     * @throws IOException
+     */
+    private void handle(SelectionKey selectionKey) throws IOException {
+        ServerSocketChannel serverSocketChannel = null;
+        SocketChannel socketChannel = null;
+        String requestMsg = "";
+        String responseMsg = "";
+        int count = 0;
+        if (selectionKey.isAcceptable()) {
+            //每有客户端连接,即注册通信信道为可读
+            serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
+            socketChannel = serverSocketChannel.accept();
+            socketChannel.configureBlocking(false);
+            socketChannel.register(selector, SelectionKey.OP_READ);
+        } else if (selectionKey.isReadable()) {
+            socketChannel = (SocketChannel) selectionKey.channel();
+            rBuffer.clear();
+            count = socketChannel.read(rBuffer);
+            //读取数据
+            if (count > 0) {
+                rBuffer.flip();
+
+                byte[] bytes = new byte[rBuffer.remaining()];
+                rBuffer.get(bytes, 0, bytes.length);
+
+                requestMsg = ByteUtil.bytesToHexString(bytes).toUpperCase();
+                log.warn("Received TCP Msg :" + requestMsg);
+
+                try {
+                    responseMsg = handleYG(requestMsg);
+                }catch (Exception ex){
+                    log.error(ex.getMessage());
+                }
+            }
+            //返回数据
+            sBuffer = ByteBuffer.allocate(responseMsg.getBytes("UTF-8").length);
+            sBuffer.put(responseMsg.getBytes("UTF-8"));
+            sBuffer.flip();
+            socketChannel.write(sBuffer);
+            socketChannel.close();
+        }
+    }
+
+    private String handleYG(String receiveMsg) {
+        log.warn("======接收到烟感传感器推送信息======");
+        String[] str = DeviceUtil.turnToArray(receiveMsg);
+        String deviceID = DeviceUtil.getYGDeviceID(str);
+        log.warn("deviceID:"+deviceID);
+        Device device = deviceService.findByDeviceId16Hex(deviceID);
+        if (device != null){
+            log.warn("接收到:"+device.getDeviceId()+" 推送的信息");
+        }
+
+        String type = str[6];
+        switch (type){
+            // 心跳
+            case "02":
+                log.warn("======心跳信息,无异常状态======");
+                break;
+            // 状态
+            case "04":
+                log.warn("======心跳信息,推送状态信息======");
+                /*int total = Integer.valueOf(str[16]);
+                for (int i = 0, length = 3; i < total; i++){
+                    String a = str[17 + i * length];
+                    //String b = str[18 + i * length];
+                    String c = str[19 + i * length];
+                    // 状态异常
+                    if (!StringUtils.isEmpty(deviceStatusMap.get(a+c)) && device != null){
+
+
+
+                        DeviceStatus status =  new DeviceStatus();
+                        status.setContent(deviceStatusMap.get(a+c));
+                        status.setDevice(device);
+                        status.setStatus((byte)0);
+                        deviceStatusService.save(status);
+                        log.warn(device.getDeviceId() + ":"+ status.getContent());
+
+                        JSONObject result = new JSONObject();
+                        result.put("id", device.getDeviceId());
+                        result.put("deviceType", device.getDeviceType());
+                        result.put("status", a+c);
+
+                        messagingTemplate.convertAndSend("/topic/device", result.toJSONString());
+                    }
+                }*/
+                break;
+            // 报警
+            case "09":
+                // 报警
+                String hex = ByteUtil.hexStringToString(str[24]+str[25]+str[26]);
+                if (!StringUtils.isEmpty(deviceStatusMap.get(hex)) && device != null){
+
+                    if (LOW_PRESSURE_CODE.equals(hex)){
+                        device.setStatus((byte)2);
+                    }else if (SMOKE_CODE.equals(hex)){
+                        device.setStatus((byte)1);
+                    }
+                    deviceService.update(device);
+
+                    DeviceEvent event =  new DeviceEvent();
+                    event.setContent(deviceStatusMap.get(hex));
+                    event.setDevice(device);
+                    event.setHandleStatus((byte)0);
+                    event.setPostTime(new Date());
+                    deviceEventService.save(event);
+                    log.warn(device.getDeviceId() + ":"+ event.getContent());
+
+                    JSONObject result = new JSONObject();
+                    result.put("id", device.getId());
+                    result.put("deviceType", device.getDeviceType());
+                    result.put("status", hex);
+
+                    // 推送报警事件给前端
+                    messagingTemplate.convertAndSend("/topic/device", result.toJSONString());
+                }
+                break;
+        }
+
+        return DeviceUtil.getOKFeedback(str);
+    }
+
+}

+ 46 - 0
wsm-admin-web/src/main/java/com/wsm/admin/init/UdpServer.java

@@ -0,0 +1,46 @@
+package com.wsm.admin.init;
+
+import com.wsm.admin.handle.UdpServerHandler;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioDatagramChannel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+/**
+ * server服务器
+ *
+ * 假如要启动,需要把@Component注释去掉
+ */
+
+//@Component
+public class UdpServer {
+
+    private static final Logger log= LoggerFactory.getLogger(UdpServer.class);
+
+    @Async("updAsyncPool")
+    public void run(int udpReceivePort) {
+
+        EventLoopGroup group = new NioEventLoopGroup();
+        log.info("Server start!  Udp Receive msg Port:" + udpReceivePort );
+
+        try {
+            Bootstrap b = new Bootstrap();
+            b.group(group)
+                    .channel(NioDatagramChannel.class)
+                    .option(ChannelOption.SO_BROADCAST, true)
+                    .handler(new UdpServerHandler());
+
+            b.bind(udpReceivePort).sync().channel().closeFuture().await();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        } finally {
+            group.shutdownGracefully();
+        }
+    }
+
+}

+ 85 - 0
wsm-admin-web/src/main/java/com/wsm/admin/mqtt/ClientMQTT.java

@@ -0,0 +1,85 @@
+package com.wsm.admin.mqtt;
+
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttTopic;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+public class ClientMQTT {
+
+//topic, demo只订阅了火警的topic,其他的添加topic到数组中即可
+//      火警      - /chiefdata/push/fire_alarm/department/34/area/1/dev/3jyun-866971030771930
+//      设备故障      - /chiefdata/push/fault_alarm/department/34/area/1/dev/3jyun-866971030771930
+//      上下线     - /chiefdata/push/device_online_status/department/34/area/1/dev/3jyun-866971030771930
+//      设备属性上报      - /chiefdata/push/dev_msg/department/34/area/1/dev/3jyun-866971030771930
+//      服务器账号密码等私密信息请勿外泄    
+
+
+
+
+
+
+
+    /**
+     * 服务器地址
+     */
+    public static final String HOST = "tcp://swan.3jyun.com:8008";
+
+    /**
+     * 客户端id
+     */
+    private static final String clientId = "MQTT_FX_Client";
+
+    private String userName = "httpAgent";
+    private String passWord = "c3772e1bee68544284e47e8806a2a8ca";
+
+    private MqttClient client;
+    private MqttConnectOptions options;
+
+
+    public void start() {
+        try {
+            // host为主机名,clientid即连接MQTT的客户端ID,一般以唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
+            client = new MqttClient(HOST, clientId, new MemoryPersistence());
+            // MQTT的连接设置
+            options = new MqttConnectOptions();
+            // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,设置为true表示每次连接到服务器都以新的身份连接
+            options.setCleanSession(false);
+            // 设置连接的用户名
+            options.setUserName(userName);
+            // 设置连接的密码
+            options.setPassword(passWord.toCharArray());
+            // 设置超时时间 单位为秒
+            options.setConnectionTimeout(5);
+            // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
+            options.setKeepAliveInterval(20);
+            // 设置回调
+            client.setCallback(new PushCallback());
+            MqttTopic topic = client.getTopic(TopicCode.TOPIC_FIRE_ALARM);
+            //setWill方法,如果项目中需要知道客户端是否掉线可以调用该方法。设置最终端口的通知消息
+//遗嘱        options.setWill(topic, "close".getBytes(), 2, true);
+            client.connect(options);
+            /**
+             * 订阅消息
+             * 0代表“至多一次”
+             * 1代表“至少一次”
+             * 2代表“只有一次”
+             */
+            int[] qos  = {1,1,1,1};
+            // 订阅topic ,最少一个,允许多个,加入数组中就可以了
+            String[] subscribeTopic = {TopicCode.TOPIC_FIRE_ALARM, TopicCode.TOPIC_FAULT_ALARM, TopicCode.TOPIC_DEVICE_ONLINE_STATUS, TopicCode.TOPIC_DEV_MSG};
+//            String[] topic1 = {TOPIC1};
+            client.subscribe(subscribeTopic, qos);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+//    public static void main(String[] args) throws MqttException {
+//        ClientMQTT client = new ClientMQTT();
+//        client.start();
+//    }
+
+}

+ 149 - 0
wsm-admin-web/src/main/java/com/wsm/admin/mqtt/PushCallback.java

@@ -0,0 +1,149 @@
+package com.wsm.admin.mqtt;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.wsm.admin.constant.MsgCode;
+import com.wsm.admin.model.Device;
+import com.wsm.admin.model.DeviceEvent;
+import com.wsm.admin.service.IDeviceEventService;
+import com.wsm.admin.service.IDeviceService;
+import com.wsm.admin.service.impl.DeviceEventServiceImpl;
+import com.wsm.admin.service.impl.DeviceServiceImpl;
+import com.wsm.common.util.DateTimeUtils;
+import com.wsm.common.util.RedisUtil;
+import com.wsm.common.util.SpringContext;
+import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
+import org.eclipse.paho.client.mqttv3.MqttCallback;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.messaging.simp.SimpMessagingTemplate;
+
+import java.util.Date;
+
+
+public class PushCallback implements MqttCallback {
+
+    private static final Logger log = LoggerFactory.getLogger(PushCallback.class);
+
+    private IDeviceService deviceService;
+
+    private IDeviceEventService deviceEventService;
+
+    private SimpMessagingTemplate messagingTemplate;
+
+    private RedisUtil redisUtil;
+
+
+    /**
+     * 火灾报警
+     * alarm_type : 1
+     */
+    private static String TYPE_FIRE = "1";
+
+
+    /**
+     * 故障
+     * alarm_type : 2
+     */
+    private static String TYPE_FAULT = "2";
+
+    public PushCallback(){
+        if (deviceService == null){
+            deviceService = SpringContext.getBean(DeviceServiceImpl.class);
+        }
+        if (deviceEventService == null){
+            deviceEventService = SpringContext.getBean(DeviceEventServiceImpl.class);
+        }
+        if (messagingTemplate == null){
+            messagingTemplate = SpringContext.getBean(SimpMessagingTemplate.class);
+        }
+
+        if (redisUtil == null){
+            redisUtil = SpringContext.getBean(RedisUtil.class);
+        }
+    }
+
+    @Override
+    public void connectionLost(Throwable cause) {
+        // 连接丢失后,一般在这里面进行重连
+        log.info("连接断开,需要从连重连");
+        ClientMQTT clientMqtt = new ClientMQTT();
+        clientMqtt.start();
+        log.info("重新启动MQTT成功");
+    }
+    @Override
+    public void deliveryComplete(IMqttDeliveryToken token) {
+        log.warn("deliveryComplete: {}", token.isComplete());
+    }
+    @Override
+    public void messageArrived(String topic, MqttMessage message) throws Exception {
+        // subscribe后得到的消息会执行到这里面
+        log.warn("接收消息主题 : {}", topic);
+        log.warn("接收消息Qos : {}", message.getQos());
+
+        corventJson(new String(message.getPayload()), topic);
+    }
+
+
+    /**
+     * 解析接收到的内容
+     */
+    private void corventJson(String str, String topic){
+//        String str = "{\"devid\":\"3jyun-866971030771930\",\"pid\":\"H388N\",\"pname\":\"广东潮庭集团-珠海移动白蕉项目1\",\"cid\":34,\"aid\":1,\"a_name\":\"\",\"bid\":2,\"b_name\":\"\",\"lid\":5,\"l_name\":\"北京天安门\",\"time\":\"2019-12-05 14:19:54\",\"alarm_type\":1,\"alarm_type_name\":\"烟感传感器火警\",\"event_id\":32,\"event_count\":1,\"device_type\":1,\"comm_type\":2,\"first_alarm_time\":\"2019-12-05 14:19:54\",\"last_alarm_time\":\"2019-12-05 14:19:54\"}";
+        JSONObject orgin = JSON.parseObject(str);
+        log.info("orgin data: {}", orgin);
+
+        // 火灾报警、设备故障
+        String devid = orgin.getString("devid");
+        String time = orgin.getString("time");
+        Date postTime = DateTimeUtils.parse(time);
+        log.warn("上报时间: {}", time);
+
+        // 用来心跳检测
+        redisUtil.set(devid,"heartbeat", Long.parseLong("25"));
+
+        // 火警报警
+        String alarmTypeName = orgin.getString("alarm_type_name");
+        String alarmType = orgin.getString("alarm_type");
+        log.info("devid : {}", devid);
+        log.info("time : {}", time);
+        log.info("alarmType : {}", alarmType);
+        log.info("alarmTypeName : {}", alarmTypeName);
+
+        Device device = deviceService.findByDeviceId(devid);
+        if (device != null && alarmType.equals(TYPE_FIRE)) {
+            // 报警
+            device.setStatus((byte)1);
+            device.setUpdateTime(new Date());
+            deviceService.update(device);
+            redisUtil.delete(MsgCode.REDIS_CYCLE_DEVICE_LIST);
+
+            // 记录报警详情
+            DeviceEvent event = new DeviceEvent();
+//            DeviceEvent event = deviceEventService.findByDeviceIdTop(device.getId());
+//            if (event == null) {
+                event = new DeviceEvent();
+                event.setDevice(device);
+                event.setCreateTime(new Date());
+//            }
+            event.setHandleStatus((byte)0);
+            event.setContent(alarmTypeName);
+            event.setUpdateTime(new Date());
+            event.setPostTime(postTime);
+            deviceEventService.save(event);
+            log.warn(device + ": " + alarmTypeName);
+
+
+            JSONObject result = new JSONObject();
+            result.put("id", device.getDeviceId());
+            result.put("deviceType", device.getDeviceType());
+            result.put("status", alarmTypeName);
+
+            //推送信息到前端
+            messagingTemplate.convertAndSend("/topic/device", result.toJSONString());
+
+        }
+    }
+
+}

+ 36 - 0
wsm-admin-web/src/main/java/com/wsm/admin/mqtt/TopicCode.java

@@ -0,0 +1,36 @@
+package com.wsm.admin.mqtt;
+
+/**
+ * Created by Owen on 2019/12/12 0012 15:14
+ *
+ * 话题类型
+ //      火警      - /chiefdata/push/fire_alarm/department/34/area/1/dev/3jyun-866971030771930
+ //      设备故障      - /chiefdata/push/fault_alarm/department/34/area/1/dev/3jyun-866971030771930
+ //      上下线     - /chiefdata/push/device_online_status/department/34/area/1/dev/3jyun-866971030771930
+ //      设备属性上报      - /chiefdata/push/dev_msg/department/34/area/1/dev/3jyun-866971030771930
+ */
+public class TopicCode {
+
+
+
+
+    /**
+     * 火灾事件消息
+     */
+    public static final String TOPIC_FIRE_ALARM = "/chiefdata/push/fire_alarm/department/34/area/1/dev/3jyun-866971030771930";
+
+    /**
+     * 设备故障
+     */
+    public static final String TOPIC_FAULT_ALARM = "/chiefdata/push/fault_alarm/department/34/area/1/dev/3jyun-866971030771930";
+
+    /**
+     * 上下线
+     */
+    public static final String TOPIC_DEVICE_ONLINE_STATUS = "/chiefdata/push/device_online_status/department/34/area/1/dev/3jyun-866971030771930";
+
+    /**
+     * 设备属性上报
+     */
+    public static final String TOPIC_DEV_MSG = "/chiefdata/push/dev_msg/department/34/area/1/dev/3jyun-866971030771930";
+}

+ 89 - 0
wsm-admin-web/src/main/java/com/wsm/admin/shiro/MyShiroRealm.java

@@ -0,0 +1,89 @@
+package com.wsm.admin.shiro;
+
+import com.wsm.admin.model.Resource;
+import com.wsm.admin.model.Role;
+import com.wsm.admin.model.User;
+import com.wsm.admin.service.IUserService;
+import com.wsm.common.util.PasswordUtils;
+import org.apache.shiro.authc.*;
+import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author ajay peng
+ */
+@Component
+public class MyShiroRealm extends AuthorizingRealm {
+
+    @Autowired
+    private IUserService userService;
+
+    public MyShiroRealm() {
+        super(new AllowAllCredentialsMatcher());
+        setAuthenticationTokenClass(UsernamePasswordToken.class);
+        //FIXME: 暂时禁用Cache
+        setCachingEnabled(false);
+    }
+
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(
+            PrincipalCollection principals) {
+        User user = (User) principals.getPrimaryPrincipal();
+        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
+        try {
+            User dbUser = userService.findByUserName(user.getUserName());
+            Set<String> shiroPermissions = new HashSet<>();
+            Set<String> roleSet = new HashSet<String>();
+            Set<Role> roles = dbUser.getRoles();
+            for (Role role : roles) {
+                Set<Resource> resources = role.getResources();
+                for (Resource resource : resources) {
+                    shiroPermissions.add(resource.getResourceKey());
+                }
+                roleSet.add(role.getRoleKey());
+            }
+            authorizationInfo.setRoles(roleSet);
+            authorizationInfo.setStringPermissions(shiroPermissions);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return authorizationInfo;
+    }
+
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
+        String username = (String) token.getPrincipal();
+
+
+        User user = userService.findByUserName(username);
+        // 账号不存在
+        if (user == null) {
+            throw new UnknownAccountException("账号或密码不正确");
+        }
+        Object credentials = token.getCredentials();
+        if (credentials == null) {
+            throw new UnknownAccountException("账号或密码不正确");
+        }
+        String password = new String((char[]) credentials);
+        String passwordCode = PasswordUtils.encrypt(password, user.getUserName(), PasswordUtils.getStaticSalt());
+        // 密码错误
+        if (!passwordCode.equals(user.getPassword())) {
+            throw new IncorrectCredentialsException("账号或密码不正确");
+        }
+        // 账号锁定
+        if (user.getStatus() == 1) {
+            throw new LockedAccountException("账号已被禁用,请联系管理员");
+        }
+        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
+        return info;
+    }
+
+}

+ 139 - 0
wsm-admin-web/src/main/java/com/wsm/admin/shiro/ShiroConfig.java

@@ -0,0 +1,139 @@
+package com.wsm.admin.shiro;
+
+import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
+import com.wsm.admin.service.IResourceService;
+import com.wsm.common.shiro.ShiroManager;
+import org.apache.shiro.cache.CacheManager;
+import org.apache.shiro.cache.MemoryConstrainedCacheManager;
+import org.apache.shiro.codec.Base64;
+import org.apache.shiro.mgt.DefaultSecurityManager;
+import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
+import org.apache.shiro.web.mgt.CookieRememberMeManager;
+import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+import org.apache.shiro.web.servlet.SimpleCookie;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.DependsOn;
+import org.springframework.context.annotation.Import;
+
+import javax.annotation.Resource;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+@Configuration
+@Import(ShiroManager.class)
+public class ShiroConfig {
+
+    @Resource
+    private IResourceService resourceService;
+
+    @Bean(name = "myShiroRealm")
+    @DependsOn("lifecycleBeanPostProcessor")
+    public MyShiroRealm myShiroRealm() {
+        return new MyShiroRealm();
+    }
+
+    @Bean
+    public ShiroDialect shiroDialect() {
+        return new ShiroDialect();
+    }
+
+    /**
+     * 用户授权信息Cache
+     */
+    @Bean(name = "shiroCacheManager")
+    @ConditionalOnMissingBean
+    public CacheManager cacheManager() {
+        return new MemoryConstrainedCacheManager();
+    }
+
+    @Bean
+    public SimpleCookie rememberMeCookie() {
+        //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
+        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
+        //如果httyOnly设置为true,则客户端不会暴露给客户端脚本代码,使用HttpOnly cookie有助于减少某些类型的跨站点脚本攻击;
+        simpleCookie.setHttpOnly(true);
+        //记住我cookie生效时间,默认30天 ,单位秒:60 * 60 * 24 * 30
+        simpleCookie.setMaxAge(259200);
+        return simpleCookie;
+    }
+
+    @Bean
+    public CookieRememberMeManager rememberMeManager() {
+        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
+        //rememberme cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位),通过以下代码可以获取
+        //KeyGenerator keygen = KeyGenerator.getInstance("AES");
+        //SecretKey deskey = keygen.generateKey();
+        //System.out.println(Base64.encodeToString(deskey.getEncoded()));
+        byte[] cipherKey = Base64.decode("wGiHplamyXlVB11UXWol8g==");
+        cookieRememberMeManager.setCipherKey(cipherKey);
+        cookieRememberMeManager.setCookie(rememberMeCookie());
+        return cookieRememberMeManager;
+    }
+
+
+    @Bean(name = "securityManager")
+    @ConditionalOnMissingBean
+    public DefaultSecurityManager securityManager() {
+        DefaultSecurityManager sm = new DefaultWebSecurityManager();
+        sm.setRealm(myShiroRealm());
+        sm.setCacheManager(cacheManager());
+        //注入记住我管理器
+        sm.setRememberMeManager(rememberMeManager());
+        return sm;
+    }
+
+    @Bean(name = "shiroFilter")
+    public ShiroFilterFactoryBean getShiroFilterFactoryBean() throws Exception {
+
+        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
+        shiroFilter.setSecurityManager(securityManager());
+
+
+        shiroFilter.setLoginUrl("/admin/login");
+        //登录成功后要跳转的链接
+        shiroFilter.setSuccessUrl("/admin/index");
+        //未授权界面
+        shiroFilter.setUnauthorizedUrl("/previlige/no");
+
+        //拦截器.
+        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
+        //配置不会被拦截的链接 顺序判断
+        //静态资源不拦截
+        filterChainDefinitionMap.put("/", "anon");
+        filterChainDefinitionMap.put("/webSocketServer/**", "anon");
+        filterChainDefinitionMap.put("/live/**", "anon");
+        filterChainDefinitionMap.put("/static/**", "anon");
+        filterChainDefinitionMap.put("/index.html", "anon");
+        filterChainDefinitionMap.put("/css/**", "anon");
+        filterChainDefinitionMap.put("/img/**", "anon");
+        filterChainDefinitionMap.put("/js/**", "anon");
+        filterChainDefinitionMap.put("/plugins/**", "anon");
+        filterChainDefinitionMap.put("/audio/**", "anon");
+        //登录链接不拦截
+        filterChainDefinitionMap.put("/admin/login", "anon");
+        filterChainDefinitionMap.put("/admin", "anon");
+        filterChainDefinitionMap.put("/kaptcha", "anon");
+        filterChainDefinitionMap.put("/api/**", "anon");
+
+        filterChainDefinitionMap.put("/test", "anon");
+
+        filterChainDefinitionMap.put("/**", "authc");
+
+
+
+
+
+        /*Map<String, Filter> filters = shiroFilter.getFilters();
+        filters.put("authc", new CustomFormAuthenticationFilter());*/
+
+        List<com.wsm.admin.model.Resource> list = resourceService.findAll();
+        for (com.wsm.admin.model.Resource resource : list) {
+            filterChainDefinitionMap.put(resource.getUrl(), "perms[" + resource.getResourceKey() + "]");
+        }
+        shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMap);
+        return shiroFilter;
+    }
+}

+ 60 - 0
wsm-admin-web/src/main/java/com/wsm/admin/tcp/NettyServer.java

@@ -0,0 +1,60 @@
+package com.wsm.admin.tcp;
+
+import com.wsm.admin.tcp.init.NettyServerHandler;
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+
+public class NettyServer {
+	private static final int port = 2000;
+
+	public void run() throws Exception {
+		// NioEventLoopGroup是用来处理IO操作的多线程事件循环器
+		// 用来接收进来的连接
+		EventLoopGroup bossGroup = new NioEventLoopGroup();
+		// 用来处理已经被接收的连接
+		EventLoopGroup workerGroup = new NioEventLoopGroup();
+		try {
+			// 是一个启动NIO服务的辅助启动类
+			ServerBootstrap server = new ServerBootstrap();
+			// 这里告诉Channel如何接收新的连接
+			server.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
+					.childHandler(new ChannelInitializer<SocketChannel>() {
+						@Override
+						protected void initChannel(SocketChannel ch) throws Exception {
+							// 自定义处理类
+							ch.pipeline().addLast(new NettyServerHandler());
+						}
+					});
+			// 初始化服务端可连接队列,指定了队列的大小128
+			server.option(ChannelOption.SO_BACKLOG, 128);
+			// 用来接收进来的连接
+			server.childOption(ChannelOption.SO_KEEPALIVE, true);
+			// 绑定端口,开始接收进来的连接
+			ChannelFuture f = server.bind(port).sync();
+			System.out.println("服务端启动成功...");
+			// 监听服务器关闭监听
+			f.channel().closeFuture().sync();
+		} finally {
+			// 关闭EventLoopGroup,释放掉所有资源包括创建的线程
+			bossGroup.shutdownGracefully();
+			workerGroup.shutdownGracefully();
+		}
+		// 服务器绑定端口监听
+	}
+
+
+
+
+//	public static void main(String[] args) throws Exception {
+//		new NettyServer().run();
+//	}
+
+
+
+}

+ 83 - 0
wsm-admin-web/src/main/java/com/wsm/admin/tcp/init/ConvertData.java

@@ -0,0 +1,83 @@
+package com.wsm.admin.tcp.init;
+
+import com.alibaba.fastjson.JSON;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+public class ConvertData {
+
+	private List<Rule> ruleList = new ArrayList<>();
+
+	public ConvertData() {
+		ruleList.add(new Rule("sn1", "string", 22, 26));
+		ruleList.add(new Rule("sn2", null, 26, 46));
+		ruleList.add(new Rule("yyyy", "int", 46, 48));
+		ruleList.add(new Rule("MM", "int", 48, 50));
+		ruleList.add(new Rule("dd", "int", 50, 52));
+		ruleList.add(new Rule("HH", "int", 52, 54));
+		ruleList.add(new Rule("mm", "int", 54, 56));
+		ruleList.add(new Rule("ss", "int", 56, 58));
+		ruleList.add(new Rule("x", "int", 58, 62));
+		ruleList.add(new Rule("y", "int", 62, 66));
+		ruleList.add(new Rule("z", "int", 66, 70));
+		ruleList.add(new Rule("CSQ", "int", 74, 78));
+		ruleList.add(new Rule("RSRQ", "int", 78, 82));
+		ruleList.add(new Rule("SNR", "int", 82, 86));
+		ruleList.add(new Rule("RSRP", "int", 86, 90));
+		ruleList.add(new Rule("经度方向", "string", 90, 92));
+		ruleList.add(new Rule("经度", "string", 92, 112));
+		ruleList.add(new Rule("纬度方向", "string", 112, 114));
+		ruleList.add(new Rule("纬度", "string", 114, 134));
+		ruleList.add(new Rule("status", null, 134, 142));
+	}
+
+	public Map<String, Object> convert(String date) {
+		//此例子没做对数据的校验
+		Map<String, Object> reHm = new TreeMap<>();
+		for (Rule rule : ruleList) {
+			if (rule.getStart() < date.length() && rule.getEnd() < date.length()) {
+				String inString = date.substring(rule.getStart(), rule.getEnd());
+				if ("int".equals(rule.getType())) {
+					reHm.put(rule.getName(), hexStr2Int(inString));
+				} else if ("string".equals(rule.getType())) {
+					reHm.put(rule.getName(), hexStr2String(inString));
+				} else {
+					reHm.put(rule.getName(), inString);
+				}
+			}
+		}
+		return reHm;
+	}
+
+	private int hexStr2Int(String hexString) {
+		int ret = Integer.parseInt(hexString, 16);
+		ret = ((ret & 0x8000) > 0) ? (ret - 0x10000) : (ret);
+		return ret;
+	}
+
+	private String hexStr2String(String hexStr) {
+		String str = "0123456789ABCDEF";
+		char[] hexs = hexStr.toCharArray();
+		byte[] bytes = new byte[hexStr.length() / 2];
+		int n;
+		for (int i = 0; i < bytes.length; i++) {
+			n = str.indexOf(hexs[2 * i]) * 16;
+			n += str.indexOf(hexs[2 * i + 1]);
+			bytes[i] = (byte) (n & 0xff);
+		}
+		return new String(bytes);
+	}
+
+	public static void main(String[] args) {
+		String d = "010001004A0000A3010044514300010003020100000001130C020B0B1EFFF3000000F100000000000000000000453131332E3536393639354E3032322E3337363735390000000000000000000000004140";
+		System.out.println(d.length());
+		ConvertData cd = new ConvertData();
+		Map<String, Object> hm = cd.convert(d);
+		System.out.println(JSON.toJSONString(hm));
+	}
+
+}
+

+ 62 - 0
wsm-admin-web/src/main/java/com/wsm/admin/tcp/init/CoverTcpServer.java

@@ -0,0 +1,62 @@
+package com.wsm.admin.tcp.init;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+/**
+ * Created by Owen on 2019/12/3 0003 14:46
+ *
+ * 井盖tcp服务
+ */
+
+@Component
+public class CoverTcpServer {
+
+    private static final Logger log = LoggerFactory.getLogger(CoverTcpServer.class);
+
+    @Async("updAsyncPool")
+    public void run(int port) throws Exception {
+        log.info("run startTcpServer");
+        // NioEventLoopGroup是用来处理IO操作的多线程事件循环器
+        // 用来接收进来的连接
+        EventLoopGroup bossGroup = new NioEventLoopGroup();
+        // 用来处理已经被接收的连接
+        EventLoopGroup workerGroup = new NioEventLoopGroup();
+        try {
+            // 是一个启动NIO服务的辅助启动类
+            ServerBootstrap server = new ServerBootstrap();
+            // 这里告诉Channel如何接收新的连接
+            server.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
+                    .childHandler(new ChannelInitializer<SocketChannel>() {
+                        @Override
+                        protected void initChannel(SocketChannel ch) throws Exception {
+                            // 自定义处理类
+                            ch.pipeline().addLast(new NettyServerHandler());
+                        }
+                    });
+            // 初始化服务端可连接队列,指定了队列的大小128
+            server.option(ChannelOption.SO_BACKLOG, 128);
+            // 用来接收进来的连接
+            server.childOption(ChannelOption.SO_KEEPALIVE, true);
+            // 绑定端口,开始接收进来的连接
+            ChannelFuture f = server.bind(port).sync();
+            log.info("tcp:2000 端口,服务端启动成功...");
+            // 监听服务器关闭监听
+            f.channel().closeFuture().sync();
+        } finally {
+            // 关闭EventLoopGroup,释放掉所有资源包括创建的线程
+            bossGroup.shutdownGracefully();
+            workerGroup.shutdownGracefully();
+        }
+    }
+}

+ 285 - 0
wsm-admin-web/src/main/java/com/wsm/admin/tcp/init/NettyServerHandler.java

@@ -0,0 +1,285 @@
+package com.wsm.admin.tcp.init;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.wsm.admin.constant.MsgCode;
+import com.wsm.admin.model.Device;
+import com.wsm.admin.model.DeviceEvent;
+import com.wsm.admin.service.IDeviceEventService;
+import com.wsm.admin.service.IDeviceService;
+import com.wsm.admin.service.impl.DeviceEventServiceImpl;
+import com.wsm.admin.service.impl.DeviceServiceImpl;
+import com.wsm.common.util.DateTimeUtils;
+import com.wsm.common.util.RedisUtil;
+import com.wsm.common.util.SpringContext;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.util.ReferenceCountUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.messaging.simp.SimpMessagingTemplate;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+public class NettyServerHandler extends ChannelInboundHandlerAdapter {
+	private static final Logger log= LoggerFactory.getLogger(NettyServerHandler.class);
+
+
+	private IDeviceService deviceService;
+
+	private IDeviceEventService deviceEventService;
+
+	private SimpMessagingTemplate messagingTemplate;
+
+	private RedisUtil redisUtil;
+
+
+//	@Autowired
+//	private RedisTemplate<String, Object> redisTemplate;
+
+
+
+	private static final Map<String, String> deviceStatusMap = new HashMap<>();
+
+
+	private static final String JG_NORMAL = "00000000";
+
+	private static final String JG_LOW_PRESSURE_CODE = "0xFF002F00";
+
+	private static final String JG_LOW_PRESSURE_OFF = "0xFF002F01";
+
+	/**
+	 * 心跳响应
+	 */
+	private static final String JG_HEARTBEAT = "GET / HTTP/1.0";
+
+	/**
+	 * 井盖正常数据长度
+	 */
+	private static final Integer CHECK_DATA_LENGTH = 162;
+
+	private static final double JG_ERC40 = 10;
+
+	private static final double JG_ERC90 = 70;
+
+
+
+
+	static {
+		deviceStatusMap.put(JG_NORMAL, "井盖正常");
+		deviceStatusMap.put(JG_LOW_PRESSURE_CODE, "井盖低电告警 ");
+		deviceStatusMap.put(JG_LOW_PRESSURE_OFF, "井盖低电关机");
+		deviceStatusMap.put("ERC40", "井盖倾斜/抬起");
+		deviceStatusMap.put("ERC90", "井盖掀翻");
+	}
+
+
+	public NettyServerHandler(){
+		if (deviceService == null){
+			deviceService = SpringContext.getBean(DeviceServiceImpl.class);
+		}
+		if (deviceEventService == null){
+			deviceEventService = SpringContext.getBean(DeviceEventServiceImpl.class);
+		}
+		if (messagingTemplate == null){
+			messagingTemplate = SpringContext.getBean(SimpMessagingTemplate.class);
+		}
+		if (redisUtil == null){
+			redisUtil = SpringContext.getBean(RedisUtil.class);
+		}
+	}
+
+
+	/**
+     * 收到数据时调用
+	 * @param ctx
+     * @param msg
+     * @throws Exception
+	 */
+	@Override
+	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+
+		log.info("Time: {}", new SimpleDateFormat("yyyy.MM.dd HH:mm:ss.SSS").format(new Date()));
+		log.info("客户端地址: {}", ctx.channel().remoteAddress());
+		log.info("ID: {}", ctx.channel().id());
+		try {
+			ByteBuf in = (ByteBuf) msg;
+			int readableBytes = in.readableBytes();
+			byte[] bytes = new byte[readableBytes];
+			in.readBytes(bytes);
+			String inString = new String(bytes);
+			log.info("接收data: {}", inString);
+
+
+
+			if (StringUtils.isNotEmpty(inString) && inString.length() == CHECK_DATA_LENGTH){
+
+				// 这应该是心跳,直接结束
+//				if (inString.contains(JG_HEARTBEAT)) {
+//					return;
+//				}
+
+				ConvertData cd = new ConvertData();
+				Map<String, Object> hm = cd.convert(inString);
+
+
+				log.info("解析json: {}", JSON.toJSONString(hm));
+				String status = hm.get("status").toString();
+
+				// 计算井盖角度
+				String ox = hm.get("x").toString();
+				String oy = hm.get("y").toString();
+				double angle = angle(Double.parseDouble(ox), Double.parseDouble(oy));
+				log.info("井盖开启角度: {} 度", Math.round(angle));
+
+				// 设备id
+				String sn2 = hm.get("sn2").toString();
+				Device device = deviceService.findByDeviceId(sn2);
+				log.warn("JG设备号: {}", sn2);
+
+				// 用来心跳检测
+				redisUtil.set(sn2,"heartbeat",Long.parseLong("25"));
+
+				// 上报时间
+				String year = hm.get("yyyy").toString();
+				String month = hm.get("MM").toString();
+				String day = hm.get("dd").toString();
+				String hh = hm.get("HH").toString();
+				String mm = hm.get("mm").toString();
+				String ss = hm.get("ss").toString();
+				String time = "20"+year+"-"+month+"-"+day+" "+hh+":"+mm+":"+ss;
+				Date postTime = DateTimeUtils.parse(time);
+				log.warn("上报时间: {}", time);
+
+
+				//报警开关
+				boolean needEvent = false;
+				String content = "";
+
+				if (device != null) {
+					// 低电压
+					if (JG_LOW_PRESSURE_CODE.equals(status)) {
+						device.setStatus((byte)2);
+
+						// 故障
+					} else if (JG_LOW_PRESSURE_OFF.equals(status)) {
+						device.setStatus((byte)3);
+
+						// 报警
+					} else if (JG_NORMAL.equals(status)) {
+						device.setStatus((byte)1);
+						needEvent = true;
+
+						//处理报警类型
+						// 大于40度
+
+						if (angle > JG_ERC40) {
+							// 报警
+							content = deviceStatusMap.get("ERC40");
+
+						}
+						if (angle > JG_ERC90) {
+							content = deviceStatusMap.get("ERC90");
+						}
+					}
+					device.setUpdateTime(new Date());
+					deviceService.update(device);
+
+					redisUtil.delete(MsgCode.REDIS_CYCLE_DEVICE_LIST);
+
+
+
+
+					// 记录报警详情
+					if (needEvent) {
+						DeviceEvent event  = new DeviceEvent();
+//						DeviceEvent event = deviceEventService.findByDeviceIdTop(device.getId());
+//						if (event == null) {
+							event = new DeviceEvent();
+							event.setDevice(device);
+							event.setCreateTime(new Date());
+//						}
+						event.setHandleStatus((byte)0);
+						event.setContent(content);
+						event.setUpdateTime(new Date());
+						event.setPostTime(postTime);
+						deviceEventService.save(event);
+						log.warn(device.getDeviceId() + ": " + content);
+
+
+						JSONObject result = new JSONObject();
+						result.put("id", device.getDeviceId());
+						result.put("deviceType", device.getDeviceType());
+						result.put("status", status);
+
+						//推送信息到前端
+						messagingTemplate.convertAndSend("/topic/device", result.toJSONString());
+
+					}
+				}
+			}
+
+
+		} finally {
+			// 抛弃收到的数据
+			ReferenceCountUtil.release(msg);
+			log.warn("<<<<<<<<<end");
+		}
+	}
+
+	@Override
+	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+		// 当出现异常就关闭连接
+		cause.printStackTrace();
+		ctx.close();
+	}
+
+
+	/**
+	 * 获取角度
+	 * @return
+	 */
+	private static double angle(double x, double y) {
+
+		// 三轴计算
+		// 计算因子
+		double factor = 3.90625;
+
+		double gx = x * factor;
+		double gy = y * factor;
+
+		double Axy =  Math.sqrt(gx * gx + gy * gy);
+
+		if (Axy > 980) {
+			Axy = 980;
+		}
+
+		Axy = Math.acos(Axy/980) * 180 / 3.1415;
+
+		double angleXY = Axy;
+
+		if ((Axy - angleXY) >= 0.5){
+			angleXY += 1;
+		}
+		angleXY = 90 - angleXY;
+
+//		System.out.println("angleXY: " + angleXY); // 23.574218229866414
+
+
+		return angleXY;
+	}
+
+	public static void main(String[] args) {
+		double x = -125;
+		double y = -193;
+		angle(x, y);
+	}
+
+
+
+}

+ 39 - 0
wsm-admin-web/src/main/java/com/wsm/admin/tcp/init/Rule.java

@@ -0,0 +1,39 @@
+package com.wsm.admin.tcp.init;
+
+/**
+ * Created by Owen on 2019/12/3 0003 15:39
+ */
+
+public class Rule {
+
+    private String name;
+
+    private String type;
+
+    private int start;
+
+    private int end;
+
+    public Rule(String name, String type, int start, int end) {
+        this.name = name;
+        this.type = type;
+        this.start = start;
+        this.end = end;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public int getStart() {
+        return start;
+    }
+
+    public int getEnd() {
+        return end;
+    }
+}

+ 42 - 0
wsm-admin-web/src/main/java/com/wsm/admin/thread/TaskExecutePool.java

@@ -0,0 +1,42 @@
+package com.wsm.admin.thread;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * Created by wangjian on 2017/8/29.
+ */
+@Configuration
+@EnableAsync
+public class TaskExecutePool {
+
+    @Value("${spring.task.pool.corePoolSize}")
+    private int corePoolSize;
+    @Value("${spring.task.pool.corePoolSize}")
+    private int maxPoolSize;
+    @Value("${spring.task.pool.keepAliveSeconds}")
+    private int keepAliveSeconds;
+    @Value("${spring.task.pool.queueCapacity}")
+    private int queueCapacity;
+
+    @Bean
+    public Executor updAsyncPool() {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        executor.setCorePoolSize(corePoolSize);
+        executor.setMaxPoolSize(maxPoolSize);
+        executor.setQueueCapacity(keepAliveSeconds);
+        executor.setKeepAliveSeconds(queueCapacity);
+        executor.setThreadNamePrefix("MyExecutor-");
+        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
+        // CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+        executor.initialize();
+        return executor;
+    }
+}

+ 59 - 0
wsm-admin-web/src/main/resources/static/css/login.css

@@ -0,0 +1,59 @@
+body {
+    overflow: hidden;
+}
+
+.video-player {
+    background-color: transparent;
+    min-width: 100%;
+    min-height: 100%;
+    display: block;
+    position: absolute;
+    z-index: 1;
+    top: 0;
+}
+
+.video_mask {
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    left: 0;
+    top: 0;
+    z-index: 90;
+    background-color: rgba(0, 0, 0, 0.5);
+}
+
+.login {
+    height: 260px;
+    width: 260px;
+    padding: 20px;
+    background-color: rgba(0, 0, 0, 0.5);
+    border-radius: 4px;
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    margin: -150px 0 0 -150px;
+    z-index: 99;
+}
+
+.login h1 {
+    text-align: center;
+    color: #fff;
+    font-size: 24px;
+    margin-bottom: 20px;
+}
+
+.form_code {
+    position: relative;
+}
+
+.form_code .code {
+    position: absolute;
+    right: 0;
+    top: 1px;
+    cursor: pointer;
+}
+
+.login_btn {
+    width: 50%;
+    margin-right: 10px
+}

+ 45 - 0
wsm-admin-web/src/main/resources/static/css/main.css

@@ -0,0 +1,45 @@
+/*引入阿里个人图标库*/
+@import "https://at.alicdn.com/t/font_594558_ajc56eo86iw45cdi.css";
+
+.showMenu.layui-layout-admin .layui-side {
+    left: -200px;
+}
+
+.showMenu .layui-body, .showMenu .layui-footer {
+    left: 0;
+}
+
+/*.hideMenu{ float:left; width:20px; height:20px; margin-top:20px; font-size:17px; line-height:20px; text-align:center;  color:#fff; background-color:#1AA094; }*/
+.mini .layui-side-scroll ul li cite {
+    display: none;
+}
+
+.mini .layui-nav-tree .layui-nav-more {
+    right: 3px;
+}
+
+.mini .layui-nav-tree {
+    width: 50px;
+}
+
+/*下面是菜单使用了个人图标情况下的样式申明 否则mini状态不显示图标*/
+/*.mini .layui-nav-tree .layui-nav-item a {text-overflow: clip !important;}*/
+/*样式改变的过渡*/
+.layui-body, .layui-footer, .layui-layout-admin .layui-side {
+    -o-transition: all 0.3s ease-in-out;
+    -moz-transition: all 0.3s ease-in-out;
+    -ms-transition: all 0.3s ease-in-out;
+}
+
+iframe {
+    position: absolute;
+    height: 100%;
+    width: 100%;
+    border: none;
+}
+
+/*iframe 其他属性 frameborder="false" scrolling="auto" style=allowtransparency="true"*/
+
+.layui-nav cite {
+    margin-left: 5px;
+}

二进制
wsm-admin-web/src/main/resources/static/css/metroStyle/img/line_conn.png


二进制
wsm-admin-web/src/main/resources/static/css/metroStyle/img/loading.gif


二进制
wsm-admin-web/src/main/resources/static/css/metroStyle/img/metro.gif


二进制
wsm-admin-web/src/main/resources/static/css/metroStyle/img/metro.png


+ 383 - 0
wsm-admin-web/src/main/resources/static/css/metroStyle/metroStyle.css

@@ -0,0 +1,383 @@
+/*-------------------------------------
+zTree Style
+
+version:    3.4
+author:     Hunter.z
+email:      hunter.z@263.net
+website:    http://code.google.com/p/jquerytree/
+
+-------------------------------------*/
+
+.ztree * {
+    padding: 0;
+    margin: 0;
+    font-size: 14px;
+    font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif
+}
+
+.ztree {
+    margin: 0;
+    padding: 5px;
+    color: #333
+}
+
+.ztree li {
+    padding: 0;
+    margin: 0;
+    list-style: none;
+    line-height: 17px;
+    text-align: left;
+    white-space: nowrap;
+    outline: 0
+}
+
+.ztree li ul {
+    margin: 0;
+    padding: 0 0 0 18px
+}
+
+.ztree li ul.line {
+    background: url(./img/line_conn.png) 0 0 repeat-y;
+}
+
+.ztree li a {
+    padding-right: 3px;
+    margin: 0;
+    cursor: pointer;
+    height: 21px;
+    color: #333;
+    background-color: transparent;
+    text-decoration: none;
+    vertical-align: top;
+    display: inline-block
+}
+
+.ztree li a:hover {
+    text-decoration: underline
+}
+
+.ztree li a.curSelectedNode {
+    padding-top: 0px;
+    background-color: #e5e5e5;
+    color: black;
+    height: 21px;
+    opacity: 0.8;
+}
+
+.ztree li a.curSelectedNode_Edit {
+    padding-top: 0px;
+    background-color: #e5e5e5;
+    color: black;
+    height: 21px;
+    border: 1px #666 solid;
+    opacity: 0.8;
+}
+
+.ztree li a.tmpTargetNode_inner {
+    padding-top: 0px;
+    background-color: #aaa;
+    color: white;
+    height: 21px;
+    border: 1px #666 solid;
+    opacity: 0.8;
+    filter: alpha(opacity=80)
+}
+
+.ztree li a.tmpTargetNode_prev {
+}
+
+.ztree li a.tmpTargetNode_next {
+}
+
+.ztree li a input.rename {
+    height: 14px;
+    width: 80px;
+    padding: 0;
+    margin: 0;
+    font-size: 12px;
+    border: 1px #585956 solid;
+    *border: 0px
+}
+
+.ztree li span {
+    line-height: 21px;
+    margin-right: 2px
+}
+
+.ztree li span.button {
+    line-height: 0;
+    margin: 0;
+    padding: 0;
+    width: 21px;
+    height: 21px;
+    display: inline-block;
+    vertical-align: middle;
+    border: 0 none;
+    cursor: pointer;
+    outline: none;
+    background-color: transparent;
+    background-repeat: no-repeat;
+    background-attachment: scroll;
+    background-image: url("./img/metro.png");
+    *background-image: url("./img/metro.gif")
+}
+
+.ztree li span.button.chk {
+    width: 13px;
+    height: 13px;
+    margin: 0 2px;
+    cursor: auto
+}
+
+.ztree li span.button.chk.checkbox_false_full {
+    background-position: -5px -5px;
+}
+
+.ztree li span.button.chk.checkbox_false_full_focus {
+    background-position: -5px -26px;
+}
+
+.ztree li span.button.chk.checkbox_false_part {
+    background-position: -5px -48px;
+}
+
+.ztree li span.button.chk.checkbox_false_part_focus {
+    background-position: -5px -68px;
+}
+
+.ztree li span.button.chk.checkbox_false_disable {
+    background-position: -5px -89px;
+}
+
+.ztree li span.button.chk.checkbox_true_full {
+    background-position: -26px -5px;
+}
+
+.ztree li span.button.chk.checkbox_true_full_focus {
+    background-position: -26px -26px;
+}
+
+.ztree li span.button.chk.checkbox_true_part {
+    background-position: -26px -48px;
+}
+
+.ztree li span.button.chk.checkbox_true_part_focus {
+    background-position: -26px -68px;
+}
+
+.ztree li span.button.chk.checkbox_true_disable {
+    background-position: -26px -89px;
+}
+
+.ztree li span.button.chk.radio_false_full {
+    background-position: -47px -5px;
+}
+
+.ztree li span.button.chk.radio_false_full_focus {
+    background-position: -47px -26px;
+}
+
+.ztree li span.button.chk.radio_false_part {
+    background-position: -47px -47px;
+}
+
+.ztree li span.button.chk.radio_false_part_focus {
+    background-position: -47px -68px;
+}
+
+.ztree li span.button.chk.radio_false_disable {
+    background-position: -47px -89px;
+}
+
+.ztree li span.button.chk.radio_true_full {
+    background-position: -68px -5px;
+}
+
+.ztree li span.button.chk.radio_true_full_focus {
+    background-position: -68px -26px;
+}
+
+.ztree li span.button.chk.radio_true_part {
+    background-position: -68px -47px;
+}
+
+.ztree li span.button.chk.radio_true_part_focus {
+    background-position: -68px -68px;
+}
+
+.ztree li span.button.chk.radio_true_disable {
+    background-position: -68px -89px;
+}
+
+.ztree li span.button.switch {
+    width: 21px;
+    height: 21px
+}
+
+.ztree li span.button.root_open {
+    background-position: -105px -63px
+}
+
+.ztree li span.button.root_close {
+    background-position: -126px -63px
+}
+
+.ztree li span.button.roots_open {
+    background-position: -105px 0;
+}
+
+.ztree li span.button.roots_close {
+    background-position: -126px 0;
+}
+
+.ztree li span.button.center_open {
+    background-position: -105px -21px;
+}
+
+.ztree li span.button.center_close {
+    background-position: -126px -21px;
+}
+
+.ztree li span.button.bottom_open {
+    background-position: -105px -42px;
+}
+
+.ztree li span.button.bottom_close {
+    background-position: -126px -42px;
+}
+
+.ztree li span.button.noline_open {
+    background-position: -105px -84px;
+}
+
+.ztree li span.button.noline_close {
+    background-position: -126px -84px;
+}
+
+.ztree li span.button.root_docu {
+    background: none;
+}
+
+.ztree li span.button.roots_docu {
+    background-position: -84px 0;
+}
+
+.ztree li span.button.center_docu {
+    background-position: -84px -21px;
+}
+
+.ztree li span.button.bottom_docu {
+    background-position: -84px -42px;
+}
+
+.ztree li span.button.noline_docu {
+    background: none;
+}
+
+.ztree li span.button.ico_open {
+    margin-right: 2px;
+    background-position: -147px -21px;
+    vertical-align: top;
+    *vertical-align: middle
+}
+
+.ztree li span.button.ico_close {
+    margin-right: 2px;
+    margin-right: 2px;
+    background-position: -147px 0;
+    vertical-align: top;
+    *vertical-align: middle
+}
+
+.ztree li span.button.ico_docu {
+    margin-right: 2px;
+    background-position: -147px -42px;
+    vertical-align: top;
+    *vertical-align: middle
+}
+
+.ztree li span.button.edit {
+    margin-left: 2px;
+    margin-right: -1px;
+    background-position: -189px -21px;
+    vertical-align: top;
+    *vertical-align: middle
+}
+
+.ztree li span.button.edit:hover {
+    background-position: -168px -21px;
+}
+
+.ztree li span.button.remove {
+    margin-left: 2px;
+    margin-right: -1px;
+    background-position: -189px -42px;
+    vertical-align: top;
+    *vertical-align: middle
+}
+
+.ztree li span.button.remove:hover {
+    background-position: -168px -42px;
+}
+
+.ztree li span.button.add {
+    margin-left: 2px;
+    margin-right: -1px;
+    background-position: -189px 0;
+    vertical-align: top;
+    *vertical-align: middle
+}
+
+.ztree li span.button.add:hover {
+    background-position: -168px 0;
+}
+
+.ztree li span.button.ico_loading {
+    margin-right: 2px;
+    background: url(./img/loading.gif) no-repeat scroll 0 0 transparent;
+    vertical-align: top;
+    *vertical-align: middle
+}
+
+ul.tmpTargetzTree {
+    background-color: #FFE6B0;
+    opacity: 0.8;
+    filter: alpha(opacity=80)
+}
+
+span.tmpzTreeMove_arrow {
+    width: 16px;
+    height: 21px;
+    display: inline-block;
+    padding: 0;
+    margin: 2px 0 0 1px;
+    border: 0 none;
+    position: absolute;
+    background-color: transparent;
+    background-repeat: no-repeat;
+    background-attachment: scroll;
+    background-position: -168px -84px;
+    background-image: url("./img/metro.png");
+    *background-image: url("./img/metro.gif")
+}
+
+ul.ztree.zTreeDragUL {
+    margin: 0;
+    padding: 0;
+    position: absolute;
+    width: auto;
+    height: auto;
+    overflow: hidden;
+    background-color: #cfcfcf;
+    border: 1px #00B83F dotted;
+    opacity: 0.8;
+    filter: alpha(opacity=80)
+}
+
+.ztreeMask {
+    z-index: 10000;
+    background-color: #cfcfcf;
+    opacity: 0.0;
+    filter: alpha(opacity=0);
+    position: absolute
+}

+ 78 - 0
wsm-admin-web/src/main/resources/static/css/public.css

@@ -0,0 +1,78 @@
+@import "https://at.alicdn.com/t/font_594558_g140ya4hgdlpu8fr.css";
+
+.child-body {
+    padding: 10px 15px 15px 15px
+}
+
+.child-nav {
+    position: relative;
+    border-bottom: 1px solid #e5e5e5;
+    overflow: hidden;
+    height: 39px;
+    line-height: 39px;
+    margin-bottom: 15px
+}
+
+.search-row {
+    padding: 7px 0px;
+    background-color: #f2f2f2
+}
+
+.search-label {
+    float: left;
+    display: block;
+    text-align: right;
+    padding: 9px 5px;
+    font-weight: 400;
+    line-height: 20px
+}
+
+.search-input {
+    float: left;
+    display: inline-block;
+    vertical-align: middle;
+    width: 110px;
+    margin-right: 2px
+}
+
+.date-input {
+    float: left;
+    display: inline-block;
+    vertical-align: middle;
+    width: 150px;
+    margin-right: 2px
+}
+
+.treegrid-indent {
+    width: 16px;
+    height: 16px;
+    display: inline-block;
+    position: relative
+}
+
+.treegrid-expander {
+    width: 16px;
+    height: 16px;
+    display: inline-block;
+    position: relative;
+    cursor: pointer
+}
+
+.treeview .list-group-item {
+    cursor: pointer
+}
+
+.treeview span.indent {
+    margin-left: 10px;
+    margin-right: 10px
+}
+
+.treeview span.icon {
+    width: 12px;
+    margin-right: 5px
+}
+
+.treeview .node-disabled {
+    color: silver;
+    cursor: not-allowed
+}

二进制
wsm-admin-web/src/main/resources/static/img/avater.jpg


二进制
wsm-admin-web/src/main/resources/static/img/cloud10.png


二进制
wsm-admin-web/src/main/resources/static/img/favicon.ico


二进制
wsm-admin-web/src/main/resources/static/img/lockBg.jpg


+ 66 - 0
wsm-admin-web/src/main/resources/static/js/Detector.js

@@ -0,0 +1,66 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+Detector = {
+
+    canvas: !!window.CanvasRenderingContext2D,
+    webgl: (function () {
+        try {
+            return !!window.WebGLRenderingContext && !!document.createElement('canvas').getContext('experimental-webgl');
+        } catch (e) {
+            return false;
+        }
+    })(),
+    workers: !!window.Worker,
+    fileapi: window.File && window.FileReader && window.FileList && window.Blob,
+
+    getWebGLErrorMessage: function () {
+
+        var domElement = document.createElement('div');
+
+        domElement.style.fontFamily = 'monospace';
+        domElement.style.fontSize = '13px';
+        domElement.style.textAlign = 'center';
+        domElement.style.background = '#eee';
+        domElement.style.color = '#000';
+        domElement.style.padding = '1em';
+        domElement.style.width = '475px';
+        domElement.style.margin = '5em auto 0';
+
+        if (!this.webgl) {
+
+            domElement.innerHTML = window.WebGLRenderingContext ? [
+                'Sorry, your graphics card doesn\'t support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation">WebGL</a>'
+            ].join('\n') : [
+                'Sorry, your browser doesn\'t support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation">WebGL</a><br/>',
+                'Please try with',
+                '<a href="http://www.google.com/chrome">Chrome 10</a>, ',
+                '<a href="http://www.mozilla.com/en-US/firefox/all-beta.html">Firefox 4</a> or',
+                '<a href="http://nightly.webkit.org/">Safari 6</a>'
+            ].join('\n');
+
+        }
+
+        return domElement;
+
+    },
+
+    addGetWebGLMessage: function (parameters) {
+
+        var parent, id, domElement;
+
+        parameters = parameters || {};
+
+        parent = parameters.parent !== undefined ? parameters.parent : document.body;
+        id = parameters.id !== undefined ? parameters.id : 'oldie';
+
+        domElement = Detector.getWebGLErrorMessage();
+        domElement.id = id;
+
+        parent.appendChild(domElement);
+
+    }
+
+};

+ 19 - 0
wsm-admin-web/src/main/resources/static/js/index.js

@@ -0,0 +1,19 @@
+/**
+ * Created by cly on 2017/12/21 0027.
+ * 设置iframe高度
+ */
+var indexModel = (function () {
+    return {
+        initFrameHeight: function () {
+            var window_height = $(window).height();
+            var header_height = $('.layui-header').outerHeight();
+            var footer_height = $('.layui-footer').outerHeight();
+            $("#content").height(window_height - header_height - footer_height - 10);
+        }
+
+    }
+})();
+
+(function () {
+    indexModel.initFrameHeight();
+})();

文件差异内容过多而无法显示
+ 2 - 0
wsm-admin-web/src/main/resources/static/js/jquery.min.js


文件差异内容过多而无法显示
+ 165 - 0
wsm-admin-web/src/main/resources/static/js/jquery.ztree.all.min.js


+ 103 - 0
wsm-admin-web/src/main/resources/static/js/map.js

@@ -0,0 +1,103 @@
+/*初始化地图*/
+var map, markersArray = [], geocoder;
+function init(){
+    // var myLatlng = new qq.maps.LatLng(39.916527,116.397128);
+    var myLatlng = new qq.maps.LatLng(22.364046,113.601136);
+    var myOptions = {
+        zoom: 16,
+        center: myLatlng,
+        mapTypeId: qq.maps.MapTypeId.ROADMAP,
+        disableDefaultUI: true
+    };
+
+    map = new qq.maps.Map(document.getElementById("container"), myOptions);
+
+    qq.maps.event.addListener(
+        map, 'click', function(event) {
+            var latLng = new qq.maps.LatLng(event.latLng.getLat(), event.latLng.getLng());
+
+            if (geocoder == null) geocoder = getGeocoder();
+            geocoder.getAddress(latLng);
+        }
+    );
+
+    /*地图地址查询*/
+
+    var lat = $("#latitude").val();
+    var lng = $("#longitude").val();
+    var addressSearch = $("#addressSearch").val();
+
+
+    if (lat != null && "" != lat && lng != null && "" != lng){
+        var latLng = new qq.maps.LatLng(lat, lng);
+        if (geocoder == null) geocoder = getGeocoder();
+        geocoder.getAddress(latLng);
+
+    }
+    else if (addressSearch != null && "" != addressSearch) {
+        if (geocoder == null) geocoder = getGeocoder();
+        geocoder.getLocation(addressSearch);
+    }
+
+    /*地图地址查询*/
+    $("#searchBtn").click(function() {
+        if (geocoder == null) geocoder = getGeocoder();
+        geocoder.getLocation($("#addressSearch").val());
+    });
+
+    /*地图坐标查询*/
+    $("#searchCoordBtn").click(function () {
+        var vlat = $("#latitude").val();
+        var vlng = $("#longitude").val();
+
+        // 根据坐标获取位置
+        var vlatLng = new qq.maps.LatLng(vlat, vlng);
+
+        if (geocoder == null) {
+            geocoder = getGeocoder();
+        }
+        // 显示位置
+        geocoder.getAddress(vlatLng);
+
+    });
+
+}
+
+function getGeocoder(){
+    geocoder = new qq.maps.Geocoder({
+        complete : function(result){
+
+            clearOverlays();
+
+            var addComp = result.detail.addressComponents;
+
+            // $("#addressSearch").val(result.detail.address);
+            $("#city").val(addComp.city);
+            $("#latitude").val(result.detail.location.lat);
+            $("#longitude").val(result.detail.location.lng);
+
+            //添加标记
+            map.setCenter(result.detail.location);
+            var marker = new qq.maps.Marker({
+                map:map,
+                position: result.detail.location,
+                draggable: false
+            });
+            markersArray.push(marker);
+        }
+    });
+    return geocoder;
+}
+
+//清除覆盖层
+function clearOverlays() {
+    if (markersArray) {
+        for (i in markersArray) {
+            markersArray[i].setMap(null);
+        }
+    }
+}
+
+window.onload = init;
+/*初始化地图*/
+

文件差异内容过多而无法显示
+ 699 - 0
wsm-admin-web/src/main/resources/static/js/three.min.js


+ 189 - 0
wsm-admin-web/src/main/resources/static/plugins/diyUpload/css/diyUpload.css

@@ -0,0 +1,189 @@
+@charset "utf-8";
+.parentFileBox {
+    width: auto;
+    height: auto;
+    overflow: hidden;
+    position: relative
+}
+
+.parentFileBox > .fileBoxUl {
+    position: relative;
+    width: 100%;
+    height: auto;
+    overflow: hidden;
+    padding-bottom: 5px
+}
+
+.parentFileBox > .fileBoxUl > li {
+    float: left;
+    border: 1px solid #09f;
+    border-radius: 5px;
+    width: 170px;
+    height: 150px;
+    margin-top: 5px;
+    margin-left: 5px;
+    overflow: hidden;
+    position: relative;
+    background-color: #099
+}
+
+.parentFileBox > .fileBoxUl > li > .viewThumb {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 170px;
+    height: 150px;
+    overflow: hidden
+}
+
+.parentFileBox > .fileBoxUl > li > .viewThumb > img {
+    width: 100%;
+    height: 100%
+}
+
+.parentFileBox > .fileBoxUl > li > .diyCancel, .parentFileBox > .fileBoxUl > li > .diySuccess {
+    position: absolute;
+    width: 32px;
+    height: 32px;
+    top: 2px;
+    right: 2px;
+    cursor: pointer;
+    display: none
+}
+
+.parentFileBox > .fileBoxUl > li > .diyCancel {
+    background: url(../images/x_alt.png) no-repeat
+}
+
+.parentFileBox > .fileBoxUl > li > .diySuccess {
+    background: url(../images/check_alt.png) no-repeat;
+    cursor: default
+}
+
+.parentFileBox > .fileBoxUl > li > .diyFileName {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    width: 100%;
+    height: 20px;
+    line-height: 20px;
+    text-align: center;
+    color: #fff;
+    font-size: 12px;
+    display: none;
+    background: url(../images/bgblack.png)
+}
+
+.parentFileBox > .fileBoxUl > li > .diyBar {
+    top: 0;
+    left: 0;
+    position: absolute;
+    width: 170px;
+    height: 150px;
+    line-height: 150px;
+    background: url(../images/bgblack.png);
+    display: none
+}
+
+.parentFileBox > .fileBoxUl > li > .diyBar > .diyProgressText {
+    font-size: 14px;
+    text-align: center;
+    color: #fff;
+    position: relative;
+    z-index: 99
+}
+
+.parentFileBox > .fileBoxUl > li > .diyBar > .diyProgress {
+    position: absolute;
+    left: 0;
+    top: 42%;
+    height: 24px;
+    width: 100%;
+    background-color: #09f;
+    filter: alpha(opacity=70);
+    -moz-opacity: .7;
+    opacity: .7;
+    z-index: 97
+}
+
+.parentFileBox > .diyButton {
+    width: 100%;
+    margin-top: 5px;
+    margin-bottom: 5px;
+    height: 20px;
+    line-height: 20px;
+    text-align: center
+}
+
+.parentFileBox > .diyButton > a {
+    padding: 5px 10px;
+    /*background-color: #09c;*/
+    background-color: #009688;
+    color: #fff;
+    font-size: 12px;
+    text-decoration: none;
+    border-radius: 3px
+}
+
+.parentFileBox > .diyButton > a:hover {
+    /*background-color: #0cc;
+    color: #f30;*/
+    opacity: .8;
+    filter: alpha(opacity=80);
+    color: #fff;
+}
+
+.parentFileBox > .fileBoxUl > li:hover {
+    -moz-box-shadow: 3px 3px 4px #ff0;
+    -webkit-box-shadow: 3px 3px 4px #ff0;
+    box-shadow: 3px 3px 4px #ff0
+}
+
+.parentFileBox > .fileBoxUl > .diyUploadHover:hover .diyCancel {
+    display: block
+}
+
+.parentFileBox > .fileBoxUl > li:hover .diyFileName {
+    display: block
+}
+
+.avi_diy_bg, .txt_diy_bg, .doc_diy_bg, .zip_diy_bg, .csv_diy_bg, .xls_diy_bg, .mp3_diy_bg, .pdf_diy_bg, .rar_diy_bg {
+    background-position: center;
+    background-repeat: no-repeat
+}
+
+.avi_diy_bg {
+    background-image: url(../images/filebg/avi.png)
+}
+
+.txt_diy_bg {
+    background-image: url(../images/filebg/txt.png)
+}
+
+.doc_diy_bg {
+    background-image: url(../images/filebg/doc.png)
+}
+
+.zip_diy_bg {
+    background-image: url(../images/filebg/zip.png)
+}
+
+.csv_diy_bg {
+    background-image: url(../images/filebg/csv.png)
+}
+
+.xls_diy_bg {
+    background-image: url(../images/filebg/xls.png)
+}
+
+.mp3_diy_bg {
+    background-image: url(../images/filebg/mp3.png)
+}
+
+.pdf_diy_bg {
+    background-image: url(../images/filebg/pdf.png)
+}
+
+.rar_diy_bg {
+    background-image: url(../images/filebg/rar.png)
+}

+ 45 - 0
wsm-admin-web/src/main/resources/static/plugins/diyUpload/css/webuploader.css

@@ -0,0 +1,45 @@
+.webuploader-container {
+    position: relative
+}
+
+.webuploader-element-invisible {
+    position: absolute !important;
+    clip: rect(1px 1px 1px 1px);
+    clip: rect(1px, 1px, 1px, 1px)
+}
+
+.webuploader-pick {
+    position: relative;
+    display: inline-block;
+    cursor: pointer;
+    background: #00b7ee;
+    padding: 10px 15px;
+    color: #fff;
+    text-align: center;
+    border-radius: 3px;
+    overflow: hidden;
+    display: inline-block;
+    height: 38px;
+    line-height: 38px;
+    padding: 0 18px;
+    background-color: #009688;
+    color: #fff;
+    white-space: nowrap;
+    text-align: center;
+    font-size: 14px;
+    border: none;
+    border-radius: 2px;
+    cursor: pointer;
+}
+
+.webuploader-pick-hover {
+    /*background: #00a2d4*/
+    opacity: .8;
+    filter: alpha(opacity=80);
+    color: #fff;
+}
+
+.webuploader-pick-disable {
+    opacity: .6;
+    pointer-events: none
+}

二进制
wsm-admin-web/src/main/resources/static/plugins/diyUpload/images/bgblack.png


二进制
wsm-admin-web/src/main/resources/static/plugins/diyUpload/images/check_alt.png


二进制
wsm-admin-web/src/main/resources/static/plugins/diyUpload/images/x_alt.png


+ 236 - 0
wsm-admin-web/src/main/resources/static/plugins/diyUpload/js/diyUpload.js

@@ -0,0 +1,236 @@
+(function ($) {
+    var startupload;
+    var endupload;
+    $.fn.extend({
+        diyUpload: function (opt, serverCallBack) {
+            if (typeof opt != "object") {
+                alert('参数错误!');
+                return;
+            }
+            var $fileInput = $(this);
+            var $fileInputId = $fileInput.attr('id');
+            if (opt.url) {
+                opt.server = opt.url;
+                delete opt.url;
+            }
+            if (opt.success) {
+                var successCallBack = opt.success;
+                delete opt.success;
+            }
+            if (opt.error) {
+                var errorCallBack = opt.error;
+                delete opt.error;
+            }
+            if (opt.startupload){
+                startupload = opt.startupload;
+                delete opt.startupload;
+            }
+            if (opt.endupload){
+                endupload = opt.endupload;
+                delete opt.endupload;
+            }
+            $.each(getOption('#' + $fileInputId), function (key, value) {
+                opt[key] = opt[key] || value;
+            });
+            if (opt.buttonText) {
+                opt['pick']['label'] = opt.buttonText;
+                delete opt.buttonText;
+            }
+            var webUploader = getUploader(opt);
+            if (!WebUploader.Uploader.support()) {
+                alert(' 上传组件不支持您的浏览器!');
+                return false;
+            }
+            webUploader.on('fileQueued', function (file) {
+                createBox($fileInput, file, webUploader);
+            });
+            webUploader.on('uploadProgress', function (file, percentage) {
+                var $fileBox = $('#fileBox_' + file.id);
+                var $diyBar = $fileBox.find('.diyBar');
+                $diyBar.show();
+                percentage = percentage * 100;
+                showDiyProgress(percentage.toFixed(2), $diyBar);
+            });
+            webUploader.on('uploadFinished', function () {
+                $fileInput.next('.parentFileBox').children('.diyButton').remove();
+                if (endupload) {
+                    endupload();
+                }
+            });
+            webUploader.on('uploadAccept', function (object, data) {
+                if (serverCallBack) serverCallBack(data);
+            });
+            webUploader.on('uploadSuccess', function (file, response) {
+                var $fileBox = $('#fileBox_' + file.id);
+                var $diyBar = $fileBox.find('.diyBar');
+                $fileBox.removeClass('diyUploadHover');
+                $diyBar.fadeOut(1000, function () {
+                    $fileBox.children('.diySuccess').show();
+                });
+                if (successCallBack) {
+                    successCallBack(response);
+                }
+            });
+            webUploader.on('uploadError', function (file, reason) {
+                var $fileBox = $('#fileBox_' + file.id);
+                var $diyBar = $fileBox.find('.diyBar');
+                showDiyProgress(0, $diyBar, '上传失败!');
+                var err = '上传失败! 文件:' + file.name + ' 错误码:' + reason;
+                if (errorCallBack) {
+                    errorCallBack(err);
+                }
+            });
+            webUploader.on('error', function (code) {
+                var text = '';
+                switch (code) {
+                    case 'F_DUPLICATE':
+                        text = '该文件已经被选择了!';
+                        break;
+                    case 'Q_EXCEED_NUM_LIMIT':
+                        text = '上传文件数量超过限制!';
+                        break;
+                    case 'F_EXCEED_SIZE':
+                        text = '文件大小超过限制!';
+                        break;
+                    case 'Q_EXCEED_SIZE_LIMIT':
+                        text = '所有文件总大小超过限制!';
+                        break;
+                    case 'Q_TYPE_DENIED':
+                        text = '文件类型不正确或者是空文件!';
+                        break;
+                    default:
+                        text = '未知错误!';
+                        break;
+                }
+                alert(text);
+            });
+        }
+    });
+
+    function getOption(objId) {
+        return {
+            pick: {id: objId, label: "点击选择图片"},
+            accept: {title: "Images", extensions: "gif,jpg,jpeg,bmp,png", mimeTypes: "image/*"},
+            thumb: {width: 170, height: 150, quality: 70, allowMagnify: false, crop: true, type: "image/jpeg"},
+            method: "POST",
+            server: "",
+            sendAsBinary: false,
+            threads:1,
+            chunked: true,
+            fileNumLimit: 20,
+            fileSizeLimit: 100 * 1024 * 1024,
+            fileSingleSizeLimit: 5 * 1024 * 1024
+        };
+    }
+
+    function getUploader(opt) {
+        return new WebUploader.Uploader(opt);
+    }
+
+    function showDiyProgress(progress, $diyBar, text) {
+        if (progress >= 100) {
+            progress = progress + '%';
+            text = text || '上传完成';
+        } else {
+            progress = progress + '%';
+            text = text || progress;
+        }
+        var $diyProgress = $diyBar.find('.diyProgress');
+        var $diyProgressText = $diyBar.find('.diyProgressText');
+        $diyProgress.width(progress);
+        $diyProgressText.text(text);
+    }
+
+    function removeLi($li, file_id, webUploader) {
+        webUploader.removeFile(file_id);
+        if ($li.siblings('li').length <= 0) {
+            $li.parents('.parentFileBox').remove();
+        } else {
+            $li.remove();
+        }
+    }
+
+    function createBox($fileInput, file, webUploader) {
+        var file_id = file.id;
+        var $parentFileBox = $fileInput.next('.parentFileBox');
+        if ($parentFileBox.length <= 0) {
+            var div = '<div class="parentFileBox"> \
+						<ul class="fileBoxUl"></ul>\
+					</div>';
+            $fileInput.after(div);
+            $parentFileBox = $fileInput.next('.parentFileBox');
+        }
+        if ($parentFileBox.find('.diyButton').length <= 0) {
+            var div = '<div class="diyButton"> \
+						<a class="diyStart" href="javascript:void(0)">开始上传</a> \
+						<a class="diyCancelAll" href="javascript:void(0)">全部取消</a> \
+					</div>';
+            $parentFileBox.append(div);
+            var $startButton = $parentFileBox.find('.diyStart');
+            var $cancelButton = $parentFileBox.find('.diyCancelAll');
+            var uploadStart = function () {
+                if (startupload) {
+                    startupload();
+                }
+                webUploader.upload();
+                $startButton.text('暂停上传').one('click', function () {
+                    webUploader.stop();
+                    $(this).text('继续上传').one('click', function () {
+                        uploadStart();
+                    });
+                });
+            }
+            $startButton.one('click', uploadStart);
+            $cancelButton.bind('click', function () {
+                var fileArr = webUploader.getFiles('queued');
+                $.each(fileArr, function (i, v) {
+                    removeLi($('#fileBox_' + v.id), v.id, webUploader);
+                });
+            });
+        }
+        var li = '<li id="fileBox_' + file_id + '" class="diyUploadHover"> \
+					<div class="viewThumb"></div> \
+					<div class="diyCancel"></div> \
+					<div class="diySuccess"></div> \
+					<div class="diyFileName">' + file.name + '</div>\
+					<div class="diyBar"> \
+							<div class="diyProgress"></div> \
+							<div class="diyProgressText">0%</div> \
+					</div> \
+				</li>';
+        $parentFileBox.children('.fileBoxUl').append(li);
+        var $width = $('.fileBoxUl>li').length * 180;
+        var $maxWidth = $fileInput.parent().width();
+        $width = $maxWidth > $width ? $width : $maxWidth;
+        $parentFileBox.width($width);
+        var $fileBox = $parentFileBox.find('#fileBox_' + file_id);
+        var $diyCancel = $fileBox.children('.diyCancel').one('click', function () {
+            removeLi($(this).parent('li'), file_id, webUploader);
+        });
+        if (file.type.split("/")[0] != 'image') {
+            var liClassName = getFileTypeClassName(file.name.split(".").pop());
+            $fileBox.addClass(liClassName);
+            return;
+        }
+        webUploader.makeThumb(file, function (error, dataSrc) {
+            if (!error) {
+                $fileBox.find('.viewThumb').append('<img src="' + dataSrc + '" >');
+            }
+        });
+    }
+
+    function getFileTypeClassName(type) {
+        var fileType = {};
+        var suffix = '_diy_bg';
+        fileType['pdf'] = 'pdf';
+        fileType['zip'] = 'zip';
+        fileType['rar'] = 'rar';
+        fileType['csv'] = 'csv';
+        fileType['doc'] = 'doc';
+        fileType['xls'] = 'xls';
+        fileType['xlsx'] = 'xls';
+        fileType['txt'] = 'txt';
+        fileType = fileType[type] || 'txt';
+        return fileType + suffix;
+    }
+})(jQuery);

文件差异内容过多而无法显示
+ 2 - 0
wsm-admin-web/src/main/resources/static/plugins/diyUpload/js/webuploader.js


文件差异内容过多而无法显示
+ 2 - 0
wsm-admin-web/src/main/resources/static/plugins/layui/css/layui.css


文件差异内容过多而无法显示
+ 2 - 0
wsm-admin-web/src/main/resources/static/plugins/layui/css/layui.mobile.css


文件差异内容过多而无法显示
+ 2 - 0
wsm-admin-web/src/main/resources/static/plugins/layui/css/modules/code.css


文件差异内容过多而无法显示
+ 2 - 0
wsm-admin-web/src/main/resources/static/plugins/layui/css/modules/laydate/default/laydate.css


二进制
wsm-admin-web/src/main/resources/static/plugins/layui/css/modules/layer/default/icon-ext.png


二进制
wsm-admin-web/src/main/resources/static/plugins/layui/css/modules/layer/default/icon.png


文件差异内容过多而无法显示
+ 2 - 0
wsm-admin-web/src/main/resources/static/plugins/layui/css/modules/layer/default/layer.css


二进制
wsm-admin-web/src/main/resources/static/plugins/layui/css/modules/layer/default/loading-0.gif


二进制
wsm-admin-web/src/main/resources/static/plugins/layui/css/modules/layer/default/loading-1.gif


二进制
wsm-admin-web/src/main/resources/static/plugins/layui/css/modules/layer/default/loading-2.gif


+ 0 - 0
wsm-admin-web/src/main/resources/static/plugins/layui/font/iconfont.eot


部分文件因为文件数量过多而无法显示