commit 572ad1205f978bba52964f5d3aad3ded57f79ad5
Author: rqian <1206436827@qq.com>
Date: Fri Apr 17 10:09:03 2026 +0800
first commit
diff --git a/maibu-admin/pom.xml b/maibu-admin/pom.xml
new file mode 100644
index 0000000..3c496f6
--- /dev/null
+++ b/maibu-admin/pom.xml
@@ -0,0 +1,93 @@
+
+
+ 4.0.0
+
+ com.maibu
+ MiddlePlatform
+ 4.0.0
+
+
+ maibu-admin
+
+
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ true
+
+
+
+ com.maibu
+ maibu-netty-server
+ ${maibu.version}
+
+
+ com.maibu
+ maibu-webrtc-server
+ ${maibu.version}
+
+
+
+ com.maibu
+ maibu-web-middleware
+ ${maibu.version}
+
+
+
+ com.maibu
+ maibu-external
+ ${maibu.version}
+
+
+
+ com.maibu
+ maibu-iotDA
+ ${maibu.version}
+
+
+
+
+ io.springfox
+ springfox-boot-starter
+
+
+
+
+ io.swagger
+ swagger-models
+ 1.6.2
+
+
+
+
+ mysql
+ mysql-connector-java
+
+
+
+
+ com.maibu
+ maibu-framework
+
+
+
+ com.maibu
+ maibu-common
+
+
+
+ com.github.ben-manes.caffeine
+ caffeine
+
+
+
+
+ 8
+ 8
+ UTF-8
+
+
+
\ No newline at end of file
diff --git a/maibu-admin/src/main/java/com/maibu/MiddlePlatformApplication.java b/maibu-admin/src/main/java/com/maibu/MiddlePlatformApplication.java
new file mode 100644
index 0000000..157652b
--- /dev/null
+++ b/maibu-admin/src/main/java/com/maibu/MiddlePlatformApplication.java
@@ -0,0 +1,48 @@
+package com.maibu;
+
+import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
+import com.dtflys.forest.springboot.annotation.ForestScan;
+import com.fastbee.netty.NettyServer;
+import com.fastbee.websocket.WebsocketHandler;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.ConfigurableApplicationContext;
+
+/**
+ * 启动程序
+ *
+ * @author ruoyi
+ */
+@SpringBootApplication(exclude = { DruidDataSourceAutoConfigure.class })
+@ForestScan(basePackages = "com.maibu")
+public class MiddlePlatformApplication
+{
+
+ public static void main(String[] args)
+ {
+ // System.setProperty("spring.devtools.restart.enabled", "false");
+ ConfigurableApplicationContext context = SpringApplication.run(MiddlePlatformApplication.class, args);
+
+ WebsocketHandler websocketHandler = new WebsocketHandler(9002);
+ websocketHandler.start();
+
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ // 关闭WebSocket服务(核心:释放9002端口)
+ System.out.println("开始释放websocket资源");
+ try {
+ websocketHandler.stopServer();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ // 关闭Spring上下文
+ context.close();
+ }, "shutdown-hook-thread"));
+
+ NettyServer nettyServer = context.getBean(NettyServer.class);
+ nettyServer.start();
+
+
+
+ }
+
+}
diff --git a/maibu-admin/src/main/resources/META-INF/spring-devtools.properties b/maibu-admin/src/main/resources/META-INF/spring-devtools.properties
new file mode 100644
index 0000000..37e7b58
--- /dev/null
+++ b/maibu-admin/src/main/resources/META-INF/spring-devtools.properties
@@ -0,0 +1 @@
+restart.include.json=/com.alibaba.fastjson2.*.jar
\ No newline at end of file
diff --git a/maibu-admin/src/main/resources/application-dev.yml b/maibu-admin/src/main/resources/application-dev.yml
new file mode 100644
index 0000000..80aebdd
--- /dev/null
+++ b/maibu-admin/src/main/resources/application-dev.yml
@@ -0,0 +1,112 @@
+# 数据源配置
+spring:
+ datasource:
+ dynamic:
+ primary: master
+ strict: false
+ datasource:
+ master:
+ type: com.alibaba.druid.pool.DruidDataSource
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://1.95.137.212:3306/fastbee?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+ username: fastbee
+ password: maibu520
+ # slave:
+ # type: com.alibaba.druid.pool.DruidDataSource
+ # driver-class-name: com.mysql.cj.jdbc.Driver
+ # url: jdbc:mysql://localhost:3306/fastbee1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+ # username: root
+ # password: fastbee
+ sharding:
+ url: jdbc:shardingsphere:classpath:sharding-sphere-config.yaml
+ driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
+ taos: # 配置 taos 数据源
+ enabled: false
+ type: com.alibaba.druid.pool.DruidDataSource
+ driver-class-name: com.taosdata.jdbc.TSDBDriver
+ url: jdbc:TAOS://fastbee:6030/fastbee_log?timezone=UTC-8&charset=utf-8
+ username: root
+ password: taosdata
+ dbName: fastbee_log
+
+ # redis 配置
+ redis:
+ host: localhost # 地址
+ port: 6379 # 端口,默认为6379
+ database: 3 # 数据库索引
+ #password: # 密码
+ timeout: 10s # 连接超时时间
+ lettuce:
+ pool:
+ min-idle: 0 # 连接池中的最小空闲连接
+ max-idle: 8 # 连接池中的最大空闲连接
+ max-active: 8 # 连接池的最大数据库连接数
+ max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
+ # mqtt 配置
+ mqtt:
+ username: fastbee # 账号
+ password: fastbee # 密码
+ host-url: tcp://localhost:1883 # mqtt连接tcp地址
+ client-id: ${random.int} # 客户端Id,不能相同,采用随机数 ${random.value}
+ default-topic: test # 默认主题
+ timeout: 30 # 超时时间
+ keepalive: 30 # 保持连接
+ clearSession: true # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
+ servlet:
+ multipart:
+ enabled: true
+ max-file-size: 10MB
+ max-request-size: 10MB
+
+# sip 配置
+sip:
+ enabled: false # 是否启用视频监控SIP,true为启用
+ ## 本地调试时,绑定网卡局域网IP,设备在同一局域网,设备接入IP填写绑定IP
+ ## 部署服务端时,默认绑定容器IP,设备接入IP填写服务器公网IP
+ ip: 177.7.0.13
+ port: 5061 # SIP端口(保持默认)
+ domain: 3402000000 # 由省级、市级、区级、基层编号组成
+ id: 34020000002000000001 # 同上,另外增加编号,(可保持默认)
+ password: 12345678 # 监控设备接入的密码
+ log: true
+ zlmRecordPath: /opt/media/bin/www
+
+# 日志配置
+logging:
+ level:
+ com.fastbee: debug
+ com.yomahub: debug
+ org.dromara: warn
+ org.springframework: warn
+
+# Swagger配置
+swagger:
+ enabled: true # 是否开启swagger
+ pathMapping: /dev-api # 请求前缀
+
+
+ali:
+ sms:
+ access-key-id: LTAI5tFxmTZAeFBNa7sqcHUj
+ access-key-secret: vtHYhEWrh585jleku55TbHhtYscmGU
+ endpoint: dysmsapi.aliyuncs.com
+ sign-name: 飒沓机器人
+ template-code: SMS_498590140
+ expired-time: 1
+
+UAV:
+ token: eyJhbGciOiJIUzUxMiIsImNyaXQiOlsidHlwIiwiYWxnIiwia2lkIl0sImtpZCI6IjhiZmRiZmRkLWM4OGYtNGE5Yi04NzI3LWQ0ZGYzYWE5OTJlOSIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50IjoiODQ5MDczQHFxLmNvbSIsImV4cCI6MjA1OTg2ODc3NCwibmJmIjoxNzQ0MzM1OTc0LCJvcmdhbml6YXRpb25fdXVpZCI6ImYwMmIwZTM4LWUyZjgtNGNhMi04ZTBmLWM1YmVlMTM3NDk2ZiIsInByb2plY3RfdXVpZCI6IiIsInN1YiI6ImZoMiIsInVzZXJfaWQiOiIxMDEyOSJ9.t9KH3SOBNxJwi3bZwA7diGV7qeLZY2cXI9ovT5FnkWXLjSHNYHD4KQObGi1iGJ5igAxZZaWIooT8v8VcPwsrSQ
+ projectUId: bb191b8f-5110-4536-82e3-f56730e93e4c
+ baseUrl: https://es-flight-api-cn.djigate.com
+
+ioTDA:
+ serverIp: 2d8fd0f2a9.st1.iotda-device.cn-north-4.myhuaweicloud.com
+ deviceId: 698551ef7f2e6c302f519144_MC700AIR-CN-JS-1762486208349-0000001A-FD
+ secret: d940bccd7b591848eadab9a24d332d52
+ serviceId: MowingRobot
+ REGION_ID: cn-north-4
+ ENDPOINT: 2d8fd0f2a9.st1.iotda-app.cn-north-4.myhuaweicloud.com
+ ak: HPUAQHOL0WPXJ1BX3SDV
+ sk: 06B2ex4JkeGjE7PfWLsYt7PdXN2xvBxEjotPbkaQ
+ projectId: df32e2f94c15428a9763f01f4f0d337c
+ productId: 698551ef7f2e6c302f519144
\ No newline at end of file
diff --git a/maibu-admin/src/main/resources/application-prod.yml b/maibu-admin/src/main/resources/application-prod.yml
new file mode 100644
index 0000000..c61757c
--- /dev/null
+++ b/maibu-admin/src/main/resources/application-prod.yml
@@ -0,0 +1,91 @@
+# 数据源配置
+spring:
+ datasource:
+ dynamic:
+ primary: master
+ strict: false
+ datasource:
+ master:
+ type: com.alibaba.druid.pool.DruidDataSource
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://localhost:3306/fastbee?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+ username: root
+ password: maibu520
+ filters: stat,wall
+ filter:
+ stat:
+ enabled: true
+ # 慢SQL记录
+ log-slow-sql: true
+ slow-sql-millis: 1000
+ merge-sql: true
+ wall:
+ config:
+ multi-statement-allow: true
+# slave:
+# type: com.alibaba.druid.pool.DruidDataSource
+# driver-class-name: com.mysql.cj.jdbc.Driver
+# url: jdbc:mysql://localhost:3306/fastbee1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+# username: root
+# password: fastbee
+ sharding:
+ url: jdbc:shardingsphere:classpath:sharding-sphere-config.yaml
+ driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
+ taos: # 配置 taos 数据源
+ enabled: true
+ type: com.alibaba.druid.pool.DruidDataSource
+ driver-class-name: com.taosdata.jdbc.TSDBDriver
+ url: jdbc:TAOS://fastbee:6030/fastbee_log?timezone=UTC-8&charset=utf-8
+ username: root
+ password: taosdata
+ dbName: fastbee_log
+ # redis 配置
+ redis:
+ host: 177.7.0.10 # 地址
+ port: 6379 # 端口,默认为6379
+ database: 0 # 数据库索引
+ password: fastbee # 密码
+ timeout: 10s # 连接超时时间
+ lettuce:
+ pool:
+ min-idle: 0 # 连接池中的最小空闲连接
+ max-idle: 8 # 连接池中的最大空闲连接
+ max-active: 8 # 连接池的最大数据库连接数
+ max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
+ # mqtt 配置
+ mqtt:
+ username: fastbee # 账号(仅用于后端自认证)
+ password: fastbee # 密码(仅用于后端自认证)
+ host-url: tcp://177.7.0.12:1883 # 连接 Emqx 消息服务器地址
+ # host-url: tcp://177.7.0.13:1883 # 内置netty mqtt broker地址
+ client-id: ${random.int} # 客户端Id,不能相同,采用随机数 ${random.value}
+ default-topic: test # 默认主题
+ timeout: 30 # 超时时间
+ keepalive: 30 # 保持连接
+ clearSession: true # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
+
+# sip 配置
+sip:
+ enabled: true # 是否启用视频监控SIP,true为启用
+ ## 本地调试时,绑定网卡局域网IP,设备在同一局域网,设备接入IP填写绑定IP
+ ## 部署服务端时,默认绑定容器IP,设备接入IP填写服务器公网IP
+ ip: 177.7.0.13
+ port: 5061 # SIP端口(保持默认)
+ domain: 3402000000 # 由省级、市级、区级、基层编号组成
+ id: 34020000002000000001 # 同上,另外增加编号,(可保持默认)
+ password: 12345678 # 监控设备接入的密码
+ log: false
+ zlmRecordPath: /opt/media/bin/www
+
+# 日志配置
+logging:
+ level:
+ com.fastbee: debug
+ com.yomahub: warn
+ org.dromara: warn
+ org.springframework: warn
+
+# Swagger配置
+swagger:
+ enabled: true # 是否开启swagger
+ pathMapping: /prod-api # 请求前缀
diff --git a/maibu-admin/src/main/resources/application-sql.yml b/maibu-admin/src/main/resources/application-sql.yml
new file mode 100644
index 0000000..98c80e1
--- /dev/null
+++ b/maibu-admin/src/main/resources/application-sql.yml
@@ -0,0 +1,91 @@
+# 数据源配置
+spring:
+ datasource:
+ dynamic:
+ primary: master
+ strict: false
+ datasource:
+ master:
+ type: com.alibaba.druid.pool.DruidDataSource
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://localhost:3306/fastbee?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+ username: root
+ password: maibu520
+ filters: stat,wall
+ filter:
+ stat:
+ enabled: true
+ # 慢SQL记录
+ log-slow-sql: true
+ slow-sql-millis: 1000
+ merge-sql: true
+ wall:
+ config:
+ multi-statement-allow: true
+# slave:
+# type: com.alibaba.druid.pool.DruidDataSource
+# driver-class-name: com.mysql.cj.jdbc.Driver
+# url: jdbc:mysql://localhost:3306/fastbee1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+# username: root
+# password: fastbee
+ sharding:
+ url: jdbc:shardingsphere:classpath:sharding-sphere-config.yaml
+ driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
+ taos: # 配置 taos 数据源
+ enabled: true
+ type: com.alibaba.druid.pool.DruidDataSource
+ driver-class-name: com.taosdata.jdbc.TSDBDriver
+ url: jdbc:TAOS://fastbee:6030/fastbee_log?timezone=UTC-8&charset=utf-8
+ username: root
+ password: taosdata
+ dbName: fastbee_log
+ # redis 配置
+ redis:
+ host: localhost # 地址
+ port: 6379 # 端口,默认为6379
+ database: 3 # 数据库索引
+ password: # 密码
+ timeout: 10s # 连接超时时间
+ lettuce:
+ pool:
+ min-idle: 0 # 连接池中的最小空闲连接
+ max-idle: 8 # 连接池中的最大空闲连接
+ max-active: 8 # 连接池的最大数据库连接数
+ max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
+ # mqtt 配置
+ mqtt:
+ username: fastbee # 账号
+ password: fastbee # 密码
+ host-url: tcp://localhost:1883 # mqtt连接tcp地址
+ client-id: ${random.int} # 客户端Id,不能相同,采用随机数 ${random.value}
+ default-topic: test # 默认主题
+ timeout: 30 # 超时时间
+ keepalive: 30 # 保持连接
+ clearSession: true # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
+
+# sip 配置
+sip:
+ enabled: true # 是否启用视频监控SIP,true为启用
+ ## 默认为容器IP,IDE启动可以写本地网卡内网IP或者127.0.0.1
+ ## 本地调试需保持设备与服务器在同一局域网
+ ip: 192.168.31.165
+ port: 5061 # SIP端口(保持默认)
+ domain: 3402000000 # 由省级、市级、区级、基层编号组成
+ id: 34020000002000000001 # 同上,另外增加编号,(可保持默认)
+ password: 12345678 # 监控设备接入的密码
+ log: true
+ zlmRecordPath: /opt/media/bin/www
+
+# 日志配置
+logging:
+ level:
+ com.fastbee: debug
+ com.yomahub: debug
+ org.dromara: warn
+ org.springframework: warn
+
+# Swagger配置
+swagger:
+ enabled: true # 是否开启swagger
+ pathMapping: /dev-api # 请求前缀
+
diff --git a/maibu-admin/src/main/resources/application.yml b/maibu-admin/src/main/resources/application.yml
new file mode 100644
index 0000000..3969893
--- /dev/null
+++ b/maibu-admin/src/main/resources/application.yml
@@ -0,0 +1,218 @@
+# 项目相关配置
+fastbee:
+ name: fastbee # 名称
+ version: 3.8.5 # 版本
+ copyrightYear: 2023 # 版权年份
+ demoEnabled: true # 实例演示开关
+ # 文件路径,以uploadPath结尾 示例( Windows配置 D:/uploadPath,Linux配置 /uploadPath)
+ profile: D:/uploadPath
+ addressEnabled: true # 获取ip地址开关
+ captchaType: math # 验证码类型 math 数组计算 char 字符验证
+
+# 开发环境配置
+server:
+ port: 8081 # 服务器的HTTP端口,默认为8080
+ servlet:
+ context-path: / # 应用的访问路径
+ tomcat:
+ uri-encoding: UTF-8 # tomcat的URI编码
+ accept-count: 1000 # 连接数满后的排队数,默认为100
+ threads:
+ max: 800 # tomcat最大线程数,默认为200
+ min-spare: 100 # Tomcat启动初始化的线程数,默认值10
+ # 基于netty的服务器
+ broker:
+ enabled: false # mqttBroker类型选择, true: 基于netty的mqttBroker和webSocket false: emq的mqttBroker
+ port: 1883
+ websocket-port: 8083
+ websocket-path: /mqtt
+ keep-alive: 70 # 默认的全部客户端心跳上传时间
+ #TCP服务端口
+ tcp:
+ enabled: true # 控制tcp端口是否开启
+ port: 8888
+ keep-alive: 70
+ delimiter: 0x7e
+ udp:
+ enabled: false # 控制udp端口是否开启
+ port: 8889
+ read-idle: 300 # udp保活时间 默认5分钟
+ http:
+ enabled: false
+ port: 8081
+ auth:
+ type: Basic # 支持Basic,Digest
+ user:
+ name: fastbee
+ password: fastbee
+ coap:
+ enabled: false
+ port: 5683
+
+# Spring配置
+spring:
+ # 环境配置,dev=开发环境,prod=生产环境
+ profiles:
+ active: dev # 环境配置,dev=开发环境,prod=生产环境
+ # 资源信息
+ messages:
+ # 国际化资源文件路径
+ basename: i18n/messages
+ # 文件上传
+ servlet:
+ multipart:
+ max-file-size: 10MB # 单个文件大小
+ max-request-size: 20MB # 设置总上传的文件大小
+ # 服务模块
+ devtools:
+ restart:
+ enabled: true # 热部署开关
+ task:
+ execution:
+ pool:
+ core-size: 20 # 最小连接数
+ max-size: 200 # 最大连接数
+ queue-capacity: 3000 # 最大容量
+ keep-alive: 60
+ # 缓存配置
+ cache:
+ enable: false
+ type: none # none=不使用缓存 redis=使用redis缓存
+ ttl: 1800 # 缓存过期时间(默认60秒)
+ datasource:
+ druid:
+ filters: stat,wall
+ filter:
+ stat:
+ enabled: true
+ webStatFilter:
+ enabled: true
+ stat-view-servlet:
+ enabled: true
+ allow:
+ url-pattern: /druid/*
+ loginUsername: fastbee
+ loginPassword: fastbee
+
+
+# 用户配置
+user:
+ password:
+ maxRetryCount: 5 # 密码最大错误次数
+ lockTime: 10 # 密码锁定时间(默认10分钟)
+
+# token配置
+token:
+ header: Authorization # 令牌自定义标识
+ secret: abcdefghijklfastbeesmartrstuvwxyz # 令牌密钥
+ expireTime: 1440 # 令牌有效期(默认30分钟)1440为一天
+
+# MyBatis配置
+#mybatis:
+# typeAliasesPackage: com.fastbee.**.domain # 搜索指定包别名
+# mapperLocations: classpath*:mapper/**/*Mapper.xml # 配置mapper的扫描,找到所有的mapper.xml映射文件
+# configLocation: classpath:mybatis/mybatis-config.xml # 加载全局的配置文件
+
+# mybatis-plus配置
+mybatis-plus:
+ typeAliasesPackage: com.fastbee.**.domain # 搜索指定包别名
+ mapperLocations: classpath*:mapper/**/*Mapper.xml # 配置mapper的扫描,找到所有的mapper.xml映射文件
+ configLocation: classpath:mybatis/mybatis-config.xml # 加载全局的配置文件
+ global-config:
+ db-config:
+ id-type: AUTO # 自增 ID
+ logic-delete-value: 1 # 逻辑已删除值(默认为 1)
+ logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
+
+# PageHelper分页插件
+pagehelper:
+ helperDialect: mysql
+ supportMethodsArguments: true
+ params: count=countSql
+
+# 防止XSS攻击
+xss:
+ enabled: true # 过滤开关
+ excludes: /system/notice # 排除链接(多个用逗号分隔)
+ urlPatterns: /system/*,/monitor/*,/tool/* # 匹配链接
+
+# EMQX API配置需要在运行emqx之后去EMQX管理后台手动创建API Key和Secret,并配置到application.yml中
+emqx:
+ host: localhost # EMQX服务器地址
+ port: 18083
+ ApiKey: ApiKey # EMQX API Key
+ ApiSecret: ApiSecret # EMQX API Secret
+
+# redisson 配置
+redisson:
+ # redis key前缀
+ keyPrefix: sql_cache
+ # 线程池数量
+ threads: 16
+ # Netty线程池数量
+ nettyThreads: 32
+ # 单节点配置
+ singleServerConfig:
+ # 客户端名称
+ clientName: ${fastbee.name}
+ # 最小空闲连接数
+ connectionMinimumIdleSize: 32
+ # 连接池大小
+ connectionPoolSize: 64
+ # 连接空闲超时,单位:毫秒
+ idleConnectionTimeout: 10000
+ # 命令等待超时,单位:毫秒
+ timeout: 3000
+ # 发布和订阅连接池大小
+ subscriptionConnectionPoolSize: 50
+
+forest: # Forest配置 版本为1.5.36
+ backend: okhttp3 # 后端HTTP框架(默认为 okhttp3)
+ max-connections: 1000 # 连接池最大连接数(默认为 500)
+ max-route-connections: 500 # 每个路由的最大连接数(默认为 500)
+ max-request-queue-size: 100 # [自v1.5.22版本起可用] 最大请求等待队列大小
+ max-async-thread-size: 300 # [自v1.5.21版本起可用] 最大异步线程数
+ max-async-queue-size: 16 # [自v1.5.22版本起可用] 最大异步线程池队列大小
+ connect-timeout: 3000 # 连接超时时间,单位为毫秒(默认为 timeout)
+ read-timeout: 3000 # 数据读取超时时间,单位为毫秒(默认为 timeout)
+ max-retry-count: 0 # 请求失败后重试次数(默认为 0 次不重试)
+ ssl-protocol: TLS # 单向验证的HTTPS的默认TLS协议(默认为 TLS)
+ log-enabled: true # 打开或关闭日志(默认为 true)
+ log-request: true # 打开/关闭Forest请求日志(默认为 true)
+ log-response-status: true # 打开/关闭Forest响应状态日志(默认为 true)
+ log-response-content: true # 打开/关闭Forest响应内容日志(默认为 false)
+ async-mode: platform # [自v1.5.27版本起可用] 异步模式(默认为 platform)
+
+liteflow:
+ #FlowExecutor的execute2Future的线程数,默认为64
+ main-executor-works: 64
+ #FlowExecutor的execute2Future的自定义线程池Builder
+ main-executor-class: com.fastbee.ruleEngine.config.MainExecutorBuilder
+ #并行节点的线程池Builder
+ thread-executor-class: com.fastbee.ruleEngine.config.WhenExecutorBuilder
+ rule-source-ext-data-map:
+ # 应用名称,规则链和脚本组件名称需要一致,不要修改
+ applicationName: fastbee
+ #是否开启SQL日志
+ sqlLogEnabled: true
+ # 规则多时,启用快速加载模式
+ fast-load: false
+ #是否开启SQL数据轮询自动刷新机制 默认不开启
+ pollingEnabled: false
+ pollingIntervalSeconds: 60
+ pollingStartSeconds: 60
+ #以下是chain表的配置
+ chainTableName: iot_scene
+ chainApplicationNameField: application_name
+ chainNameField: chain_name
+ elDataField: el_data
+ chainEnableField: enable
+ #以下是script表的配置
+ scriptTableName: iot_script
+ scriptApplicationNameField: application_name
+ scriptIdField: script_id
+ scriptNameField: script_name
+ scriptDataField: script_data
+ scriptTypeField: script_type
+ scriptLanguageField: script_language
+ scriptEnableField: enable
diff --git a/maibu-admin/src/main/resources/banner.txt b/maibu-admin/src/main/resources/banner.txt
new file mode 100644
index 0000000..b8ebf46
--- /dev/null
+++ b/maibu-admin/src/main/resources/banner.txt
@@ -0,0 +1,2 @@
+Application Version: ${fastbee.version}
+Spring Boot Version: ${spring-boot.version}
\ No newline at end of file
diff --git a/maibu-admin/src/main/resources/i18n/messages.properties b/maibu-admin/src/main/resources/i18n/messages.properties
new file mode 100644
index 0000000..a17c1e4
--- /dev/null
+++ b/maibu-admin/src/main/resources/i18n/messages.properties
@@ -0,0 +1,210 @@
+#\u9519\u8BEF\u6D88\u606F
+not.null=* \u5FC5\u987B\u586B\u5199
+user.jcaptcha.error=\u9A8C\u8BC1\u7801\u9519\u8BEF
+user.jcaptcha.expire=\u9A8C\u8BC1\u7801\u5DF2\u5931\u6548
+user.not.exists=\u7528\u6237\u4E0D\u5B58\u5728/\u5BC6\u7801\u9519\u8BEF
+user.password.not.match=\u7528\u6237\u4E0D\u5B58\u5728/\u5BC6\u7801\u9519\u8BEF
+user.password.retry.limit.count=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21
+user.password.retry.limit.exceed=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F
+user.password.delete=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u8D26\u53F7\u5DF2\u88AB\u5220\u9664
+user.blocked=\u7528\u6237\u5DF2\u5C01\u7981\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+role.blocked=\u89D2\u8272\u5DF2\u5C01\u7981\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.logout.success=\u9000\u51FA\u6210\u529F
+
+length.not.valid=\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4
+
+user.username.not.valid=* 2\u523020\u4E2A\u6C49\u5B57\u3001\u5B57\u6BCD\u3001\u6570\u5B57\u6216\u4E0B\u5212\u7EBF\u7EC4\u6210\uFF0C\u4E14\u5FC5\u987B\u4EE5\u975E\u6570\u5B57\u5F00\u5934
+user.password.not.valid=* 5-50\u4E2A\u5B57\u7B26
+
+user.email.not.valid=\u90AE\u7BB1\u683C\u5F0F\u9519\u8BEF
+user.mobile.phone.number.not.valid=\u624B\u673A\u53F7\u683C\u5F0F\u9519\u8BEF
+user.login.success=\u767B\u5F55\u6210\u529F
+user.register.success=\u6CE8\u518C\u6210\u529F
+user.notfound=\u8BF7\u91CD\u65B0\u767B\u5F55
+user.forcelogout=\u7BA1\u7406\u5458\u5F3A\u5236\u9000\u51FA\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
+user.unknown.error=\u672A\u77E5\u9519\u8BEF\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
+
+##\u6743\u9650
+no.permission=\u60A8\u6CA1\u6709\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.create.permission=\u60A8\u6CA1\u6709\u521B\u5EFA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.update.permission=\u60A8\u6CA1\u6709\u4FEE\u6539\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.delete.permission=\u60A8\u6CA1\u6709\u5220\u9664\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.export.permission=\u60A8\u6CA1\u6709\u5BFC\u51FA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.view.permission=\u60A8\u6CA1\u6709\u67E5\u770B\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+
+##\u6587\u4EF6\u4E0A\u4F20\u6D88\u606F
+upload.exceed.maxSize=\u4E0A\u4F20\u7684\u6587\u4EF6\u5927\u5C0F\u8D85\u51FA\u9650\u5236\u7684\u6587\u4EF6\u5927\u5C0F\uFF01
\u5141\u8BB8\u7684\u6587\u4EF6\u6700\u5927\u5927\u5C0F\u662F\uFF1A{0}MB\uFF01
+upload.filename.exceed.length=\u4E0A\u4F20\u7684\u6587\u4EF6\u540D\u6700\u957F{0}\u4E2A\u5B57\u7B26
+upload.success=\u4E0A\u4F20\u6210\u529F
+
+##\u6587\u4EF6\u4E0B\u8F7D\u6D88\u606F
+download.filename.not.valid=\u6587\u4EF6\u540D\u79F0[{}]\u975E\u6CD5\uFF0C\u4E0D\u5141\u8BB8\u4E0B\u8F7D
+download.file.failed=\u4E0B\u8F7D\u6587\u4EF6\u5931\u8D25
+download.resource.not.valid=\u8D44\u6E90\u6587\u4EF6[{}]\u975E\u6CD5\uFF0C\u4E0D\u5141\u8BB8\u4E0B\u8F7D
+
+##Dept
+dept.add.failed.name.exists=\u65B0\u589E\u673A\u6784[{}]\u5931\u8D25\uFF0C\u673A\u6784\u540D\u79F0\u5DF2\u5B58\u5728
+dept.update.failed.name.exists=\u4FEE\u6539\u673A\u6784[{}]\u5931\u8D25\uFF0C\u673A\u6784\u540D\u79F0\u5DF2\u5B58\u5728
+dept.update.failed.parent.not.valid=\u4FEE\u6539\u673A\u6784[{}]\u5931\u8D25\uFF0C\u4E0A\u7EA7\u673A\u6784\u4E0D\u80FD\u662F\u81EA\u5DF1
+dept.update.failed.child.not.valid=\u8BE5\u673A\u6784\u5305\u542B\u672A\u505C\u7528\u7684\u5B50\u673A\u6784\uFF01
+dept.delete.failed.child.exists=\u5B58\u5728\u4E0B\u7EA7\u673A\u6784\uFF0C\u4E0D\u5141\u8BB8\u5220\u9664
+dept.delete.failed.user.exists=\u673A\u6784\u5B58\u5728\u7528\u6237\uFF0C\u4E0D\u5141\u8BB8\u5220\u9664
+
+##Dict
+dict.add.failed.type.exists=\u65B0\u589E\u5B57\u5178[{}]\u5931\u8D25\uFF0C\u5B57\u5178\u7C7B\u578B\u5DF2\u5B58\u5728
+dict.update.failed.type.exists=\u65B0\u589E\u5B57\u5178[{}]\u5931\u8D25\uFF0C\u5B57\u5178\u7C7B\u578B\u5DF2\u5B58\u5728
+
+##Index
+index.welcome.message=\u6B22\u8FCE\u4F7F\u7528{}\u540E\u53F0\u7BA1\u7406\u6846\u67B6\uFF0C\u5F53\u524D\u7248\u672C\uFF1Av{}\uFF0C\u8BF7\u901A\u8FC7\u524D\u7AEF\u5730\u5740\u8BBF\u95EE\u3002
+
+##Menu
+menu.add.failed.name.exists=\u65B0\u589E\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u83DC\u5355\u540D\u79F0\u5DF2\u5B58\u5728
+menu.add.failed.path.not.valid=\u65B0\u589E\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u5730\u5740\u5FC5\u987B\u4EE5http(s)://\u5F00\u5934
+menu.update.failed.name.exists=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u83DC\u5355\u540D\u79F0\u5DF2\u5B58\u5728
+menu.update.failed.path.not.valid=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u5730\u5740\u5FC5\u987B\u4EE5http(s)://\u5F00\u5934
+menu.update.failed.parent.not.valid=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u4E0A\u7EA7\u83DC\u5355\u4E0D\u80FD\u9009\u62E9\u81EA\u5DF1
+menu.delete.failed.child.exists=\u5B58\u5728\u5B50\u83DC\u5355,\u4E0D\u5141\u8BB8\u5220\u9664
+menu.delete.failed.role.exists=\u83DC\u5355\u5DF2\u5206\u914D,\u4E0D\u5141\u8BB8\u5220\u9664
+
+##Post
+post.add.failed.name.exists=\u65B0\u589E\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u540D\u79F0\u5DF2\u5B58\u5728
+post.add.failed.code.exists=\u65B0\u589E\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u7F16\u7801\u5DF2\u5B58\u5728
+post.update.failed.name.exists=\u4FEE\u6539\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u540D\u79F0\u5DF2\u5B58\u5728
+post.update.failed.code.exists=\u4FEE\u6539\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u7F16\u7801\u5DF2\u5B58\u5728
+
+##User
+user.username.exists=\u7CFB\u7EDF\u8D26\u53F7\u540D\u79F0\u5DF2\u5B58\u5728\uFF0C\u8BF7\u4FEE\u6539\u540E\u91CD\u8BD5
+user.password.differ=\u4E24\u6B21\u5BC6\u7801\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165
+user.add.failed.name.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u767B\u5F55\u8D26\u53F7\u5DF2\u5B58\u5728
+user.add.failed.phone.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u624B\u673A\u53F7\u7801\u5DF2\u5B58\u5728
+user.add.failed.email.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u90AE\u7BB1\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed.password.wrong=\u4FEE\u6539\u5BC6\u7801\u5931\u8D25\uFF0C\u65E7\u5BC6\u7801\u9519\u8BEF
+user.update.failed.password.repeat=\u65B0\u5BC6\u7801\u4E0D\u80FD\u4E0E\u65E7\u5BC6\u7801\u76F8\u540C
+user.update.password.failed=\u4FEE\u6539\u5BC6\u7801\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.update.failed.name.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u767B\u5F55\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed.phone.exists=\u4FEE\u6539\u7528\u6237[{}]\u5931\u8D25\uFF0C\u624B\u673A\u53F7\u7801\u5DF2\u5B58\u5728
+user.update.failed.email.exists=\u4FEE\u6539\u7528\u6237[{}]\u5931\u8D25\uFF0C\u90AE\u7BB1\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed=\u4FEE\u6539\u4E2A\u4EBA\u4FE1\u606F\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.delete.failed=\u5F53\u524D\u7528\u6237\u4E0D\u80FD\u5220\u9664
+user.upload.avatar.failed=\u4E0A\u4F20\u56FE\u7247\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.not.login=\u8BF7\u767B\u5F55\u540E\u91CD\u8BD5
+user.access.denied=\u7528\u6237\u62D2\u7EDD\u8BBF\u95EE
+
+##Role
+role.add.manager.failed=\u4E0D\u5141\u8BB8\u8BBE\u7F6E\u7BA1\u7406\u5458\u89D2\u8272\u6807\u8BC6
+role.add.failed.name.exists=\u65B0\u589E\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u540D\u79F0\u5DF2\u5B58\u5728
+role.add.failed.key.exists=\u65B0\u589E\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u6743\u9650\u5DF2\u5B58\u5728
+role.update.failed.name.exists=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u540D\u79F0\u5DF2\u5B58\u5728
+role.update.failed.key.exists=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u6743\u9650\u5DF2\u5B58\u5728
+role.update.failed=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+
+##Import
+import.failed.file.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u8BF7\u5148\u4E0A\u4F20\u6587\u4EF6\uFF01
+import.failed.data.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u5BFC\u5165\u6570\u636E\u4E3A\u7A7A\uFF01
+import.failed.nettyDevice.name.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u6A21\u677F\u91CC\u8BBE\u5907\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A\uFF01
+import.success=\u5BFC\u5165\u6210\u529F
+
+##General
+success=\u6210\u529F
+fail=\u5931\u8D25
+query.success=\u67E5\u8BE2\u6210\u529F
+operate.success=\u64CD\u4F5C\u6210\u529F
+create.success=\u521B\u5EFA\u6210\u529F
+create.failed=\u521B\u5EFA\u5931\u8D25
+save.success=\u4FDD\u5B58\u6210\u529F
+save.failed=\u4FDD\u5B58\u5931\u8D25
+authorization.success=\u6388\u6743\u6210\u529F
+
+##Email
+email.format.error=\u90AE\u7BB1\u683C\u5F0F\u9519\u8BEF
+email.verification.code.send=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u5DF2\u53D1\u9001
+
+##Firmware
+firmware.task.upgrade.failed.time.not.valid=\u9884\u5B9A\u5347\u7EA7\u65F6\u95F4\u5E94\u5927\u4E8E\u5F53\u524D\u65F6\u95F4
+##Media
+media.record.query.failed=\u8FDE\u63A5\u8D85\u65F6\u6216\u53D1\u751F\u9519\u8BEF\uFF0C\u672A\u83B7\u53D6\u5230\u6570\u636E
+##Modbus
+modbus.type.null=\u7C7B\u578B\u4E3A\u7A7A
+##Netty
+netty.client.not.exists=\u5BA2\u6237\u7AEF\u4E0D\u5B58\u5728
+##Runtime
+runtime.message.id.null=\u6D88\u606Fid\u4E3A\u7A7A
+##Wechat
+wechat.verify.type.null=\u8BF7\u4F20\u5165\u9A8C\u8BC1\u65B9\u5F0F
+wechat.bind.message.id.null=\u8BF7\u4F20\u5165\u7ED1\u5B9A\u4FE1\u606FID
+##AuthResource
+auth.resource.product.query.success=\u67E5\u8BE2\u4EA7\u54C1\u5217\u8868\u6210\u529F
+##Device
+nettyDevice.user.id.null=\u7528\u6237ID\u4E0D\u80FD\u4E3A\u7A7A
+nettyDevice.product.id.null=\u8BBE\u5907\u7F16\u53F7\u548C\u4EA7\u54C1ID\u4E0D\u80FD\u4E3A\u7A7A
+nettyDevice.dept.id.null=\u8BF7\u9009\u62E9\u5206\u914D\u673A\u6784
+nettyDevice.id.null=\u8BF7\u9009\u62E9\u8BBE\u5907
+##DeviceJob
+job.add.failed.cron.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0CCron\u8868\u8FBE\u5F0F\u4E0D\u6B63\u786E
+job.add.failed.rmi.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'rmi'\u8C03\u7528
+job.add.failed.ldap.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'ldap(s)'\u8C03\u7528
+job.add.failed.http.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'http(s)'\u8C03\u7528
+job.add.failed.string.error=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u5B58\u5728\u8FDD\u89C4
+job.add.failed.string.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5728\u767D\u540D\u5355\u5185
+job.update.failed.cron.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0CCron\u8868\u8FBE\u5F0F\u4E0D\u6B63\u786E
+job.update.failed.rmi.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'rmi'\u8C03\u7528
+job.update.failed.ldap.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'ldap(s)'\u8C03\u7528
+job.update.failed.http.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'http(s)'\u8C03\u7528
+job.update.failed.string.error=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u5B58\u5728\u8FDD\u89C4
+job.update.failed.string.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5728\u767D\u540D\u5355\u5185
+job.not.exists=\u4EFB\u52A1\u4E0D\u5B58\u5728\u6216\u5DF2\u8FC7\u671F
+##DeviceUser
+nettyDevice.user.delete.failed.user.not.valid=\u8BBE\u5907\u6240\u6709\u8005\u4E0D\u80FD\u5220\u9664
+##GoviewProject
+goview.project.data.save.failed.id.null=\u6CA1\u6709\u8BE5\u9879\u76EEID
+goview.project.data.execute.sql.failed=\u8BF7\u7F16\u5199sql\u8BED\u53E5
+##ThingsModel
+things.model.identifier.repeat=\u4EA7\u54C1\u4E0B\u7684\u6807\u8BC6\u7B26\u4E0D\u80FD\u91CD\u590D
+things.model.import.failed.identifier.repeat=[{}]\u6761\u6570\u636E\u672A\u5BFC\u5165\uFF0C\u6807\u8BC6\u7B26\u91CD\u590D
+##MQTT
+mqtt.unauthorized=mqtt\u8D26\u53F7\u548C\u5BC6\u7801\u4E0E\u8BA4\u8BC1\u670D\u52A1\u5668\u914D\u7F6E\u4E0D\u5339\u914D
+##Oauth
+oauth.response.type.not.valid=response_type\u53C2\u6570\u503C\u53EA\u5141\u8BB8code\u548Ctoken
+oauth.grant.type.null=\u672A\u77E5\u6388\u6743\u7C7B\u578B
+oauth.grant.type.implicit.not.support=Token\u63A5\u53E3\u4E0D\u652F\u6301implicit\u6388\u6743\u6A21\u5F0F
+oauth.access.token.null=\u8BBF\u95EE\u4EE4\u724C\u4E0D\u80FD\u4E3A\u7A7A
+obtain.basic.authorization.failed=client_id\u6216client_secret\u672A\u6B63\u786E\u4F20\u9012
+##Record
+record.app.null=app\u4E0D\u80FD\u4E3A\u7A7A
+record.stream.null=stream\u4E0D\u80FD\u4E3A\u7A7A
+record.time.not.valid=\u9519\u8BEF\u7684\u5F00\u59CB\u65F6\u95F4\u6216\u7ED3\u675F\u65F6\u95F4
+record.file.null=\u672A\u627E\u5230\u89C6\u9891\u6587\u4EF6
+
+##ErrorCodeConstants
+app.not.found=App \u4E0D\u5B58\u5728
+app.is.disable=App \u5DF2\u7ECF\u88AB\u7981\u7528
+app.exist.order.cant.delete=\u652F\u4ED8\u5E94\u7528\u5B58\u5728\u652F\u4ED8\u8BA2\u5355\uFF0C\u65E0\u6CD5\u5220\u9664
+app.exist.refund.cant.delete=\u652F\u4ED8\u5E94\u7528\u5B58\u5728\u9000\u6B3E\u8BA2\u5355\uFF0C\u65E0\u6CD5\u5220\u9664
+channel.not.found=\u652F\u4ED8\u6E20\u9053\u7684\u914D\u7F6E\u4E0D\u5B58\u5728
+channel.is.disable=\u652F\u4ED8\u6E20\u9053\u5DF2\u7ECF\u7981\u7528
+channel.exists.same.channel.error=\u5DF2\u5B58\u5728\u76F8\u540C\u7684\u6E20\u9053
+order.not.found=\u652F\u4ED8\u8BA2\u5355\u4E0D\u5B58\u5728
+order.status.is.not.waiting=\u652F\u4ED8\u8BA2\u5355\u4E0D\u5904\u4E8E\u5F85\u652F\u4ED8
+order.status.is.success=\u8BA2\u5355\u5DF2\u652F\u4ED8\uFF0C\u8BF7\u5237\u65B0\u9875\u9762
+order.is.expired=\u652F\u4ED8\u8BA2\u5355\u5DF2\u7ECF\u8FC7\u671F
+order.submit.channel.error=\u53D1\u8D77\u652F\u4ED8\u62A5\u9519\uFF0C\u9519\u8BEF\u7801\uFF1A{}\uFF0C\u9519\u8BEF\u63D0\u793A\uFF1A{}
+order.refund.fail.status.error=\u652F\u4ED8\u8BA2\u5355\u9000\u6B3E\u5931\u8D25\uFF0C\u539F\u56E0\uFF1A\u72B6\u6001\u4E0D\u662F\u5DF2\u652F\u4ED8\u6216\u5DF2\u9000\u6B3E
+order.extension.not.found=\u652F\u4ED8\u4EA4\u6613\u62D3\u5C55\u5355\u4E0D\u5B58\u5728
+order.extension.status.is.not.waiting=\u652F\u4ED8\u4EA4\u6613\u62D3\u5C55\u5355\u4E0D\u5904\u4E8E\u5F85\u652F\u4ED8
+order.extension.is.paid=\u8BA2\u5355\u5DF2\u652F\u4ED8\uFF0C\u8BF7\u7B49\u5F85\u652F\u4ED8\u7ED3\u679C
+refund.price.exceed=\u9000\u6B3E\u91D1\u989D\u8D85\u8FC7\u8BA2\u5355\u53EF\u9000\u6B3E\u91D1\u989D
+refund.has.refunding=\u5DF2\u7ECF\u6709\u9000\u6B3E\u5728\u5904\u7406\u4E2D
+refund.exists=\u5DF2\u7ECF\u5B58\u5728\u9000\u6B3E\u5355
+refund.not.found=\u652F\u4ED8\u9000\u6B3E\u5355\u4E0D\u5B58\u5728
+refund.statue.is.not.waiting=\u652F\u4ED8\u9000\u6B3E\u5355\u4E0D\u5904\u4E8E\u5F85\u9000\u6B3E
+demo.order.not.found=\u793A\u4F8B\u8BA2\u5355\u4E0D\u5B58\u5728
+demo.order.update.paid.status.not.unpaid=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u8BA2\u5355\u4E0D\u662F\u3010\u672A\u652F\u4ED8\u3011\u72B6\u6001
+demo.order.update.paid.fail.pay.order.id.error=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u7F16\u53F7\u4E0D\u5339\u914D
+demo.order.update.paid.fail.pay.order.status.not.success=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u72B6\u6001\u4E0D\u662F\u3010\u652F\u4ED8\u6210\u529F\u3011\u72B6\u6001
+demo.order.update.paid.fail.pay.price.not.match=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u91D1\u989D\u4E0D\u5339\u914D
+demo.order.refund.fail.not.paid=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u793A\u4F8B\u8BA2\u5355\u672A\u652F\u4ED8
+demo.order.refund.fail.refunded=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u793A\u4F8B\u8BA2\u5355\u5DF2\u9000\u6B3E
+demo.order.refund.fail.refund.not.found=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u8BA2\u5355\u4E0D\u5B58\u5728
+demo.order.refund.fail.refund.not.success=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u8BA2\u5355\u672A\u9000\u6B3E\u6210\u529F
+demo.order.refund.fail.refund.order.id.error=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u5355\u7F16\u53F7\u4E0D\u5339\u914D
+demo.order.refund.fail.refund.price.not.match=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u5355\u91D1\u989D\u4E0D\u5339\u914D
diff --git a/maibu-admin/src/main/resources/i18n/messages_en_US.properties b/maibu-admin/src/main/resources/i18n/messages_en_US.properties
new file mode 100644
index 0000000..eea9a3a
--- /dev/null
+++ b/maibu-admin/src/main/resources/i18n/messages_en_US.properties
@@ -0,0 +1,211 @@
+#\u9519\u8BEF\u6D88\u606F
+not.null=* \u5FC5\u987B\u586B\u5199
+user.jcaptcha.error=\u9A8C\u8BC1\u7801\u9519\u8BEF
+user.jcaptcha.expire=\u9A8C\u8BC1\u7801\u5DF2\u5931\u6548
+user.not.exists=\u7528\u6237\u4E0D\u5B58\u5728/\u5BC6\u7801\u9519\u8BEF
+user.password.not.match=\u7528\u6237\u4E0D\u5B58\u5728/\u5BC6\u7801\u9519\u8BEF
+user.password.retry.limit.count=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21
+user.password.retry.limit.exceed=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F
+user.password.delete=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u8D26\u53F7\u5DF2\u88AB\u5220\u9664
+user.blocked=\u7528\u6237\u5DF2\u5C01\u7981\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+role.blocked=\u89D2\u8272\u5DF2\u5C01\u7981\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.logout.success=\u9000\u51FA\u6210\u529F
+
+length.not.valid=\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4
+
+user.username.not.valid=* 2\u523020\u4E2A\u6C49\u5B57\u3001\u5B57\u6BCD\u3001\u6570\u5B57\u6216\u4E0B\u5212\u7EBF\u7EC4\u6210\uFF0C\u4E14\u5FC5\u987B\u4EE5\u975E\u6570\u5B57\u5F00\u5934
+user.password.not.valid=* 5-50\u4E2A\u5B57\u7B26
+
+user.email.not.valid=\u90AE\u7BB1\u683C\u5F0F\u9519\u8BEF
+user.mobile.phone.number.not.valid=\u624B\u673A\u53F7\u683C\u5F0F\u9519\u8BEF
+user.login.success=\u767B\u5F55\u6210\u529F
+user.register.success=\u6CE8\u518C\u6210\u529F
+user.notfound=\u8BF7\u91CD\u65B0\u767B\u5F55
+user.forcelogout=\u7BA1\u7406\u5458\u5F3A\u5236\u9000\u51FA\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
+user.unknown.error=\u672A\u77E5\u9519\u8BEF\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
+
+##\u6743\u9650
+no.permission=\u60A8\u6CA1\u6709\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.create.permission=\u60A8\u6CA1\u6709\u521B\u5EFA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.update.permission=\u60A8\u6CA1\u6709\u4FEE\u6539\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.delete.permission=\u60A8\u6CA1\u6709\u5220\u9664\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.export.permission=\u60A8\u6CA1\u6709\u5BFC\u51FA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.view.permission=\u60A8\u6CA1\u6709\u67E5\u770B\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+
+##\u6587\u4EF6\u4E0A\u4F20\u6D88\u606F
+upload.exceed.maxSize=\u4E0A\u4F20\u7684\u6587\u4EF6\u5927\u5C0F\u8D85\u51FA\u9650\u5236\u7684\u6587\u4EF6\u5927\u5C0F\uFF01
\u5141\u8BB8\u7684\u6587\u4EF6\u6700\u5927\u5927\u5C0F\u662F\uFF1A{0}MB\uFF01
+upload.filename.exceed.length=\u4E0A\u4F20\u7684\u6587\u4EF6\u540D\u6700\u957F{0}\u4E2A\u5B57\u7B26
+upload.success=\u4E0A\u4F20\u6210\u529F
+
+##\u6587\u4EF6\u4E0B\u8F7D\u6D88\u606F
+download.filename.not.valid=\u6587\u4EF6\u540D\u79F0[{}]\u975E\u6CD5\uFF0C\u4E0D\u5141\u8BB8\u4E0B\u8F7D
+download.file.failed=\u4E0B\u8F7D\u6587\u4EF6\u5931\u8D25
+download.resource.not.valid=\u8D44\u6E90\u6587\u4EF6[{}]\u975E\u6CD5\uFF0C\u4E0D\u5141\u8BB8\u4E0B\u8F7D
+
+##Dept
+dept.add.failed.name.exists=\u65B0\u589E\u673A\u6784[{}]\u5931\u8D25\uFF0C\u673A\u6784\u540D\u79F0\u5DF2\u5B58\u5728
+dept.update.failed.name.exists=\u4FEE\u6539\u673A\u6784[{}]\u5931\u8D25\uFF0C\u673A\u6784\u540D\u79F0\u5DF2\u5B58\u5728
+dept.update.failed.parent.not.valid=\u4FEE\u6539\u673A\u6784[{}]\u5931\u8D25\uFF0C\u4E0A\u7EA7\u673A\u6784\u4E0D\u80FD\u662F\u81EA\u5DF1
+dept.update.failed.child.not.valid=\u8BE5\u673A\u6784\u5305\u542B\u672A\u505C\u7528\u7684\u5B50\u673A\u6784\uFF01
+dept.delete.failed.child.exists=\u5B58\u5728\u4E0B\u7EA7\u673A\u6784\uFF0C\u4E0D\u5141\u8BB8\u5220\u9664
+dept.delete.failed.user.exists=\u673A\u6784\u5B58\u5728\u7528\u6237\uFF0C\u4E0D\u5141\u8BB8\u5220\u9664
+
+##Dict
+dict.add.failed.type.exists=\u65B0\u589E\u5B57\u5178[{}]\u5931\u8D25\uFF0C\u5B57\u5178\u7C7B\u578B\u5DF2\u5B58\u5728
+dict.update.failed.type.exists=\u65B0\u589E\u5B57\u5178[{}]\u5931\u8D25\uFF0C\u5B57\u5178\u7C7B\u578B\u5DF2\u5B58\u5728
+
+##Index
+index.welcome.message=\u6B22\u8FCE\u4F7F\u7528{}\u540E\u53F0\u7BA1\u7406\u6846\u67B6\uFF0C\u5F53\u524D\u7248\u672C\uFF1Av{}\uFF0C\u8BF7\u901A\u8FC7\u524D\u7AEF\u5730\u5740\u8BBF\u95EE\u3002
+
+##Menu
+menu.add.failed.name.exists=\u65B0\u589E\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u83DC\u5355\u540D\u79F0\u5DF2\u5B58\u5728
+menu.add.failed.path.not.valid=\u65B0\u589E\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u5730\u5740\u5FC5\u987B\u4EE5http(s)://\u5F00\u5934
+menu.update.failed.name.exists=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u83DC\u5355\u540D\u79F0\u5DF2\u5B58\u5728
+menu.update.failed.path.not.valid=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u5730\u5740\u5FC5\u987B\u4EE5http(s)://\u5F00\u5934
+menu.update.failed.parent.not.valid=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u4E0A\u7EA7\u83DC\u5355\u4E0D\u80FD\u9009\u62E9\u81EA\u5DF1
+menu.delete.failed.child.exists=\u5B58\u5728\u5B50\u83DC\u5355,\u4E0D\u5141\u8BB8\u5220\u9664
+menu.delete.failed.role.exists=\u83DC\u5355\u5DF2\u5206\u914D,\u4E0D\u5141\u8BB8\u5220\u9664
+
+##Post
+post.add.failed.name.exists=\u65B0\u589E\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u540D\u79F0\u5DF2\u5B58\u5728
+post.add.failed.code.exists=\u65B0\u589E\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u7F16\u7801\u5DF2\u5B58\u5728
+post.update.failed.name.exists=\u4FEE\u6539\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u540D\u79F0\u5DF2\u5B58\u5728
+post.update.failed.code.exists=\u4FEE\u6539\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u7F16\u7801\u5DF2\u5B58\u5728
+
+##User
+user.username.exists=\u7CFB\u7EDF\u8D26\u53F7\u540D\u79F0\u5DF2\u5B58\u5728\uFF0C\u8BF7\u4FEE\u6539\u540E\u91CD\u8BD5
+user.password.differ=\u4E24\u6B21\u5BC6\u7801\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165
+user.add.failed.name.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u767B\u5F55\u8D26\u53F7\u5DF2\u5B58\u5728
+user.add.failed.phone.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u624B\u673A\u53F7\u7801\u5DF2\u5B58\u5728
+user.add.failed.email.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u90AE\u7BB1\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed.password.wrong=\u4FEE\u6539\u5BC6\u7801\u5931\u8D25\uFF0C\u65E7\u5BC6\u7801\u9519\u8BEF
+user.update.failed.password.repeat=\u65B0\u5BC6\u7801\u4E0D\u80FD\u4E0E\u65E7\u5BC6\u7801\u76F8\u540C
+user.update.password.failed=\u4FEE\u6539\u5BC6\u7801\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.update.failed.name.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u767B\u5F55\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed.phone.exists=\u4FEE\u6539\u7528\u6237[{}]\u5931\u8D25\uFF0C\u624B\u673A\u53F7\u7801\u5DF2\u5B58\u5728
+user.update.failed.email.exists=\u4FEE\u6539\u7528\u6237[{}]\u5931\u8D25\uFF0C\u90AE\u7BB1\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed=\u4FEE\u6539\u4E2A\u4EBA\u4FE1\u606F\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.delete.failed=\u5F53\u524D\u7528\u6237\u4E0D\u80FD\u5220\u9664
+user.upload.avatar.failed=\u4E0A\u4F20\u56FE\u7247\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.not.login=\u8BF7\u767B\u5F55\u540E\u91CD\u8BD5
+user.access.denied=\u7528\u6237\u62D2\u7EDD\u8BBF\u95EE
+
+##Role
+role.add.manager.failed=\u4E0D\u5141\u8BB8\u8BBE\u7F6E\u7BA1\u7406\u5458\u89D2\u8272\u6807\u8BC6
+role.add.failed.name.exists=\u65B0\u589E\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u540D\u79F0\u5DF2\u5B58\u5728
+role.add.failed.key.exists=\u65B0\u589E\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u6743\u9650\u5DF2\u5B58\u5728
+role.update.failed.name.exists=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u540D\u79F0\u5DF2\u5B58\u5728
+role.update.failed.key.exists=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u6743\u9650\u5DF2\u5B58\u5728
+role.update.failed=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+
+##Import
+import.failed.file.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u8BF7\u5148\u4E0A\u4F20\u6587\u4EF6\uFF01
+import.failed.data.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u5BFC\u5165\u6570\u636E\u4E3A\u7A7A\uFF01
+import.failed.nettyDevice.name.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u6A21\u677F\u91CC\u8BBE\u5907\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A\uFF01
+import.success=\u5BFC\u5165\u6210\u529F
+
+##General
+success=\u6210\u529F
+fail=\u5931\u8D25
+query.success=\u67E5\u8BE2\u6210\u529F
+operate.success=\u64CD\u4F5C\u6210\u529F
+create.success=\u521B\u5EFA\u6210\u529F
+create.failed=\u521B\u5EFA\u5931\u8D25
+save.success=\u4FDD\u5B58\u6210\u529F
+save.failed=\u4FDD\u5B58\u5931\u8D25
+authorization.success=\u6388\u6743\u6210\u529F
+
+##Email
+email.format.error=\u90AE\u7BB1\u683C\u5F0F\u9519\u8BEF
+email.verification.code.send=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u5DF2\u53D1\u9001
+
+##Firmware
+firmware.task.upgrade.failed.time.not.valid=\u9884\u5B9A\u5347\u7EA7\u65F6\u95F4\u5E94\u5927\u4E8E\u5F53\u524D\u65F6\u95F4
+##Media
+media.record.query.failed=\u8FDE\u63A5\u8D85\u65F6\u6216\u53D1\u751F\u9519\u8BEF\uFF0C\u672A\u83B7\u53D6\u5230\u6570\u636E
+##Modbus
+modbus.type.null=\u7C7B\u578B\u4E3A\u7A7A
+##Netty
+netty.client.not.exists=\u5BA2\u6237\u7AEF\u4E0D\u5B58\u5728
+##Runtime
+runtime.message.id.null=\u6D88\u606Fid\u4E3A\u7A7A
+##Wechat
+wechat.verify.type.null=\u8BF7\u4F20\u5165\u9A8C\u8BC1\u65B9\u5F0F
+wechat.bind.message.id.null=\u8BF7\u4F20\u5165\u7ED1\u5B9A\u4FE1\u606FID
+##AuthResource
+auth.resource.product.query.success=\u67E5\u8BE2\u4EA7\u54C1\u5217\u8868\u6210\u529F
+##Device
+nettyDevice.user.id.null=\u7528\u6237ID\u4E0D\u80FD\u4E3A\u7A7A
+nettyDevice.product.id.null=\u8BBE\u5907\u7F16\u53F7\u548C\u4EA7\u54C1ID\u4E0D\u80FD\u4E3A\u7A7A
+nettyDevice.dept.id.null=\u8BF7\u9009\u62E9\u5206\u914D\u673A\u6784
+nettyDevice.id.null=\u8BF7\u9009\u62E9\u8BBE\u5907
+##DeviceJob
+job.add.failed.cron.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0CCron\u8868\u8FBE\u5F0F\u4E0D\u6B63\u786E
+job.add.failed.rmi.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'rmi'\u8C03\u7528
+job.add.failed.ldap.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'ldap(s)'\u8C03\u7528
+job.add.failed.http.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'http(s)'\u8C03\u7528
+job.add.failed.string.error=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u5B58\u5728\u8FDD\u89C4
+job.add.failed.string.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5728\u767D\u540D\u5355\u5185
+job.update.failed.cron.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0CCron\u8868\u8FBE\u5F0F\u4E0D\u6B63\u786E
+job.update.failed.rmi.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'rmi'\u8C03\u7528
+job.update.failed.ldap.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'ldap(s)'\u8C03\u7528
+job.update.failed.http.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'http(s)'\u8C03\u7528
+job.update.failed.string.error=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u5B58\u5728\u8FDD\u89C4
+job.update.failed.string.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5728\u767D\u540D\u5355\u5185
+job.not.exists=\u4EFB\u52A1\u4E0D\u5B58\u5728\u6216\u5DF2\u8FC7\u671F
+##DeviceUser
+nettyDevice.user.delete.failed.user.not.valid=\u8BBE\u5907\u6240\u6709\u8005\u4E0D\u80FD\u5220\u9664
+##GoviewProject
+goview.project.data.save.failed.id.null=\u6CA1\u6709\u8BE5\u9879\u76EEID
+goview.project.data.execute.sql.failed=\u8BF7\u7F16\u5199sql\u8BED\u53E5
+##ThingsModel
+things.model.identifier.repeat=\u4EA7\u54C1\u4E0B\u7684\u6807\u8BC6\u7B26\u4E0D\u80FD\u91CD\u590D
+things.model.import.failed.identifier.repeat=[{}]\u6761\u6570\u636E\u672A\u5BFC\u5165\uFF0C\u6807\u8BC6\u7B26\u91CD\u590D
+##MQTT
+mqtt.unauthorized=mqtt\u8D26\u53F7\u548C\u5BC6\u7801\u4E0E\u8BA4\u8BC1\u670D\u52A1\u5668\u914D\u7F6E\u4E0D\u5339\u914D
+##Oauth
+oauth.response.type.not.valid=response_type\u53C2\u6570\u503C\u53EA\u5141\u8BB8code\u548Ctoken
+oauth.grant.type.null=\u672A\u77E5\u6388\u6743\u7C7B\u578B
+oauth.grant.type.implicit.not.support=Token\u63A5\u53E3\u4E0D\u652F\u6301implicit\u6388\u6743\u6A21\u5F0F
+oauth.access.token.null=\u8BBF\u95EE\u4EE4\u724C\u4E0D\u80FD\u4E3A\u7A7A
+obtain.basic.authorization.failed=client_id\u6216client_secret\u672A\u6B63\u786E\u4F20\u9012
+##Record
+record.app.null=app\u4E0D\u80FD\u4E3A\u7A7A
+record.stream.null=stream\u4E0D\u80FD\u4E3A\u7A7A
+record.time.not.valid=\u9519\u8BEF\u7684\u5F00\u59CB\u65F6\u95F4\u6216\u7ED3\u675F\u65F6\u95F4
+record.file.null=\u672A\u627E\u5230\u89C6\u9891\u6587\u4EF6
+
+##ErrorCodeConstants
+app.not.found=App \u4E0D\u5B58\u5728
+app.is.disable=App \u5DF2\u7ECF\u88AB\u7981\u7528
+app.exist.order.cant.delete=\u652F\u4ED8\u5E94\u7528\u5B58\u5728\u652F\u4ED8\u8BA2\u5355\uFF0C\u65E0\u6CD5\u5220\u9664
+app.exist.refund.cant.delete=\u652F\u4ED8\u5E94\u7528\u5B58\u5728\u9000\u6B3E\u8BA2\u5355\uFF0C\u65E0\u6CD5\u5220\u9664
+channel.not.found=\u652F\u4ED8\u6E20\u9053\u7684\u914D\u7F6E\u4E0D\u5B58\u5728
+channel.is.disable=\u652F\u4ED8\u6E20\u9053\u5DF2\u7ECF\u7981\u7528
+channel.exists.same.channel.error=\u5DF2\u5B58\u5728\u76F8\u540C\u7684\u6E20\u9053
+order.not.found=\u652F\u4ED8\u8BA2\u5355\u4E0D\u5B58\u5728
+order.status.is.not.waiting=\u652F\u4ED8\u8BA2\u5355\u4E0D\u5904\u4E8E\u5F85\u652F\u4ED8
+order.status.is.success=\u8BA2\u5355\u5DF2\u652F\u4ED8\uFF0C\u8BF7\u5237\u65B0\u9875\u9762
+order.is.expired=\u652F\u4ED8\u8BA2\u5355\u5DF2\u7ECF\u8FC7\u671F
+order.submit.channel.error=\u53D1\u8D77\u652F\u4ED8\u62A5\u9519\uFF0C\u9519\u8BEF\u7801\uFF1A{}\uFF0C\u9519\u8BEF\u63D0\u793A\uFF1A{}
+order.refund.fail.status.error=\u652F\u4ED8\u8BA2\u5355\u9000\u6B3E\u5931\u8D25\uFF0C\u539F\u56E0\uFF1A\u72B6\u6001\u4E0D\u662F\u5DF2\u652F\u4ED8\u6216\u5DF2\u9000\u6B3E
+order.extension.not.found=\u652F\u4ED8\u4EA4\u6613\u62D3\u5C55\u5355\u4E0D\u5B58\u5728
+order.extension.status.is.not.waiting=\u652F\u4ED8\u4EA4\u6613\u62D3\u5C55\u5355\u4E0D\u5904\u4E8E\u5F85\u652F\u4ED8
+order.extension.is.paid=\u8BA2\u5355\u5DF2\u652F\u4ED8\uFF0C\u8BF7\u7B49\u5F85\u652F\u4ED8\u7ED3\u679C
+refund.price.exceed=\u9000\u6B3E\u91D1\u989D\u8D85\u8FC7\u8BA2\u5355\u53EF\u9000\u6B3E\u91D1\u989D
+refund.has.refunding=\u5DF2\u7ECF\u6709\u9000\u6B3E\u5728\u5904\u7406\u4E2D
+refund.exists=\u5DF2\u7ECF\u5B58\u5728\u9000\u6B3E\u5355
+refund.not.found=\u652F\u4ED8\u9000\u6B3E\u5355\u4E0D\u5B58\u5728
+refund.statue.is.not.waiting=\u652F\u4ED8\u9000\u6B3E\u5355\u4E0D\u5904\u4E8E\u5F85\u9000\u6B3E
+demo.order.not.found=\u793A\u4F8B\u8BA2\u5355\u4E0D\u5B58\u5728
+demo.order.update.paid.status.not.unpaid=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u8BA2\u5355\u4E0D\u662F\u3010\u672A\u652F\u4ED8\u3011\u72B6\u6001
+demo.order.update.paid.fail.pay.order.id.error=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u7F16\u53F7\u4E0D\u5339\u914D
+demo.order.update.paid.fail.pay.order.status.not.success=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u72B6\u6001\u4E0D\u662F\u3010\u652F\u4ED8\u6210\u529F\u3011\u72B6\u6001
+demo.order.update.paid.fail.pay.price.not.match=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u91D1\u989D\u4E0D\u5339\u914D
+demo.order.refund.fail.not.paid=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u793A\u4F8B\u8BA2\u5355\u672A\u652F\u4ED8
+demo.order.refund.fail.refunded=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u793A\u4F8B\u8BA2\u5355\u5DF2\u9000\u6B3E
+demo.order.refund.fail.refund.not.found=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u8BA2\u5355\u4E0D\u5B58\u5728
+demo.order.refund.fail.refund.not.success=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u8BA2\u5355\u672A\u9000\u6B3E\u6210\u529F
+demo.order.refund.fail.refund.order.id.error=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u5355\u7F16\u53F7\u4E0D\u5339\u914D
+demo.order.refund.fail.refund.price.not.match=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u5355\u91D1\u989D\u4E0D\u5339\u914D
+nettyDevice.can.send=No permission operation at present
diff --git a/maibu-admin/src/main/resources/i18n/messages_zh_CN.properties b/maibu-admin/src/main/resources/i18n/messages_zh_CN.properties
new file mode 100644
index 0000000..3d1f15d
--- /dev/null
+++ b/maibu-admin/src/main/resources/i18n/messages_zh_CN.properties
@@ -0,0 +1,211 @@
+#\u9519\u8BEF\u6D88\u606F
+not.null=* \u5FC5\u987B\u586B\u5199
+user.jcaptcha.error=\u9A8C\u8BC1\u7801\u9519\u8BEF
+user.jcaptcha.expire=\u9A8C\u8BC1\u7801\u5DF2\u5931\u6548
+user.not.exists=\u7528\u6237\u4E0D\u5B58\u5728/\u5BC6\u7801\u9519\u8BEF
+user.password.not.match=\u7528\u6237\u4E0D\u5B58\u5728/\u5BC6\u7801\u9519\u8BEF
+user.password.retry.limit.count=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21
+user.password.retry.limit.exceed=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F
+user.password.delete=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u8D26\u53F7\u5DF2\u88AB\u5220\u9664
+user.blocked=\u7528\u6237\u5DF2\u5C01\u7981\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+role.blocked=\u89D2\u8272\u5DF2\u5C01\u7981\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.logout.success=\u9000\u51FA\u6210\u529F
+
+length.not.valid=\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4
+
+user.username.not.valid=* 2\u523020\u4E2A\u6C49\u5B57\u3001\u5B57\u6BCD\u3001\u6570\u5B57\u6216\u4E0B\u5212\u7EBF\u7EC4\u6210\uFF0C\u4E14\u5FC5\u987B\u4EE5\u975E\u6570\u5B57\u5F00\u5934
+user.password.not.valid=* 5-50\u4E2A\u5B57\u7B26
+
+user.email.not.valid=\u90AE\u7BB1\u683C\u5F0F\u9519\u8BEF
+user.mobile.phone.number.not.valid=\u624B\u673A\u53F7\u683C\u5F0F\u9519\u8BEF
+user.login.success=\u767B\u5F55\u6210\u529F
+user.register.success=\u6CE8\u518C\u6210\u529F
+user.notfound=\u8BF7\u91CD\u65B0\u767B\u5F55
+user.forcelogout=\u7BA1\u7406\u5458\u5F3A\u5236\u9000\u51FA\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
+user.unknown.error=\u672A\u77E5\u9519\u8BEF\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
+
+##\u6743\u9650
+no.permission=\u60A8\u6CA1\u6709\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.create.permission=\u60A8\u6CA1\u6709\u521B\u5EFA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.update.permission=\u60A8\u6CA1\u6709\u4FEE\u6539\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.delete.permission=\u60A8\u6CA1\u6709\u5220\u9664\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.export.permission=\u60A8\u6CA1\u6709\u5BFC\u51FA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.view.permission=\u60A8\u6CA1\u6709\u67E5\u770B\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+
+##\u6587\u4EF6\u4E0A\u4F20\u6D88\u606F
+upload.exceed.maxSize=\u4E0A\u4F20\u7684\u6587\u4EF6\u5927\u5C0F\u8D85\u51FA\u9650\u5236\u7684\u6587\u4EF6\u5927\u5C0F\uFF01
\u5141\u8BB8\u7684\u6587\u4EF6\u6700\u5927\u5927\u5C0F\u662F\uFF1A{0}MB\uFF01
+upload.filename.exceed.length=\u4E0A\u4F20\u7684\u6587\u4EF6\u540D\u6700\u957F{0}\u4E2A\u5B57\u7B26
+upload.success=\u4E0A\u4F20\u6210\u529F
+
+##\u6587\u4EF6\u4E0B\u8F7D\u6D88\u606F
+download.filename.not.valid=\u6587\u4EF6\u540D\u79F0[{}]\u975E\u6CD5\uFF0C\u4E0D\u5141\u8BB8\u4E0B\u8F7D
+download.file.failed=\u4E0B\u8F7D\u6587\u4EF6\u5931\u8D25
+download.resource.not.valid=\u8D44\u6E90\u6587\u4EF6[{}]\u975E\u6CD5\uFF0C\u4E0D\u5141\u8BB8\u4E0B\u8F7D
+
+##Dept
+dept.add.failed.name.exists=\u65B0\u589E\u673A\u6784[{}]\u5931\u8D25\uFF0C\u673A\u6784\u540D\u79F0\u5DF2\u5B58\u5728
+dept.update.failed.name.exists=\u4FEE\u6539\u673A\u6784[{}]\u5931\u8D25\uFF0C\u673A\u6784\u540D\u79F0\u5DF2\u5B58\u5728
+dept.update.failed.parent.not.valid=\u4FEE\u6539\u673A\u6784[{}]\u5931\u8D25\uFF0C\u4E0A\u7EA7\u673A\u6784\u4E0D\u80FD\u662F\u81EA\u5DF1
+dept.update.failed.child.not.valid=\u8BE5\u673A\u6784\u5305\u542B\u672A\u505C\u7528\u7684\u5B50\u673A\u6784\uFF01
+dept.delete.failed.child.exists=\u5B58\u5728\u4E0B\u7EA7\u673A\u6784\uFF0C\u4E0D\u5141\u8BB8\u5220\u9664
+dept.delete.failed.user.exists=\u673A\u6784\u5B58\u5728\u7528\u6237\uFF0C\u4E0D\u5141\u8BB8\u5220\u9664
+
+##Dict
+dict.add.failed.type.exists=\u65B0\u589E\u5B57\u5178[{}]\u5931\u8D25\uFF0C\u5B57\u5178\u7C7B\u578B\u5DF2\u5B58\u5728
+dict.update.failed.type.exists=\u65B0\u589E\u5B57\u5178[{}]\u5931\u8D25\uFF0C\u5B57\u5178\u7C7B\u578B\u5DF2\u5B58\u5728
+
+##Index
+index.welcome.message=\u6B22\u8FCE\u4F7F\u7528{}\u540E\u53F0\u7BA1\u7406\u6846\u67B6\uFF0C\u5F53\u524D\u7248\u672C\uFF1Av{}\uFF0C\u8BF7\u901A\u8FC7\u524D\u7AEF\u5730\u5740\u8BBF\u95EE\u3002
+
+##Menu
+menu.add.failed.name.exists=\u65B0\u589E\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u83DC\u5355\u540D\u79F0\u5DF2\u5B58\u5728
+menu.add.failed.path.not.valid=\u65B0\u589E\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u5730\u5740\u5FC5\u987B\u4EE5http(s)://\u5F00\u5934
+menu.update.failed.name.exists=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u83DC\u5355\u540D\u79F0\u5DF2\u5B58\u5728
+menu.update.failed.path.not.valid=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u5730\u5740\u5FC5\u987B\u4EE5http(s)://\u5F00\u5934
+menu.update.failed.parent.not.valid=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u4E0A\u7EA7\u83DC\u5355\u4E0D\u80FD\u9009\u62E9\u81EA\u5DF1
+menu.delete.failed.child.exists=\u5B58\u5728\u5B50\u83DC\u5355,\u4E0D\u5141\u8BB8\u5220\u9664
+menu.delete.failed.role.exists=\u83DC\u5355\u5DF2\u5206\u914D,\u4E0D\u5141\u8BB8\u5220\u9664
+
+##Post
+post.add.failed.name.exists=\u65B0\u589E\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u540D\u79F0\u5DF2\u5B58\u5728
+post.add.failed.code.exists=\u65B0\u589E\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u7F16\u7801\u5DF2\u5B58\u5728
+post.update.failed.name.exists=\u4FEE\u6539\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u540D\u79F0\u5DF2\u5B58\u5728
+post.update.failed.code.exists=\u4FEE\u6539\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u7F16\u7801\u5DF2\u5B58\u5728
+
+##User
+user.username.exists=\u7CFB\u7EDF\u8D26\u53F7\u540D\u79F0\u5DF2\u5B58\u5728\uFF0C\u8BF7\u4FEE\u6539\u540E\u91CD\u8BD5
+user.password.differ=\u4E24\u6B21\u5BC6\u7801\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165
+user.add.failed.name.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u767B\u5F55\u8D26\u53F7\u5DF2\u5B58\u5728
+user.add.failed.phone.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u624B\u673A\u53F7\u7801\u5DF2\u5B58\u5728
+user.add.failed.email.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u90AE\u7BB1\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed.password.wrong=\u4FEE\u6539\u5BC6\u7801\u5931\u8D25\uFF0C\u65E7\u5BC6\u7801\u9519\u8BEF
+user.update.failed.password.repeat=\u65B0\u5BC6\u7801\u4E0D\u80FD\u4E0E\u65E7\u5BC6\u7801\u76F8\u540C
+user.update.password.failed=\u4FEE\u6539\u5BC6\u7801\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.update.failed.name.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u767B\u5F55\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed.phone.exists=\u4FEE\u6539\u7528\u6237[{}]\u5931\u8D25\uFF0C\u624B\u673A\u53F7\u7801\u5DF2\u5B58\u5728
+user.update.failed.email.exists=\u4FEE\u6539\u7528\u6237[{}]\u5931\u8D25\uFF0C\u90AE\u7BB1\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed=\u4FEE\u6539\u4E2A\u4EBA\u4FE1\u606F\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.delete.failed=\u5F53\u524D\u7528\u6237\u4E0D\u80FD\u5220\u9664
+user.upload.avatar.failed=\u4E0A\u4F20\u56FE\u7247\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.not.login=\u8BF7\u767B\u5F55\u540E\u91CD\u8BD5
+user.access.denied=\u7528\u6237\u62D2\u7EDD\u8BBF\u95EE
+
+##Role
+role.add.manager.failed=\u4E0D\u5141\u8BB8\u8BBE\u7F6E\u7BA1\u7406\u5458\u89D2\u8272\u6807\u8BC6
+role.add.failed.name.exists=\u65B0\u589E\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u540D\u79F0\u5DF2\u5B58\u5728
+role.add.failed.key.exists=\u65B0\u589E\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u6743\u9650\u5DF2\u5B58\u5728
+role.update.failed.name.exists=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u540D\u79F0\u5DF2\u5B58\u5728
+role.update.failed.key.exists=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u6743\u9650\u5DF2\u5B58\u5728
+role.update.failed=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+
+##Import
+import.failed.file.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u8BF7\u5148\u4E0A\u4F20\u6587\u4EF6\uFF01
+import.failed.data.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u5BFC\u5165\u6570\u636E\u4E3A\u7A7A\uFF01
+import.failed.nettyDevice.name.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u6A21\u677F\u91CC\u8BBE\u5907\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A\uFF01
+import.success=\u5BFC\u5165\u6210\u529F
+
+##General
+success=\u6210\u529F
+fail=\u5931\u8D25
+query.success=\u67E5\u8BE2\u6210\u529F
+operate.success=\u64CD\u4F5C\u6210\u529F
+create.success=\u521B\u5EFA\u6210\u529F
+create.failed=\u521B\u5EFA\u5931\u8D25
+save.success=\u4FDD\u5B58\u6210\u529F
+save.failed=\u4FDD\u5B58\u5931\u8D25
+authorization.success=\u6388\u6743\u6210\u529F
+
+##Email
+email.format.error=\u90AE\u7BB1\u683C\u5F0F\u9519\u8BEF
+email.verification.code.send=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u5DF2\u53D1\u9001
+
+##Firmware
+firmware.task.upgrade.failed.time.not.valid=\u9884\u5B9A\u5347\u7EA7\u65F6\u95F4\u5E94\u5927\u4E8E\u5F53\u524D\u65F6\u95F4
+##Media
+media.record.query.failed=\u8FDE\u63A5\u8D85\u65F6\u6216\u53D1\u751F\u9519\u8BEF\uFF0C\u672A\u83B7\u53D6\u5230\u6570\u636E
+##Modbus
+modbus.type.null=\u7C7B\u578B\u4E3A\u7A7A
+##Netty
+netty.client.not.exists=\u5BA2\u6237\u7AEF\u4E0D\u5B58\u5728
+##Runtime
+runtime.message.id.null=\u6D88\u606Fid\u4E3A\u7A7A
+##Wechat
+wechat.verify.type.null=\u8BF7\u4F20\u5165\u9A8C\u8BC1\u65B9\u5F0F
+wechat.bind.message.id.null=\u8BF7\u4F20\u5165\u7ED1\u5B9A\u4FE1\u606FID
+##AuthResource
+auth.resource.product.query.success=\u67E5\u8BE2\u4EA7\u54C1\u5217\u8868\u6210\u529F
+##Device
+nettyDevice.user.id.null=\u7528\u6237ID\u4E0D\u80FD\u4E3A\u7A7A
+nettyDevice.product.id.null=\u8BBE\u5907\u7F16\u53F7\u548C\u4EA7\u54C1ID\u4E0D\u80FD\u4E3A\u7A7A
+nettyDevice.dept.id.null=\u8BF7\u9009\u62E9\u5206\u914D\u673A\u6784
+nettyDevice.id.null=\u8BF7\u9009\u62E9\u8BBE\u5907
+##DeviceJob
+job.add.failed.cron.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0CCron\u8868\u8FBE\u5F0F\u4E0D\u6B63\u786E
+job.add.failed.rmi.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'rmi'\u8C03\u7528
+job.add.failed.ldap.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'ldap(s)'\u8C03\u7528
+job.add.failed.http.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'http(s)'\u8C03\u7528
+job.add.failed.string.error=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u5B58\u5728\u8FDD\u89C4
+job.add.failed.string.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5728\u767D\u540D\u5355\u5185
+job.update.failed.cron.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0CCron\u8868\u8FBE\u5F0F\u4E0D\u6B63\u786E
+job.update.failed.rmi.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'rmi'\u8C03\u7528
+job.update.failed.ldap.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'ldap(s)'\u8C03\u7528
+job.update.failed.http.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'http(s)'\u8C03\u7528
+job.update.failed.string.error=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u5B58\u5728\u8FDD\u89C4
+job.update.failed.string.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5728\u767D\u540D\u5355\u5185
+job.not.exists=\u4EFB\u52A1\u4E0D\u5B58\u5728\u6216\u5DF2\u8FC7\u671F
+##DeviceUser
+nettyDevice.user.delete.failed.user.not.valid=\u8BBE\u5907\u6240\u6709\u8005\u4E0D\u80FD\u5220\u9664
+##GoviewProject
+goview.project.data.save.failed.id.null=\u6CA1\u6709\u8BE5\u9879\u76EEID
+goview.project.data.execute.sql.failed=\u8BF7\u7F16\u5199sql\u8BED\u53E5
+##ThingsModel
+things.model.identifier.repeat=\u4EA7\u54C1\u4E0B\u7684\u6807\u8BC6\u7B26\u4E0D\u80FD\u91CD\u590D
+things.model.import.failed.identifier.repeat=[{}]\u6761\u6570\u636E\u672A\u5BFC\u5165\uFF0C\u6807\u8BC6\u7B26\u91CD\u590D
+##MQTT
+mqtt.unauthorized=mqtt\u8D26\u53F7\u548C\u5BC6\u7801\u4E0E\u8BA4\u8BC1\u670D\u52A1\u5668\u914D\u7F6E\u4E0D\u5339\u914D
+##Oauth
+oauth.response.type.not.valid=response_type\u53C2\u6570\u503C\u53EA\u5141\u8BB8code\u548Ctoken
+oauth.grant.type.null=\u672A\u77E5\u6388\u6743\u7C7B\u578B
+oauth.grant.type.implicit.not.support=Token\u63A5\u53E3\u4E0D\u652F\u6301implicit\u6388\u6743\u6A21\u5F0F
+oauth.access.token.null=\u8BBF\u95EE\u4EE4\u724C\u4E0D\u80FD\u4E3A\u7A7A
+obtain.basic.authorization.failed=client_id\u6216client_secret\u672A\u6B63\u786E\u4F20\u9012
+##Record
+record.app.null=app\u4E0D\u80FD\u4E3A\u7A7A
+record.stream.null=stream\u4E0D\u80FD\u4E3A\u7A7A
+record.time.not.valid=\u9519\u8BEF\u7684\u5F00\u59CB\u65F6\u95F4\u6216\u7ED3\u675F\u65F6\u95F4
+record.file.null=\u672A\u627E\u5230\u89C6\u9891\u6587\u4EF6
+
+##ErrorCodeConstants
+app.not.found=App \u4E0D\u5B58\u5728
+app.is.disable=App \u5DF2\u7ECF\u88AB\u7981\u7528
+app.exist.order.cant.delete=\u652F\u4ED8\u5E94\u7528\u5B58\u5728\u652F\u4ED8\u8BA2\u5355\uFF0C\u65E0\u6CD5\u5220\u9664
+app.exist.refund.cant.delete=\u652F\u4ED8\u5E94\u7528\u5B58\u5728\u9000\u6B3E\u8BA2\u5355\uFF0C\u65E0\u6CD5\u5220\u9664
+channel.not.found=\u652F\u4ED8\u6E20\u9053\u7684\u914D\u7F6E\u4E0D\u5B58\u5728
+channel.is.disable=\u652F\u4ED8\u6E20\u9053\u5DF2\u7ECF\u7981\u7528
+channel.exists.same.channel.error=\u5DF2\u5B58\u5728\u76F8\u540C\u7684\u6E20\u9053
+order.not.found=\u652F\u4ED8\u8BA2\u5355\u4E0D\u5B58\u5728
+order.status.is.not.waiting=\u652F\u4ED8\u8BA2\u5355\u4E0D\u5904\u4E8E\u5F85\u652F\u4ED8
+order.status.is.success=\u8BA2\u5355\u5DF2\u652F\u4ED8\uFF0C\u8BF7\u5237\u65B0\u9875\u9762
+order.is.expired=\u652F\u4ED8\u8BA2\u5355\u5DF2\u7ECF\u8FC7\u671F
+order.submit.channel.error=\u53D1\u8D77\u652F\u4ED8\u62A5\u9519\uFF0C\u9519\u8BEF\u7801\uFF1A{}\uFF0C\u9519\u8BEF\u63D0\u793A\uFF1A{}
+order.refund.fail.status.error=\u652F\u4ED8\u8BA2\u5355\u9000\u6B3E\u5931\u8D25\uFF0C\u539F\u56E0\uFF1A\u72B6\u6001\u4E0D\u662F\u5DF2\u652F\u4ED8\u6216\u5DF2\u9000\u6B3E
+order.extension.not.found=\u652F\u4ED8\u4EA4\u6613\u62D3\u5C55\u5355\u4E0D\u5B58\u5728
+order.extension.status.is.not.waiting=\u652F\u4ED8\u4EA4\u6613\u62D3\u5C55\u5355\u4E0D\u5904\u4E8E\u5F85\u652F\u4ED8
+order.extension.is.paid=\u8BA2\u5355\u5DF2\u652F\u4ED8\uFF0C\u8BF7\u7B49\u5F85\u652F\u4ED8\u7ED3\u679C
+refund.price.exceed=\u9000\u6B3E\u91D1\u989D\u8D85\u8FC7\u8BA2\u5355\u53EF\u9000\u6B3E\u91D1\u989D
+refund.has.refunding=\u5DF2\u7ECF\u6709\u9000\u6B3E\u5728\u5904\u7406\u4E2D
+refund.exists=\u5DF2\u7ECF\u5B58\u5728\u9000\u6B3E\u5355
+refund.not.found=\u652F\u4ED8\u9000\u6B3E\u5355\u4E0D\u5B58\u5728
+refund.statue.is.not.waiting=\u652F\u4ED8\u9000\u6B3E\u5355\u4E0D\u5904\u4E8E\u5F85\u9000\u6B3E
+demo.order.not.found=\u793A\u4F8B\u8BA2\u5355\u4E0D\u5B58\u5728
+demo.order.update.paid.status.not.unpaid=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u8BA2\u5355\u4E0D\u662F\u3010\u672A\u652F\u4ED8\u3011\u72B6\u6001
+demo.order.update.paid.fail.pay.order.id.error=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u7F16\u53F7\u4E0D\u5339\u914D
+demo.order.update.paid.fail.pay.order.status.not.success=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u72B6\u6001\u4E0D\u662F\u3010\u652F\u4ED8\u6210\u529F\u3011\u72B6\u6001
+demo.order.update.paid.fail.pay.price.not.match=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u91D1\u989D\u4E0D\u5339\u914D
+demo.order.refund.fail.not.paid=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u793A\u4F8B\u8BA2\u5355\u672A\u652F\u4ED8
+demo.order.refund.fail.refunded=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u793A\u4F8B\u8BA2\u5355\u5DF2\u9000\u6B3E
+demo.order.refund.fail.refund.not.found=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u8BA2\u5355\u4E0D\u5B58\u5728
+demo.order.refund.fail.refund.not.success=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u8BA2\u5355\u672A\u9000\u6B3E\u6210\u529F
+demo.order.refund.fail.refund.order.id.error=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u5355\u7F16\u53F7\u4E0D\u5339\u914D
+demo.order.refund.fail.refund.price.not.match=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u5355\u91D1\u989D\u4E0D\u5339\u914D
+nettyDevice.can.send=\u6682\u65E0\u6743\u9650\u64CD\u4F5C
diff --git a/maibu-admin/src/main/resources/logback.xml b/maibu-admin/src/main/resources/logback.xml
new file mode 100644
index 0000000..cdc92e9
--- /dev/null
+++ b/maibu-admin/src/main/resources/logback.xml
@@ -0,0 +1,150 @@
+
+
+
+
+
+
+
+
+
+
+ ${log.pattern}
+
+
+
+
+
+
+ ${log.path}/sys-debug.log
+
+
+
+ ${log.path}/sys-debug.%d{yyyy-MM-dd}.log
+
+ 10
+
+
+ ${log.pattern}
+
+
+
+ DEBUG
+
+ ACCEPT
+
+ DENY
+
+
+
+
+
+ ${log.path}/sys-info.log
+
+
+
+ ${log.path}/sys-info.%d{yyyy-MM-dd}.log
+
+ 10
+
+
+ ${log.pattern}
+
+
+
+ INFO
+
+ ACCEPT
+
+ DENY
+
+
+
+
+ ${log.path}/sys-error.log
+
+
+
+ ${log.path}/sys-error.%d{yyyy-MM-dd}.log
+
+ 10
+
+
+ ${log.pattern}
+
+
+
+ ERROR
+
+ ACCEPT
+
+ DENY
+
+
+
+
+
+ ${log.path}/sys-user.log
+
+
+ ${log.path}/sys-user.%d{yyyy-MM-dd}.log
+
+ 10
+
+
+ ${log.pattern}
+
+
+
+
+
+
+ scriptId
+ 0
+
+
+
+ ${log.path}/script/${scriptId}.log
+ true
+ -->
+
+ ${log.path}/rule.%d{yyyy-MM}.log
+
+ 3
+
+
+ %d{HH:mm:ss.SSS} [%method,%line] - %msg%n
+
+
+ INFO
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/maibu-admin/src/main/resources/mybatis/mybatis-config.xml b/maibu-admin/src/main/resources/mybatis/mybatis-config.xml
new file mode 100644
index 0000000..ac47c03
--- /dev/null
+++ b/maibu-admin/src/main/resources/mybatis/mybatis-config.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/maibu-admin/src/main/resources/sharding-sphere-config.yaml b/maibu-admin/src/main/resources/sharding-sphere-config.yaml
new file mode 100644
index 0000000..1b33482
--- /dev/null
+++ b/maibu-admin/src/main/resources/sharding-sphere-config.yaml
@@ -0,0 +1,59 @@
+mode:
+ type: Standalone
+ repository:
+ type: JDBC
+props:
+ # 是否显示 ShardingSpher 的sql,用于Debug
+ sql-show: true
+datasource:
+ # 配置真实数据源
+ names: ds0,ds1
+ ds0: # 配置 mysql 数据源
+ type: com.alibaba.druid.pool.DruidDataSource
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://localhost:3306/fastbee?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+ username: root
+ password: fastbee
+ filters: stat,wall
+ filter:
+ stat:
+ enabled: true
+ # 慢SQL记录
+ log-slow-sql: true
+ slow-sql-millis: 1000
+ merge-sql: true
+ wall:
+ config:
+ multi-statement-allow: true
+ ds1: # 配置 mysql 数据源
+ type: com.alibaba.druid.pool.DruidDataSource
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://localhost:3306/information_schema?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+ username: root
+ password: fastbee
+
+rules: # 配置表规则
+ sharding:
+ # 表策略配置
+ tables:
+ # iot_device_log 是逻辑表
+ iot_device_log:
+ actualDataNodes: ds0.iot_device_log_$->{2024..2030}0$->{1..9},ds0.iot_device_log_$->{2024..2030}1$->{0..2}
+ tableStrategy:
+ # 使用标准分片策略
+ standard:
+ # 配置分片字段
+ shardingColumn: create_time
+ # 分片算法名称,不支持大写字母和下划线,否则启动就会报错
+ shardingAlgorithmName: time-sharding-algorithm
+ # 分片算法配置
+ shardingAlgorithms:
+ # 分片算法名称,不支持大写字母和下划线,否则启动就会报错
+ time-sharding-algorithm:
+ # 类型:自定义策略
+ type: CLASS_BASED
+ props:
+ # 分片策略
+ strategy: standard
+ # 分片算法类
+ algorithmClassName: com.fastbee.framework.config.sharding.TimeShardingAlgorithm
diff --git a/maibu-common/pom.xml b/maibu-common/pom.xml
new file mode 100644
index 0000000..db2d0b6
--- /dev/null
+++ b/maibu-common/pom.xml
@@ -0,0 +1,219 @@
+
+
+ 4.0.0
+
+ com.maibu
+ MiddlePlatform
+ 4.0.0
+
+
+ maibu-common
+
+
+
+
+ org.springframework
+ spring-context-support
+
+
+
+
+ org.springframework
+ spring-web
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+
+
+ com.baomidou
+ mybatis-plus-generator
+ ${mybatis-plus-generator.version}
+
+
+
+
+ com.github.pagehelper
+ pagehelper-spring-boot-starter
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+
+
+ com.alibaba.fastjson2
+ fastjson2
+
+
+
+
+ commons-io
+ commons-io
+
+
+
+
+ commons-fileupload
+ commons-fileupload
+
+
+
+
+ org.apache.poi
+ poi-ooxml
+
+
+
+
+ org.yaml
+ snakeyaml
+
+
+
+
+ io.jsonwebtoken
+ jjwt
+
+
+
+
+ javax.xml.bind
+ jaxb-api
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+
+
+ org.apache.commons
+ commons-pool2
+
+
+
+
+ eu.bitwalker
+ UserAgentUtils
+
+
+
+
+ javax.servlet
+ javax.servlet-api
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+ io.swagger
+ swagger-annotations
+ 1.6.2
+ compile
+
+
+
+ org.eclipse.paho
+ org.eclipse.paho.client.mqttv3
+ 1.2.5
+ compile
+
+
+
+ cn.hutool
+ hutool-all
+
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+ 2.15.2
+
+
+
+
+ com.google.guava
+ guava
+
+
+
+ com.alibaba
+ easyexcel-core
+
+
+
+
+ org.dromara.sms4j
+ sms4j-spring-boot-starter
+ 3.0.4
+
+
+
+ org.mapstruct
+ mapstruct
+
+
+ org.mapstruct
+ mapstruct-jdk8
+
+
+ org.mapstruct
+ mapstruct-processor
+
+
+
+ com.google.zxing
+ core
+
+
+
+ com.google.zxing
+ javase
+
+
+
+ io.minio
+ minio
+ 7.1.4
+
+
+
+
+
+ 8
+ 8
+ UTF-8
+
+
+
\ No newline at end of file
diff --git a/maibu-common/src/main/java/com/maibu/annotation/Anonymous.java b/maibu-common/src/main/java/com/maibu/annotation/Anonymous.java
new file mode 100644
index 0000000..b99c1ac
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/annotation/Anonymous.java
@@ -0,0 +1,15 @@
+package com.maibu.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 匿名访问不鉴权注解
+ *
+ * @author ruoyi
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Anonymous
+{
+}
diff --git a/maibu-common/src/main/java/com/maibu/annotation/DataScope.java b/maibu-common/src/main/java/com/maibu/annotation/DataScope.java
new file mode 100644
index 0000000..eb66dbb
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/annotation/DataScope.java
@@ -0,0 +1,29 @@
+package com.maibu.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 数据权限过滤注解
+ *
+ * @author ruoyi
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DataScope
+{
+ /**
+ * 部门表的别名
+ */
+ public String deptAlias() default "";
+
+ /**
+ * 用户表的别名
+ */
+ public String userAlias() default "";
+
+ /**
+ * 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取,多个权限用逗号分隔开来
+ */
+ public String permission() default "";
+}
diff --git a/maibu-common/src/main/java/com/maibu/annotation/DataSource.java b/maibu-common/src/main/java/com/maibu/annotation/DataSource.java
new file mode 100644
index 0000000..c969cb8
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/annotation/DataSource.java
@@ -0,0 +1,25 @@
+package com.maibu.annotation;
+
+
+import com.maibu.enums.DataSourceType;
+
+import java.lang.annotation.*;
+
+/**
+ * 自定义多数据源切换注解
+ *
+ * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
+ *
+ * @author ruoyi
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface DataSource
+{
+ /**
+ * 切换数据源名称
+ */
+ public DataSourceType value() default DataSourceType.master;
+}
diff --git a/maibu-common/src/main/java/com/maibu/annotation/DictFormat.java b/maibu-common/src/main/java/com/maibu/annotation/DictFormat.java
new file mode 100644
index 0000000..d58017c
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/annotation/DictFormat.java
@@ -0,0 +1,22 @@
+package com.maibu.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 字典格式化
+ *
+ * 实现将字典数据的值,格式化成字典数据的标签
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface DictFormat {
+
+ /**
+ * 例如说,SysDictTypeConstants、InfDictTypeConstants
+ *
+ * @return 字典类型
+ */
+ String value();
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/annotation/Excel.java b/maibu-common/src/main/java/com/maibu/annotation/Excel.java
new file mode 100644
index 0000000..e87f760
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/annotation/Excel.java
@@ -0,0 +1,188 @@
+package com.maibu.annotation;
+
+import com.maibu.utils.poi.ExcelHandlerAdapter;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.math.BigDecimal;
+
+/**
+ * 自定义导出Excel数据注解
+ *
+ * @author ruoyi
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Excel
+{
+ /**
+ * 导出时在excel中排序
+ */
+ public int sort() default Integer.MAX_VALUE;
+
+ /**
+ * 导出到Excel中的名字.
+ */
+ public String name() default "";
+
+ /**
+ * 日期格式, 如: yyyy-MM-dd
+ */
+ public String dateFormat() default "";
+
+ /**
+ * 如果是字典类型,请设置字典的type值 (如: sys_user_sex)
+ */
+ public String dictType() default "";
+
+ /**
+ * 读取内容转表达式 (如: 0=男,1=女,2=未知)
+ */
+ public String readConverterExp() default "";
+
+ /**
+ * 分隔符,读取字符串组内容
+ */
+ public String separator() default ",";
+
+ /**
+ * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
+ */
+ public int scale() default -1;
+
+ /**
+ * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
+ */
+ public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
+
+ /**
+ * 导出时在excel中每个列的高度 单位为字符
+ */
+ public double height() default 14;
+
+ /**
+ * 导出时在excel中每个列的宽 单位为字符
+ */
+ public double width() default 16;
+
+ /**
+ * 文字后缀,如% 90 变成90%
+ */
+ public String suffix() default "";
+
+ /**
+ * 当值为空时,字段的默认值
+ */
+ public String defaultValue() default "";
+
+ /**
+ * 提示信息
+ */
+ public String prompt() default "";
+
+ /**
+ * 设置只能选择不能输入的列内容.
+ */
+ public String[] combo() default {};
+
+ /**
+ * 是否需要纵向合并单元格,应对需求:含有list集合单元格)
+ */
+ public boolean needMerge() default false;
+
+ /**
+ * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
+ */
+ public boolean isExport() default true;
+
+ /**
+ * 另一个类中的属性名称,支持多级获取,以小数点隔开
+ */
+ public String targetAttr() default "";
+
+ /**
+ * 是否自动统计数据,在最后追加一行统计数据总和
+ */
+ public boolean isStatistics() default false;
+
+ /**
+ * 导出类型(0数字 1字符串 2图片)
+ */
+ public ColumnType cellType() default ColumnType.STRING;
+
+ /**
+ * 导出列头背景色
+ */
+ public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
+
+ /**
+ * 导出列头字体颜色
+ */
+ public IndexedColors headerColor() default IndexedColors.WHITE;
+
+ /**
+ * 导出单元格背景色
+ */
+ public IndexedColors backgroundColor() default IndexedColors.WHITE;
+
+ /**
+ * 导出单元格字体颜色
+ */
+ public IndexedColors color() default IndexedColors.BLACK;
+
+ /**
+ * 导出字段对齐方式
+ */
+ public HorizontalAlignment align() default HorizontalAlignment.CENTER;
+
+ /**
+ * 自定义数据处理器
+ */
+ public Class> handler() default ExcelHandlerAdapter.class;
+
+ /**
+ * 自定义数据处理器参数
+ */
+ public String[] args() default {};
+
+ /**
+ * 字段类型(0:导出导入;1:仅导出;2:仅导入)
+ */
+ Type type() default Type.ALL;
+
+ public enum Type
+ {
+ ALL(0), EXPORT(1), IMPORT(2);
+ private final int value;
+
+ Type(int value)
+ {
+ this.value = value;
+ }
+
+ public int value()
+ {
+ return this.value;
+ }
+ }
+
+ public enum ColumnType
+ {
+ NUMERIC(0), STRING(1), IMAGE(2);
+ private final int value;
+
+ ColumnType(int value)
+ {
+ this.value = value;
+ }
+
+ public int value()
+ {
+ return this.value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/maibu-common/src/main/java/com/maibu/annotation/Excels.java b/maibu-common/src/main/java/com/maibu/annotation/Excels.java
new file mode 100644
index 0000000..a78fca7
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/annotation/Excels.java
@@ -0,0 +1,18 @@
+package com.maibu.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Excel注解集
+ *
+ * @author ruoyi
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Excels
+{
+ public Excel[] value();
+}
diff --git a/maibu-common/src/main/java/com/maibu/annotation/Log.java b/maibu-common/src/main/java/com/maibu/annotation/Log.java
new file mode 100644
index 0000000..79f60f0
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/annotation/Log.java
@@ -0,0 +1,43 @@
+package com.maibu.annotation;
+
+import com.maibu.enums.BusinessType;
+import com.maibu.enums.OperatorType;
+
+import java.lang.annotation.*;
+
+/**
+ * 自定义操作日志记录注解
+ *
+ * @author ruoyi
+ *
+ */
+@Target({ ElementType.PARAMETER, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Log
+{
+ /**
+ * 模块
+ */
+ public String title() default "";
+
+ /**
+ * 功能
+ */
+ public BusinessType businessType() default BusinessType.OTHER;
+
+ /**
+ * 操作人类别
+ */
+ public OperatorType operatorType() default OperatorType.MANAGE;
+
+ /**
+ * 是否保存请求的参数
+ */
+ public boolean isSaveRequestData() default true;
+
+ /**
+ * 是否保存响应的参数
+ */
+ public boolean isSaveResponseData() default true;
+}
diff --git a/maibu-common/src/main/java/com/maibu/annotation/RateLimiter.java b/maibu-common/src/main/java/com/maibu/annotation/RateLimiter.java
new file mode 100644
index 0000000..2ad8d8c
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/annotation/RateLimiter.java
@@ -0,0 +1,38 @@
+package com.maibu.annotation;
+
+
+import com.maibu.constant.CacheConstants;
+import com.maibu.enums.LimitType;
+
+import java.lang.annotation.*;
+
+/**
+ * 限流注解
+ *
+ * @author ruoyi
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RateLimiter
+{
+ /**
+ * 限流key
+ */
+ public String key() default CacheConstants.RATE_LIMIT_KEY;
+
+ /**
+ * 限流时间,单位秒
+ */
+ public int time() default 60;
+
+ /**
+ * 限流次数
+ */
+ public int count() default 100;
+
+ /**
+ * 限流类型
+ */
+ public LimitType limitType() default LimitType.DEFAULT;
+}
diff --git a/maibu-common/src/main/java/com/maibu/annotation/RepeatSubmit.java b/maibu-common/src/main/java/com/maibu/annotation/RepeatSubmit.java
new file mode 100644
index 0000000..eeca9f6
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/annotation/RepeatSubmit.java
@@ -0,0 +1,26 @@
+package com.maibu.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 自定义注解防止表单重复提交
+ *
+ * @author ruoyi
+ *
+ */
+@Inherited
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RepeatSubmit
+{
+ /**
+ * 间隔时间(ms),小于此时间视为重复提交
+ */
+ public int interval() default 5000;
+
+ /**
+ * 提示消息
+ */
+ public String message() default "不允许重复提交,请稍候再试";
+}
diff --git a/maibu-common/src/main/java/com/maibu/annotation/SysProtocol.java b/maibu-common/src/main/java/com/maibu/annotation/SysProtocol.java
new file mode 100644
index 0000000..6a6bd56
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/annotation/SysProtocol.java
@@ -0,0 +1,21 @@
+package com.maibu.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 表示系统内部协议解析器
+ * @author gsb
+ * @date 2022/10/24 10:33
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface SysProtocol {
+
+ /*协议名*/
+ String name() default "";
+ /*协议编码*/
+ String protocolCode() default "";
+ //协议描述
+ String description() default "";
+}
diff --git a/maibu-common/src/main/java/com/maibu/config/DeviceTask.java b/maibu-common/src/main/java/com/maibu/config/DeviceTask.java
new file mode 100644
index 0000000..53660a5
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/config/DeviceTask.java
@@ -0,0 +1,121 @@
+package com.maibu.config;
+
+import com.maibu.constant.FastBeeConstant;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+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;
+
+/**
+ * 设备报文处理线程池
+ *
+ * @author bill
+ */
+@Configuration
+@EnableAsync
+@ConfigurationProperties(prefix = "spring.task.execution.pool")
+@Data
+public class DeviceTask {
+
+ private int coreSize;
+
+ private int maxSize;
+
+ private int queueCapacity;
+
+ private int keepAlive;
+
+ /*设备状态池*/
+ @Bean(FastBeeConstant.TASK.DEVICE_STATUS_TASK)
+ public Executor deviceStatusTaskExecutor() {
+ return builder(FastBeeConstant.TASK.DEVICE_STATUS_TASK);
+ }
+
+ /*平台自动获取线程池(例如定时获取设备信息)*/
+ @Bean(FastBeeConstant.TASK.DEVICE_FETCH_PROP_TASK)
+ public Executor deviceFetchTaskExecutor() {
+ return builder(FastBeeConstant.TASK.DEVICE_FETCH_PROP_TASK);
+ }
+
+ /*设备回调信息(下发指令(服务)设备应答信息)*/
+ @Bean(FastBeeConstant.TASK.DEVICE_REPLY_MESSAGE_TASK)
+ public Executor deviceReplyTaskExecutor() {
+ return builder(FastBeeConstant.TASK.DEVICE_REPLY_MESSAGE_TASK);
+ }
+
+ /*设备主动上报(设备数据有变化主动上报)*/
+ @Bean(FastBeeConstant.TASK.DEVICE_UP_MESSAGE_TASK)
+ public Executor deviceUpMessageTaskExecutor() {
+ return builder(FastBeeConstant.TASK.DEVICE_UP_MESSAGE_TASK);
+ }
+
+ /*指令下发(服务下发)*/
+ @Bean(FastBeeConstant.TASK.FUNCTION_INVOKE_TASK)
+ public Executor functionInvokeTaskExecutor() {
+ return builder(FastBeeConstant.TASK.FUNCTION_INVOKE_TASK);
+ }
+
+ /*内部消费线程*/
+ @Bean(FastBeeConstant.TASK.MESSAGE_CONSUME_TASK)
+ public Executor messageConsumeTaskExecutor() {
+ return builder(FastBeeConstant.TASK.MESSAGE_CONSUME_TASK);
+ }
+
+ @Bean(FastBeeConstant.TASK.MESSAGE_CONSUME_TASK_PUB)
+ public Executor messageConsumePubTaskExecutor() {
+ return builder(FastBeeConstant.TASK.MESSAGE_CONSUME_TASK_PUB);
+ }
+
+ @Bean(FastBeeConstant.TASK.MESSAGE_CONSUME_TASK_FETCH)
+ public Executor messageConsumeFetchTaskExecutor() {
+ return builder(FastBeeConstant.TASK.MESSAGE_CONSUME_TASK_FETCH);
+ }
+
+ @Bean(FastBeeConstant.TASK.DELAY_UPGRADE_TASK)
+ public Executor delayedTaskExecutor() {
+ return builder(FastBeeConstant.TASK.DELAY_UPGRADE_TASK);
+ }
+
+ /*设备其他消息处理*/
+ @Bean(FastBeeConstant.TASK.DEVICE_OTHER_TASK)
+ public Executor deviceOtherTaskExecutor() {
+ return builder(FastBeeConstant.TASK.DEVICE_OTHER_TASK);
+ }
+
+ @Bean(FastBeeConstant.TASK.DEVICE_TEST_TASK)
+ public Executor deviceTestTaskExecutor() {
+ return builder(FastBeeConstant.TASK.DEVICE_TEST_TASK);
+ }
+
+ @Bean(FastBeeConstant.TASK.DEVICE_ERROR_MONITOR)
+ public Executor deviceErrorMonitor() {
+ return builder(FastBeeConstant.TASK.DEVICE_ERROR_MONITOR);
+ }
+
+ @Bean(FastBeeConstant.TASK.DEVICE_TASK_HANDLER)
+ public Executor deviceTaskHandler() {
+ return builder(FastBeeConstant.TASK.DEVICE_TASK_HANDLER);
+ }
+
+
+ /*组装线程池*/
+ private ThreadPoolTaskExecutor builder(String threadNamePrefix) {
+ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+ executor.setCorePoolSize(coreSize);
+ executor.setMaxPoolSize(maxSize);
+ executor.setKeepAliveSeconds(keepAlive);
+ executor.setQueueCapacity(queueCapacity);
+ // 线程池对拒绝任务的处理策略
+ executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
+ //线程池名的前缀
+ executor.setThreadNamePrefix(threadNamePrefix);
+ executor.initialize();
+ return executor;
+ }
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/config/MinioConfig.java b/maibu-common/src/main/java/com/maibu/config/MinioConfig.java
new file mode 100644
index 0000000..0c641a0
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/config/MinioConfig.java
@@ -0,0 +1,18 @@
+package com.maibu.config;
+
+import io.minio.MinioClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class MinioConfig {
+
+ @Bean
+ public MinioClient minioClient() {
+ return MinioClient.builder()
+ .endpoint("https://oss.satabot.com")
+ .build();
+ }
+}
+
+
diff --git a/maibu-common/src/main/java/com/maibu/config/RuoYiConfig.java b/maibu-common/src/main/java/com/maibu/config/RuoYiConfig.java
new file mode 100644
index 0000000..0e12bfa
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/config/RuoYiConfig.java
@@ -0,0 +1,135 @@
+package com.maibu.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 读取项目相关配置
+ *
+ * @author ruoyi
+ */
+@Component
+@ConfigurationProperties(prefix = "fastbee")
+public class RuoYiConfig
+{
+ /** 项目名称 */
+ private String name;
+
+ /** 版本 */
+ private String version;
+
+ /** 版权年份 */
+ private String copyrightYear;
+
+ /** 实例演示开关 */
+ private boolean demoEnabled;
+
+ /** 上传路径 */
+ private static String profile;
+
+ /** 获取地址开关 */
+ private static boolean addressEnabled;
+
+ /** 验证码类型 */
+ private static String captchaType;
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public String getVersion()
+ {
+ return version;
+ }
+
+ public void setVersion(String version)
+ {
+ this.version = version;
+ }
+
+ public String getCopyrightYear()
+ {
+ return copyrightYear;
+ }
+
+ public void setCopyrightYear(String copyrightYear)
+ {
+ this.copyrightYear = copyrightYear;
+ }
+
+ public boolean isDemoEnabled()
+ {
+ return demoEnabled;
+ }
+
+ public void setDemoEnabled(boolean demoEnabled)
+ {
+ this.demoEnabled = demoEnabled;
+ }
+
+ public static String getProfile()
+ {
+ return profile;
+ }
+
+ public void setProfile(String profile)
+ {
+ RuoYiConfig.profile = profile;
+ }
+
+ public static boolean isAddressEnabled()
+ {
+ return addressEnabled;
+ }
+
+ public void setAddressEnabled(boolean addressEnabled)
+ {
+ RuoYiConfig.addressEnabled = addressEnabled;
+ }
+
+ public static String getCaptchaType() {
+ return captchaType;
+ }
+
+ public void setCaptchaType(String captchaType) {
+ RuoYiConfig.captchaType = captchaType;
+ }
+
+ /**
+ * 获取导入上传路径
+ */
+ public static String getImportPath()
+ {
+ return getProfile() + "/import";
+ }
+
+ /**
+ * 获取头像上传路径
+ */
+ public static String getAvatarPath()
+ {
+ return getProfile() + "/avatar";
+ }
+
+ /**
+ * 获取下载路径
+ */
+ public static String getDownloadPath()
+ {
+ return getProfile() + "/download/";
+ }
+
+ /**
+ * 获取上传路径
+ */
+ public static String getUploadPath()
+ {
+ return getProfile() + "/upload";
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/constant/CacheConstants.java b/maibu-common/src/main/java/com/maibu/constant/CacheConstants.java
new file mode 100644
index 0000000..2928ff2
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/constant/CacheConstants.java
@@ -0,0 +1,90 @@
+package com.maibu.constant;
+
+/**
+ * 缓存的key 常量
+ *
+ * @author ruoyi
+ */
+public class CacheConstants
+{
+ /**
+ * 登录用户 redis key
+ */
+ public static final String LOGIN_TOKEN_KEY = "login_tokens:";
+
+ /**
+ * 登录用户 redis key
+ */
+ public static final String LOGIN_USERID_KEY = "login_userId:";
+
+ /**
+ * 登录用户 平台 redis key
+ */
+ public static final String LOGIN_USERID_SOURCE_KEY = "login_userId_source:";
+
+ /**
+ * 验证码 redis key
+ */
+ public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
+
+ /**
+ * 参数管理 cache key
+ */
+ public static final String SYS_CONFIG_KEY = "sys_config:";
+
+ /**
+ * 字典管理 cache key
+ */
+ public static final String SYS_DICT_KEY = "sys_dict:";
+
+ /**
+ * 数据库查询 cache key
+ */
+ public static final String SQL_CACHE_KEY = "sql_cache:";
+
+ /**
+ * 防重提交 redis key
+ */
+ public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
+
+ /**
+ * 限流 redis key
+ */
+ public static final String RATE_LIMIT_KEY = "rate_limit:";
+
+ /**
+ * 登录账户密码错误次数 redis key
+ */
+ public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
+
+ /**
+ * 短信登录验证码 redis key
+ */
+ public static final String LOGIN_SMS_CAPTCHA_PHONE = "login_sms_captcha_phone:";
+
+ /**
+ * 邮箱登录验证码 redis key
+ */
+ public static final String LOGIN_EMAIL_CAPTCHA = "login_email_captcha:";
+
+ /**
+ * 微信获取accessToken redis key
+ */
+ public static final String WECHAT_GET_ACCESS_TOKEN_APPID = "wechat_get_accessToken:";
+
+ /**
+ * 短信注册验证码 redis key
+ */
+ public static final String REGISTER_SMS_CAPTCHA_PHONE = "register_sms_captcha_phone:";
+
+ /**
+ * 邮箱注册验证码 redis key
+ */
+ public static final String REGISTER_EMAIL_CAPTCHA = "register_email_captcha:";
+
+ /**设备OTA升级实时数据*/
+ public static final String DEVICE_OTA_DATA = "device:ota:";
+
+}
+
+
diff --git a/maibu-common/src/main/java/com/maibu/constant/Constants.java b/maibu-common/src/main/java/com/maibu/constant/Constants.java
new file mode 100644
index 0000000..59f59d9
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/constant/Constants.java
@@ -0,0 +1,163 @@
+package com.maibu.constant;
+
+import io.jsonwebtoken.Claims;
+
+/**
+ * 通用常量信息
+ *
+ * @author ruoyi
+ */
+public class Constants
+{
+ /**
+ * UTF-8 字符集
+ */
+ public static final String UTF8 = "UTF-8";
+
+ /**
+ * GBK 字符集
+ */
+ public static final String GBK = "GBK";
+
+ /**
+ * www主域
+ */
+ public static final String WWW = "www.";
+
+ /**
+ * http请求
+ */
+ public static final String HTTP = "http://";
+
+ /**
+ * https请求
+ */
+ public static final String HTTPS = "https://";
+
+ /**
+ * 通用成功标识
+ */
+ public static final String SUCCESS = "0";
+
+ /**
+ * 通用失败标识
+ */
+ public static final String FAIL = "1";
+
+ /**
+ * 登录成功
+ */
+ public static final String LOGIN_SUCCESS = "Success";
+
+ /**
+ * 注销
+ */
+ public static final String LOGOUT = "Logout";
+
+ /**
+ * 注册
+ */
+ public static final String REGISTER = "Register";
+
+ /**
+ * 登录失败
+ */
+ public static final String LOGIN_FAIL = "Error";
+
+ /**
+ * 验证码有效期(分钟)
+ */
+ public static final Integer CAPTCHA_EXPIRATION = 2;
+
+ /**
+ * 令牌
+ */
+ public static final String TOKEN = "token";
+
+ /**
+ * 令牌前缀
+ */
+ public static final String TOKEN_PREFIX = "Bearer ";
+
+ /**
+ * 令牌前缀
+ */
+ public static final String LOGIN_USER_KEY = "login_user_key";
+
+ /**
+ * 用户ID
+ */
+ public static final String JWT_USERID = "userid";
+
+ /**
+ * 用户名称
+ */
+ public static final String JWT_USERNAME = Claims.SUBJECT;
+
+ /**
+ * 用户头像
+ */
+ public static final String JWT_AVATAR = "avatar";
+
+ /**
+ * 创建时间
+ */
+ public static final String JWT_CREATED = "created";
+
+ /**
+ * 用户权限
+ */
+ public static final String JWT_AUTHORITIES = "authorities";
+
+ /**
+ * 资源映射路径 前缀
+ */
+ public static final String RESOURCE_PREFIX = "/profile";
+
+ /**
+ * RMI 远程方法调用
+ */
+ public static final String LOOKUP_RMI = "rmi:";
+
+ /**
+ * LDAP 远程方法调用
+ */
+ public static final String LOOKUP_LDAP = "ldap:";
+
+ /**
+ * LDAPS 远程方法调用
+ */
+ public static final String LOOKUP_LDAPS = "ldaps:";
+
+ /**
+ * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
+ */
+ public static final String[] JOB_WHITELIST_STR = { "com.fastbee" };
+
+ /**
+ * 定时任务违规的字符
+ */
+ public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
+ "org.springframework", "org.apache", "com.fastbee.common.utils.file", "com.fastbee.common.config" };
+
+ /**
+ * 语言类型
+ */
+ public static final String LANGUAGE = "language";
+ public static final String ZH_CN = "zh-CN";
+ public static final String EN_US = "en-US";
+
+ /**
+ * 翻译数据类型
+ */
+ public static final String MENU = "menu";
+ public static final String DICT_DATA = "dict_data";
+ public static final String DICT_TYPE = "dict_type";
+ public static final String THINGS_MODEL = "things_model";
+ public static final String THINGS_MODEL_TEMPLATE = "things_model_template";
+
+ /**
+ * 组态分享缓存token-key
+ */
+ public static final String SCADA_SHARE_KEY = "scada_share_key";
+}
diff --git a/maibu-common/src/main/java/com/maibu/constant/FastBeeConstant.java b/maibu-common/src/main/java/com/maibu/constant/FastBeeConstant.java
new file mode 100644
index 0000000..0b53109
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/constant/FastBeeConstant.java
@@ -0,0 +1,356 @@
+package com.maibu.constant;
+
+/**
+ * 常量
+ *
+ * @author bill
+ */
+public interface FastBeeConstant {
+
+ interface SERVER {
+ String UFT8 = "UTF-8";
+ String GB2312 = "GB2312";
+
+
+ String MQTT = "mqtt";
+ String PORT = "port";
+ String ADAPTER = "adapter";
+ String FRAMEDECODER = "frameDecoder";
+ String DISPATCHER = "dispatcher";
+ String DECODER = "decoder";
+ String ENCODER = "encoder";
+ String MAXFRAMELENGTH = "maxFrameLength";
+ String SLICER = "slicer";
+ String DELIMITERS = "delimiters";
+ String IDLE = "idle";
+ String WS_PREFIX = "web-";
+ String WM_PREFIX = "server-";
+ String FAST_PHONE = "phone-";
+
+ /*MQTT平台判定离线时间 keepAlive*1.5 */
+ Long DEVICE_PING_EXPIRED = 90000L;
+ }
+
+ interface CLIENT {
+ //加盐
+ String TOKEN = "fastbee-smart!@#$123";
+ }
+
+ /*webSocket配置*/
+ interface WS {
+ String HEART_BEAT = "heartbeat";
+ String HTTP_SERVER_CODEC = "httpServerCodec";
+ String AGGREGATOR = "aggregator";
+ String COMPRESSOR = "compressor";
+ String PROTOCOL = "protocol";
+ String MQTT_WEBSOCKET = "mqttWebsocket";
+ String DECODER = "decoder";
+ String ENCODER = "encoder";
+ String BROKER_HANDLER = "brokerHandler";
+
+ }
+
+ interface TASK {
+ /**
+ * 设备上下线任务
+ */
+ String DEVICE_STATUS_TASK = "deviceStatusTask";
+ /**
+ * 设备主动上报任务
+ */
+ String DEVICE_UP_MESSAGE_TASK = "deviceUpMessageTask";
+ /**
+ * 设备回调任务
+ */
+ String DEVICE_REPLY_MESSAGE_TASK = "deviceReplyMessageTask";
+ /**
+ * 设备下行任务
+ */
+ String DEVICE_DOWN_MESSAGE_TASK = "deviceDownMessageTask";
+ /**
+ * 服务调用(指令下发)任务
+ */
+ String FUNCTION_INVOKE_TASK = "functionInvokeTask";
+ /**
+ * 属性读取任务,区分服务调用
+ */
+ String DEVICE_FETCH_PROP_TASK = "deviceFetchPropTask";
+ /**
+ * 设备其他消息处理
+ */
+ String DEVICE_OTHER_TASK = "deviceOtherMsgTask";
+ /**
+ * 数据调试任务
+ */
+ String DEVICE_TEST_TASK = "deviceTestMsgTask";
+ /**
+ * 消息消费线程
+ */
+ String MESSAGE_CONSUME_TASK = "messageConsumeTask";
+ /*内部消费线程publish*/
+ String MESSAGE_CONSUME_TASK_PUB = "messageConsumeTaskPub";
+ /*内部消费线程Fetch*/
+ String MESSAGE_CONSUME_TASK_FETCH = "messageConsumeTaskFetch";
+ /*OTA升级延迟队列*/
+ String DELAY_UPGRADE_TASK = "delayUpgradeTask";
+ /*OTA升级线程池*/
+ String OTA_THREAD_POOL = "otaThreadPoolTaskExecutor";
+
+ /**
+ * 设备错误
+ */
+ String DEVICE_ERROR_MONITOR = "deviceErrorMonitor";
+ /**
+ * 设备任务处理线程
+ */
+ String DEVICE_TASK_HANDLER = "deviceTaskHandler";
+
+ }
+
+ interface MQTT {
+
+ String PREDIX = "/+/+";
+
+ /*OTA消息回复*/
+ String OTA_REPLY = "upgrade/reply";
+
+ }
+
+ /*集群,全局发布的消息类型*/
+ interface CHANNEL {
+ /*设备状态*/
+ String DEVICE_STATUS = "device_status";
+ /*平台读取属性*/
+ String PROP_READ = "prop_read";
+ /*推送消息*/
+ String PUBLISH = "publish";
+ /*服务下发*/
+ String FUNCTION_INVOKE = "function_invoke";
+ /*事件*/
+ String EVENT = "event";
+ /*other*/
+ String OTHER = "other";
+ /*Qos1 推送应答*/
+ String PUBLISH_ACK = "publish_ack";
+ /*Qos2 发布消息收到*/
+ String PUB_REC = "pub_rec";
+ /*Qos 发布消息释放*/
+ String PUB_REL = "pub_rel";
+ /*Qos2 发布消息完成*/
+ String PUB_COMP = "pub_comp";
+
+ String UPGRADE = "upgrade";
+
+ /*-------------------------ROCKETMQ-------------------------*/
+ String SUFFIX = "group";
+ /*设备状态*/
+ String DEVICE_STATUS_GROUP = DEVICE_STATUS + SUFFIX;
+ String PROP_READ_GROUP = PROP_READ + SUFFIX;
+ /*服务下发*/
+ String FUNCTION_INVOKE_GROUP = FUNCTION_INVOKE + SUFFIX;
+ /*推送消息*/
+ String PUBLISH_GROUP = PUBLISH + SUFFIX;
+ /*Qos1 推送应答*/
+ String PUBLISH_ACK_GROUP = PUBLISH_ACK + SUFFIX;
+ /*Qos2 发布消息收到*/
+ String PUB_REC_GROUP = PUB_REC + SUFFIX;
+ /*Qos 发布消息释放*/
+ String PUB_REL_GROUP = PUB_REL + SUFFIX;
+ /*Qos2 发布消息完成*/
+ String PUB_COMP_GROUP = PUB_COMP + SUFFIX;
+ /*OTA升级*/
+ String UPGRADE_GROUP = UPGRADE + SUFFIX;
+ }
+
+
+ /**
+ * redisKey 定义
+ */
+ interface REDIS {
+ /*在线设备列表*/
+ String DEVICE_ONLINE_LIST = "device:online:list";
+ /*设备实时状态key*/
+ String DEVICE_RUNTIME_DATA = "device:runtime:";
+ /*通讯协议参数*/
+ String DEVICE_PROTOCOL_PARAM = "device:param:";
+ /**
+ * 设备消息id缓存key
+ */
+ String DEVICE_MESSAGE_ID = "device:messageId:";
+ /**
+ * 固件版本key
+ */
+ String FIRMWARE_VERSION = "device:firmware:";
+ /**
+ * 设备信息
+ */
+ String DEVICE_MSG = "device:msg:";
+ /**
+ * 属性下发回调
+ */
+ String PROP_READ_STORE = "prop:read:store:";
+ /**
+ * sip
+ */
+ String RECORDINFO_KEY = "sip:recordinfo:";
+ String DEVICEID_KEY = "sip:deviceid:";
+ String STREAM_KEY = "sip:stream:";
+ String INVITE_KEY = "sip:invite:";
+ String SIP_CSEQ_PREFIX = "sip:CSEQ:";
+ String DEFAULT_SIP_CONFIG = "sip:config";
+ String DEFAULT_MEDIA_CONFIG = "sip:mediaconfig";
+
+ /**
+ * rule
+ */
+ String RULE_SILENT_TIME = "rule:SilentTime";
+
+ /**
+ * 总保留消息
+ */
+ String MESSAGE_RETAIN_TOTAL = "message:retain:total";
+
+ /*发送消息数*/
+ String MESSAGE_SEND_TOTAL = "message:send:total";
+ /*接收消息数*/
+ String MESSAGE_RECEIVE_TOTAL = "message:receive:total";
+ /*连接次数*/
+ String MESSAGE_CONNECT_TOTAL = "message:connect:total";
+ /**
+ * 认证次数
+ */
+ String MESSAGE_AUTH_TOTAL = "message:auth:total";
+ /**
+ * 订阅次数
+ */
+ String MESSAGE_SUBSCRIBE_TOTAL = "message:subscribe:total";
+
+ /**
+ * 今日接收消息
+ */
+ String MESSAGE_RECEIVE_TODAY = "message:receive:today";
+ /**
+ * 今日发送消息
+ */
+ String MESSAGE_SEND_TODAY = "message:send:today";
+
+ /**
+ * 物模型值缓存
+ */
+ String DEVICE_PRE_KEY = "TSLV:";
+
+ /**
+ * 物模型缓存
+ */
+ String TSL_PRE_KEY = "TSL:";
+
+ String MODBUS_PRE_KEY = "MODBUS:";
+
+ /**
+ * modbus缓存指令
+ */
+ String POLL_MODBUS_KEY = "MODBUS:POLL:";
+ /**
+ * modbus运行时数据
+ */
+ String MODBUS_RUNTIME = "MODBUS:RUNTIME:";
+
+ String MODBUS_LOCK = "MODBUS:LOCK:";
+
+ /**
+ * 通知企业微信应用消息accessToken缓存key
+ */
+ String NOTIFY_WECOM_APPLY_ACCESSTOKEN = "notify:wecom:apply:";
+
+ // 场景变量命名空间:Key:SMTV:{sceneModelTagId}
+ String SCENE_MODEL_TAG_ID = "SMTV:";
+
+ /**
+ * modbus运行时数据
+ */
+ String MODBUS_TCP = "MODBUS:TCP:";
+
+ /**
+ * modbus运行时数据
+ */
+ String MODBUS_TCP_RUNTIME = "MODBUS:TCP:RUNTIME:";
+ /**
+ * OTA实时数据
+ */
+ String DEVICE_OTA_DATA = "device:ota:";
+
+ }
+
+ interface PROTOCOL {
+ String ModbusRtu = "MODBUS-RTU";
+ String YinErDa = "YinErDa";
+ String JsonObject = "JSONOBJECT";
+ String JsonArray = "JSON";
+ String ModbusRtuPak = "MODBUS-RTU-PAK";
+ String NetOTA = "OTA-NET";
+ String FlowMeter = "FlowMeter";
+ String RJ45 = "RJ45";
+ String ModbusToJson = "MODBUS-JSON";
+ String ModbusToJsonHP = "MODBUS-JSON-HP";
+ String ModbusToJsonZQWL = "MODBUS-JSON-ZQWL";
+ String JsonObject_ChenYi = "JSONOBJECT-CHENYI";
+ String GEC6100D = "MODBUS-JSON-GEC6100D";
+ String SGZ = "SGZ";
+ String CH = "CH";
+ String ModbusTcp = "MODBUS-TCP";
+
+
+ }
+
+ interface URL {
+ /**
+ * 微信小程序订阅消息推送url前缀
+ */
+ String WX_MINI_PROGRAM_PUSH_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send";
+ /**
+ * 微信网站、移动应用登录获取用户access_token
+ */
+ String WX_GET_ACCESS_TOKEN_URL_PREFIX = "https://api.weixin.qq.com/sns/oauth2/access_token";
+ /**
+ * 微信小程序登录获取用户会话参数
+ */
+ String WX_MINI_PROGRAM_GET_USER_SESSION_URL_PREFIX = "https://api.weixin.qq.com/sns/jscode2session";
+ /**
+ * 微信小程序、公众号获取access_token
+ */
+ String WX_MINI_PROGRAM_GET_ACCESS_TOKEN_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";
+ /**
+ * 微信获取用户信息
+ */
+ String WX_GET_USER_INFO_URL_PREFIX = "https://api.weixin.qq.com/sns/userinfo";
+ /**
+ * 获取用户手机号信息
+ */
+ String WX_GET_USER_PHONE_URL_PREFIX = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=";
+ /**
+ * 企业微信获取accessToken
+ */
+ String WECOM_GET_ACCESSTOKEN = "https://qyapi.weixin.qq.com/cgi-bin/gettoken";
+ /**
+ * 企业微信发送应用消息
+ */
+ String WECOM_APPLY_SEND = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=";
+ /**
+ * 微信公众号获取用户信息
+ */
+ String WX_PUBLIC_ACCOUNT_GET_USER_INFO_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/user/info";
+ /**
+ * 微信公众号发送模版消息
+ */
+ String WX_PUBLIC_ACCOUNT_TEMPLATE_SEND_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=";
+ }
+
+ interface TRANSPORT {
+ String MQTT = "MQTT";
+ String TCP = "TCP";
+ String COAP = "COAP";
+ String UDP = "UDP";
+ String GB28181 = "GB28181";
+ }
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/constant/GenConstants.java b/maibu-common/src/main/java/com/maibu/constant/GenConstants.java
new file mode 100644
index 0000000..9ab9f06
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/constant/GenConstants.java
@@ -0,0 +1,117 @@
+package com.maibu.constant;
+
+/**
+ * 代码生成通用常量
+ *
+ * @author ruoyi
+ */
+public class GenConstants
+{
+ /** 单表(增删改查) */
+ public static final String TPL_CRUD = "crud";
+
+ /** 树表(增删改查) */
+ public static final String TPL_TREE = "tree";
+
+ /** 主子表(增删改查) */
+ public static final String TPL_SUB = "sub";
+
+ /** 树编码字段 */
+ public static final String TREE_CODE = "treeCode";
+
+ /** 树父编码字段 */
+ public static final String TREE_PARENT_CODE = "treeParentCode";
+
+ /** 树名称字段 */
+ public static final String TREE_NAME = "treeName";
+
+ /** 上级菜单ID字段 */
+ public static final String PARENT_MENU_ID = "parentMenuId";
+
+ /** 上级菜单名称字段 */
+ public static final String PARENT_MENU_NAME = "parentMenuName";
+
+ /** 数据库字符串类型 */
+ public static final String[] COLUMNTYPE_STR = { "char", "varchar", "nvarchar", "varchar2" };
+
+ /** 数据库文本类型 */
+ public static final String[] COLUMNTYPE_TEXT = { "tinytext", "text", "mediumtext", "longtext" };
+
+ /** 数据库时间类型 */
+ public static final String[] COLUMNTYPE_TIME = { "datetime", "time", "date", "timestamp" };
+
+ /** 数据库数字类型 */
+ public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer",
+ "bit", "bigint", "float", "double", "decimal" };
+
+ /** 页面不需要编辑字段 */
+ public static final String[] COLUMNNAME_NOT_EDIT = { "id", "create_by", "create_time", "del_flag" };
+
+ /** 页面不需要显示的列表字段 */
+ public static final String[] COLUMNNAME_NOT_LIST = { "id", "create_by", "create_time", "del_flag", "update_by",
+ "update_time" };
+
+ /** 页面不需要查询字段 */
+ public static final String[] COLUMNNAME_NOT_QUERY = { "id", "create_by", "create_time", "del_flag", "update_by",
+ "update_time", "remark" };
+
+ /** Entity基类字段 */
+ public static final String[] BASE_ENTITY = { "createBy", "createTime", "updateBy", "updateTime", "remark" };
+
+ /** Tree基类字段 */
+ public static final String[] TREE_ENTITY = { "parentName", "parentId", "orderNum", "ancestors", "children" };
+
+ /** 文本框 */
+ public static final String HTML_INPUT = "input";
+
+ /** 文本域 */
+ public static final String HTML_TEXTAREA = "textarea";
+
+ /** 下拉框 */
+ public static final String HTML_SELECT = "select";
+
+ /** 单选框 */
+ public static final String HTML_RADIO = "radio";
+
+ /** 复选框 */
+ public static final String HTML_CHECKBOX = "checkbox";
+
+ /** 日期控件 */
+ public static final String HTML_DATETIME = "datetime";
+
+ /** 图片上传控件 */
+ public static final String HTML_IMAGE_UPLOAD = "imageUpload";
+
+ /** 文件上传控件 */
+ public static final String HTML_FILE_UPLOAD = "fileUpload";
+
+ /** 富文本控件 */
+ public static final String HTML_EDITOR = "editor";
+
+ /** 字符串类型 */
+ public static final String TYPE_STRING = "String";
+
+ /** 整型 */
+ public static final String TYPE_INTEGER = "Integer";
+
+ /** 长整型 */
+ public static final String TYPE_LONG = "Long";
+
+ /** 浮点型 */
+ public static final String TYPE_DOUBLE = "Double";
+
+ /** 高精度计算类型 */
+ public static final String TYPE_BIGDECIMAL = "BigDecimal";
+
+ /** 时间类型 */
+ public static final String TYPE_DATE = "Date";
+
+ /** 模糊查询 */
+ public static final String QUERY_LIKE = "LIKE";
+
+ /** 相等查询 */
+ public static final String QUERY_EQ = "EQ";
+
+ /** 需要 */
+ public static final String REQUIRE = "1";
+}
diff --git a/maibu-common/src/main/java/com/maibu/constant/HttpStatus.java b/maibu-common/src/main/java/com/maibu/constant/HttpStatus.java
new file mode 100644
index 0000000..4bc6f91
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/constant/HttpStatus.java
@@ -0,0 +1,105 @@
+package com.maibu.constant;
+
+/**
+ * 返回状态码
+ *
+ * @author ruoyi
+ */
+public class HttpStatus
+{
+ /**
+ * 操作成功
+ */
+ public static final int SUCCESS = 200;
+
+ /**
+ * 对象创建成功
+ */
+ public static final int CREATED = 201;
+
+ /**
+ * 请求已经被接受
+ */
+ public static final int ACCEPTED = 202;
+
+ /**
+ * 操作已经执行成功,但是没有返回数据
+ */
+ public static final int NO_CONTENT = 204;
+
+ /**
+ * 资源已被移除
+ */
+ public static final int MOVED_PERM = 301;
+
+ /**
+ * 重定向
+ */
+ public static final int SEE_OTHER = 303;
+
+ /**
+ * 资源没有被修改
+ */
+ public static final int NOT_MODIFIED = 304;
+
+ /**
+ * 参数列表错误(缺少,格式不匹配)
+ */
+ public static final int BAD_REQUEST = 400;
+
+ /**
+ * 未授权
+ */
+ public static final int UNAUTHORIZED = 401;
+
+ /**
+ * 访问受限,授权过期
+ */
+ public static final int FORBIDDEN = 403;
+
+ /**
+ * 资源,服务未找到
+ */
+ public static final int NOT_FOUND = 404;
+
+ /**
+ * 不允许的http方法
+ */
+ public static final int BAD_METHOD = 405;
+
+ /**
+ * 资源冲突,或者资源被锁
+ */
+ public static final int CONFLICT = 409;
+
+ /**
+ * 不支持的数据,媒体类型
+ */
+ public static final int UNSUPPORTED_TYPE = 415;
+
+ /**
+ * 用户不存在
+ */
+ public static final int USER_NO_EXIST = 450;
+
+ /**
+ * 系统内部错误
+ */
+ public static final int ERROR = 500;
+
+ /**
+ * 接口未实现
+ */
+ public static final int NOT_IMPLEMENTED = 501;
+
+ /**
+ * 不弹窗显示
+ */
+ public static final int NO_MESSAGE_ALERT = 502;
+
+
+ /**
+ * 系统警告消息
+ */
+ public static final int WARN = 601;
+}
diff --git a/maibu-common/src/main/java/com/maibu/constant/IoTCommonDeviceConstant.java b/maibu-common/src/main/java/com/maibu/constant/IoTCommonDeviceConstant.java
new file mode 100644
index 0000000..b5b15d6
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/constant/IoTCommonDeviceConstant.java
@@ -0,0 +1,19 @@
+package com.maibu.constant;
+
+public class IoTCommonDeviceConstant {
+
+ /**
+ * 定义下用到的topic 格式
+ */
+ public static final String property_topic = "/iot/device/+/property";
+
+ /**
+ * 定义下用到的topic 格式
+ */
+ public static final String event_topic = "/iot/device/+/event";
+
+ /**
+ * 定义下用到的topic 格式
+ */
+ public static final String action_topic = "/iot/device/+/action";
+}
diff --git a/maibu-common/src/main/java/com/maibu/constant/MagicValueConstants.java b/maibu-common/src/main/java/com/maibu/constant/MagicValueConstants.java
new file mode 100644
index 0000000..08903e3
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/constant/MagicValueConstants.java
@@ -0,0 +1,21 @@
+package com.maibu.constant;
+
+/**
+ * 魔法值常量
+ *
+ * @author ruoyi
+ */
+public class MagicValueConstants
+{
+ /**
+ * 3600
+ */
+ public static final Integer VALUE_3600 = 3600;
+
+ /**
+ * 60
+ */
+ public static final Integer VALUE_60 = 60;
+
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/constant/ProductAuthConstant.java b/maibu-common/src/main/java/com/maibu/constant/ProductAuthConstant.java
new file mode 100644
index 0000000..89b9316
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/constant/ProductAuthConstant.java
@@ -0,0 +1,41 @@
+package com.maibu.constant;
+
+/**
+ *
+ * @author fastb
+ * @date 2023-08-03 10:20
+ */
+public class ProductAuthConstant {
+
+ /**
+ * 产品设备认证方式-简单认证
+ */
+ public static final Integer AUTH_WAY_SIMPLE = 1;
+ /**
+ * 产品设备认证方式-简单认证
+ */
+ public static final Integer AUTH_WAY_ENCRYPT = 2;
+ /**
+ * 产品设备认证方式-简单认证
+ */
+ public static final Integer AUTH_WAY_SIMPLE_AND_ENCRYPT = 3;
+
+ /**
+ * 产品设备客户端ID认证类型-简单认证
+ */
+ public static final String CLIENT_ID_AUTH_TYPE_SIMPLE = "S";
+
+ /**
+ * 产品设备客户端ID认证类型-简单认证
+ */
+ public static final String CLIENT_ID_AUTH_TYPE_ENCRYPT = "E";
+ /**
+ * 设备授权
+ */
+ public static final Integer AUTHORIZE = 1;
+ /**
+ * 设备没有授权
+ */
+ public static final Integer NO_AUTHORIZE = 1;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/constant/ScadaConstant.java b/maibu-common/src/main/java/com/maibu/constant/ScadaConstant.java
new file mode 100644
index 0000000..88546da
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/constant/ScadaConstant.java
@@ -0,0 +1,14 @@
+package com.maibu.constant;
+
+/**
+ * @author fastb
+ * @version 1.0
+ * @description: 组态常量类
+ * @date 2024-01-02 14:40
+ */
+public class ScadaConstant {
+
+ public static final String COMPONENT_TEMPLATE_DEFAULT = "
\n
自定义组件案例
\n 支持element ui、样式自定义、vue的语法等
\n 点击按钮\n";
+ public static final String COMPONENT_SCRIPT_DEFAULT = "export default {\n data() {\n return {}\n },\n created() {\n\n },\n mounted(){\n\n },\n methods:{\n handleClick(){\n this.$message('这是一条消息提示');\n }\n }\n}";
+ public static final String COMPONENT_STYLE_DEFAULT = "h2 {\n color:#409EFF\n}\n\nh4 {\n color:#F56C6C\n}";
+}
diff --git a/maibu-common/src/main/java/com/maibu/constant/SceneModelConstants.java b/maibu-common/src/main/java/com/maibu/constant/SceneModelConstants.java
new file mode 100644
index 0000000..9324176
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/constant/SceneModelConstants.java
@@ -0,0 +1,47 @@
+package com.maibu.constant;
+
+/**
+ * @author fastb
+ * @version 1.0
+ * @description: 场景相关的场景
+ * @date 2024-06-04 15:26
+ */
+public class SceneModelConstants {
+
+ /**
+ * 时
+ */
+ public static final String CYCLE_HOUR = "hour";
+
+ /**
+ * 日
+ */
+ public static final String CYCLE_DAY = "day";
+
+ /**
+ * 周
+ */
+ public static final String CYCLE_WEEK = "week";
+
+ /**
+ * 月
+ */
+ public static final String CYCLE_MONTH = "month";
+
+ /**
+ * 当日
+ */
+ public static final Integer CYCLE_TO_TYPE_NOW_DAY = 1;
+ /**
+ * 次日
+ */
+ public static final Integer CYCLE_TO_TYPE_SECOND_DAY = 2;
+ /**
+ * 周
+ */
+ public static final Integer CYCLE_TO_TYPE_WEEK = 3;
+ /**
+ * 月
+ */
+ public static final Integer CYCLE_TO_TYPE_MONTH = 4;
+}
diff --git a/maibu-common/src/main/java/com/maibu/constant/ScheduleConstants.java b/maibu-common/src/main/java/com/maibu/constant/ScheduleConstants.java
new file mode 100644
index 0000000..12b9833
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/constant/ScheduleConstants.java
@@ -0,0 +1,50 @@
+package com.maibu.constant;
+
+/**
+ * 任务调度通用常量
+ *
+ * @author ruoyi
+ */
+public class ScheduleConstants
+{
+ public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";
+
+ /** 执行目标key */
+ public static final String TASK_PROPERTIES = "TASK_PROPERTIES";
+
+ /** 默认 */
+ public static final String MISFIRE_DEFAULT = "0";
+
+ /** 立即触发执行 */
+ public static final String MISFIRE_IGNORE_MISFIRES = "1";
+
+ /** 触发一次执行 */
+ public static final String MISFIRE_FIRE_AND_PROCEED = "2";
+
+ /** 不触发立即执行 */
+ public static final String MISFIRE_DO_NOTHING = "3";
+
+ public enum Status
+ {
+ /**
+ * 正常
+ */
+ NORMAL("0"),
+ /**
+ * 暂停
+ */
+ PAUSE("1");
+
+ private String value;
+
+ private Status(String value)
+ {
+ this.value = value;
+ }
+
+ public String getValue()
+ {
+ return value;
+ }
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/constant/SipConstants.java b/maibu-common/src/main/java/com/maibu/constant/SipConstants.java
new file mode 100644
index 0000000..8b8b903
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/constant/SipConstants.java
@@ -0,0 +1,9 @@
+package com.maibu.constant;
+
+public class SipConstants {
+ public static final String MESSAGE_CATALOG = "Catalog";
+ public static final String MESSAGE_KEEP_ALIVE = "Keepalive";
+ public static final String MESSAGE_DEVICE_INFO = "DeviceInfo";
+ public static final String MESSAGE_RECORD_INFO = "RecordInfo";
+ public static final String MESSAGE_MEDIA_STATUS = "MediaStatus";
+}
diff --git a/maibu-common/src/main/java/com/maibu/constant/UserConstants.java b/maibu-common/src/main/java/com/maibu/constant/UserConstants.java
new file mode 100644
index 0000000..c2757e3
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/constant/UserConstants.java
@@ -0,0 +1,78 @@
+package com.maibu.constant;
+
+/**
+ * 用户常量信息
+ *
+ * @author ruoyi
+ */
+public class UserConstants
+{
+ /**
+ * 平台内系统用户的唯一标志
+ */
+ public static final String SYS_USER = "SYS_USER";
+
+ /** 正常状态 */
+ public static final String NORMAL = "0";
+
+ /** 异常状态 */
+ public static final String EXCEPTION = "1";
+
+ /** 用户封禁状态 */
+ public static final String USER_DISABLE = "1";
+
+ /** 角色封禁状态 */
+ public static final String ROLE_DISABLE = "1";
+
+ /** 部门正常状态 */
+ public static final String DEPT_NORMAL = "0";
+
+ /** 部门停用状态 */
+ public static final String DEPT_DISABLE = "1";
+
+ /** 字典正常状态 */
+ public static final String DICT_NORMAL = "0";
+
+ /** 是否为系统默认(是) */
+ public static final String YES = "Y";
+
+ /** 是否菜单外链(是) */
+ public static final String YES_FRAME = "0";
+
+ /** 是否菜单外链(否) */
+ public static final String NO_FRAME = "1";
+
+ /** 菜单类型(目录) */
+ public static final String TYPE_DIR = "M";
+
+ /** 菜单类型(菜单) */
+ public static final String TYPE_MENU = "C";
+
+ /** 菜单类型(按钮) */
+ public static final String TYPE_BUTTON = "F";
+
+ /** Layout组件标识 */
+ public final static String LAYOUT = "Layout";
+
+ /** ParentView组件标识 */
+ public final static String PARENT_VIEW = "ParentView";
+
+ /** InnerLink组件标识 */
+ public final static String INNER_LINK = "InnerLink";
+
+ /** 校验返回结果码 */
+ public final static String UNIQUE = "0";
+ public final static String NOT_UNIQUE = "1";
+
+ /**
+ * 用户名长度限制
+ */
+ public static final int USERNAME_MIN_LENGTH = 2;
+ public static final int USERNAME_MAX_LENGTH = 20;
+
+ /**
+ * 密码长度限制
+ */
+ public static final int PASSWORD_MIN_LENGTH = 5;
+ public static final int PASSWORD_MAX_LENGTH = 20;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/controller/BaseController.java b/maibu-common/src/main/java/com/maibu/core/controller/BaseController.java
new file mode 100644
index 0000000..c278df3
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/controller/BaseController.java
@@ -0,0 +1,206 @@
+package com.maibu.core.controller;
+
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.maibu.constant.CacheConstants;
+import com.maibu.constant.HttpStatus;
+import com.maibu.core.domain.AjaxResult;
+import com.maibu.core.domain.model.LoginUser;
+import com.maibu.core.page.PageDomain;
+import com.maibu.core.page.TableDataInfo;
+import com.maibu.core.page.TableSupport;
+import com.maibu.core.redis.RedisCache;
+import com.maibu.utils.*;
+import com.maibu.utils.sql.SqlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.WebDataBinder;
+import org.springframework.web.bind.annotation.InitBinder;
+
+import javax.annotation.Resource;
+import java.beans.PropertyEditorSupport;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * web层通用数据处理
+ *
+ * @author ruoyi
+ */
+public class BaseController {
+ protected final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Resource
+ private RedisCache redisCache;
+
+ /**
+ * 将前台传递过来的日期格式的字符串,自动转化为Date类型
+ */
+ @InitBinder
+ public void initBinder(WebDataBinder binder) {
+ // Date 类型转换
+ binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
+ @Override
+ public void setAsText(String text) {
+ setValue(DateUtils.parseDate(text));
+ }
+ });
+ }
+
+ /**
+ * 设置请求分页数据
+ */
+ protected void startPage() {
+ PageUtils.startPage();
+ }
+
+ /**
+ * 设置请求排序数据
+ */
+ protected void startOrderBy() {
+ PageDomain pageDomain = TableSupport.buildPageRequest();
+ if (StringUtils.isNotEmpty(pageDomain.getOrderBy())) {
+ String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
+ PageHelper.orderBy(orderBy);
+ }
+ }
+
+ /**
+ * 清理分页的线程变量
+ */
+ protected void clearPage() {
+ PageUtils.clearPage();
+ }
+
+ /**
+ * 响应请求分页数据
+ */
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ protected TableDataInfo getDataTable(List> list) {
+ TableDataInfo rspData = new TableDataInfo();
+ rspData.setCode(HttpStatus.SUCCESS);
+ rspData.setMsg(MessageUtils.message("query.success"));
+ rspData.setRows(list);
+ rspData.setTotal(new PageInfo(list).getTotal());
+ return rspData;
+ }
+
+ protected TableDataInfo getDataTable(List> list, Long total) {
+ TableDataInfo rspData = new TableDataInfo();
+ rspData.setCode(HttpStatus.SUCCESS);
+ rspData.setMsg("查询成功");
+ rspData.setRows(list);
+ rspData.setTotal(total);
+ return rspData;
+ }
+
+ /**
+ * 返回成功
+ */
+ public AjaxResult success() {
+ return AjaxResult.success();
+ }
+
+ /**
+ * 返回失败消息
+ */
+ public AjaxResult error() {
+ return AjaxResult.error();
+ }
+
+ /**
+ * 返回成功消息
+ */
+ public AjaxResult success(String message) {
+ return AjaxResult.success(message);
+ }
+
+ /**
+ * 返回成功消息
+ */
+ public AjaxResult success(Object data) {
+ return AjaxResult.success(data);
+ }
+
+ /**
+ * 返回失败消息
+ */
+ public AjaxResult error(String message) {
+ return AjaxResult.error(message);
+ }
+
+ /**
+ * 返回警告消息
+ */
+ public AjaxResult warn(String message) {
+ return AjaxResult.warn(message);
+ }
+
+ /**
+ * 响应返回结果
+ *
+ * @param rows 影响行数
+ * @return 操作结果
+ */
+ protected AjaxResult toAjax(int rows) {
+ return rows > 0 ? AjaxResult.success() : AjaxResult.error();
+ }
+
+ /**
+ * 响应返回结果
+ *
+ * @param result 结果
+ * @return 操作结果
+ */
+ protected AjaxResult toAjax(boolean result) {
+ return result ? success() : error();
+ }
+
+ protected AjaxResult toAjax(Object result) {
+ return result != null ? success(result) : error();
+ }
+
+ /**
+ * 页面跳转
+ */
+ public String redirect(String url) {
+ return StringUtils.format("redirect:{}", url);
+ }
+
+ /**
+ * 获取用户缓存信息
+ * 由于不同端不能获取最新用户信息,所以优先以用户id缓存key获取用户信息
+ */
+ public LoginUser getLoginUser() {
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ if (loginUser != null) {
+ Long userId = loginUser.getUserId();
+ if (userId != null) {
+ String userKey = CacheConstants.LOGIN_USERID_KEY + userId;
+ return redisCache.getCacheObject(userKey);
+ }
+ }
+ return loginUser;
+ }
+
+ /**
+ * 获取登录用户id
+ */
+ public Long getUserId() {
+ return getLoginUser().getUserId();
+ }
+
+ /**
+ * 获取登录部门id
+ */
+ public Long getDeptId() {
+ return getLoginUser().getDeptId();
+ }
+
+ /**
+ * 获取登录用户名
+ */
+ public String getUsername() {
+ return getLoginUser().getUsername();
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/device/DeviceAndProtocol.java b/maibu-common/src/main/java/com/maibu/core/device/DeviceAndProtocol.java
new file mode 100644
index 0000000..3a29788
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/device/DeviceAndProtocol.java
@@ -0,0 +1,66 @@
+package com.maibu.core.device;
+
+import lombok.Data;
+
+/**
+ * @author gsb
+ * @date 2024/6/14 9:25
+ */
+@Data
+public class DeviceAndProtocol {
+
+ /**
+ * 子设备编号
+ */
+ private Long deviceId;
+ /**
+ * 设备编号
+ */
+ private String serialNumber;
+ /**
+ * 协议编号
+ */
+ private String protocolCode;
+ /**
+ * 产品id
+ */
+ private Long productId;
+
+ private String transport;
+
+ /**
+ * 设备类型
+ */
+ private Integer deviceType;
+ /**
+ * 子设备地址
+ */
+ private Integer slaveId;
+ /**
+ * 网关绑定的子设备地址
+ */
+ private Integer proSlaveId;
+ /**
+ * 网关设备id
+ */
+ private Long gwDeviceId;
+ /**
+ * 网关设备产品id
+ */
+ private Long gwProductId;
+ /**
+ * 网关设备编号
+ */
+ private String gwSerialNumber;
+ /**
+ * 网关设备名
+ */
+ private String gwDeviceName;
+ /**
+ * 网关产品名
+ */
+ private String gwProductName;
+
+ private Long tenantId;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/AjaxResult.java b/maibu-common/src/main/java/com/maibu/core/domain/AjaxResult.java
new file mode 100644
index 0000000..b28c745
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/AjaxResult.java
@@ -0,0 +1,216 @@
+package com.maibu.core.domain;
+
+
+import com.maibu.constant.HttpStatus;
+import com.maibu.utils.StringUtils;
+
+import java.util.HashMap;
+
+/**
+ * 操作消息提醒
+ *
+ * @author ruoyi
+ */
+public class AjaxResult extends HashMap
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 状态码 */
+ public static final String CODE_TAG = "code";
+
+ /** 返回内容 */
+ public static final String MSG_TAG = "msg";
+
+ /** 数据对象 */
+ public static final String DATA_TAG = "data";
+
+ /**
+ * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
+ */
+ public AjaxResult()
+ {
+ }
+
+ /**
+ * 初始化一个新创建的 AjaxResult 对象
+ *
+ * @param code 状态码
+ * @param msg 返回内容
+ */
+ public AjaxResult(int code, String msg)
+ {
+ super.put(CODE_TAG, code);
+ super.put(MSG_TAG, msg);
+ }
+
+ /**
+ * 初始化一个新创建的 AjaxResult 对象
+ *
+ * @param code 状态码
+ * @param msg 返回内容
+ * @param data 数据对象
+ */
+ public AjaxResult(int code, String msg, Object data)
+ {
+ super.put(CODE_TAG, code);
+ super.put(MSG_TAG, msg);
+ if (StringUtils.isNotNull(data))
+ {
+ super.put(DATA_TAG, data);
+ }
+ }
+
+
+ /**
+ * 初始化一个新创建的 AjaxResult 对象
+ *
+ * @param code 状态码
+ * @param msg 返回内容
+ * @param data 数据对象
+ */
+ public AjaxResult(int code, String msg, Object data,int total)
+ {
+ super.put(CODE_TAG, code);
+ super.put(MSG_TAG, msg);
+ if (StringUtils.isNotNull(data))
+ {
+ super.put(DATA_TAG, data);
+ }
+ super.put("total",total);
+ }
+
+ /**
+ * 返回成功消息
+ *
+ * @return 成功消息
+ */
+ public static AjaxResult success()
+ {
+ return AjaxResult.success("操作成功");
+ }
+
+ /**
+ * 返回成功数据
+ *
+ * @return 成功消息
+ */
+ public static AjaxResult success(Object data)
+ {
+ return AjaxResult.success("操作成功", data);
+ }
+
+ /**
+ * 返回成功数据
+ *
+ * @return 成功消息
+ */
+ public static AjaxResult success(Object data,int total)
+ {
+ return new AjaxResult(HttpStatus.SUCCESS, "操作成功", data,total);
+ }
+
+ /**
+ * 返回成功消息
+ *
+ * @param msg 返回内容
+ * @return 成功消息
+ */
+ public static AjaxResult success(String msg)
+ {
+ return AjaxResult.success(msg, null);
+ }
+
+ /**
+ * 返回成功消息
+ *
+ * @param msg 返回内容
+ * @param data 数据对象
+ * @return 成功消息
+ */
+ public static AjaxResult success(String msg, Object data)
+ {
+ return new AjaxResult(HttpStatus.SUCCESS, msg, data);
+ }
+
+ /**
+ * 返回警告消息
+ *
+ * @param msg 返回内容
+ * @return 警告消息
+ */
+ public static AjaxResult warn(String msg)
+ {
+ return AjaxResult.warn(msg, null);
+ }
+
+ /**
+ * 返回警告消息
+ *
+ * @param msg 返回内容
+ * @param data 数据对象
+ * @return 警告消息
+ */
+ public static AjaxResult warn(String msg, Object data)
+ {
+ return new AjaxResult(HttpStatus.WARN, msg, data);
+ }
+
+ /**
+ * 返回错误消息
+ *
+ * @return 错误消息
+ */
+ public static AjaxResult error()
+ {
+ return AjaxResult.error("操作失败");
+ }
+
+ /**
+ * 返回错误消息
+ *
+ * @param msg 返回内容
+ * @return 错误消息
+ */
+ public static AjaxResult error(String msg)
+ {
+ return AjaxResult.error(msg, null);
+ }
+
+ /**
+ * 返回错误消息
+ *
+ * @param msg 返回内容
+ * @param data 数据对象
+ * @return 错误消息
+ */
+ public static AjaxResult error(String msg, Object data)
+ {
+ return new AjaxResult(HttpStatus.ERROR, msg, data);
+ }
+
+ /**
+ * 返回错误消息
+ *
+ * @param code 状态码
+ * @param msg 返回内容
+ * @return 错误消息
+ */
+ public static AjaxResult error(int code, String msg)
+ {
+ return new AjaxResult(code, msg, null);
+ }
+
+ /**
+ * 方便链式调用
+ *
+ * @param key 键
+ * @param value 值
+ * @return 数据对象
+ */
+ @Override
+ public AjaxResult put(String key, Object value)
+ {
+ super.put(key, value);
+ return this;
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/BaseDO.java b/maibu-common/src/main/java/com/maibu/core/domain/BaseDO.java
new file mode 100644
index 0000000..39066f7
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/BaseDO.java
@@ -0,0 +1,43 @@
+package com.maibu.core.domain;
+
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 基类,时间类型改为LocalDateTime
+ * @author fastb
+ * @date 2023-08-22 9:11
+ */
+@Data
+public class BaseDO implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /** 创建者 */
+ @ApiModelProperty("创建者")
+ private String createBy;
+
+ /** 创建时间 */
+ @ApiModelProperty("创建时间")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime createTime;
+
+ /** 更新者 */
+ @ApiModelProperty("更新者")
+ private String updateBy;
+
+ /** 更新时间 */
+ @ApiModelProperty("更新时间")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime updateTime;
+
+ /** 逻辑删除 */
+ @ApiModelProperty("逻辑删除")
+ @TableLogic
+ private Boolean delFlag;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/BaseEntity.java b/maibu-common/src/main/java/com/maibu/core/domain/BaseEntity.java
new file mode 100644
index 0000000..e981649
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/BaseEntity.java
@@ -0,0 +1,153 @@
+package com.maibu.core.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Entity基类
+ *
+ * @author ruoyi
+ */
+public class BaseEntity implements Serializable
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 搜索值 */
+ @TableField(exist = false)
+ @ApiModelProperty("搜索值")
+ @JsonIgnore
+ private String searchValue;
+
+ /** 创建者 */
+ @ApiModelProperty("创建者")
+ private String createBy;
+
+ /** 创建时间 */
+ @ApiModelProperty("创建时间")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+
+ /** 更新者 */
+ @ApiModelProperty("更新者")
+ private String updateBy;
+
+ /** 更新时间 */
+ @ApiModelProperty("更新时间")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+
+ /** 备注 */
+ @ApiModelProperty("备注")
+ @TableField(exist = false)
+ private String remark;
+
+ public Integer getPageNum() {
+ return pageNum;
+ }
+
+ public void setPageNum(Integer pageNum) {
+ this.pageNum = pageNum;
+ }
+
+ public Integer getPageSize() {
+ return pageSize;
+ }
+
+ public void setPageSize(Integer pageSize) {
+ this.pageSize = pageSize;
+ }
+
+ @TableField(exist = false)
+ private Integer pageNum;
+
+ @TableField(exist = false)
+ private Integer pageSize;
+
+ /** 请求参数 */
+ @TableField(exist = false)
+ @ApiModelProperty("请求参数")
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private Map params;
+
+ public String getSearchValue()
+ {
+ return searchValue;
+ }
+
+ public void setSearchValue(String searchValue)
+ {
+ this.searchValue = searchValue;
+ }
+
+ public String getCreateBy()
+ {
+ return createBy;
+ }
+
+ public void setCreateBy(String createBy)
+ {
+ this.createBy = createBy;
+ }
+
+ public Date getCreateTime()
+ {
+ return createTime;
+ }
+
+ public void setCreateTime(Date createTime)
+ {
+ this.createTime = createTime;
+ }
+
+ public String getUpdateBy()
+ {
+ return updateBy;
+ }
+
+ public void setUpdateBy(String updateBy)
+ {
+ this.updateBy = updateBy;
+ }
+
+ public Date getUpdateTime()
+ {
+ return updateTime;
+ }
+
+ public void setUpdateTime(Date updateTime)
+ {
+ this.updateTime = updateTime;
+ }
+
+ public String getRemark()
+ {
+ return remark;
+ }
+
+ public void setRemark(String remark)
+ {
+ this.remark = remark;
+ }
+
+ public Map getParams()
+ {
+ if (params == null)
+ {
+ params = new HashMap<>();
+ }
+ return params;
+ }
+
+ public void setParams(Map params)
+ {
+ this.params = params;
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/CommonResult.java b/maibu-common/src/main/java/com/maibu/core/domain/CommonResult.java
new file mode 100644
index 0000000..e4578c1
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/CommonResult.java
@@ -0,0 +1,112 @@
+package com.maibu.core.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.maibu.enums.GlobalErrorCodeConstants;
+import com.maibu.exception.ErrorCode;
+import com.maibu.exception.ServiceException;
+import lombok.Data;
+import org.springframework.util.Assert;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * 通用返回
+ *
+ * @param 数据泛型
+ */
+@Data
+public class CommonResult implements Serializable {
+
+ /**
+ * 错误码
+ *
+ * @see ErrorCode#getCode()
+ */
+ private Integer code;
+ /**
+ * 返回数据
+ */
+ private T data;
+ /**
+ * 错误提示,用户可阅读
+ *
+ * @see ErrorCode#getMsg() ()
+ */
+ private String msg;
+
+ /**
+ * 将传入的 result 对象,转换成另外一个泛型结果的对象
+ *
+ * 因为 A 方法返回的 CommonResult 对象,不满足调用其的 B 方法的返回,所以需要进行转换。
+ *
+ * @param result 传入的 result 对象
+ * @param 返回的泛型
+ * @return 新的 CommonResult 对象
+ */
+ public static CommonResult error(CommonResult> result) {
+ return error(result.getCode(), result.getMsg());
+ }
+
+ public static CommonResult error(Integer code, String message) {
+ Assert.isTrue(!GlobalErrorCodeConstants.SUCCESS.getCode().equals(code), "code 必须是错误的!");
+ CommonResult result = new CommonResult<>();
+ result.code = code;
+ result.msg = message;
+ return result;
+ }
+
+ public static CommonResult error(ErrorCode errorCode) {
+ return error(errorCode.getCode(), errorCode.getMsg());
+ }
+
+ public static CommonResult success(T data) {
+ CommonResult result = new CommonResult<>();
+ result.code = GlobalErrorCodeConstants.SUCCESS.getCode();
+ result.data = data;
+ result.msg = "";
+ return result;
+ }
+
+ public static boolean isSuccess(Integer code) {
+ return Objects.equals(code, GlobalErrorCodeConstants.SUCCESS.getCode());
+ }
+
+ @JsonIgnore // 避免 jackson 序列化
+ public boolean isSuccess() {
+ return isSuccess(code);
+ }
+
+ @JsonIgnore // 避免 jackson 序列化
+ public boolean isError() {
+ return !isSuccess();
+ }
+
+ // ========= 和 Exception 异常体系集成 =========
+
+ /**
+ * 判断是否有异常。如果有,则抛出 {@link ServiceException} 异常
+ */
+ public void checkError() throws ServiceException {
+ if (isSuccess()) {
+ return;
+ }
+ // 业务异常
+ throw new ServiceException(code, msg);
+ }
+
+ /**
+ * 判断是否有异常。如果有,则抛出 {@link ServiceException} 异常
+ * 如果没有,则返回 {@link #data} 数据
+ */
+ @JsonIgnore // 避免 jackson 序列化
+ public T getCheckedData() {
+ checkError();
+ return data;
+ }
+
+ public static CommonResult error(ServiceException serviceException) {
+ return error(serviceException.getCode(), serviceException.getMessage());
+ }
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/ImportExcelVO.java b/maibu-common/src/main/java/com/maibu/core/domain/ImportExcelVO.java
new file mode 100644
index 0000000..4ba1be2
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/ImportExcelVO.java
@@ -0,0 +1,36 @@
+package com.maibu.core.domain;
+
+import com.maibu.annotation.Excel;
+import lombok.Data;
+
+/**
+ * @author admin
+ * @version 1.0
+ * @description: TODO
+ * @date 2024-07-12 16:20
+ */
+@Data
+public class ImportExcelVO {
+
+ @Excel(name = "ID")
+ private Long id;
+
+ @Excel(name = "城市ID")
+ private String code;
+
+ @Excel(name = "行政归属")
+ private String city;
+
+ @Excel(name = "城市简称")
+ private String simCity;
+
+ @Excel(name = "拼音")
+ private String cn;
+
+ @Excel(name = "lat")
+ private String lat;
+
+ @Excel(name = "lon")
+ private String lon;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/OutputExcelVO.java b/maibu-common/src/main/java/com/maibu/core/domain/OutputExcelVO.java
new file mode 100644
index 0000000..83b9aaf
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/OutputExcelVO.java
@@ -0,0 +1,25 @@
+package com.maibu.core.domain;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author admin
+ * @version 1.0
+ * @description: TODO
+ * @date 2024-07-12 16:25
+ */
+@Data
+public class OutputExcelVO {
+
+ private String code;
+
+ private String name;
+
+ private String lat;
+
+ private String lon;
+
+ private List children;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/PageParam.java b/maibu-common/src/main/java/com/maibu/core/domain/PageParam.java
new file mode 100644
index 0000000..ace6c8e
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/PageParam.java
@@ -0,0 +1,25 @@
+package com.maibu.core.domain;
+
+import lombok.Data;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+@Data
+public class PageParam implements Serializable {
+
+ private static final Integer PAGE_NO = 1;
+ private static final Integer PAGE_SIZE = 10;
+
+ @NotNull(message = "页码不能为空")
+ @Min(value = 1, message = "页码最小值为 1")
+ private Integer pageNo = PAGE_NO;
+
+ @NotNull(message = "每页条数不能为空")
+ @Min(value = 1, message = "每页条数最小值为 1")
+ @Max(value = 100, message = "每页条数最大值为 100")
+ private Integer pageSize = PAGE_SIZE;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/PageResult.java b/maibu-common/src/main/java/com/maibu/core/domain/PageResult.java
new file mode 100644
index 0000000..0d85017
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/PageResult.java
@@ -0,0 +1,42 @@
+package com.maibu.core.domain;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+@Api(tags = "分页结果")
+@Data
+public final class PageResult implements Serializable {
+
+ @ApiModelProperty(value = "数据", required = true)
+ private List list;
+
+ @ApiModelProperty(value = "总量", required = true)
+ private Long total;
+
+ public PageResult() {
+ }
+
+ public PageResult(List list, Long total) {
+ this.list = list;
+ this.total = total;
+ }
+
+ public PageResult(Long total) {
+ this.list = new ArrayList<>();
+ this.total = total;
+ }
+
+ public static PageResult empty() {
+ return new PageResult<>(0L);
+ }
+
+ public static PageResult empty(Long total) {
+ return new PageResult<>(total);
+ }
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/R.java b/maibu-common/src/main/java/com/maibu/core/domain/R.java
new file mode 100644
index 0000000..271a68e
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/R.java
@@ -0,0 +1,117 @@
+package com.maibu.core.domain;
+
+
+import com.maibu.constant.HttpStatus;
+
+import java.io.Serializable;
+
+/**
+ * 响应信息主体
+ *
+ * @author ruoyi
+ */
+public class R implements Serializable
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 成功 */
+ public static final int SUCCESS = HttpStatus.SUCCESS;
+
+ /** 失败 */
+ public static final int FAIL = HttpStatus.ERROR;
+
+ private int code;
+
+ private String msg;
+
+ private T data;
+
+ public static R ok()
+ {
+ return restResult(null, SUCCESS, "操作成功");
+ }
+
+ public static R ok(T data)
+ {
+ return restResult(data, SUCCESS, "操作成功");
+ }
+
+ public static R ok(T data, String msg)
+ {
+ return restResult(data, SUCCESS, msg);
+ }
+
+ public static R fail()
+ {
+ return restResult(null, FAIL, "操作失败");
+ }
+
+ public static R fail(String msg)
+ {
+ return restResult(null, FAIL, msg);
+ }
+
+ public static R fail(T data)
+ {
+ return restResult(data, FAIL, "操作失败");
+ }
+
+ public static R fail(T data, String msg)
+ {
+ return restResult(data, FAIL, msg);
+ }
+
+ public static R fail(int code, String msg)
+ {
+ return restResult(null, code, msg);
+ }
+
+ private static R restResult(T data, int code, String msg)
+ {
+ R apiResult = new R<>();
+ apiResult.setCode(code);
+ apiResult.setData(data);
+ apiResult.setMsg(msg);
+ return apiResult;
+ }
+
+ public int getCode()
+ {
+ return code;
+ }
+
+ public void setCode(int code)
+ {
+ this.code = code;
+ }
+
+ public String getMsg()
+ {
+ return msg;
+ }
+
+ public void setMsg(String msg)
+ {
+ this.msg = msg;
+ }
+
+ public T getData()
+ {
+ return data;
+ }
+
+ public void setData(T data)
+ {
+ this.data = data;
+ }
+
+ public static Boolean isError(R ret)
+ {
+ return !isSuccess(ret);
+ }
+
+ public static Boolean isSuccess(R ret)
+ {
+ return R.SUCCESS == ret.getCode();
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/SortingField.java b/maibu-common/src/main/java/com/maibu/core/domain/SortingField.java
new file mode 100644
index 0000000..f986d60
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/SortingField.java
@@ -0,0 +1,56 @@
+package com.maibu.core.domain;
+
+import java.io.Serializable;
+
+/**
+ * 排序字段 DTO
+ *
+ * 类名加了 ing 的原因是,避免和 ES SortField 重名。
+ */
+public class SortingField implements Serializable {
+
+ /**
+ * 顺序 - 升序
+ */
+ public static final String ORDER_ASC = "asc";
+ /**
+ * 顺序 - 降序
+ */
+ public static final String ORDER_DESC = "desc";
+
+ /**
+ * 字段
+ */
+ private String field;
+ /**
+ * 顺序
+ */
+ private String order;
+
+ // 空构造方法,解决反序列化
+ public SortingField() {
+ }
+
+ public SortingField(String field, String order) {
+ this.field = field;
+ this.order = order;
+ }
+
+ public String getField() {
+ return field;
+ }
+
+ public SortingField setField(String field) {
+ this.field = field;
+ return this;
+ }
+
+ public String getOrder() {
+ return order;
+ }
+
+ public SortingField setOrder(String order) {
+ this.order = order;
+ return this;
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/TenantBaseDO.java b/maibu-common/src/main/java/com/maibu/core/domain/TenantBaseDO.java
new file mode 100644
index 0000000..5627745
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/TenantBaseDO.java
@@ -0,0 +1,20 @@
+package com.maibu.core.domain;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 拓展多租户的 BaseDO 基类
+ *
+ * @author fastbee
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public abstract class TenantBaseDO extends BaseDO {
+
+ /**
+ * 多租户编号
+ */
+ private Long tenantId;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/TreeEntity.java b/maibu-common/src/main/java/com/maibu/core/domain/TreeEntity.java
new file mode 100644
index 0000000..c3e6d32
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/TreeEntity.java
@@ -0,0 +1,79 @@
+package com.maibu.core.domain;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tree基类
+ *
+ * @author ruoyi
+ */
+public class TreeEntity extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 父菜单名称 */
+ private String parentName;
+
+ /** 父菜单ID */
+ private Long parentId;
+
+ /** 显示顺序 */
+ private Integer orderNum;
+
+ /** 祖级列表 */
+ private String ancestors;
+
+ /** 子部门 */
+ private List> children = new ArrayList<>();
+
+ public String getParentName()
+ {
+ return parentName;
+ }
+
+ public void setParentName(String parentName)
+ {
+ this.parentName = parentName;
+ }
+
+ public Long getParentId()
+ {
+ return parentId;
+ }
+
+ public void setParentId(Long parentId)
+ {
+ this.parentId = parentId;
+ }
+
+ public Integer getOrderNum()
+ {
+ return orderNum;
+ }
+
+ public void setOrderNum(Integer orderNum)
+ {
+ this.orderNum = orderNum;
+ }
+
+ public String getAncestors()
+ {
+ return ancestors;
+ }
+
+ public void setAncestors(String ancestors)
+ {
+ this.ancestors = ancestors;
+ }
+
+ public List> getChildren()
+ {
+ return children;
+ }
+
+ public void setChildren(List> children)
+ {
+ this.children = children;
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/TreeSelect.java b/maibu-common/src/main/java/com/maibu/core/domain/TreeSelect.java
new file mode 100644
index 0000000..8db221f
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/TreeSelect.java
@@ -0,0 +1,78 @@
+package com.maibu.core.domain;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.maibu.core.domain.entity.SysDept;
+import com.maibu.core.domain.entity.SysMenu;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Treeselect树结构实体类
+ *
+ * @author ruoyi
+ */
+public class TreeSelect implements Serializable
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 节点ID */
+ private Long id;
+
+ /** 节点名称 */
+ private String label;
+
+ /** 子节点 */
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private List children;
+
+ public TreeSelect()
+ {
+
+ }
+
+ public TreeSelect(SysDept dept)
+ {
+ this.id = dept.getDeptId();
+ this.label = dept.getDeptName();
+ this.children = dept.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
+ }
+
+ public TreeSelect(SysMenu menu)
+ {
+ this.id = menu.getMenuId();
+ this.label = menu.getMenuName();
+ this.children = menu.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
+ }
+
+ public Long getId()
+ {
+ return id;
+ }
+
+ public void setId(Long id)
+ {
+ this.id = id;
+ }
+
+ public String getLabel()
+ {
+ return label;
+ }
+
+ public void setLabel(String label)
+ {
+ this.label = label;
+ }
+
+ public List getChildren()
+ {
+ return children;
+ }
+
+ public void setChildren(List children)
+ {
+ this.children = children;
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/entity/SysDept.java b/maibu-common/src/main/java/com/maibu/core/domain/entity/SysDept.java
new file mode 100644
index 0000000..d3348a0
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/entity/SysDept.java
@@ -0,0 +1,311 @@
+package com.maibu.core.domain.entity;
+
+import com.maibu.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 部门表 sys_dept
+ *
+ * @author ruoyi
+ */
+@ApiModel(value = "SysDept", description = "部门表 sys_dept")
+public class SysDept extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 部门ID */
+ @ApiModelProperty("部门ID")
+ private Long deptId;
+
+ /**
+ * 机构系统账号ID
+ */
+ private Long deptUserId;
+
+ /** 父部门ID */
+ @ApiModelProperty("父部门ID")
+ private Long parentId;
+
+ /** 祖级列表 */
+ @ApiModelProperty("祖级列表")
+ private String ancestors;
+
+ /** 部门名称 */
+ @ApiModelProperty("部门名称")
+ private String deptName;
+
+ /** 显示顺序 */
+ @ApiModelProperty("显示顺序")
+ private Integer orderNum;
+
+ /** 负责人 */
+ @ApiModelProperty("负责人")
+ private String leader;
+
+ /** 联系电话 */
+ @ApiModelProperty("联系电话")
+ private String phone;
+
+ /** 邮箱 */
+ @ApiModelProperty("邮箱")
+ private String email;
+
+ /** 部门状态:0正常,1停用 */
+ @ApiModelProperty("部门状态:0正常,1停用")
+ private String status;
+
+ /** 删除标志(0代表存在 2代表删除) */
+ @ApiModelProperty("删除标志(0代表存在 2代表删除)")
+ private String delFlag;
+
+ /** 父部门名称 */
+ @ApiModelProperty("父部门名称")
+ private String parentName;
+
+ /** 子部门 */
+ @ApiModelProperty("子部门")
+ private List children = new ArrayList();
+
+ /**
+ * 系统账号名称
+ */
+ private String userName;
+
+ /**
+ * 系统账号密码
+ */
+ private String password;
+
+ /**
+ * 确认密码
+ */
+ private String confirmPassword;
+
+ /**
+ * 机构类型
+ */
+ private Integer deptType;
+
+ public Boolean getShowOwner() {
+ return showOwner;
+ }
+
+ public void setShowOwner(Boolean showOwner) {
+ this.showOwner = showOwner;
+ }
+
+ /**
+ * 是否显示自己
+ */
+ private Boolean showOwner;
+
+ /**
+ * 管理员姓名
+ */
+ private String deptUserName;
+
+ public String getDeptUserName() {
+ return deptUserName;
+ }
+
+ public void setDeptUserName(String deptUserName) {
+ this.deptUserName = deptUserName;
+ }
+
+ public Integer getDeptType() {
+ return deptType;
+ }
+
+ public void setDeptType(Integer deptType) {
+ this.deptType = deptType;
+ }
+
+ 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 getConfirmPassword() {
+ return confirmPassword;
+ }
+
+ public void setConfirmPassword(String confirmPassword) {
+ this.confirmPassword = confirmPassword;
+ }
+
+ public Long getDeptUserId() {
+ return deptUserId;
+ }
+
+ public void setDeptUserId(Long deptUserId) {
+ this.deptUserId = deptUserId;
+ }
+
+ public Long getDeptId()
+ {
+ return deptId;
+ }
+
+ public void setDeptId(Long deptId)
+ {
+ this.deptId = deptId;
+ }
+
+ public Long getParentId()
+ {
+ return parentId;
+ }
+
+ public void setParentId(Long parentId)
+ {
+ this.parentId = parentId;
+ }
+
+ public String getAncestors()
+ {
+ return ancestors;
+ }
+
+ public void setAncestors(String ancestors)
+ {
+ this.ancestors = ancestors;
+ }
+
+ @NotBlank(message = "部门名称不能为空")
+ @Size(min = 0, max = 30, message = "部门名称长度不能超过30个字符")
+ public String getDeptName()
+ {
+ return deptName;
+ }
+
+ public void setDeptName(String deptName)
+ {
+ this.deptName = deptName;
+ }
+
+ @NotNull(message = "显示顺序不能为空")
+ public Integer getOrderNum()
+ {
+ return orderNum;
+ }
+
+ public void setOrderNum(Integer orderNum)
+ {
+ this.orderNum = orderNum;
+ }
+
+ public String getLeader()
+ {
+ return leader;
+ }
+
+ public void setLeader(String leader)
+ {
+ this.leader = leader;
+ }
+
+ @Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符")
+ public String getPhone()
+ {
+ return phone;
+ }
+
+ public void setPhone(String phone)
+ {
+ this.phone = phone;
+ }
+
+ @Email(message = "邮箱格式不正确")
+ @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
+ public String getEmail()
+ {
+ return email;
+ }
+
+ public void setEmail(String email)
+ {
+ this.email = email;
+ }
+
+ public String getStatus()
+ {
+ return status;
+ }
+
+ public void setStatus(String status)
+ {
+ this.status = status;
+ }
+
+ public String getDelFlag()
+ {
+ return delFlag;
+ }
+
+ public void setDelFlag(String delFlag)
+ {
+ this.delFlag = delFlag;
+ }
+
+ public String getParentName()
+ {
+ return parentName;
+ }
+
+ public void setParentName(String parentName)
+ {
+ this.parentName = parentName;
+ }
+
+ public List getChildren()
+ {
+ return children;
+ }
+
+ public void setChildren(List children)
+ {
+ this.children = children;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("deptId", getDeptId())
+ .append("deptUserId", getDeptUserId())
+ .append("parentId", getParentId())
+ .append("ancestors", getAncestors())
+ .append("deptName", getDeptName())
+ .append("orderNum", getOrderNum())
+ .append("leader", getLeader())
+ .append("phone", getPhone())
+ .append("email", getEmail())
+ .append("status", getStatus())
+ .append("delFlag", getDelFlag())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .toString();
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/entity/SysDictData.java b/maibu-common/src/main/java/com/maibu/core/domain/entity/SysDictData.java
new file mode 100644
index 0000000..b25b552
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/entity/SysDictData.java
@@ -0,0 +1,209 @@
+package com.maibu.core.domain.entity;
+
+import com.maibu.annotation.Excel;
+import com.maibu.constant.UserConstants;
+import com.maibu.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+
+/**
+ * 字典数据表 sys_dict_data
+ *
+ * @author ruoyi
+ */
+@Data
+@ApiModel(value = "SysDictData", description = "字典数据表 sys_dict_data")
+public class SysDictData extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 字典编码 */
+ @ApiModelProperty("字典编码")
+ @Excel(name = "字典编码", cellType = Excel.ColumnType.NUMERIC)
+ private Long dictCode;
+
+ /** 字典排序 */
+ @ApiModelProperty("字典排序")
+ @Excel(name = "字典排序", cellType = Excel.ColumnType.NUMERIC)
+ private Long dictSort;
+
+ /** 字典标签 */
+ @ApiModelProperty("字典标签")
+ @Excel(name = "字典标签")
+ private String dictLabel;
+
+ /** 字典标签 */
+ @ApiModelProperty("中文字典标签")
+ private String dictLabel_zh_CN;
+
+ /** 字典标签 */
+ @ApiModelProperty("英文字典标签")
+ private String dictLabel_en_US;
+
+ /** 字典键值 */
+ @ApiModelProperty("字典键值")
+ @Excel(name = "字典键值")
+ private String dictValue;
+
+ /** 字典类型 */
+ @ApiModelProperty("字典类型")
+ @Excel(name = "字典类型")
+ private String dictType;
+
+ /** 样式属性(其他样式扩展) */
+ @ApiModelProperty("样式属性(其他样式扩展)")
+ private String cssClass;
+
+ /** 表格字典样式 */
+ @ApiModelProperty("表格字典样式")
+ private String listClass;
+
+ /** 是否默认(Y是 N否) */
+ @ApiModelProperty("是否默认(Y是 N否)")
+ @Excel(name = "是否默认", readConverterExp = "Y=是,N=否")
+ private String isDefault;
+
+ /** 状态(0正常 1停用) */
+ @ApiModelProperty("状态(0正常 1停用)")
+ @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
+ private String status;
+
+ @Deprecated
+ private String language;
+
+ public Long getDictCode()
+ {
+ return dictCode;
+ }
+
+ public void setDictCode(Long dictCode)
+ {
+ this.dictCode = dictCode;
+ }
+
+ public Long getDictSort()
+ {
+ return dictSort;
+ }
+
+ public void setDictSort(Long dictSort)
+ {
+ this.dictSort = dictSort;
+ }
+
+ @NotBlank(message = "字典标签不能为空")
+ @Size(min = 0, max = 100, message = "字典标签长度不能超过100个字符")
+ public String getDictLabel()
+ {
+ return dictLabel;
+ }
+
+ public void setDictLabel(String dictLabel)
+ {
+ this.dictLabel = dictLabel;
+ }
+
+ @NotBlank(message = "字典键值不能为空")
+ @Size(min = 0, max = 100, message = "字典键值长度不能超过100个字符")
+ public String getDictValue()
+ {
+ return dictValue;
+ }
+
+ public void setDictValue(String dictValue)
+ {
+ this.dictValue = dictValue;
+ }
+
+ @NotBlank(message = "字典类型不能为空")
+ @Size(min = 0, max = 100, message = "字典类型长度不能超过100个字符")
+ public String getDictType()
+ {
+ return dictType;
+ }
+
+ public void setDictType(String dictType)
+ {
+ this.dictType = dictType;
+ }
+
+ @Size(min = 0, max = 100, message = "样式属性长度不能超过100个字符")
+ public String getCssClass()
+ {
+ return cssClass;
+ }
+
+ public void setCssClass(String cssClass)
+ {
+ this.cssClass = cssClass;
+ }
+
+ public String getListClass()
+ {
+ return listClass;
+ }
+
+ public void setListClass(String listClass)
+ {
+ this.listClass = listClass;
+ }
+
+ public boolean getDefault()
+ {
+ return UserConstants.YES.equals(this.isDefault);
+ }
+
+ public String getIsDefault()
+ {
+ return isDefault;
+ }
+
+ public void setIsDefault(String isDefault)
+ {
+ this.isDefault = isDefault;
+ }
+
+ public String getStatus()
+ {
+ return status;
+ }
+
+ public void setStatus(String status)
+ {
+ this.status = status;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("dictCode", getDictCode())
+ .append("dictSort", getDictSort())
+ .append("dictLabel", getDictLabel())
+ .append("dictValue", getDictValue())
+ .append("dictType", getDictType())
+ .append("cssClass", getCssClass())
+ .append("listClass", getListClass())
+ .append("isDefault", getIsDefault())
+ .append("status", getStatus())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .append("remark", getRemark())
+ .toString();
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/entity/SysDictType.java b/maibu-common/src/main/java/com/maibu/core/domain/entity/SysDictType.java
new file mode 100644
index 0000000..b7ada3d
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/entity/SysDictType.java
@@ -0,0 +1,117 @@
+package com.maibu.core.domain.entity;
+
+import com.maibu.annotation.Excel;
+import com.maibu.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+
+/**
+ * 字典类型表 sys_dict_type
+ *
+ * @author ruoyi
+ */
+@ApiModel(value = "SysDictType", description = "字典类型表 sys_dict_type")
+public class SysDictType extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 字典主键 */
+ @ApiModelProperty("字典主键")
+ @Excel(name = "字典主键", cellType = Excel.ColumnType.NUMERIC)
+ private Long dictId;
+
+ /** 字典名称 */
+ @ApiModelProperty("字典名称")
+ @Excel(name = "字典名称")
+ private String dictName;
+
+ /** 字典类型 */
+ @ApiModelProperty("字典类型")
+ @Excel(name = "字典类型")
+ private String dictType;
+
+ /** 状态(0正常 1停用) */
+ @ApiModelProperty("状态(0正常 1停用)")
+ @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
+ private String status;
+
+ @Deprecated
+ private String language;
+
+
+ public Long getDictId()
+ {
+ return dictId;
+ }
+
+ public void setDictId(Long dictId)
+ {
+ this.dictId = dictId;
+ }
+
+ @NotBlank(message = "字典名称不能为空")
+ @Size(min = 0, max = 100, message = "字典类型名称长度不能超过100个字符")
+ public String getDictName()
+ {
+ return dictName;
+ }
+
+ public void setDictName(String dictName)
+ {
+ this.dictName = dictName;
+ }
+
+ @NotBlank(message = "字典类型不能为空")
+ @Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符")
+ @Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)")
+ public String getDictType()
+ {
+ return dictType;
+ }
+
+ public void setDictType(String dictType)
+ {
+ this.dictType = dictType;
+ }
+
+ public String getStatus()
+ {
+ return status;
+ }
+
+ public void setStatus(String status)
+ {
+ this.status = status;
+ }
+
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("dictId", getDictId())
+ .append("dictName", getDictName())
+ .append("dictType", getDictType())
+ .append("status", getStatus())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .append("remark", getRemark())
+ .toString();
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/entity/SysMenu.java b/maibu-common/src/main/java/com/maibu/core/domain/entity/SysMenu.java
new file mode 100644
index 0000000..5c54ece
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/entity/SysMenu.java
@@ -0,0 +1,305 @@
+package com.maibu.core.domain.entity;
+
+import com.maibu.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 菜单权限表 sys_menu
+ *
+ * @author ruoyi
+ */
+@ApiModel(value = "SysMenu", description = "菜单权限表 sys_menu")
+public class SysMenu extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 菜单ID */
+ @ApiModelProperty("菜单ID")
+ private Long menuId;
+
+ /** 菜单名称 */
+ @ApiModelProperty("菜单名称")
+ private String menuName;
+
+ /** 父菜单名称 */
+ @ApiModelProperty("父菜单名称")
+ private String parentName;
+
+ /** 父菜单ID */
+ @ApiModelProperty("父菜单ID")
+ private Long parentId;
+
+ /** 显示顺序 */
+ @ApiModelProperty("显示顺序")
+ private Integer orderNum;
+
+ /** 路由地址 */
+ @ApiModelProperty("路由地址")
+ private String path;
+
+ /** 组件路径 */
+ @ApiModelProperty("组件路径")
+ private String component;
+
+ /** 路由参数 */
+ @ApiModelProperty("路由参数")
+ private String query;
+
+ /** 是否为外链(0是 1否) */
+ @ApiModelProperty("是否为外链(0是 1否)")
+ private String isFrame;
+
+ /** 是否缓存(0缓存 1不缓存) */
+ @ApiModelProperty("是否缓存(0缓存 1不缓存)")
+ private String isCache;
+
+ /** 类型(M目录 C菜单 F按钮) */
+ @ApiModelProperty("类型(M目录 C菜单 F按钮)")
+ private String menuType;
+
+ /** 显示状态(0显示 1隐藏) */
+ @ApiModelProperty("显示状态(0显示 1隐藏)")
+ private String visible;
+
+ /** 菜单状态(0正常 1停用) */
+ @ApiModelProperty("菜单状态(0正常 1停用)")
+ private String status;
+
+ /** 权限字符串 */
+ @ApiModelProperty("权限字符串")
+ private String perms;
+
+ /** 菜单图标 */
+ @ApiModelProperty("菜单图标")
+ private String icon;
+
+ /** 子菜单 */
+ @ApiModelProperty("子菜单")
+ private List children = new ArrayList();
+
+ /**
+ * 部门id
+ */
+ private Long deptId;
+
+ /** 菜单语言 */
+ @Deprecated
+ private String language;
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+
+ public Long getDeptId() {
+ return deptId;
+ }
+
+ public void setDeptId(Long deptId) {
+ this.deptId = deptId;
+ }
+
+ public Long getMenuId()
+ {
+ return menuId;
+ }
+
+ public void setMenuId(Long menuId)
+ {
+ this.menuId = menuId;
+ }
+
+ @NotBlank(message = "菜单名称不能为空")
+ @Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符")
+ public String getMenuName()
+ {
+ return menuName;
+ }
+
+ public void setMenuName(String menuName)
+ {
+ this.menuName = menuName;
+ }
+
+ public String getParentName()
+ {
+ return parentName;
+ }
+
+ public void setParentName(String parentName)
+ {
+ this.parentName = parentName;
+ }
+
+ public Long getParentId()
+ {
+ return parentId;
+ }
+
+ public void setParentId(Long parentId)
+ {
+ this.parentId = parentId;
+ }
+
+ @NotNull(message = "显示顺序不能为空")
+ public Integer getOrderNum()
+ {
+ return orderNum;
+ }
+
+ public void setOrderNum(Integer orderNum)
+ {
+ this.orderNum = orderNum;
+ }
+
+ @Size(min = 0, max = 200, message = "路由地址不能超过200个字符")
+ public String getPath()
+ {
+ return path;
+ }
+
+ public void setPath(String path)
+ {
+ this.path = path;
+ }
+
+ @Size(min = 0, max = 200, message = "组件路径不能超过255个字符")
+ public String getComponent()
+ {
+ return component;
+ }
+
+ public void setComponent(String component)
+ {
+ this.component = component;
+ }
+
+ public String getQuery()
+ {
+ return query;
+ }
+
+ public void setQuery(String query)
+ {
+ this.query = query;
+ }
+
+ public String getIsFrame()
+ {
+ return isFrame;
+ }
+
+ public void setIsFrame(String isFrame)
+ {
+ this.isFrame = isFrame;
+ }
+
+ public String getIsCache()
+ {
+ return isCache;
+ }
+
+ public void setIsCache(String isCache)
+ {
+ this.isCache = isCache;
+ }
+
+ @NotBlank(message = "菜单类型不能为空")
+ public String getMenuType()
+ {
+ return menuType;
+ }
+
+ public void setMenuType(String menuType)
+ {
+ this.menuType = menuType;
+ }
+
+ public String getVisible()
+ {
+ return visible;
+ }
+
+ public void setVisible(String visible)
+ {
+ this.visible = visible;
+ }
+
+ public String getStatus()
+ {
+ return status;
+ }
+
+ public void setStatus(String status)
+ {
+ this.status = status;
+ }
+
+ @Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符")
+ public String getPerms()
+ {
+ return perms;
+ }
+
+ public void setPerms(String perms)
+ {
+ this.perms = perms;
+ }
+
+ public String getIcon()
+ {
+ return icon;
+ }
+
+ public void setIcon(String icon)
+ {
+ this.icon = icon;
+ }
+
+ public List getChildren()
+ {
+ return children;
+ }
+
+ public void setChildren(List children)
+ {
+ this.children = children;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("menuId", getMenuId())
+ .append("menuName", getMenuName())
+ .append("parentId", getParentId())
+ .append("orderNum", getOrderNum())
+ .append("path", getPath())
+ .append("component", getComponent())
+ .append("isFrame", getIsFrame())
+ .append("IsCache", getIsCache())
+ .append("menuType", getMenuType())
+ .append("visible", getVisible())
+ .append("status ", getStatus())
+ .append("perms", getPerms())
+ .append("icon", getIcon())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .append("remark", getRemark())
+ .toString();
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/entity/SysRole.java b/maibu-common/src/main/java/com/maibu/core/domain/entity/SysRole.java
new file mode 100644
index 0000000..61cf2b9
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/entity/SysRole.java
@@ -0,0 +1,321 @@
+package com.maibu.core.domain.entity;
+
+import com.maibu.annotation.Excel;
+import com.maibu.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.Set;
+
+/**
+ * 角色表 sys_role
+ *
+ * @author ruoyi
+ */
+@ApiModel(value = "SysRole", description = "角色表 sys_role")
+public class SysRole extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 角色ID */
+ @ApiModelProperty("角色ID")
+ @Excel(name = "角色序号", cellType = Excel.ColumnType.NUMERIC)
+ private Long roleId;
+
+ /** 角色名称 */
+ @ApiModelProperty("角色名称")
+ @Excel(name = "角色名称")
+ private String roleName;
+
+ /** 角色权限 */
+ @ApiModelProperty("角色权限")
+ @Excel(name = "角色权限")
+ private String roleKey;
+
+ /** 角色排序 */
+ @ApiModelProperty("角色排序")
+ @Excel(name = "角色排序")
+ private Integer roleSort;
+
+ /** 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) */
+ @ApiModelProperty(value = "数据范围", notes = "(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限)")
+ @Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限")
+ private String dataScope;
+
+ /** 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示) */
+ @ApiModelProperty(value = "菜单树选择项是否关联显示", notes = "( 0:父子不互相关联显示 1:父子互相关联显示)")
+ private boolean menuCheckStrictly;
+
+ /** 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 ) */
+ @ApiModelProperty(value = "部门树选择项是否关联显示", notes = "(0:父子不互相关联显示 1:父子互相关联显示 )")
+ private boolean deptCheckStrictly;
+
+ /** 角色状态(0正常 1停用) */
+ @ApiModelProperty("角色状态(0正常 1停用)")
+ @Excel(name = "角色状态", readConverterExp = "0=正常,1=停用")
+ private String status;
+
+ /** 删除标志(0代表存在 2代表删除) */
+ @ApiModelProperty("删除标志")
+ private String delFlag;
+
+ /** 用户是否存在此角色标识 默认不存在 */
+ private boolean flag = false;
+
+ /** 菜单组 */
+ @ApiModelProperty("菜单组")
+ private Long[] menuIds;
+
+ /** 部门组(数据权限) */
+ @ApiModelProperty("部门组")
+ private Long[] deptIds;
+
+ /** 角色菜单权限 */
+ @ApiModelProperty("角色菜单权限")
+ private Set permissions;
+
+ /**
+ * 部门id
+ */
+ private Long deptId;
+
+ /**
+ * 部门名称
+ */
+ private String deptName;
+
+ /**
+ * 是否显示下级机构数据
+ */
+ private Boolean showChild;
+
+ /**
+ * 是否可以修改用户角色
+ */
+ private Boolean canEditRole;
+
+ /**
+ * 是否是机构管理员角色
+ */
+ private Boolean manager;
+
+ public Boolean getManager() {
+ return manager;
+ }
+
+ public void setManager(Boolean manager) {
+ this.manager = manager;
+ }
+
+ public Boolean getCanEditRole() {
+ return canEditRole;
+ }
+
+ public void setCanEditRole(Boolean canEditRole) {
+ this.canEditRole = canEditRole;
+ }
+
+ public Boolean getShowChild() {
+ return showChild;
+ }
+
+ public void setShowChild(Boolean showChild) {
+ this.showChild = showChild;
+ }
+
+ public Long getDeptId() {
+ return deptId;
+ }
+
+ public void setDeptId(Long deptId) {
+ this.deptId = deptId;
+ }
+
+ public String getDeptName() {
+ return deptName;
+ }
+
+ public void setDeptName(String deptName) {
+ this.deptName = deptName;
+ }
+
+ public SysRole()
+ {
+
+ }
+
+ public SysRole(Long roleId)
+ {
+ this.roleId = roleId;
+ }
+
+ public Long getRoleId()
+ {
+ return roleId;
+ }
+
+ public void setRoleId(Long roleId)
+ {
+ this.roleId = roleId;
+ }
+
+ public boolean isAdmin()
+ {
+ return isAdmin(this.roleId);
+ }
+
+ public static boolean isAdmin(Long roleId)
+ {
+ return roleId != null && 1L == roleId;
+ }
+
+ @NotBlank(message = "角色名称不能为空")
+ @Size(min = 0, max = 30, message = "角色名称长度不能超过30个字符")
+ public String getRoleName()
+ {
+ return roleName;
+ }
+
+ public void setRoleName(String roleName)
+ {
+ this.roleName = roleName;
+ }
+
+ @NotBlank(message = "权限字符不能为空")
+ @Size(min = 0, max = 100, message = "权限字符长度不能超过100个字符")
+ public String getRoleKey()
+ {
+ return roleKey;
+ }
+
+ public void setRoleKey(String roleKey)
+ {
+ this.roleKey = roleKey;
+ }
+
+ @NotNull(message = "显示顺序不能为空")
+ public Integer getRoleSort()
+ {
+ return roleSort;
+ }
+
+ public void setRoleSort(Integer roleSort)
+ {
+ this.roleSort = roleSort;
+ }
+
+ public String getDataScope()
+ {
+ return dataScope;
+ }
+
+ public void setDataScope(String dataScope)
+ {
+ this.dataScope = dataScope;
+ }
+
+ public boolean isMenuCheckStrictly()
+ {
+ return menuCheckStrictly;
+ }
+
+ public void setMenuCheckStrictly(boolean menuCheckStrictly)
+ {
+ this.menuCheckStrictly = menuCheckStrictly;
+ }
+
+ public boolean isDeptCheckStrictly()
+ {
+ return deptCheckStrictly;
+ }
+
+ public void setDeptCheckStrictly(boolean deptCheckStrictly)
+ {
+ this.deptCheckStrictly = deptCheckStrictly;
+ }
+
+ public String getStatus()
+ {
+ return status;
+ }
+
+ public void setStatus(String status)
+ {
+ this.status = status;
+ }
+
+ public String getDelFlag()
+ {
+ return delFlag;
+ }
+
+ public void setDelFlag(String delFlag)
+ {
+ this.delFlag = delFlag;
+ }
+
+ public boolean isFlag()
+ {
+ return flag;
+ }
+
+ public void setFlag(boolean flag)
+ {
+ this.flag = flag;
+ }
+
+ public Long[] getMenuIds()
+ {
+ return menuIds;
+ }
+
+ public void setMenuIds(Long[] menuIds)
+ {
+ this.menuIds = menuIds;
+ }
+
+ public Long[] getDeptIds()
+ {
+ return deptIds;
+ }
+
+ public void setDeptIds(Long[] deptIds)
+ {
+ this.deptIds = deptIds;
+ }
+
+ public Set getPermissions()
+ {
+ return permissions;
+ }
+
+ public void setPermissions(Set permissions)
+ {
+ this.permissions = permissions;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("roleId", getRoleId())
+ .append("roleName", getRoleName())
+ .append("roleKey", getRoleKey())
+ .append("roleSort", getRoleSort())
+ .append("dataScope", getDataScope())
+ .append("menuCheckStrictly", isMenuCheckStrictly())
+ .append("deptCheckStrictly", isDeptCheckStrictly())
+ .append("status", getStatus())
+ .append("delFlag", getDelFlag())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .append("remark", getRemark())
+ .toString();
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/entity/SysTranslate.java b/maibu-common/src/main/java/com/maibu/core/domain/entity/SysTranslate.java
new file mode 100644
index 0000000..d946a85
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/entity/SysTranslate.java
@@ -0,0 +1,34 @@
+package com.maibu.core.domain.entity;
+
+import com.maibu.annotation.Excel;
+import com.maibu.core.domain.BaseEntity;
+import lombok.Data;
+
+/**
+ * 翻译对象 sys_translate
+ *
+ * @author ruoyi
+ */
+@Data
+public class SysTranslate extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** ID */
+ @Excel(name = "ID")
+ private Long id;
+
+ /** zh_CN */
+ @Excel(name = "zh-CN")
+ private String zh_CN;
+
+ /** en_US */
+ @Excel(name = "en-US")
+ private String en_US;
+
+ /** 物模型翻译表使用 */
+ private Long productId;
+
+ private String tableName;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/entity/SysUser.java b/maibu-common/src/main/java/com/maibu/core/domain/entity/SysUser.java
new file mode 100644
index 0000000..e62200f
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/entity/SysUser.java
@@ -0,0 +1,426 @@
+package com.maibu.core.domain.entity;
+
+import com.maibu.annotation.Excel;
+import com.maibu.annotation.Excels;
+import com.maibu.core.domain.BaseEntity;
+import com.maibu.xss.Xss;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.*;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 用户对象 sys_user
+ *
+ * @author ruoyi
+ */
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "SysUser", description = "用户对象 sys_user")
+@Data
+public class SysUser extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 用户ID
+ */
+ @ApiModelProperty("用户ID")
+ @Excel(name = "用户序号", cellType = Excel.ColumnType.NUMERIC, prompt = "用户编号")
+ private Long userId;
+
+ /**
+ * 部门ID
+ */
+ @ApiModelProperty("部门ID")
+ @Excel(name = "部门编号", type = Excel.Type.IMPORT)
+ private Long deptId;
+
+ /**
+ * 用户账号
+ */
+ @ApiModelProperty("用户账号")
+ @Excel(name = "登录名称")
+ private String userName;
+
+ /**
+ * 用户昵称
+ */
+ @ApiModelProperty("用户昵称")
+ @Excel(name = "用户名称")
+ private String nickName;
+
+ /**
+ * 用户邮箱
+ */
+ @ApiModelProperty("用户邮箱")
+ @Excel(name = "用户邮箱")
+ private String email;
+
+ /**
+ * 手机号码
+ */
+ @ApiModelProperty("手机号码")
+ @Excel(name = "手机号码")
+ private String phonenumber;
+
+ /**
+ * 用户性别
+ */
+ @ApiModelProperty("用户性别")
+ @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")
+ private String sex;
+
+ /**
+ * 用户头像
+ */
+ @ApiModelProperty("用户头像")
+ private String avatar;
+
+ /**
+ * 密码
+ */
+ @ApiModelProperty("密码")
+ private String password;
+
+
+ private String displayPassword;
+
+ /**
+ * 帐号状态(0正常 1停用)
+ */
+ @ApiModelProperty("帐号状态(0正常 1停用)")
+ @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")
+ private String status;
+
+ /**
+ * 删除标志(0代表存在 2代表删除)
+ */
+ @ApiModelProperty("删除标志")
+ private String delFlag;
+
+ /**
+ * 最后登录IP
+ */
+ @ApiModelProperty("最后登录IP")
+ @Excel(name = "最后登录IP", type = Excel.Type.EXPORT)
+ private String loginIp;
+
+ /**
+ * 最后登录时间
+ */
+ @ApiModelProperty("最后登录时间")
+ @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Excel.Type.EXPORT)
+ private Date loginDate;
+
+ /**
+ * 部门对象
+ */
+ @ApiModelProperty("部门对象")
+ @Excels({
+ @Excel(name = "部门名称", targetAttr = "deptName", type = Excel.Type.EXPORT),
+ @Excel(name = "部门负责人", targetAttr = "leader", type = Excel.Type.EXPORT)
+ })
+ private SysDept dept;
+
+ /**
+ * 角色对象
+ */
+ @ApiModelProperty("角色对象")
+ private List roles;
+
+ /**
+ * 角色组
+ */
+ @ApiModelProperty("角色组")
+ private Long[] roleIds;
+
+ /**
+ * 岗位组
+ */
+ @ApiModelProperty("岗位组")
+ private Long[] postIds;
+
+ /**
+ * 角色ID
+ */
+ @ApiModelProperty("角色ID")
+ private Long roleId;
+
+ /**
+ * 用,拼接的角色名称
+ */
+ @ApiModelProperty("用,拼接的角色名称")
+ private String roleNames;
+
+ /**
+ * 用,拼接的角色名称
+ */
+ @ApiModelProperty("sessionId")
+ private String sessionId;
+
+ /**
+ * 微信openid
+ */
+ private String openId;
+
+ /**
+ * 是否显示下级机构数据
+ */
+ private Boolean showChild;
+
+ /**
+ * 是否是机构管理员
+ */
+ private Boolean manager;
+ /**
+ * 语言
+ */
+ private String language;
+ /**
+ * 时区
+ */
+ private String timeZone;
+
+ /**
+ * ai助手问答使用条数
+ */
+ private Integer aiChatNum;
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public String getTimeZone() {
+ return timeZone;
+ }
+
+ public void setTimeZone(String timeZone) {
+ this.timeZone = timeZone;
+ }
+
+ public Boolean getManager() {
+ return manager;
+ }
+
+ public void setManager(Boolean manager) {
+ this.manager = manager;
+ }
+
+ public Boolean getShowChild() {
+ return showChild;
+ }
+
+ public void setShowChild(Boolean showChild) {
+ this.showChild = showChild;
+ }
+
+ public SysUser() {
+
+ }
+
+ public SysUser(Long userId) {
+ this.userId = userId;
+ }
+
+ public Long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Long userId) {
+ this.userId = userId;
+ }
+
+ public boolean isAdmin() {
+ return isAdmin(this.userId);
+ }
+
+ public static boolean isAdmin(Long userId) {
+ return userId != null && 1L == userId;
+ }
+
+ public Long getDeptId() {
+ return deptId;
+ }
+
+ public void setDeptId(Long deptId) {
+ this.deptId = deptId;
+ }
+
+ @Xss(message = "用户昵称不能包含脚本字符")
+ @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
+ public String getNickName() {
+ return nickName;
+ }
+
+ public void setNickName(String nickName) {
+ this.nickName = nickName;
+ }
+
+ @Xss(message = "用户账号不能包含脚本字符")
+ @NotBlank(message = "用户账号不能为空")
+ @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ @Email(message = "邮箱格式不正确")
+ @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ @Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符")
+ public String getPhonenumber() {
+ return phonenumber;
+ }
+
+ public void setPhonenumber(String phonenumber) {
+ this.phonenumber = phonenumber;
+ }
+
+ public String getSex() {
+ return sex;
+ }
+
+ public void setSex(String sex) {
+ this.sex = sex;
+ }
+
+ public String getAvatar() {
+ return avatar;
+ }
+
+ public void setAvatar(String avatar) {
+ this.avatar = avatar;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getDelFlag() {
+ return delFlag;
+ }
+
+ public void setDelFlag(String delFlag) {
+ this.delFlag = delFlag;
+ }
+
+ public String getLoginIp() {
+ return loginIp;
+ }
+
+ public void setLoginIp(String loginIp) {
+ this.loginIp = loginIp;
+ }
+
+ public Date getLoginDate() {
+ return loginDate;
+ }
+
+ public void setLoginDate(Date loginDate) {
+ this.loginDate = loginDate;
+ }
+
+ public SysDept getDept() {
+ return dept;
+ }
+
+ public void setDept(SysDept dept) {
+ this.dept = dept;
+ }
+
+ public List getRoles() {
+ return roles;
+ }
+
+ public void setRoles(List roles) {
+ this.roles = roles;
+ }
+
+ public Long[] getRoleIds() {
+ return roleIds;
+ }
+
+ public void setRoleIds(Long[] roleIds) {
+ this.roleIds = roleIds;
+ }
+
+ public Long[] getPostIds() {
+ return postIds;
+ }
+
+ public void setPostIds(Long[] postIds) {
+ this.postIds = postIds;
+ }
+
+ public Long getRoleId() {
+ return roleId;
+ }
+
+ public void setRoleId(Long roleId) {
+ this.roleId = roleId;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ .append("userId", getUserId())
+ .append("deptId", getDeptId())
+ .append("userName", getUserName())
+ .append("nickName", getNickName())
+ .append("email", getEmail())
+ .append("phonenumber", getPhonenumber())
+ .append("sex", getSex())
+ .append("avatar", getAvatar())
+ .append("password", getPassword())
+ .append("status", getStatus())
+ .append("delFlag", getDelFlag())
+ .append("loginIp", getLoginIp())
+ .append("loginDate", getLoginDate())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .append("remark", getRemark())
+ .append("dept", getDept())
+ .toString();
+ }
+
+ public String getRoleNames() {
+ return roleNames;
+ }
+
+ public void setRoleNames(String roleNames) {
+ this.roleNames = roleNames;
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/entity/UserClient.java b/maibu-common/src/main/java/com/maibu/core/domain/entity/UserClient.java
new file mode 100644
index 0000000..31d663c
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/entity/UserClient.java
@@ -0,0 +1,24 @@
+package com.maibu.core.domain.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+@Data
+@TableName("sys_user_client")
+public class UserClient {
+
+ private static final long serialVersionUID = 1L;
+
+ private Long clientId;
+
+ private Long userId;
+
+ private String userName;
+
+ private String clientName;
+
+ private String deviceName;
+
+ private int isAlive;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/model/BindLoginBody.java b/maibu-common/src/main/java/com/maibu/core/domain/model/BindLoginBody.java
new file mode 100644
index 0000000..b464ccd
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/model/BindLoginBody.java
@@ -0,0 +1,22 @@
+package com.maibu.core.domain.model;
+
+/**
+ * 用户登录对象
+ *
+ * @author ruoyi
+ */
+public class BindLoginBody extends LoginBody
+{
+ /**
+ * 绑定id
+ */
+ private String bindId;
+
+ public String getBindId() {
+ return bindId;
+ }
+
+ public void setBindId(String bindId) {
+ this.bindId = bindId;
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/model/BindRegisterBody.java b/maibu-common/src/main/java/com/maibu/core/domain/model/BindRegisterBody.java
new file mode 100644
index 0000000..e84b75a
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/model/BindRegisterBody.java
@@ -0,0 +1,21 @@
+package com.maibu.core.domain.model;
+
+/**
+ * 用户注册对象
+ *
+ * @author ruoyi
+ */
+public class BindRegisterBody extends RegisterBody {
+ /**
+ * 绑定id
+ */
+ private String bindId;
+
+ public String getBindId() {
+ return bindId;
+ }
+
+ public void setBindId(String bindId) {
+ this.bindId = bindId;
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/model/LoginBody.java b/maibu-common/src/main/java/com/maibu/core/domain/model/LoginBody.java
new file mode 100644
index 0000000..58d5bb8
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/model/LoginBody.java
@@ -0,0 +1,67 @@
+package com.maibu.core.domain.model;
+
+import lombok.Data;
+
+/**
+ * 用户登录对象
+ *
+ * @author ruoyi
+ */
+@Data
+public class LoginBody {
+
+ /**
+ * 用户id
+ */
+ private Long userId;
+ /**
+ * 用户名
+ */
+ private String username;
+
+ /**
+ * 用户密码
+ */
+ private String password;
+
+ /**
+ * 验证码
+ */
+ private String code;
+
+ /**
+ * 唯一标识 app端是手机地址出厂id
+ */
+ private String uuid;
+
+ /**
+ * 手机号 三方
+ */
+ private String phonenumber;
+ /**
+ * 微信openId 三方
+ */
+ private String openId;
+
+ /**
+ * 登录平台 1-web端;2-app 3-PC端
+ */
+ private Integer sourceType;
+
+ /**
+ * 登录平台 1-账号密码 2-公众号;3-手机号;4-微信 不传或者是null 默认账号密码
+ */
+ private Integer loginPlatForm = 1;
+
+ /**
+ * 短信验证码
+ */
+ private String smsCode;
+
+
+ /**
+ * sessionId
+ */
+ private String sessionId;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/model/LoginUser.java b/maibu-common/src/main/java/com/maibu/core/domain/model/LoginUser.java
new file mode 100644
index 0000000..d7257cf
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/model/LoginUser.java
@@ -0,0 +1,278 @@
+package com.maibu.core.domain.model;
+
+import com.alibaba.fastjson2.annotation.JSONField;
+import com.maibu.core.domain.entity.SysUser;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * 登录用户身份权限
+ *
+ * @author ruoyi
+ */
+public class LoginUser implements UserDetails {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 用户ID
+ */
+ private Long userId;
+
+ /**
+ * 部门ID
+ */
+ private Long deptId;
+
+ /**
+ * 用户唯一标识
+ */
+ private String token;
+
+ /**
+ * 登录时间
+ */
+ private Long loginTime;
+
+ /**
+ * 过期时间
+ */
+ private Long expireTime;
+
+ /**
+ * 登录IP地址
+ */
+ private String ipaddr;
+
+ /**
+ * 登录地点
+ */
+ private String loginLocation;
+
+ /**
+ * 浏览器类型
+ */
+ private String browser;
+
+ /**
+ * 操作系统
+ */
+ private String os;
+
+ /**
+ * 权限列表
+ */
+ private Set permissions;
+
+ /**
+ * 用户信息
+ */
+ private SysUser user;
+
+ private String language;
+
+ private Long deptUserId;
+
+ private Boolean neverExpire = Boolean.FALSE;
+
+ /**
+ * 登录平台 1-web端;2-app 3-PC端
+ */
+ private Integer sourceType;
+
+ public Integer getSourceType() {
+ return sourceType;
+ }
+
+ public void setSourceType(Integer s) {
+ this.sourceType = s;
+ }
+
+ public Boolean getNeverExpire() {
+ return neverExpire;
+ }
+
+ public void setNeverExpire(Boolean neverExpire) {
+ this.neverExpire = neverExpire;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public Long getDeptUserId() {
+ return deptUserId;
+ }
+
+ public void setDeptUserId(Long deptUserId) {
+ this.deptUserId = deptUserId;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public Long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Long userId) {
+ this.userId = userId;
+ }
+
+ public Long getDeptId() {
+ return deptId;
+ }
+
+ public void setDeptId(Long deptId) {
+ this.deptId = deptId;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ public void setToken(String token) {
+ this.token = token;
+ }
+
+ public LoginUser() {
+ }
+
+ public LoginUser(SysUser user, Set permissions) {
+ this.user = user;
+ this.permissions = permissions;
+ }
+
+ public LoginUser(Long userId, Long deptId, String language, SysUser user, Set permissions) {
+ this.userId = userId;
+ this.deptId = deptId;
+ this.user = user;
+ this.language = language;
+ this.permissions = permissions;
+ }
+
+ @JSONField(serialize = false)
+ @Override
+ public String getPassword() {
+ return user.getPassword();
+ }
+
+ @Override
+ public String getUsername() {
+ return user.getUserName();
+ }
+
+ /**
+ * 账户是否未过期,过期无法验证
+ */
+ @JSONField(serialize = false)
+ @Override
+ public boolean isAccountNonExpired() {
+ return true;
+ }
+
+ /**
+ * 指定用户是否解锁,锁定的用户无法进行身份验证
+ *
+ * @return
+ */
+ @JSONField(serialize = false)
+ @Override
+ public boolean isAccountNonLocked() {
+ return true;
+ }
+
+ /**
+ * 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
+ *
+ * @return
+ */
+ @JSONField(serialize = false)
+ @Override
+ public boolean isCredentialsNonExpired() {
+ return true;
+ }
+
+ /**
+ * 是否可用 ,禁用的用户不能身份验证
+ *
+ * @return
+ */
+ @JSONField(serialize = false)
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+
+ public Long getLoginTime() {
+ return loginTime;
+ }
+
+ public void setLoginTime(Long loginTime) {
+ this.loginTime = loginTime;
+ }
+
+ public String getIpaddr() {
+ return ipaddr;
+ }
+
+ public void setIpaddr(String ipaddr) {
+ this.ipaddr = ipaddr;
+ }
+
+ public String getLoginLocation() {
+ return loginLocation;
+ }
+
+ public void setLoginLocation(String loginLocation) {
+ this.loginLocation = loginLocation;
+ }
+
+ public String getBrowser() {
+ return browser;
+ }
+
+ public void setBrowser(String browser) {
+ this.browser = browser;
+ }
+
+ public String getOs() {
+ return os;
+ }
+
+ public void setOs(String os) {
+ this.os = os;
+ }
+
+ public Long getExpireTime() {
+ return expireTime;
+ }
+
+ public void setExpireTime(Long expireTime) {
+ this.expireTime = expireTime;
+ }
+
+ public Set getPermissions() {
+ return permissions;
+ }
+
+ public void setPermissions(Set permissions) {
+ this.permissions = permissions;
+ }
+
+ public SysUser getUser() {
+ return user;
+ }
+
+ public void setUser(SysUser user) {
+ this.user = user;
+ }
+
+ @Override
+ public Collection extends GrantedAuthority> getAuthorities() {
+ return null;
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/domain/model/RegisterBody.java b/maibu-common/src/main/java/com/maibu/core/domain/model/RegisterBody.java
new file mode 100644
index 0000000..74e637a
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/domain/model/RegisterBody.java
@@ -0,0 +1,19 @@
+package com.maibu.core.domain.model;
+
+/**
+ * 用户注册对象
+ *
+ * @author ruoyi
+ */
+public class RegisterBody extends LoginBody
+{
+ private String email;
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/iot/response/DashDeviceTotalDto.java b/maibu-common/src/main/java/com/maibu/core/iot/response/DashDeviceTotalDto.java
new file mode 100644
index 0000000..e7cb5fe
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/iot/response/DashDeviceTotalDto.java
@@ -0,0 +1,22 @@
+package com.maibu.core.iot.response;
+
+import lombok.Data;
+
+/**
+ * 大屏设备总览数据
+ * @author bill
+ */
+@Data
+public class DashDeviceTotalDto {
+
+ /*设备总数*/
+ private Integer total;
+ /*在线设备总数*/
+ private Integer onlineCount;
+ /*离线设备总数*/
+ private Integer OfflineCount;
+ /*未激活设备数*/
+ private Integer unActiveCount;
+
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/iot/response/DeCodeBo.java b/maibu-common/src/main/java/com/maibu/core/iot/response/DeCodeBo.java
new file mode 100644
index 0000000..ed10181
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/iot/response/DeCodeBo.java
@@ -0,0 +1,26 @@
+package com.maibu.core.iot.response;
+
+import lombok.Data;
+
+/**
+ * @author gsb
+ * @date 2023/4/8 15:43
+ */
+@Data
+public class DeCodeBo {
+
+ /**原始报文*/
+ private String payload;
+ /**从机编号*/
+ private Integer slaveId;
+ /**寄存器地址*/
+ private Integer address;
+ /**功能码*/
+ private Integer code;
+ /**读取个数*/
+ private Integer count;
+ /**写入值*/
+ private Integer writeData;
+ /**读写类型 1-解析 2-读指令 3-写指令 */
+ private Integer type;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/iot/response/IdentityAndName.java b/maibu-common/src/main/java/com/maibu/core/iot/response/IdentityAndName.java
new file mode 100644
index 0000000..480bdcc
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/iot/response/IdentityAndName.java
@@ -0,0 +1,70 @@
+package com.maibu.core.iot.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 物模型值的项
+ *
+ * @author kerwincui
+ * @date 2021-12-16
+ */
+@NoArgsConstructor
+@AllArgsConstructor
+@Data
+public class IdentityAndName
+{
+
+ public IdentityAndName(String id,String value){
+ this.id=id;
+ this.value=value;
+ }
+
+ public IdentityAndName(String id,Integer isHistory){
+ this.id=id;
+ this.isHistory=isHistory;
+ }
+
+ public IdentityAndName(String id, Integer isHistory, String specs, String name, Integer type){
+ this.id = id;
+ this.isHistory = isHistory;
+ this.dataType = specs;
+ this.name = name;
+ this.type = type;
+ }
+
+ /** 物模型唯一标识符 */
+ private String id;
+ /** 物模型值 */
+ private Object value;
+
+ private Integer isChart;
+
+ /**是否监控*/
+ private Integer isHistory;
+ /**
+ * 数据定义
+ */
+ private String dataType;
+ /**物模型名称*/
+ private String name;
+ /**
+ * 物模型类型
+ */
+ private Integer type;
+ /**
+ * 是否是参数
+ */
+ private Integer isParams;
+
+ private String formula;
+
+ private Integer slaveId;
+
+ private Integer tempSlaveId;
+
+ private Integer quantity;
+
+ private String code;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/DeviceReplyBo.java b/maibu-common/src/main/java/com/maibu/core/mq/DeviceReplyBo.java
new file mode 100644
index 0000000..8c836df
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/DeviceReplyBo.java
@@ -0,0 +1,17 @@
+package com.maibu.core.mq;
+
+import lombok.Data;
+
+/**
+ * @author bill
+ */
+@Data
+public class DeviceReplyBo {
+
+ /*设备下发消息id*/
+ private String messageId;
+ /*标识符*/
+ private String id;
+ /**下发值*/
+ private String value;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/DeviceReport.java b/maibu-common/src/main/java/com/maibu/core/mq/DeviceReport.java
new file mode 100644
index 0000000..8e8b35d
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/DeviceReport.java
@@ -0,0 +1,78 @@
+package com.maibu.core.mq;
+
+import com.maibu.core.protocol.Message;
+import com.maibu.core.thingsModel.ThingsModelSimpleItem;
+import com.maibu.enums.FunctionReplyStatus;
+import com.maibu.enums.ServerType;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * 设备上行数据model
+ *
+ * @author bill
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class DeviceReport extends Message {
+
+ /**
+ * 设备编号
+ */
+ private String serialNumber;
+ /**
+ * 产品ID
+ */
+ private Long productId;
+ /**
+ * 平台时间
+ */
+ private Date platformDate;
+ /**
+ * 消息id
+ */
+ private String messageId;
+
+ /** 设备物模型值的集合 **/
+ private List thingsModelSimpleItem;
+
+ /**
+ * 是否设备回复数据
+ */
+ private Boolean isReply = false;
+ /**
+ * 原数据报文
+ */
+ private String sources;
+
+ /**
+ * 设备回复消息
+ */
+ private String replyMessage;
+ /**
+ * 设备回复状态
+ */
+ private FunctionReplyStatus status;
+ /**
+ * 从机编号
+ */
+ private Integer slaveId;
+ /**
+ * 服务器类型
+ */
+ private ServerType serverType;
+
+ private String protocolCode;
+
+ private Long userId;
+ private String userName;
+ private String deviceName;
+
+ private SubDeviceBo subDeviceBo;
+
+ private GwDeviceBo gwDeviceBo;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/DeviceReportBo.java b/maibu-common/src/main/java/com/maibu/core/mq/DeviceReportBo.java
new file mode 100644
index 0000000..ef6ffce
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/DeviceReportBo.java
@@ -0,0 +1,77 @@
+package com.maibu.core.mq;
+
+import com.maibu.core.mq.message.PropRead;
+import com.maibu.core.thingsModel.ThingsModelSimpleItem;
+import com.maibu.enums.FunctionReplyStatus;
+import com.maibu.enums.ServerType;
+import com.maibu.enums.ThingsModelType;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 设备上报
+ * @author bill
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DeviceReportBo {
+
+ /*设备编号或IMEI号*/
+ private String serialNumber;
+ /*产品ID*/
+ private Long productId;
+ /*4G物联网卡CCID*/
+ private String ccId;
+ /*topic*/
+ private String topicName;
+ /*mqtt消息中的packetId*/
+ private Long packetId;
+ /*上报时间*/
+ private Date platformDate;
+ /*物模型类型 1=-属性,2-功能,3-事件 */
+ private ThingsModelType type;
+ /*上报数据*/
+ private byte[] data;
+ /*1-设备数据上报 2- 下发指令给设备,设备应答数据*/
+ private Integer reportType;
+ /*消息id*/
+ private String messageId;
+ /* modbus协议消息回调,记录数据*/
+ private PropRead prop;
+
+ /** 设备物模型值的集合 **/
+ private List thingsModelSimpleItem;
+ /*处理的消息服务类型*/
+ private ServerType serverType;
+ private Integer slaveId;
+
+ /**
+ * 是否设备回复数据
+ */
+ private Boolean isReply = false;
+
+ /**
+ * 设备回复消息
+ */
+ private String replyMessage;
+ /**
+ * 设备回复状态
+ */
+ private FunctionReplyStatus status;
+ /**
+ * 寄存器地址
+ */
+ private int address;
+
+ private String protocolCode;
+
+ private String sources;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/DeviceStatusBo.java b/maibu-common/src/main/java/com/maibu/core/mq/DeviceStatusBo.java
new file mode 100644
index 0000000..07f0f73
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/DeviceStatusBo.java
@@ -0,0 +1,35 @@
+package com.maibu.core.mq;
+
+import com.maibu.enums.DeviceStatus;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+/**
+ * 设备状态
+ * @author bill
+ */
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+@Builder
+public class DeviceStatusBo {
+ /**
+ * 设备客户端id
+ */
+ private String serialNumber;
+ /**是否活跃*/
+ private DeviceStatus status;
+ /**消息时间*/
+ private Date timestamp;
+ /*host*/
+ private String hostName;
+ /*port*/
+ private Integer port;
+
+ private String ip;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/DeviceTestReportBo.java b/maibu-common/src/main/java/com/maibu/core/mq/DeviceTestReportBo.java
new file mode 100644
index 0000000..5edc3fa
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/DeviceTestReportBo.java
@@ -0,0 +1,32 @@
+package com.maibu.core.mq;
+
+import com.maibu.core.thingsModel.ThingsModelSimpleItem;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author bill
+ */
+@Data
+public class DeviceTestReportBo {
+
+ private Long productId;
+ /**
+ * 设备编号
+ */
+ private String serialNumber;
+ /**
+ * 是否是回复数据
+ */
+ private Boolean isReply;
+
+ /**
+ * 设备物模型值的集合
+ */
+ private List thingsModelSimpleItem;
+ /**
+ * 原报文
+ */
+ private Object sources;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/GwDeviceBo.java b/maibu-common/src/main/java/com/maibu/core/mq/GwDeviceBo.java
new file mode 100644
index 0000000..e7595fb
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/GwDeviceBo.java
@@ -0,0 +1,16 @@
+package com.maibu.core.mq;
+
+
+import lombok.Data;
+
+/**
+ * @author gsb
+ * @date 2024/9/4 10:49
+ */
+@Data
+public class GwDeviceBo {
+
+ private Long productId;
+
+ private String serialNumber;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/InvokeReqDto.java b/maibu-common/src/main/java/com/maibu/core/mq/InvokeReqDto.java
new file mode 100644
index 0000000..1963ea9
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/InvokeReqDto.java
@@ -0,0 +1,63 @@
+package com.maibu.core.mq;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.maibu.enums.ThingsModelType;
+import com.maibu.utils.DateUtils;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * @author gsb
+ * @date 2022/12/5 11:26
+ */
+@Data
+public class InvokeReqDto {
+
+ @ApiModelProperty(value = "设备编号")
+ private String serialNumber;
+
+ @NotNull(message = "标识符不能为空")
+ @ApiModelProperty(value = "标识符")
+ private String identifier;
+ /**消息体*/
+ @ApiModelProperty(value = "消息体")
+ private JSONObject params;
+ /**远程消息体*/
+ @ApiModelProperty(value = "远程调用消息体")
+ private Map remoteCommand;
+ /**设备超时时间*/
+ @ApiModelProperty(value = "设备超时响应时间,默认10s")
+ private Integer timeOut = 10;
+
+ @ApiModelProperty(value = "下发物模型类型")
+ private Integer type = ThingsModelType.SERVICE.getCode();
+
+ @ApiModelProperty(value = "是否是影子模式")
+ private String isShadow ;
+
+ @ApiModelProperty(value = "产品id")
+ private Long productId;
+
+ /**
+ * 物模型名称
+ */
+ private String modelName;
+
+ private Date timestamp = DateUtils.getNowDate();
+
+ /**
+ * 场景id
+ */
+ private Long sceneModelId;
+
+ /**
+ * 场景变量类型
+ */
+ private Integer variableType;
+
+ private Long userId;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/MQSendMessageBo.java b/maibu-common/src/main/java/com/maibu/core/mq/MQSendMessageBo.java
new file mode 100644
index 0000000..e56d8ee
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/MQSendMessageBo.java
@@ -0,0 +1,61 @@
+package com.maibu.core.mq;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.maibu.core.device.DeviceAndProtocol;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 服务(指令)下发对象
+ *
+ * @author bill
+ */
+@Data
+@NoArgsConstructor
+public class MQSendMessageBo {
+
+ /**
+ * 设备编号
+ */
+ private String serialNumber;
+ /**
+ * 下发属性标识符
+ */
+ private String identifier;
+ /**
+ * 下发参数
+ */
+ private JSONObject params;
+
+ /**
+ * 下发的值
+ */
+ private String value;
+ /**
+ * messageId生成放到调用接口的时候生成
+ */
+ private String messageId;
+ /**
+ * 协议产品相关信息
+ */
+ private DeviceAndProtocol dp;
+
+ /**
+ * 物模型
+ */
+ private String thingsModel;
+ /**
+ * 主题
+ */
+ private String topicName;
+
+
+ public Boolean isShadow;
+
+ public Long userId;
+
+ public Long delay;
+
+ private String parentSerialNumber;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/MessageReplyBo.java b/maibu-common/src/main/java/com/maibu/core/mq/MessageReplyBo.java
new file mode 100644
index 0000000..3bc881a
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/MessageReplyBo.java
@@ -0,0 +1,51 @@
+package com.maibu.core.mq;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+/**
+ * 设备消息回调或者下发指令值
+ *
+ * @author gsb
+ * @date 2022/5/11 9:27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class MessageReplyBo {
+
+
+ private String id;
+ /**
+ * 消息回执的messageId,和下行消息呼应
+ */
+ private String messageId;
+ /**
+ * 设备处理消息的状态
+ */
+ private Integer status;
+ /**
+ * 抵达服务器时间
+ */
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Date timestamp;
+ /**
+ * 设备上报的时间
+ */
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Date deviceTimestamp;
+ /**
+ * 回执消息内容
+ */
+ private String body;
+ /*产品编号*/
+ private Long productId;
+ /*设备编号*/
+ private String serialNumber;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/SubDeviceBo.java b/maibu-common/src/main/java/com/maibu/core/mq/SubDeviceBo.java
new file mode 100644
index 0000000..d7d2e6c
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/SubDeviceBo.java
@@ -0,0 +1,35 @@
+package com.maibu.core.mq;
+
+import lombok.Data;
+
+/**
+ * @author bill
+ */
+@Data
+public class SubDeviceBo {
+ /**
+ * 网关设备id
+ */
+
+ private Long gwDeviceId;
+
+ /**
+ * 子设备id
+ */
+ private Long subDeviceId;
+
+ /**
+ * 从机地址
+ */
+ private Integer slaveId;
+ /**
+ * 子设备名称
+ */
+ private String subDeviceName;
+ /**
+ * 子设备编号
+ */
+ private String subDeviceNo;
+
+ private Long subProductId;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/message/DeviceData.java b/maibu-common/src/main/java/com/maibu/core/mq/message/DeviceData.java
new file mode 100644
index 0000000..f22beef
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/message/DeviceData.java
@@ -0,0 +1,43 @@
+package com.maibu.core.mq.message;
+
+import com.maibu.core.ota.OtaPackageCode;
+import com.maibu.core.protocol.Message;
+import com.maibu.core.protocol.modbus.ModbusCode;
+import io.netty.buffer.ByteBuf;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 消息解析model
+ * @author gsb
+ * @date 2022/10/10 15:53
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@Builder
+public class DeviceData extends Message {
+
+ /*topic*/
+ private String topicName;
+
+ /*设备编号*/
+ private String serialNumber;
+
+ /*原数据*/
+ private byte[] data;
+
+ private ByteBuf buf;
+
+ private Object body;
+ /*MQTT OR 其他*/
+ private int type;
+ /*Modbus*/
+ private ModbusCode code;
+ /**产品id*/
+ private Long productId;
+
+ private OtaPackageCode netModbusCode;
+
+ private int bitCount;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/message/DeviceDownMessage.java b/maibu-common/src/main/java/com/maibu/core/mq/message/DeviceDownMessage.java
new file mode 100644
index 0000000..eb0d646
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/message/DeviceDownMessage.java
@@ -0,0 +1,59 @@
+package com.maibu.core.mq.message;
+
+import com.maibu.core.protocol.modbus.ModbusCode;
+import com.maibu.enums.ServerType;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * 设备下发指令model
+ *
+ * @author gsb
+ * @date 2022/10/10 16:18
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DeviceDownMessage {
+
+ private String messageId;
+ /**
+ * 时间戳,单位毫秒
+ */
+ private Long timestamp;
+ /**
+ * 消息体
+ */
+ private Object body;
+ /*下发的指令,服务调用的时候就是服务标识符*/
+ private String identifier;
+ /*产品id*/
+ private Long productId;
+ /**
+ * 设备编码
+ */
+ private String serialNumber;
+ /**
+ * 从机编号
+ */
+ private Integer slaveId;
+ private ModbusCode code;
+ private String protocolCode;
+
+ private List values;
+ private String topic;
+ private String subCode;
+ private ServerType serverType;
+
+ public DeviceDownMessage(List values, String topic, String subCode,String transport) {
+ this.values = values;
+ this.topic = topic;
+ this.subCode = subCode;
+ this.serverType = ServerType.explain(transport);
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/message/DeviceFunctionMessage.java b/maibu-common/src/main/java/com/maibu/core/mq/message/DeviceFunctionMessage.java
new file mode 100644
index 0000000..b0344c7
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/message/DeviceFunctionMessage.java
@@ -0,0 +1,33 @@
+package com.maibu.core.mq.message;
+
+import lombok.Data;
+
+/**
+ * 平台下发指令数据model
+ * @author bill
+ */
+@Data
+public class DeviceFunctionMessage {
+
+ /*流水号,兼容modbus标准协议没有消息流水号*/
+ private String seqNo;
+ /*平台时间*/
+ private Long pfTimestamp;
+ /*下发的消息体*/
+ private Object body;
+ /*下发的指令物模型标识符*/
+ private String identifier;
+ /*下发的数据寄存器地址*/
+ private String hexAddress;
+ /*产品ID*/
+ private Long productId;
+ /*设备编号*/
+ private String serialNumber;
+ /*网关设备编号*/
+ private String protocolCode;
+
+ /*是否有子设备 0-否,1-是*/
+ private Integer hasSub;
+ /*子设备从机编号 例如 02 编号从机。通过主机集控下发的指定从机编号*/
+ private String subDeviceCode;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/message/DeviceMessage.java b/maibu-common/src/main/java/com/maibu/core/mq/message/DeviceMessage.java
new file mode 100644
index 0000000..ea594af
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/message/DeviceMessage.java
@@ -0,0 +1,31 @@
+package com.maibu.core.mq.message;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 设备消息
+ * @author bill
+ */
+@Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class DeviceMessage {
+
+ /** 下发的数据*/
+ private Object message;
+
+ /** 下发的topic*/
+ private String topicName;
+
+ /** 设备编号*/
+ private String serialNumber;
+
+ private String dataType;
+
+ /** 时间 */
+ @JsonFormat(pattern ="yyyy-MM-dd HH:mm:ss:SSS")
+ private Date time;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/message/FunctionCallBackBo.java b/maibu-common/src/main/java/com/maibu/core/mq/message/FunctionCallBackBo.java
new file mode 100644
index 0000000..5e5be3e
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/message/FunctionCallBackBo.java
@@ -0,0 +1,24 @@
+package com.maibu.core.mq.message;
+
+import lombok.Data;
+
+/**
+ * 指令下发组将的model
+ * @author bill
+ */
+@Data
+public class FunctionCallBackBo {
+
+ /*下发的数据*/
+ private byte[] message;
+
+ /*MQTt-下发的topic*/
+ private String topicName;
+
+ /*设备编号*/
+ private String serialNumber;
+ /**
+ * 原数据包
+ */
+ private String sources;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/message/InstructionsMessage.java b/maibu-common/src/main/java/com/maibu/core/mq/message/InstructionsMessage.java
new file mode 100644
index 0000000..d5e38fc
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/message/InstructionsMessage.java
@@ -0,0 +1,20 @@
+package com.maibu.core.mq.message;
+
+import lombok.Data;
+
+/**
+ * 指令下发组将的model
+ * @author bill
+ */
+@Data
+public class InstructionsMessage {
+
+ /*下发的数据*/
+ private byte[] message;
+
+ /*MQTt-下发的topic*/
+ private String topicName;
+
+ /*设备编号*/
+ private String serialNumber;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/message/ModbusPollMsg.java b/maibu-common/src/main/java/com/maibu/core/mq/message/ModbusPollMsg.java
new file mode 100644
index 0000000..ad7c7f9
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/message/ModbusPollMsg.java
@@ -0,0 +1,32 @@
+package com.maibu.core.mq.message;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author gsb
+ * @date 2024/6/20 10:53
+ */
+@Data
+public class ModbusPollMsg {
+
+ /**
+ * 下发指令
+ */
+ private List commandList;
+ /**
+ * 服务端类型
+ */
+ private Integer serverType;
+ /**
+ * 产品id
+ */
+ private Long productId;
+ /**
+ * 设备编码
+ */
+ private String serialNumber;
+
+ private String transport;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/message/MqttBo.java b/maibu-common/src/main/java/com/maibu/core/mq/message/MqttBo.java
new file mode 100644
index 0000000..cfbe849
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/message/MqttBo.java
@@ -0,0 +1,26 @@
+package com.maibu.core.mq.message;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @author bill
+ */
+@Data
+public class MqttBo {
+
+ /*主题*/
+ private String topic;
+ /*数据*/
+ private String data;
+ /*消息质量*/
+ private int qos = 1;
+ /*发送方向*/
+ private String direction;
+ /*时间*/
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Date ts;
+}
+
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/message/PropRead.java b/maibu-common/src/main/java/com/maibu/core/mq/message/PropRead.java
new file mode 100644
index 0000000..e313202
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/message/PropRead.java
@@ -0,0 +1,39 @@
+package com.maibu.core.mq.message;
+
+import com.maibu.core.protocol.modbus.ModbusCode;
+import lombok.Data;
+
+/**
+ * @author gsb
+ * @date 2022/12/9 10:15
+ */
+@Data
+public class PropRead {
+
+ /**设备编号*/
+ private String serialNumber;
+ /**寄存器起始地址*/
+ private int address;
+ /**
+ * 读取寄存器个数
+ */
+ private int count;
+ /**数据结果长度计算值*/
+ private int length;
+ /**
+ * 从机地址
+ */
+ private int slaveId;
+ /**
+ * 读取个数
+ */
+ private int quantity;
+ /**
+ * 数据
+ */
+ private String data;
+ /**
+ * 功能码
+ */
+ private ModbusCode code;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/message/ProtocolDto.java b/maibu-common/src/main/java/com/maibu/core/mq/message/ProtocolDto.java
new file mode 100644
index 0000000..8194837
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/message/ProtocolDto.java
@@ -0,0 +1,21 @@
+package com.maibu.core.mq.message;
+
+import lombok.Data;
+
+/**
+ * 协议bean
+ * @author gsb
+ * @date 2022/10/25 14:54
+ */
+@Data
+public class ProtocolDto {
+
+ /**协议编号*/
+ private String code;
+ private String name;
+ /*外部协议url*/
+ private String protocolUrl;
+ private String description;
+ /**协议类型 协议类型 0:系统协议 1:jar,2.js,3.c*/
+ private Integer protocolType;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/message/ReportDataBo.java b/maibu-common/src/main/java/com/maibu/core/mq/message/ReportDataBo.java
new file mode 100644
index 0000000..d895d14
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/message/ReportDataBo.java
@@ -0,0 +1,48 @@
+package com.maibu.core.mq.message;
+
+import com.maibu.core.mq.GwDeviceBo;
+import com.maibu.core.thingsModel.ThingsModelSimpleItem;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.List;
+
+/**
+ * 上报数据模型bo
+ * @author bill
+ */
+@Data
+@Accessors(chain = true)
+public class ReportDataBo {
+
+ /**产品id*/
+ private Long productId;
+ /**设备编号*/
+ private String serialNumber;
+ /**上报消息*/
+ private String message;
+ /**上报的数据*/
+ private List dataList;
+ /**设备影子*/
+ private boolean isShadow;
+ /**
+ * 物模型类型
+ * 1=属性,2=功能,3=事件,4=设备升级,5=设备上线,6=设备下线
+ */
+ private int type;
+ /**是否执行规则引擎*/
+ private boolean isRuleEngine;
+ /**从机编号*/
+ private Integer slaveId;
+ /**
+ * 上报原数据包
+ */
+ private Object sources;
+
+ private GwDeviceBo gwDeviceBo;
+
+ private Long userId;
+ private String userName;
+ private String deviceName;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/message/SubDeviceMessage.java b/maibu-common/src/main/java/com/maibu/core/mq/message/SubDeviceMessage.java
new file mode 100644
index 0000000..b4b59da
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/message/SubDeviceMessage.java
@@ -0,0 +1,18 @@
+package com.maibu.core.mq.message;
+
+import lombok.Data;
+
+/**
+ * 网关子设备model
+ * @author gsb
+ * @date 2022/10/10 10:18
+ */
+@Data
+public class SubDeviceMessage {
+ /*子设备编号或编码*/
+ private String serialNumber;
+ /*数据*/
+ private byte[] data;
+ /*消息id*/
+ private String messageId;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/ota/OtaReplyMessage.java b/maibu-common/src/main/java/com/maibu/core/mq/ota/OtaReplyMessage.java
new file mode 100644
index 0000000..8f5cd6d
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/ota/OtaReplyMessage.java
@@ -0,0 +1,21 @@
+package com.maibu.core.mq.ota;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * OTA升级回复model
+ * @author gsb
+ * @date 2022/10/24 17:20
+ */
+@Data
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class OtaReplyMessage {
+
+ private Long taskId;
+ private BigDecimal version;
+ private int status;
+ private int progress;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/ota/OtaUpgradeBo.java b/maibu-common/src/main/java/com/maibu/core/mq/ota/OtaUpgradeBo.java
new file mode 100644
index 0000000..d6f1a38
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/ota/OtaUpgradeBo.java
@@ -0,0 +1,40 @@
+package com.maibu.core.mq.ota;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Builder;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * OTA远程升级
+ * @author gsb
+ * @date 2022/10/10 10:22
+ */
+@Data
+@Builder
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class OtaUpgradeBo {
+
+ // 设备编码
+ private String serialNumber;
+ // 升级任务ID
+ private Long taskId;
+ // 消息内容
+ private byte[] msg;
+ // 设备状态
+ private int status;
+ // topic
+ private String topicName;
+ // 固件包版本
+ private BigDecimal version;
+ // 固件包http地址
+ private String url;
+ // 固件包分包传输大小
+ private int packageSize;
+ // 固件包传输偏移量
+ private int offset;
+ // 升级进度
+ private int progress;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/mq/ota/OtaUpgradeDelayTask.java b/maibu-common/src/main/java/com/maibu/core/mq/ota/OtaUpgradeDelayTask.java
new file mode 100644
index 0000000..0e83aa3
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/mq/ota/OtaUpgradeDelayTask.java
@@ -0,0 +1,63 @@
+package com.maibu.core.mq.ota;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.maibu.utils.DateUtils;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.Delayed;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * ota升级发送,实现Delayed延时接口
+ *
+ * @author bill
+ */
+@Data
+public class OtaUpgradeDelayTask implements Delayed {
+
+ /**
+ * 固件id
+ */
+ private Long firmwareId;
+ /**
+ * 1:指定产品 2:指定设备
+ */
+ private Long upgradeType;
+
+ private List devices;
+ /**
+ * 任务id
+ */
+ private Long taskId;
+ /**
+ * 开始升级时间
+ */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Date startTime;
+
+
+ /**
+ * 设置延迟执行时间 开始升级时间 -当前时间
+ *
+ * @param unit
+ * @return
+ */
+ @Override
+ public long getDelay(TimeUnit unit) {
+ return startTime.getTime() - DateUtils.getTimestamp();
+ }
+
+ @Override
+ public int compareTo(Delayed o) {
+ OtaUpgradeDelayTask delayTask = (OtaUpgradeDelayTask) o;
+ //比较
+ long diff = this.startTime.getTime() - delayTask.startTime.getTime();
+ if (diff <= 0) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/notify/AlertPushParams.java b/maibu-common/src/main/java/com/maibu/core/notify/AlertPushParams.java
new file mode 100644
index 0000000..8ffca71
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/notify/AlertPushParams.java
@@ -0,0 +1,48 @@
+package com.maibu.core.notify;
+
+import lombok.Data;
+
+import java.util.Set;
+
+/**
+ * @author fastb
+ * @version 1.0
+ * @description: TODO
+ * @date 2023-12-26 11:03
+ */
+@Data
+public class AlertPushParams {
+
+ /**
+ * 通知模版id
+ */
+ private Long notifyTemplateId;
+ /**
+ * 告警时间
+ */
+ private String alertTime;
+ /**
+ * 设备名称
+ */
+ private String deviceName;
+ /**
+ * 设备编号
+ */
+ private String serialNumber;
+ /**
+ * 告警发生地点
+ */
+ private String address;
+ /**
+ * 告警名称
+ */
+ private String alertName;
+ /**
+ * 告警推送手机号
+ */
+ private Set userPhoneSet;
+ /**
+ * 告警推送用户id
+ */
+ private Set userIdSet;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/notify/AppGeTuiParams.java b/maibu-common/src/main/java/com/maibu/core/notify/AppGeTuiParams.java
new file mode 100644
index 0000000..5d71aaa
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/notify/AppGeTuiParams.java
@@ -0,0 +1,33 @@
+package com.maibu.core.notify;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+import org.dromara.sms4j.provider.config.BaseConfig;
+
+/**
+ * 个推参数配置
+ * @author gsb
+ * @date 2023/12/11 17:14
+ */
+@Data
+@Accessors(chain = true)
+public class AppGeTuiParams extends BaseConfig {
+
+ @ApiModelProperty("appId")
+ private String appId;
+
+ @ApiModelProperty("appKey")
+ private String appKey;
+
+ @ApiModelProperty("秘钥")
+ private String masterSecret;
+
+ @ApiModelProperty("模板参数")
+ private String params;
+
+ @Override
+ public String getSupplier() {
+ return null;
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/notify/EnterpriseWeChatAPPParams.java b/maibu-common/src/main/java/com/maibu/core/notify/EnterpriseWeChatAPPParams.java
new file mode 100644
index 0000000..bf0b1e1
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/notify/EnterpriseWeChatAPPParams.java
@@ -0,0 +1,35 @@
+package com.maibu.core.notify;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+import org.dromara.sms4j.provider.config.BaseConfig;
+
+/**
+ * 企业微信(应用消息)
+ * @author gsb
+ * @date 2023/12/11 17:25
+ */
+@Data
+@Accessors(chain = true)
+public class EnterpriseWeChatAPPParams extends BaseConfig {
+
+ @ApiModelProperty("企业ID")
+ private String corpId;
+ @ApiModelProperty("企业应用私钥OA")
+ private String corpSecret;
+ @ApiModelProperty("企业应用的id")
+ private Integer agentId;
+ //@ApiModelProperty("token")
+ //private String token;
+ //@ApiModelProperty("aes秘钥")
+ //private String aesKey;
+
+ @ApiModelProperty("模板参数")
+ private String params;
+
+ @Override
+ public String getSupplier() {
+ return null;
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/notify/NotifyConfigVO.java b/maibu-common/src/main/java/com/maibu/core/notify/NotifyConfigVO.java
new file mode 100644
index 0000000..242bc82
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/notify/NotifyConfigVO.java
@@ -0,0 +1,37 @@
+package com.maibu.core.notify;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author fastb
+ * @version 1.0
+ * @description: 通知配置参数属性VO类
+ * @date 2024-01-09 14:01
+ */
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+public class NotifyConfigVO {
+
+ /**
+ * 配置属性
+ */
+ private String attribute;
+
+ /**
+ * 配置属性名称
+ */
+ private String name;
+
+ /**
+ * 配置属性样式 string-字符串;text-富文本;file-文件;boolean-启用;int-整数
+ */
+ private String type;
+
+ /**
+ * 值
+ */
+ private String value;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/notify/NotifySendResponse.java b/maibu-common/src/main/java/com/maibu/core/notify/NotifySendResponse.java
new file mode 100644
index 0000000..c8d9f8e
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/notify/NotifySendResponse.java
@@ -0,0 +1,33 @@
+package com.maibu.core.notify;
+
+import lombok.Data;
+
+/**
+ * @author fastb
+ * @version 1.0
+ * @description: 通知发送响应类
+ * @date 2024-01-11 16:06
+ */
+@Data
+public class NotifySendResponse {
+
+ /**
+ * 发送结果 1-成功;0-失败
+ */
+ private Integer status = 0;
+
+ /**
+ * 返回结果内容
+ */
+ private String resultContent = "";
+
+ /**
+ * 发送内容,变量替换后的
+ */
+ private String sendContent = "";
+
+ /**
+ * 不是使用sendAccount账号发送,而是像钉钉这种,发送所有人或部门,记录这个
+ */
+ private String otherSendAccount = "";
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/notify/WeChatServerParams.java b/maibu-common/src/main/java/com/maibu/core/notify/WeChatServerParams.java
new file mode 100644
index 0000000..16aecbb
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/notify/WeChatServerParams.java
@@ -0,0 +1,31 @@
+package com.maibu.core.notify;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * 微信服务号推送参数
+ * @author gsb
+ * @date 2023/12/11 17:11
+ */
+@Data
+@Accessors(chain = true)
+public class WeChatServerParams {
+
+ @ApiModelProperty("appId")
+ private String appId;
+
+ @ApiModelProperty("app秘钥")
+ private String secret;
+
+ @ApiModelProperty("模板ID")
+ private String templateId;
+
+ @ApiModelProperty("跳转地址")
+ private String page;
+
+ @ApiModelProperty("模板参数")
+ private String params;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/notify/alertPush/AlertPushItem.java b/maibu-common/src/main/java/com/maibu/core/notify/alertPush/AlertPushItem.java
new file mode 100644
index 0000000..6b43ec8
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/notify/alertPush/AlertPushItem.java
@@ -0,0 +1,28 @@
+package com.maibu.core.notify.alertPush;
+
+import lombok.Data;
+
+/**
+ * 推送项item
+ * @author bill
+ */
+@Data
+public class AlertPushItem {
+
+ /**
+ * 告警时间
+ */
+ private String alertTime;
+ /**
+ * 设备编号
+ */
+ private String serialNumber;
+ /**
+ * 告警发生地点
+ */
+ private String address;
+ /**
+ * 告警名称
+ */
+ private String alertName;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/notify/alertPush/PushMsg.java b/maibu-common/src/main/java/com/maibu/core/notify/alertPush/PushMsg.java
new file mode 100644
index 0000000..033f944
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/notify/alertPush/PushMsg.java
@@ -0,0 +1,32 @@
+package com.maibu.core.notify.alertPush;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 推送配置信息
+ * @author bill
+ */
+@Data
+public class PushMsg {
+
+ /**
+ * 用户Id
+ */
+ private Long userId;
+ /**
+ * 设备id
+ */
+ private Long deviceId;
+ /**
+ * 告警id
+ */
+ private Long alertId;
+ /**
+ * 推送内容值
+ */
+ private AlertPushItem item;
+
+ private List values;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/notify/config/DingTalkConfigParams.java b/maibu-common/src/main/java/com/maibu/core/notify/config/DingTalkConfigParams.java
new file mode 100644
index 0000000..0282eb7
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/notify/config/DingTalkConfigParams.java
@@ -0,0 +1,21 @@
+package com.maibu.core.notify.config;
+
+import lombok.Data;
+
+/**
+ * @author fastb
+ * @version 1.0
+ * @description: 钉钉渠道应用配置类
+ * @date 2024-01-12 17:50
+ */
+@Data
+public class DingTalkConfigParams {
+
+ private String appKey;
+
+ private String appSecret;
+
+ private String agentId;
+
+ private String webHook;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/notify/config/EmailConfigParams.java b/maibu-common/src/main/java/com/maibu/core/notify/config/EmailConfigParams.java
new file mode 100644
index 0000000..d14addd
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/notify/config/EmailConfigParams.java
@@ -0,0 +1,48 @@
+package com.maibu.core.notify.config;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 邮箱配置参数
+ * @author gsb
+ * @date 2023/12/11 17:17
+ */
+@Data
+public class EmailConfigParams {
+
+ @ApiModelProperty("服务器地址")
+ private String smtpServer;
+
+ @ApiModelProperty("端口号")
+ private String port;
+
+ @ApiModelProperty("账号(发件人地址)")
+ private String username;
+
+ @ApiModelProperty("密码")
+ private String password;
+
+ /**
+ * 是否开启ssl 默认开启 QQ之类的邮箱默认都需要ssl
+ */
+ @ApiModelProperty("是否启动ssl")
+ private Boolean sslEnable;
+
+ /**
+ * 是否开启验证 默认开启
+ */
+ @ApiModelProperty("启动ttl")
+ private Boolean authEnable;
+
+ /**
+ * 重试间隔(单位:秒),默认为5秒
+ */
+ private Integer retryInterval = 5;
+
+ /**
+ * 重试次数,默认为1次
+ */
+ private Integer maxRetries = 1;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/notify/config/VoiceConfigParams.java b/maibu-common/src/main/java/com/maibu/core/notify/config/VoiceConfigParams.java
new file mode 100644
index 0000000..54424ab
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/notify/config/VoiceConfigParams.java
@@ -0,0 +1,23 @@
+package com.maibu.core.notify.config;
+
+import lombok.Data;
+
+/**
+ * 语音配置
+ * @author fastb
+ * @date 2023-12-09 17:32
+ */
+@Data
+public class VoiceConfigParams {
+
+ /**
+ * 您的AccessKey ID
+ */
+ private String accessKeyId;
+
+ /**
+ * 您的AccessKey Secret
+ */
+ private String accessKeySecret;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/notify/config/WeChatConfigParams.java b/maibu-common/src/main/java/com/maibu/core/notify/config/WeChatConfigParams.java
new file mode 100644
index 0000000..9e91c29
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/notify/config/WeChatConfigParams.java
@@ -0,0 +1,25 @@
+package com.maibu.core.notify.config;
+
+import lombok.Data;
+
+/**
+ * 微信推送配置参数
+ * @author gsb
+ * @date 2023/12/11 17:11
+ */
+@Data
+public class WeChatConfigParams {
+
+ private String appId;
+
+ private String appSecret;
+
+ private String corpId;
+
+ private String corpSecret;
+
+ private String agentId;
+
+ private String webHook;
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/notify/msg/DingTalkMsgParams.java b/maibu-common/src/main/java/com/maibu/core/notify/msg/DingTalkMsgParams.java
new file mode 100644
index 0000000..a4d2582
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/notify/msg/DingTalkMsgParams.java
@@ -0,0 +1,53 @@
+package com.maibu.core.notify.msg;
+
+import lombok.Data;
+
+/**
+ * @author fastb
+ * @version 1.0
+ * @description: 钉钉模版配置参数类
+ * @date 2024-01-12 17:51
+ */
+@Data
+public class DingTalkMsgParams {
+
+ /**
+ * 发送账号
+ */
+ private String sendAccount;
+
+ /**
+ * 是否发送所有人
+ */
+ private String sendAllEnable;
+
+ /**
+ * 发送什么类型的文本
+ */
+ private String msgType;
+
+ /**
+ * 消息内容
+ */
+ private String content;
+
+ /**
+ * 消息标题
+ */
+ private String title;
+
+ /**
+ * 消息链接
+ */
+ private String messageUrl;
+
+ /**
+ * 图片链接
+ */
+ private String picUrl;
+
+ /**
+ * 所属部门id
+ */
+ private String deptId;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/notify/msg/EmailMsgParams.java b/maibu-common/src/main/java/com/maibu/core/notify/msg/EmailMsgParams.java
new file mode 100644
index 0000000..7add3e6
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/notify/msg/EmailMsgParams.java
@@ -0,0 +1,33 @@
+package com.maibu.core.notify.msg;
+
+import lombok.Data;
+
+/**
+ * @author fastb
+ * @version 1.0
+ * @description: 邮箱模板消息参数
+ * @date 2023-12-22 10:47
+ */
+@Data
+public class EmailMsgParams {
+
+ /**
+ * 发送账号
+ */
+ private String sendAccount;
+
+ /**
+ * 标题
+ */
+ private String title;
+
+ /**
+ * 内容
+ */
+ private String content;
+
+ /**
+ * 附件
+ */
+ private String attachment;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/notify/msg/VoiceMsgParams.java b/maibu-common/src/main/java/com/maibu/core/notify/msg/VoiceMsgParams.java
new file mode 100644
index 0000000..6c2f0bf
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/notify/msg/VoiceMsgParams.java
@@ -0,0 +1,49 @@
+package com.maibu.core.notify.msg;
+
+import lombok.Data;
+
+/**
+ * @author fastb
+ * @version 1.0
+ * @description: 语音消息模板参数
+ * @date 2023-12-22 10:54
+ */
+@Data
+public class VoiceMsgParams {
+
+ /**
+ * 发送账号
+ */
+ private String sendAccount;
+
+ /**
+ * 模板ID
+ */
+ private String templateId;
+
+ /**
+ * 内容
+ */
+ private String content;
+
+ /**
+ * 应用ID
+ */
+ private String sdkAppId;
+
+ /**
+ * 播放次数 1~3
+ */
+ private String playTimes = "1";
+
+ /**
+ * 播放音量 0-100
+ */
+ private String volume = "50";
+
+ /**
+ * 语速控制 -500-500
+ */
+ private String speed = "0";
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/notify/msg/WeComMsgParams.java b/maibu-common/src/main/java/com/maibu/core/notify/msg/WeComMsgParams.java
new file mode 100644
index 0000000..0dbd5b9
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/notify/msg/WeComMsgParams.java
@@ -0,0 +1,43 @@
+package com.maibu.core.notify.msg;
+
+import lombok.Data;
+
+/**
+ * @author fastb
+ * @version 1.0
+ * @description: 企业微信消息模板参数
+ * @date 2023-12-22 10:57
+ */
+@Data
+public class WeComMsgParams {
+
+ /**
+ * 发送账号
+ */
+ private String sendAccount;
+
+ /**
+ * 消息类型
+ */
+ private String msgType;
+ /**
+ * 消息内容
+ */
+ private String content;
+ /**
+ * 消息标题
+ */
+ private String title;
+ /**
+ * 消息描述
+ */
+ private String description;
+ /**
+ * 跳转链接
+ */
+ private String url;
+ /**
+ * 图片链接
+ */
+ private String picUrl;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/notify/msg/WechatMsgParams.java b/maibu-common/src/main/java/com/maibu/core/notify/msg/WechatMsgParams.java
new file mode 100644
index 0000000..98e6e76
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/notify/msg/WechatMsgParams.java
@@ -0,0 +1,43 @@
+package com.maibu.core.notify.msg;
+
+import lombok.Data;
+
+/**
+ * @author fastb
+ * @version 1.0
+ * @description: 微信消息模板参数
+ * @date 2023-12-22 10:57
+ */
+@Data
+public class WechatMsgParams {
+
+ /**
+ * 发送账号
+ */
+ private String sendAccount;
+
+ /**
+ * 模版id
+ */
+ private String templateId;
+
+ /**
+ * 内容
+ */
+ private String content;
+
+ /**
+ * 跳转链接
+ */
+ private String redirectUrl;
+
+ /**
+ * 跳转小程序appid
+ */
+ private String appid;
+
+ /**
+ * 小程序跳转路径
+ */
+ private String pagePath;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/ota/OtaPackageCode.java b/maibu-common/src/main/java/com/maibu/core/ota/OtaPackageCode.java
new file mode 100644
index 0000000..ea9ff87
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/ota/OtaPackageCode.java
@@ -0,0 +1,45 @@
+package com.maibu.core.ota;
+
+import com.maibu.exception.ServiceException;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum OtaPackageCode {
+
+ OTA_01("查询产品工装号",(byte) 0x01),
+ OTA_0A("OTA升级启动",(byte) 0x0A),
+ OTA_0B("OTA升级包传输",(byte) 0x0B)
+ ;
+
+ private String desc;
+ private byte code;
+
+ public static OtaPackageCode getInstance(int code) {
+ switch ((byte)code) {
+ case 0x01:
+ return OTA_01;
+ case 0x0A:
+ return OTA_0A;
+ case 0x0B:
+ return OTA_0B;
+ default:
+ throw new ServiceException("功能码[" + code + "],未定义");
+ }
+ }
+
+ public static String getDes(int code){
+ switch ((byte)code) {
+ case 0x01:
+ return OTA_01.desc;
+ case 0x0A:
+ return OTA_0A.desc;
+ case 0x0B:
+ return OTA_0B.desc;
+ default:
+ return "UNKOWN";
+ }
+ }
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/page/PageDomain.java b/maibu-common/src/main/java/com/maibu/core/page/PageDomain.java
new file mode 100644
index 0000000..06aadb7
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/page/PageDomain.java
@@ -0,0 +1,102 @@
+package com.maibu.core.page;
+
+
+import com.maibu.utils.StringUtils;
+
+/**
+ * 分页数据
+ *
+ * @author ruoyi
+ */
+public class PageDomain
+{
+ /** 当前记录起始索引 */
+ private Integer pageNum;
+
+ /** 每页显示记录数 */
+ private Integer pageSize;
+
+ /** 排序列 */
+ private String orderByColumn;
+
+ /** 排序的方向desc或者asc */
+ private String isAsc = "asc";
+
+ /** 分页参数合理化 */
+ private Boolean reasonable = true;
+
+ public String getOrderBy()
+ {
+ if (StringUtils.isEmpty(orderByColumn))
+ {
+ return "";
+ }
+ return StringUtils.toUnderScoreCase(orderByColumn) + " " + isAsc;
+ }
+
+ public Integer getPageNum()
+ {
+ return pageNum;
+ }
+
+ public void setPageNum(Integer pageNum)
+ {
+ this.pageNum = pageNum;
+ }
+
+ public Integer getPageSize()
+ {
+ return pageSize;
+ }
+
+ public void setPageSize(Integer pageSize)
+ {
+ this.pageSize = pageSize;
+ }
+
+ public String getOrderByColumn()
+ {
+ return orderByColumn;
+ }
+
+ public void setOrderByColumn(String orderByColumn)
+ {
+ this.orderByColumn = orderByColumn;
+ }
+
+ public String getIsAsc()
+ {
+ return isAsc;
+ }
+
+ public void setIsAsc(String isAsc)
+ {
+ if (StringUtils.isNotEmpty(isAsc))
+ {
+ // 兼容前端排序类型
+ if ("ascending".equals(isAsc))
+ {
+ isAsc = "asc";
+ }
+ else if ("descending".equals(isAsc))
+ {
+ isAsc = "desc";
+ }
+ this.isAsc = isAsc;
+ }
+ }
+
+ public Boolean getReasonable()
+ {
+ if (StringUtils.isNull(reasonable))
+ {
+ return Boolean.TRUE;
+ }
+ return reasonable;
+ }
+
+ public void setReasonable(Boolean reasonable)
+ {
+ this.reasonable = reasonable;
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/page/TableDataExtendInfo.java b/maibu-common/src/main/java/com/maibu/core/page/TableDataExtendInfo.java
new file mode 100644
index 0000000..c16bae1
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/page/TableDataExtendInfo.java
@@ -0,0 +1,99 @@
+package com.maibu.core.page;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 表格分页数据对象
+ * 可添加扩展参数
+ *
+ * @author ruoyi
+ */
+public class TableDataExtendInfo implements Serializable
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 总记录数 */
+ private long total;
+
+ /** 列表数据 */
+ private List> rows;
+
+ /** 消息状态码 */
+ private int code;
+
+ /** 消息内容 */
+ private String msg;
+
+ /**
+ * 全部启用
+ */
+ private Integer allEnable;
+
+ public Integer getAllEnable() {
+ return allEnable;
+ }
+
+ public void setAllEnable(Integer allEnable) {
+ this.allEnable = allEnable;
+ }
+
+ /**
+ * 表格数据对象
+ */
+ public TableDataExtendInfo()
+ {
+ }
+
+ /**
+ * 分页
+ *
+ * @param list 列表数据
+ * @param total 总记录数
+ */
+ public TableDataExtendInfo(List> list, int total)
+ {
+ this.rows = list;
+ this.total = total;
+ }
+
+ public long getTotal()
+ {
+ return total;
+ }
+
+ public void setTotal(long total)
+ {
+ this.total = total;
+ }
+
+ public List> getRows()
+ {
+ return rows;
+ }
+
+ public void setRows(List> rows)
+ {
+ this.rows = rows;
+ }
+
+ public int getCode()
+ {
+ return code;
+ }
+
+ public void setCode(int code)
+ {
+ this.code = code;
+ }
+
+ public String getMsg()
+ {
+ return msg;
+ }
+
+ public void setMsg(String msg)
+ {
+ this.msg = msg;
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/page/TableDataInfo.java b/maibu-common/src/main/java/com/maibu/core/page/TableDataInfo.java
new file mode 100644
index 0000000..4e327aa
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/page/TableDataInfo.java
@@ -0,0 +1,85 @@
+package com.maibu.core.page;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 表格分页数据对象
+ *
+ * @author ruoyi
+ */
+public class TableDataInfo implements Serializable
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 总记录数 */
+ private long total;
+
+ /** 列表数据 */
+ private List> rows;
+
+ /** 消息状态码 */
+ private int code;
+
+ /** 消息内容 */
+ private String msg;
+
+ /**
+ * 表格数据对象
+ */
+ public TableDataInfo()
+ {
+ }
+
+ /**
+ * 分页
+ *
+ * @param list 列表数据
+ * @param total 总记录数
+ */
+ public TableDataInfo(List> list, int total)
+ {
+ this.rows = list;
+ this.total = total;
+ }
+
+ public long getTotal()
+ {
+ return total;
+ }
+
+ public void setTotal(long total)
+ {
+ this.total = total;
+ }
+
+ public List> getRows()
+ {
+ return rows;
+ }
+
+ public void setRows(List> rows)
+ {
+ this.rows = rows;
+ }
+
+ public int getCode()
+ {
+ return code;
+ }
+
+ public void setCode(int code)
+ {
+ this.code = code;
+ }
+
+ public String getMsg()
+ {
+ return msg;
+ }
+
+ public void setMsg(String msg)
+ {
+ this.msg = msg;
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/page/TableSupport.java b/maibu-common/src/main/java/com/maibu/core/page/TableSupport.java
new file mode 100644
index 0000000..8fff726
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/page/TableSupport.java
@@ -0,0 +1,57 @@
+package com.maibu.core.page;
+
+
+import com.maibu.core.text.Convert;
+import com.maibu.utils.ServletUtils;
+
+/**
+ * 表格数据处理
+ *
+ * @author ruoyi
+ */
+public class TableSupport
+{
+ /**
+ * 当前记录起始索引
+ */
+ public static final String PAGE_NUM = "pageNum";
+
+ /**
+ * 每页显示记录数
+ */
+ public static final String PAGE_SIZE = "pageSize";
+
+ /**
+ * 排序列
+ */
+ public static final String ORDER_BY_COLUMN = "orderByColumn";
+
+ /**
+ * 排序的方向 "desc" 或者 "asc".
+ */
+ public static final String IS_ASC = "isAsc";
+
+ /**
+ * 分页参数合理化
+ */
+ public static final String REASONABLE = "reasonable";
+
+ /**
+ * 封装分页对象
+ */
+ public static PageDomain getPageDomain()
+ {
+ PageDomain pageDomain = new PageDomain();
+ pageDomain.setPageNum(Convert.toInt(ServletUtils.getParameter(PAGE_NUM), 1));
+ pageDomain.setPageSize(Convert.toInt(ServletUtils.getParameter(PAGE_SIZE), 10));
+ pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN));
+ pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC));
+ pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE));
+ return pageDomain;
+ }
+
+ public static PageDomain buildPageRequest()
+ {
+ return getPageDomain();
+ }
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/protocol/Message.java b/maibu-common/src/main/java/com/maibu/core/protocol/Message.java
new file mode 100644
index 0000000..cd38421
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/protocol/Message.java
@@ -0,0 +1,33 @@
+package com.maibu.core.protocol;
+
+import io.netty.buffer.ByteBuf;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 基础消息
+ *
+ * @author bill
+ */
+@Data
+public class Message implements Serializable {
+
+ /*获取客户端id*/
+ public String clientId;
+ /*消息类型*/
+ public String messageId;
+ /*消息流水号*/
+ public String serNo;
+ /**消息通道id*/
+ public String channelId;
+
+ public ByteBuf payload;
+
+ /**
+ * 是否数据和注册包都封装到一起
+ */
+ private Boolean isPackage = false;
+
+ private Object body;
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/protocol/modbus/ModbusCode.java b/maibu-common/src/main/java/com/maibu/core/protocol/modbus/ModbusCode.java
new file mode 100644
index 0000000..d571d42
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/protocol/modbus/ModbusCode.java
@@ -0,0 +1,88 @@
+package com.maibu.core.protocol.modbus;
+
+import com.maibu.exception.ServiceException;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * Modbus功能码
+ * @author bill
+ *
+ * {bit 位操作}
+ * 线圈寄存器: bit对应一个信号的开关状态。功能码里面又分为写单个线圈寄存器和写多个线圈寄存器。对应上面的功能码也就是:0x01 0x05 0x0f
+ * 离散输入寄存器:离散输入寄存器就 是 只读线圈寄存器,每个bit表示一个开关量,是不能够写的。 功能码: 0x02
+ *
+ * {byte 字节操作}
+ * 保持寄存器: 两个byte,可读写的 写也分为单个写和多个写对应的三个:0x03 0x06 0x10
+ * 输入寄存器: 和保持寄存器类似,只支持读而不能写,一般是读取各种实时数据。一个寄存器也是占据两个byte的空间。对应的功能码: 0x04
+ *
+ */
+@Getter
+@AllArgsConstructor
+public enum ModbusCode {
+
+ Read01("读线圈",(byte) 0x01,"1"), // 读线圈(读写位模式)
+ Read02("读离散量输入",(byte) 0x02,"2"), // 读离散量输入(位只读模式)
+ Read03("读保持寄存器",(byte) 0x03,"3"), // 读保持寄存器(字节读写模式)
+ Read04("读输入寄存器",(byte) 0x04,"4"), // 读输入寄存器(字节只读模式)
+
+ Write05("写单个线圈(读写位模式)",(byte) 0x05,"5"), // 写单个线圈(读写位模式)
+ Write06("写多个线圈",(byte) 0x06,"6"), // 写单个保持寄存器
+ Write0F("写多个线圈",(byte) 0x0F,"15"), // 写多个线圈
+ Write10("写多个保持寄存器",(byte) 0x10,"16"), // 写多个保持寄存器
+ UnKnow("未知功能码",(byte)0x0000,"100");
+
+ private String desc;
+ private byte code;
+ private String hex;
+
+ public static ModbusCode getInstance(int code) {
+ switch ((byte)code) {
+ case 0x01:
+ return Read01;
+ case 0x02:
+ return Read02;
+ case 0x03:
+ return Read03;
+ case 0x04:
+ return Read04;
+
+ case 0x05:
+ return Write05;
+ case 0x06:
+ return Write06;
+ case 0x0F:
+ return Write0F;
+ case 0x10:
+ return Write10;
+
+ default:
+ throw new ServiceException("功能码[" + code + "],未定义");
+ }
+ }
+
+ public static String getDes(int code){
+ switch ((byte)code) {
+ case 0x01:
+ return Read01.desc;
+ case 0x02:
+ return Read02.desc;
+ case 0x03:
+ return Read03.desc;
+ case 0x04:
+ return Read04.desc;
+ case 0x05:
+ return Write05.desc;
+ case 0x06:
+ return Write06.desc;
+ case 0x0F:
+ return Write0F.desc;
+ case 0x10:
+ return Write10.desc;
+
+ default:
+ return "UNKOWN";
+ }
+ }
+
+}
diff --git a/maibu-common/src/main/java/com/maibu/core/redis/RedisCache.java b/maibu-common/src/main/java/com/maibu/core/redis/RedisCache.java
new file mode 100644
index 0000000..ce1ab7c
--- /dev/null
+++ b/maibu-common/src/main/java/com/maibu/core/redis/RedisCache.java
@@ -0,0 +1,914 @@
+package com.maibu.core.redis;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.maibu.utils.StringUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.BooleanUtils;
+import org.springframework.data.redis.core.*;
+import org.springframework.data.redis.support.atomic.RedisAtomicLong;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Isolation;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static com.maibu.core.redis.RedisKeyBuilder.buildModbusTcpCacheKey;
+import static com.maibu.core.redis.RedisKeyBuilder.buildModbusTcpRuntimeCacheKey;
+import static java.util.regex.Pattern.compile;
+
+/**
+ * spring redis 工具类
+ *
+ * @author ruoyi
+ **/
+@SuppressWarnings(value = {"unchecked", "rawtypes"})
+@Component
+@Slf4j
+public class RedisCache {
+ @Resource
+ public RedisTemplate redisTemplate;
+
+ @Resource
+ private StringRedisTemplate stringRedisTemplate;
+
+
+ /**
+ * 缓存基本的对象,Integer、String、实体类等
+ *
+ * @param key 缓存的键值
+ * @param value 缓存的值
+ */
+ public void setCacheObject(final String key, final T value) {
+ redisTemplate.opsForValue().set(key, value);
+ }
+
+ /**
+ * 缓存基本的对象,Integer、String、实体类等
+ *
+ * @param key 缓存的键值
+ * @param value 缓存的值
+ * @param timeout 时间
+ * @param timeUnit 时间颗粒度
+ */
+ public void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
+ redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
+ }
+
+ /**
+ * 设置有效时间
+ *
+ * @param key Redis键
+ * @param timeout 超时时间
+ * @return true=设置成功;false=设置失败
+ */
+ public boolean expire(final String key, final long timeout) {
+ return expire(key, timeout, TimeUnit.SECONDS);
+ }
+
+ /**
+ * 设置有效时间
+ *
+ * @param key Redis键
+ * @param timeout 超时时间
+ * @param unit 时间单位
+ * @return true=设置成功;false=设置失败
+ */
+ public boolean expire(final String key, final long timeout, final TimeUnit unit) {
+ return redisTemplate.expire(key, timeout, unit);
+ }
+
+ /**
+ * 获取有效时间
+ *
+ * @param key Redis键
+ * @return 有效时间
+ */
+ public long getExpire(final String key) {
+ return redisTemplate.getExpire(key);
+ }
+
+ /**
+ * 判断 key是否存在
+ *
+ * @param key 键
+ * @return true 存在 false不存在
+ */
+ public Boolean hasKey(String key) {
+ return redisTemplate.hasKey(key);
+ }
+
+ /**
+ * 获得缓存的基本对象。
+ *
+ * @param key 缓存键值
+ * @return 缓存键值对应的数据
+ */
+ public T getCacheObject(final String key) {
+ ValueOperations operation = redisTemplate.opsForValue();
+ return operation.get(key);
+ }
+
+ /**
+ * 删除单个对象
+ *
+ * @param key
+ */
+ public boolean deleteObject(final String key) {
+ return redisTemplate.delete(key);
+ }
+
+ /**
+ * 删除集合对象
+ *
+ * @param collection 多个对象
+ * @return
+ */
+ public boolean deleteObject(final Collection collection) {
+ return redisTemplate.delete(collection) > 0;
+ }
+
+ /**
+ * 缓存List数据
+ *
+ * @param key 缓存的键值
+ * @param dataList 待缓存的List数据
+ * @return 缓存的对象
+ */
+ public long setCacheList(final String key, final List dataList) {
+ Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
+ return count == null ? 0 : count;
+ }
+
+ /**
+ * 获得缓存的list对象
+ *
+ * @param key 缓存的键值
+ * @return 缓存键值对应的数据
+ */
+ public List getCacheList(final String key) {
+ return redisTemplate.opsForList().range(key, 0, -1);
+ }
+
+ /**
+ * 缓存Set
+ *
+ * @param key 缓存键值
+ * @param dataSet 缓存的数据
+ * @return 缓存数据的对象
+ */
+ public BoundSetOperations setCacheSet(final String key, final Set dataSet) {
+ BoundSetOperations setOperation = redisTemplate.boundSetOps(key);
+ Iterator it = dataSet.iterator();
+ while (it.hasNext()) {
+ setOperation.add(it.next());
+ }
+ return setOperation;
+ }
+
+ /**
+ * 获得缓存的set
+ *
+ * @param key
+ * @return
+ */
+ public Set getCacheSet(final String key) {
+ return redisTemplate.opsForSet().members(key);
+ }
+
+ /**
+ * 缓存Map
+ *
+ * @param key
+ * @param dataMap
+ */
+ public void setCacheMap(final String key, final Map dataMap) {
+ if (dataMap != null) {
+ redisTemplate.opsForHash().putAll(key, dataMap);
+ }
+ }
+
+ /**
+ * 获得缓存的Map
+ *
+ * @param key
+ * @return
+ */
+ public Map getCacheMap(final String key) {
+ return redisTemplate.opsForHash().entries(key);
+ }
+
+ /**
+ * 往Hash中存入数据
+ *
+ * @param key Redis键
+ * @param hKey Hash键
+ * @param value 值
+ */
+ public void setCacheMapValue(final String key, final String hKey, final T value) {
+ redisTemplate.opsForHash().put(key, hKey, value);
+ }
+
+ /**
+ * 获取Hash中的数据
+ *
+ * @param key Redis键
+ * @param hKey Hash键
+ * @return Hash中的对象
+ */
+ public T getCacheMapValue(final String key, final String hKey) {
+ HashOperations opsForHash = redisTemplate.opsForHash();
+ return opsForHash.get(key, hKey);
+ }
+
+ /**
+ * 获取多个Hash中的数据
+ *
+ * @param key Redis键
+ * @param hKeys Hash键集合
+ * @return Hash对象集合
+ */
+ public List getMultiCacheMapValue(final String key, final Collection