This commit is contained in:
kerwincui
2024-03-17 14:59:23 +08:00
parent 3d44f4674c
commit 5539c1b6af
999 changed files with 115642 additions and 10757 deletions

22
CHANGELOG.md Normal file
View File

@@ -0,0 +1,22 @@
<a name="v2.0.0"></a>
## [v2.0.0] - 2024-01-31
### 新增功能
- 支持netty mqtt broker ([#1]())
- 支持多种编码协议管理([#2]())
- 支持emqx5.0([#3]())
### 功能优化
- 设备列表卡片优化,设备详情页面优化
- 物模型功能优化
- 产品管理功能优化
### 代码重构
- java项目代码目录重新调整
- 消息网关重构
### 其他事务
- 新增Git提交规范([#Git提交规范](https://gitee.com/kerwincui/wumei-smart/blob/master/doc/Git%E6%8F%90%E4%BA%A4%E8%A7%84%E8%8C%83.md))
- 新增贡献者指南([#贡献者指南](https://gitee.com/kerwincui/wumei-smart/blob/master/doc/%E8%B4%A1%E7%8C%AE%E8%80%85%E6%8C%87%E5%8D%97.md))
- 新增功能规划([#功能规划](https://gitee.com/kerwincui/wumei-smart/blob/master/RoadMap.md))
- 修改项目AGPL3协议商用授权说明

View File

@@ -6,18 +6,40 @@
1. FastBee开源物联网平台简单易用更适合中小企业和个人学习使用。适用于智能家居、智慧办公、智慧社区、农业监测、水利监测、工业控制等。
2. 系统后端采用Spring boot前端采用Vue消息服务器采用EMQX移动端支持微信小程序、安卓、苹果和H5采用Uniapp数据库采用Mysql、TDengine和Redis设备端支持ESP32、ESP8266、树莓派、合宙等
<img src="https://oscimg.oschina.net/oscnet/up-004a50200a81efff7530d2cf963052b4e8c.png" />
<img src="https://oscimg.oschina.net/oscnet/up-004a50200a81efff7530d2cf963052b4e8c.png" />
### 二、系统功能
- 权限管理: 用户管理、部门管理、岗位管理、菜单管理、角色管理、字典和参数管理等
- 系统监控: 操作日志、登录日志、系统日志、在线用户、服务监控、连接池监控、缓存监控等
- 产品管理: 产品、产品物模型、产品分类、产品固件、设备授权码、自定义告警等
- 设备管理: 设备控制、设备分组、设备定时、设备日志、监测统计、设备定位、设备分享、设备禁用、OTA升级、实时状态、影子模式、实时监测、加密认证等
- EMQ管理 Mqtt客户端、监听器、消息主题、消息订阅、插件管理、规则引擎、资源
- 硬件 SDK 支持WIFI和MQTT连接、物模型响应、实时监测、定时上报数据、AES加密、NTP时间、AP配网等
- 物模型管理: 属性(设备状态和监测数据),功能(执行特定任务),事件(设备主动上报给云端)
- 扩展模块: 智能音响小度、天猫精灵、小爱同学、web组态等
- 其他功能网关、TCP/Modbus/协议和netty-mqtt支持、视频监控、多租户、场景联动、数据可视化平台、统计、新闻资讯、通知公告、支持TDengine时序数据库
| 系统功能 | 功能说明 | 开源版本 | 商业版本 |
|:--------:|:-----------------------------------------------:|------|--------------|
| 产品管理 | 产品详情、产品物模型、产品分类、设备授权、产品固件 | 支持 | 支持 |
| 设备管理 | 设备详情、设备分组、设备日志、设备分享、设备实时控制、实时状态、数据监测 | 支持 | 支持 |
| 物模型管理 | 属性(设备状态和监测数据),功能(执行特定任务),事件(设备主动上报给云端) | 支持 | 支持 |
| MQTT接入 | emqx开源版、netty版本MqttBroker | 支持 | 支持 |
| 硬件 SDK | ESP-IDF、Arduino、RaspberryPi、合宙等平台设备接入 | 支持 | 支持 |
| 视频监控接入 | 基于GB/T28181协议支持主流厂商监控设备接入直播、设备录制回放、 云端录像和云台控制 | 支持设备接入和直播 | 支持 |
| 多协议管理 | 硬件设备多种协议支持管理 | 支持JSON | 支持多种 |
| TCP接入 | 基于Netty搭建的TCP服务器 | 不支持 | 支持 |
| UDP接入 | 基于Netty搭建的UDP服务器 | 不支持 | 支持 |
| Modbus接入 | 透传Modbus/边缘网关接入Modbus设备 | 不支持 | 支持 |
| 采集点管理 | 网关设备管理子设备接入 | 不支持 | 支持 |
| OTA升级 | 固件在线升级 | 不支持 | 支持 |
| 设备模拟器调试 | Modbus设备在线调试 | 不支持 | 支持 |
| 数据大屏 | 数据大屏可视化将图表或页面元素封装为基础组件0代码即可完成业务需求。 | 不支持 | 支持 |
| 规则引擎-规则脚本 | 可视化规则引擎编写支持js,java等脚本修改消息结构处理设备上行/下行/上线/下线/数据解析/数据转换 | 不支持 | 支持 |
| 场景联动 | 基于规则引擎生成场景联动 | 不支持 | 支持 |
| 告警&&告警配置&&告警记录 | 告警: 设备告警/平台告警判定 告警配置: 基于规则引擎开发的平台告警判定 告警记录:设备告警记录入库 | 不支持 | 支持 |
| 通知渠道 &&通知面板&&通知日志 | 阿里云短信/腾讯云短信阿里云语言/腾讯云语音/QQ邮箱/163邮箱/微信小程序/企业微信群机器人/企业微信应用信息/钉钉消息通知/钉钉群机器人 | 不支持 | 支持 |
| 多租户 | 系统内租户的管理,独占一套系统配置,数据相互隔离。如:租户权限、过期时间、用户数量、企业信息等 | 不支持 | 支持 |
| 移动端app | 移动端(安卓 / 苹果 / 微信小程序) | 不支持 | 支持 |
| 云云对接 -智能音响(小度、天猫精灵、小爱同学) | 云云对接 | 不支持 | 额外付费模块 |
| web组态 | 自定义数据大屏/2D/3D | 不支持 | 额外付费模块 |
| 萤石云海康sdk接入、AI SDK接入 | 视频接入 | 不支持 | 额外付费模块 |
| 数据存储 | 设备数据处理 | redis存储最后一条数据不支持实时更新 | redis存储最新数据,实时更新/mysql存储系统数据/TDengine时序数据库存储设备数据 |
| 设备接入数/上行数据并发支持 | 设备接入数,以及设备数据并发量 | 支持小规模设备接入,同步处理数据 | 支持规模量大设备。消息队列削峰,线程池异步处理高并发数据 |
| 技术支持 | | 不支持 | 提供一定的技术支持/技术方案 |
![](https://oscimg.oschina.net/oscnet/up-a9a7fdaf40208becd26c2485783bc0f86e6.png)
@@ -26,55 +48,63 @@
| ![](https://oscimg.oschina.net/oscnet/up-ad98a81677e5e68d660866770e3266ca4cf.png) | ![](https://oscimg.oschina.net/oscnet/up-68caf860d0659444e73f42717a03d2fdf72.png) | ![](https://oscimg.oschina.net/oscnet/up-cf690f6058042dccb567ff382ea9432ebab.png) |![](https://oscimg.oschina.net/oscnet/up-c4a7971510127324d6566dd6ea95d571483.jpg) | ![](https://oscimg.oschina.net/oscnet/up-4ce09be3599e3ff7ed91fe182572abd258b.jpg) |
### 三、技术栈
### 三、技术栈
* 服务端
- 相关技术Spring boot、MyBatis、Spring Security、Jwt、Mysql、Redis、TDengine、EMQX、Netty等
- 开发工具IDEA
- 相关技术Spring boot、MyBatis、Spring Security、Jwt、Mysql、Redis、TDengine、EMQX、Netty等
- 开发工具IDEA
* Web端
- 相关技术ES6、Vue、Vuex、Vue-router、Vue-cli、Axios、Element-ui、Echart等
- 开发工具Visual Studio Code
- 相关技术ES6、Vue、Vuex、Vue-router、Vue-cli、Axios、Element-ui、Echart等
- 开发工具Visual Studio Code
* 移动端(微信小程序 / Android / Ios / H5
- 相关技术uniapp、[uView](https://www.uviewui.com/)、[uChart](https://www.ucharts.cn/)
- 开发工具HBuilder
- 相关技术uniapp、[uView](https://www.uviewui.com/)、[uChart](https://www.ucharts.cn/)
- 开发工具HBuilder
* 硬件端
- 相关技术: ESP-IDF、Arduino、FreeRTOS、Python、Lua等
- 开发工具Visual Studio Code 和 Arduino等
- 相关技术: ESP-IDF、Arduino、FreeRTOS、Python、Lua等
- 开发工具Visual Studio Code 和 Arduino等
### 四、项目目录
&nbsp;&nbsp;&nbsp;&nbsp; spring-boot --------------- 后端<br/>
&nbsp;&nbsp;&nbsp;&nbsp; vue ----------------------- 前端<br />
&nbsp;&nbsp;&nbsp;&nbsp; docker -------------------- docker部署文件<br />
&nbsp;&nbsp;&nbsp;&nbsp; sdk ----------------------- 硬件SDK,已集成多种设备<br />
&nbsp;&nbsp;&nbsp;&nbsp; app -------------------- 移动端(微信小程序 / Android / Ios / H5 商业版开源<br/>
&nbsp;&nbsp;&nbsp;&nbsp; docker ---------------- docker部署文件<br />
&nbsp;&nbsp;&nbsp;&nbsp; sdk -------------------- 硬件SDK,已集成多种设备<br />
&nbsp;&nbsp;&nbsp;&nbsp; spring-boot ---------- 后端<br/>
&nbsp;&nbsp;&nbsp;&nbsp; vue -------------------- 前端<br />
### 五、商用授权
项目采用AGPL3协议可用于个人学习和使用商业用途需要赞助项目获得授权并提供商业版本源码、可视化平台和移动端源码。赞助过的用户请下载商业版本源码。
- [授权详情>>](https://fastbee.cn/doc/pages/sponsor/) &nbsp; [商业版本源码>>](https://fastbee.cn/doc/pages/sponsor/)
- [移动端源码>>](https://fastbee.cn/doc/pages/sponsor/) &nbsp; [可视化平台源码>>](https://fastbee.cn/doc/pages/sponsor/)
- [移动端源码>>](https://fastbee.cn/doc/pages/sponsor/) &nbsp; [可视化平台源码>>](https://fastbee.cn/doc/pages/sponsor/)
- 二开项目同样遵守AGPL3.0协议进行开源,可以向原作者申请授权
- 如果商业项目想转闭源,可以向原作者申请或者购买闭源授权
### 六、贡献代码
- [贡献者指南>>](./doc/贡献者指南.md)
- [Git提交规范>>](./doc/Git提交规范.md)
- [功能规划>>](./RoadMap.md)
### 、其他
### 、其他
1. QQ交流群&#x1F680;946029159 &#x1F680;1073236354(已满)
2. 权限管理基于ruoyi-vue系统开发Mqtt消息服务器使用EMQX4.0开源版
2. 权限管理基于ruoyi-vue系统开发Mqtt消息服务器使用EMQX5.0开源版
* [在线演示](https://iot.fastbee.cn/)
* [项目使用文档](https://fastbee.cn/doc/)
* [若依权限管理系统文档](http://doc.ruoyi.vip/ruoyi-vue/)
* [EMQX4.0消息服务器文档](https://www.emqx.io/docs/zh/v4.0/)
* [uCharts高性能跨平台图表库](https://www.ucharts.cn)
* [开源版本在线演示](http://101.33.237.12/)
* [商业版本在线演示](https://iot.fastbee.cn/)
* [项目使用文档](https://fastbee.cn/doc/)
* [若依权限管理系统文档](http://doc.ruoyi.vip/ruoyi-vue/)
* [EMQX5.0消息服务器文档](https://www.emqx.io/docs/zh/v5.0/)
* [uCharts高性能跨平台图表库](https://www.ucharts.cn)
3. 项目贡献者(如有遗漏请联系作者)
- [小驿物联](https://gitee.com/iot-xiaoyi)、[CrazyDull](https://gitee.com/crazyDull)、[YBZX](https://github.com/YBZX)、 [CQAdu](https://gitee.com/iot.adu)、[孙阿龙](https://gitee.com/sunalong)、[xxmfl](https://gitee.com/xxmfl)、[董晓龙-3715687@qq.com](https://fastbee.cn/)
- [SXH](https://gitee.com/sixiaohu)、 [Redamancy_zxp](https://gitee.com/redamancy-zxp)、 [LEE](https://gitee.com/yueming188)、 [LemonTree](https://gitee.com/fishhunterplus)、 [Tang](https://gitee.com/mexiaotang)、 [Tang](https://gitee.com/mexiaotang)、[KUN](https://gitee.com/L_KUN_KUN)
- [小驿物联](https://gitee.com/iot-xiaoyi)、[CrazyDull](https://gitee.com/crazyDull)、[YBZX](https://github.com/YBZX)、 [CQAdu](https://gitee.com/iot.adu)、[孙阿龙](https://gitee.com/sunalong)、[xxmfl](https://gitee.com/xxmfl)、[董晓龙-3715687@qq.com](https://fastbee.cn/)
- [SXH](https://gitee.com/sixiaohu)、 [Redamancy_zxp](https://gitee.com/redamancy-zxp)、 [LEE](https://gitee.com/yueming188)、 [LemonTree](https://gitee.com/fishhunterplus)、 [Tang](https://gitee.com/mexiaotang)、 [Tang](https://gitee.com/mexiaotang)、[KUN](https://gitee.com/L_KUN_KUN)
4. 主要参与用户:
- [Guanshubiao](https://gitee.com/guanshubiao):熟悉物联网开发,完善和优化系统的网关架构和部分功能等
- [帐篷](https://gitee.com/zhuangpengli):熟悉物联网开发,完善视频监控模块和部分协议等
- [JaminDeng](https://gitee.com/jamin-deng):熟悉物联网开发,完善平台前端设计可视化等
### 、部分图片
### 、部分图片
![](https://oscimg.oschina.net/oscnet/up-972dea7b54eca705dcc8bf2fe0680b12c09.png)
![](https://oscimg.oschina.net/oscnet/up-6d89f1558797a9becf07c20f92c1407a13a.png)
@@ -103,4 +133,3 @@
</table>

57
RoadMap.md Normal file
View File

@@ -0,0 +1,57 @@
# 架构优化
- 代码简化
- 业务&协议解耦
- 关键组件支持横向拓展
- 网络协议支持横向拓展包括mqtt broker,tcp,coap,udp,sip等
- 协议插件化
- 编码脚本化
- 业务代码模版化
- 消息总线
# 功能优化
- 网关/子网关:上线,绑定,拓扑,消息代理/透传/轮询等功能完善
- 设备详情简化,运行状态,监测,历史记录等界面优化,组件可编辑
- 设备OT能力完善配合SDK完善设备产测设备出厂配置设备一键注网设备批量上线设备升级设备维护&替换等流程
- 设备IT能力完善更方便对接联动第三方系统打通数据烟囱集成更多三方SDK
- 消息路由,消息流转,消息编解码,消息过滤更加灵活
# 功能拓展
- 规则引擎
- 组态
- 可视化大屏
- 视频监控协议
- 视频分析,图形识别能力
- coap协议
- sip协议
- snmp协议
- tr069/tr369协议
- plc对接
- modbus rtu/ascii/tcp等协议
- ai能力
- gpt能力
# 设备SDK
- esp-idf框架搭建
- 基于esp-aliyun编写fastbee相关mqtt接入示例
- esp-modbus示例完善增加mqtt透传主站轮询指令下发等特性
- esp-aliyun重构升级esp-idf5.0
- esp-fastbee组件模块开发
- rt-thread,openwrt等os接入组件开发
- 尝试适配更多硬件方案rk,esp32,stm32,合宙等等
- 免费帮10家不同类型设备厂商接入平台
# 文档完善
- 新手入门任务
- 各模块使用说明书
- 调试方式文档
- 二次开发说明书
- 三方工具关键组件使用说明
- 简化代码二发和部署流程
- 交付方式优化docker镜像一键部署包等方式
# 社区建设
- 发展一批Committer
- 规范issues和pr流程
- 完善测试用例和测试流程
- 完善自动化发布,代码静态检查,自动化测试等流程
- 与行业伙伴共同打造5-8个垂直行业典型案例

22
doc/CHANGELOG.md Normal file
View File

@@ -0,0 +1,22 @@
<a name="v2.0.0"></a>
## [v2.0.0] - 2024-01-31
### 新增功能
- 支持netty mqtt broker ([#1]())
- 支持多种编码协议管理([#2]())
- 支持emqx5.0([#3]())
### 功能优化
- 设备列表卡片优化,设备详情页面优化
- 物模型功能优化
- 产品管理功能优化
### 代码重构
- java项目代码目录重新调整
- 消息网关重构
### 其他事务
- 新增Git提交规范([#Git提交规范](https://gitee.com/kerwincui/wumei-smart/blob/master/doc/Git%E6%8F%90%E4%BA%A4%E8%A7%84%E8%8C%83.md))
- 新增贡献者指南([#贡献者指南](https://gitee.com/kerwincui/wumei-smart/blob/master/doc/%E8%B4%A1%E7%8C%AE%E8%80%85%E6%8C%87%E5%8D%97.md))
- 新增功能规划([#功能规划](https://gitee.com/kerwincui/wumei-smart/blob/master/RoadMap.md))
- 修改项目AGPL3协议商用授权说明

63
doc/Git提交规范.md Normal file
View File

@@ -0,0 +1,63 @@
# 一conventional commit(约定式提交)
Conventional Commits 是一种用于给提交信息增加人机可读含义的规范。它提供了一组用于创建清晰的提交历史的简单规则。
## 1.1 作用
- 自动化生成 CHANGELOG
- 基于提交类型,自动决定语义化的版本变更
- 向项目相关合作开发者发送变更信心
- 触发自动化构建和部署流程
- 给开发者提供一个更加结构化的提交历史,便于减低对项目做贡献的难度
## 1.2 提交格式
提交说明的结构如下:
<type>(<scope>): <subject>
空行
[可选的正文]
空行
[可选的脚注]
### 1.2.1 Header
Header部分只有一行包括三个字段 type必需、scope必需和subject必需
#### 1type 类型
type用于说明 commit 的类别只允许使用下面7个标识
- feat新功能feature
- fix修补bug
- docs文档documentation
- style 格式(不影响代码运行的变动)
- refactor重构即不是新增功能也不是修改bug的代码变动
- test增加测试
- build构建过程或辅助工具的变动
#### 2scope 范围
scope用于说明 commit 影响的范围,比如指标模板、规则上下线等等,视项目不同而不同。
#### 3subject 主题
subject是 commit 目的的简短描述不超过50个字符。
1. 以动词开头使用第一人称现在时比如change而不是changed或changes
2. 第一个字母小写
3. 结尾不加句号(.
### 1.2.2 Body 正文
Body 部分是对本次 commit 的详细描述,可以分成多行。
1. 需要简要的列出各种正向或者反向的测试场景测试通过填pass。
2. 增加修改人信息
## 1.3 例子
### 1.3.1 feat例子
```
feat(规则上下线、构建、生效、仿真生效): 添加规则上下线功能
1. 规则上下线主流程引擎正常订阅fldl生成正常。 pass
2. 规则上下线,传入不存在的规则编号,异常提示。 pass
提交人xxx
```
### 1.3.2 fix例子
```
fix(模型模块): 模型测试失败
1. 导入mar模型包含衍生字段。 pass
2. 导入mar模型不包含衍生字段。 pass
提交人xxx
```
## 1.4 IDEA插件推荐
1. 安装路径File->Settings->Plugins->Marketplace->搜索Conventional Commit点击安装即可。
2. 提交的时候点击中间的小红点创建提交消息,根据对话框提示填写相关信息即可生成规范的提交消息。

69
doc/贡献者指南.md Normal file
View File

@@ -0,0 +1,69 @@
> 非常欢迎参与项目贡献,我们致力于维护一个互相帮助,共同成长社区。
# 贡献方式
在Fastbee 社区,贡献方式有很多:
- 💻代码可以帮助社区完成一些任务、编写新的feature或者是修复一些bug
-测试可以来参与测试代码的编写包括了单元测试、集成测试、e2e测试
- ✅编译构建或者辅助工具建议包括DockerK8sCI/CD辅助调试工具等
- 📖文档:可以编写或完善文档,来帮助用户更好地了解和使用 物联网平台;
- 🤔讨论:可以参与 Fastbee 新的feature的讨论将您的想法跟 Fastbee 融合;
- 💬建议:也可以对项目或者社区提出一些建议,促进社区的良性发展;
- ❗疑问:问出一个好的问题,同样也可以促进项目发展,拓宽思考方向;
> 即便是小到错别字的修正我们也都非常欢迎 :)
# 提PR有以下注意点
PR统一在Gitee平台上进行提交如果你不知道如何提交PR可以在Gitee平台里去学习。这里不作说明。
- fork后切换到develop分支请以这个分支为开发基准。
- 所有的PR提交到develop分支这个分支为开发分支。
- 如果你作了功能性的变动,请带上你的测试用例,测试用例规范可以参考之前的测试用例。
- 所有的PR必须关联至少一个issue如果没有相关issue请自行创建一个。
- 正式提交PR之前请确保所有的测试用例都通过。
- Git提交消息需要按照[Git提交规范](./Git提交规范.md)。
# 提交 Pull Request
1. 首先您需要 Fork 目标仓库 Fastbee repository.
2. 然后 用git命令 将代码下载到本地:
```
git clone https://gitee.com/zhuangpengli/FastBee
```
3. 下载完成后请参考目标仓库README 文件对项目进行初始化。
4. 接着,您可以参考如下命令进行代码的提交, 切换新的分支, 进行开发:
```
# 根据项目需要创建对应分支
git checkout -b feat-xxx 或者 fix-xxx 等等
```
5. 提交 commit , commit 描述信息需要符合[约定格式](./Git提交规范.md).
```
git add <modified file/path>
git commit -m '[docs]feature: necessary instructions'
```
6. 推送到远程仓库
```
git push origin feat-xxx
```
7. 然后您就可以在 Gitee 上发起新的 PR (Pull Request)。
> 注意!!! PR 的标题需要符合我们的规范,并且在 PR 中写上必要的说明,来方便 Committer 和其他贡献者进行代码审查。等待PR代码被合并
> 在提交了 PR 后Committer 或者社区的小伙伴们会对您提交的代码进行审查Code Review会提出一些修改建议或者是进行一些讨论请及时关注您的PR。
若后续需要改动,不需要发起一个新的 PR在原有的分支上提交 commit 并推送到远程仓库后PR会自动更新。
# 代码被合并后
在代码被合并后,您就可以在本地和远程仓库删除这个开发分支了:
```
git branch -d feat-xxx
git push origin --delete feat-xxx在主分支上
```
您可以执行以下操作来同步上游仓库:
```
git remote add upstream https://gitee.com/zhuangpengli/FastBee.git
#Bind the remote warehouse, if it has been executed, it does not need to be executed againgit checkout master git pull upstream master
```

50
docker/Dockerfile Normal file
View File

@@ -0,0 +1,50 @@
FROM ubuntu:20.04 as build
RUN export DEBIAN_FRONTEND=noninteractive &&\
apt-get update && \
apt-get install -y --no-install-recommends openjdk-8-jre-headless openjdk-8-jdk-headless git maven nodejs npm openssl && \
mkdir -p /opt/fastbee/java /opt/fastbee/vue
RUN cd /home && \
git clone "https://gitee.com/zhuangpengli/FastBee" && \
cp /home/FastBee/docker/settings.xml /usr/share/maven/conf/
RUN cd /home/FastBee/vue && \
npm install --registry=https://registry.npmmirror.com && \
npm run build:prod && \
cp -rf /home/FastBee/vue/dist/* /opt/fastbee/vue/
RUN cd /home/FastBee/springboot && \
mvn clean package -Dmaven.test.skip=true && \
cp -rf /home/FastBee/springboot/fastbee-admin/target/fastbee-admin.jar /opt/fastbee/java
FROM openjdk:8-jre
EXPOSE 8080/tcp
EXPOSE 1883/tcp
EXPOSE 8083/tcp
EXPOSE 8888/tcp
EXPOSE 8889/tcp
EXPOSE 5061/udp
ENV LC_ALL zh_CN.UTF-8
COPY --from=build /opt/fastbee/java /opt
WORKDIR /opt
CMD ["java", "-jar", "/server.jar"]
FROM nginx:stable
EXPOSE 80/tcp
EXPOSE 443/tcp
ENV LC_ALL zh_CN.UTF-8
COPY --from=build /opt/fastbee/vue/* /usr/share/nginx/html
COPY ./data/nginx/ssl/* /usr/share/nginx/ssl
COPY ./data/nginx/nginx.conf /etc/nginx/nginx.conf

39
docker/README.md Normal file
View File

@@ -0,0 +1,39 @@
## 1.clone本项目
```
git clone https://gitee.com/zhuangpengli/fastbee-docker.git
cd fastbee-docker
cp -rf ./data /var
```
## 2.编译java包
```
git clone https://gitee.com/zhuangpengli/FastBee.git
cd FastBee/springboot
# 编译emqx版本 请修改fastbee-admin下面 application.yml
# server:
# broker:
# enabled: false
# openws: false
# 编译netty mqtt版本 保持默认配置
mvn clean package -Dmaven.test.skip=true
cp ./fastbee-admin/target/fastbee-admin.jar /var/data/java/fastbee-admin.jar
```
## 3.打包前端目录
```
git clone https://gitee.com/zhuangpengli/FastBee.git
cd FastBee/vue
npm install
npm run build:prod
cp -rf ./dist/* /var/data/nginx/vue
```
## 4.启动项目
```
cd /var/data
setenforce 0
chmod 777 -R /var/data
# 使用emqx版本mqtt broker输入该命令
sudo cp -rf docker-compose-emqx.yml docker-compose.yml
# 使用netty mqtt则使用默认脚本直接启动
docker-compose up -d
```

View File

@@ -0,0 +1,117 @@
version: '2'
networks:
network:
ipam:
driver: default
config:
- subnet: '177.7.0.0/16'
services:
redis:
image: redis:7.0.0
container_name: redis
ports:
- 6379:6379
privileged: true
networks:
network:
ipv4_address: 177.7.0.10
volumes:
- /var/data/redis:/usr/local/etc/redis
- /var/data/redis/data:/data
command: [ '-- requirepass fastbee', '-- appendonly yes' ]
mysql:
image: mysql:5.7
container_name: mysql
ports:
- 3306:3306
privileged: true
networks:
network:
ipv4_address: 177.7.0.11
volumes:
- /var/data/mysql/mysql:/var/lib/mysql
- /var/data/mysql/mysql.cnf:/etc/mysql/conf.d/mysql.cnf
- /var/data/mysql/initdb:/docker-entrypoint-initdb.d
environment:
MYSQL_DATABASE: fastbee
MYSQL_ROOT_PASSWORD: fastbee
command:
[
'mysqld',
'--character-set-server=utf8',
'--collation-server=utf8_unicode_ci',
'--default-time-zone=+8:00',
'--lower-case-table-names=1'
]
emqx:
image: emqx:5.1
container_name: emqx
ports:
- 1883:1883
- 8083:8083
- 8084:8084
- 18083:18083
privileged: true
networks:
network:
ipv4_address: 177.7.0.12
volumes:
- /etc/localtime:/etc/localtime
- /var/data/emqx/etc/emqx.conf:/opt/emqx/etc/emqx.conf
- /var/data/emqx/etc/acl.conf:/opt/emqx/etc/acl.conf
- /var/data/emqx/etc/log:/opt/emqx/log
- /var/data/emqx/data/:/opt/emqx/data
environment:
SET_CONTAINER_TIMEZONE: "true"
CONTAINER_TIMEZONE: Asia/Shanghai
java:
image: openjdk:8-jre
container_name: java
ports:
- 8080:8080
- 8888:8888
- 8889:8889/udp
- 5061:5061/udp
privileged: true
networks:
network:
ipv4_address: 177.7.0.13
depends_on:
- emqx
- redis
- mysql
- tdengine
volumes:
- /var/data/java/fastbee-admin.jar:/server.jar
- /var/data/java/libtaos.so:/usr/lib/libtaos.so
- /var/data/java/uploadPath:/uploadPath
- /var/data/java/logs:/logs
- /etc/localtime:/etc/localtime
environment:
TZ: Asia/Shanghai
entrypoint: java -jar /server.jar
nginx:
image: nginx:stable
container_name: nginx
ports:
- 80:80
- 443:443
privileged: true
networks:
network:
ipv4_address: 177.7.0.15
depends_on:
- java
volumes:
- /var/data/nginx/vue:/usr/share/nginx/html
- /var/data/nginx/h5:/usr/share/nginx/h5
- /var/data/nginx/www:/usr/share/nginx/www
- /var/data/nginx/ssl:/usr/share/nginx/ssl
- /var/data/nginx/nginx-emqx.conf:/etc/nginx/nginx.conf
- /var/data/nginx:/var/log/nginx

View File

@@ -17,11 +17,10 @@ services:
networks:
network:
ipv4_address: 177.7.0.10
restart: unless-stopped
volumes:
- /var/data/redis:/usr/local/etc/redis
- /var/data/redis/data:/data
command: [ '-- requirepass wumei-smart', '-- appendonly yes' ]
command: [ '-- requirepass fastbee', '-- appendonly yes' ]
mysql:
image: mysql:5.7
@@ -32,14 +31,13 @@ services:
networks:
network:
ipv4_address: 177.7.0.11
restart: unless-stopped
volumes:
- /var/data/mysql/mysql:/var/lib/mysql
- /var/data/mysql/mysql.cnf:/etc/mysql/conf.d/mysql.cnf
- /var/data/mysql/initdb:/docker-entrypoint-initdb.d
environment:
MYSQL_DATABASE: wumeismart
MYSQL_ROOT_PASSWORD: wumei-smart
MYSQL_DATABASE: fastbee
MYSQL_ROOT_PASSWORD: fastbee
command:
[
'mysqld',
@@ -49,48 +47,27 @@ services:
'--lower-case-table-names=1'
]
emqx:
image: emqx/emqx:v4.0.0
container_name: emqx
ports:
- 1883:1883
- 8081:8081
- 8083:8083
- 8883:8883
- 8084:8084
- 18083:18083
privileged: true
networks:
network:
ipv4_address: 177.7.0.12
restart: unless-stopped
volumes:
- /etc/localtime:/etc/localtime
- /var/data/emqx/conf/emqx_auth_http.conf:/opt/emqx/etc/plugins/emqx_auth_http.conf
- /var/data/emqx/conf/emqx_web_hook.conf:/opt/emqx/etc/plugins/emqx_web_hook.conf
- /var/data/emqx/data/loaded_plugins:/opt/emqx/data/loaded_plugins
environment:
EMQX_ALLOW__ANONYMOUS: "false"
SET_CONTAINER_TIMEZONE: "true"
CONTAINER_TIMEZONE: Asia/Shanghai
java:
image: openjdk:8-jre
container_name: java
ports:
- 8080:8080
- 1883:1883
- 8083:8083
- 8888:8888
- 8889:8889/udp
- 5061:5061/udp
privileged: true
networks:
network:
ipv4_address: 177.7.0.13
ipv4_address: 177.7.0.12
depends_on:
- emqx
- redis
- mysql
restart: unless-stopped
- tdengine
volumes:
- /var/data/java/wumei-admin.jar:/server.jar
- /var/data/java/fastbee-admin.jar:/server.jar
- /var/data/java/libtaos.so:/usr/lib/libtaos.so
- /var/data/java/uploadPath:/uploadPath
- /var/data/java/logs:/logs
- /etc/localtime:/etc/localtime
@@ -103,17 +80,20 @@ services:
container_name: nginx
ports:
- 80:80
- 15060:15060/udp
- 443:443
privileged: true
networks:
network:
ipv4_address: 177.7.0.14
ipv4_address: 177.7.0.13
depends_on:
- java
restart: unless-stopped
volumes:
- /var/data/nginx/html:/usr/share/nginx/html
- /var/data/nginx/vue:/usr/share/nginx/html
- /var/data/nginx/h5:/usr/share/nginx/h5
- /var/data/nginx/www:/usr/share/nginx/www
- /var/data/nginx/ssl:/usr/share/nginx/ssl
- /var/data/nginx/nginx.conf:/etc/nginx/nginx.conf
- /var/data/nginx:/var/log/nginx

View File

@@ -0,0 +1,32 @@
%%--------------------------------------------------------------------
%% -type(ipaddr() :: {ipaddr, string()}).
%%
%% -type(ipaddrs() :: {ipaddrs, string()}).
%%
%% -type(username() :: {user | username, string()} | {user | username, {re, regex()}}).
%%
%% -type(clientid() :: {client | clientid, string()} | {client | clientid, {re, regex()}}).
%%
%% -type(who() :: ipaddr() | ipaddrs() |username() | clientid() |
%% {'and', [ipaddr() | ipaddrs()| username() | clientid()]} |
%% {'or', [ipaddr() | ipaddrs()| username() | clientid()]} |
%% all).
%%
%% -type(action() :: subscribe | publish | all).
%%
%% -type(topic_filters() :: string()).
%%
%% -type(topics() :: [topic_filters() | {eq, topic_filters()}]).
%%
%% -type(permission() :: allow | deny).
%%
%% -type(rule() :: {permission(), who(), access(), topics()} | {permission(), all}).
%%--------------------------------------------------------------------
{allow, {username, {re, "^dashboard$"}}, subscribe, ["$SYS/#"]}.
{allow, {ipaddr, "127.0.0.1"}, all, ["$SYS/#", "#"]}.
{deny, all, subscribe, ["$SYS/#", {eq, "#"}]}.
{allow, all}.

View File

@@ -0,0 +1,92 @@
## NOTE:
## This config file overrides data/configs/cluster.hocon,
## and is merged with environment variables which start with 'EMQX_' prefix.
##
## Config changes made from EMQX dashboard UI, management HTTP API, or CLI
## are stored in data/configs/cluster.hocon.
## To avoid confusion, please do not store the same configs in both files.
##
## See https://docs.emqx.com/en/enterprise/v5.0/configuration/configuration.html
## Configuration full example can be found in emqx.conf.example
node {
name = "emqx@177.7.0.12"
cookie = "emqxsecretcookie"
data_dir = "data"
}
cluster {
name = emqxcl
discovery_strategy = manual
}
dashboard {
listeners.http {
bind = 18083
}
default_username = "admin"
default_password = "admin123"
}
authorization {
deny_action = ignore
no_match = allow
cache = { enable = true }
}
## http 认证
authentication = [
{
mechanism = password_based
backend = http
enable = true
method = post
url = "http://java:8080/iot/tool/mqtt/authv5"
body {
clientid = "${clientid}"
username = "${username}"
password = "${password}"
peerhost = "${peerhost}"
}
headers {
"Content-Type" = "application/json"
"X-Request-Source" = "EMQX"
}
}
]
# WebHook(匹配上线和下线规则后触发)
bridges {
webhook.fastbee_hook =
{
enable = true
connect_timeout = 15s
retry_interval = 60s
pool_type = random
pool_size = 8
enable_pipelining = 100
max_retries = 2
request_timeout = 15s
method = post
url = "http://java:8080/iot/tool/mqtt/webhookv5"
body = "{\"clientid\" : \"${clientid}\",\"event\" : \"${event}\",\"peername\" : \"${peername}\"}"
headers = { accept = "application/json" "cache-control" = "no-cache" connection = "keep-alive" "content-type" = "application/json" "keep-alive" = "timeout=5"}
}
}
# 规则(处理上线和下线)
rule_engine {
ignore_sys_message = true
jq_function_default_timeout = 10s
rules.fastbee_rule =
{
sql = "SELECT * FROM \"t/#\",\"$events/client_connected\", \"$events/client_disconnected\", \"$events/session_subscribed\""
actions = ["webhook:fastbee_hook"]
enable = true
description = "处理设备上下线和订阅完主题的规则"
}
}

BIN
docker/data/java/libtaos.so Normal file

Binary file not shown.

View File

@@ -0,0 +1 @@
springboot打包后的文件

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,91 @@
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
gzip on;
gzip_min_length 1k;
gzip_buffers 16 64K;
gzip_http_version 1.1;
gzip_comp_level 5;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";
# Http跳转Https
# server {
# listen 80;
# server_name localhost;
# location / {
# rewrite ^(.*) https://$server_name$1 permanent;
# }
# }
server {
listen 80;
# SSL 默认访问端口号为443
listen 443 ssl;
server_name localhost;
charset utf-8;
# 证书文件的路径
ssl_certificate /usr/share/nginx/ssl/fastbee.crt;
# 私钥文件的路径
ssl_certificate_key /usr/share/nginx/ssl/fastbee.key;
ssl_session_timeout 10m;
# 请按照以下协议配置
ssl_protocols TLSv1.2 TLSv1.3;
# 请按照以下套件配置配置加密套件写法遵循openssl 标准
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_prefer_server_ciphers on;
# 前端
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
# H5移动端
location /h5 {
alias /usr/share/nginx/h5/;
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
# 后端接口
location /prod-api/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://java:8080/;
}
# wss连接代理到ws
location /mqtt {
proxy_pass http://emqx:8083/mqtt;
proxy_read_timeout 60s;
proxy_set_header Host $host;
proxy_set_header X-Real_IP $remote_addr;
proxy_set_header X-Forwarded-for $remote_addr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'Upgrade';
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

View File

@@ -20,17 +20,49 @@ http {
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";
# Http跳转Https
# server {
# listen 80;
# server_name localhost;
# location / {
# rewrite ^(.*) https://$server_name$1 permanent;
# }
# }
server {
listen 80;
listen 80;
# SSL 默认访问端口号为443
listen 443 ssl;
server_name localhost;
charset utf-8;
# 证书文件的路径
ssl_certificate /usr/share/nginx/ssl/fastbee.crt;
# 私钥文件的路径
ssl_certificate_key /usr/share/nginx/ssl/fastbee.key;
ssl_session_timeout 10m;
# 请按照以下协议配置
ssl_protocols TLSv1.2 TLSv1.3;
# 请按照以下套件配置配置加密套件写法遵循openssl 标准
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_prefer_server_ciphers on;
# 前端
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
# H5移动端
location /h5 {
alias /usr/share/nginx/h5/;
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
# 后端接口
location /prod-api/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
@@ -39,12 +71,16 @@ http {
proxy_pass http://java:8080/;
}
location /api/v4/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://emqx:8081/api/v4/;
# wss连接代理到ws
location /mqtt {
proxy_pass http://java:8083/mqtt;
proxy_read_timeout 60s;
proxy_set_header Host $host;
proxy_set_header X-Real_IP $remote_addr;
proxy_set_header X-Forwarded-for $remote_addr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'Upgrade';
}
error_page 500 502 503 504 /50x.html;

View File

@@ -0,0 +1,68 @@
-----BEGIN CERTIFICATE-----
MIIGujCCBaKgAwIBAgIQCEZHO+Au3dO0pmMgFV+CXDANBgkqhkiG9w0BAQsFADBf
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMR4wHAYDVQQDExVHZW9UcnVzdCBDTiBSU0EgQ0EgRzEw
HhcNMjEwNzI2MDAwMDAwWhcNMjIwODI1MjM1OTU5WjB+MQswCQYDVQQGEwJDTjES
MBAGA1UECAwJ5bm/5Lic55yBMRIwEAYDVQQHDAnmt7HlnLPluIIxMDAuBgNVBAoM
J+a3seWcs+W4guWTgemBk+mkkOmlrueuoeeQhuaciemZkOWFrOWPuDEVMBMGA1UE
AwwMKi5waW4tZGFvLmNuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
rMBuC6MXRP7NaP5ux7nZmuOy2wKY6xWk/i2POrfGSnX0IeY7phoGliH2EBa+UyCA
rj5B960UYDkpAmh5uCmDOO1Zs4VPwdoyj+OA6Up/LJXVg/txFvZfDkpk7lTjAQz4
OcYXxv+iMxDkpEnnlLRsUlUs2JdQUAXEzjwlKVVUqzEZ+9QY+BLb88bDQEBjaE4+
JH95/oRJAby3OH/AXljswh0VUbj3S8pAbiI6f8xoWSn9mjPSGIlABYDgWma2T0RD
9F7sbY7JS/1njPA67i8vzVRMnpkMvYLt4a2qG1THUpFysmT0R2OOb8DlOZiPhnZk
xEvUGeDx8y34FSucWLQTvwIDAQABo4IDUTCCA00wHwYDVR0jBBgwFoAUkZ9eMRWu
EJ+tYMH3wcyqSDQvDCYwHQYDVR0OBBYEFDrSDW+dz8TXCfrIPED7lQX1IGM5MCMG
A1UdEQQcMBqCDCoucGluLWRhby5jboIKcGluLWRhby5jbjAOBgNVHQ8BAf8EBAMC
BaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHUGA1UdHwRuMGwwNKAy
oDCGLmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9HZW9UcnVzdENOUlNBQ0FHMS5j
cmwwNKAyoDCGLmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9HZW9UcnVzdENOUlNB
Q0FHMS5jcmwwPgYDVR0gBDcwNTAzBgZngQwBAgIwKTAnBggrBgEFBQcCARYbaHR0
cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMG8GCCsGAQUFBwEBBGMwYTAhBggrBgEF
BQcwAYYVaHR0cDovL29jc3AuZGNvY3NwLmNuMDwGCCsGAQUFBzAChjBodHRwOi8v
Y3JsLmRpZ2ljZXJ0LWNuLmNvbS9HZW9UcnVzdENOUlNBQ0FHMS5jcnQwDAYDVR0T
AQH/BAIwADCCAX8GCisGAQQB1nkCBAIEggFvBIIBawFpAHYARqVV63X6kSAwtaKJ
afTzfREsQXS+/Um4havy/HD+bUcAAAF64K3X/QAABAMARzBFAiBOmRovvmyKDMxG
fA3H6aFk/x8ce6THZVe4bTW4gEDDJwIhANKatQg5dedqYI78Fevo3ZEUEYUyMB1V
ml1AajGZm/ebAHcAUaOw9f0BeZxWbbg3eI8MpHrMGyfL956IQpoN/tSLBeUAAAF6
4K3YDgAABAMASDBGAiEAmVXJCrNphalqawzCGHqLOHIbDUEH0S2mXOG/4jpQsKgC
IQDxC3C/aVX/D8CRj3py4OvD3PSkmP5+ZtvLsZDYEliYQQB2AEHIyrHfIkZKEMah
OglCh15OMYsbA+vrS8do8JBilgb2AAABeuCt15EAAAQDAEcwRQIhANIAPeLjWGRz
Qm11rXG9VeBazY520LJ39puYjr4ovR4tAiBwU9cJ5esSS6hOtLrSkhLCeg4i3isp
w30Hn1D77Um2UzANBgkqhkiG9w0BAQsFAAOCAQEAGPOc0d869d9C1YkbdSBwJtoh
BMkf2RFlPSIlGUacELN6gSHP37CIe7CVcwTAS+bDUGRtTD5+8loa96pbLoloEqfD
7Z7js9LE8anXazye/4W81ko3lThUq9PO0B+udKWWrhhD9wC9sfj5u22ruUN/8oyJ
OeMIYj5Xi8RTFH1QgXtg3BX3oKgRWPsib+1BgLQQgchsV709DhlT1oAI4x69JL57
K5m5eVyK5eY3Y93+5GEQLxMhxJPpBbDbsieBHvvFzZ9sFxRLSW6YlRYPKcCMd80a
+uHNq69hXv4ZBkmoJV9PI7NJDD1e6RmRYj1v9vMarM2rhcL4yYZ1y7LiT5BkkA==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFGjCCBAKgAwIBAgIQCgRw0Ja8ihLIkKbfgm7sSzANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0xOTA2MjAxMjI3NThaFw0yOTA2MjAxMjI3NThaMF8xCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xHjAcBgNVBAMTFUdlb1RydXN0IENOIFJTQSBDQSBHMTCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBALFJ+j1KeZVG4jzgQob23lQ8PJUNhY31ufZihuUx
hYc6HSU4Lw0fxfA43a9DpJl74M3E6F1ZRBOfJ+dWnaiyYD0PxRIQd4wJisti4Uad
vz61IYY/oQ/Elxk/X7GFDquYuxCSyBdHtTVMXCxFSvQ2C/7jWZFDfGGKKNoQSiJy
wDe8iiHbUOakLMmXmOTZyWJnFdR/TH5YNTiMKCNUPHAleG4IigGxDyL/gbwrdDNi
bDA4lUNhD0xNvPjQ8BNKqm5HWDvirUuHdC+4hpi0GJO34O3iiRV16YmWTuVFNboU
LDZ0+PQtctJnatpuZKPGyKX6jCpPvzzPw/EhNDlpEdrYHZMCAwEAAaOCAc4wggHK
MB0GA1UdDgQWBBSRn14xFa4Qn61gwffBzKpINC8MJjAfBgNVHSMEGDAWgBQD3lA1
VtFMu2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYB
BQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wMQYIKwYBBQUHAQEEJTAj
MCEGCCsGAQUFBzABhhVodHRwOi8vb2NzcC5kY29jc3AuY24wRAYDVR0fBD0wOzA5
oDegNYYzaHR0cDovL2NybC5kaWdpY2VydC1jbi5jb20vRGlnaUNlcnRHbG9iYWxS
b290Q0EuY3JsMIHOBgNVHSAEgcYwgcMwgcAGBFUdIAAwgbcwKAYIKwYBBQUHAgEW
HGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgYoGCCsGAQUFBwICMH4MfEFu
eSB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBjb25zdGl0dXRlcyBhY2NlcHRhbmNl
IG9mIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCBsb2NhdGVkIGF0IGh0dHBz
Oi8vd3d3LmRpZ2ljZXJ0LmNvbS9ycGEtdWEwDQYJKoZIhvcNAQELBQADggEBABfg
eXrxIrtlixBv+KMDeqKxtNJbZiLDzJBkGCd4HI63X5eS6BElJBn6mI9eYVrr7qOL
Tp7WiO02Sf1Yrpaz/ePSjZ684o89UAGpxOfbgVSMvo/a07n/220jUWLxzaJhQNLu
lACXwwWsxYf8twP8glkoIHnUUNTlhsyyl1ZzvVC4bDpI4hC6QkJGync1MNqYSMj8
tZbhQNw3HdSmcTO0Nc/J/pK2VZc6fFbKBgspmzdHc6jMKG2t4lisXEysS3wPcg0a
Nfr1Odl5+myh3MnMK08f6pTXvduLz+QZiIh8IYL+Z6QWgTZ9e2jnV8juumX1I8Ge
7cZdtNnTCB8hFfwGLUA=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEArMBuC6MXRP7NaP5ux7nZmuOy2wKY6xWk/i2POrfGSnX0IeY7
phoGliH2EBa+UyCArj5B960UYDkpAmh5uCmDOO1Zs4VPwdoyj+OA6Up/LJXVg/tx
FvZfDkpk7lTjAQz4OcYXxv+iMxDkpEnnlLRsUlUs2JdQUAXEzjwlKVVUqzEZ+9QY
+BLb88bDQEBjaE4+JH95/oRJAby3OH/AXljswh0VUbj3S8pAbiI6f8xoWSn9mjPS
GIlABYDgWma2T0RD9F7sbY7JS/1njPA67i8vzVRMnpkMvYLt4a2qG1THUpFysmT0
R2OOb8DlOZiPhnZkxEvUGeDx8y34FSucWLQTvwIDAQABAoIBAAdXly9bCCZZ8540
9vDGklwStcuFib0VsQSCKGZx4LVrdZI3RQbwCW86FElmXg9BM2O0dUmy8bAnqpMi
oGgjKfBlp6+8lVsDP62wsqe3qQraqpxIauvZ65WIGrZ42LxDskBQwTpakdwJXMTE
Xoy9Ollcq2JG1BZo/sG9+d2O3EfGS/yCb0PemXMN+1L3Lds4LaVbWhkJTvRMYpQU
m4wdRnAoKW1GKhFy9mvZ70HROPgmZ+jJkj63ZiOQyIpH1XlM6POdJCJx70ppZ6PP
ckjwvaV7wrrIYxK/tIWfDk4V+VxMc5tFJtjrNB/FwDAqBm9ltT1LjfN/j/cpQtZ7
xk3kKSkCgYEA2Zo9tOMGdU/1lOZJ2MGQ2kRAeNfcgA/ZA7FlIAoqMc52/OrIiO4u
oAWJ5VkQNhgXazbEMl8ifI3fnSCcEjIcL3zVqIdFAeTOv+Wg1quK/TVENiG1uVnc
Kr/YCbuD0DLXgZ/Szm0+dwYxcRHb5oHpsE0XNl0mEpQUnCbxrSYOKNsCgYEAyzwk
bXczNjx90phzbIYqHG7LmZvWWKa7mqISL8RvyXhhzy9fXoBKhUtkC6XazYaYCO6F
mvSRT9BT/sRV9YgoOONHxscNMv7I2mKg8R6TDIFS/tq3E4A35YMvbVo4k/LfzExZ
FKis6KuUfnA216++CaVAfIRTLSHsO4K2Hw6wE+0CgYEAimB3lSw50yhB96pqk5ik
UOjORwqegiGR07Nfp3xPUNUG/dcgJ1Ov+rsK8fotQPkZC2kMYyv0dliSNw2hskCD
g/9Sr5U14PpsL8QK//ierl7NPc86DOCEDftpmubP7/ok6Z2FJRh7fJ1Hm6vLt04u
GZssg7nAmFfqs1JgpcdpgbkCgYAOo+F35TtSL99ceVDvQ2brL2wJP7mcHz6qb/xh
ZoQq/joFg8MZ+qHjoj+tux/c6FIxaoVDWVTSbA5w7tHGYy2Kk4zLG/Gud74eRTaU
yAANyY8h/r1rcTQVm3KiLPqgZcGLZQCRxWjXRezngsvgk69b4ISZs6qOOMBctRjL
efJjLQKBgFGdU3jg/+MctfR7N2yj3DHfPw6eya+yCjuY01S5E0oEJSE3yiLw7vPQ
kHeyZ5cEXD9y7VTCsfuYqsEwxKViBRc8xyyS7kYEEORLz/sAVU2V3TN7aKVinrEn
MnKh1m2n4wno3AE4huJFbPuXqJO3iUkfhIuLkCFyZtEd72JFO9ns
-----END RSA PRIVATE KEY-----

View File

View File

264
docker/settings.xml Normal file
View File

@@ -0,0 +1,264 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<!--
| This is the configuration file for Maven. It can be specified at two levels:
|
| 1. User Level. This settings.xml file provides configuration for a single user,
| and is normally provided in ${user.home}/.m2/settings.xml.
|
| NOTE: This location can be overridden with the CLI option:
|
| -s /path/to/user/settings.xml
|
| 2. Global Level. This settings.xml file provides configuration for all Maven
| users on a machine (assuming they're all using the same Maven
| installation). It's normally provided in
| ${maven.conf}/settings.xml.
|
| NOTE: This location can be overridden with the CLI option:
|
| -gs /path/to/global/settings.xml
|
| The sections in this sample file are intended to give you a running start at
| getting the most out of your Maven installation. Where appropriate, the default
| values (values used when the setting is not specified) are provided.
|
|-->
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<!-- localRepository
| The path to the local repository maven will use to store artifacts.
|
| Default: ${user.home}/.m2/repository
<localRepository>/path/to/local/repo</localRepository>
-->
<!-- interactiveMode
| This will determine whether maven prompts you when it needs input. If set to false,
| maven will use a sensible default value, perhaps based on some other setting, for
| the parameter in question.
|
| Default: true
<interactiveMode>true</interactiveMode>
-->
<!-- offline
| Determines whether maven should attempt to connect to the network when executing a build.
| This will have an effect on artifact downloads, artifact deployment, and others.
|
| Default: false
<offline>false</offline>
-->
<!-- pluginGroups
| This is a list of additional group identifiers that will be searched when resolving plugins by their prefix, i.e.
| when invoking a command line like "mvn prefix:goal". Maven will automatically add the group identifiers
| "org.apache.maven.plugins" and "org.codehaus.mojo" if these are not already contained in the list.
|-->
<pluginGroups>
<!-- pluginGroup
| Specifies a further group identifier to use for plugin lookup.
<pluginGroup>com.your.plugins</pluginGroup>
-->
</pluginGroups>
<!-- proxies
| This is a list of proxies which can be used on this machine to connect to the network.
| Unless otherwise specified (by system property or command-line switch), the first proxy
| specification in this list marked as active will be used.
|-->
<proxies>
<!-- proxy
| Specification for one proxy, to be used in connecting to the network.
|
<proxy>
<id>optional</id>
<active>true</active>
<protocol>http</protocol>
<username>proxyuser</username>
<password>proxypass</password>
<host>proxy.host.net</host>
<port>80</port>
<nonProxyHosts>local.net|some.host.com</nonProxyHosts>
</proxy>
-->
</proxies>
<!-- servers
| This is a list of authentication profiles, keyed by the server-id used within the system.
| Authentication profiles can be used whenever maven must make a connection to a remote server.
|-->
<servers>
<!-- server
| Specifies the authentication information to use when connecting to a particular server, identified by
| a unique name within the system (referred to by the 'id' attribute below).
|
| NOTE: You should either specify username/password OR privateKey/passphrase, since these pairings are
| used together.
|
<server>
<id>deploymentRepo</id>
<username>repouser</username>
<password>repopwd</password>
</server>
-->
<!-- Another sample, using keys to authenticate.
<server>
<id>siteServer</id>
<privateKey>/path/to/private/key</privateKey>
<passphrase>optional; leave empty if not used.</passphrase>
</server>
-->
</servers>
<!-- mirrors
| This is a list of mirrors to be used in downloading artifacts from remote repositories.
|
| It works like this: a POM may declare a repository to use in resolving certain artifacts.
| However, this repository may have problems with heavy traffic at times, so people have mirrored
| it to several places.
|
| That repository definition will have a unique id, so we can create a mirror reference for that
| repository, to be used as an alternate download site. The mirror site will be the preferred
| server for that repository.
|-->
<mirrors>
<!-- mirror
| Specifies a repository mirror site to use instead of a given repository. The repository that
| this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used
| for inheritance and direct lookup purposes, and must be unique across the set of mirrors.
|
<mirror>
<id>mirrorId</id>
<mirrorOf>repositoryId</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<url>http://my.repository.com/repo/path</url>
</mirror>
-->
<!--阿里maven镜像-->
<mirror>
<id>aliyun</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
<!-- profiles
| This is a list of profiles which can be activated in a variety of ways, and which can modify
| the build process. Profiles provided in the settings.xml are intended to provide local machine-
| specific paths and repository locations which allow the build to work in the local environment.
|
| For example, if you have an integration testing plugin - like cactus - that needs to know where
| your Tomcat instance is installed, you can provide a variable here such that the variable is
| dereferenced during the build process to configure the cactus plugin.
|
| As noted above, profiles can be activated in a variety of ways. One way - the activeProfiles
| section of this document (settings.xml) - will be discussed later. Another way essentially
| relies on the detection of a system property, either matching a particular value for the property,
| or merely testing its existence. Profiles can also be activated by JDK version prefix, where a
| value of '1.4' might activate a profile when the build is executed on a JDK version of '1.4.2_07'.
| Finally, the list of active profiles can be specified directly from the command line.
|
| NOTE: For profiles defined in the settings.xml, you are restricted to specifying only artifact
| repositories, plugin repositories, and free-form properties to be used as configuration
| variables for plugins in the POM.
|
|-->
<profiles>
<!-- profile
| Specifies a set of introductions to the build process, to be activated using one or more of the
| mechanisms described above. For inheritance purposes, and to activate profiles via <activatedProfiles/>
| or the command line, profiles have to have an ID that is unique.
|
| An encouraged best practice for profile identification is to use a consistent naming convention
| for profiles, such as 'env-dev', 'env-test', 'env-production', 'user-jdcasey', 'user-brett', etc.
| This will make it more intuitive to understand what the set of introduced profiles is attempting
| to accomplish, particularly when you only have a list of profile id's for debug.
|
| This profile example uses the JDK version to trigger activation, and provides a JDK-specific repo.
<profile>
<id>jdk-1.4</id>
<activation>
<jdk>1.4</jdk>
</activation>
<repositories>
<repository>
<id>jdk14</id>
<name>Repository for JDK 1.4 builds</name>
<url>http://www.myhost.com/maven/jdk14</url>
<layout>default</layout>
<snapshotPolicy>always</snapshotPolicy>
</repository>
</repositories>
</profile>
-->
<!--
| Here is another profile, activated by the system property 'target-env' with a value of 'dev',
| which provides a specific path to the Tomcat instance. To use this, your plugin configuration
| might hypothetically look like:
|
| ...
| <plugin>
| <groupId>org.myco.myplugins</groupId>
| <artifactId>myplugin</artifactId>
|
| <configuration>
| <tomcatLocation>${tomcatPath}</tomcatLocation>
| </configuration>
| </plugin>
| ...
|
| NOTE: If you just wanted to inject this configuration whenever someone set 'target-env' to
| anything, you could just leave off the <value/> inside the activation-property.
|
<profile>
<id>env-dev</id>
<activation>
<property>
<name>target-env</name>
<value>dev</value>
</property>
</activation>
<properties>
<tomcatPath>/path/to/tomcat/instance</tomcatPath>
</properties>
</profile>
-->
</profiles>
<!-- activeProfiles
| List of profiles that are active for all builds.
|
<activeProfiles>
<activeProfile>alwaysActiveProfile</activeProfile>
<activeProfile>anotherAlwaysActiveProfile</activeProfile>
</activeProfiles>
-->
</settings>

11
docker/sources.list Normal file
View File

@@ -0,0 +1,11 @@
deb http://mirrors.cloud.tencent.com/ubuntu/ bionic main restricted universe multiverse
# deb-src http://mirrors.cloud.tencent.com/ubuntu/ bionic main restricted universe multiverse
deb http://mirrors.cloud.tencent.com/ubuntu/ bionic-updates main restricted universe multiverse
# deb-src http://mirrors.cloud.tencent.com/ubuntu/ bionic-updates main restricted universe multiverse
deb http://mirrors.cloud.tencent.com/ubuntu/ bionic-backports main restricted universe multiverse
# deb-src http://mirrors.cloud.tencent.com/ubuntu/ bionic-backports main restricted universe multiverse
deb http://mirrors.cloud.tencent.com/ubuntu/ bionic-security main restricted universe multiverse
# deb-src http://mirrors.cloud.tencent.com/ubuntu/ bionic-security main restricted universe multiverse
# deb http://mirrors.cloud.tencent.com/ubuntu/ bionic-proposed main restricted universe multiverse
# deb-src http://mirrors.cloud.tencent.com/ubuntu/ bionic-proposed main restricted universe multiverse

View File

@@ -461,7 +461,7 @@ String getTime()
}
delay(500);
}
return "";
return "1672524366000";
}
//打印提示信息

View File

@@ -450,7 +450,7 @@ String getTime()
}
delay(500);
}
return "";
return "1672524366000";
}
//打印提示信息

View File

@@ -8,7 +8,7 @@
#include "ApConfig.h"
String randomName = "wumei-device" + (String)random(1000);
String randomName = "fastbee-device" + (String)random(1000);
const char *ap_ssid = randomName.c_str();
//开放式网络,不设置密码
const char *ap_password = "";

View File

@@ -38,29 +38,29 @@ String pEventTopic = "/event/post";
/********************************** begin 可配置的项 **********************************/
// wifi信息
char *wifiSsid = "MERCURY100";
char *wifiPwd = "164770707";
char *wifiSsid = "";
char *wifiPwd = "";
char *userId = "1";
// 产品启用授权码,则授权码不能为空
char *authCode = "";
// 设备信息配置
char *deviceNum = "D1H2584G22Q2";
char *productId = "41";
char *deviceNum = "D1FJTWOT3HIB";
char *productId = "588";
float firmwareVersion = 1.0;
// 经度和纬度可选,如果产品使用设备定位,则必须传
float latitude = 0;
float longitude = 0;
// Mqtt配置
char *mqttHost = "43.143.82.218";
char *mqttHost = "fastbee.cn";
int mqttPort = 1883;
char *mqttUserName = "wumei-smart";
char *mqttPwd = "P47T6OD5IPFWHUM6";
char mqttSecret[17] = "KX3TSH4Q4OS835DO";
char *mqttUserName = "FastBee";
char *mqttPwd = "P63653937TRQ8F27";
char mqttSecret[17] = "KV52PPZ813EFCQD8";
// NTP地址用于获取时间,修改为自己部署项目的接口地址)
String ntpServer = "http://wumei.live:8080/iot/tool/ntp?deviceSendTime=";
String ntpServer = "http://fastbee.cn:8080/iot/tool/ntp?deviceSendTime=";
/********************************** end 可配置的项 **********************************/

View File

@@ -57,6 +57,7 @@ void loop() {
// 发布模拟数据,测试用
publishSimulateDataClient();
}
ESP.wdtFeed(); // 喂软件看门狗,防止程序跑偏
}
/*

View File

@@ -97,7 +97,7 @@ String randomPropertyData() {
int randInt = 0;
StaticJsonDocument<1024> doc;
JsonObject objTmeperature = doc.createNestedObject();
objTmeperature["id"] = "temperature";
objTmeperature["id"] = "light_current";
randFloat = random(1000, 3000);
objTmeperature["value"] = (String)(randFloat / 100);
objTmeperature["remark"] = (String)millis();
@@ -159,7 +159,7 @@ void processFunction(String msg) {
// 匹配云端定义的功能
const char *id = object["id"];
const char *value = object["value"];
if (strcmp(id, "switch") == 0) {
if (strcmp(id, "light_switch") == 0) {
printMsg("开关 switch" + (String)value);
if (strcmp(value, "1") == 0) {
// 打开继电器

View File

@@ -38,29 +38,29 @@ String pEventTopic = "/event/post";
/********************************** begin 可配置的项 **********************************/
// wifi信息
char *wifiSsid = "MERCURY100";
char *wifiPwd = "FastBee";
char *userId = "1";
char *wifiSsid = (char*)"MERCURY100";
char *wifiPwd = (char*)"FastBee";
char *userId = (char*)"1";
// 产品启用授权码,则授权码不能为空
char *authCode = "";
char *authCode = (char*)"";
// 设备信息配置
char *deviceNum = "D1PGLPG58KZ2";
char *productId = "96";
char *deviceNum = (char*)"D1PGLPG58K88";
char *productId = (char*)"96";
float firmwareVersion = 1.0;
// 经度和纬度可选,如果产品使用设备定位,则必须传
float latitude = 0;
float longitude = 0;
// Mqtt配置
char *mqttHost = "43.143.82.218";
char *mqttHost = (char*)"iot.fastbee.cn";
int mqttPort = 1883;
char *mqttUserName = "FastBee";
char *mqttPwd = "P467433O1MT8MXS2";
char *mqttUserName = (char*)"FastBee";
char *mqttPwd = (char*)"P467433O1MT8MXS2";
char mqttSecret[17] = "KWF32S3H95LH14LO";
// NTP地址用于获取时间,修改为自己部署项目的接口地址)
String ntpServer = "http://wumei.live:8080/iot/tool/ntp?deviceSendTime=";
String ntpServer = "http://fastbee.cn:8080/iot/tool/ntp?deviceSendTime=";
/********************************** end 可配置的项 **********************************/

View File

@@ -67,9 +67,9 @@ void publishProperty(String msg) {
// 4.发布功能
void publishFunction(String msg) {
printMsg("发布功能:" + prefix + pFunctionTopic);
printMsg("发布属性(功能:" + prefix + pPropertyTopic);
printMsg("消息:" + msg);
mqttClient.publish((prefix + pFunctionTopic).c_str(), msg.c_str());
mqttClient.publish((prefix + pPropertyTopic).c_str(), msg.c_str());
}
// 5.发布事件

View File

@@ -72,7 +72,8 @@ void mqttCallback(char *topic, byte *payload, unsigned int length) {
printMsg("当前时间:" + String(now, 0));
} else if (strcmp(topic, (prefix + sPropertyTopic).c_str()) == 0 || strcmp(topic, (prefix + sPropertyOnline).c_str()) == 0) {
printMsg("订阅到属性指令...");
processProperty(data);
printMsg("新版本属性和功能合并为功能主题...");
// processProperty(data);
} else if (strcmp(topic, (prefix + sFunctionTopic).c_str()) == 0 || strcmp(topic, (prefix + sFunctionOnline).c_str()) == 0) {
printMsg("订阅到功能指令...");
processFunction(data);
@@ -437,6 +438,8 @@ void processFunction(String msg) {
delay(1000);
}
}
// 处理子设备的数据上报
processSubDeviceReport(id, value);
}
// 最后发布功能,服务端订阅存储(重要)
publishFunction(msg);

View File

@@ -0,0 +1,113 @@
--- 模块功能物美MQTT应用
-- @author 杜兴杰
-- @module 物美MQTT应用
-- @license MIT
-- @copyright 杜兴杰
-- @email 1066950103@qq.com
-- @release 2022.8.5
module(..., package.seeall)
local VERSION = "0.1"
local m_strUserId = "1"
local m_strLongitude = "0"
local m_strLatitude = "0"
local m_nTemperature = 25
--local m_nVoltval = 4.0
local rtos_bsp = rtos.bsp()
function adc_pin() -- 根据不同开发板设置ADC编号
if rtos_bsp == "AIR101" then -- Air101开发板ADC编号
return 0,1,255,255,adc.CH_CPU ,adc.CH_VBAT
elseif rtos_bsp == "AIR103" then -- Air103开发板ADC编号
return 0,1,2,3,adc.CH_CPU ,adc.CH_VBAT
elseif rtos_bsp == "AIR105" then -- Air105开发板ADC编号
return 0,5,6,255,255,255
elseif rtos_bsp == "ESP32C3" then -- ESP32C3开发板ADC编号
return 0,1,2,3,adc.CH_CPU , 255
elseif rtos_bsp == "ESP32C2" then -- ESP32C2开发板ADC编号
return 0,1,2,3,adc.CH_CPU , 255
elseif rtos_bsp == "ESP32S3" then -- ESP32S3开发板ADC编号
return 0,1,2,3,adc.CH_CPU , 255
elseif rtos_bsp == "EC618" then --Air780E开发板ADC编号
return 0,1,255,255,adc.CH_CPU ,adc.CH_VBAT
else
log.info("main", "define ADC pin in main.lua")
return 0, 0,0,0,0,0
end
end
local adc_pin_0,adc_pin_1,adc_pin_2,adc_pin_3,adc_pin_temp,adc_pin_vbat=adc_pin()
--模块温度返回回调函数
--@temp温度srting类型如果要对该值进行运算可以使用带float的固件将该值转为number
local function getTemperatureCb(temp)
m_nTemperature = temp
end
--- ADC读取测试
-- @return 无
-- @usage read()
local function read0()
--ADC0接口用来读取电压
local ADC_ID = 0
local adcval,voltval = adc.get(adc_pin_0)
log.info("testAdc0.read",adcval,(voltval-(voltval%3))/3,voltval)
-- 输出计算得出的原始电压值
m_nVoltval = voltval/3 * 3127 / 1000
log.info("testAdc0.Vbat", m_nVoltval)
end
--2秒循环查询模块温度
--sys.timerLoopStart(misc.getTemperature,1000,getTemperatureCb)
--sys.timerLoopStart(read0,1000)
-- 开启对应的adc通道
adc.open(adc_pin_0)
function FunctionData()
local jsonStr = ""
end
function PropertyData()
local jsonData = {{
id= "temperature",
value= m_nTemperature ,
remark="温度信息"
},{
id= "voltage",
value= m_nVoltval,
remark="电压信息"
}}
local jsonStr = json.encode(jsonData)
return jsonStr
end
function InformationData()
local jsonData = {
rssi = mobile.rssi(),
firmwareVersion = VERSION,
status = 3 ,
userId = m_strUserId ,
longitude = m_strLongitude ,
latitude = m_strLatitude,
summary = {
name= "device",
chip = "air724",
author = "duxingjie",
version=0.1,
create = "2022-08-07"
}
}
local jsonStr = json.encode(jsonData)
return jsonStr
end
return {
InformationData = InformationData,
PropertyData = PropertyData,
FunctionData = FunctionData
}

View File

@@ -0,0 +1,184 @@
--- 模块功能物美MQTT认证
-- @author 杜兴杰
-- @module 物美MQTT通信
-- @license MIT
-- @copyright 杜兴杰
-- @email 1066950103@qq.com
-- @release 2022.8.4
module(..., package.seeall)
local m_strEncryptionMode
local m_strProductId
local m_strDeviceId
local m_strUserId
local m_strUser
local m_strPassword
local m_nTimeout
local m_strIp
local m_strDeviceAuthorizationCode = nil
local m_strProductPassword = nil
local m_InitCallback = nil
local m_strOutPassword
local m_strClientId
local m_nTimeSyncFlag
local function CreateCommunicationPassword()
if m_strEncryptionMode == "S" then
if nil == m_strDeviceAuthorizationCode then
m_strOutPassword = m_strPassword
else
m_strOutPassword = m_strPassword .. "&" .. m_strDeviceAuthorizationCode
end
return true
end
if m_strEncryptionMode == "E" then
m_strOutPassword = AesPassword()
return true
end
return false
end
local function Callback(nResult)
log.info("Callback" .. nResult)
if m_InitCallback ~= nil then
m_InitCallback(nResult)
end
end
local function ParameterCheck()
return true
end
local function CreatedClientId()
m_strClientId = m_strEncryptionMode .. "&" .. m_strDeviceId .. "&" .. m_strProductId .. "&" .. m_strUserId
end
local function httpCallbackFun(result,prompt,head,body)
log.info("GetTimeHttp.cbFnc",result,prompt)
if result and body then
log.info("GetTimeHttp.cbFnc"..body.."bodyLen="..body:len())
local nDeviceRunTickMs = 1000--rtos.tick() * 5
local nEnd = string.find(body,'}')
local outStr= string.sub(body,1,nEnd-4) .. '}'
log.info("----outStr " .. outStr)
local jsonObj = json.decode(outStr) --bug json 64 转换不支持
local nDeviceSendTime = jsonObj["deviceSendTime"]
local nServerSendTime = jsonObj["serverSendTime"]
local nServerRecvTime = jsonObj["serverRecvTime"]
log.info("nDeviceSendTime=" .. nDeviceSendTime)
log.info("nServerSendTime=" .. nServerSendTime)
log.info("nServerRecvTime=" .. nServerRecvTime)
local nSyncTime = nServerRecvTime --秒为单位 --(nServerRecvTime + nServerSendTime + nDeviceRunTickMs - nDeviceSendTime)/2 --这里运算有问题 可能存在数据移除了
log.info("nSyncTime=" .. nSyncTime)
rtc.set(nSyncTime)
--创建客户端ID
CreatedClientId()
--创建密码
CreateCommunicationPassword()
Callback(1)
m_nTimeSyncFlag = 1
end
end
function SyncTime()
local nDeviceRunTickMs = 1000--rtos.tick() * 5
local strUrl = "http://" .. m_strIp .. ":8080/iot/tool/ntp?deviceSendTime=" .. nDeviceRunTickMs
log.info("strUrl" .. strUrl)
--http.request("GET",strUrl,nil,nil,nil,nil,httpCallbackFun)
local code, headers, body = http.request("GET", strUrl).wait()
log.info("http.get", code, headers, body)
httpCallbackFun(code,"NULL",headers,body)
end
local function GetCurrentTime()
local nCurrentTime = os.time()
log.info("GetCurrentTime= " .. nCurrentTime)
return nCurrentTime
end
function AesPassword()
local nCurrentTime = GetCurrentTime()
local nExpireTime = m_nTimeout + nCurrentTime --这里存在bug 数据溢出了
local strAesSource = nil
if nil == m_strDeviceAuthorizationCode then
strAesSource = m_strPassword .. "&" .. nExpireTime .. "000"
else
strAesSource = m_strPassword .. "&" .. nExpireTime .. "000" .."&" .. m_strDeviceAuthorizationCode
end
--加密内容: mqtt密码 & expireTime & 授权码(可选)
--加密模式CBC填充方式Pkcs5Padding密钥1234567890123456密钥长度128 bit偏移量1234567890666666
log.info("strAesSource=".. strAesSource .. " m_strProductPassword=" ..m_strProductPassword)
local encodeStr = crypto.cipher_encrypt("AES-128-CBC", "PKCS7", strAesSource, m_strProductPassword, "wumei-smart-open") --todo 密码验证
log.info("AesPassword strAesSource" .. strAesSource .. " encodeStr " .. encodeStr )
log.info("AES", "aes-128-cbc", encodeStr:toHex())
encodeStr = crypto.base64_encode(encodeStr)
log.info("AesPassword strAesSource" .. strAesSource .. " encodeStrbase64 " .. encodeStr )
return encodeStr
end
--- mqtt认证初始化
-- @string strEncryptionMode,string类型,认证类型S=简单认证E=加密认证
-- @string strProductId,string类型物美里面定义的产品ID
-- @string strDeviceId,string类型设备ID 一般用imei
-- @string strUserId,string类型用户ID
-- @string strUser,string类型用户
-- @string strPassword,string类型密码
-- @number nTimeout,number类型延迟秒为单位
-- @string strIp,string类型Ip
-- @string strDeviceAuthorizationCode,string类型 设备认证码 不用不填
-- @string strProductPassword,string类型 产品密码
-- @return nil
function Init(strEncryptionMode,strProductId,strDeviceId,strUserId,strUser,strPassword,nTimeout,strIp,strDeviceAuthorizationCode,strProductPassword,callback)
m_strEncryptionMode = strEncryptionMode
m_strProductId = strProductId
m_strDeviceId = strDeviceId
m_strUserId = strUserId
m_strUser = strUser
m_strPassword = strPassword
m_nTimeout = nTimeout
m_strIp = strIp
m_strDeviceAuthorizationCode = strDeviceAuthorizationCode
m_strProductPassword = strProductPassword
m_nTimeSyncFlag = 0
m_InitCallback = callback
--if ParameterCheck() == false then
-- Callback(0)
-- end
SyncTime()
end
function GetUser()
return m_strUser
end
function GetPassword()
return m_strOutPassword
end
function GetClientId()
return m_strClientId
end
function GetIP()
return m_strIp
end
return {
GetUser = GetUser,
GetPassword = GetPassword,
GetClientId = GetClientId,
GetIP = GetIP,
Init=Init
}

View File

@@ -0,0 +1,304 @@
--- 模块功能物美MQTT交互
-- @author 杜兴杰
-- @module 物美MQTT通信
-- @license MIT
-- @copyright 杜兴杰
-- @email 1066950103@qq.com
-- @release 2022.8.5
module(..., package.seeall)
local m_strProductId
local m_strDeviceNum
local m_tMessageQueue = {}
local m_callbackPropertyData = nil
local m_callbackFunctionData = nil
local m_callbackEventData = nil
local m_callbackDeviceInformationData = nil
local m_timePropertyId = 0
local m_timeFunctionId = 0
local m_timeEventId = 0
local m_nMonitorCount = 0
local m_nMonitorTime = 0
local m_timeMonitorId = 0
local function GetSubscriberDeviceInformation()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/info/get"
end
local function GetSubscriberDeviceInOta()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/ota/get"
end
local function GetSubscriberDeviceProperty()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/property/get"
end
local function GetSubscriberDevicePropertyOnline()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/property-online/get"
end
local function GetSubscriberDeviceFunction()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/function/get"
end
local function GetSubscriberDeviceFunctionOnline()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/function-online/get"
end
local function GetSubscriberDeviceMonitor()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/monitor/get"
end
local function GetSubscriberDeviceNtp()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/ntp/get"
end
local function GetPublishDeviceInformation()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/info/post"
end
local function GetPublishDeviceProperty()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/property/post"
end
local function GetPublishDeviceFunction()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/function/post"
end
local function GetPublishDeviceEvent()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/event/post"
end
local function GetPublishDeviceNtp()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/ntp/post"
end
local function GetPublishMonitorProperty()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/monitor/post"
end
local function PropertyPush()
if m_callbackPropertyData ~= nil then
local strTopic = GetPublishDeviceProperty()
local strMessage = m_callbackPropertyData()
local nQos = 1
table.insert(m_tMessageQueue,{topic=strTopic,payload=strMessage,qosr=nQos})
log.info("------------------PropertyPush---------------")
end
end
local function FunctionPush()
if m_callbackFunctionData ~= nil then
local strTopic = GetPublishDeviceFunction()
local strMessage = m_callbackFunctionData()
local nQos = 1
table.insert(m_tMessageQueue,{topic=strTopic,payload=strMessage,qosr=nQos})
log.info("------------------FunctionPush---------------")
end
end
local function EventPush()
if m_callbackEventData ~= nil then
local strTopic = GetPublishDeviceEvent()
local strMessage = m_callbackEventData()
local nQos = 1
table.insert(m_tMessageQueue,{topic=strTopic,payload=strMessage,qosr=nQos})
log.info("------------------EventPush---------------")
end
end
local function MonitorPush()
if m_callbackPropertyData ~= nil then
local strTopic = GetPublishMonitorProperty()
local strMessage = m_callbackPropertyData()
local nQos = 1
table.insert(m_tMessageQueue,{topic=strTopic,payload=strMessage,qosr=nQos})
log.info("------------------MonitorPush---------------")
end
end
local function DeviceMonitorTimeCallback()
MonitorPush()
if m_nMonitorCount ~= 0 then
m_nMonitorCount = m_nMonitorCount -1
m_timeMonitorId = sys.timerStart(
DeviceMonitorTimeCallback
,m_nMonitorTime)
else
sys.timerStop(m_timeMonitorId)
m_timeMonitorId= 0
end
log.info("----m_nMonitorCount=" .. m_nMonitorCount)
end
local function DeviceInformationPush()
if m_callbackDeviceInformationData ~= nil then
local strTopic = GetPublishDeviceInformation()
local strMessage = m_callbackDeviceInformationData()
local nQos = 1
table.insert(m_tMessageQueue,{topic=strTopic,payload=strMessage,qosr=nQos})
end
end
--- mqtt交互初始化
-- @string strProductId,string类型,产品ID
-- @string strDeviceNum,string类型设备号 IMEI
-- @return nil
function Init(strProductId,strDeviceNum)
m_strProductId = strProductId
m_strDeviceNum = strDeviceNum
end
--- mqtt交互延时初始化
-- @return nil
function DelayInit()
DeviceInformationPush();
end
--- mqtt 获取待发送数据 一次取出一天且删除
-- @return bResult false 没有数据 true 有数据
-- @return strMessage 要发送的数据
-- @return strTopic 要发送的主题
-- @return nQos 发送消息级别
function GetData()
local bResult = false
local strMessage =""
local strTopic =""
local nQos = 0
if #m_tMessageQueue>0 then
local outMsg = table.remove(m_tMessageQueue,1)
bResult = true
strMessage = outMsg.payload
strTopic = outMsg.topic
nQos = outMsg.qosr
end
return bResult,strMessage,strTopic,nQos
end
--- mqtt 设置属性的获取获取函数,内部调用发送的时候会执行这个函数 这个函数外部实现
-- @function callback,函数类型, 数据函
function SetCallbackPropertyData(callback)
m_callbackPropertyData = callback
end
--- mqtt 设置功能的获取获取函数,内部调用发送的时候会执行这个函数 这个函数外部实现
-- @function callback,函数类型, 数据函
function SetCallbackFunctionData(callback)
m_callbackFunctionData = callback
end
--- mqtt 设置事件的获取获取函数,内部调用发送的时候会执行这个函数 这个函数外部实现
-- @function callback,函数类型, 数据函
function SetCallbackEventData(callback)
m_callbackEventData = callback
end
--- mqtt 设置设备信息获取函数,这个函数外部实现
-- @function callback,函数类型, 数据函
function SetCallbackInformationData(callback)
m_callbackDeviceInformationData = callback
end
--- mqtt 设置属性发布
-- @number nTime,数字类型, 0停止定时器 其他值开启定时器
function SetPropertyPush(nTime)
if m_timePropertyId ~= 0 then
sys.timerStop(m_timePropertyId)
m_timePropertyId = 0
end
if nTime~= 0 then
m_timePropertyId = sys.timerLoopStart(PropertyPush,nTime)
end
end
--- mqtt 设置功能发布
-- @number nTime,数字类型, 0停止定时器 其他值开启定时器
function SetFunctionPush(nTime)
if m_timeFunctionId ~= 0 then
sys.timerStop(m_timeFunctionId)
m_timeFunctionId = 0
end
if nTime~= 0 then
m_timeFunctionId = sys.timerLoopStart(FunctionPush,nTime)
end
end
--- mqtt 设置事件发布
-- @number nTime,数字类型, 0停止定时器 其他值开启定时器
function SetEventPush(nTime)
if m_timeEventId ~= 0 then
sys.timerStop(m_timeEventId)
m_timeEventId = 0
end
if nTime~= 0 then
m_timeEventId = sys.timerLoopStart(EventPush,nTime)
end
end
--- mqtt 获取要订阅的所有主题
-- @return tSubscriber,表类型, topic 主题 qos级别
function GetSubscriberAll()
local tSubscriber ={}
table.insert(tSubscriber,{topic=GetSubscriberDeviceInformation(),qos=1})
table.insert(tSubscriber,{topic=GetSubscriberDeviceProperty(),qos=1})
table.insert(tSubscriber,{topic=GetSubscriberDevicePropertyOnline(),qos=1})
table.insert(tSubscriber,{topic=GetSubscriberDeviceFunction(),qos=1})
table.insert(tSubscriber,{topic=GetSubscriberDeviceFunctionOnline(),qos=1})
table.insert(tSubscriber,{topic=GetSubscriberDeviceMonitor(),qos=1})
table.insert(tSubscriber,{topic=GetSubscriberDeviceNtp(),qos=1})
return tSubscriber
end
--- mqtt接受数据
-- @string topic,string类型,接收到的主题
-- @string message,string类型消息内容
-- @return nil
function OnRecvData(topic , message)
if topic == GetSubscriberDeviceInformation() then
DeviceInformationPush();
elseif topic == GetSubscriberDeviceInOta() then
local jsonObj = json.decode(message)
local strVersion = jsonObj["version"]
local strUrl = jsonObj["downloadUrl"]
elseif topic == GetSubscriberDeviceProperty() then
PropertyPush();
elseif topic == GetSubscriberDevicePropertyOnline() then
PropertyPush();
elseif topic == GetSubscriberDeviceFunction() then
FunctionPush();
elseif topic == GetSubscriberDeviceFunctionOnline() then
FunctionPush();
elseif topic == GetSubscriberDeviceMonitor() then
local jsonObj = json.decode(message)
m_nMonitorCount = jsonObj["count"]
m_nMonitorTime = jsonObj["interval"]
if m_timeMonitorId ~= 0 then
sys.timerStop(m_timeMonitorId)
m_timeMonitorId = 0
end
m_timeMonitorId = sys.timerStart(
DeviceMonitorTimeCallback
,m_nMonitorTime)
elseif topic == GetSubscriberDeviceNtp() then
log.info("--DeviceNtp---" .. message)
end
end
return {
Init = Init,
DelayInit = DelayInit,
SetCallbackPropertyData = SetCallbackPropertyData,
SetCallbackFunctionData = SetCallbackFunctionData,
SetCallbackEventData=SetCallbackEventData,
SetCallbackInformationData=SetCallbackInformationData,
SetPropertyPush =SetPropertyPush,
SetFunctionPush =SetFunctionPush,
SetEventPush=SetEventPush,
GetSubscriberAll=GetSubscriberAll,
OnRecvData=OnRecvData,
GetData = GetData
}

View File

@@ -0,0 +1,130 @@
--- 模块功能物美MQTT测试
-- @author 杜兴杰
-- @module 物美MQTT通信测试
-- @license MIT
-- @copyright 杜兴杰
-- @email 1066950103@qq.com
-- @release 2022.8.5
module(..., package.seeall)
WeiMeiComAuth = require"WeiMeiComAuth"
WeiMeiComInteraction = require"WeiMeiComInteraction"
WeiMeiApp = require"WeiMeiApp"
--require"misc"
--require"mqtt"
--[[特别注意, 使用mqtt库需要下列语句]]
_G.sysplus = require("sysplus")
local ready = false
--物美配置参数相关配置
local m_strEncryptionMode = "E"
local m_strProductId = 253
local m_strDeviceId = nil
local m_strUserId = "1" -- admin
local m_strMqttUser = "FastBee"
local m_strMqttPassword = "P77A4MMCA20V0D0K"
local m_strProductPassword = "K4PAICCX042H88E6" --产品密码
local m_nMqttAuthenticationTimeout = 24*60*60*1 --24小时
local m_strMqttIp = "www.fastbee.cn"
local m_strDeviceAuthorizationCode = nill--= "A25040D2E34B483DA371B5F9A315BB43" --设备授权码
local mqttc = nil
local m_mqttFlag = 0
function AuthenticationResultCallback(nResult)
if nResult == 1 then
log.info("---AuthenticationResultCallback---ok")
WeiMeiComInteraction.Init(m_strProductId,m_strDeviceId)
m_mqttFlag = 1
end
end
local function MqttInit()
WeiMeiComAuth.Init(m_strEncryptionMode,m_strProductId,m_strDeviceId,m_strUserId,m_strMqttUser,m_strMqttPassword,m_nMqttAuthenticationTimeout,m_strMqttIp,m_strDeviceAuthorizationCode,m_strProductPassword,AuthenticationResultCallback)
end
-- 订阅所有主题
local function GetSubscriberAll()
local tSubscriber = WeiMeiComInteraction.GetSubscriberAll()
while #tSubscriber > 0 do
local ouSubscriber = table.remove(tSubscriber,1)
mqttc:subscribe(ouSubscriber.topic,ouSubscriber.qos) --todo 可能订阅数量有限
--if m_mqttClient:subscribe({[ouSubscriber.topic]=ouSubscriber.qos}) == nil then
-- log.info("subscribe eeror ")
-- return false
--end
end
return true
end
--- MQTT连接是否处于激活状态
-- @return 激活状态返回true非激活状态返回false
-- @usage mqttTask.isReady()
function isReady()
return ready
end
--启动MQTT客户端任务
sys.taskInit(
function()
local retryConnectCnt = 0
sys.waitUntil("IP_READY", 50000)
--创建一个MQTT客户端
m_strDeviceId = mobile.imei()
MqttInit()
while m_mqttFlag == 0 do
sys.wait(50)
end
log.info("ClientId=" .. WeiMeiComAuth.GetClientId() )
log.info("User=" .. WeiMeiComAuth.GetUser() )
log.info("Password=" .. WeiMeiComAuth.GetPassword() )
log.info("Ip=" .. WeiMeiComAuth.GetIP() )
mqttc = mqtt.create(nil,WeiMeiComAuth.GetIP(), 1883, false, ca_file)
mqttc:auth(WeiMeiComAuth.GetClientId(),WeiMeiComAuth.GetUser(),WeiMeiComAuth.GetPassword()) -- client_id必填,其余选填
mqttc:keepalive(30) -- 默认值240s
mqttc:autoreconn(true, 3000) -- 自动重连机制
mqttc:on(function(mqtt_client, event, data, payload)
-- 用户自定义代码
log.info("mqtt", "event", event, mqtt_client, data, payload)
if event == "conack" then
--连接成功
sys.publish("mqtt_conack")
if GetSubscriberAll() == true then
WeiMeiComInteraction.SetCallbackInformationData(WeiMeiApp.InformationData)
WeiMeiComInteraction.SetCallbackPropertyData(WeiMeiApp.PropertyData)
WeiMeiComInteraction.SetPropertyPush(1000*30) --30秒钟定时上传一次属性
WeiMeiComInteraction.DelayInit()
end
elseif event == "recv" then
log.info("mqtt", "downlink", "topic", data, "payload", payload)
WeiMeiComInteraction.OnRecvData(data,payload);
elseif event == "sent" then
log.info("mqtt", "sent", "pkgid", data)
-- elseif event == "disconnect" then
-- 非自动重连时,按需重启mqttc
-- mqtt_client:connect()
end
end)
mqttc:connect()
sys.waitUntil("mqtt_conack") --todo 超时重启
while true do
-- mqttc自动处理重连
result,strMessage,strTopic,nQos = WeiMeiComInteraction.GetData()
if result == true then
local mqttResult = mqttc:publish(strTopic,strMessage,nQos)
if not mqttResult then
break
end
end
sys.wait(50)
end
mqttc:close()
mqttc = nil
end
)

View File

@@ -0,0 +1,31 @@
--- 模块功能lvgldemo
-- @module main
-- @author 杜兴杰
-- @release 2023.03.15
-- LuaTools需要PROJECT和VERSION这两个信息
PROJECT = "wumeiAir780"
VERSION = "0.0.1"
log.info("main", PROJECT, VERSION)
-- sys库是标配
_G.sys = require("sys")
--添加硬狗防止程序卡死
if wdt then
wdt.init(9000)--初始化watchdog设置为9s
sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
end
require "WuMeiTest"
-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!

View File

@@ -0,0 +1,65 @@
--必须在这个位置定义PROJECT和VERSION变量
--PROJECTascii string类型可以随便定义只要不使用,就行
--VERSIONascii string类型如果使用Luat物联云平台固件升级的功能必须按照"X.X.X"定义X表示1位数字否则可随便定义
PROJECT = "DTU"
VERSION = "1.0.0"
--加载日志功能模块,并且设置日志输出等级
--如果关闭调用log模块接口输出的日志等级设置为log.LOG_SILENT即可
require "log"
LOG_LEVEL = log.LOGLEVEL_TRACE
--[[
如果使用UART输出日志打开这行注释的代码"--log.openTrace(true,1,115200)"即可,根据自己的需求修改此接口的参数
如果要彻底关闭脚本中的输出日志包括调用log模块接口和Lua标准print接口输出的日志执行log.openTrace(false,第二个参数跟调用openTrace接口打开日志的第二个参数相同),例如:
1、没有调用过sys.opntrace配置日志输出端口或者最后一次是调用log.openTrace(true,nil,921600)配置日志输出端口此时要关闭输出日志直接调用log.openTrace(false)即可
2、最后一次是调用log.openTrace(true,1,115200)配置日志输出端口此时要关闭输出日志直接调用log.openTrace(false,1)即可
--]]
--log.openTrace(true,1,115200)
require "sys"
require "net"
--每1分钟查询一次GSM信号强度
--每1分钟查询一次基站信息
net.startQueryAll(60000, 60000)
--此处关闭RNDIS网卡功能
--否则模块通过USB连接电脑后会在电脑的网络适配器中枚举一个RNDIS网卡电脑默认使用此网卡上网导致模块使用的sim卡流量流失
--如果项目中需要打开此功能把ril.request("AT+RNDISCALL=0,1")修改为ril.request("AT+RNDISCALL=1,1")即可
--注意core固件V0030以及之后的版本、V3028以及之后的版本才以稳定地支持此功能
ril.request("AT+RNDISCALL=1,1")
--加载控制台调试功能模块此处代码配置的是uart2波特率115200
--此功能模块不是必须的,根据项目需求决定是否加载
--使用时注意控制台使用的uart不要和其他功能使用的uart冲突
--使用说明参考demo/console下的《console功能使用说明.docx》
--require "console"
--console.setup(2, 115200)
--加载网络指示灯和LTE指示灯功能模块
--根据自己的项目需求和硬件配置决定1、是否加载此功能模块2、配置指示灯引脚
--合宙官方出售的Air720U开发板上的网络指示灯引脚为pio.P0_1LTE指示灯引脚为pio.P0_4
require "netLed"
pmd.ldoset(2,pmd.LDO_VLCD)
netLed.setup(true,pio.P0_1,pio.P0_4)
--网络指示灯功能模块中默认配置了各种工作状态下指示灯的闪烁规律参考netLed.lua中ledBlinkTime配置的默认值
--如果默认值满足不了需求此处调用netLed.updateBlinkTime去配置闪烁时长
--LTE指示灯功能模块中配置的是注册上4G网络灯就常亮其余任何状态灯都会熄灭
--加载错误日志管理功能模块【强烈建议打开此功能】
--如下2行代码只是简单的演示如何使用errDump功能详情参考errDump的api
require "errDump"
errDump.request("udp://dev_msg1.openluat.com:12425", nil, true)
--加载远程升级功能模块【强烈建议打开此功能如果使用了阿里云的OTA功能可以不打开此功能】
--如下3行代码只是简单的演示如何使用update功能详情参考update的api以及demo/update
PRODUCT_KEY = "7wazHLKGOdfjrSoG5tXOr4uUg7D5wT9k"
--require "update"
--update.request()
--加载MQTT功能测试模块
require "WuMeiTest"
--启动系统框架
sys.init(0, 0)
sys.run()

View File

@@ -0,0 +1,10 @@
PROJECT = 'test'
VERSION = '2.0.0'
require 'log'
LOG_LEVEL = log.LOGLEVEL_TRACE
require 'sys'
require "WuMeiTest"
sys.init(0, 0)
sys.run()

View File

@@ -1,6 +1,6 @@
######################################################################
# Build Tools
.yml
.gradle
/build/
!gradle/wrapper/gradle-wrapper.jar

View File

@@ -1,86 +1,10 @@
## 平台简介
若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。
* 前端采用Vue、Element UI。
* 后端采用Spring Boot、Spring Security、Redis & Jwt。
* 权限认证使用Jwt支持多终端认证系统。
* 支持加载动态权限菜单,多方式轻松权限控制。
* 高效率开发,使用代码生成器可以一键生成前后端代码。
* 提供了技术栈([Vue3](https://v3.cn.vuejs.org) [Element Plus](https://element-plus.org/zh-CN) [Vite](https://cn.vitejs.dev))版本[RuoYi-Vue3](https://github.com/yangzongzhuan/RuoYi-Vue3),保持同步更新。
* 提供了单应用版本[RuoYi-Vue-fast](https://github.com/yangzongzhuan/RuoYi-Vue-fast)Oracle版本[RuoYi-Vue-Oracle](https://github.com/yangzongzhuan/RuoYi-Vue-Oracle),保持同步更新。
* 不分离版本,请移步[RuoYi](https://gitee.com/y_project/RuoYi),微服务版本,请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud)
* 特别鸣谢:[element](https://github.com/ElemeFE/element)[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)[eladmin-web](https://github.com/elunez/eladmin-web)。
* 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)&nbsp;&nbsp;
* 阿里云优惠券:[点我领取](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link),腾讯云优惠券:[点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)&nbsp;&nbsp;
## 内置功能
1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。
3. 岗位管理:配置系统用户所属担任职务。
4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。
5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。
7. 参数管理:对系统动态配置常用参数。
8. 通知公告:系统通知公告信息发布维护。
9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
10. 登录日志:系统登录日志记录查询包含登录异常。
11. 在线用户:当前系统中活跃用户状态监控。
12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
13. 代码生成前后端代码的生成java、html、xml、sql支持CRUD下载 。
14. 系统接口根据业务代码自动生成相关的api接口文档。
15. 服务监控监视当前系统CPU、内存、磁盘、堆栈等相关信息。
16. 缓存监控:对系统的缓存信息查询,命令统计等。
17. 在线构建器拖动表单元素生成相应的HTML代码。
18. 连接池监视监视当前系统数据库连接池状态可进行分析SQL找出系统性能瓶颈。
## 在线体验
- admin/admin123
- 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。
演示地址http://vue.ruoyi.vip
文档地址http://doc.ruoyi.vip
## 演示图
<table>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/cd1f90be5f2684f4560c9519c0f2a232ee8.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/1cbcf0e6f257c7d3a063c0e3f2ff989e4b3.jpg"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-8074972883b5ba0622e13246738ebba237a.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-9f88719cdfca9af2e58b352a20e23d43b12.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-39bf2584ec3a529b0d5a3b70d15c9b37646.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-936ec82d1f4872e1bc980927654b6007307.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-b2d62ceb95d2dd9b3fbe157bb70d26001e9.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-d67451d308b7a79ad6819723396f7c3d77a.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/5e8c387724954459291aafd5eb52b456f53.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/644e78da53c2e92a95dfda4f76e6d117c4b.jpg"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-8370a0d02977eebf6dbf854c8450293c937.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-49003ed83f60f633e7153609a53a2b644f7.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-d4fe726319ece268d4746602c39cffc0621.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-c195234bbcd30be6927f037a6755e6ab69c.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/b6115bc8c31de52951982e509930b20684a.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-5e4daac0bb59612c5038448acbcef235e3a.png"/></td>
</tr>
</table>
## 若依前后端分离交流群
QQ群 [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/已满-101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [![加入QQ群](https://img.shields.io/badge/101539465-blue.svg)](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) 点击按钮入群。
### 一、项目目录
&nbsp;&nbsp; fastbee-admin ------------- 主程序入口<br/>
&nbsp;&nbsp; fastbee-common ---------- 公共模块<br />
&nbsp;&nbsp; fastbee-framework -------- 开发框架<br />
&nbsp;&nbsp; fastbee-gateway ----------- 消息通道转发<br/>
&nbsp;&nbsp; fastbee-open-api ---------- 系统开放接口<br />
&nbsp;&nbsp; fastbee-plugs --------------- 拓展插件<br/>
&nbsp;&nbsp; fastbee-protocol ------------ 编解码协议<br />
&nbsp;&nbsp; fastbee-server --------------- 传输层服务端 netty-mqtt<br />
&nbsp;&nbsp; fastbee-service -------------- 核心业务处理<br/>

View File

@@ -4,11 +4,11 @@ echo [<5B><>Ϣ] ʹ<><CAB9>Jar<61><72><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Web<65><62><EFBFBD>̡<EFBFBD>
echo.
cd %~dp0
cd ../wumei-admin/target
cd ../fastbee-admin/target
set JAVA_OPTS=-Xms256m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
java -jar %JAVA_OPTS% wumei-admin.jar
java -jar %JAVA_OPTS% fastbee-admin.jar
cd bin
pause

View File

@@ -0,0 +1,112 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>fastbee</artifactId>
<groupId>com.fastbee</groupId>
<version>3.8.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>fastbee-admin</artifactId>
<description>
web服务入口
</description>
<dependencies>
<!-- spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 表示依赖不会传递 -->
</dependency>
<!-- swagger3-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
</dependency>
<!-- 防止进入swagger页面报类型转换错误排除3.0.0中的引用手动增加1.6.2版本 -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.6.2</version>
</dependency>
<!-- Mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 核心模块-->
<dependency>
<groupId>com.fastbee</groupId>
<artifactId>fastbee-framework</artifactId>
</dependency>
<!-- 定时任务-->
<dependency>
<groupId>com.fastbee</groupId>
<artifactId>fastbee-quartz</artifactId>
</dependency>
<!-- 代码生成-->
<dependency>
<groupId>com.fastbee</groupId>
<artifactId>fastbee-generator</artifactId>
</dependency>
<!-- controller API模块-->
<dependency>
<groupId>com.fastbee</groupId>
<artifactId>fastbee-open-api</artifactId>
</dependency>
<!--服务集成启动模块-->
<dependency>
<groupId>com.fastbee</groupId>
<artifactId>boot-strap</artifactId>
</dependency>
<!--网关集成启动模块-->
<dependency>
<groupId>com.fastbee</groupId>
<artifactId>gateway-boot</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.1.RELEASE</version>
<configuration>
<fork>true</fork> <!-- 如果没有该配置devtools不会生效 -->
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${project.artifactId}</warName>
</configuration>
</plugin>
</plugins>
<finalName>${project.artifactId}</finalName>
</build>
</project>

View File

@@ -0,0 +1,20 @@
package com.fastbee;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/**
* 启动程序
*
* @author ruoyi
*/
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class FastBeeApplication
{
public static void main(String[] args)
{
// System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(FastBeeApplication.class, args);
}
}

View File

@@ -0,0 +1,18 @@
package com.fastbee;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
/**
* web容器中进行部署
*
* @author ruoyi
*/
public class FastBeeServletInitializer extends SpringBootServletInitializer
{
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
{
return application.sources(FastBeeApplication.class);
}
}

View File

@@ -0,0 +1,99 @@
package com.fastbee.web.controller.common;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.google.code.kaptcha.Producer;
import com.fastbee.common.config.RuoYiConfig;
import com.fastbee.common.constant.CacheConstants;
import com.fastbee.common.constant.Constants;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.redis.RedisCache;
import com.fastbee.common.utils.sign.Base64;
import com.fastbee.common.utils.uuid.IdUtils;
import com.fastbee.system.service.ISysConfigService;
/**
* 验证码操作处理
*
* @author ruoyi
*/
@Api(tags = "验证码操作")
@RestController
public class CaptchaController
{
@Resource(name = "captchaProducer")
private Producer captchaProducer;
@Resource(name = "captchaProducerMath")
private Producer captchaProducerMath;
@Autowired
private RedisCache redisCache;
@Autowired
private ISysConfigService configService;
/**
* 生成验证码
*/
@ApiOperation("获取验证码")
@GetMapping("/captchaImage")
public AjaxResult getCode(HttpServletResponse response) throws IOException
{
AjaxResult ajax = AjaxResult.success();
boolean captchaEnabled = configService.selectCaptchaEnabled();
ajax.put("captchaEnabled", captchaEnabled);
if (!captchaEnabled)
{
return ajax;
}
// 保存验证码信息
String uuid = IdUtils.simpleUUID();
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
String capStr = null, code = null;
BufferedImage image = null;
// 生成验证码
String captchaType = RuoYiConfig.getCaptchaType();
if ("math".equals(captchaType))
{
String capText = captchaProducerMath.createText();
capStr = capText.substring(0, capText.lastIndexOf("@"));
code = capText.substring(capText.lastIndexOf("@") + 1);
image = captchaProducerMath.createImage(capStr);
}
else if ("char".equals(captchaType))
{
capStr = code = captchaProducer.createText();
image = captchaProducer.createImage(capStr);
}
redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
// 转换流信息写出
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
try
{
ImageIO.write(image, "jpg", os);
}
catch (IOException e)
{
return AjaxResult.error(e.getMessage());
}
ajax.put("uuid", uuid);
ajax.put("img", Base64.encode(os.toByteArray()));
return ajax;
}
}

View File

@@ -0,0 +1,171 @@
package com.fastbee.web.controller.common;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.fastbee.common.config.RuoYiConfig;
import com.fastbee.common.constant.Constants;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.utils.StringUtils;
import com.fastbee.common.utils.file.FileUploadUtils;
import com.fastbee.common.utils.file.FileUtils;
import com.fastbee.framework.config.ServerConfig;
/**
* 通用请求处理
*
* @author ruoyi
*/
@Api(tags = "通用请求处理")
@RestController
@RequestMapping("/common")
public class CommonController
{
private static final Logger log = LoggerFactory.getLogger(CommonController.class);
@Autowired
private ServerConfig serverConfig;
private static final String FILE_DELIMETER = ",";
/**
* 通用下载请求
*
* @param fileName 文件名称
* @param delete 是否删除
*/
@ApiOperation("文件下载")
@GetMapping("/download")
public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
{
try
{
if (!FileUtils.checkAllowDownload(fileName))
{
throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
}
String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
String filePath = RuoYiConfig.getDownloadPath() + fileName;
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
FileUtils.setAttachmentResponseHeader(response, realFileName);
FileUtils.writeBytes(filePath, response.getOutputStream());
if (delete)
{
FileUtils.deleteFile(filePath);
}
}
catch (Exception e)
{
log.error("下载文件失败", e);
}
}
/**
* 通用上传请求(单个)
*/
@ApiOperation("单个文件上传")
@PostMapping("/upload")
public AjaxResult uploadFile(MultipartFile file) throws Exception
{
try
{
// 上传文件路径
String filePath = RuoYiConfig.getUploadPath();
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + fileName;
AjaxResult ajax = AjaxResult.success();
ajax.put("url", url);
ajax.put("fileName", fileName);
ajax.put("newFileName", FileUtils.getName(fileName));
ajax.put("originalFilename", file.getOriginalFilename());
return ajax;
}
catch (Exception e)
{
return AjaxResult.error(e.getMessage());
}
}
/**
* 通用上传请求(多个)
*/
@ApiOperation("多个文件上传")
@PostMapping("/uploads")
public AjaxResult uploadFiles(List<MultipartFile> files) throws Exception
{
try
{
// 上传文件路径
String filePath = RuoYiConfig.getUploadPath();
List<String> urls = new ArrayList<String>();
List<String> fileNames = new ArrayList<String>();
List<String> newFileNames = new ArrayList<String>();
List<String> originalFilenames = new ArrayList<String>();
for (MultipartFile file : files)
{
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + fileName;
urls.add(url);
fileNames.add(fileName);
newFileNames.add(FileUtils.getName(fileName));
originalFilenames.add(file.getOriginalFilename());
}
AjaxResult ajax = AjaxResult.success();
ajax.put("urls", StringUtils.join(urls, FILE_DELIMETER));
ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMETER));
ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER));
ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER));
return ajax;
}
catch (Exception e)
{
return AjaxResult.error(e.getMessage());
}
}
/**
* 本地资源通用下载
*/
@GetMapping("/download/resource")
@ApiOperation("本地资源通用下载")
public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
throws Exception
{
try
{
if (!FileUtils.checkAllowDownload(resource))
{
throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource));
}
// 本地资源路径
String localPath = RuoYiConfig.getProfile();
// 数据库资源地址
String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);
// 下载名称
String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
FileUtils.setAttachmentResponseHeader(response, downloadName);
FileUtils.writeBytes(downloadPath, response.getOutputStream());
}
catch (Exception e)
{
log.error("下载文件失败", e);
}
}
}

View File

@@ -0,0 +1,131 @@
package com.fastbee.web.controller.monitor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.constant.CacheConstants;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.utils.StringUtils;
import com.fastbee.system.domain.SysCache;
/**
* 缓存监控
*
* @author ruoyi
*/
@Api(tags = "缓存监控")
@RestController
@RequestMapping("/monitor/cache")
public class CacheController
{
@Autowired
private RedisTemplate<String, String> redisTemplate;
private final static List<SysCache> caches = new ArrayList<SysCache>();
{
caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "用户信息"));
caches.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "配置信息"));
caches.add(new SysCache(CacheConstants.SYS_DICT_KEY, "数据字典"));
caches.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码"));
caches.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交"));
caches.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理"));
caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数"));
}
@ApiOperation("获取缓存信息")
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping()
public AjaxResult getInfo() throws Exception
{
Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info());
Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
Object dbSize = redisTemplate.execute((RedisCallback<Object>) connection -> connection.dbSize());
Map<String, Object> result = new HashMap<>(3);
result.put("info", info);
result.put("dbSize", dbSize);
List<Map<String, String>> pieList = new ArrayList<>();
commandStats.stringPropertyNames().forEach(key -> {
Map<String, String> data = new HashMap<>(2);
String property = commandStats.getProperty(key);
data.put("name", StringUtils.removeStart(key, "cmdstat_"));
data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
pieList.add(data);
});
result.put("commandStats", pieList);
return AjaxResult.success(result);
}
@ApiOperation("缓存列表")
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping("/getNames")
public AjaxResult cache()
{
return AjaxResult.success(caches);
}
@ApiOperation("键名列表")
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping("/getKeys/{cacheName}")
public AjaxResult getCacheKeys(@PathVariable String cacheName)
{
Set<String> cacheKeys = redisTemplate.keys(cacheName + "*");
return AjaxResult.success(cacheKeys);
}
@ApiOperation("缓存内容")
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping("/getValue/{cacheName}/{cacheKey}")
public AjaxResult getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey)
{
String cacheValue = redisTemplate.opsForValue().get(cacheKey);
SysCache sysCache = new SysCache(cacheName, cacheKey, cacheValue);
return AjaxResult.success(sysCache);
}
@ApiOperation("清理缓存名称")
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@DeleteMapping("/clearCacheName/{cacheName}")
public AjaxResult clearCacheName(@PathVariable String cacheName)
{
Collection<String> cacheKeys = redisTemplate.keys(cacheName + "*");
redisTemplate.delete(cacheKeys);
return AjaxResult.success();
}
@ApiOperation("清理缓存键名")
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@DeleteMapping("/clearCacheKey/{cacheKey}")
public AjaxResult clearCacheKey(@PathVariable String cacheKey)
{
redisTemplate.delete(cacheKey);
return AjaxResult.success();
}
@ApiOperation("清理所有缓存内容")
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@DeleteMapping("/clearCacheAll")
public AjaxResult clearCacheAll()
{
Collection<String> cacheKeys = redisTemplate.keys("*");
redisTemplate.delete(cacheKeys);
return AjaxResult.success();
}
}

View File

@@ -0,0 +1,31 @@
package com.fastbee.web.controller.monitor;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.framework.web.domain.Server;
/**
* 服务器监控
*
* @author ruoyi
*/
@Api(tags = "服务器监控")
@RestController
@RequestMapping("/monitor/server")
public class ServerController
{
@ApiOperation("获取服务器信息")
@PreAuthorize("@ss.hasPermi('monitor:server:list')")
@GetMapping()
public AjaxResult getInfo() throws Exception
{
Server server = new Server();
server.copyTo();
return AjaxResult.success(server);
}
}

View File

@@ -0,0 +1,91 @@
package com.fastbee.web.controller.monitor;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.annotation.Log;
import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.page.TableDataInfo;
import com.fastbee.common.enums.BusinessType;
import com.fastbee.common.utils.poi.ExcelUtil;
import com.fastbee.framework.web.service.SysPasswordService;
import com.fastbee.system.domain.SysLogininfor;
import com.fastbee.system.service.ISysLogininforService;
/**
* 系统访问记录
*
* @author ruoyi
*/
@Api(tags = "日志管理:登录日志")
@RestController
@RequestMapping("/monitor/logininfor")
public class SysLogininforController extends BaseController
{
@Autowired
private ISysLogininforService logininforService;
@Autowired
private SysPasswordService passwordService;
@ApiOperation("获取列表登录信息")
@PreAuthorize("@ss.hasPermi('monitor:logininfor:list')")
@GetMapping("/list")
public TableDataInfo list(SysLogininfor logininfor)
{
startPage();
List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
return getDataTable(list);
}
@ApiOperation("导出登录日志列表")
@Log(title = "登录日志", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('monitor:logininfor:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysLogininfor logininfor)
{
List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
util.exportExcel(response, list, "登录日志");
}
@ApiOperation("批量删除登录日志")
@PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
@Log(title = "登录日志", businessType = BusinessType.DELETE)
@DeleteMapping("/{infoIds}")
public AjaxResult remove(@PathVariable Long[] infoIds)
{
return toAjax(logininforService.deleteLogininforByIds(infoIds));
}
@ApiOperation("清空登录日志信息")
@PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
@Log(title = "登录日志", businessType = BusinessType.CLEAN)
@DeleteMapping("/clean")
public AjaxResult clean()
{
logininforService.cleanLogininfor();
return success();
}
@ApiOperation("账户解锁")
@PreAuthorize("@ss.hasPermi('monitor:logininfor:unlock')")
@Log(title = "账户解锁", businessType = BusinessType.OTHER)
@GetMapping("/unlock/{userName}")
public AjaxResult unlock(@PathVariable("userName") String userName)
{
passwordService.clearLoginRecordCache(userName);
return success();
}
}

View File

@@ -0,0 +1,77 @@
package com.fastbee.web.controller.monitor;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.annotation.Log;
import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.page.TableDataInfo;
import com.fastbee.common.enums.BusinessType;
import com.fastbee.common.utils.poi.ExcelUtil;
import com.fastbee.system.domain.SysOperLog;
import com.fastbee.system.service.ISysOperLogService;
/**
* 操作日志记录
*
* @author ruoyi
*/
@Api(tags = "日志管理:操作日志")
@RestController
@RequestMapping("/monitor/operlog")
public class SysOperlogController extends BaseController
{
@Autowired
private ISysOperLogService operLogService;
@ApiOperation("获取操作日志列表")
@PreAuthorize("@ss.hasPermi('monitor:operlog:list')")
@GetMapping("/list")
public TableDataInfo list(SysOperLog operLog)
{
startPage();
List<SysOperLog> list = operLogService.selectOperLogList(operLog);
return getDataTable(list);
}
@ApiOperation("导出操作日志")
@Log(title = "操作日志", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('monitor:operlog:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysOperLog operLog)
{
List<SysOperLog> list = operLogService.selectOperLogList(operLog);
ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
util.exportExcel(response, list, "操作日志");
}
@ApiOperation("批量删除操作日志")
@Log(title = "操作日志", businessType = BusinessType.DELETE)
@PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
@DeleteMapping("/{operIds}")
public AjaxResult remove(@PathVariable Long[] operIds)
{
return toAjax(operLogService.deleteOperLogByIds(operIds));
}
@ApiOperation("清空操作日志")
@Log(title = "操作日志", businessType = BusinessType.CLEAN)
@PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
@DeleteMapping("/clean")
public AjaxResult clean()
{
operLogService.cleanOperLog();
return success();
}
}

View File

@@ -0,0 +1,98 @@
package com.fastbee.web.controller.monitor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.annotation.Log;
import com.fastbee.common.constant.CacheConstants;
import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.core.page.TableDataInfo;
import com.fastbee.common.core.redis.RedisCache;
import com.fastbee.common.enums.BusinessType;
import com.fastbee.common.utils.StringUtils;
import com.fastbee.system.domain.SysUserOnline;
import com.fastbee.system.service.ISysUserOnlineService;
/**
* 在线用户监控
*
* @author ruoyi
*/
@Api(tags = "在线用户监控")
@RestController
@RequestMapping("/monitor/online")
public class SysUserOnlineController extends BaseController
{
@Autowired
private ISysUserOnlineService userOnlineService;
@Autowired
private RedisCache redisCache;
@ApiOperation("获取在线用户列表")
@PreAuthorize("@ss.hasPermi('monitor:online:list')")
@GetMapping("/list")
public TableDataInfo list(String ipaddr, String userName)
{
Collection<String> keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
for (String key : keys)
{
LoginUser user = redisCache.getCacheObject(key);
if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
{
if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername()))
{
userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
}
}
else if (StringUtils.isNotEmpty(ipaddr))
{
if (StringUtils.equals(ipaddr, user.getIpaddr()))
{
userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
}
}
else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
{
if (StringUtils.equals(userName, user.getUsername()))
{
userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
}
}
else
{
userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
}
}
Collections.reverse(userOnlineList);
userOnlineList.removeAll(Collections.singleton(null));
return getDataTable(userOnlineList);
}
/**
* 强退用户
*/
@ApiOperation("强制退出在线用户")
@PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')")
@Log(title = "在线用户", businessType = BusinessType.FORCE)
@DeleteMapping("/{tokenId}")
public AjaxResult forceLogout(@PathVariable String tokenId)
{
redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
return success();
}
}

View File

@@ -0,0 +1,146 @@
package com.fastbee.web.controller.system;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.annotation.Log;
import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.page.TableDataInfo;
import com.fastbee.common.enums.BusinessType;
import com.fastbee.common.utils.poi.ExcelUtil;
import com.fastbee.system.domain.SysConfig;
import com.fastbee.system.service.ISysConfigService;
/**
* 参数配置 信息操作处理
*
* @author ruoyi
*/
@Api(tags = "参数设置")
@RestController
@RequestMapping("/system/config")
public class SysConfigController extends BaseController
{
@Autowired
private ISysConfigService configService;
/**
* 获取参数配置列表
*/
@ApiOperation("获取参数配置列表")
@PreAuthorize("@ss.hasPermi('system:config:list')")
@GetMapping("/list")
public TableDataInfo list(SysConfig config)
{
startPage();
List<SysConfig> list = configService.selectConfigList(config);
return getDataTable(list);
}
@ApiOperation("导出参数配置列表")
@Log(title = "参数管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:config:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysConfig config)
{
List<SysConfig> list = configService.selectConfigList(config);
ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);
util.exportExcel(response, list, "参数数据");
}
/**
* 根据参数编号获取详细信息
*/
@ApiOperation("根据参数编号获取详细信息")
@PreAuthorize("@ss.hasPermi('system:config:query')")
@GetMapping(value = "/{configId}")
public AjaxResult getInfo(@PathVariable Long configId)
{
return success(configService.selectConfigById(configId));
}
/**
* 根据参数键名查询参数值
*/
@ApiOperation("根据参数键名查询参数值")
@GetMapping(value = "/configKey/{configKey}")
public AjaxResult getConfigKey(@PathVariable String configKey)
{
return success(configService.selectConfigByKey(configKey));
}
/**
* 新增参数配置
*/
@ApiOperation("新增参数配置")
@PreAuthorize("@ss.hasPermi('system:config:add')")
@Log(title = "参数管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysConfig config)
{
if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
{
return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
}
config.setCreateBy(getUsername());
return toAjax(configService.insertConfig(config));
}
/**
* 修改参数配置
*/
@ApiOperation("修改参数配置")
@PreAuthorize("@ss.hasPermi('system:config:edit')")
@Log(title = "参数管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysConfig config)
{
if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
{
return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
}
config.setUpdateBy(getUsername());
return toAjax(configService.updateConfig(config));
}
/**
* 删除参数配置
*/
@ApiOperation("批量删除参数配置")
@PreAuthorize("@ss.hasPermi('system:config:remove')")
@Log(title = "参数管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{configIds}")
public AjaxResult remove(@PathVariable Long[] configIds)
{
configService.deleteConfigByIds(configIds);
return success();
}
/**
* 刷新参数缓存
*/
@ApiOperation("刷新参数缓存")
@PreAuthorize("@ss.hasPermi('system:config:remove')")
@Log(title = "参数管理", businessType = BusinessType.CLEAN)
@DeleteMapping("/refreshCache")
public AjaxResult refreshCache()
{
configService.resetConfigCache();
return success();
}
}

View File

@@ -0,0 +1,142 @@
package com.fastbee.web.controller.system;
import java.util.List;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.annotation.Log;
import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.domain.entity.SysDept;
import com.fastbee.common.enums.BusinessType;
import com.fastbee.common.utils.StringUtils;
import com.fastbee.system.service.ISysDeptService;
/**
* 部门信息
*
* @author ruoyi
*/
@Api(tags = "部门管理")
@RestController
@RequestMapping("/system/dept")
public class SysDeptController extends BaseController
{
@Autowired
private ISysDeptService deptService;
/**
* 获取部门列表
*/
@ApiOperation("获取部门列表")
@PreAuthorize("@ss.hasPermi('system:dept:list')")
@GetMapping("/list")
public AjaxResult list(SysDept dept)
{
List<SysDept> depts = deptService.selectDeptList(dept);
return success(depts);
}
/**
* 查询部门列表(排除节点)
*/
@ApiOperation("查询部门列表(排除节点)")
@PreAuthorize("@ss.hasPermi('system:dept:list')")
@GetMapping("/list/exclude/{deptId}")
public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId)
{
List<SysDept> depts = deptService.selectDeptList(new SysDept());
depts.removeIf(d -> d.getDeptId().intValue() == deptId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + ""));
return success(depts);
}
/**
* 根据部门编号获取详细信息
*/
@ApiOperation("根据部门编号获取详细信息")
@PreAuthorize("@ss.hasPermi('system:dept:query')")
@GetMapping(value = "/{deptId}")
public AjaxResult getInfo(@PathVariable Long deptId)
{
deptService.checkDeptDataScope(deptId);
return success(deptService.selectDeptById(deptId));
}
/**
* 新增部门
*/
@ApiOperation("新增部门")
@PreAuthorize("@ss.hasPermi('system:dept:add')")
@Log(title = "部门管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysDept dept)
{
if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept)))
{
return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
}
dept.setCreateBy(getUsername());
return toAjax(deptService.insertDept(dept));
}
/**
* 修改部门
*/
@ApiOperation("修改部门")
@PreAuthorize("@ss.hasPermi('system:dept:edit')")
@Log(title = "部门管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysDept dept)
{
Long deptId = dept.getDeptId();
deptService.checkDeptDataScope(deptId);
if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept)))
{
return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
}
else if (dept.getParentId().equals(deptId))
{
return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
}
else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0)
{
return error("该部门包含未停用的子部门!");
}
dept.setUpdateBy(getUsername());
return toAjax(deptService.updateDept(dept));
}
/**
* 删除部门
*/
@ApiOperation("根据部门编号删除部门")
@PreAuthorize("@ss.hasPermi('system:dept:remove')")
@Log(title = "部门管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{deptId}")
public AjaxResult remove(@PathVariable Long deptId)
{
if (deptService.hasChildByDeptId(deptId))
{
return warn("存在下级部门,不允许删除");
}
if (deptService.checkDeptExistUser(deptId))
{
return warn("部门存在用户,不允许删除");
}
deptService.checkDeptDataScope(deptId);
return toAjax(deptService.deleteDeptById(deptId));
}
}

View File

@@ -0,0 +1,121 @@
package com.fastbee.web.controller.system;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.annotation.Log;
import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.domain.entity.SysDictData;
import com.fastbee.common.core.page.TableDataInfo;
import com.fastbee.common.enums.BusinessType;
import com.fastbee.common.utils.StringUtils;
import com.fastbee.common.utils.poi.ExcelUtil;
import com.fastbee.system.service.ISysDictDataService;
import com.fastbee.system.service.ISysDictTypeService;
/**
* 数据字典信息
*
* @author ruoyi
*/
@RestController
@RequestMapping("/system/dict/data")
public class SysDictDataController extends BaseController
{
@Autowired
private ISysDictDataService dictDataService;
@Autowired
private ISysDictTypeService dictTypeService;
@PreAuthorize("@ss.hasPermi('system:dict:list')")
@GetMapping("/list")
public TableDataInfo list(SysDictData dictData)
{
startPage();
List<SysDictData> list = dictDataService.selectDictDataList(dictData);
return getDataTable(list);
}
@Log(title = "字典数据", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:dict:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysDictData dictData)
{
List<SysDictData> list = dictDataService.selectDictDataList(dictData);
ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class);
util.exportExcel(response, list, "字典数据");
}
/**
* 查询字典数据详细
*/
@PreAuthorize("@ss.hasPermi('system:dict:query')")
@GetMapping(value = "/{dictCode}")
public AjaxResult getInfo(@PathVariable Long dictCode)
{
return success(dictDataService.selectDictDataById(dictCode));
}
/**
* 根据字典类型查询字典数据信息
*/
@GetMapping(value = "/type/{dictType}")
public AjaxResult dictType(@PathVariable String dictType)
{
List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
if (StringUtils.isNull(data))
{
data = new ArrayList<SysDictData>();
}
return success(data);
}
/**
* 新增字典类型
*/
@PreAuthorize("@ss.hasPermi('system:dict:add')")
@Log(title = "字典数据", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysDictData dict)
{
dict.setCreateBy(getUsername());
return toAjax(dictDataService.insertDictData(dict));
}
/**
* 修改保存字典类型
*/
@PreAuthorize("@ss.hasPermi('system:dict:edit')")
@Log(title = "字典数据", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysDictData dict)
{
dict.setUpdateBy(getUsername());
return toAjax(dictDataService.updateDictData(dict));
}
/**
* 删除字典类型
*/
@PreAuthorize("@ss.hasPermi('system:dict:remove')")
@Log(title = "字典类型", businessType = BusinessType.DELETE)
@DeleteMapping("/{dictCodes}")
public AjaxResult remove(@PathVariable Long[] dictCodes)
{
dictDataService.deleteDictDataByIds(dictCodes);
return success();
}
}

View File

@@ -0,0 +1,144 @@
package com.fastbee.web.controller.system;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.annotation.Log;
import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.domain.entity.SysDictType;
import com.fastbee.common.core.page.TableDataInfo;
import com.fastbee.common.enums.BusinessType;
import com.fastbee.common.utils.poi.ExcelUtil;
import com.fastbee.system.service.ISysDictTypeService;
/**
* 数据字典信息
*
* @author ruoyi
*/
@Api(tags = "字典管理")
@RestController
@RequestMapping("/system/dict/type")
public class SysDictTypeController extends BaseController
{
@Autowired
private ISysDictTypeService dictTypeService;
@ApiOperation("获取字典分页列表")
@PreAuthorize("@ss.hasPermi('system:dict:list')")
@GetMapping("/list")
public TableDataInfo list(SysDictType dictType)
{
startPage();
List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
return getDataTable(list);
}
@ApiOperation("导出字典列表")
@Log(title = "字典类型", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:dict:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysDictType dictType)
{
List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
ExcelUtil<SysDictType> util = new ExcelUtil<SysDictType>(SysDictType.class);
util.exportExcel(response, list, "字典类型");
}
/**
* 查询字典类型详细
*/
@ApiOperation("查询字典类型详细")
@PreAuthorize("@ss.hasPermi('system:dict:query')")
@GetMapping(value = "/{dictId}")
public AjaxResult getInfo(@PathVariable Long dictId)
{
return success(dictTypeService.selectDictTypeById(dictId));
}
/**
* 新增字典类型
*/
@ApiOperation("新增字典类型")
@PreAuthorize("@ss.hasPermi('system:dict:add')")
@Log(title = "字典类型", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysDictType dict)
{
if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict)))
{
return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
}
dict.setCreateBy(getUsername());
return toAjax(dictTypeService.insertDictType(dict));
}
/**
* 修改字典类型
*/
@ApiOperation("新增字典类型")
@PreAuthorize("@ss.hasPermi('system:dict:edit')")
@Log(title = "字典类型", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysDictType dict)
{
if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict)))
{
return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
}
dict.setUpdateBy(getUsername());
return toAjax(dictTypeService.updateDictType(dict));
}
/**
* 删除字典类型
*/
@ApiOperation("删除字典类型")
@PreAuthorize("@ss.hasPermi('system:dict:remove')")
@Log(title = "字典类型", businessType = BusinessType.DELETE)
@DeleteMapping("/{dictIds}")
public AjaxResult remove(@PathVariable Long[] dictIds)
{
dictTypeService.deleteDictTypeByIds(dictIds);
return success();
}
/**
* 刷新字典缓存
*/
@ApiOperation("刷新字典缓存")
@PreAuthorize("@ss.hasPermi('system:dict:remove')")
@Log(title = "字典类型", businessType = BusinessType.CLEAN)
@DeleteMapping("/refreshCache")
public AjaxResult refreshCache()
{
dictTypeService.resetDictCache();
return success();
}
/**
* 获取字典选择框列表
*/
@ApiOperation("获取字典选择框列表")
@GetMapping("/optionselect")
public AjaxResult optionselect()
{
List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll();
return success(dictTypes);
}
}

View File

@@ -0,0 +1,29 @@
package com.fastbee.web.controller.system;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.config.RuoYiConfig;
import com.fastbee.common.utils.StringUtils;
/**
* 首页
*
* @author ruoyi
*/
@RestController
public class SysIndexController
{
/** 系统基础配置 */
@Autowired
private RuoYiConfig ruoyiConfig;
/**
* 访问首页,提示语
*/
@RequestMapping("/")
public String index()
{
return StringUtils.format("欢迎使用{}后台管理框架当前版本v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion());
}
}

View File

@@ -0,0 +1,97 @@
package com.fastbee.web.controller.system;
import java.util.List;
import java.util.Set;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.constant.Constants;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.domain.entity.SysMenu;
import com.fastbee.common.core.domain.entity.SysUser;
import com.fastbee.common.core.domain.model.LoginBody;
import com.fastbee.common.utils.SecurityUtils;
import com.fastbee.framework.web.service.SysLoginService;
import com.fastbee.framework.web.service.SysPermissionService;
import com.fastbee.system.service.ISysMenuService;
/**
* 登录验证
*
* @author ruoyi
*/
@Api(tags = "登录验证")
@RestController
public class SysLoginController
{
@Autowired
private SysLoginService loginService;
@Autowired
private ISysMenuService menuService;
@Autowired
private SysPermissionService permissionService;
@Value("${server.broker.enabled}")
private Boolean enabled;
/**
* 登录方法
*
* @param loginBody 登录信息
* @return 结果
*/
@ApiOperation("用户登录")
@PostMapping("/login")
public AjaxResult login(@RequestBody LoginBody loginBody)
{
AjaxResult ajax = AjaxResult.success();
// 生成令牌
String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
loginBody.getUuid());
ajax.put(Constants.TOKEN, token);
return ajax;
}
/**
* 获取用户信息
*
* @return 用户信息
*/
@ApiOperation("获取用户信息")
@GetMapping("getInfo")
public AjaxResult getInfo()
{
SysUser user = SecurityUtils.getLoginUser().getUser();
// 角色集合
Set<String> roles = permissionService.getRolePermission(user);
// 权限集合
Set<String> permissions = permissionService.getMenuPermission(user);
AjaxResult ajax = AjaxResult.success();
ajax.put("user", user);
ajax.put("roles", roles);
ajax.put("permissions", permissions);
ajax.put("mqtt",enabled);
return ajax;
}
/**
* 获取路由信息
*
* @return 路由信息
*/
@ApiOperation("获取路由信息")
@GetMapping("getRouters")
public AjaxResult getRouters()
{
Long userId = SecurityUtils.getUserId();
List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
return AjaxResult.success(menuService.buildMenus(menus));
}
}

View File

@@ -0,0 +1,153 @@
package com.fastbee.web.controller.system;
import java.util.List;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.annotation.Log;
import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.domain.entity.SysMenu;
import com.fastbee.common.enums.BusinessType;
import com.fastbee.common.utils.StringUtils;
import com.fastbee.system.service.ISysMenuService;
/**
* 菜单信息
*
* @author ruoyi
*/
@Api(tags = "菜单管理")
@RestController
@RequestMapping("/system/menu")
public class SysMenuController extends BaseController
{
@Autowired
private ISysMenuService menuService;
/**
* 获取菜单列表
*/
@ApiOperation("获取菜单列表")
@PreAuthorize("@ss.hasPermi('system:menu:list')")
@GetMapping("/list")
public AjaxResult list(SysMenu menu)
{
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
return success(menus);
}
/**
* 根据菜单编号获取详细信息
*/
@ApiOperation("根据菜单编号获取详细信息")
@PreAuthorize("@ss.hasPermi('system:menu:query')")
@GetMapping(value = "/{menuId}")
public AjaxResult getInfo(@PathVariable Long menuId)
{
return success(menuService.selectMenuById(menuId));
}
/**
* 获取菜单下拉树列表
*/
@ApiOperation("获取菜单下拉树列表")
@GetMapping("/treeselect")
public AjaxResult treeselect(SysMenu menu)
{
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
return success(menuService.buildMenuTreeSelect(menus));
}
/**
* 加载对应角色菜单列表树
*/
@ApiOperation("加载对应角色菜单列表树")
@GetMapping(value = "/roleMenuTreeselect/{roleId}")
public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId)
{
List<SysMenu> menus = menuService.selectMenuList(getUserId());
AjaxResult ajax = AjaxResult.success();
ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
ajax.put("menus", menuService.buildMenuTreeSelect(menus));
return ajax;
}
/**
* 新增菜单
*/
@ApiOperation("新增菜单")
@PreAuthorize("@ss.hasPermi('system:menu:add')")
@Log(title = "菜单管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysMenu menu)
{
if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu)))
{
return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
}
else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
{
return error("新增菜单'" + menu.getMenuName() + "'失败地址必须以http(s)://开头");
}
menu.setCreateBy(getUsername());
return toAjax(menuService.insertMenu(menu));
}
/**
* 修改菜单
*/
@ApiOperation("修改菜单")
@PreAuthorize("@ss.hasPermi('system:menu:edit')")
@Log(title = "菜单管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysMenu menu)
{
if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu)))
{
return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
}
else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
{
return error("修改菜单'" + menu.getMenuName() + "'失败地址必须以http(s)://开头");
}
else if (menu.getMenuId().equals(menu.getParentId()))
{
return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
}
menu.setUpdateBy(getUsername());
return toAjax(menuService.updateMenu(menu));
}
/**
* 删除菜单
*/
@ApiOperation("删除菜单")
@PreAuthorize("@ss.hasPermi('system:menu:remove')")
@Log(title = "菜单管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{menuId}")
public AjaxResult remove(@PathVariable("menuId") Long menuId)
{
if (menuService.hasChildByMenuId(menuId))
{
return warn("存在子菜单,不允许删除");
}
if (menuService.checkMenuExistRole(menuId))
{
return warn("菜单已分配,不允许删除");
}
return toAjax(menuService.deleteMenuById(menuId));
}
}

View File

@@ -0,0 +1,100 @@
package com.fastbee.web.controller.system;
import java.util.List;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.annotation.Log;
import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.page.TableDataInfo;
import com.fastbee.common.enums.BusinessType;
import com.fastbee.system.domain.SysNotice;
import com.fastbee.system.service.ISysNoticeService;
/**
* 公告 信息操作处理
*
* @author ruoyi
*/
@Api(tags = "通知公告")
@RestController
@RequestMapping("/system/notice")
public class SysNoticeController extends BaseController
{
@Autowired
private ISysNoticeService noticeService;
/**
* 获取通知公告列表
*/
@ApiOperation("获取通知公告列表")
@PreAuthorize("@ss.hasPermi('system:notice:list')")
@GetMapping("/list")
public TableDataInfo list(SysNotice notice)
{
startPage();
List<SysNotice> list = noticeService.selectNoticeList(notice);
return getDataTable(list);
}
/**
* 根据通知公告编号获取详细信息
*/
@ApiOperation("根据通知公告编号获取详细信息")
@PreAuthorize("@ss.hasPermi('system:notice:query')")
@GetMapping(value = "/{noticeId}")
public AjaxResult getInfo(@PathVariable Long noticeId)
{
return success(noticeService.selectNoticeById(noticeId));
}
/**
* 新增通知公告
*/
@ApiOperation("新增通知公告")
@PreAuthorize("@ss.hasPermi('system:notice:add')")
@Log(title = "通知公告", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysNotice notice)
{
notice.setCreateBy(getUsername());
return toAjax(noticeService.insertNotice(notice));
}
/**
* 修改通知公告
*/
@ApiOperation("修改通知公告")
@PreAuthorize("@ss.hasPermi('system:notice:edit')")
@Log(title = "通知公告", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysNotice notice)
{
notice.setUpdateBy(getUsername());
return toAjax(noticeService.updateNotice(notice));
}
/**
* 删除通知公告
*/
@ApiOperation("删除通知公告")
@PreAuthorize("@ss.hasPermi('system:notice:remove')")
@Log(title = "通知公告", businessType = BusinessType.DELETE)
@DeleteMapping("/{noticeIds}")
public AjaxResult remove(@PathVariable Long[] noticeIds)
{
return toAjax(noticeService.deleteNoticeByIds(noticeIds));
}
}

View File

@@ -0,0 +1,141 @@
package com.fastbee.web.controller.system;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.annotation.Log;
import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.page.TableDataInfo;
import com.fastbee.common.enums.BusinessType;
import com.fastbee.common.utils.poi.ExcelUtil;
import com.fastbee.system.domain.SysPost;
import com.fastbee.system.service.ISysPostService;
/**
* 岗位信息操作处理
*
* @author ruoyi
*/
@Api(tags = "岗位管理")
@RestController
@RequestMapping("/system/post")
public class SysPostController extends BaseController
{
@Autowired
private ISysPostService postService;
/**
* 获取岗位列表
*/
@ApiOperation("获取岗位列表")
@PreAuthorize("@ss.hasPermi('system:post:list')")
@GetMapping("/list")
public TableDataInfo list(SysPost post)
{
startPage();
List<SysPost> list = postService.selectPostList(post);
return getDataTable(list);
}
@ApiOperation("导出岗位列表")
@Log(title = "岗位管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:post:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysPost post)
{
List<SysPost> list = postService.selectPostList(post);
ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class);
util.exportExcel(response, list, "岗位数据");
}
/**
* 根据岗位编号获取详细信息
*/
@ApiOperation("根据岗位编号获取详细信息")
@PreAuthorize("@ss.hasPermi('system:post:query')")
@GetMapping(value = "/{postId}")
public AjaxResult getInfo(@PathVariable Long postId)
{
return success(postService.selectPostById(postId));
}
/**
* 新增岗位
*/
@ApiOperation("新增岗位")
@PreAuthorize("@ss.hasPermi('system:post:add')")
@Log(title = "岗位管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysPost post)
{
if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post)))
{
return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
}
else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post)))
{
return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在");
}
post.setCreateBy(getUsername());
return toAjax(postService.insertPost(post));
}
/**
* 修改岗位
*/
@ApiOperation("修改岗位")
@PreAuthorize("@ss.hasPermi('system:post:edit')")
@Log(title = "岗位管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysPost post)
{
if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post)))
{
return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
}
else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post)))
{
return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
}
post.setUpdateBy(getUsername());
return toAjax(postService.updatePost(post));
}
/**
* 删除岗位
*/
@ApiOperation("删除岗位")
@PreAuthorize("@ss.hasPermi('system:post:remove')")
@Log(title = "岗位管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{postIds}")
public AjaxResult remove(@PathVariable Long[] postIds)
{
return toAjax(postService.deletePostByIds(postIds));
}
/**
* 获取岗位选择框列表
*/
@ApiOperation("获取岗位选择框列表")
@GetMapping("/optionselect")
public AjaxResult optionselect()
{
List<SysPost> posts = postService.selectPostAll();
return success(posts);
}
}

View File

@@ -0,0 +1,163 @@
package com.fastbee.web.controller.system;
import com.fastbee.common.annotation.Log;
import com.fastbee.common.config.RuoYiConfig;
import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.domain.entity.SysUser;
import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.enums.BusinessType;
import com.fastbee.common.enums.SocialPlatformType;
import com.fastbee.common.utils.SecurityUtils;
import com.fastbee.common.utils.StringUtils;
import com.fastbee.common.utils.file.FileUploadUtils;
import com.fastbee.common.utils.file.MimeTypeUtils;
import com.fastbee.framework.web.service.TokenService;
import com.fastbee.iot.domain.UserSocialProfile;
import com.fastbee.iot.service.IUserSocialProfileService;
import com.fastbee.system.service.ISysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* 个人信息 业务处理
*
* @author ruoyi
*/
@Api(tags = "个人中心")
@RestController
@RequestMapping("/system/user/profile")
public class SysProfileController extends BaseController
{
@Autowired
private ISysUserService userService;
@Autowired
private TokenService tokenService;
@Autowired
private IUserSocialProfileService iUserSocialProfileService;
/**
* 个人信息
*/
@ApiOperation("获取个人信息")
@GetMapping
public AjaxResult profile()
{
LoginUser loginUser = getLoginUser();
SysUser user = loginUser.getUser();
AjaxResult ajax = AjaxResult.success(user);
ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername()));
ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername()));
List<UserSocialProfile> socialProfileList = iUserSocialProfileService.selectUserSocialProfile(loginUser.getUserId());
UserSocialProfile userSocialProfile = socialProfileList.stream().filter(s -> SocialPlatformType.listWechatPlatform.contains(s.getSourceClient()) && "1".equals(s.getStatus())).findFirst().orElse(null);
ajax.put("socialGroup", socialProfileList);
ajax.put("wxBind", userSocialProfile != null);
return ajax;
}
/**
* 修改用户
*/
@ApiOperation("修改个人信息")
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult updateProfile(@RequestBody SysUser user)
{
LoginUser loginUser = getLoginUser();
SysUser sysUser = loginUser.getUser();
user.setUserName(sysUser.getUserName());
if (StringUtils.isNotEmpty(user.getPhonenumber())
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
{
return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
}
if (StringUtils.isNotEmpty(user.getEmail())
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
{
return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
}
user.setUserId(sysUser.getUserId());
user.setPassword(null);
user.setAvatar(null);
user.setDeptId(null);
if (userService.updateUserProfile(user) > 0)
{
// 更新缓存用户信息
sysUser.setNickName(user.getNickName());
sysUser.setPhonenumber(user.getPhonenumber());
sysUser.setEmail(user.getEmail());
sysUser.setSex(user.getSex());
tokenService.setLoginUser(loginUser);
return success();
}
return error("修改个人信息异常,请联系管理员");
}
/**
* 重置密码
*/
@ApiOperation("重置密码")
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
@PutMapping("/updatePwd")
public AjaxResult updatePwd(String oldPassword, String newPassword)
{
LoginUser loginUser = getLoginUser();
String userName = loginUser.getUsername();
String password = loginUser.getPassword();
if (!SecurityUtils.matchesPassword(oldPassword, password))
{
return error("修改密码失败,旧密码错误");
}
if (SecurityUtils.matchesPassword(newPassword, password))
{
return error("新密码不能与旧密码相同");
}
if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0)
{
// 更新缓存用户密码
loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword));
tokenService.setLoginUser(loginUser);
return success();
}
return error("修改密码异常,请联系管理员");
}
/**
* 头像上传
*/
@ApiOperation("头像上传")
@Log(title = "用户头像", businessType = BusinessType.UPDATE)
@PostMapping("/avatar")
public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception
{
if (!file.isEmpty())
{
LoginUser loginUser = getLoginUser();
String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION);
if (userService.updateUserAvatar(loginUser.getUsername(), avatar))
{
AjaxResult ajax = AjaxResult.success();
ajax.put("imgUrl", avatar);
// 更新缓存用户头像
loginUser.getUser().setAvatar(avatar);
tokenService.setLoginUser(loginUser);
return ajax;
}
}
return error("上传图片异常,请联系管理员");
}
}

View File

@@ -0,0 +1,42 @@
package com.fastbee.web.controller.system;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.domain.model.RegisterBody;
import com.fastbee.common.utils.StringUtils;
import com.fastbee.framework.web.service.SysRegisterService;
import com.fastbee.system.service.ISysConfigService;
/**
* 注册验证
*
* @author ruoyi
*/
@Api(tags = "注册账号")
@RestController
public class SysRegisterController extends BaseController
{
@Autowired
private SysRegisterService registerService;
@Autowired
private ISysConfigService configService;
@ApiOperation("注册账号")
@PostMapping("/register")
public AjaxResult register(@RequestBody RegisterBody user)
{
if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser"))))
{
return error("当前系统没有开启注册功能!");
}
String msg = registerService.register(user);
return StringUtils.isEmpty(msg) ? success() : error(msg);
}
}

View File

@@ -0,0 +1,282 @@
package com.fastbee.web.controller.system;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.annotation.Log;
import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.domain.entity.SysDept;
import com.fastbee.common.core.domain.entity.SysRole;
import com.fastbee.common.core.domain.entity.SysUser;
import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.core.page.TableDataInfo;
import com.fastbee.common.enums.BusinessType;
import com.fastbee.common.utils.StringUtils;
import com.fastbee.common.utils.poi.ExcelUtil;
import com.fastbee.framework.web.service.SysPermissionService;
import com.fastbee.framework.web.service.TokenService;
import com.fastbee.system.domain.SysUserRole;
import com.fastbee.system.service.ISysDeptService;
import com.fastbee.system.service.ISysRoleService;
import com.fastbee.system.service.ISysUserService;
/**
* 角色信息
*
* @author ruoyi
*/
@Api(tags = "角色管理")
@RestController
@RequestMapping("/system/role")
public class SysRoleController extends BaseController
{
@Autowired
private ISysRoleService roleService;
@Autowired
private TokenService tokenService;
@Autowired
private SysPermissionService permissionService;
@Autowired
private ISysUserService userService;
@Autowired
private ISysDeptService deptService;
@ApiOperation("获取角色分页列表")
@PreAuthorize("@ss.hasPermi('system:role:list')")
@GetMapping("/list")
public TableDataInfo list(SysRole role)
{
startPage();
List<SysRole> list = roleService.selectRoleList(role);
return getDataTable(list);
}
@ApiOperation("导出角色列表")
@Log(title = "角色管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:role:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysRole role)
{
List<SysRole> list = roleService.selectRoleList(role);
ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class);
util.exportExcel(response, list, "角色数据");
}
/**
* 根据角色编号获取详细信息
*/
@ApiOperation("根据角色编号获取详细信息")
@PreAuthorize("@ss.hasPermi('system:role:query')")
@GetMapping(value = "/{roleId}")
public AjaxResult getInfo(@PathVariable Long roleId)
{
roleService.checkRoleDataScope(roleId);
return success(roleService.selectRoleById(roleId));
}
/**
* 新增角色
*/
@ApiOperation("新增角色")
@PreAuthorize("@ss.hasPermi('system:role:add')")
@Log(title = "角色管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysRole role)
{
if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role)))
{
return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
}
else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role)))
{
return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
}
role.setCreateBy(getUsername());
return toAjax(roleService.insertRole(role));
}
/**
* 修改保存角色
*/
@ApiOperation("修改角色")
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysRole role)
{
roleService.checkRoleAllowed(role);
roleService.checkRoleDataScope(role.getRoleId());
if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role)))
{
return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
}
else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role)))
{
return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
}
role.setUpdateBy(getUsername());
if (roleService.updateRole(role) > 0)
{
// 更新缓存用户权限
LoginUser loginUser = getLoginUser();
if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin())
{
loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName()));
tokenService.setLoginUser(loginUser);
}
return success();
}
return error("修改角色'" + role.getRoleName() + "'失败,请联系管理员");
}
/**
* 修改保存数据权限
*/
@ApiOperation("修改保存数据权限")
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
@PutMapping("/dataScope")
public AjaxResult dataScope(@RequestBody SysRole role)
{
roleService.checkRoleAllowed(role);
roleService.checkRoleDataScope(role.getRoleId());
return toAjax(roleService.authDataScope(role));
}
/**
* 状态修改
*/
@ApiOperation("修改角色状态")
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus")
public AjaxResult changeStatus(@RequestBody SysRole role)
{
roleService.checkRoleAllowed(role);
roleService.checkRoleDataScope(role.getRoleId());
role.setUpdateBy(getUsername());
return toAjax(roleService.updateRoleStatus(role));
}
/**
* 删除角色
*/
@ApiOperation("删除角色")
@PreAuthorize("@ss.hasPermi('system:role:remove')")
@Log(title = "角色管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{roleIds}")
public AjaxResult remove(@PathVariable Long[] roleIds)
{
return toAjax(roleService.deleteRoleByIds(roleIds));
}
/**
* 获取角色选择框列表
*/
@ApiOperation("获取角色选择框列表")
@PreAuthorize("@ss.hasPermi('system:role:query')")
@GetMapping("/optionselect")
public AjaxResult optionselect()
{
return success(roleService.selectRoleAll());
}
/**
* 查询已分配用户角色列表
*/
@ApiOperation("查询已分配用户角色列表")
@PreAuthorize("@ss.hasPermi('system:role:list')")
@GetMapping("/authUser/allocatedList")
public TableDataInfo allocatedList(SysUser user)
{
startPage();
List<SysUser> list = userService.selectAllocatedList(user);
return getDataTable(list);
}
/**
* 查询未分配用户角色列表
*/
@ApiOperation("查询未分配用户角色列表")
@PreAuthorize("@ss.hasPermi('system:role:list')")
@GetMapping("/authUser/unallocatedList")
public TableDataInfo unallocatedList(SysUser user)
{
startPage();
List<SysUser> list = userService.selectUnallocatedList(user);
return getDataTable(list);
}
/**
* 取消授权用户
*/
@ApiOperation("取消授权用户")
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.GRANT)
@PutMapping("/authUser/cancel")
public AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole)
{
return toAjax(roleService.deleteAuthUser(userRole));
}
/**
* 批量取消授权用户
*/
@ApiOperation("批量取消授权用户")
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.GRANT)
@PutMapping("/authUser/cancelAll")
public AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds)
{
return toAjax(roleService.deleteAuthUsers(roleId, userIds));
}
/**
* 批量选择用户授权
*/
@ApiOperation("批量选择用户授权")
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.GRANT)
@PutMapping("/authUser/selectAll")
public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds)
{
roleService.checkRoleDataScope(roleId);
return toAjax(roleService.insertAuthUsers(roleId, userIds));
}
/**
* 获取对应角色部门树列表
*/
@ApiOperation("获取对应角色部门树列表")
@PreAuthorize("@ss.hasPermi('system:role:query')")
@GetMapping(value = "/deptTree/{roleId}")
public AjaxResult deptTree(@PathVariable("roleId") Long roleId)
{
AjaxResult ajax = AjaxResult.success();
ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
ajax.put("depts", deptService.selectDeptTreeList(new SysDept()));
return ajax;
}
}

View File

@@ -0,0 +1,274 @@
package com.fastbee.web.controller.system;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.fastbee.common.annotation.Log;
import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.domain.entity.SysDept;
import com.fastbee.common.core.domain.entity.SysRole;
import com.fastbee.common.core.domain.entity.SysUser;
import com.fastbee.common.core.page.TableDataInfo;
import com.fastbee.common.enums.BusinessType;
import com.fastbee.common.utils.SecurityUtils;
import com.fastbee.common.utils.StringUtils;
import com.fastbee.common.utils.poi.ExcelUtil;
import com.fastbee.system.service.ISysDeptService;
import com.fastbee.system.service.ISysPostService;
import com.fastbee.system.service.ISysRoleService;
import com.fastbee.system.service.ISysUserService;
/**
* 用户信息
*
* @author ruoyi
*/
@Api(tags = "用户管理")
@RestController
@RequestMapping("/system/user")
public class SysUserController extends BaseController
{
@Autowired
private ISysUserService userService;
@Autowired
private ISysRoleService roleService;
@Autowired
private ISysDeptService deptService;
@Autowired
private ISysPostService postService;
/**
* 获取用户列表
*/
@ApiOperation("获取用户分页列表")
@PreAuthorize("@ss.hasPermi('system:user:list')")
@GetMapping("/list")
public TableDataInfo list(SysUser user)
{
startPage();
List<SysUser> list = userService.selectUserList(user);
return getDataTable(list);
}
@ApiOperation("导出用户列表")
@Log(title = "用户管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:user:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysUser user)
{
List<SysUser> list = userService.selectUserList(user);
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
util.exportExcel(response, list, "用户数据");
}
@ApiOperation("批量导入用户")
@Log(title = "用户管理", businessType = BusinessType.IMPORT)
@PreAuthorize("@ss.hasPermi('system:user:import')")
@PostMapping("/importData")
public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
{
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
List<SysUser> userList = util.importExcel(file.getInputStream());
String operName = getUsername();
String message = userService.importUser(userList, updateSupport, operName);
return success(message);
}
@ApiOperation("下载用户导入模板")
@PostMapping("/importTemplate")
public void importTemplate(HttpServletResponse response)
{
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
util.importTemplateExcel(response, "用户数据");
}
/**
* 根据用户编号获取详细信息
*/
@ApiOperation("根据用户编号获取详细信息")
@PreAuthorize("@ss.hasPermi('system:user:query')")
@GetMapping(value = { "/", "/{userId}" })
public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
{
userService.checkUserDataScope(userId);
AjaxResult ajax = AjaxResult.success();
List<SysRole> roles = roleService.selectRoleAll();
ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
ajax.put("posts", postService.selectPostAll());
if (StringUtils.isNotNull(userId))
{
SysUser sysUser = userService.selectUserById(userId);
ajax.put(AjaxResult.DATA_TAG, sysUser);
ajax.put("postIds", postService.selectPostListByUserId(userId));
ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
}
return ajax;
}
/**
* 新增用户
*/
@ApiOperation("新增用户")
@PreAuthorize("@ss.hasPermi('system:user:add')")
@Log(title = "用户管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysUser user)
{
if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user)))
{
return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
}
else if (StringUtils.isNotEmpty(user.getPhonenumber())
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
{
return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
}
else if (StringUtils.isNotEmpty(user.getEmail())
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
{
return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
}
user.setCreateBy(getUsername());
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
return toAjax(userService.insertUser(user));
}
/**
* 修改用户
*/
@ApiOperation("修改用户")
@PreAuthorize("@ss.hasPermi('system:user:edit')")
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysUser user)
{
userService.checkUserAllowed(user);
userService.checkUserDataScope(user.getUserId());
if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user)))
{
return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
}
else if (StringUtils.isNotEmpty(user.getPhonenumber())
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
{
return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
}
else if (StringUtils.isNotEmpty(user.getEmail())
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
{
return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
}
user.setUpdateBy(getUsername());
return toAjax(userService.updateUser(user));
}
/**
* 删除用户
*/
@ApiOperation("删除用户")
@PreAuthorize("@ss.hasPermi('system:user:remove')")
@Log(title = "用户管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{userIds}")
public AjaxResult remove(@PathVariable Long[] userIds)
{
if (ArrayUtils.contains(userIds, getUserId()))
{
return error("当前用户不能删除");
}
return toAjax(userService.deleteUserByIds(userIds));
}
/**
* 重置密码
*/
@ApiOperation("重置用户密码")
@PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PutMapping("/resetPwd")
public AjaxResult resetPwd(@RequestBody SysUser user)
{
userService.checkUserAllowed(user);
userService.checkUserDataScope(user.getUserId());
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
user.setUpdateBy(getUsername());
return toAjax(userService.resetPwd(user));
}
/**
* 状态修改
*/
@ApiOperation("修改用户状态")
@PreAuthorize("@ss.hasPermi('system:user:edit')")
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus")
public AjaxResult changeStatus(@RequestBody SysUser user)
{
userService.checkUserAllowed(user);
userService.checkUserDataScope(user.getUserId());
user.setUpdateBy(getUsername());
return toAjax(userService.updateUserStatus(user));
}
/**
* 根据用户编号获取授权角色
*/
@ApiOperation("根据用户编号获取授权角色")
@PreAuthorize("@ss.hasPermi('system:user:query')")
@GetMapping("/authRole/{userId}")
public AjaxResult authRole(@PathVariable("userId") Long userId)
{
AjaxResult ajax = AjaxResult.success();
SysUser user = userService.selectUserById(userId);
List<SysRole> roles = roleService.selectRolesByUserId(userId);
ajax.put("user", user);
ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
return ajax;
}
/**
* 用户授权角色
*/
@ApiOperation("为用户授权角色")
@PreAuthorize("@ss.hasPermi('system:user:edit')")
@Log(title = "用户管理", businessType = BusinessType.GRANT)
@PutMapping("/authRole")
public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
{
userService.checkUserDataScope(userId);
userService.insertUserAuth(userId, roleIds);
return success();
}
/**
* 获取部门树列表
*/
@ApiOperation("获取部门树列表")
@PreAuthorize("@ss.hasPermi('system:user:list')")
@GetMapping("/deptTree")
public AjaxResult deptTree(SysDept dept)
{
return success(deptService.selectDeptTreeList(dept));
}
}

View File

@@ -0,0 +1,24 @@
package com.fastbee.web.controller.tool;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.fastbee.common.core.controller.BaseController;
/**
* swagger 接口
*
* @author ruoyi
*/
@Controller
@RequestMapping("/tool/swagger")
public class SwaggerController extends BaseController
{
@PreAuthorize("@ss.hasPermi('tool:swagger:view')")
@GetMapping()
public String index()
{
return redirect("/swagger-ui.html");
}
}

View File

@@ -0,0 +1,185 @@
package com.fastbee.web.controller.tool;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.R;
import com.fastbee.common.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import javax.annotation.Resource;
/**
* swagger 用户测试方法
*
* @author ruoyi
*/
@Api("swagger 用户测试方法")
@RestController
@RequestMapping("/test/user")
public class TestController extends BaseController
{
private final static Map<Integer, UserEntity> users = new LinkedHashMap<Integer, UserEntity>();
{
users.put(1, new UserEntity(1, "admin", "admin123", "15888888888"));
users.put(2, new UserEntity(2, "ry", "admin123", "15666666666"));
}
@ApiOperation("获取用户列表")
@GetMapping("/list")
public R<List<UserEntity>> userList()
{
List<UserEntity> userList = new ArrayList<UserEntity>(users.values());
return R.ok(userList);
}
@ApiOperation("获取用户详细")
@ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
@GetMapping("/{userId}")
public R<UserEntity> getUser(@PathVariable Integer userId)
{
if (!users.isEmpty() && users.containsKey(userId))
{
return R.ok(users.get(userId));
}
else
{
return R.fail("用户不存在");
}
}
@ApiOperation("新增用户")
@ApiImplicitParams({
@ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", dataTypeClass = Integer.class),
@ApiImplicitParam(name = "username", value = "用户名称", dataType = "String", dataTypeClass = String.class),
@ApiImplicitParam(name = "password", value = "用户密码", dataType = "String", dataTypeClass = String.class),
@ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class)
})
@PostMapping("/save")
public R<String> save(UserEntity user)
{
if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
{
return R.fail("用户ID不能为空");
}
users.put(user.getUserId(), user);
return R.ok();
}
@ApiOperation("更新用户")
@PutMapping("/update")
public R<String> update(@RequestBody UserEntity user)
{
if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
{
return R.fail("用户ID不能为空");
}
if (users.isEmpty() || !users.containsKey(user.getUserId()))
{
return R.fail("用户不存在");
}
users.remove(user.getUserId());
users.put(user.getUserId(), user);
return R.ok();
}
@ApiOperation("删除用户信息")
@ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
@DeleteMapping("/{userId}")
public R<String> delete(@PathVariable Integer userId)
{
if (!users.isEmpty() && users.containsKey(userId))
{
users.remove(userId);
return R.ok();
}
else
{
return R.fail("用户不存在");
}
}
}
@ApiModel(value = "UserEntity", description = "用户实体")
class UserEntity
{
@ApiModelProperty("用户ID")
private Integer userId;
@ApiModelProperty("用户名称")
private String username;
@ApiModelProperty("用户密码")
private String password;
@ApiModelProperty("用户手机")
private String mobile;
public UserEntity()
{
}
public UserEntity(Integer userId, String username, String password, String mobile)
{
this.userId = userId;
this.username = username;
this.password = password;
this.mobile = mobile;
}
public Integer getUserId()
{
return userId;
}
public void setUserId(Integer userId)
{
this.userId = userId;
}
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 getMobile()
{
return mobile;
}
public void setMobile(String mobile)
{
this.mobile = mobile;
}
}

View File

@@ -0,0 +1,44 @@
package com.fastbee.web.controller.tool;
import com.fastbee.common.annotation.Anonymous;
import com.fastbee.iot.mapper.DeviceMapper;
import com.fastbee.iot.model.DeviceRelateAlertLogVO;
import com.fastbee.iot.service.IDeviceService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 测试类
* @author fastb
* @date 2023-09-13 11:42
*/
@Anonymous
@RestController
@RequestMapping("/test2")
public class TestController2 {
@Resource
private IDeviceService deviceService;
@Resource
private DeviceMapper deviceMapper;
@GetMapping("/add")
public void add()
{
Set<String> deviceNumbers = new HashSet<>();
deviceNumbers.add("D1PGLPG58K88");
deviceNumbers.add("D1F0L7P84D8Z");
deviceNumbers.add("D1F0L7P84D8Z_2");
List<DeviceRelateAlertLogVO> deviceRelateAlertLogVOList = deviceMapper.selectDeviceBySerialNumbers(deviceNumbers);
Map<String, DeviceRelateAlertLogVO> deviceRelateAlertLogVOMap = deviceRelateAlertLogVOList.stream().collect(Collectors.toMap(DeviceRelateAlertLogVO::getSerialNumber, Function.identity()));
}
}

View File

@@ -0,0 +1,125 @@
package com.fastbee.web.core.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.fastbee.common.config.RuoYiConfig;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.Contact;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.service.SecurityScheme;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
/**
* Swagger2的接口配置
*
* @author ruoyi
*/
@Configuration
public class SwaggerConfig
{
/** 系统基础配置 */
@Autowired
private RuoYiConfig ruoyiConfig;
/** 是否开启swagger */
@Value("${swagger.enabled}")
private boolean enabled;
/** 设置请求的统一前缀 */
@Value("${swagger.pathMapping}")
private String pathMapping;
/**
* 创建API
*/
@Bean
public Docket createRestApi()
{
return new Docket(DocumentationType.OAS_30)
// 是否启用Swagger
.enable(enabled)
// 用来创建该API的基本信息展示在文档的页面中自定义展示的信息
.apiInfo(apiInfo())
// 设置哪些接口暴露给Swagger展示
.select()
// 扫描所有有注解的api用这种方式更灵活
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
// 扫描指定包中的swagger注解
// .apis(RequestHandlerSelectors.basePackage("com.fastbee.project.tool.swagger"))
// 扫描所有 .apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
/* 设置安全模式swagger可以设置访问token */
.securitySchemes(securitySchemes())
.securityContexts(securityContexts())
.pathMapping(pathMapping);
}
/**
* 安全模式这里指定token通过Authorization头请求头传递
*/
private List<SecurityScheme> securitySchemes()
{
List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue()));
return apiKeyList;
}
/**
* 安全上下文
*/
private List<SecurityContext> securityContexts()
{
List<SecurityContext> securityContexts = new ArrayList<>();
securityContexts.add(
SecurityContext.builder()
.securityReferences(defaultAuth())
.operationSelector(o -> o.requestMappingPattern().matches("/.*"))
.build());
return securityContexts;
}
/**
* 默认的安全上引用
*/
private List<SecurityReference> defaultAuth()
{
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
List<SecurityReference> securityReferences = new ArrayList<>();
securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
return securityReferences;
}
/**
* 添加摘要信息
*/
private ApiInfo apiInfo()
{
// 用ApiInfoBuilder进行定制
return new ApiInfoBuilder()
// 设置标题
.title("FastBee物联网平台接口文档")
// 描述
.description("描述FastBee物联网平台")
// 作者信息
.contact(new Contact(ruoyiConfig.getName(), null, null))
// 版本
.version("版本号:" + ruoyiConfig.getVersion())
.build();
}
}

View File

@@ -0,0 +1 @@
restart.include.json=/com.alibaba.fastjson2.*.jar

View File

@@ -0,0 +1,82 @@
# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
druid:
# 主库数据源
master:
url: jdbc:mysql://localhost/fastbee?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: 123456
# 从库数据源
slave:
enabled: false # 从数据源开关/默认关闭
url:
username:
password:
initialSize: 5 # 初始连接数
minIdle: 10 # 最小连接池数量
maxActive: 20 # 最大连接池数量
maxWait: 60000 # 配置获取连接等待超时的时间
timeBetweenEvictionRunsMillis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最小生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000 # 配置一个连接在池中最大生存的时间,单位是毫秒
validationQuery: SELECT 1 FROM DUAL # 配置检测连接是否有效
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: fastbee
login-password: fastbee
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
# redis 配置
redis:
host: localhost # 地址
port: 6379 # 端口默认为6379
database: 1 # 数据库索引
#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://localhost:1883 # mqtt连接tcp地址
client-id: ${random.int} # 客户端Id不能相同采用随机数 ${random.value}
default-topic: test # 默认主题
timeout: 30 # 超时时间
keepalive: 30 # 保持连接
clearSession: true # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
# 日志配置
logging:
level:
com.fastbee: debug
org.springframework: warn
# Swagger配置
swagger:
enabled: true # 是否开启swagger
pathMapping: /dev-api # 请求前缀

View File

@@ -0,0 +1,83 @@
# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
druid:
# 主库数据源
master:
url: jdbc:mysql://177.7.0.11/fastbee?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: fastbee
# 从库数据源
slave:
enabled: false # 从数据源开关/默认关闭
url:
username:
password:
initialSize: 5 # 初始连接数
minIdle: 10 # 最小连接池数量
maxActive: 20 # 最大连接池数量
maxWait: 60000 # 配置获取连接等待超时的时间
timeBetweenEvictionRunsMillis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最小生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000 # 配置一个连接在池中最大生存的时间,单位是毫秒
validationQuery: SELECT 1 FROM DUAL # 配置检测连接是否有效
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: fastbee
login-password: fastbee
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
# 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 # 连接消息服务器地址
client-id: ${random.int} # 客户端Id不能相同采用随机数 ${random.value}
default-topic: test # 默认主题
timeout: 30 # 超时时间
keepalive: 30 # 保持连接
clearSession: true # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
# 日志配置
logging:
level:
com.fastbee: error
org.springframework: warn
# Swagger配置
swagger:
enabled: true # 是否开启swagger
pathMapping: /prod-api # 请求前缀

View File

@@ -0,0 +1,98 @@
# 项目相关配置
fastbee:
name: fastbee # 名称
version: 3.8.5 # 版本
copyrightYear: 2023 # 版权年份
demoEnabled: true # 实例演示开关
# 文件路径以uploadPath结尾 示例( Windows配置 D:/uploadPathLinux配置 /uploadPath
profile: /uploadPath
addressEnabled: true # 获取ip地址开关
captchaType: math # 验证码类型 math 数组计算 char 字符验证
# 开发环境配置
server:
port: 8080 # 服务器的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:
must-pass: false # 客户端连接是否需要密码
enabled: true # mqttBroker类型选择, true: 基于netty的mqttBroker和webSocket false: emq的mqttBroker
broker-node: node1
port: 1883
websocket-port: 8083
websocket-path: /mqtt
keep-alive: 70 # 默认的全部客户端心跳上传时间
# 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
#集群配置
cluster:
enable: true
type: redis
# 用户配置
user:
password:
maxRetryCount: 5 # 密码最大错误次数
lockTime: 10 # 密码锁定时间默认10分钟
# token配置
token:
header: Authorization # 令牌自定义标识
secret: abcdefghijklfastbeesmartrstuvwxyz # 令牌密钥
expireTime: 1440 # 令牌有效期默认30分钟1440为一天
# 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/* # 匹配链接

View File

@@ -0,0 +1,2 @@
Application Version: ${fastbee.version}
Spring Boot Version: ${spring-boot.version}

View File

@@ -0,0 +1,37 @@
#错误消息
not.null=* 必须填写
user.jcaptcha.error=验证码错误
user.jcaptcha.expire=验证码已失效
user.not.exists=用户不存在/密码错误
user.password.not.match=用户不存在/密码错误
user.password.retry.limit.count=密码输入错误{0}次
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
user.password.delete=对不起,您的账号已被删除
user.blocked=用户已封禁,请联系管理员
role.blocked=角色已封禁,请联系管理员
user.logout.success=退出成功
length.not.valid=长度必须在{min}到{max}个字符之间
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成且必须以非数字开头
user.password.not.valid=* 5-50个字符
user.email.not.valid=邮箱格式错误
user.mobile.phone.number.not.valid=手机号格式错误
user.login.success=登录成功
user.register.success=注册成功
user.notfound=请重新登录
user.forcelogout=管理员强制退出,请重新登录
user.unknown.error=未知错误,请重新登录
##文件上传消息
upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB
upload.filename.exceed.length=上传的文件名最长{0}个字符
##权限
no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]

View File

@@ -0,0 +1,118 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 日志存放路径 -->
<property name="log.path" value="/logs" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-debug.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-debug.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 DEBUG-->
<level>DEBUG</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 用户访问日志输出 -->
<appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-user.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.fastbee" level="debug" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<root level="info">
<appender-ref ref="console" />
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_debug"/>
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
</root>
<!--系统用户操作日志-->
<logger name="sys-user" level="info">
<appender-ref ref="sys-user"/>
</logger>
</configuration>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 全局参数 -->
<settings>
<!-- 使全局的映射器启用或禁用缓存 -->
<setting name="cacheEnabled" value="true" />
<!-- 允许JDBC 支持自动生成主键 -->
<setting name="useGeneratedKeys" value="true" />
<!-- 配置默认的执行器.SIMPLE就是普通执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 -->
<setting name="defaultExecutorType" value="SIMPLE" />
<!-- 指定 MyBatis 所用日志的具体实现 -->
<setting name="logImpl" value="SLF4J" />
<!-- 使用驼峰命名法转换字段 -->
<!-- <setting name="mapUnderscoreToCamelCase" value="true"/> -->
</settings>
</configuration>

View File

@@ -0,0 +1,197 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>fastbee</artifactId>
<groupId>com.fastbee</groupId>
<version>3.8.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>fastbee-common</artifactId>
<description>
common通用工具
</description>
<dependencies>
<!-- Spring框架基本的核心工具 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- SpringWeb模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<!-- spring security 安全认证 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatis-plus-generator.version}</version>
</dependency>
<!-- pagehelper 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
<!-- 自定义验证注解 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!--常用工具类 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- JSON工具类 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- 动态数据源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<!-- 阿里JSON解析器 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
<!-- io常用工具类 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<!-- 文件上传工具类 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</dependency>
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
<!-- yml解析器 -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<!-- Token生成与解析-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<!-- Jaxb -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<!-- redis 缓存操作 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- pool 对象池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- 解析客户端操作系统、浏览器等 -->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
</dependency>
<!-- servlet包 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.6.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.redisson</groupId>-->
<!-- <artifactId>redisson-spring-boot-starter</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel-core</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,19 @@
package com.fastbee.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 匿名访问不鉴权注解
*
* @author ruoyi
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Anonymous
{
}

View File

@@ -0,0 +1,33 @@
package com.fastbee.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 数据权限过滤注解
*
* @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 "";
}

View File

@@ -0,0 +1,28 @@
package com.fastbee.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.fastbee.common.enums.DataSourceType;
/**
* 自定义多数据源切换注解
*
* 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
*
* @author ruoyi
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DataSource
{
/**
* 切换数据源名称
*/
public DataSourceType value() default DataSourceType.MASTER;
}

View File

@@ -0,0 +1,22 @@
package com.fastbee.common.annotation;
import java.lang.annotation.*;
/**
* 字典格式化
*
* 实现将字典数据的值,格式化成字典数据的标签
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface DictFormat {
/**
* 例如说SysDictTypeConstants、InfDictTypeConstants
*
* @return 字典类型
*/
String value();
}

View File

@@ -0,0 +1,187 @@
package com.fastbee.common.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.math.BigDecimal;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import com.fastbee.common.utils.poi.ExcelHandlerAdapter;
/**
* 自定义导出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;
}
}
}

View File

@@ -0,0 +1,18 @@
package com.fastbee.common.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();
}

View File

@@ -0,0 +1,46 @@
package com.fastbee.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.fastbee.common.enums.BusinessType;
import com.fastbee.common.enums.OperatorType;
/**
* 自定义操作日志记录注解
*
* @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;
}

View File

@@ -0,0 +1,40 @@
package com.fastbee.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.fastbee.common.constant.CacheConstants;
import com.fastbee.common.enums.LimitType;
/**
* 限流注解
*
* @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;
}

View File

@@ -0,0 +1,31 @@
package com.fastbee.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义注解防止表单重复提交
*
* @author ruoyi
*
*/
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeatSubmit
{
/**
* 间隔时间(ms),小于此时间视为重复提交
*/
public int interval() default 5000;
/**
* 提示消息
*/
public String message() default "不允许重复提交,请稍候再试";
}

View File

@@ -0,0 +1,21 @@
package com.fastbee.common.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 "";
}

View File

@@ -0,0 +1,104 @@
package com.fastbee.common.config;
import com.fastbee.common.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);
}
/*组装线程池*/
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;
}
}

View File

@@ -0,0 +1,135 @@
package com.fastbee.common.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";
}
}

View File

@@ -0,0 +1,49 @@
package com.fastbee.common.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 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:";
/**
* 防重提交 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:";
}

View File

@@ -0,0 +1,142 @@
package com.fastbee.common.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" };
}

View File

@@ -0,0 +1,252 @@
package com.fastbee.common.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 MESSAGE_CONSUME_TASK = "messageConsumeTask";
/*内部消费线程publish*/
String MESSAGE_CONSUME_TASK_PUB = "messageConsumeTaskPub";
/*内部消费线程Fetch*/
String MESSAGE_CONSUME_TASK_FETCH = "messageConsumeTaskFetch";
/*OTA升级延迟队列*/
String DELAY_UPGRADE_TASK = "delayUpgradeTask";
}
interface MQTT{
//*上报平台前缀*//*
String UP_TOPIC_SUFFIX = "post";
//*下发设备前缀*//*
String DOWN_TOPIC_SUFFIX = "get";
/*模拟设备后缀*/
String PROPERTY_GET_SIMULATE = "simulate";
String PREDIX = "/+/+";
String DUP = "dup";
String QOS = "qos";
String RETAIN = "retain";
String CLEAN_SESSION = "cleanSession";
/*集群方式*/
String REDIS_CHANNEL = "redis";
String ROCKET_MQ = "rocketmq";
}
/*集群,全局发布的消息类型*/
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{
/*redis全局前缀*/
String GLOBAL_PREFIX_KEY = "fastbee:";
/*设备在线状态*/
String DEVICE_STATUS_KEY = "device:status";
/*在线设备列表*/
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:";
/**采集点变更记录缓存key*/
String COLLECT_POINT_CHANGE = "collect:point:change:";
/**属性下发回调*/
String PROP_READ_STORE = "prop:read:store:";
/**sip*/
String RECORDINFO_KEY = "sip:recordinfo:";
String DEVICEID_KEY = "sip:deviceid:";
String STREAM_KEY = "sip:stream:";
String SIP_CSEQ_PREFIX = "sip:CSEQ:";
String DEFAULT_SIP_CONFIG = "sip:config";
String DEFAULT_MEDIA_CONFIG = "sip:mediaconfig";
/**当前连接数*/
String MESSAGE_CONNECT_COUNT = "messages:connect:count";
/**总保留消息*/
String MESSAGE_RETAIN_TOTAL = "message:retain:total";
/**主题数*/
String MESSAGE_TOPIC_TOTAL = "message:topic: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";
// 物模型值命名空间KeyTSLV:{productId}_{deviceNumber} HKey:{identity#V/identity#S/identity#M/identity#N}
/**
* v-值
* s-影子值
* m-是否为检测值
* n-名称
*/
String DEVICE_PRE_KEY = "TSLV:";
// 物模型命名空间Key:TSL:{productId}
String TSL_PRE_KEY ="TSL:";
/**modbus缓存指令*/
String POLL_MODBUS_KEY = "poll:modbus";
}
interface TOPIC{
/*属性上报*/
String PROP = "properties";
//事件
String EVENT = "events";
//功能
String FUNCTION = "functions";
/*非OTA消息回复*/
String MSG_REPLY = "message/reply";
/*OTA升级回复*/
String UPGRADE_REPLY = "upgrade/reply";
String SUB_UPGRADE_REPLY = "sub/upgrade/reply";
/*网关子设备结尾*/
String SUB = "/sub";
}
interface PROTOCOL {
String ModbusRtu = "MODBUS-RTU";
String YinErDa = "YinErDa";
String JsonObject = "JSONOBJECT";
String JsonArray = "JSON";
String ModbusRtuPak = "MODBUS-RTU-PAK";
String FlowMeter = "FlowMeter";
String RJ45 = "RJ45";
String ModbusToJson = "MODBUS-JSON";
String ModbusToJsonFY = "MODBUS-JSON-FY";
String JsonObject_ChenYi = "JSONOBJECT-CHENYI";
}
}

View File

@@ -0,0 +1,117 @@
package com.fastbee.common.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";
}

View File

@@ -0,0 +1,105 @@
package com.fastbee.common.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;
}

View File

@@ -0,0 +1,41 @@
package com.fastbee.common.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;
}

View File

@@ -0,0 +1,50 @@
package com.fastbee.common.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;
}
}
}

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