68 Commits

Author SHA1 Message Date
zhuangpeng.li
9abbecf61c Merge branch 'dev-ruoyi-5.8.9' into dev-springboot3 2025-04-28 10:28:07 +08:00
zhuangpeng.li
efe562f7e6 fix(启动报错): 启动报错问题修复 2025-04-28 10:11:16 +08:00
zhuangpeng.li
4d8e1c5167 feat(支持springboot3): 支持springboot3框架 2025-04-27 17:56:52 +08:00
gx_ma
3500faf044 feat(多数据源): 新增字段 2025-04-27 11:51:39 +08:00
zhuangpeng.li
5b6ec185c4 fix(ruoyi3.8.9): 后端代码同步 2025-04-27 11:21:09 +08:00
gx_ma
f545198645 feat(多数据源): Oracle脚本 2025-04-24 18:01:30 +08:00
gx_ma
32cc5e794e fix(视频设备): 报错修改 2025-04-24 17:14:00 +08:00
gx_ma
461ab2a37e Merge remote-tracking branch 'origin/dev-ruoyi-5.8.9' into dev-ruoyi-5.8.9 2025-04-24 16:49:27 +08:00
gx_ma
44bd079c06 refactor(代码生成): 代码生成支持多数据源 2025-04-24 16:48:48 +08:00
Zhu
70f466e471 fix(优化): 代码优化 2025-04-24 16:48:38 +08:00
Zhu
8d60474904 fix(代码更新): 更新代码 2025-04-24 16:35:20 +08:00
Zhu
2df210fe6b fix(生成代码): 数据源的优化 2025-04-24 16:05:18 +08:00
Zhu
00f5c882e2 fix(生成代码): 新增数据源的显示 2025-04-24 15:47:04 +08:00
gx_ma
25239c32cb refactor(多数据源): 报错与关键字修改 2025-04-24 11:10:17 +08:00
gx_ma
bfd2977ff4 fix(通知公告): string与blob类型互转报错 2025-04-24 09:34:26 +08:00
gx_ma
8c9031acef fix(多数据源): 配置增加 2025-04-23 17:05:43 +08:00
gx_ma
f5598f1663 fix(多数据源): 报错修改 2025-04-23 17:04:02 +08:00
zhuangpeng.li
d681d4b22b Merge remote-tracking branch 'origin/dev-ruoyi-5.8.9' into dev-ruoyi-5.8.9 2025-04-23 11:39:55 +08:00
zhuangpeng.li
0215feb4b0 fix(登录问题): 修复登录用户缓存为空的问题 2025-04-23 11:39:44 +08:00
gx_ma
905e36243c refactor(字段规范): sip_device字段命名规范 2025-04-22 15:18:20 +08:00
zhuangpeng.li
201bbfeefb Merge remote-tracking branch 'origin/dev-ruoyi-5.8.9' into dev-ruoyi-5.8.9
# Conflicts:
#	springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/DataSourceConfig.java
2025-04-22 10:20:28 +08:00
zhuangpeng.li
39aba490c6 feat(多数据源): 支持多数据源动态切换 2025-04-22 10:20:02 +08:00
gx_ma
54f2487330 feat(多数据源脚本): 达梦、SQL server、postgres 2025-04-22 10:03:31 +08:00
zhuangpeng.li
ff51ea78af feat(ruoyi版本同步): ruoyi-3.8.9版本同步 2025-04-17 09:44:10 +08:00
zhuangpeng.li
e404cd26d4 build(依赖包整理): 依赖包版本统一整理 2025-04-16 14:31:24 +08:00
zhuangpeng.li
b86acd933b build(版本号修改): 版本号修改 2025-04-16 11:08:49 +08:00
zhuangpeng.li
5fc141719a fix(规则脚本增加日志): 规则脚本增加日志 2025-04-15 17:22:45 +08:00
zhuangpeng.li
8939c78e37 fix(规则脚本增加日志): 规则脚本增加日志 2025-04-15 16:07:23 +08:00
zhuangpeng.li
19fedbe841 fix(规则脚本增加日志): 规则脚本增加日志 2025-04-15 15:42:19 +08:00
kerwincui
1805c99f4f 日志报错信息处理 2025-04-15 15:37:08 +08:00
kerwincui
56577f4262 规则脚本增加日志 2025-04-15 15:34:04 +08:00
kerwincui
12dc1e869e 说明简化 2025-04-01 16:31:52 +08:00
kerwincui
7f5d432f5a 更新图片 2025-04-01 16:23:42 +08:00
kerwincui
d979c9025a 认证信息界面和接口调整 2025-04-01 12:00:21 +08:00
随遇而安
f71cbff3d7 update springboot/fastbee-admin/src/main/resources/application-prod.yml.
Signed-off-by: 随遇而安 <164770707@qq.com>
2025-03-31 09:38:58 +00:00
随遇而安
645fca0119 update springboot/fastbee-admin/src/main/resources/application-dev.yml.
Signed-off-by: 随遇而安 <164770707@qq.com>
2025-03-31 09:37:45 +00:00
kerwincui
4065392ccc 简化后端配置 2025-03-31 17:36:44 +08:00
kerwincui
bc8b5796d2 sql更新 2025-03-26 17:55:56 +08:00
kerwincui
18568aa663 增加定时更新设备状态任务 2025-03-26 17:50:29 +08:00
kerwincui
38e236a8ff 修复前端打包警告信息 2025-03-26 11:19:22 +08:00
kerwincui
8099d7bdcc 接口添加说明 2025-03-24 15:50:44 +08:00
kerwincui
a5a88ae379 脚本更新 2025-03-20 22:32:42 +08:00
kerwincui
462da2a6ce 删除多余文件,添加引用的js文件 2025-03-20 22:28:07 +08:00
kerwincui
f7e9e403b0 界面简化 2025-03-20 22:27:27 +08:00
kerwincui
2772c49df1 设备详情调整,其中tab-panel直接添加key属性解决key重复问题 2025-03-20 22:02:59 +08:00
kerwincui
1afceda43c sql数据简化 2025-03-19 16:31:08 +08:00
kerwincui
4920d84516 物模型和产品操作优化 2025-03-19 16:27:17 +08:00
kerwincui
14ad72b6fa Merge branch 'dev'
# Conflicts:
#	docker/data/mysql/initdb/fastbee2.1.sql
2024-12-17 22:05:18 +08:00
kerwincui
59f4185d2b sql脚本中注释bug修复 2024-12-17 22:04:50 +08:00
kerwincui
59c83b1601 Merge branch 'dev' 2024-12-13 10:44:49 +08:00
随遇而安
e8c192dbd4 update README.md.
Signed-off-by: 随遇而安 <164770707@qq.com>
2024-12-13 02:37:03 +00:00
gx_ma
1424423769 Merge remote-tracking branch 'origin/master' 2024-12-10 15:07:32 +08:00
gx_ma
0615f005b7 fix(初始化脚本): sql修改 2024-12-10 15:06:02 +08:00
随遇而安
c2a7aafcd4 !45 fix:解决设备运行状态无法显示问题https://gitee.com/beecue/fastbee/issues/IAW9KE
Merge pull request !45 from Ming/master
2024-11-29 03:54:26 +00:00
Ming
d8e07328c7 fix:解决设备运行状态无法显示问题https://gitee.com/beecue/fastbee/issues/ 2024-11-28 05:21:24 +08:00
Ming
5abe95f617 fix:解决设备运行状态无法显示问题https://gitee.com/beecue/fastbee/issues/IAW9KE 2024-11-28 05:12:59 +08:00
随遇而安
c12352ffea update springboot/fastbee-admin/src/main/resources/application-dev.yml.
Signed-off-by: 随遇而安 <164770707@qq.com>
2024-11-11 07:30:48 +00:00
随遇而安
5715a15d46 update springboot/fastbee-admin/src/main/resources/application.yml.
Signed-off-by: 随遇而安 <164770707@qq.com>
2024-11-11 07:29:51 +00:00
Zhu
92b504d78a Merge branch 'master' into dev 2024-11-06 12:02:04 +08:00
Zhu
c8a9fd0a99 fix(运行状态):实时更新问题修复 2024-11-06 12:00:55 +08:00
随遇而安
4af4f250eb update README.md.
Signed-off-by: 随遇而安 <164770707@qq.com>
2024-10-28 07:20:28 +00:00
随遇而安
6d50802b60 update vue/README.md.
Signed-off-by: 随遇而安 <164770707@qq.com>
2024-09-26 03:06:15 +00:00
gx_ma
87cb9f2ba1 1.开源app已经上线,代码删除对应安装包 2024-08-19 16:26:20 +08:00
gx_ma
2f481c1b13 1.sql脚本运行报错修改 2024-08-19 15:17:09 +08:00
gx_ma
cfebb8753f Merge branch 'dev' 2024-08-14 16:32:43 +08:00
gx_ma
a7f60c902a !44 修复验证码关闭的bug
Merge pull request !44 from 像风一样/N/A
2024-08-14 08:29:48 +00:00
像风一样
aab9710423 修复验证码关闭的bug
后台配置了取消验证,但实际没有取消

Signed-off-by: 像风一样 <963565242@qq.com>
2024-08-14 07:59:03 +00:00
zhuangpeng.li
a56ab82a94 1.播放器版本更新 2024-08-09 15:46:03 +08:00
404 changed files with 42832 additions and 5968 deletions

View File

@@ -1,4 +1,4 @@
![](https://oscimg.oschina.net/oscnet/up-09e0fd4e7966a3049aa39e7ab2a99dc5586.png) ![](./images/banner.jpg)
### 一、项目介绍 ### 一、项目介绍
@@ -9,38 +9,21 @@
### 二、系统功能 ### 二、系统功能
| 系统功能 | 功能说明 | 开源版本 | 商业版本 | | 系统功能 | 功能说明 |
|:------------------------:|:-----------------------------------------------:|------|--------------| |:------------------------:|:-----------------------------------------------:|
| 产品管理 | 产品详情、产品物模型、产品分类、设备授权、产品固件 | 支持 | 支持 | | 产品管理 | 产品详情、产品物模型、产品分类、设备授权、产品固件 |
| 设备管理 | 设备详情、设备分组、设备日志、设备分享、设备实时控制、实时状态、数据监测 | 支持 | 支持 | | 设备管理 | 设备详情、设备分组、设备日志、设备分享、设备实时控制、实时状态、数据监测 |
| 物模型管理 | 属性(设备状态和监测数据),功能(执行特定任务),事件(设备主动上报给云端) | 支持 | 支持 | | 物模型管理 | 属性(设备状态和监测数据),功能(执行特定任务),事件(设备主动上报给云端) |
| MQTT接入 | emqx开源版、netty版本MqttBroker | 支持 | 支持 | | MQTT接入 | emqx开源版、netty版本MqttBroker |
| 硬件 SDK | ESP-IDF、Arduino、RaspberryPi、合宙等平台设备接入 | 支持 | 支持 | | 硬件 SDK | ESP-IDF、Arduino、RaspberryPi、合宙等平台设备接入 |
| 视频监控接入 | 基于GB/T28181协议支持主流厂商监控设备接入直播、设备录制回放、 云端录像和云台控制 | 支持设备接入和直播 | 支持 | | 视频监控接入 | 基于GB/T28181协议支持主流厂商监控设备接入直播 |
| 多协议管理 | 硬件设备多种协议支持管理 | 支持JSON | 支持多种 | | 权限管理 | 基于若依的权限管理系统,用户、部分、角色、岗位、权限、日志等 |
| TCP接入 | 基于Netty搭建的TCP服务器 | 不支持 | 支持 |
| Modbus接入 | 透传Modbus/边缘网关接入Modbus设备 | 不支持 | 支持 |
| 采集点管理 | 网关设备管理子设备接入 | 不支持 | 支持 |
| 设备模拟器调试 | Modbus设备在线调试 | 不支持 | 支持 |
| 数据大屏 | 数据大屏可视化将图表或页面元素封装为基础组件0代码即可完成业务需求。 | 不支持 | 支持 |
| 规则引擎-规则脚本 | 可视化规则引擎编写支持js,java等脚本修改消息结构处理设备上行/下行/上线/下线/数据解析/数据转换 | 不支持 | 支持 |
| 场景联动 | 基于规则引擎生成场景联动 | 不支持 | 支持 |
| 告警功能 | 告警: 设备告警/平台告警判定 告警配置: 基于规则引擎开发的平台告警判定 告警记录:设备告警记录入库 | 不支持 | 支持 |
| 消息通知功能 | 阿里云短信/腾讯云短信阿里云语言/腾讯云语音/QQ邮箱/163邮箱/微信小程序/企业微信群机器人/企业微信应用信息/钉钉消息通知/钉钉群机器人 | 不支持 | 支持 |
| 多租户 | 系统内租户的管理,独占一套系统配置,数据相互隔离。如:租户权限、过期时间、用户数量、企业信息等 | 不支持 | 支持 |
| 移动端app | 移动端(安卓 / 苹果 / 微信小程序) | 不支持 | 支持 |
| 智能音响对接 | 云云对接:智能音响(小度、天猫精灵、小爱同学) | 不支持 | 额外付费模块 |
| web组态 | 自定义数据大屏/2D/3D | 不支持 | 额外付费模块 |
| 第三方OpenAPT接入 | 萤石云海康sdk接入、AI SDK接入 | 不支持 | 额外付费模块 |
| 数据存储 | 设备数据处理 | redis存储最后一条数据不支持实时更新 | redis存储最新数据,实时更新/mysql存储系统数据/TDengine时序数据库存储设备数据 |
| 设备接入数/上行数据并发支持 | 设备接入数,以及设备数据并发量 | 支持小规模设备接入,同步处理数据 | 支持规模量大设备。消息队列削峰,线程池异步处理高并发数据 |
| 技术支持 | | 不支持 | 提供一定的技术支持/技术方案 |
![](https://oscimg.oschina.net/oscnet/up-a9a7fdaf40208becd26c2485783bc0f86e6.png) ![](https://oscimg.oschina.net/oscnet/up-a9a7fdaf40208becd26c2485783bc0f86e6.png)
|[空气检测仪](https://fastbee.cn/doc/pages/hardware/) | [物联网开发板](https://fastbee.cn/doc/pages/hardware/) | [Air724开发板](https://fastbee.cn/doc/pages/hardware/) | [智能开关](https://fastbee.cn/doc/pages/hardware/) | [查看更多>>](https://fastbee.cn/doc/pages/hardware/) | |空气检测仪| 物联网开发板 | Air724开发板 | 智能开关| [查看更多>>](https://fastbee.cn/doc/device/) |
| :----: | :----------: |:----------: |:----------: |:----------: | | :----: | :----------: |:----------: |:----------: |:----------: |
| ![](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) | | ![](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) |
@@ -81,7 +64,7 @@
- [功能规划>>](./RoadMap.md) - [功能规划>>](./RoadMap.md)
### 七、其他 ### 七、其他
1. QQ交流群&#x1F680;946029159 &#x1F680;1073236354(已满) 1. QQ交流群&#x1F680;946029159(已满) &#x1F680;1073236354 &#x1F680;720136372
2. 权限管理基于ruoyi-vue系统开发Mqtt消息服务器使用EMQX5.0开源版 2. 权限管理基于ruoyi-vue系统开发Mqtt消息服务器使用EMQX5.0开源版

View File

@@ -1,47 +0,0 @@
<br />
* 项目可用于个人学习;商业使用请赞助该项目,获得授权;
* 赞助后还提供了小程序、APP源码。[详情](https://wumei.live/doc/pages/sponsor/)
#### 移动端介绍
|安卓/Android|苹果/IOS|微信小程序| 网页/H5|Vue2.0
| :---: | :---: | :---: | :---: |:---: |
| √ | √| √ | √ | √ |
1. 项目使用uniapp开发适配小程序、安卓、苹果和H5其他平台未测试。
2. UI框架使用uView2.0
3. 组件使用easycom模式只要组件安装在项目的components目录下或uni_modules目录下并符合components/组件名称/组件名称.vue目录结构。就可以不用引用、注册直接在页面中使用。
4. 开发工具为Hbuilder3.3版本,版本不易过低。
###### 项目结构
```
├─apis // 接口管理
│ ├─modules // api模块化目录
│ │ └─device.js // 设备接口地址
│ ├─http.api.js // 接口定义文件
│ └─http.interceptor // 拦截器
├─common // 公共文件
│ ├─config // 环境配置 (设置baseurl等)
│ ├─extend // 扩展原型方法
│ ├─filters // 全局过滤器
│ └─tools // 全局公共方法
├─components // 项目组件库,组件放置这里,其他页面可直接使用
│ ├─cl-test // easycom测试组件
│ └─cl-icon // iconfont图标组件
├─pages // 页面目录
│ ├─public // 公共页面
│ └─tarbar // 底部导航栏页面
├─static // 图片目录
├─store // vuex
│ ├─$u.mixin // store全局混入方法
│ └─index // vuex 组件全局状态管理
├─uni_modules // 插件市场插件目录
│ └─uview-ui // uview-ui
```
<br /><br />

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

BIN
images/banner.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>fastbee</artifactId> <artifactId>fastbee</artifactId>
<groupId>com.fastbee</groupId> <groupId>com.fastbee</groupId>
<version>3.8.5</version> <version>${fastbee.version}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>
@@ -34,13 +34,14 @@
<dependency> <dependency>
<groupId>io.swagger</groupId> <groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId> <artifactId>swagger-models</artifactId>
<version>1.6.2</version> <version>${io.swagger.version}</version>
</dependency> </dependency>
<!-- Mysql驱动包 --> <!-- Mysql驱动包 -->
<dependency> <dependency>
<groupId>mysql</groupId> <groupId>com.mysql</groupId>
<artifactId>mysql-connector-java</artifactId> <artifactId>mysql-connector-j</artifactId>
<version>${mysql.version}</version>
</dependency> </dependency>
<!-- 核心模块--> <!-- 核心模块-->
@@ -84,7 +85,7 @@
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.1.RELEASE</version> <version>2.5.15</version>
<configuration> <configuration>
<fork>true</fork> <!-- 如果没有该配置devtools不会生效 --> <fork>true</fork> <!-- 如果没有该配置devtools不会生效 -->
</configuration> </configuration>

View File

@@ -1,15 +1,15 @@
package com.fastbee; package com.fastbee;
import com.dtflys.forest.springboot.annotation.ForestScan;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/** /**
* 启动程序 * 启动程序
* *
* @author ruoyi * @author ruoyi
*/ */
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) @SpringBootApplication
public class FastBeeApplication public class FastBeeApplication
{ {
public static void main(String[] args) public static void main(String[] args)

View File

@@ -3,9 +3,9 @@ package com.fastbee.web.controller.common;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.annotation.Resource; import jakarta.annotation.Resource;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;

View File

@@ -2,8 +2,8 @@ package com.fastbee.web.controller.common;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;

View File

@@ -7,6 +7,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.TreeSet;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
@@ -87,7 +88,7 @@ public class CacheController
public AjaxResult getCacheKeys(@PathVariable String cacheName) public AjaxResult getCacheKeys(@PathVariable String cacheName)
{ {
Set<String> cacheKeys = redisTemplate.keys(cacheName + "*"); Set<String> cacheKeys = redisTemplate.keys(cacheName + "*");
return AjaxResult.success(cacheKeys); return AjaxResult.success(new TreeSet<>(cacheKeys));
} }
@ApiOperation("缓存内容") @ApiOperation("缓存内容")

View File

@@ -1,7 +1,7 @@
package com.fastbee.web.controller.monitor; package com.fastbee.web.controller.monitor;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;

View File

@@ -1,7 +1,7 @@
package com.fastbee.web.controller.monitor; package com.fastbee.web.controller.monitor;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;

View File

@@ -54,24 +54,15 @@ public class SysUserOnlineController extends BaseController
LoginUser user = redisCache.getCacheObject(key); LoginUser user = redisCache.getCacheObject(key);
if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) 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));
{
userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
}
} }
else if (StringUtils.isNotEmpty(ipaddr)) else if (StringUtils.isNotEmpty(ipaddr))
{ {
if (StringUtils.equals(ipaddr, user.getIpaddr())) userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
{
userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
}
} }
else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser())) else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
{ {
if (StringUtils.equals(userName, user.getUsername())) userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
{
userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
}
} }
else else
{ {

View File

@@ -1,7 +1,7 @@
package com.fastbee.web.controller.system; package com.fastbee.web.controller.system;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
@@ -93,7 +93,7 @@ public class SysConfigController extends BaseController
@PostMapping @PostMapping
public AjaxResult add(@Validated @RequestBody SysConfig config) public AjaxResult add(@Validated @RequestBody SysConfig config)
{ {
if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) if (!configService.checkConfigKeyUnique(config))
{ {
return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在"); return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
} }
@@ -110,7 +110,7 @@ public class SysConfigController extends BaseController
@PutMapping @PutMapping
public AjaxResult edit(@Validated @RequestBody SysConfig config) public AjaxResult edit(@Validated @RequestBody SysConfig config)
{ {
if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) if (!configService.checkConfigKeyUnique(config))
{ {
return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在"); return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
} }

View File

@@ -84,7 +84,7 @@ public class SysDeptController extends BaseController
@PostMapping @PostMapping
public AjaxResult add(@Validated @RequestBody SysDept dept) public AjaxResult add(@Validated @RequestBody SysDept dept)
{ {
if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) if (!deptService.checkDeptNameUnique(dept))
{ {
return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在"); return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
} }
@@ -103,7 +103,7 @@ public class SysDeptController extends BaseController
{ {
Long deptId = dept.getDeptId(); Long deptId = dept.getDeptId();
deptService.checkDeptDataScope(deptId); deptService.checkDeptDataScope(deptId);
if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) if (!deptService.checkDeptNameUnique(dept))
{ {
return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
} }

View File

@@ -2,7 +2,7 @@ package com.fastbee.web.controller.system;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;

View File

@@ -1,7 +1,7 @@
package com.fastbee.web.controller.system; package com.fastbee.web.controller.system;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
@@ -80,7 +80,7 @@ public class SysDictTypeController extends BaseController
@PostMapping @PostMapping
public AjaxResult add(@Validated @RequestBody SysDictType dict) public AjaxResult add(@Validated @RequestBody SysDictType dict)
{ {
if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict))) if (!dictTypeService.checkDictTypeUnique(dict))
{ {
return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在"); return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
} }
@@ -97,7 +97,7 @@ public class SysDictTypeController extends BaseController
@PutMapping @PutMapping
public AjaxResult edit(@Validated @RequestBody SysDictType dict) public AjaxResult edit(@Validated @RequestBody SysDictType dict)
{ {
if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict))) if (!dictTypeService.checkDictTypeUnique(dict))
{ {
return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
} }

View File

@@ -1,32 +1,30 @@
package com.fastbee.web.controller.system; 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.constant.Constants;
import com.fastbee.common.core.domain.AjaxResult; import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.domain.entity.SysMenu; import com.fastbee.common.core.domain.entity.SysMenu;
import com.fastbee.common.core.domain.entity.SysUser; import com.fastbee.common.core.domain.entity.SysUser;
import com.fastbee.common.core.domain.model.LoginBody; import com.fastbee.common.core.domain.model.LoginBody;
import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.utils.SecurityUtils; import com.fastbee.common.utils.SecurityUtils;
import com.fastbee.framework.web.service.SysLoginService; import com.fastbee.framework.web.service.SysLoginService;
import com.fastbee.framework.web.service.SysPermissionService; import com.fastbee.framework.web.service.SysPermissionService;
import com.fastbee.framework.web.service.TokenService;
import com.fastbee.system.service.ISysMenuService; import com.fastbee.system.service.ISysMenuService;
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.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Set;
/** /**
* 登录验证 * 登录验证
* *
* @author ruoyi * @author ruoyi
*/ */
@Api(tags = "登录验证")
@RestController @RestController
public class SysLoginController public class SysLoginController
{ {
@@ -38,8 +36,9 @@ public class SysLoginController
@Autowired @Autowired
private SysPermissionService permissionService; private SysPermissionService permissionService;
@Value("${server.broker.enabled}")
private Boolean enabled; @Autowired
private TokenService tokenService;
/** /**
* 登录方法 * 登录方法
@@ -47,7 +46,6 @@ public class SysLoginController
* @param loginBody 登录信息 * @param loginBody 登录信息
* @return 结果 * @return 结果
*/ */
@ApiOperation("用户登录")
@PostMapping("/login") @PostMapping("/login")
public AjaxResult login(@RequestBody LoginBody loginBody) public AjaxResult login(@RequestBody LoginBody loginBody)
{ {
@@ -64,20 +62,24 @@ public class SysLoginController
* *
* @return 用户信息 * @return 用户信息
*/ */
@ApiOperation("获取用户信息")
@GetMapping("getInfo") @GetMapping("getInfo")
public AjaxResult getInfo() public AjaxResult getInfo()
{ {
SysUser user = SecurityUtils.getLoginUser().getUser(); LoginUser loginUser = SecurityUtils.getLoginUser();
SysUser user = loginUser.getUser();
// 角色集合 // 角色集合
Set<String> roles = permissionService.getRolePermission(user); Set<String> roles = permissionService.getRolePermission(user);
// 权限集合 // 权限集合
Set<String> permissions = permissionService.getMenuPermission(user); Set<String> permissions = permissionService.getMenuPermission(user);
if (!loginUser.getPermissions().equals(permissions))
{
loginUser.setPermissions(permissions);
tokenService.refreshToken(loginUser);
}
AjaxResult ajax = AjaxResult.success(); AjaxResult ajax = AjaxResult.success();
ajax.put("user", user); ajax.put("user", user);
ajax.put("roles", roles); ajax.put("roles", roles);
ajax.put("permissions", permissions); ajax.put("permissions", permissions);
ajax.put("mqtt",enabled);
return ajax; return ajax;
} }
@@ -86,7 +88,6 @@ public class SysLoginController
* *
* @return 路由信息 * @return 路由信息
*/ */
@ApiOperation("获取路由信息")
@GetMapping("getRouters") @GetMapping("getRouters")
public AjaxResult getRouters() public AjaxResult getRouters()
{ {

View File

@@ -94,7 +94,7 @@ public class SysMenuController extends BaseController
@PostMapping @PostMapping
public AjaxResult add(@Validated @RequestBody SysMenu menu) public AjaxResult add(@Validated @RequestBody SysMenu menu)
{ {
if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) if (!menuService.checkMenuNameUnique(menu))
{ {
return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
} }
@@ -115,7 +115,7 @@ public class SysMenuController extends BaseController
@PutMapping @PutMapping
public AjaxResult edit(@Validated @RequestBody SysMenu menu) public AjaxResult edit(@Validated @RequestBody SysMenu menu)
{ {
if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) if (!menuService.checkMenuNameUnique(menu))
{ {
return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
} }

View File

@@ -1,7 +1,7 @@
package com.fastbee.web.controller.system; package com.fastbee.web.controller.system;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
@@ -83,11 +83,11 @@ public class SysPostController extends BaseController
@PostMapping @PostMapping
public AjaxResult add(@Validated @RequestBody SysPost post) public AjaxResult add(@Validated @RequestBody SysPost post)
{ {
if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post))) if (!postService.checkPostNameUnique(post))
{ {
return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在"); return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
} }
else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post))) else if (!postService.checkPostCodeUnique(post))
{ {
return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在"); return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在");
} }
@@ -104,11 +104,11 @@ public class SysPostController extends BaseController
@PutMapping @PutMapping
public AjaxResult edit(@Validated @RequestBody SysPost post) public AjaxResult edit(@Validated @RequestBody SysPost post)
{ {
if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post))) if (!postService.checkPostNameUnique(post))
{ {
return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在"); return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
} }
else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post))) else if (!postService.checkPostCodeUnique(post))
{ {
return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在"); return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
} }

View File

@@ -30,6 +30,7 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 个人信息 业务处理 * 个人信息 业务处理
@@ -78,29 +79,22 @@ public class SysProfileController extends BaseController
public AjaxResult updateProfile(@RequestBody SysUser user) public AjaxResult updateProfile(@RequestBody SysUser user)
{ {
LoginUser loginUser = getLoginUser(); LoginUser loginUser = getLoginUser();
SysUser sysUser = loginUser.getUser(); SysUser currentUser = loginUser.getUser();
user.setUserName(sysUser.getUserName()); currentUser.setNickName(user.getNickName());
if (StringUtils.isNotEmpty(user.getPhonenumber()) currentUser.setEmail(user.getEmail());
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) currentUser.setPhonenumber(user.getPhonenumber());
currentUser.setSex(user.getSex());
if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser))
{ {
return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
} }
if (StringUtils.isNotEmpty(user.getEmail()) if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser))
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
{ {
return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); return error("修改用户'" + loginUser.getUsername() + "'失败,邮箱账号已存在");
} }
user.setUserId(sysUser.getUserId()); if (userService.updateUserProfile(currentUser) > 0)
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); tokenService.setLoginUser(loginUser);
return success(); return success();
} }
@@ -113,8 +107,10 @@ public class SysProfileController extends BaseController
@ApiOperation("重置密码") @ApiOperation("重置密码")
@Log(title = "个人信息", businessType = BusinessType.UPDATE) @Log(title = "个人信息", businessType = BusinessType.UPDATE)
@PutMapping("/updatePwd") @PutMapping("/updatePwd")
public AjaxResult updatePwd(String oldPassword, String newPassword) public AjaxResult updatePwd(@RequestBody Map<String, String> params)
{ {
String oldPassword = params.get("oldPassword");
String newPassword = params.get("newPassword");
LoginUser loginUser = getLoginUser(); LoginUser loginUser = getLoginUser();
String userName = loginUser.getUsername(); String userName = loginUser.getUsername();
String password = loginUser.getPassword(); String password = loginUser.getPassword();
@@ -126,10 +122,11 @@ public class SysProfileController extends BaseController
{ {
return error("新密码不能与旧密码相同"); return error("新密码不能与旧密码相同");
} }
if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0) newPassword = SecurityUtils.encryptPassword(newPassword);
if (userService.resetUserPwd(userName, newPassword) > 0)
{ {
// 更新缓存用户密码 // 更新缓存用户密码
loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword)); loginUser.getUser().setPassword(newPassword);
tokenService.setLoginUser(loginUser); tokenService.setLoginUser(loginUser);
return success(); return success();
} }

View File

@@ -1,7 +1,7 @@
package com.fastbee.web.controller.system; package com.fastbee.web.controller.system;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
@@ -102,11 +102,11 @@ public class SysRoleController extends BaseController
@PostMapping @PostMapping
public AjaxResult add(@Validated @RequestBody SysRole role) public AjaxResult add(@Validated @RequestBody SysRole role)
{ {
if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role))) if (!roleService.checkRoleNameUnique(role))
{ {
return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在"); return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
} }
else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role))) else if (!roleService.checkRoleKeyUnique(role))
{ {
return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
} }
@@ -126,11 +126,11 @@ public class SysRoleController extends BaseController
{ {
roleService.checkRoleAllowed(role); roleService.checkRoleAllowed(role);
roleService.checkRoleDataScope(role.getRoleId()); roleService.checkRoleDataScope(role.getRoleId());
if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role))) if (!roleService.checkRoleNameUnique(role))
{ {
return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在"); return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
} }
else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role))) else if (!roleService.checkRoleKeyUnique(role))
{ {
return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
} }
@@ -142,8 +142,8 @@ public class SysRoleController extends BaseController
LoginUser loginUser = getLoginUser(); LoginUser loginUser = getLoginUser();
if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin()) if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin())
{ {
loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName())); loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName()));
loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
tokenService.setLoginUser(loginUser); tokenService.setLoginUser(loginUser);
} }
return success(); return success();

View File

@@ -1,26 +1,6 @@
package com.fastbee.web.controller.system; 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.annotation.Log;
import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.controller.BaseController; import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.AjaxResult; import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.domain.entity.SysDept; import com.fastbee.common.core.domain.entity.SysDept;
@@ -35,13 +15,22 @@ import com.fastbee.system.service.ISysDeptService;
import com.fastbee.system.service.ISysPostService; import com.fastbee.system.service.ISysPostService;
import com.fastbee.system.service.ISysRoleService; import com.fastbee.system.service.ISysRoleService;
import com.fastbee.system.service.ISysUserService; import com.fastbee.system.service.ISysUserService;
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.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.stream.Collectors;
/** /**
* 用户信息 * 用户信息
* *
* @author ruoyi * @author ruoyi
*/ */
@Api(tags = "用户管理")
@RestController @RestController
@RequestMapping("/system/user") @RequestMapping("/system/user")
public class SysUserController extends BaseController public class SysUserController extends BaseController
@@ -61,7 +50,6 @@ public class SysUserController extends BaseController
/** /**
* 获取用户列表 * 获取用户列表
*/ */
@ApiOperation("获取用户分页列表")
@PreAuthorize("@ss.hasPermi('system:user:list')") @PreAuthorize("@ss.hasPermi('system:user:list')")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(SysUser user) public TableDataInfo list(SysUser user)
@@ -71,7 +59,6 @@ public class SysUserController extends BaseController
return getDataTable(list); return getDataTable(list);
} }
@ApiOperation("导出用户列表")
@Log(title = "用户管理", businessType = BusinessType.EXPORT) @Log(title = "用户管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:user:export')") @PreAuthorize("@ss.hasPermi('system:user:export')")
@PostMapping("/export") @PostMapping("/export")
@@ -82,7 +69,6 @@ public class SysUserController extends BaseController
util.exportExcel(response, list, "用户数据"); util.exportExcel(response, list, "用户数据");
} }
@ApiOperation("批量导入用户")
@Log(title = "用户管理", businessType = BusinessType.IMPORT) @Log(title = "用户管理", businessType = BusinessType.IMPORT)
@PreAuthorize("@ss.hasPermi('system:user:import')") @PreAuthorize("@ss.hasPermi('system:user:import')")
@PostMapping("/importData") @PostMapping("/importData")
@@ -95,8 +81,6 @@ public class SysUserController extends BaseController
return success(message); return success(message);
} }
@ApiOperation("下载用户导入模板")
@PostMapping("/importTemplate") @PostMapping("/importTemplate")
public void importTemplate(HttpServletResponse response) public void importTemplate(HttpServletResponse response)
{ {
@@ -107,46 +91,44 @@ public class SysUserController extends BaseController
/** /**
* 根据用户编号获取详细信息 * 根据用户编号获取详细信息
*/ */
@ApiOperation("根据用户编号获取详细信息")
@PreAuthorize("@ss.hasPermi('system:user:query')") @PreAuthorize("@ss.hasPermi('system:user:query')")
@GetMapping(value = { "/", "/{userId}" }) @GetMapping(value = { "/", "/{userId}" })
public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId) public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
{ {
userService.checkUserDataScope(userId);
AjaxResult ajax = AjaxResult.success(); 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)) if (StringUtils.isNotNull(userId))
{ {
userService.checkUserDataScope(userId);
SysUser sysUser = userService.selectUserById(userId); SysUser sysUser = userService.selectUserById(userId);
ajax.put(AjaxResult.DATA_TAG, sysUser); ajax.put(AjaxResult.DATA_TAG, sysUser);
ajax.put("postIds", postService.selectPostListByUserId(userId)); ajax.put("postIds", postService.selectPostListByUserId(userId));
ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList())); ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
} }
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());
return ajax; return ajax;
} }
/** /**
* 新增用户 * 新增用户
*/ */
@ApiOperation("新增用户")
@PreAuthorize("@ss.hasPermi('system:user:add')") @PreAuthorize("@ss.hasPermi('system:user:add')")
@Log(title = "用户管理", businessType = BusinessType.INSERT) @Log(title = "用户管理", businessType = BusinessType.INSERT)
@PostMapping @PostMapping
public AjaxResult add(@Validated @RequestBody SysUser user) public AjaxResult add(@Validated @RequestBody SysUser user)
{ {
if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user))) deptService.checkDeptDataScope(user.getDeptId());
roleService.checkRoleDataScope(user.getRoleIds());
if (!userService.checkUserNameUnique(user))
{ {
return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在"); return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
} }
else if (StringUtils.isNotEmpty(user.getPhonenumber()) else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
{ {
return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在"); return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
} }
else if (StringUtils.isNotEmpty(user.getEmail()) else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
{ {
return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在"); return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
} }
@@ -158,7 +140,6 @@ public class SysUserController extends BaseController
/** /**
* 修改用户 * 修改用户
*/ */
@ApiOperation("修改用户")
@PreAuthorize("@ss.hasPermi('system:user:edit')") @PreAuthorize("@ss.hasPermi('system:user:edit')")
@Log(title = "用户管理", businessType = BusinessType.UPDATE) @Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PutMapping @PutMapping
@@ -166,17 +147,17 @@ public class SysUserController extends BaseController
{ {
userService.checkUserAllowed(user); userService.checkUserAllowed(user);
userService.checkUserDataScope(user.getUserId()); userService.checkUserDataScope(user.getUserId());
if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user))) deptService.checkDeptDataScope(user.getDeptId());
roleService.checkRoleDataScope(user.getRoleIds());
if (!userService.checkUserNameUnique(user))
{ {
return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在"); return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
} }
else if (StringUtils.isNotEmpty(user.getPhonenumber()) else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
{ {
return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
} }
else if (StringUtils.isNotEmpty(user.getEmail()) else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
{ {
return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
} }
@@ -187,7 +168,6 @@ public class SysUserController extends BaseController
/** /**
* 删除用户 * 删除用户
*/ */
@ApiOperation("删除用户")
@PreAuthorize("@ss.hasPermi('system:user:remove')") @PreAuthorize("@ss.hasPermi('system:user:remove')")
@Log(title = "用户管理", businessType = BusinessType.DELETE) @Log(title = "用户管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{userIds}") @DeleteMapping("/{userIds}")
@@ -203,7 +183,6 @@ public class SysUserController extends BaseController
/** /**
* 重置密码 * 重置密码
*/ */
@ApiOperation("重置用户密码")
@PreAuthorize("@ss.hasPermi('system:user:resetPwd')") @PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
@Log(title = "用户管理", businessType = BusinessType.UPDATE) @Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PutMapping("/resetPwd") @PutMapping("/resetPwd")
@@ -219,7 +198,6 @@ public class SysUserController extends BaseController
/** /**
* 状态修改 * 状态修改
*/ */
@ApiOperation("修改用户状态")
@PreAuthorize("@ss.hasPermi('system:user:edit')") @PreAuthorize("@ss.hasPermi('system:user:edit')")
@Log(title = "用户管理", businessType = BusinessType.UPDATE) @Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus") @PutMapping("/changeStatus")
@@ -234,7 +212,6 @@ public class SysUserController extends BaseController
/** /**
* 根据用户编号获取授权角色 * 根据用户编号获取授权角色
*/ */
@ApiOperation("根据用户编号获取授权角色")
@PreAuthorize("@ss.hasPermi('system:user:query')") @PreAuthorize("@ss.hasPermi('system:user:query')")
@GetMapping("/authRole/{userId}") @GetMapping("/authRole/{userId}")
public AjaxResult authRole(@PathVariable("userId") Long userId) public AjaxResult authRole(@PathVariable("userId") Long userId)
@@ -250,13 +227,13 @@ public class SysUserController extends BaseController
/** /**
* 用户授权角色 * 用户授权角色
*/ */
@ApiOperation("为用户授权角色")
@PreAuthorize("@ss.hasPermi('system:user:edit')") @PreAuthorize("@ss.hasPermi('system:user:edit')")
@Log(title = "用户管理", businessType = BusinessType.GRANT) @Log(title = "用户管理", businessType = BusinessType.GRANT)
@PutMapping("/authRole") @PutMapping("/authRole")
public AjaxResult insertAuthRole(Long userId, Long[] roleIds) public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
{ {
userService.checkUserDataScope(userId); userService.checkUserDataScope(userId);
roleService.checkRoleDataScope(roleIds);
userService.insertUserAuth(userId, roleIds); userService.insertUserAuth(userId, roleIds);
return success(); return success();
} }
@@ -264,7 +241,6 @@ public class SysUserController extends BaseController
/** /**
* 获取部门树列表 * 获取部门树列表
*/ */
@ApiOperation("获取部门树列表")
@PreAuthorize("@ss.hasPermi('system:user:list')") @PreAuthorize("@ss.hasPermi('system:user:list')")
@GetMapping("/deptTree") @GetMapping("/deptTree")
public AjaxResult deptTree(SysDept dept) public AjaxResult deptTree(SysDept dept)

View File

@@ -22,7 +22,7 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import javax.annotation.Resource; import jakarta.annotation.Resource;
/** /**
* swagger 用户测试方法 * swagger 用户测试方法

View File

@@ -4,11 +4,12 @@ import com.fastbee.common.annotation.Anonymous;
import com.fastbee.iot.mapper.DeviceMapper; import com.fastbee.iot.mapper.DeviceMapper;
import com.fastbee.iot.model.DeviceRelateAlertLogVO; import com.fastbee.iot.model.DeviceRelateAlertLogVO;
import com.fastbee.iot.service.IDeviceService; import com.fastbee.iot.service.IDeviceService;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import jakarta.annotation.Resource;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -22,6 +23,7 @@ import java.util.stream.Collectors;
* @date 2023-09-13 11:42 * @date 2023-09-13 11:42
*/ */
@Anonymous @Anonymous
@Api("测试方法")
@RestController @RestController
@RequestMapping("/test2") @RequestMapping("/test2")
public class TestController2 { public class TestController2 {

View File

@@ -1,57 +1,51 @@
# 数据源配置 # 数据源配置
spring: spring:
datasource: datasource:
type: com.alibaba.druid.pool.DruidDataSource dynamic:
driverClassName: com.mysql.cj.jdbc.Driver druid:
druid: initial-size: 5
# 主库数据源 min-idle: 10
master: max-wait: 60000
url: jdbc:mysql://localhost/fastbee?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 max-active: 20
username: root timeBetweenEvictionRunsMillis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
password: 123456 minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最小生存的时间,单位是毫秒
# 从库数据源 maxEvictableIdleTimeMillis: 900000 # 配置一个连接在池中最大生存的时间,单位是毫秒
slave: validation-query: 'SELECT 1'
enabled: false # 从数据源开关/默认关闭 testWhileIdle: true
url: testOnBorrow: false
username: testOnReturn: false
password: datasource:
initialSize: 5 # 初始连接数 master:
minIdle: 10 # 最小连接池数量 type: com.alibaba.druid.pool.DruidDataSource
maxActive: 20 # 最大连接池数量 driver-class-name: com.mysql.cj.jdbc.Driver
maxWait: 60000 # 配置获取连接等待超时的时间 url: jdbc:mysql://localhost/fastbee?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
timeBetweenEvictionRunsMillis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 username: root
minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最小生存的时间,单位是毫秒 password: fastbee
maxEvictableIdleTimeMillis: 900000 # 配置一个连接在池中最大生存的时间,单位是毫秒 druid:
validationQuery: SELECT 1 FROM DUAL # 配置检测连接是否有效 filters: stat,wall
testWhileIdle: true stat:
testOnBorrow: false # 慢SQL记录
testOnReturn: false log-slow-sql: true
webStatFilter: slow-sql-millis: 1000
enabled: true merge-sql: true
statViewServlet: wall:
enabled: true none-base-statement-allow: true
# 设置白名单,不填则允许所有访问 # slave:
allow: # type: com.alibaba.druid.pool.DruidDataSource
url-pattern: /druid/* # driver-class-name: com.mysql.cj.jdbc.Driver
# 控制台管理用户名和密码 # url: jdbc:mysql://localhost:3306/fastbee1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
login-username: fastbee # username: root
login-password: fastbee # password: fastbee
filter:
stat:
enabled: true
# 慢SQL记录 # redis 配置
log-slow-sql: true spring.data:
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
# redis 配置
redis: redis:
host: localhost # 地址 host: localhost # 地址
port: 6379 # 端口默认为6379 port: 6379 # 端口默认为6379
database: 1 # 数据库索引 database: 10 # 数据库索引
password: 123456 # 密码 password: fastbee # 密码
timeout: 10s # 连接超时时间 timeout: 10s # 连接超时时间
lettuce: lettuce:
pool: pool:
@@ -59,20 +53,10 @@ spring:
max-idle: 8 # 连接池中的最大空闲连接 max-idle: 8 # 连接池中的最大空闲连接
max-active: 8 # 连接池的最大数据库连接数 max-active: 8 # 连接池的最大数据库连接数
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
# mqtt 配置
mqtt:
username: fastbee # 账号
password: fastbee # 密码
host-url: tcp://localhost:1883 # mqtt连接tcp地址
client-id: ${random.int} # 客户端Id不能相同采用随机数 ${random.value}
default-topic: test # 默认主题
timeout: 30 # 超时时间
keepalive: 30 # 保持连接
clearSession: true # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
# sip 配置 # sip 配置
sip: sip:
enabled: true # 是否启用视频监控SIPtrue为启用 enabled: false # 是否启用视频监控SIPtrue为启用
## 本地调试时绑定网卡局域网IP设备在同一局域网设备接入IP填写绑定IP ## 本地调试时绑定网卡局域网IP设备在同一局域网设备接入IP填写绑定IP
## 部署服务端时默认绑定容器IP设备接入IP填写服务器公网IP ## 部署服务端时默认绑定容器IP设备接入IP填写服务器公网IP
#ip: 177.7.0.13 #ip: 177.7.0.13

View File

@@ -1,53 +1,44 @@
# 数据源配置 # 数据源配置
spring: spring:
datasource: datasource:
type: com.alibaba.druid.pool.DruidDataSource dynamic:
driverClassName: com.mysql.cj.jdbc.Driver druid:
druid: initial-size: 5
# 主库数据源 min-idle: 10
master: max-wait: 60000
url: jdbc:mysql://177.7.0.11/fastbee?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 max-active: 20
username: root timeBetweenEvictionRunsMillis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
password: fastbee minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最小生存的时间,单位是毫秒
# 从库数据源 maxEvictableIdleTimeMillis: 900000 # 配置一个连接在池中最大生存的时间,单位是毫秒
slave: validation-query: 'SELECT 1'
enabled: false # 从数据源开关/默认关闭 testWhileIdle: true
url: testOnBorrow: false
username: testOnReturn: false
password: datasource:
master:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://177.7.0.11/fastbee?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: fastbee
druid:
filters: stat,wall
stat:
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
none-base-statement-allow: true
# slave:
# type: com.alibaba.druid.pool.DruidDataSource
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://localhost:3306/fastbee1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
# username: root
# password: fastbee
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 配置
spring.data:
redis: redis:
host: 177.7.0.10 # 地址 host: 177.7.0.10 # 地址
port: 6379 # 端口默认为6379 port: 6379 # 端口默认为6379
@@ -60,16 +51,6 @@ spring:
max-idle: 8 # 连接池中的最大空闲连接 max-idle: 8 # 连接池中的最大空闲连接
max-active: 8 # 连接池的最大数据库连接数 max-active: 8 # 连接池的最大数据库连接数
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制) 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,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
# sip 配置 # sip 配置
sip: sip:

View File

@@ -0,0 +1,132 @@
# 数据源配置
spring:
datasource:
dynamic:
druid:
initial-size: 5
min-idle: 10
max-wait: 60000
max-active: 20
timeBetweenEvictionRunsMillis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最小生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000 # 配置一个连接在池中最大生存的时间,单位是毫秒
validation-query: 'SELECT 1'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
datasource:
master:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: dm.jdbc.driver.DmDriver
url: jdbc:dm://192.168.5.12:5236/OPENSOURCE&useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: OPENSOURCE
password: fastbee@123
druid:
filters: stat
stat:
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
none-base-statement-allow: true
# sqlServer: # 配置 SQLServer 数据源
# type: com.alibaba.druid.pool.DruidDataSource
# driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
# url: jdbc:sqlserver://localhost:1433;databaseName=fastbee
# username: sa
# password: fastbee@123
# postgres: # 配置 postgres 数据源
# type: com.alibaba.druid.pool.DruidDataSource
# driver-class-name: org.postgresql.Driver
# url: jdbc:postgresql://101.33.237.12:5432/fastbee?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
# username: root
# password: fastbee@123
# dameng: # 配置达梦数据源
# type: com.alibaba.druid.pool.DruidDataSource
# driver-class-name: dm.jdbc.driver.DmDriver
# url: jdbc:dm://192.168.5.28:5236/fastbee&useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
# username: root
# password: fastbee@123
# druid:
# filters: stat
# slave:
# type: com.alibaba.druid.pool.DruidDataSource
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://localhost:3306/fastbee1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
# username: root
# password: fastbee
# slave:
# type: com.alibaba.druid.pool.DruidDataSource
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://localhost:3306/fastbee1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
# username: root
# password: fastbee
# redis 配置
spring.data:
redis:
host: 192.168.5.12 # 地址
port: 6379 # 端口默认为6379
database: 11 # 数据库索引
password: fastbee # 密码
timeout: 10s # 连接超时时间
lettuce:
pool:
min-idle: 0 # 连接池中的最小空闲连接
max-idle: 8 # 连接池中的最大空闲连接
max-active: 8 # 连接池的最大数据库连接数
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
# sip 配置
sip:
enabled: false # 是否启用视频监控SIPtrue为启用
## 本地调试时绑定网卡局域网IP设备在同一局域网设备接入IP填写绑定IP
## 部署服务端时默认绑定容器IP设备接入IP填写服务器公网IP
#ip: 177.7.0.13
ip: 192.168.5.12
port: 5061 # SIP端口(保持默认)
domain: 3402000000 # 由省级、市级、区级、基层编号组成
id: 34020000002000000001 # 同上,另外增加编号,(可保持默认)
password: 12345678 # 监控设备接入的密码
# 日志配置
logging:
level:
com.fastbee: debug
org.springframework: warn
# Swagger配置
swagger:
enabled: true # 是否开启swagger
pathMapping: /dev-api # 请求前缀
liteflow:
rule-source-ext-data-map:
# 应用名称,规则链和脚本组件名称需要一致,不要修改
applicationName: fastbee
#是否开启SQL日志
sqlLogEnabled: true
# 规则多时,启用快速加载模式
fast-load: false
#是否开启SQL数据轮询自动刷新机制 默认不开启
pollingEnabled: false
pollingIntervalSeconds: 60
pollingStartSeconds: 60
#以下是chain表的配置
chainTableName: iot_scene
chainApplicationNameField: application_name
chainNameField: chain_name
elDataField: el_data
chainEnableField: enable
#以下是script表的配置
scriptTableName: iot_script
scriptApplicationNameField: application_name
scriptIdField: script_id
scriptNameField: script_name
scriptDataField: script_data
scriptTypeField: script_type
scriptLanguageField: script_language
scriptEnableField: enable

View File

@@ -1,8 +1,8 @@
# 项目相关配置 # 项目相关配置
fastbee: fastbee:
name: fastbee # 名称 name: fastbee # 名称
version: 3.8.5 # 版本 version: 2.1.0 # 版本
copyrightYear: 2023 # 版权年份 copyrightYear: 2024 # 版权年份
demoEnabled: true # 实例演示开关 demoEnabled: true # 实例演示开关
# 文件路径以uploadPath结尾 示例( Windows配置 D:/uploadPathLinux配置 /uploadPath # 文件路径以uploadPath结尾 示例( Windows配置 D:/uploadPathLinux配置 /uploadPath
profile: /uploadPath profile: /uploadPath
@@ -23,18 +23,23 @@ server:
# 基于netty的服务器 # 基于netty的服务器
broker: broker:
must-pass: false # 客户端连接是否需要密码 must-pass: false # 客户端连接是否需要密码
enabled: true # mqttBroker类型选择, true: 基于netty的mqttBroker和webSocket false: emq的mqttBroker enabled: true # 需要配置为true
broker-node: node1 broker-node: node1
port: 1883 port: 1883
websocket-port: 8083 websocket-port: 8083
websocket-path: /mqtt websocket-path: /mqtt
keep-alive: 70 # 默认的全部客户端心跳上传时间 keep-alive: 30 # 默认的全部客户端心跳上传时间
# Spring配置 # Spring配置
spring: spring:
# 环境配置dev=开发环境prod=生产环境 # 环境配置dev=开发环境prod=生产环境
profiles: profiles:
active: prod # 环境配置dev=开发环境prod=生产环境 active: prod # 环境配置dev=开发环境prod=生产环境
main:
allow-circular-references: true
mvc:
pathmatch:
matching-strategy: ant_path_matcher
# 资源信息 # 资源信息
messages: messages:
# 国际化资源文件路径 # 国际化资源文件路径
@@ -55,6 +60,20 @@ spring:
max-size: 200 # 最大连接数 max-size: 200 # 最大连接数
queue-capacity: 3000 # 最大容量 queue-capacity: 3000 # 最大容量
keep-alive: 60 keep-alive: 60
datasource:
druid:
webStatFilter:
enabled: true
stat-view-servlet:
enabled: true
allow:
url-pattern: /druid/*
loginUsername: fastbee
loginPassword: fastbee
dynamic:
primary: master
strict: false
lazy: true
#集群配置 #集群配置
cluster: cluster:
@@ -76,11 +95,16 @@ token:
# mybatis-plus配置 # mybatis-plus配置
mybatis-plus: mybatis-plus:
typeAliasesPackage: com.fastbee.**.domain # 搜索指定包别名 # 搜索指定包别名
mapperLocations: classpath*:mapper/**/*Mapper.xml # 配置mapper的扫描找到所有的mapper.xml映射文件 typeAliasesPackage: com.fastbee.**.domain
# 配置mapper的扫描找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml
configLocation: classpath:mybatis/mybatis-config.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # 加载全局的配置文件
global-config: global-config:
db-config: dbConfig:
# 主键类型
# AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
# 如需改为自增 需要将数据库表全部设置为自增
id-type: AUTO # 自增 ID id-type: AUTO # 自增 ID
logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
@@ -96,3 +120,8 @@ xss:
enabled: true # 过滤开关 enabled: true # 过滤开关
excludes: /system/notice # 排除链接(多个用逗号分隔) excludes: /system/notice # 排除链接(多个用逗号分隔)
urlPatterns: /system/*,/monitor/*,/tool/* # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* # 匹配链接
forest:
max-connections: 1000 # 连接池最大连接数
connect-timeout: 3000 # 连接超时时间,单位为毫秒
read-timeout: 3000 # 数据读取超时时间,单位为毫秒

View File

@@ -9,6 +9,7 @@ user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分
user.password.delete=对不起,您的账号已被删除 user.password.delete=对不起,您的账号已被删除
user.blocked=用户已封禁,请联系管理员 user.blocked=用户已封禁,请联系管理员
role.blocked=角色已封禁,请联系管理员 role.blocked=角色已封禁,请联系管理员
login.blocked=很遗憾访问IP已被列入系统黑名单
user.logout.success=退出成功 user.logout.success=退出成功
length.not.valid=长度必须在{min}到{max}个字符之间 length.not.valid=长度必须在{min}到{max}个字符之间

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<configuration> <configuration>
<!-- 日志存放路径 --> <!-- 日志存放路径 -->
<property name="log.path" value="/logs" /> <property name="log.path" scope="context" value="D:/logs" />
<!-- 日志输出格式 --> <!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" /> <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
@@ -95,6 +95,24 @@
</encoder> </encoder>
</appender> </appender>
<!-- 规则引擎日志输出 -->
<appender name="script" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/rule/script.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>${log.path}/rule/script.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 3天 -->
<maxHistory>3</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%method,%line] - %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
</appender>
<!-- 系统模块日志级别控制 --> <!-- 系统模块日志级别控制 -->
<logger name="com.fastbee" level="debug" /> <logger name="com.fastbee" level="debug" />
<!-- Spring日志级别控制 --> <!-- Spring日志级别控制 -->
@@ -115,4 +133,10 @@
<logger name="sys-user" level="info"> <logger name="sys-user" level="info">
<appender-ref ref="sys-user"/> <appender-ref ref="sys-user"/>
</logger> </logger>
<!--规则引擎日志-->
<logger name="script" level="info">
<appender-ref ref="script"/>
</logger>
</configuration> </configuration>

View File

@@ -14,7 +14,9 @@ PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
<!-- 指定 MyBatis 所用日志的具体实现 --> <!-- 指定 MyBatis 所用日志的具体实现 -->
<setting name="logImpl" value="SLF4J" /> <setting name="logImpl" value="SLF4J" />
<!-- 使用驼峰命名法转换字段 --> <!-- 使用驼峰命名法转换字段 -->
<!-- <setting name="mapUnderscoreToCamelCase" value="true"/> --> <setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="autoMappingBehavior" value="FULL"/>
<setting name="autoMappingUnknownColumnBehavior" value="NONE"/>
</settings> </settings>
</configuration> </configuration>

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>fastbee</artifactId> <artifactId>fastbee</artifactId>
<groupId>com.fastbee</groupId> <groupId>com.fastbee</groupId>
<version>3.8.5</version> <version>${fastbee.version}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -38,8 +38,9 @@
<!-- mybatis-plus --> <!-- mybatis-plus -->
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId> <artifactId>mybatis-plus-generator</artifactId>
@@ -73,8 +74,7 @@
<!-- 动态数据源 --> <!-- 动态数据源 -->
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId> <artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>3.5.2</version>
</dependency> </dependency>
<!-- 阿里JSON解析器 --> <!-- 阿里JSON解析器 -->
@@ -139,9 +139,10 @@
<!-- servlet包 --> <!-- servlet包 -->
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>jakarta.servlet</groupId>
<artifactId>javax.servlet-api</artifactId> <artifactId>jakarta.servlet-api</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
@@ -150,20 +151,11 @@
<dependency> <dependency>
<groupId>io.swagger</groupId> <groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId> <artifactId>swagger-annotations</artifactId>
<version>1.6.2</version>
<scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.paho</groupId> <groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId> <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>
<dependency> <dependency>
@@ -182,16 +174,16 @@
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
</dependency> </dependency>
<!-- <dependency>-->
<!-- <groupId>org.redisson</groupId>-->
<!-- <artifactId>redisson-spring-boot-starter</artifactId>-->
<!-- </dependency>-->
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>easyexcel-core</artifactId> <artifactId>easyexcel-core</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -56,15 +56,16 @@ public @interface Excel
/** /**
* BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
*/ */
@SuppressWarnings("deprecation")
public int roundingMode() default BigDecimal.ROUND_HALF_EVEN; public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
/** /**
* 导出时在excel中每个列的高度 单位为字符 * 导出时在excel中每个列的高度
*/ */
public double height() default 14; public double height() default 14;
/** /**
* 导出时在excel中每个列的宽 单位为字符 * 导出时在excel中每个列的宽
*/ */
public double width() default 16; public double width() default 16;
@@ -83,11 +84,21 @@ public @interface Excel
*/ */
public String prompt() default ""; public String prompt() default "";
/**
* 是否允许内容换行
*/
public boolean wrapText() default false;
/** /**
* 设置只能选择不能输入的列内容. * 设置只能选择不能输入的列内容.
*/ */
public String[] combo() default {}; public String[] combo() default {};
/**
* 是否从字典读数据到combo,默认不读取,如读取需要设置dictType注解.
*/
public boolean comboReadDict() default false;
/** /**
* 是否需要纵向合并单元格,应对需求:含有list集合单元格) * 是否需要纵向合并单元格,应对需求:含有list集合单元格)
*/ */
@@ -114,7 +125,7 @@ public @interface Excel
public ColumnType cellType() default ColumnType.STRING; public ColumnType cellType() default ColumnType.STRING;
/** /**
* 导出列头背景色 * 导出列头背景
*/ */
public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT; public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
@@ -124,7 +135,7 @@ public @interface Excel
public IndexedColors headerColor() default IndexedColors.WHITE; public IndexedColors headerColor() default IndexedColors.WHITE;
/** /**
* 导出单元格背景色 * 导出单元格背景
*/ */
public IndexedColors backgroundColor() default IndexedColors.WHITE; public IndexedColors backgroundColor() default IndexedColors.WHITE;
@@ -171,7 +182,7 @@ public @interface Excel
public enum ColumnType public enum ColumnType
{ {
NUMERIC(0), STRING(1), IMAGE(2); NUMERIC(0), STRING(1), IMAGE(2), TEXT(3);
private final int value; private final int value;
ColumnType(int value) ColumnType(int value)

View File

@@ -1,13 +1,10 @@
package com.fastbee.common.annotation; 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.BusinessType;
import com.fastbee.common.enums.OperatorType; import com.fastbee.common.enums.OperatorType;
import java.lang.annotation.*;
/** /**
* 自定义操作日志记录注解 * 自定义操作日志记录注解
* *
@@ -43,4 +40,9 @@ public @interface Log
* 是否保存响应的参数 * 是否保存响应的参数
*/ */
public boolean isSaveResponseData() default true; public boolean isSaveResponseData() default true;
/**
* 排除指定的请求参数
*/
public String[] excludeParamNames() default {};
} }

View File

@@ -0,0 +1,24 @@
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 com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fastbee.common.config.serializer.SensitiveJsonSerializer;
import com.fastbee.common.enums.DesensitizedType;
/**
* 数据脱敏注解
*
* @author ruoyi
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveJsonSerializer.class)
public @interface Sensitive
{
DesensitizedType desensitizedType();
}

View File

@@ -0,0 +1,67 @@
package com.fastbee.common.config.serializer;
import java.io.IOException;
import java.util.Objects;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fastbee.common.annotation.Sensitive;
import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.enums.DesensitizedType;
import com.fastbee.common.utils.SecurityUtils;
/**
* 数据脱敏序列化过滤
*
* @author ruoyi
*/
public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer
{
private DesensitizedType desensitizedType;
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException
{
if (desensitization())
{
gen.writeString(desensitizedType.desensitizer().apply(value));
}
else
{
gen.writeString(value);
}
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
throws JsonMappingException
{
Sensitive annotation = property.getAnnotation(Sensitive.class);
if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass()))
{
this.desensitizedType = annotation.desensitizedType();
return this;
}
return prov.findValueSerializer(property.getType(), property);
}
/**
* 是否需要脱敏处理
*/
private boolean desensitization()
{
try
{
LoginUser securityUser = SecurityUtils.getLoginUser();
// 管理员不脱敏
return !securityUser.getUser().isAdmin();
}
catch (Exception e)
{
return true;
}
}
}

View File

@@ -2,6 +2,8 @@ package com.fastbee.common.constant;
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Claims;
import java.util.Locale;
/** /**
* 通用常量信息 * 通用常量信息
* *
@@ -19,6 +21,11 @@ public class Constants
*/ */
public static final String GBK = "GBK"; public static final String GBK = "GBK";
/**
* 系统语言
*/
public static final Locale DEFAULT_LOCALE = Locale.SIMPLIFIED_CHINESE;
/** /**
* www主域 * www主域
*/ */
@@ -64,6 +71,26 @@ public class Constants
*/ */
public static final String LOGIN_FAIL = "Error"; public static final String LOGIN_FAIL = "Error";
/**
* 所有权限标识
*/
public static final String ALL_PERMISSION = "*:*:*";
/**
* 管理员角色权限标识
*/
public static final String SUPER_ADMIN = "admin";
/**
* 角色权限分隔符
*/
public static final String ROLE_DELIMETER = ",";
/**
* 权限标识分隔符
*/
public static final String PERMISSION_DELIMETER = ",";
/** /**
* 验证码有效期(分钟) * 验证码有效期(分钟)
*/ */
@@ -129,14 +156,19 @@ public class Constants
*/ */
public static final String LOOKUP_LDAPS = "ldaps:"; public static final String LOOKUP_LDAPS = "ldaps:";
/**
* 自动识别json对象白名单配置仅允许解析的包名范围越小越安全
*/
public static final String[] JSON_WHITELIST_STR = { "org.springframework", "com.ruoyi" };
/** /**
* 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加) * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
*/ */
public static final String[] JOB_WHITELIST_STR = { "com.fastbee" }; public static final String[] JOB_WHITELIST_STR = { "com.ruoyi.quartz.task" };
/** /**
* 定时任务违规的字符 * 定时任务违规的字符
*/ */
public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml", 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" }; "org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config", "com.ruoyi.generator" };
} }

View File

@@ -21,6 +21,9 @@ public class UserConstants
/** 用户封禁状态 */ /** 用户封禁状态 */
public static final String USER_DISABLE = "1"; public static final String USER_DISABLE = "1";
/** 角色正常状态 */
public static final String ROLE_NORMAL = "0";
/** 角色封禁状态 */ /** 角色封禁状态 */
public static final String ROLE_DISABLE = "1"; public static final String ROLE_DISABLE = "1";
@@ -60,9 +63,9 @@ public class UserConstants
/** InnerLink组件标识 */ /** InnerLink组件标识 */
public final static String INNER_LINK = "InnerLink"; public final static String INNER_LINK = "InnerLink";
/** 校验返回结果码 */ /** 校验是否唯一的返回标识 */
public final static String UNIQUE = "0"; public final static boolean UNIQUE = true;
public final static String NOT_UNIQUE = "1"; public final static boolean NOT_UNIQUE = false;
/** /**
* 用户名长度限制 * 用户名长度限制

View File

@@ -15,12 +15,13 @@ import com.fastbee.common.utils.StringUtils;
import com.fastbee.common.utils.sql.SqlUtil; import com.fastbee.common.utils.sql.SqlUtil;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
import jakarta.annotation.Resource;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.InitBinder;
import javax.annotation.Resource;
import java.beans.PropertyEditorSupport; import java.beans.PropertyEditorSupport;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;

View File

@@ -1,6 +1,7 @@
package com.fastbee.common.core.domain; package com.fastbee.common.core.domain;
import java.util.HashMap; import java.util.HashMap;
import java.util.Objects;
import com.fastbee.common.constant.HttpStatus; import com.fastbee.common.constant.HttpStatus;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
@@ -198,6 +199,36 @@ public class AjaxResult extends HashMap<String, Object>
return new AjaxResult(code, msg, null); return new AjaxResult(code, msg, null);
} }
/**
* 是否为成功消息
*
* @return 结果
*/
public boolean isSuccess()
{
return Objects.equals(HttpStatus.SUCCESS, this.get(CODE_TAG));
}
/**
* 是否为警告消息
*
* @return 结果
*/
public boolean isWarn()
{
return Objects.equals(HttpStatus.WARN, this.get(CODE_TAG));
}
/**
* 是否为错误消息
*
* @return 结果
*/
public boolean isError()
{
return Objects.equals(HttpStatus.ERROR, this.get(CODE_TAG));
}
/** /**
* 方便链式调用 * 方便链式调用
* *

View File

@@ -1,126 +1,175 @@
package com.fastbee.common.core.domain; package com.fastbee.common.core.domain;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModelProperty;
/** /**
* Entity基类 * Entity基类
* *
* @author ruoyi * @author ruoyi
*/ */
public class BaseEntity implements Serializable public class BaseEntity implements Serializable {
{
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** 搜索值 */ /**
* 搜索值
*/
@TableField(exist = false)
@ApiModelProperty("搜索值") @ApiModelProperty("搜索值")
@JsonIgnore @JsonIgnore
private String searchValue; private String searchValue;
/** 创建者 */ /**
* 创建者
*/
@ApiModelProperty("创建者") @ApiModelProperty("创建者")
private String createBy; private String createBy;
/** 创建时间 */ /**
* 创建时间
*/
@ApiModelProperty("创建时间") @ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime; private Date createTime;
/** 更新者 */ /**
* 更新者
*/
@ApiModelProperty("更新者") @ApiModelProperty("更新者")
private String updateBy; private String updateBy;
/** 更新时间 */ /**
* 更新时间
*/
@ApiModelProperty("更新时间") @ApiModelProperty("更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime; private Date updateTime;
/** 备注 */ /**
* 备注
*/
@ApiModelProperty("备注") @ApiModelProperty("备注")
private String remark; private String remark;
/** 请求参数 */ /**
* 当前记录起始索引 默认值
*/
public static final int DEFAULT_PAGE_NUM = 1;
/**
* 每页显示记录数 默认值 默认查全部
*/
public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
/**
* 构建分页对象
*/
public <T> Page<T> buildPage() {
Integer pageNum = ObjectUtil.defaultIfNull(this.pageNum, DEFAULT_PAGE_NUM);
Integer pageSize = ObjectUtil.defaultIfNull(this.pageSize, DEFAULT_PAGE_SIZE);
if (pageNum <= 0) {
pageNum = DEFAULT_PAGE_NUM;
}
Page<T> page = new Page<>(pageNum, pageSize);
return page;
}
public Integer getPageNum() {
return ObjectUtil.defaultIfNull(this.pageNum, DEFAULT_PAGE_NUM);
}
public void setPageNum(Integer pageNum) {
this.pageNum = pageNum;
}
public Integer getPageSize() {
return ObjectUtil.defaultIfNull(this.pageSize, DEFAULT_PAGE_SIZE);
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
@TableField(exist = false)
private Integer pageNum;
@TableField(exist = false)
private Integer pageSize;
/**
* 请求参数
*/
@TableField(exist = false)
@ApiModelProperty("请求参数") @ApiModelProperty("请求参数")
@JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonInclude(JsonInclude.Include.NON_EMPTY)
private Map<String, Object> params; private Map<String, Object> params;
public String getSearchValue() public String getSearchValue() {
{
return searchValue; return searchValue;
} }
public void setSearchValue(String searchValue) public void setSearchValue(String searchValue) {
{
this.searchValue = searchValue; this.searchValue = searchValue;
} }
public String getCreateBy() public String getCreateBy() {
{
return createBy; return createBy;
} }
public void setCreateBy(String createBy) public void setCreateBy(String createBy) {
{
this.createBy = createBy; this.createBy = createBy;
} }
public Date getCreateTime() public Date getCreateTime() {
{
return createTime; return createTime;
} }
public void setCreateTime(Date createTime) public void setCreateTime(Date createTime) {
{
this.createTime = createTime; this.createTime = createTime;
} }
public String getUpdateBy() public String getUpdateBy() {
{
return updateBy; return updateBy;
} }
public void setUpdateBy(String updateBy) public void setUpdateBy(String updateBy) {
{
this.updateBy = updateBy; this.updateBy = updateBy;
} }
public Date getUpdateTime() public Date getUpdateTime() {
{
return updateTime; return updateTime;
} }
public void setUpdateTime(Date updateTime) public void setUpdateTime(Date updateTime) {
{
this.updateTime = updateTime; this.updateTime = updateTime;
} }
public String getRemark() public String getRemark() {
{
return remark; return remark;
} }
public void setRemark(String remark) public void setRemark(String remark) {
{
this.remark = remark; this.remark = remark;
} }
public Map<String, Object> getParams() public Map<String, Object> getParams() {
{ if (params == null) {
if (params == null)
{
params = new HashMap<>(); params = new HashMap<>();
} }
return params; return params;
} }
public void setParams(Map<String, Object> params) public void setParams(Map<String, Object> params) {
{
this.params = params; this.params = params;
} }
} }

View File

@@ -0,0 +1,76 @@
package com.fastbee.common.core.domain;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* @author admin
* @version 1.0
* @description: 分页参数基础类
* @date 2024-11-15 18:00
*/
@Data
public class PageEntity implements Serializable {
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@TableField(exist = false)
private Integer pageNum;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@TableField(exist = false)
private Integer pageSize;
/**
* 当前记录起始索引 默认值
*/
public static final int DEFAULT_PAGE_NUM = 1;
/**
* 每页显示记录数 默认值 默认查全部
*/
public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
/**
* 构建分页对象
*/
public <T> Page<T> buildPage() {
Integer pageNum = ObjectUtil.defaultIfNull(this.pageNum, DEFAULT_PAGE_NUM);
Integer pageSize = ObjectUtil.defaultIfNull(this.pageSize, DEFAULT_PAGE_SIZE);
if (pageNum <= 0) {
pageNum = DEFAULT_PAGE_NUM;
}
Page<T> page = new Page<>(pageNum, pageSize);
return page;
}
/**
* 请求参数
*/
@TableField(exist = false)
@ApiModelProperty("请求参数")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private Map<String, Object> params;
public Map<String, Object> getParams() {
if (params == null) {
params = new HashMap<>();
}
return params;
}
public Integer getPageNum() {
return ObjectUtil.defaultIfNull(this.pageNum, DEFAULT_PAGE_NUM);
}
public Integer getPageSize() {
return ObjectUtil.defaultIfNull(this.pageSize, DEFAULT_PAGE_SIZE);
}
}

View File

@@ -1,10 +1,11 @@
package com.fastbee.common.core.domain; package com.fastbee.common.core.domain;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min; import jakarta.validation.constraints.NotNull;
import javax.validation.constraints.NotNull;
import java.io.Serializable; import java.io.Serializable;
@Data @Data

View File

@@ -4,8 +4,10 @@ import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.domain.entity.SysDept; import com.fastbee.common.core.domain.entity.SysDept;
import com.fastbee.common.core.domain.entity.SysMenu; import com.fastbee.common.core.domain.entity.SysMenu;
import com.fastbee.common.utils.StringUtils;
/** /**
* Treeselect树结构实体类 * Treeselect树结构实体类
@@ -22,6 +24,9 @@ public class TreeSelect implements Serializable
/** 节点名称 */ /** 节点名称 */
private String label; private String label;
/** 节点禁用 */
private boolean disabled = false;
/** 子节点 */ /** 子节点 */
@JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<TreeSelect> children; private List<TreeSelect> children;
@@ -35,6 +40,7 @@ public class TreeSelect implements Serializable
{ {
this.id = dept.getDeptId(); this.id = dept.getDeptId();
this.label = dept.getDeptName(); this.label = dept.getDeptName();
this.disabled = StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus());
this.children = dept.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList()); this.children = dept.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
} }
@@ -65,6 +71,16 @@ public class TreeSelect implements Serializable
this.label = label; this.label = label;
} }
public boolean isDisabled()
{
return disabled;
}
public void setDisabled(boolean disabled)
{
this.disabled = disabled;
}
public List<TreeSelect> getChildren() public List<TreeSelect> getChildren()
{ {
return children; return children;

View File

@@ -2,13 +2,13 @@ package com.fastbee.common.core.domain.entity;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import com.fastbee.common.core.domain.BaseEntity; import com.fastbee.common.core.domain.BaseEntity;

View File

@@ -1,8 +1,7 @@
package com.fastbee.common.core.domain.entity; package com.fastbee.common.core.domain.entity;
import javax.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import javax.validation.constraints.Size; import jakarta.validation.constraints.Size;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;

View File

@@ -1,8 +1,9 @@
package com.fastbee.common.core.domain.entity; package com.fastbee.common.core.domain.entity;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern; import jakarta.validation.constraints.NotBlank;
import javax.validation.constraints.Size; import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;

View File

@@ -2,9 +2,9 @@ package com.fastbee.common.core.domain.entity;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import javax.validation.constraints.Size; import jakarta.validation.constraints.Size;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
@@ -54,6 +54,9 @@ public class SysMenu extends BaseEntity
@ApiModelProperty("路由参数") @ApiModelProperty("路由参数")
private String query; private String query;
/** 路由名称默认和路由地址相同的驼峰格式注意因为vue3版本的router会删除名称相同路由为避免名字的冲突特殊情况可以自定义 */
private String routeName;
/** 是否为外链0是 1否 */ /** 是否为外链0是 1否 */
@ApiModelProperty("是否为外链0是 1否") @ApiModelProperty("是否为外链0是 1否")
private String isFrame; private String isFrame;
@@ -171,6 +174,16 @@ public class SysMenu extends BaseEntity
this.query = query; this.query = query;
} }
public String getRouteName()
{
return routeName;
}
public void setRouteName(String routeName)
{
this.routeName = routeName;
}
public String getIsFrame() public String getIsFrame()
{ {
return isFrame; return isFrame;
@@ -262,6 +275,8 @@ public class SysMenu extends BaseEntity
.append("orderNum", getOrderNum()) .append("orderNum", getOrderNum())
.append("path", getPath()) .append("path", getPath())
.append("component", getComponent()) .append("component", getComponent())
.append("query", getQuery())
.append("routeName", getRouteName())
.append("isFrame", getIsFrame()) .append("isFrame", getIsFrame())
.append("IsCache", getIsCache()) .append("IsCache", getIsCache())
.append("menuType", getMenuType()) .append("menuType", getMenuType())

View File

@@ -1,12 +1,13 @@
package com.fastbee.common.core.domain.entity; package com.fastbee.common.core.domain.entity;
import java.util.Set; import java.util.Set;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import com.fastbee.common.annotation.Excel; import com.fastbee.common.annotation.Excel;

View File

@@ -2,7 +2,9 @@ package com.fastbee.common.core.domain.entity;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import javax.validation.constraints.*; import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
@@ -27,7 +29,7 @@ public class SysUser extends BaseEntity
/** 用户ID */ /** 用户ID */
@ApiModelProperty("用户ID") @ApiModelProperty("用户ID")
@Excel(name = "用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号") @Excel(name = "用户序号", type = Type.EXPORT, cellType = ColumnType.NUMERIC, prompt = "用户编号")
private Long userId; private Long userId;
/** 部门ID */ /** 部门ID */
@@ -52,7 +54,7 @@ public class SysUser extends BaseEntity
/** 手机号码 */ /** 手机号码 */
@ApiModelProperty("手机号码") @ApiModelProperty("手机号码")
@Excel(name = "手机号码") @Excel(name = "手机号码", cellType = ColumnType.TEXT)
private String phonenumber; private String phonenumber;
/** 用户性别 */ /** 用户性别 */

View File

@@ -1,19 +1,19 @@
package com.fastbee.common.core.domain.model; package com.fastbee.common.core.domain.model;
import com.alibaba.fastjson2.annotation.JSONField;
import com.fastbee.common.core.domain.entity.SysUser;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection; import java.util.Collection;
import java.util.Set; import java.util.Set;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.alibaba.fastjson2.annotation.JSONField;
import com.fastbee.common.core.domain.entity.SysUser;
/** /**
* 登录用户身份权限 * 登录用户身份权限
* *
* @author ruoyi * @author ruoyi
*/ */
public class LoginUser implements UserDetails public class LoginUser implements UserDetails {
{
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
@@ -31,6 +31,9 @@ public class LoginUser implements UserDetails
*/ */
private String token; private String token;
private String requestToken;
/** /**
* 登录时间 * 登录时间
*/ */
@@ -71,64 +74,100 @@ public class LoginUser implements UserDetails
*/ */
private SysUser user; private SysUser user;
public Long getUserId() private String language;
{
private Long deptUserId;
private Boolean neverExpire = Boolean.FALSE;
public LoginUser() {
}
public LoginUser(SysUser user, Set<String> permissions) {
this.user = user;
this.permissions = permissions;
}
public LoginUser(Long userId, Long deptId, SysUser user, Set<String> permissions) {
this.userId = userId;
this.deptId = deptId;
this.user = user;
this.permissions = permissions;
}
public LoginUser(Long userId, Long deptId, String language, SysUser user, Set<String> permissions) {
this.userId = userId;
this.deptId = deptId;
this.user = user;
this.language = language;
this.permissions = permissions;
}
public Boolean getNeverExpire() {
return neverExpire;
}
public void setNeverExpire(Boolean neverExpire) {
this.neverExpire = neverExpire;
}
public String getLanguage() {
return language;
}
public Long getDeptUserId() {
return deptUserId;
}
public void setDeptUserId(Long deptUserId) {
this.deptUserId = deptUserId;
}
public void setLanguage(String language) {
this.language = language;
}
public Long getUserId() {
return userId; return userId;
} }
public void setUserId(Long userId) public void setUserId(Long userId) {
{
this.userId = userId; this.userId = userId;
} }
public Long getDeptId() public Long getDeptId() {
{
return deptId; return deptId;
} }
public void setDeptId(Long deptId) public void setDeptId(Long deptId) {
{
this.deptId = deptId; this.deptId = deptId;
} }
public String getToken() public String getToken() {
{
return token; return token;
} }
public void setToken(String token) public void setToken(String token) {
{
this.token = token; this.token = token;
} }
public LoginUser() public String getRequestToken() {
{ return requestToken;
} }
public LoginUser(SysUser user, Set<String> permissions) public void setRequestToken(String requestToken) {
{ this.requestToken = requestToken;
this.user = user;
this.permissions = permissions;
} }
public LoginUser(Long userId, Long deptId, SysUser user, Set<String> permissions)
{
this.userId = userId;
this.deptId = deptId;
this.user = user;
this.permissions = permissions;
}
@JSONField(serialize = false) @JSONField(serialize = false)
@Override @Override
public String getPassword() public String getPassword() {
{
return user.getPassword(); return user.getPassword();
} }
@Override @Override
public String getUsername() public String getUsername() {
{
return user.getUserName(); return user.getUserName();
} }
@@ -137,8 +176,7 @@ public class LoginUser implements UserDetails
*/ */
@JSONField(serialize = false) @JSONField(serialize = false)
@Override @Override
public boolean isAccountNonExpired() public boolean isAccountNonExpired() {
{
return true; return true;
} }
@@ -149,8 +187,7 @@ public class LoginUser implements UserDetails
*/ */
@JSONField(serialize = false) @JSONField(serialize = false)
@Override @Override
public boolean isAccountNonLocked() public boolean isAccountNonLocked() {
{
return true; return true;
} }
@@ -161,8 +198,7 @@ public class LoginUser implements UserDetails
*/ */
@JSONField(serialize = false) @JSONField(serialize = false)
@Override @Override
public boolean isCredentialsNonExpired() public boolean isCredentialsNonExpired() {
{
return true; return true;
} }
@@ -173,94 +209,76 @@ public class LoginUser implements UserDetails
*/ */
@JSONField(serialize = false) @JSONField(serialize = false)
@Override @Override
public boolean isEnabled() public boolean isEnabled() {
{
return true; return true;
} }
public Long getLoginTime() public Long getLoginTime() {
{
return loginTime; return loginTime;
} }
public void setLoginTime(Long loginTime) public void setLoginTime(Long loginTime) {
{
this.loginTime = loginTime; this.loginTime = loginTime;
} }
public String getIpaddr() public String getIpaddr() {
{
return ipaddr; return ipaddr;
} }
public void setIpaddr(String ipaddr) public void setIpaddr(String ipaddr) {
{
this.ipaddr = ipaddr; this.ipaddr = ipaddr;
} }
public String getLoginLocation() public String getLoginLocation() {
{
return loginLocation; return loginLocation;
} }
public void setLoginLocation(String loginLocation) public void setLoginLocation(String loginLocation) {
{
this.loginLocation = loginLocation; this.loginLocation = loginLocation;
} }
public String getBrowser() public String getBrowser() {
{
return browser; return browser;
} }
public void setBrowser(String browser) public void setBrowser(String browser) {
{
this.browser = browser; this.browser = browser;
} }
public String getOs() public String getOs() {
{
return os; return os;
} }
public void setOs(String os) public void setOs(String os) {
{
this.os = os; this.os = os;
} }
public Long getExpireTime() public Long getExpireTime() {
{
return expireTime; return expireTime;
} }
public void setExpireTime(Long expireTime) public void setExpireTime(Long expireTime) {
{
this.expireTime = expireTime; this.expireTime = expireTime;
} }
public Set<String> getPermissions() public Set<String> getPermissions() {
{
return permissions; return permissions;
} }
public void setPermissions(Set<String> permissions) public void setPermissions(Set<String> permissions) {
{
this.permissions = permissions; this.permissions = permissions;
} }
public SysUser getUser() public SysUser getUser() {
{
return user; return user;
} }
public void setUser(SysUser user) public void setUser(SysUser user) {
{
this.user = user; this.user = user;
} }
@Override @Override
public Collection<? extends GrantedAuthority> getAuthorities() public Collection<? extends GrantedAuthority> getAuthorities() {
{
return null; return null;
} }
} }

View File

@@ -5,7 +5,7 @@ import com.fastbee.common.utils.DateUtils;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;

View File

@@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
/** /**
* OTA远程升级 * OTA远程升级

View File

@@ -1,6 +1,15 @@
package com.fastbee.common.core.page; package com.fastbee.common.core.page;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fastbee.common.exception.ServiceException;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
import com.fastbee.common.utils.sql.SqlUtil;
import java.util.ArrayList;
import java.util.List;
/** /**
* 分页数据 * 分页数据
@@ -24,6 +33,16 @@ public class PageDomain
/** 分页参数合理化 */ /** 分页参数合理化 */
private Boolean reasonable = true; private Boolean reasonable = true;
/**
* 当前记录起始索引 默认值
*/
public static final int DEFAULT_PAGE_NUM = 1;
/**
* 每页显示记录数 默认值 默认查全部
*/
public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
public String getOrderBy() public String getOrderBy()
{ {
if (StringUtils.isEmpty(orderByColumn)) if (StringUtils.isEmpty(orderByColumn))
@@ -33,6 +52,64 @@ public class PageDomain
return StringUtils.toUnderScoreCase(orderByColumn) + " " + isAsc; return StringUtils.toUnderScoreCase(orderByColumn) + " " + isAsc;
} }
/**
* 构建分页对象
*/
public <T> Page<T> build() {
Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM);
Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE);
if (pageNum <= 0) {
pageNum = DEFAULT_PAGE_NUM;
}
Page<T> page = new Page<>(pageNum, pageSize);
List<OrderItem> orderItems = buildOrderItem();
if (CollUtil.isNotEmpty(orderItems)) {
page.addOrder(orderItems);
}
return page;
}
/**
* 构建排序
*
* 支持的用法如下:
* {isAsc:"asc",orderByColumn:"id"} order by id asc
* {isAsc:"asc",orderByColumn:"id,createTime"} order by id asc,create_time asc
* {isAsc:"desc",orderByColumn:"id,createTime"} order by id desc,create_time desc
* {isAsc:"asc,desc",orderByColumn:"id,createTime"} order by id asc,create_time desc
*/
private List<OrderItem> buildOrderItem() {
if (StringUtils.isBlank(orderByColumn) || StringUtils.isBlank(isAsc)) {
return null;
}
String orderBy = SqlUtil.escapeOrderBySql(orderByColumn);
orderBy = StringUtils.toUnderScoreCase(orderBy);
// 兼容前端排序类型
isAsc = StringUtils.replaceEach(isAsc, new String[]{"ascending", "descending"}, new String[]{"asc", "desc"});
String[] orderByArr = orderBy.split(StringUtils.SLASH);
String[] isAscArr = isAsc.split(StringUtils.SLASH);
if (isAscArr.length != 1 && isAscArr.length != orderByArr.length) {
throw new ServiceException("排序参数有误");
}
List<OrderItem> list = new ArrayList<>();
// 每个字段各自排序
for (int i = 0; i < orderByArr.length; i++) {
String orderByStr = orderByArr[i];
String isAscStr = isAscArr.length == 1 ? isAscArr[0] : isAscArr[i];
if ("asc".equals(isAscStr)) {
list.add(OrderItem.asc(orderByStr));
} else if ("desc".equals(isAscStr)) {
list.add(OrderItem.desc(orderByStr));
} else {
throw new ServiceException("排序参数有误");
}
}
return list;
}
public Integer getPageNum() public Integer getPageNum()
{ {
return pageNum; return pageNum;

View File

@@ -1,5 +1,8 @@
package com.fastbee.common.core.page; package com.fastbee.common.core.page;
import cn.hutool.http.HttpStatus;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
@@ -43,6 +46,40 @@ public class TableDataInfo implements Serializable
this.total = total; this.total = total;
} }
/**
* 根据分页对象构建表格分页数据对象
*/
public static <T> TableDataInfo build(IPage<T> page) {
TableDataInfo rspData = new TableDataInfo();
rspData.setCode(HttpStatus.HTTP_OK);
rspData.setMsg("查询成功");
rspData.setRows(page.getRecords());
rspData.setTotal(page.getTotal());
return rspData;
}
/**
* 根据数据列表构建表格分页数据对象
*/
public static <T> TableDataInfo build(List<T> list) {
TableDataInfo rspData = new TableDataInfo();
rspData.setCode(HttpStatus.HTTP_OK);
rspData.setMsg("查询成功");
rspData.setRows(list);
rspData.setTotal(list.size());
return rspData;
}
/**
* 构建表格分页数据对象
*/
public static <T> TableDataInfo build() {
TableDataInfo rspData = new TableDataInfo();
rspData.setCode(HttpStatus.HTTP_OK);
rspData.setMsg("查询成功");
return rspData;
}
public long getTotal() public long getTotal()
{ {
return total; return total;

View File

@@ -627,7 +627,7 @@ public class RedisCache {
public List<Object> scan(String query) { public List<Object> scan(String query) {
Set<String> keys = (Set<String>) redisTemplate.execute((RedisCallback<Set<String>>) connection -> { Set<String> keys = (Set<String>) redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
Set<String> keysTmp = new HashSet<>(); Set<String> keysTmp = new HashSet<>();
Cursor<byte[]> cursor = connection.scan(new ScanOptions.ScanOptionsBuilder().match(query).count(1000).build()); Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(query).count(1000).build());
while (cursor.hasNext()) { while (cursor.hasNext()) {
keysTmp.add(new String(cursor.next())); keysTmp.add(new String(cursor.next()));
} }

View File

@@ -2,12 +2,12 @@ package com.fastbee.common.core.text;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.math.RoundingMode;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.Set; import java.util.Set;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
/** /**
* 类型转换器 * 类型转换器
@@ -364,6 +364,10 @@ public class Convert
*/ */
public static String[] toStrArray(String str) public static String[] toStrArray(String str)
{ {
if (StringUtils.isEmpty(str))
{
return new String[] {};
}
return toStrArray(",", str); return toStrArray(",", str);
} }
@@ -536,7 +540,7 @@ public class Convert
/** /**
* 转换为boolean<br> * 转换为boolean<br>
* String支持的值为true、false、yes、ok、no1,0 如果给定的值为空,或者转换失败,返回默认值<br> * String支持的值为true、false、yes、ok、no、1、0、是、否, 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错 * 转换失败不会报错
* *
* @param value 被转换的值 * @param value 被转换的值
@@ -565,10 +569,12 @@ public class Convert
case "yes": case "yes":
case "ok": case "ok":
case "1": case "1":
case "":
return true; return true;
case "false": case "false":
case "no": case "no":
case "0": case "0":
case "":
return false; return false;
default: default:
return defaultValue; return defaultValue;
@@ -791,14 +797,23 @@ public class Convert
{ {
return (String) obj; return (String) obj;
} }
else if (obj instanceof byte[]) else if (obj instanceof byte[] || obj instanceof Byte[])
{ {
return str((byte[]) obj, charset); if (obj instanceof byte[])
} {
else if (obj instanceof Byte[]) return str((byte[]) obj, charset);
{ }
byte[] bytes = ArrayUtils.toPrimitive((Byte[]) obj); else
return str(bytes, charset); {
Byte[] bytes = (Byte[]) obj;
int length = bytes.length;
byte[] dest = new byte[length];
for (int i = 0; i < length; i++)
{
dest[i] = bytes[i];
}
return str(dest, charset);
}
} }
else if (obj instanceof ByteBuffer) else if (obj instanceof ByteBuffer)
{ {
@@ -954,9 +969,7 @@ public class Convert
c[i] = (char) (c[i] - 65248); c[i] = (char) (c[i] - 65248);
} }
} }
String returnString = new String(c); return new String(c);
return returnString;
} }
/** /**
@@ -977,7 +990,12 @@ public class Convert
String s = ""; String s = "";
for (int i = 0; i < fraction.length; i++) for (int i = 0; i < fraction.length; i++)
{ {
s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", ""); // 优化double计算精度丢失问题
BigDecimal nNum = new BigDecimal(n);
BigDecimal decimal = new BigDecimal(10);
BigDecimal scale = nNum.multiply(decimal).setScale(2, RoundingMode.HALF_EVEN);
double d = scale.doubleValue();
s += (digit[(int) (Math.floor(d * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
} }
if (s.length() < 1) if (s.length() < 1)
{ {

View File

@@ -0,0 +1,59 @@
package com.fastbee.common.enums;
import java.util.function.Function;
import com.fastbee.common.utils.DesensitizedUtil;
/**
* 脱敏类型
*
* @author ruoyi
*/
public enum DesensitizedType
{
/**
* 姓名第2位星号替换
*/
USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),
/**
* 密码,全部字符都用*代替
*/
PASSWORD(DesensitizedUtil::password),
/**
* 身份证中间10位星号替换
*/
ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\d{3}[Xx]|\\d{4})", "$1** **** ****$2")),
/**
* 手机号中间4位星号替换
*/
PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),
/**
* 电子邮箱,仅显示第一个字母和@后面的地址显示,其他星号替换
*/
EMAIL(s -> s.replaceAll("(^.)[^@]*(@.*$)", "$1****$2")),
/**
* 银行卡号保留最后4位其他星号替换
*/
BANK_CARD(s -> s.replaceAll("\\d{15}(\\d{3})", "**** **** **** **** $1")),
/**
* 车牌号码,包含普通车辆、新能源车辆
*/
CAR_LICENSE(DesensitizedUtil::carLicense);
private final Function<String, String> desensitizer;
DesensitizedType(Function<String, String> desensitizer)
{
this.desensitizer = desensitizer;
}
public Function<String, String> desensitizer()
{
return desensitizer;
}
}

View File

@@ -0,0 +1,61 @@
package com.fastbee.common.exception.file;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* 文件上传异常类
*
* @author ruoyi
*/
public class FileUploadException extends Exception
{
private static final long serialVersionUID = 1L;
private final Throwable cause;
public FileUploadException()
{
this(null, null);
}
public FileUploadException(final String msg)
{
this(msg, null);
}
public FileUploadException(String msg, Throwable cause)
{
super(msg);
this.cause = cause;
}
@Override
public void printStackTrace(PrintStream stream)
{
super.printStackTrace(stream);
if (cause != null)
{
stream.println("Caused by:");
cause.printStackTrace(stream);
}
}
@Override
public void printStackTrace(PrintWriter writer)
{
super.printStackTrace(writer);
if (cause != null)
{
writer.println("Caused by:");
cause.printStackTrace(writer);
}
}
@Override
public Throwable getCause()
{
return cause;
}
}

View File

@@ -0,0 +1,16 @@
package com.fastbee.common.exception.user;
/**
* 黑名单IP异常类
*
* @author ruoyi
*/
public class BlackListException extends UserException
{
private static final long serialVersionUID = 1L;
public BlackListException()
{
super("login.blocked", null);
}
}

View File

@@ -0,0 +1,16 @@
package com.fastbee.common.exception.user;
/**
* 用户不存在异常类
*
* @author ruoyi
*/
public class UserNotExistsException extends UserException
{
private static final long serialVersionUID = 1L;
public UserNotExistsException()
{
super("user.not.exists", null);
}
}

View File

@@ -1,13 +1,13 @@
package com.fastbee.common.filter; package com.fastbee.common.filter;
import java.io.IOException; import java.io.IOException;
import javax.servlet.Filter; import jakarta.servlet.Filter;
import javax.servlet.FilterChain; import jakarta.servlet.FilterChain;
import javax.servlet.FilterConfig; import jakarta.servlet.FilterConfig;
import javax.servlet.ServletException; import jakarta.servlet.ServletException;
import javax.servlet.ServletRequest; import jakarta.servlet.ServletRequest;
import javax.servlet.ServletResponse; import jakarta.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;

View File

@@ -4,11 +4,11 @@ import java.io.BufferedReader;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import javax.servlet.ReadListener; import jakarta.servlet.ReadListener;
import javax.servlet.ServletInputStream; import jakarta.servlet.ServletInputStream;
import javax.servlet.ServletResponse; import jakarta.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper; import jakarta.servlet.http.HttpServletRequestWrapper;
import com.fastbee.common.utils.http.HttpHelper; import com.fastbee.common.utils.http.HttpHelper;
import com.fastbee.common.constant.Constants; import com.fastbee.common.constant.Constants;

View File

@@ -3,14 +3,14 @@ package com.fastbee.common.filter;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.servlet.Filter; import jakarta.servlet.Filter;
import javax.servlet.FilterChain; import jakarta.servlet.FilterChain;
import javax.servlet.FilterConfig; import jakarta.servlet.FilterConfig;
import javax.servlet.ServletException; import jakarta.servlet.ServletException;
import javax.servlet.ServletRequest; import jakarta.servlet.ServletRequest;
import javax.servlet.ServletResponse; import jakarta.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
import com.fastbee.common.enums.HttpMethod; import com.fastbee.common.enums.HttpMethod;
@@ -32,10 +32,10 @@ public class XssFilter implements Filter
String tempExcludes = filterConfig.getInitParameter("excludes"); String tempExcludes = filterConfig.getInitParameter("excludes");
if (StringUtils.isNotEmpty(tempExcludes)) if (StringUtils.isNotEmpty(tempExcludes))
{ {
String[] url = tempExcludes.split(","); String[] urls = tempExcludes.split(",");
for (int i = 0; url != null && i < url.length; i++) for (String url : urls)
{ {
excludes.add(url[i]); excludes.add(url);
} }
} }
} }

View File

@@ -2,10 +2,10 @@ package com.fastbee.common.filter;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import javax.servlet.ReadListener; import jakarta.servlet.ReadListener;
import javax.servlet.ServletInputStream; import jakarta.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper; import jakarta.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;

View File

@@ -0,0 +1,64 @@
package com.fastbee.common.mybatis.enums;
import com.fastbee.common.utils.StringUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 数据库类型
*
* @author Lion Li
*/
@Getter
@AllArgsConstructor
public enum DataBaseType {
/**
* MySQL
*/
MY_SQL("MySQL"),
/**
* Oracle
*/
ORACLE("Oracle"),
/**
* PostgreSQL
*/
POSTGRE_SQL("PostgreSQL"),
/**
* SQL Server
*/
SQL_SERVER("Microsoft SQL Server"),
/**
* 达梦
*/
DM("DM DBMS");
/**
* 数据库类型
*/
private final String type;
/**
* 根据数据库产品名称查找对应的数据库类型
*
* @param databaseProductName 数据库产品名称
* @return 对应的数据库类型枚举值,如果未找到则返回 null
*/
public static DataBaseType find(String databaseProductName) {
if (StringUtils.isBlank(databaseProductName)) {
return null;
}
for (DataBaseType type : values()) {
if (type.getType().equals(databaseProductName)) {
return type;
}
}
return null;
}
}

View File

@@ -1,4 +1,4 @@
package com.fastbee.framework.mybatis.mapper; package com.fastbee.common.mybatis.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -9,7 +9,7 @@ import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.toolkit.Db; import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.fastbee.common.core.domain.PageParam; import com.fastbee.common.core.domain.PageParam;
import com.fastbee.common.core.domain.PageResult; import com.fastbee.common.core.domain.PageResult;
import com.fastbee.framework.mybatis.utils.MyBatisUtils; import com.fastbee.common.mybatis.utils.MyBatisUtils;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.Collection; import java.util.Collection;

View File

@@ -1,4 +1,4 @@
package com.fastbee.framework.mybatis.utils; package com.fastbee.common.mybatis.utils;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.OrderItem; import com.baomidou.mybatisplus.core.metadata.OrderItem;

View File

@@ -108,7 +108,6 @@ public class Arith
"The scale must be a positive integer or zero"); "The scale must be a positive integer or zero");
} }
BigDecimal b = new BigDecimal(Double.toString(v)); BigDecimal b = new BigDecimal(Double.toString(v));
BigDecimal one = BigDecimal.ONE; return b.divide(BigDecimal.ONE, scale, RoundingMode.HALF_UP).doubleValue();
return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue();
} }
} }

View File

@@ -1,18 +1,14 @@
package com.fastbee.common.utils; package com.fastbee.common.utils;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.LocalDate; import java.time.*;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date; import java.util.Date;
import java.util.Random; import java.util.Random;
import org.apache.commons.lang3.time.DateFormatUtils;
/** /**
* 时间工具类 * 时间工具类
* *
@@ -160,16 +156,20 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
} }
/** /**
* 计算两个时间差 * 计算时间差
*
* @param endDate 最后时间
* @param startTime 开始时间
* @return 时间差(天/小时/分钟)
*/ */
public static String getDatePoor(Date endDate, Date nowDate) public static String timeDistance(Date endDate, Date startTime)
{ {
long nd = 1000 * 24 * 60 * 60; long nd = 1000 * 24 * 60 * 60;
long nh = 1000 * 60 * 60; long nh = 1000 * 60 * 60;
long nm = 1000 * 60; long nm = 1000 * 60;
// long ns = 1000; // long ns = 1000;
// 获得两个时间的毫秒时间差异 // 获得两个时间的毫秒时间差异
long diff = endDate.getTime() - nowDate.getTime(); long diff = endDate.getTime() - startTime.getTime();
// 计算差多少天 // 计算差多少天
long day = diff / nd; long day = diff / nd;
// 计算差多少小时 // 计算差多少小时

View File

@@ -0,0 +1,49 @@
package com.fastbee.common.utils;
/**
* 脱敏工具类
*
* @author ruoyi
*/
public class DesensitizedUtil
{
/**
* 密码的全部字符都用*代替,比如:******
*
* @param password 密码
* @return 脱敏后的密码
*/
public static String password(String password)
{
if (StringUtils.isBlank(password))
{
return StringUtils.EMPTY;
}
return StringUtils.repeat('*', password.length());
}
/**
* 车牌中间用*代替,如果是错误的车牌,不处理
*
* @param carLicense 完整的车牌号
* @return 脱敏后的车牌
*/
public static String carLicense(String carLicense)
{
if (StringUtils.isBlank(carLicense))
{
return StringUtils.EMPTY;
}
// 普通车牌
if (carLicense.length() == 7)
{
carLicense = StringUtils.hide(carLicense, 3, 6);
}
else if (carLicense.length() == 8)
{
// 新能源车牌
carLicense = StringUtils.hide(carLicense, 3, 7);
}
return carLicense;
}
}

View File

@@ -56,6 +56,10 @@ public class DictUtils
*/ */
public static String getDictLabel(String dictType, String dictValue) public static String getDictLabel(String dictType, String dictValue)
{ {
if (StringUtils.isEmpty(dictValue))
{
return StringUtils.EMPTY;
}
return getDictLabel(dictType, dictValue, SEPARATOR); return getDictLabel(dictType, dictValue, SEPARATOR);
} }
@@ -68,6 +72,10 @@ public class DictUtils
*/ */
public static String getDictValue(String dictType, String dictLabel) public static String getDictValue(String dictType, String dictLabel)
{ {
if (StringUtils.isEmpty(dictLabel))
{
return StringUtils.EMPTY;
}
return getDictValue(dictType, dictLabel, SEPARATOR); return getDictValue(dictType, dictLabel, SEPARATOR);
} }
@@ -83,31 +91,31 @@ public class DictUtils
{ {
StringBuilder propertyString = new StringBuilder(); StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType); List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.isNull(datas))
if (StringUtils.isNotNull(datas))
{ {
if (StringUtils.containsAny(separator, dictValue)) return StringUtils.EMPTY;
}
if (StringUtils.containsAny(separator, dictValue))
{
for (SysDictData dict : datas)
{ {
for (SysDictData dict : datas) for (String value : dictValue.split(separator))
{ {
for (String value : dictValue.split(separator)) if (value.equals(dict.getDictValue()))
{ {
if (value.equals(dict.getDictValue())) propertyString.append(dict.getDictLabel()).append(separator);
{ break;
propertyString.append(dict.getDictLabel()).append(separator);
break;
}
} }
} }
} }
else }
else
{
for (SysDictData dict : datas)
{ {
for (SysDictData dict : datas) if (dictValue.equals(dict.getDictValue()))
{ {
if (dictValue.equals(dict.getDictValue())) return dict.getDictLabel();
{
return dict.getDictLabel();
}
} }
} }
} }
@@ -126,8 +134,11 @@ public class DictUtils
{ {
StringBuilder propertyString = new StringBuilder(); StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType); List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.isNull(datas))
if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas)) {
return StringUtils.EMPTY;
}
if (StringUtils.containsAny(separator, dictLabel))
{ {
for (SysDictData dict : datas) for (SysDictData dict : datas)
{ {
@@ -154,6 +165,48 @@ public class DictUtils
return StringUtils.stripEnd(propertyString.toString(), separator); return StringUtils.stripEnd(propertyString.toString(), separator);
} }
/**
* 根据字典类型获取字典所有值
*
* @param dictType 字典类型
* @return 字典值
*/
public static String getDictValues(String dictType)
{
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.isNull(datas))
{
return StringUtils.EMPTY;
}
for (SysDictData dict : datas)
{
propertyString.append(dict.getDictValue()).append(SEPARATOR);
}
return StringUtils.stripEnd(propertyString.toString(), SEPARATOR);
}
/**
* 根据字典类型获取字典所有标签
*
* @param dictType 字典类型
* @return 字典值
*/
public static String getDictLabels(String dictType)
{
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.isNull(datas))
{
return StringUtils.EMPTY;
}
for (SysDictData dict : datas)
{
propertyString.append(dict.getDictLabel()).append(SEPARATOR);
}
return StringUtils.stripEnd(propertyString.toString(), SEPARATOR);
}
/** /**
* 删除指定字典缓存 * 删除指定字典缓存
* *

View File

@@ -2,7 +2,7 @@ package com.fastbee.common.utils;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import javax.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;

View File

@@ -1,11 +1,18 @@
package com.fastbee.common.utils; package com.fastbee.common.utils;
import com.fastbee.common.constant.Constants;
import com.fastbee.common.constant.HttpStatus;
import com.fastbee.common.core.domain.entity.SysRole;
import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.exception.ServiceException;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import com.fastbee.common.constant.HttpStatus; import org.springframework.util.PatternMatchUtils;
import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.exception.ServiceException; import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/** /**
* 安全服务工具类 * 安全服务工具类
@@ -14,6 +21,7 @@ import com.fastbee.common.exception.ServiceException;
*/ */
public class SecurityUtils public class SecurityUtils
{ {
/** /**
* 用户ID * 用户ID
**/ **/
@@ -117,4 +125,55 @@ public class SecurityUtils
{ {
return userId != null && 1L == userId; return userId != null && 1L == userId;
} }
/**
* 验证用户是否具备某权限
*
* @param permission 权限字符串
* @return 用户是否具备某权限
*/
public static boolean hasPermi(String permission)
{
return hasPermi(getLoginUser().getPermissions(), permission);
}
/**
* 判断是否包含权限
*
* @param authorities 权限列表
* @param permission 权限字符串
* @return 用户是否具备某权限
*/
public static boolean hasPermi(Collection<String> authorities, String permission)
{
return authorities.stream().filter(StringUtils::hasText)
.anyMatch(x -> Constants.ALL_PERMISSION.equals(x) || PatternMatchUtils.simpleMatch(x, permission));
}
/**
* 验证用户是否拥有某个角色
*
* @param role 角色标识
* @return 用户是否具备某角色
*/
public static boolean hasRole(String role)
{
List<SysRole> roleList = getLoginUser().getUser().getRoles();
Collection<String> roles = roleList.stream().map(SysRole::getRoleKey).collect(Collectors.toSet());
return hasRole(roles, role);
}
/**
* 判断是否包含角色
*
* @param roles 角色列表
* @param role 角色
* @return 用户是否具备某角色权限
*/
public static boolean hasRole(Collection<String> roles, String role)
{
return roles.stream().filter(StringUtils::hasText)
.anyMatch(x -> Constants.SUPER_ADMIN.equals(x) || PatternMatchUtils.simpleMatch(x, role));
}
} }

View File

@@ -7,12 +7,10 @@ import java.net.URLEncoder;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.servlet.ServletRequest; import jakarta.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import jakarta.servlet.http.HttpSession;
import cn.hutool.extra.servlet.ServletUtil;
import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
@@ -217,12 +215,4 @@ public class ServletUtils
return StringUtils.EMPTY; return StringUtils.EMPTY;
} }
} }
public static String getClientIP() {
HttpServletRequest request = getRequest();
if (request == null) {
return null;
}
return ServletUtil.getClientIP(request);
}
} }

View File

@@ -1,43 +1,37 @@
package com.fastbee.common.utils; package com.fastbee.common.utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import org.springframework.util.AntPathMatcher;
import com.fastbee.common.constant.Constants; import com.fastbee.common.constant.Constants;
import com.fastbee.common.core.text.StrFormatter; import com.fastbee.common.core.text.StrFormatter;
import org.springframework.util.AntPathMatcher;
import java.util.*;
/** /**
* 字符串工具类 * 字符串工具类
* *
* @author ruoyi * @author ruoyi
*/ */
public class StringUtils extends org.apache.commons.lang3.StringUtils { public class StringUtils extends org.apache.commons.lang3.StringUtils
/** {
* 空字符串 /** 空字符串 */
*/
private static final String NULLSTR = ""; private static final String NULLSTR = "";
/** /** 下划线 */
* 下划线
*/
private static final char SEPARATOR = '_'; private static final char SEPARATOR = '_';
/** 星号 */
private static final char ASTERISK = '*';
public static final String SLASH = "/";
/** /**
* 获取参数不为空值 * 获取参数不为空值
* *
* @param value defaultValue 要判断的value * @param value defaultValue 要判断的value
* @return value 返回值 * @return value 返回值
*/ */
public static <T> T nvl(T value, T defaultValue) { public static <T> T nvl(T value, T defaultValue)
{
return value != null ? value : defaultValue; return value != null ? value : defaultValue;
} }
@@ -47,7 +41,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param coll 要判断的Collection * @param coll 要判断的Collection
* @return true为空 false非空 * @return true为空 false非空
*/ */
public static boolean isEmpty(Collection<?> coll) { public static boolean isEmpty(Collection<?> coll)
{
return isNull(coll) || coll.isEmpty(); return isNull(coll) || coll.isEmpty();
} }
@@ -57,7 +52,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param coll 要判断的Collection * @param coll 要判断的Collection
* @return true非空 false * @return true非空 false
*/ */
public static boolean isNotEmpty(Collection<?> coll) { public static boolean isNotEmpty(Collection<?> coll)
{
return !isEmpty(coll); return !isEmpty(coll);
} }
@@ -65,9 +61,10 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* * 判断一个对象数组是否为空 * * 判断一个对象数组是否为空
* *
* @param objects 要判断的对象数组 * @param objects 要判断的对象数组
* * @return true为空 false非空 ** @return true为空 false非空
*/ */
public static boolean isEmpty(Object[] objects) { public static boolean isEmpty(Object[] objects)
{
return isNull(objects) || (objects.length == 0); return isNull(objects) || (objects.length == 0);
} }
@@ -77,7 +74,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param objects 要判断的对象数组 * @param objects 要判断的对象数组
* @return true非空 false * @return true非空 false
*/ */
public static boolean isNotEmpty(Object[] objects) { public static boolean isNotEmpty(Object[] objects)
{
return !isEmpty(objects); return !isEmpty(objects);
} }
@@ -87,7 +85,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param map 要判断的Map * @param map 要判断的Map
* @return true为空 false非空 * @return true为空 false非空
*/ */
public static boolean isEmpty(Map<?, ?> map) { public static boolean isEmpty(Map<?, ?> map)
{
return isNull(map) || map.isEmpty(); return isNull(map) || map.isEmpty();
} }
@@ -97,7 +96,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param map 要判断的Map * @param map 要判断的Map
* @return true非空 false * @return true非空 false
*/ */
public static boolean isNotEmpty(Map<?, ?> map) { public static boolean isNotEmpty(Map<?, ?> map)
{
return !isEmpty(map); return !isEmpty(map);
} }
@@ -107,7 +107,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param str String * @param str String
* @return true为空 false非空 * @return true为空 false非空
*/ */
public static boolean isEmpty(String str) { public static boolean isEmpty(String str)
{
return isNull(str) || NULLSTR.equals(str.trim()); return isNull(str) || NULLSTR.equals(str.trim());
} }
@@ -117,7 +118,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param str String * @param str String
* @return true非空串 false空串 * @return true非空串 false空串
*/ */
public static boolean isNotEmpty(String str) { public static boolean isNotEmpty(String str)
{
return !isEmpty(str); return !isEmpty(str);
} }
@@ -127,7 +129,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param object Object * @param object Object
* @return true为空 false非空 * @return true为空 false非空
*/ */
public static boolean isNull(Object object) { public static boolean isNull(Object object)
{
return object == null; return object == null;
} }
@@ -137,7 +140,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param object Object * @param object Object
* @return true非空 false * @return true非空 false
*/ */
public static boolean isNotNull(Object object) { public static boolean isNotNull(Object object)
{
return !isNull(object); return !isNull(object);
} }
@@ -147,37 +151,87 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param object 对象 * @param object 对象
* @return true是数组 false不是数组 * @return true是数组 false不是数组
*/ */
public static boolean isArray(Object object) { public static boolean isArray(Object object)
{
return isNotNull(object) && object.getClass().isArray(); return isNotNull(object) && object.getClass().isArray();
} }
/** /**
* 去空格 * 去空格
*/ */
public static String trim(String str) { public static String trim(String str)
{
return (str == null ? "" : str.trim()); return (str == null ? "" : str.trim());
} }
/**
* 替换指定字符串的指定区间内字符为"*"
*
* @param str 字符串
* @param startInclude 开始位置(包含)
* @param endExclude 结束位置(不包含)
* @return 替换后的字符串
*/
public static String hide(CharSequence str, int startInclude, int endExclude)
{
if (isEmpty(str))
{
return NULLSTR;
}
final int strLength = str.length();
if (startInclude > strLength)
{
return NULLSTR;
}
if (endExclude > strLength)
{
endExclude = strLength;
}
if (startInclude > endExclude)
{
// 如果起始位置大于结束位置,不替换
return NULLSTR;
}
final char[] chars = new char[strLength];
for (int i = 0; i < strLength; i++)
{
if (i >= startInclude && i < endExclude)
{
chars[i] = ASTERISK;
}
else
{
chars[i] = str.charAt(i);
}
}
return new String(chars);
}
/** /**
* 截取字符串 * 截取字符串
* *
* @param str 字符串 * @param str 字符串
* @param start 开始 * @param start 开始
* @return 结果 * @return 结果
*/ */
public static String substring(final String str, int start) { public static String substring(final String str, int start)
if (str == null) { {
if (str == null)
{
return NULLSTR; return NULLSTR;
} }
if (start < 0) { if (start < 0)
{
start = str.length() + start; start = str.length() + start;
} }
if (start < 0) { if (start < 0)
{
start = 0; start = 0;
} }
if (start > str.length()) { if (start > str.length())
{
return NULLSTR; return NULLSTR;
} }
@@ -187,41 +241,99 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
/** /**
* 截取字符串 * 截取字符串
* *
* @param str 字符串 * @param str 字符串
* @param start 开始 * @param start 开始
* @param end 结束 * @param end 结束
* @return 结果 * @return 结果
*/ */
public static String substring(final String str, int start, int end) { public static String substring(final String str, int start, int end)
if (str == null) { {
if (str == null)
{
return NULLSTR; return NULLSTR;
} }
if (end < 0) { if (end < 0)
{
end = str.length() + end; end = str.length() + end;
} }
if (start < 0) { if (start < 0)
{
start = str.length() + start; start = str.length() + start;
} }
if (end > str.length()) { if (end > str.length())
{
end = str.length(); end = str.length();
} }
if (start > end) { if (start > end)
{
return NULLSTR; return NULLSTR;
} }
if (start < 0) { if (start < 0)
{
start = 0; start = 0;
} }
if (end < 0) { if (end < 0)
{
end = 0; end = 0;
} }
return str.substring(start, end); return str.substring(start, end);
} }
/**
* 在字符串中查找第一个出现的 `open` 和最后一个出现的 `close` 之间的子字符串
*
* @param str 要截取的字符串
* @param open 起始字符串
* @param close 结束字符串
* @return 截取结果
*/
public static String substringBetweenLast(final String str, final String open, final String close)
{
if (isEmpty(str) || isEmpty(open) || isEmpty(close))
{
return NULLSTR;
}
final int start = str.indexOf(open);
if (start != INDEX_NOT_FOUND)
{
final int end = str.lastIndexOf(close);
if (end != INDEX_NOT_FOUND)
{
return str.substring(start + open.length(), end);
}
}
return NULLSTR;
}
/**
* 判断是否为空,并且不是空白字符
*
* @param str 要判断的value
* @return 结果
*/
public static boolean hasText(String str)
{
return (str != null && !str.isEmpty() && containsText(str));
}
private static boolean containsText(CharSequence str)
{
int strLen = str.length();
for (int i = 0; i < strLen; i++)
{
if (!Character.isWhitespace(str.charAt(i)))
{
return true;
}
}
return false;
}
/** /**
* 格式化文本, {} 表示占位符<br> * 格式化文本, {} 表示占位符<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br> * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
@@ -232,11 +344,13 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* 转义\ format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br> * 转义\ format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
* *
* @param template 文本模板,被替换的部分用 {} 表示 * @param template 文本模板,被替换的部分用 {} 表示
* @param params 参数值 * @param params 参数值
* @return 格式化后的文本 * @return 格式化后的文本
*/ */
public static String format(String template, Object... params) { public static String format(String template, Object... params)
if (isEmpty(params) || isEmpty(template)) { {
if (isEmpty(params) || isEmpty(template))
{
return template; return template;
} }
return StrFormatter.format(template, params); return StrFormatter.format(template, params);
@@ -248,7 +362,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param link 链接 * @param link 链接
* @return 结果 * @return 结果
*/ */
public static boolean ishttp(String link) { public static boolean ishttp(String link)
{
return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS); return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS);
} }
@@ -259,35 +374,54 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param sep 分隔符 * @param sep 分隔符
* @return set集合 * @return set集合
*/ */
public static final Set<String> str2Set(String str, String sep) { public static final Set<String> str2Set(String str, String sep)
{
return new HashSet<String>(str2List(str, sep, true, false)); return new HashSet<String>(str2List(str, sep, true, false));
} }
/** /**
* 字符串转list * 字符串转list
* *
* @param str 字符串 * @param str 字符串
* @param sep 分隔符 * @param sep 分隔符
* @param filterBlank 过滤纯空白
* @param trim 去掉首尾空白
* @return list集合 * @return list集合
*/ */
public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) { public static final List<String> str2List(String str, String sep)
{
return str2List(str, sep, true, false);
}
/**
* 字符串转list
*
* @param str 字符串
* @param sep 分隔符
* @param filterBlank 过滤纯空白
* @param trim 去掉首尾空白
* @return list集合
*/
public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim)
{
List<String> list = new ArrayList<String>(); List<String> list = new ArrayList<String>();
if (StringUtils.isEmpty(str)) { if (StringUtils.isEmpty(str))
{
return list; return list;
} }
// 过滤空白字符串 // 过滤空白字符串
if (filterBlank && StringUtils.isBlank(str)) { if (filterBlank && StringUtils.isBlank(str))
{
return list; return list;
} }
String[] split = str.split(sep); String[] split = str.split(sep);
for (String string : split) { for (String string : split)
if (filterBlank && StringUtils.isBlank(string)) { {
if (filterBlank && StringUtils.isBlank(string))
{
continue; continue;
} }
if (trim) { if (trim)
{
string = string.trim(); string = string.trim();
} }
list.add(string); list.add(string);
@@ -297,18 +431,24 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
} }
/** /**
* 判断给定的set列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value * 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value
* *
* @param set 给定的集合 * @param collection 给定的集合
* @param array 给定的数组 * @param array 给定的数组
* @return boolean 结果 * @return boolean 结果
*/ */
public static boolean containsAny(Collection<String> collection, String... array) { public static boolean containsAny(Collection<String> collection, String... array)
if (isEmpty(collection) || isEmpty(array)) { {
if (isEmpty(collection) || isEmpty(array))
{
return false; return false;
} else { }
for (String str : array) { else
if (collection.contains(str)) { {
for (String str : array)
{
if (collection.contains(str))
{
return true; return true;
} }
} }
@@ -319,16 +459,20 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
/** /**
* 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写 * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
* *
* @param cs 指定字符串 * @param cs 指定字符串
* @param searchCharSequences 需要检查的字符串数组 * @param searchCharSequences 需要检查的字符串数组
* @return 是否包含任意一个字符串 * @return 是否包含任意一个字符串
*/ */
public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) { public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences)
if (isEmpty(cs) || isEmpty(searchCharSequences)) { {
if (isEmpty(cs) || isEmpty(searchCharSequences))
{
return false; return false;
} }
for (CharSequence testStr : searchCharSequences) { for (CharSequence testStr : searchCharSequences)
if (containsIgnoreCase(cs, testStr)) { {
if (containsIgnoreCase(cs, testStr))
{
return true; return true;
} }
} }
@@ -338,8 +482,10 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
/** /**
* 驼峰转下划线命名 * 驼峰转下划线命名
*/ */
public static String toUnderScoreCase(String str) { public static String toUnderScoreCase(String str)
if (str == null) { {
if (str == null)
{
return null; return null;
} }
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@@ -349,23 +495,31 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
boolean curreCharIsUpperCase = true; boolean curreCharIsUpperCase = true;
// 下一字符是否大写 // 下一字符是否大写
boolean nexteCharIsUpperCase = true; boolean nexteCharIsUpperCase = true;
for (int i = 0; i < str.length(); i++) { for (int i = 0; i < str.length(); i++)
{
char c = str.charAt(i); char c = str.charAt(i);
if (i > 0) { if (i > 0)
{
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
} else { }
else
{
preCharIsUpperCase = false; preCharIsUpperCase = false;
} }
curreCharIsUpperCase = Character.isUpperCase(c); curreCharIsUpperCase = Character.isUpperCase(c);
if (i < (str.length() - 1)) { if (i < (str.length() - 1))
{
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
} }
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) { if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)
{
sb.append(SEPARATOR); sb.append(SEPARATOR);
} else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) { }
else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)
{
sb.append(SEPARATOR); sb.append(SEPARATOR);
} }
sb.append(Character.toLowerCase(c)); sb.append(Character.toLowerCase(c));
@@ -377,14 +531,18 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
/** /**
* 是否包含字符串 * 是否包含字符串
* *
* @param str 验证字符串 * @param str 验证字符串
* @param strs 字符串组 * @param strs 字符串组
* @return 包含返回true * @return 包含返回true
*/ */
public static boolean inStringIgnoreCase(String str, String... strs) { public static boolean inStringIgnoreCase(String str, String... strs)
if (str != null && strs != null) { {
for (String s : strs) { if (str != null && strs != null)
if (str.equalsIgnoreCase(trim(s))) { {
for (String s : strs)
{
if (str.equalsIgnoreCase(trim(s)))
{
return true; return true;
} }
} }
@@ -398,21 +556,27 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param name 转换前的下划线大写方式命名的字符串 * @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串 * @return 转换后的驼峰式命名的字符串
*/ */
public static String convertToCamelCase(String name) { public static String convertToCamelCase(String name)
{
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
// 快速检查 // 快速检查
if (name == null || name.isEmpty()) { if (name == null || name.isEmpty())
{
// 没必要转换 // 没必要转换
return ""; return "";
} else if (!name.contains("_")) { }
else if (!name.contains("_"))
{
// 不含下划线,仅将首字母大写 // 不含下划线,仅将首字母大写
return name.substring(0, 1).toUpperCase() + name.substring(1); return name.substring(0, 1).toUpperCase() + name.substring(1);
} }
// 用下划线将原始字符串分割 // 用下划线将原始字符串分割
String[] camels = name.split("_"); String[] camels = name.split("_");
for (String camel : camels) { for (String camel : camels)
{
// 跳过原始字符串中开头、结尾的下换线或双重下划线 // 跳过原始字符串中开头、结尾的下换线或双重下划线
if (camel.isEmpty()) { if (camel.isEmpty())
{
continue; continue;
} }
// 首字母大写 // 首字母大写
@@ -423,24 +587,37 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
} }
/** /**
* 驼峰式命名法 例如user_name->userName * 驼峰式命名法
* 例如user_name->userName
*/ */
public static String toCamelCase(String s) { public static String toCamelCase(String s)
if (s == null) { {
if (s == null)
{
return null; return null;
} }
if (s.indexOf(SEPARATOR) == -1)
{
return s;
}
s = s.toLowerCase(); s = s.toLowerCase();
StringBuilder sb = new StringBuilder(s.length()); StringBuilder sb = new StringBuilder(s.length());
boolean upperCase = false; boolean upperCase = false;
for (int i = 0; i < s.length(); i++) { for (int i = 0; i < s.length(); i++)
{
char c = s.charAt(i); char c = s.charAt(i);
if (c == SEPARATOR) { if (c == SEPARATOR)
{
upperCase = true; upperCase = true;
} else if (upperCase) { }
else if (upperCase)
{
sb.append(Character.toUpperCase(c)); sb.append(Character.toUpperCase(c));
upperCase = false; upperCase = false;
} else { }
else
{
sb.append(c); sb.append(c);
} }
} }
@@ -450,16 +627,20 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
/** /**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串 * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
* *
* @param str 指定字符串 * @param str 指定字符串
* @param strs 需要检查的字符串数组 * @param strs 需要检查的字符串数组
* @return 是否匹配 * @return 是否匹配
*/ */
public static boolean matches(String str, List<String> strs) { public static boolean matches(String str, List<String> strs)
if (isEmpty(str) || isEmpty(strs)) { {
if (isEmpty(str) || isEmpty(strs))
{
return false; return false;
} }
for (String pattern : strs) { for (String pattern : strs)
if (isMatch(pattern, str)) { {
if (isMatch(pattern, str))
{
return true; return true;
} }
} }
@@ -473,202 +654,67 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* ** 表示任意层路径; * ** 表示任意层路径;
* *
* @param pattern 匹配规则 * @param pattern 匹配规则
* @param url 需要匹配的url * @param url 需要匹配的url
* @return * @return
*/ */
public static boolean isMatch(String pattern, String url) { public static boolean isMatch(String pattern, String url)
{
AntPathMatcher matcher = new AntPathMatcher(); AntPathMatcher matcher = new AntPathMatcher();
return matcher.match(pattern, url); return matcher.match(pattern, url);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> T cast(Object obj) { public static <T> T cast(Object obj)
{
return (T) obj; return (T) obj;
} }
/** /**
* 数字左边补齐0使之达到指定长度。注意如果数字转换为字符串后长度大于size则只保留 最后size个字符。 * 数字左边补齐0使之达到指定长度。注意如果数字转换为字符串后长度大于size则只保留 最后size个字符。
* *
* @param num 数字对象 * @param num 数字对象
* @param size 字符串指定长度 * @param size 字符串指定长度
* @return 返回数字的字符串格式,该字符串为指定长度。 * @return 返回数字的字符串格式,该字符串为指定长度。
*/ */
public static final String padl(final Number num, final int size) { public static final String padl(final Number num, final int size)
{
return padl(num.toString(), size, '0'); return padl(num.toString(), size, '0');
} }
/** /**
* 字符串左补齐。如果原始字符串s长度大于size则只保留最后size个字符。 * 字符串左补齐。如果原始字符串s长度大于size则只保留最后size个字符。
* *
* @param s 原始字符串 * @param s 原始字符串
* @param size 字符串指定长度 * @param size 字符串指定长度
* @param c 用于补齐的字符 * @param c 用于补齐的字符
* @return 返回指定长度的字符串,由原字符串左补齐或截取得到。 * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
*/ */
public static final String padl(final String s, final int size, final char c) { public static final String padl(final String s, final int size, final char c)
{
final StringBuilder sb = new StringBuilder(size); final StringBuilder sb = new StringBuilder(size);
if (s != null) { if (s != null)
{
final int len = s.length(); final int len = s.length();
if (s.length() <= size) { if (s.length() <= size)
for (int i = size - len; i > 0; i--) { {
for (int i = size - len; i > 0; i--)
{
sb.append(c); sb.append(c);
} }
sb.append(s); sb.append(s);
} else { }
else
{
return s.substring(len - size, len); return s.substring(len - size, len);
} }
} else { }
for (int i = size; i > 0; i--) { else
{
for (int i = size; i > 0; i--)
{
sb.append(c); sb.append(c);
} }
} }
return sb.toString(); return sb.toString();
} }
/*将字符串转小写,首字母大写,其他小写*/
public static String upperCase(String str) {
char[] ch = str.toLowerCase().toCharArray();
if (ch[0] >= 'a' && ch[0] <= 'z') {
ch[0] = (char) (ch[0] - 32);
}
return new String(ch);
}
public static String toString(Object value) {
if (value == null) {
return "null";
}
if (value instanceof ByteBuf) {
return ByteBufUtil.hexDump((ByteBuf) value);
}
if (!value.getClass().isArray()) {
return value.toString();
}
StringBuilder root = new StringBuilder(32);
toString(value, root);
return root.toString();
}
public static StringBuilder toString(Object value, StringBuilder builder) {
if (value == null) {
return builder;
}
builder.append('[');
int start = builder.length();
if (value instanceof long[]) {
long[] array = (long[]) value;
for (long t : array) {
builder.append(t).append(',');
}
} else if (value instanceof int[]) {
int[] array = (int[]) value;
for (int t : array) {
builder.append(t).append(',');
}
} else if (value instanceof short[]) {
short[] array = (short[]) value;
for (short t : array) {
builder.append(t).append(',');
}
} else if (value instanceof byte[]) {
byte[] array = (byte[]) value;
for (byte t : array) {
builder.append(t).append(',');
}
} else if (value instanceof char[]) {
char[] array = (char[]) value;
for (char t : array) {
builder.append(t).append(',');
}
} else if (value instanceof double[]) {
double[] array = (double[]) value;
for (double t : array) {
builder.append(t).append(',');
}
} else if (value instanceof float[]) {
float[] array = (float[]) value;
for (float t : array) {
builder.append(t).append(',');
}
} else if (value instanceof boolean[]) {
boolean[] array = (boolean[]) value;
for (boolean t : array) {
builder.append(t).append(',');
}
} else if (value instanceof String[]) {
String[] array = (String[]) value;
for (String t : array) {
builder.append(t).append(',');
}
} else if (isArray1(value)) {
Object[] array = (Object[]) value;
for (Object t : array) {
toString(t, builder).append(',');
}
} else if (value instanceof Object[]) {
Object[] array = (Object[]) value;
for (Object t : array) {
builder.append(t).append(',');
}
}
int end = builder.length();
if (end <= start) {
builder.append(']');
} else {
builder.setCharAt(end - 1, ']');
}
return builder;
}
private static boolean isArray1(Object value) {
Class<?> componentType = value.getClass().getComponentType();
if (componentType == null) {
return false;
}
return componentType.isArray();
}
public static String leftPad(String str, int size, char ch) {
int length = str.length();
int pads = size - length;
if (pads > 0) {
char[] result = new char[size];
str.getChars(0, length, result, pads);
while (pads > 0) {
result[--pads] = ch;
}
return new String(result);
}
return str;
}
/**
* 获取字符串中的数字
* @param str
* @return
*/
public static Integer matcherNum(String str){
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(str);
while (matcher.find()){
return Integer.parseInt(matcher.group());
}
return 0;
}
} }

View File

@@ -4,10 +4,10 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import javax.validation.ConstraintViolation; import jakarta.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException; import jakarta.validation.ConstraintViolationException;
import javax.validation.Validation; import jakarta.validation.Validation;
import javax.validation.Validator; import jakarta.validation.Validator;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;

View File

@@ -1,9 +1,9 @@
package com.fastbee.common.utils.bean; package com.fastbee.common.utils.bean;
import java.util.Set; import java.util.Set;
import javax.validation.ConstraintViolation; import jakarta.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException; import jakarta.validation.ConstraintViolationException;
import javax.validation.Validator; import jakarta.validation.Validator;
/** /**
* bean对象属性验证 * bean对象属性验证

View File

@@ -9,8 +9,8 @@ import java.io.OutputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import javax.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;

View File

@@ -5,7 +5,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import javax.servlet.ServletRequest; import jakarta.servlet.ServletRequest;
import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -21,6 +21,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.fastbee.common.constant.Constants; import com.fastbee.common.constant.Constants;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
import org.springframework.http.MediaType;
/** /**
* 通用http发送方法 * 通用http发送方法
@@ -74,7 +75,7 @@ public class HttpUtils
URLConnection connection = realUrl.openConnection(); URLConnection connection = realUrl.openConnection();
connection.setRequestProperty("accept", "*/*"); connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive"); connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); connection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
connection.connect(); connection.connect();
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType)); in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
String line; String line;
@@ -121,10 +122,23 @@ public class HttpUtils
* 向指定 URL 发送POST方法的请求 * 向指定 URL 发送POST方法的请求
* *
* @param url 发送请求的 URL * @param url 发送请求的 URL
* @param param 请求参数,请求参数应该是 JSON String格式 的形式。 * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果 * @return 所代表远程资源的响应结果
*/ */
public static String sendPost(String url, String param) public static String sendPost(String url, String param)
{
return sendPost(url, param, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数
* @param contentType 内容类型
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param, String contentType)
{ {
PrintWriter out = null; PrintWriter out = null;
BufferedReader in = null; BufferedReader in = null;
@@ -136,9 +150,9 @@ public class HttpUtils
URLConnection conn = realUrl.openConnection(); URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
conn.setRequestProperty("Accept-Charset", "utf-8"); conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8"); conn.setRequestProperty("Content-Type", contentType);
conn.setDoOutput(true); conn.setDoOutput(true);
conn.setDoInput(true); conn.setDoInput(true);
out = new PrintWriter(conn.getOutputStream()); out = new PrintWriter(conn.getOutputStream());
@@ -190,6 +204,11 @@ public class HttpUtils
} }
public static String sendSSLPost(String url, String param) public static String sendSSLPost(String url, String param)
{
return sendSSLPost(url, param, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
}
public static String sendSSLPost(String url, String param, String contentType)
{ {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
String urlNameString = url + "?" + param; String urlNameString = url + "?" + param;
@@ -202,9 +221,9 @@ public class HttpUtils
HttpsURLConnection conn = (HttpsURLConnection) console.openConnection(); HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
conn.setRequestProperty("Accept-Charset", "utf-8"); conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8"); conn.setRequestProperty("Content-Type", contentType);
conn.setDoOutput(true); conn.setDoOutput(true);
conn.setDoInput(true); conn.setDoInput(true);

View File

@@ -2,7 +2,8 @@ package com.fastbee.common.utils.ip;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import javax.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import com.fastbee.common.utils.ServletUtils;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
/** /**
@@ -12,6 +13,23 @@ import com.fastbee.common.utils.StringUtils;
*/ */
public class IpUtils public class IpUtils
{ {
public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
// 匹配 ip
public final static String REGX_IP = "((" + REGX_0_255 + "\\.){3}" + REGX_0_255 + ")";
public final static String REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + REGX_0_255 + "(\\.\\*){3})|(" + REGX_0_255 + "\\." + REGX_0_255 + ")(\\.\\*){2}" + "|((" + REGX_0_255 + "\\.){3}\\*))";
// 匹配网段
public final static String REGX_IP_SEG = "(" + REGX_IP + "\\-" + REGX_IP + ")";
/**
* 获取客户端IP
*
* @return IP地址
*/
public static String getIpAddr()
{
return getIpAddr(ServletUtils.getRequest());
}
/** /**
* 获取客户端IP * 获取客户端IP
* *
@@ -248,7 +266,7 @@ public class IpUtils
} }
} }
} }
return ip; return StringUtils.substring(ip, 0, 255);
} }
/** /**
@@ -261,4 +279,104 @@ public class IpUtils
{ {
return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString); return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
} }
/**
* 是否为IP
*/
public static boolean isIP(String ip)
{
return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP);
}
/**
* 是否为IP或 *为间隔的通配符地址
*/
public static boolean isIpWildCard(String ip)
{
return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP_WILDCARD);
}
/**
* 检测参数是否在ip通配符里
*/
public static boolean ipIsInWildCardNoCheck(String ipWildCard, String ip)
{
String[] s1 = ipWildCard.split("\\.");
String[] s2 = ip.split("\\.");
boolean isMatchedSeg = true;
for (int i = 0; i < s1.length && !s1[i].equals("*"); i++)
{
if (!s1[i].equals(s2[i]))
{
isMatchedSeg = false;
break;
}
}
return isMatchedSeg;
}
/**
* 是否为特定格式如:“10.10.10.1-10.10.10.99”的ip段字符串
*/
public static boolean isIPSegment(String ipSeg)
{
return StringUtils.isNotBlank(ipSeg) && ipSeg.matches(REGX_IP_SEG);
}
/**
* 判断ip是否在指定网段中
*/
public static boolean ipIsInNetNoCheck(String iparea, String ip)
{
int idx = iparea.indexOf('-');
String[] sips = iparea.substring(0, idx).split("\\.");
String[] sipe = iparea.substring(idx + 1).split("\\.");
String[] sipt = ip.split("\\.");
long ips = 0L, ipe = 0L, ipt = 0L;
for (int i = 0; i < 4; ++i)
{
ips = ips << 8 | Integer.parseInt(sips[i]);
ipe = ipe << 8 | Integer.parseInt(sipe[i]);
ipt = ipt << 8 | Integer.parseInt(sipt[i]);
}
if (ips > ipe)
{
long t = ips;
ips = ipe;
ipe = t;
}
return ips <= ipt && ipt <= ipe;
}
/**
* 校验ip是否符合过滤串规则
*
* @param filter 过滤IP列表,支持后缀'*'通配,支持网段如:`10.10.10.1-10.10.10.99`
* @param ip 校验IP地址
* @return boolean 结果
*/
public static boolean isMatchedIp(String filter, String ip)
{
if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(ip))
{
return false;
}
String[] ips = filter.split(";");
for (String iStr : ips)
{
if (isIP(iStr) && iStr.equals(ip))
{
return true;
}
else if (isIpWildCard(iStr) && ipIsInWildCardNoCheck(iStr, ip))
{
return true;
}
else if (isIPSegment(iStr) && ipIsInNetNoCheck(iStr, ip))
{
return true;
}
}
return false;
}
} }

View File

@@ -1,5 +1,8 @@
package com.fastbee.common.utils.poi; package com.fastbee.common.utils.poi;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Workbook;
/** /**
* Excel数据格式处理适配器 * Excel数据格式处理适配器
* *
@@ -12,8 +15,10 @@ public interface ExcelHandlerAdapter
* *
* @param value 单元格数据值 * @param value 单元格数据值
* @param args excel注解args参数组 * @param args excel注解args参数组
* @param cell 单元格对象
* @param wb 工作簿对象
* *
* @return 处理后的值 * @return 处理后的值
*/ */
Object format(Object value, String[] args); Object format(Object value, String[] args, Cell cell, Workbook wb);
} }

View File

@@ -1,74 +1,5 @@
package com.fastbee.common.utils.poi; package com.fastbee.common.utils.poi;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFPicture;
import org.apache.poi.hssf.usermodel.HSSFPictureData;
import org.apache.poi.hssf.usermodel.HSSFShape;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Name;
import org.apache.poi.ss.usermodel.PictureData;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFPicture;
import org.apache.poi.xssf.usermodel.XSSFShape;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fastbee.common.annotation.Excel; import com.fastbee.common.annotation.Excel;
import com.fastbee.common.annotation.Excel.ColumnType; import com.fastbee.common.annotation.Excel.ColumnType;
import com.fastbee.common.annotation.Excel.Type; import com.fastbee.common.annotation.Excel.Type;
@@ -84,6 +15,32 @@ import com.fastbee.common.utils.file.FileTypeUtils;
import com.fastbee.common.utils.file.FileUtils; import com.fastbee.common.utils.file.FileUtils;
import com.fastbee.common.utils.file.ImageUtils; import com.fastbee.common.utils.file.ImageUtils;
import com.fastbee.common.utils.reflect.ReflectUtils; import com.fastbee.common.utils.reflect.ReflectUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.*;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
/** /**
* Excel相关处理 * Excel相关处理
@@ -94,10 +51,17 @@ public class ExcelUtil<T>
{ {
private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
public static final String SEPARATOR = ",";
public static final String FORMULA_REGEX_STR = "=|-|\\+|@"; public static final String FORMULA_REGEX_STR = "=|-|\\+|@";
public static final String[] FORMULA_STR = { "=", "-", "+", "@" }; public static final String[] FORMULA_STR = { "=", "-", "+", "@" };
/**
* 用于dictType属性数据存储避免重复查缓存
*/
public Map<String, String> sysDictMap = new HashMap<String, String>();
/** /**
* Excel sheet最大行数默认65536 * Excel sheet最大行数默认65536
*/ */
@@ -188,6 +152,11 @@ public class ExcelUtil<T>
*/ */
public Class<T> clazz; public Class<T> clazz;
/**
* 需要显示列属性
*/
public String[] includeFields;
/** /**
* 需要排除列属性 * 需要排除列属性
*/ */
@@ -198,11 +167,20 @@ public class ExcelUtil<T>
this.clazz = clazz; this.clazz = clazz;
} }
/**
* 仅在Excel中显示列属性
*
* @param fields 列属性名 示例[单个"name"/多个"id","name"]
*/
public void showColumn(String... fields)
{
this.includeFields = fields;
}
/** /**
* 隐藏Excel中列属性 * 隐藏Excel中列属性
* *
* @param fields 列属性名 示例[单个"name"/多个"id","name"] * @param fields 列属性名 示例[单个"name"/多个"id","name"]
* @throws Exception
*/ */
public void hideColumn(String... fields) public void hideColumn(String... fields)
{ {
@@ -232,8 +210,6 @@ public class ExcelUtil<T>
{ {
if (StringUtils.isNotEmpty(title)) if (StringUtils.isNotEmpty(title))
{ {
subMergedFirstRowNum++;
subMergedLastRowNum++;
int titleLastCol = this.fields.size() - 1; int titleLastCol = this.fields.size() - 1;
if (isSubList()) if (isSubList())
{ {
@@ -244,7 +220,7 @@ public class ExcelUtil<T>
Cell titleCell = titleRow.createCell(0); Cell titleCell = titleRow.createCell(0);
titleCell.setCellStyle(styles.get("title")); titleCell.setCellStyle(styles.get("title"));
titleCell.setCellValue(title); titleCell.setCellValue(title);
sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(), titleLastCol)); sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), 0, titleLastCol));
} }
} }
@@ -255,23 +231,31 @@ public class ExcelUtil<T>
{ {
if (isSubList()) if (isSubList())
{ {
subMergedFirstRowNum++;
subMergedLastRowNum++;
Row subRow = sheet.createRow(rownum); Row subRow = sheet.createRow(rownum);
int excelNum = 0; int column = 0;
int subFieldSize = subFields != null ? subFields.size() : 0;
for (Object[] objects : fields) for (Object[] objects : fields)
{ {
Field field = (Field) objects[0];
Excel attr = (Excel) objects[1]; Excel attr = (Excel) objects[1];
Cell headCell1 = subRow.createCell(excelNum); if (Collection.class.isAssignableFrom(field.getType()))
headCell1.setCellValue(attr.name()); {
headCell1.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); Cell cell = subRow.createCell(column);
excelNum++; cell.setCellValue(attr.name());
} cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
int headFirstRow = excelNum - 1; if (subFieldSize > 1)
int headLastRow = headFirstRow + subFields.size() - 1; {
if (headLastRow > headFirstRow) CellRangeAddress cellAddress = new CellRangeAddress(rownum, rownum, column, column + subFieldSize - 1);
{ sheet.addMergedRegion(cellAddress);
sheet.addMergedRegion(new CellRangeAddress(rownum, rownum, headFirstRow, headLastRow)); }
column += subFieldSize;
}
else
{
Cell cell = subRow.createCell(column++);
cell.setCellValue(attr.name());
cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
}
} }
rownum++; rownum++;
} }
@@ -283,7 +267,7 @@ public class ExcelUtil<T>
* @param is 输入流 * @param is 输入流
* @return 转换后集合 * @return 转换后集合
*/ */
public List<T> importExcel(InputStream is) throws Exception public List<T> importExcel(InputStream is)
{ {
return importExcel(is, 0); return importExcel(is, 0);
} }
@@ -295,9 +279,23 @@ public class ExcelUtil<T>
* @param titleNum 标题占用行数 * @param titleNum 标题占用行数
* @return 转换后集合 * @return 转换后集合
*/ */
public List<T> importExcel(InputStream is, int titleNum) throws Exception public List<T> importExcel(InputStream is, int titleNum)
{ {
return importExcel(StringUtils.EMPTY, is, titleNum); List<T> list = null;
try
{
list = importExcel(StringUtils.EMPTY, is, titleNum);
}
catch (Exception e)
{
log.error("导入Excel异常{}", e.getMessage());
throw new UtilException(e.getMessage());
}
finally
{
IOUtils.closeQuietly(is);
}
return list;
} }
/** /**
@@ -320,7 +318,7 @@ public class ExcelUtil<T>
throw new IOException("文件sheet不存在"); throw new IOException("文件sheet不存在");
} }
boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook); boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook);
Map<String, PictureData> pictures; Map<String, List<PictureData>> pictures = null;
if (isXSSFWorkbook) if (isXSSFWorkbook)
{ {
pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb); pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb);
@@ -331,7 +329,6 @@ public class ExcelUtil<T>
} }
// 获取最后一个非空行的行下标比如总行数为n则返回的为n-1 // 获取最后一个非空行的行下标比如总行数为n则返回的为n-1
int rows = sheet.getLastRowNum(); int rows = sheet.getLastRowNum();
if (rows > 0) if (rows > 0)
{ {
// 定义一个map用于存放excel列的序号和field. // 定义一个map用于存放excel列的序号和field.
@@ -446,30 +443,34 @@ public class ExcelUtil<T>
{ {
propertyName = field.getName() + "." + attr.targetAttr(); propertyName = field.getName() + "." + attr.targetAttr();
} }
else if (StringUtils.isNotEmpty(attr.readConverterExp())) if (StringUtils.isNotEmpty(attr.readConverterExp()))
{ {
val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());
} }
else if (StringUtils.isNotEmpty(attr.dictType())) else if (StringUtils.isNotEmpty(attr.dictType()))
{ {
val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator()); if (!sysDictMap.containsKey(attr.dictType() + val))
{
String dictValue = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator());
sysDictMap.put(attr.dictType() + val, dictValue);
}
val = sysDictMap.get(attr.dictType() + val);
} }
else if (!attr.handler().equals(ExcelHandlerAdapter.class)) else if (!attr.handler().equals(ExcelHandlerAdapter.class))
{ {
val = dataFormatHandlerAdapter(val, attr); val = dataFormatHandlerAdapter(val, attr, null);
} }
else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures)) else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures))
{ {
PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey()); StringBuilder propertyString = new StringBuilder();
if (image == null) List<PictureData> images = pictures.get(row.getRowNum() + "_" + entry.getKey());
for (PictureData picture : images)
{ {
val = ""; byte[] data = picture.getData();
} String fileName = FileUtils.writeImportBytes(data);
else propertyString.append(fileName).append(SEPARATOR);
{
byte[] data = image.getData();
val = FileUtils.writeImportBytes(data);
} }
val = StringUtils.stripEnd(propertyString.toString(), SEPARATOR);
} }
ReflectUtils.invokeSetter(entity, propertyName, val); ReflectUtils.invokeSetter(entity, propertyName, val);
} }
@@ -687,64 +688,91 @@ public class ExcelUtil<T>
{ {
int startNo = index * sheetSize; int startNo = index * sheetSize;
int endNo = Math.min(startNo + sheetSize, list.size()); int endNo = Math.min(startNo + sheetSize, list.size());
int rowNo = (1 + rownum) - startNo; int currentRowNum = rownum + 1; // 从标题行后开始
for (int i = startNo; i < endNo; i++) for (int i = startNo; i < endNo; i++)
{ {
rowNo = isSubList() ? (i > 1 ? rowNo + 1 : rowNo + i) : i + 1 + rownum - startNo; row = sheet.createRow(currentRowNum);
row = sheet.createRow(rowNo);
// 得到导出对象.
T vo = (T) list.get(i); T vo = (T) list.get(i);
Collection<?> subList = null;
if (isSubList())
{
if (isSubListValue(vo))
{
subList = getListCellValue(vo);
subMergedLastRowNum = subMergedLastRowNum + subList.size();
}
else
{
subMergedFirstRowNum++;
subMergedLastRowNum++;
}
}
int column = 0; int column = 0;
int maxSubListSize = getCurrentMaxSubListSize(vo);
for (Object[] os : fields) for (Object[] os : fields)
{ {
Field field = (Field) os[0]; Field field = (Field) os[0];
Excel excel = (Excel) os[1]; Excel excel = (Excel) os[1];
if (Collection.class.isAssignableFrom(field.getType()) && StringUtils.isNotNull(subList)) if (Collection.class.isAssignableFrom(field.getType()))
{ {
boolean subFirst = false; try
for (Object obj : subList)
{ {
if (subFirst) Collection<?> subList = (Collection<?>) getTargetValue(vo, field, excel);
if (subList != null && !subList.isEmpty())
{ {
rowNo++; int subIndex = 0;
row = sheet.createRow(rowNo); for (Object subVo : subList)
}
List<Field> subFields = FieldUtils.getFieldsListWithAnnotation(obj.getClass(), Excel.class);
int subIndex = 0;
for (Field subField : subFields)
{
if (subField.isAnnotationPresent(Excel.class))
{ {
subField.setAccessible(true); Row subRow = sheet.getRow(currentRowNum + subIndex);
Excel attr = subField.getAnnotation(Excel.class); if (subRow == null)
this.addCell(attr, row, (T) obj, subField, column + subIndex); {
subRow = sheet.createRow(currentRowNum + subIndex);
}
int subColumn = column;
for (Field subField : subFields)
{
Excel subExcel = subField.getAnnotation(Excel.class);
addCell(subExcel, subRow, (T) subVo, subField, subColumn++);
}
subIndex++;
} }
subIndex++; column += subFields.size();
} }
subFirst = true;
} }
this.subMergedFirstRowNum = this.subMergedFirstRowNum + subList.size(); catch (Exception e)
{
log.error("填充集合数据失败", e);
}
} }
else else
{ {
this.addCell(excel, row, vo, field, column++); // 创建单元格并设置值
addCell(excel, row, vo, field, column);
if (maxSubListSize > 1 && excel.needMerge())
{
sheet.addMergedRegion(new CellRangeAddress(currentRowNum, currentRowNum + maxSubListSize - 1, column, column));
}
column++;
}
}
currentRowNum += maxSubListSize;
}
}
/**
* 获取子列表最大数
*/
private int getCurrentMaxSubListSize(T vo)
{
int maxSubListSize = 1;
for (Object[] os : fields)
{
Field field = (Field) os[0];
if (Collection.class.isAssignableFrom(field.getType()))
{
try
{
Collection<?> subList = (Collection<?>) getTargetValue(vo, field, (Excel) os[1]);
if (subList != null && !subList.isEmpty())
{
maxSubListSize = Math.max(maxSubListSize, subList.size());
}
}
catch (Exception e)
{
log.error("获取集合大小失败", e);
} }
} }
} }
return maxSubListSize;
} }
/** /**
@@ -765,6 +793,8 @@ public class ExcelUtil<T>
titleFont.setFontHeightInPoints((short) 16); titleFont.setFontHeightInPoints((short) 16);
titleFont.setBold(true); titleFont.setBold(true);
style.setFont(titleFont); style.setFont(titleFont);
DataFormat dataFormat = wb.createDataFormat();
style.setDataFormat(dataFormat.getFormat("@"));
styles.put("title", style); styles.put("title", style);
style = wb.createCellStyle(); style = wb.createCellStyle();
@@ -827,6 +857,9 @@ public class ExcelUtil<T>
headerFont.setBold(true); headerFont.setBold(true);
headerFont.setColor(excel.headerColor().index); headerFont.setColor(excel.headerColor().index);
style.setFont(headerFont); style.setFont(headerFont);
// 设置表格头单元格文本形式
DataFormat dataFormat = wb.createDataFormat();
style.setDataFormat(dataFormat.getFormat("@"));
headerStyles.put(key, style); headerStyles.put(key, style);
} }
} }
@@ -844,34 +877,67 @@ public class ExcelUtil<T>
Map<String, CellStyle> styles = new HashMap<String, CellStyle>(); Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
for (Object[] os : fields) for (Object[] os : fields)
{ {
Field field = (Field) os[0];
Excel excel = (Excel) os[1]; Excel excel = (Excel) os[1];
String key = StringUtils.format("data_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor()); if (Collection.class.isAssignableFrom(field.getType()))
if (!styles.containsKey(key))
{ {
CellStyle style = wb.createCellStyle(); ParameterizedType pt = (ParameterizedType) field.getGenericType();
style.setAlignment(excel.align()); Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];
style.setVerticalAlignment(VerticalAlignment.CENTER); List<Field> subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class);
style.setBorderRight(BorderStyle.THIN); for (Field subField : subFields)
style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); {
style.setBorderLeft(BorderStyle.THIN); Excel subExcel = subField.getAnnotation(Excel.class);
style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); annotationDataStyles(styles, subField, subExcel);
style.setBorderTop(BorderStyle.THIN); }
style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); }
style.setBorderBottom(BorderStyle.THIN); else
style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); {
style.setFillPattern(FillPatternType.SOLID_FOREGROUND); annotationDataStyles(styles, field, excel);
style.setFillForegroundColor(excel.backgroundColor().getIndex());
Font dataFont = wb.createFont();
dataFont.setFontName("Arial");
dataFont.setFontHeightInPoints((short) 10);
dataFont.setColor(excel.color().index);
style.setFont(dataFont);
styles.put(key, style);
} }
} }
return styles; return styles;
} }
/**
* 根据Excel注解创建表格列样式
*
* @param styles 自定义样式列表
* @param field 属性列信息
* @param excel 注解信息
*/
public void annotationDataStyles(Map<String, CellStyle> styles, Field field, Excel excel)
{
String key = StringUtils.format("data_{}_{}_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor(), excel.cellType(), excel.wrapText());
if (!styles.containsKey(key))
{
CellStyle style = wb.createCellStyle();
style.setAlignment(excel.align());
style.setVerticalAlignment(VerticalAlignment.CENTER);
style.setBorderRight(BorderStyle.THIN);
style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setBorderLeft(BorderStyle.THIN);
style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setBorderTop(BorderStyle.THIN);
style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setBorderBottom(BorderStyle.THIN);
style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
style.setFillForegroundColor(excel.backgroundColor().getIndex());
style.setWrapText(excel.wrapText());
Font dataFont = wb.createFont();
dataFont.setFontName("Arial");
dataFont.setFontHeightInPoints((short) 10);
dataFont.setColor(excel.color().index);
style.setFont(dataFont);
if (ColumnType.TEXT == excel.cellType())
{
DataFormat dataFormat = wb.createDataFormat();
style.setDataFormat(dataFormat.getFormat("@"));
}
styles.put(key, style);
}
}
/** /**
* 创建单元格 * 创建单元格
*/ */
@@ -886,7 +952,7 @@ public class ExcelUtil<T>
if (isSubList()) if (isSubList())
{ {
// 填充默认样式,防止合并单元格样式失效 // 填充默认样式,防止合并单元格样式失效
sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor()))); sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
if (attr.needMerge()) if (attr.needMerge())
{ {
sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column)); sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column));
@@ -904,7 +970,7 @@ public class ExcelUtil<T>
*/ */
public void setCellVo(Object value, Excel attr, Cell cell) public void setCellVo(Object value, Excel attr, Cell cell)
{ {
if (ColumnType.STRING == attr.cellType()) if (ColumnType.STRING == attr.cellType() || ColumnType.TEXT == attr.cellType())
{ {
String cellValue = Convert.toStr(value); String cellValue = Convert.toStr(value);
// 对于任何以表达式触发字符 =-+@开头的单元格直接使用tab字符作为前缀防止CSV注入。 // 对于任何以表达式触发字符 =-+@开头的单元格直接使用tab字符作为前缀防止CSV注入。
@@ -928,12 +994,15 @@ public class ExcelUtil<T>
else if (ColumnType.IMAGE == attr.cellType()) else if (ColumnType.IMAGE == attr.cellType())
{ {
ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1); ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1);
String imagePath = Convert.toStr(value); String propertyValue = Convert.toStr(value);
if (StringUtils.isNotEmpty(imagePath)) if (StringUtils.isNotEmpty(propertyValue))
{ {
byte[] data = ImageUtils.getImage(imagePath); List<String> imagePaths = StringUtils.str2List(propertyValue, SEPARATOR);
getDrawingPatriarch(cell.getSheet()).createPicture(anchor, for (String imagePath : imagePaths)
cell.getSheet().getWorkbook().addPicture(data, getImageType(data))); {
byte[] data = ImageUtils.getImage(imagePath);
getDrawingPatriarch(cell.getSheet()).createPicture(anchor, cell.getSheet().getWorkbook().addPicture(data, getImageType(data)));
}
} }
} }
} }
@@ -981,17 +1050,28 @@ public class ExcelUtil<T>
// 设置列宽 // 设置列宽
sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
} }
if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0) if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0 || attr.comboReadDict())
{ {
if (attr.combo().length > 15 || StringUtils.join(attr.combo()).length() > 255) String[] comboArray = attr.combo();
if (attr.comboReadDict())
{
if (!sysDictMap.containsKey("combo_" + attr.dictType()))
{
String labels = DictUtils.getDictLabels(attr.dictType());
sysDictMap.put("combo_" + attr.dictType(), labels);
}
String val = sysDictMap.get("combo_" + attr.dictType());
comboArray = StringUtils.split(val, DictUtils.SEPARATOR);
}
if (comboArray.length > 15 || StringUtils.join(comboArray).length() > 255)
{ {
// 如果下拉数大于15或字符串长度大于255则使用一个新sheet存储避免生成的模板下拉值获取不到 // 如果下拉数大于15或字符串长度大于255则使用一个新sheet存储避免生成的模板下拉值获取不到
setXSSFValidationWithHidden(sheet, attr.combo(), attr.prompt(), 1, 100, column, column); setXSSFValidationWithHidden(sheet, comboArray, attr.prompt(), 1, 100, column, column);
} }
else else
{ {
// 提示信息或只能选择不能输入的列内容. // 提示信息或只能选择不能输入的列内容.
setPromptOrValidation(sheet, attr.combo(), attr.prompt(), 1, 100, column, column); setPromptOrValidation(sheet, comboArray, attr.prompt(), 1, 100, column, column);
} }
} }
} }
@@ -1013,10 +1093,12 @@ public class ExcelUtil<T>
cell = row.createCell(column); cell = row.createCell(column);
if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge()) if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge())
{ {
CellRangeAddress cellAddress = new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column); if (subMergedLastRowNum >= subMergedFirstRowNum)
sheet.addMergedRegion(cellAddress); {
sheet.addMergedRegion(new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column));
}
} }
cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor()))); cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
// 用于读取对象中的属性 // 用于读取对象中的属性
Object value = getTargetValue(vo, field, attr); Object value = getTargetValue(vo, field, attr);
@@ -1026,6 +1108,7 @@ public class ExcelUtil<T>
String dictType = attr.dictType(); String dictType = attr.dictType();
if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
{ {
cell.getCellStyle().setDataFormat(this.wb.getCreationHelper().createDataFormat().getFormat(dateFormat));
cell.setCellValue(parseDateToStr(dateFormat, value)); cell.setCellValue(parseDateToStr(dateFormat, value));
} }
else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))
@@ -1034,7 +1117,12 @@ public class ExcelUtil<T>
} }
else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value)) else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value))
{ {
cell.setCellValue(convertDictByExp(Convert.toStr(value), dictType, separator)); if (!sysDictMap.containsKey(dictType + value))
{
String lable = convertDictByExp(Convert.toStr(value), dictType, separator);
sysDictMap.put(dictType + value, lable);
}
cell.setCellValue(sysDictMap.get(dictType + value));
} }
else if (value instanceof BigDecimal && -1 != attr.scale()) else if (value instanceof BigDecimal && -1 != attr.scale())
{ {
@@ -1042,7 +1130,7 @@ public class ExcelUtil<T>
} }
else if (!attr.handler().equals(ExcelHandlerAdapter.class)) else if (!attr.handler().equals(ExcelHandlerAdapter.class))
{ {
cell.setCellValue(dataFormatHandlerAdapter(value, attr)); cell.setCellValue(dataFormatHandlerAdapter(value, attr, cell));
} }
else else
{ {
@@ -1159,7 +1247,7 @@ public class ExcelUtil<T>
public static String convertByExp(String propertyValue, String converterExp, String separator) public static String convertByExp(String propertyValue, String converterExp, String separator)
{ {
StringBuilder propertyString = new StringBuilder(); StringBuilder propertyString = new StringBuilder();
String[] convertSource = converterExp.split(","); String[] convertSource = converterExp.split(SEPARATOR);
for (String item : convertSource) for (String item : convertSource)
{ {
String[] itemArray = item.split("="); String[] itemArray = item.split("=");
@@ -1196,7 +1284,7 @@ public class ExcelUtil<T>
public static String reverseByExp(String propertyValue, String converterExp, String separator) public static String reverseByExp(String propertyValue, String converterExp, String separator)
{ {
StringBuilder propertyString = new StringBuilder(); StringBuilder propertyString = new StringBuilder();
String[] convertSource = converterExp.split(","); String[] convertSource = converterExp.split(SEPARATOR);
for (String item : convertSource) for (String item : convertSource)
{ {
String[] itemArray = item.split("="); String[] itemArray = item.split("=");
@@ -1255,13 +1343,13 @@ public class ExcelUtil<T>
* @param excel 数据注解 * @param excel 数据注解
* @return * @return
*/ */
public String dataFormatHandlerAdapter(Object value, Excel excel) public String dataFormatHandlerAdapter(Object value, Excel excel, Cell cell)
{ {
try try
{ {
Object instance = excel.handler().newInstance(); Object instance = excel.handler().newInstance();
Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class }); Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class, Cell.class, Workbook.class });
value = formatMethod.invoke(instance, value, excel.args()); value = formatMethod.invoke(instance, value, excel.args(), cell, this.wb);
} }
catch (Exception e) catch (Exception e)
{ {
@@ -1321,8 +1409,7 @@ public class ExcelUtil<T>
*/ */
public String encodingFilename(String filename) public String encodingFilename(String filename)
{ {
filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx"; return UUID.randomUUID() + "_" + filename + ".xlsx";
return filename;
} }
/** /**
@@ -1352,6 +1439,7 @@ public class ExcelUtil<T>
*/ */
private Object getTargetValue(T vo, Field field, Excel excel) throws Exception private Object getTargetValue(T vo, Field field, Excel excel) throws Exception
{ {
field.setAccessible(true);
Object o = field.get(vo); Object o = field.get(vo);
if (StringUtils.isNotEmpty(excel.targetAttr())) if (StringUtils.isNotEmpty(excel.targetAttr()))
{ {
@@ -1411,45 +1499,83 @@ public class ExcelUtil<T>
List<Field> tempFields = new ArrayList<>(); List<Field> tempFields = new ArrayList<>();
tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
for (Field field : tempFields) if (StringUtils.isNotEmpty(includeFields))
{ {
if (!ArrayUtils.contains(this.excludeFields, field.getName())) for (Field field : tempFields)
{ {
// 单注解 if (ArrayUtils.contains(this.includeFields, field.getName()) || field.isAnnotationPresent(Excels.class))
if (field.isAnnotationPresent(Excel.class))
{ {
Excel attr = field.getAnnotation(Excel.class); addField(fields, field);
if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) }
}
}
else if (StringUtils.isNotEmpty(excludeFields))
{
for (Field field : tempFields)
{
if (!ArrayUtils.contains(this.excludeFields, field.getName()))
{
addField(fields, field);
}
}
}
else
{
for (Field field : tempFields)
{
addField(fields, field);
}
}
return fields;
}
/**
* 添加字段信息
*/
public void addField(List<Object[]> fields, Field field)
{
// 单注解
if (field.isAnnotationPresent(Excel.class))
{
Excel attr = field.getAnnotation(Excel.class);
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{
fields.add(new Object[] { field, attr });
}
if (Collection.class.isAssignableFrom(field.getType()))
{
subMethod = getSubMethod(field.getName(), clazz);
ParameterizedType pt = (ParameterizedType) field.getGenericType();
Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];
this.subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class);
}
}
// 多注解
if (field.isAnnotationPresent(Excels.class))
{
Excels attrs = field.getAnnotation(Excels.class);
Excel[] excels = attrs.value();
for (Excel attr : excels)
{
if (StringUtils.isNotEmpty(includeFields))
{
if (ArrayUtils.contains(this.includeFields, field.getName() + "." + attr.targetAttr())
&& (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
{ {
field.setAccessible(true);
fields.add(new Object[] { field, attr }); fields.add(new Object[] { field, attr });
} }
if (Collection.class.isAssignableFrom(field.getType()))
{
subMethod = getSubMethod(field.getName(), clazz);
ParameterizedType pt = (ParameterizedType) field.getGenericType();
Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];
this.subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class);
}
} }
else
// 多注解
if (field.isAnnotationPresent(Excels.class))
{ {
Excels attrs = field.getAnnotation(Excels.class); if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr())
Excel[] excels = attrs.value(); && (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
for (Excel attr : excels)
{ {
if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) fields.add(new Object[] { field, attr });
{
field.setAccessible(true);
fields.add(new Object[] { field, attr });
}
} }
} }
} }
} }
return fields;
} }
/** /**
@@ -1584,30 +1710,24 @@ public class ExcelUtil<T>
* @param workbook 工作簿对象 * @param workbook 工作簿对象
* @return Map key:图片单元格索引1_1Stringvalue:图片流PictureData * @return Map key:图片单元格索引1_1Stringvalue:图片流PictureData
*/ */
public static Map<String, PictureData> getSheetPictures03(HSSFSheet sheet, HSSFWorkbook workbook) public static Map<String, List<PictureData>> getSheetPictures03(HSSFSheet sheet, HSSFWorkbook workbook)
{ {
Map<String, PictureData> sheetIndexPicMap = new HashMap<String, PictureData>(); Map<String, List<PictureData>> sheetIndexPicMap = new HashMap<>();
List<HSSFPictureData> pictures = workbook.getAllPictures(); List<HSSFPictureData> pictures = workbook.getAllPictures();
if (!pictures.isEmpty()) if (!pictures.isEmpty() && sheet.getDrawingPatriarch() != null)
{ {
for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren()) for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren())
{ {
HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor();
if (shape instanceof HSSFPicture) if (shape instanceof HSSFPicture)
{ {
HSSFPicture pic = (HSSFPicture) shape; HSSFPicture pic = (HSSFPicture) shape;
int pictureIndex = pic.getPictureIndex() - 1; HSSFClientAnchor anchor = (HSSFClientAnchor) pic.getAnchor();
HSSFPictureData picData = pictures.get(pictureIndex); String picIndex = anchor.getRow1() + "_" + anchor.getCol1();
String picIndex = String.valueOf(anchor.getRow1()) + "_" + String.valueOf(anchor.getCol1()); sheetIndexPicMap.computeIfAbsent(picIndex, k -> new ArrayList<>()).add(pic.getPictureData());
sheetIndexPicMap.put(picIndex, picData);
} }
} }
return sheetIndexPicMap;
}
else
{
return sheetIndexPicMap;
} }
return sheetIndexPicMap;
} }
/** /**
@@ -1617,16 +1737,15 @@ public class ExcelUtil<T>
* @param workbook 工作簿对象 * @param workbook 工作簿对象
* @return Map key:图片单元格索引1_1Stringvalue:图片流PictureData * @return Map key:图片单元格索引1_1Stringvalue:图片流PictureData
*/ */
public static Map<String, PictureData> getSheetPictures07(XSSFSheet sheet, XSSFWorkbook workbook) public static Map<String, List<PictureData>> getSheetPictures07(XSSFSheet sheet, XSSFWorkbook workbook)
{ {
Map<String, PictureData> sheetIndexPicMap = new HashMap<String, PictureData>(); Map<String, List<PictureData>> sheetIndexPicMap = new HashMap<>();
for (POIXMLDocumentPart dr : sheet.getRelations()) for (POIXMLDocumentPart dr : sheet.getRelations())
{ {
if (dr instanceof XSSFDrawing) if (dr instanceof XSSFDrawing)
{ {
XSSFDrawing drawing = (XSSFDrawing) dr; XSSFDrawing drawing = (XSSFDrawing) dr;
List<XSSFShape> shapes = drawing.getShapes(); for (XSSFShape shape : drawing.getShapes())
for (XSSFShape shape : shapes)
{ {
if (shape instanceof XSSFPicture) if (shape instanceof XSSFPicture)
{ {
@@ -1634,7 +1753,7 @@ public class ExcelUtil<T>
XSSFClientAnchor anchor = pic.getPreferredSize(); XSSFClientAnchor anchor = pic.getPreferredSize();
CTMarker ctMarker = anchor.getFrom(); CTMarker ctMarker = anchor.getFrom();
String picIndex = ctMarker.getRow() + "_" + ctMarker.getCol(); String picIndex = ctMarker.getRow() + "_" + ctMarker.getCol();
sheetIndexPicMap.put(picIndex, pic.getPictureData()); sheetIndexPicMap.computeIfAbsent(picIndex, k -> new ArrayList<>()).add(pic.getPictureData());
} }
} }
} }

View File

@@ -1,5 +1,6 @@
package com.fastbee.common.utils.spring; package com.fastbee.common.utils.spring;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.AopContext; import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@@ -126,7 +127,12 @@ public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationC
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> T getAopProxy(T invoker) public static <T> T getAopProxy(T invoker)
{ {
return (T) AopContext.currentProxy(); Object proxy = AopContext.currentProxy();
if (((Advised) proxy).getTargetSource().getTargetClass() == invoker.getClass())
{
return (T) proxy;
}
return invoker;
} }
/** /**

View File

@@ -13,13 +13,18 @@ public class SqlUtil
/** /**
* 定义常用的 sql关键字 * 定义常用的 sql关键字
*/ */
public static String SQL_REGEX = "and |extractvalue|updatexml|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |+|user()"; public static String SQL_REGEX = "\u000B|and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()";
/** /**
* 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
*/ */
public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+"; public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
/**
* 限制orderBy最大长度
*/
private static final int ORDER_BY_MAX_LENGTH = 500;
/** /**
* 检查字符,防止注入绕过 * 检查字符,防止注入绕过
*/ */
@@ -29,6 +34,10 @@ public class SqlUtil
{ {
throw new UtilException("参数不符合规范,不能进行查询"); throw new UtilException("参数不符合规范,不能进行查询");
} }
if (StringUtils.length(value) > ORDER_BY_MAX_LENGTH)
{
throw new UtilException("参数已超过最大限制,不能进行查询");
}
return value; return value;
} }

View File

@@ -22,7 +22,7 @@ public class Seq
private static AtomicInteger uploadSeq = new AtomicInteger(1); private static AtomicInteger uploadSeq = new AtomicInteger(1);
// 机器标识 // 机器标识
private static String machineCode = "A"; private static final String machineCode = "A";
/** /**
* 获取通用序列号 * 获取通用序列号

View File

@@ -1,7 +1,7 @@
package com.fastbee.common.xss; package com.fastbee.common.xss;
import javax.validation.Constraint; import jakarta.validation.Constraint;
import javax.validation.Payload; import jakarta.validation.Payload;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;

View File

@@ -1,8 +1,8 @@
package com.fastbee.common.xss; package com.fastbee.common.xss;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
import javax.validation.ConstraintValidator; import jakarta.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext; import jakarta.validation.ConstraintValidatorContext;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -27,8 +27,13 @@ public class XssValidator implements ConstraintValidator<Xss, String>
public static boolean containsHtml(String value) public static boolean containsHtml(String value)
{ {
StringBuilder sHtml = new StringBuilder();
Pattern pattern = Pattern.compile(HTML_PATTERN); Pattern pattern = Pattern.compile(HTML_PATTERN);
Matcher matcher = pattern.matcher(value); Matcher matcher = pattern.matcher(value);
return matcher.matches(); while (matcher.find())
{
sHtml.append(matcher.group());
}
return pattern.matcher(sHtml).matches();
} }
} }

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>fastbee</artifactId> <artifactId>fastbee</artifactId>
<groupId>com.fastbee</groupId> <groupId>com.fastbee</groupId>
<version>3.8.5</version> <version>${fastbee.version}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -16,6 +16,10 @@
</description> </description>
<dependencies> <dependencies>
<dependency>
<groupId>com.fastbee</groupId>
<artifactId>fastbee-common</artifactId>
</dependency>
<!-- SpringBoot Web容器 --> <!-- SpringBoot Web容器 -->
<dependency> <dependency>
@@ -38,7 +42,7 @@
<!-- 阿里数据库连接池 --> <!-- 阿里数据库连接池 -->
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId> <artifactId>druid-spring-boot-3-starter</artifactId>
</dependency> </dependency>
<!-- 验证码 --> <!-- 验证码 -->
@@ -59,6 +63,18 @@
<artifactId>oshi-core</artifactId> <artifactId>oshi-core</artifactId>
</dependency> </dependency>
<!-- 动态数据源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>${dynamic-datasource.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-jsqlparser</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -7,6 +7,7 @@ import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.fastbee.common.annotation.DataScope; import com.fastbee.common.annotation.DataScope;
import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.domain.BaseEntity; import com.fastbee.common.core.domain.BaseEntity;
import com.fastbee.common.core.domain.entity.SysRole; import com.fastbee.common.core.domain.entity.SysRole;
import com.fastbee.common.core.domain.entity.SysUser; import com.fastbee.common.core.domain.entity.SysUser;
@@ -73,8 +74,7 @@ public class DataScopeAspect
if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin())
{ {
String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), PermissionContextHolder.getContext()); String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), PermissionContextHolder.getContext());
dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), controllerDataScope.userAlias(), permission);
controllerDataScope.userAlias(), permission);
} }
} }
} }
@@ -92,29 +92,42 @@ public class DataScopeAspect
{ {
StringBuilder sqlString = new StringBuilder(); StringBuilder sqlString = new StringBuilder();
List<String> conditions = new ArrayList<String>(); List<String> conditions = new ArrayList<String>();
List<String> scopeCustomIds = new ArrayList<String>();
user.getRoles().forEach(role -> {
if (DATA_SCOPE_CUSTOM.equals(role.getDataScope()) && StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL) && StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
{
scopeCustomIds.add(Convert.toStr(role.getRoleId()));
}
});
for (SysRole role : user.getRoles()) for (SysRole role : user.getRoles())
{ {
String dataScope = role.getDataScope(); String dataScope = role.getDataScope();
if (!DATA_SCOPE_CUSTOM.equals(dataScope) && conditions.contains(dataScope)) if (conditions.contains(dataScope) || StringUtils.equals(role.getStatus(), UserConstants.ROLE_DISABLE))
{ {
continue; continue;
} }
if (StringUtils.isNotEmpty(permission) && StringUtils.isNotEmpty(role.getPermissions()) if (!StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
&& !StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
{ {
continue; continue;
} }
if (DATA_SCOPE_ALL.equals(dataScope)) if (DATA_SCOPE_ALL.equals(dataScope))
{ {
sqlString = new StringBuilder(); sqlString = new StringBuilder();
conditions.add(dataScope);
break; break;
} }
else if (DATA_SCOPE_CUSTOM.equals(dataScope)) else if (DATA_SCOPE_CUSTOM.equals(dataScope))
{ {
sqlString.append(StringUtils.format( if (scopeCustomIds.size() > 1)
" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias, {
role.getRoleId())); // 多个自定数据权限使用in查询避免多次拼接。
sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id in ({}) ) ", deptAlias, String.join(",", scopeCustomIds)));
}
else
{
sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias, role.getRoleId()));
}
} }
else if (DATA_SCOPE_DEPT.equals(dataScope)) else if (DATA_SCOPE_DEPT.equals(dataScope))
{ {
@@ -122,9 +135,7 @@ public class DataScopeAspect
} }
else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
{ {
sqlString.append(StringUtils.format( sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )", deptAlias, user.getDeptId(), user.getDeptId()));
" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
deptAlias, user.getDeptId(), user.getDeptId()));
} }
else if (DATA_SCOPE_SELF.equals(dataScope)) else if (DATA_SCOPE_SELF.equals(dataScope))
{ {
@@ -141,6 +152,12 @@ public class DataScopeAspect
conditions.add(dataScope); conditions.add(dataScope);
} }
// 角色都不包含传递过来的权限字符这个时候sqlString也会为空所以要限制一下,不查询任何数据
if (StringUtils.isEmpty(conditions))
{
sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));
}
if (StringUtils.isNotBlank(sqlString.toString())) if (StringUtils.isNotBlank(sqlString.toString()))
{ {
Object params = joinPoint.getArgs()[0]; Object params = joinPoint.getArgs()[0];

View File

@@ -1,24 +1,14 @@
package com.fastbee.framework.aspectj; package com.fastbee.framework.aspectj;
import java.util.Collection;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.fastbee.common.annotation.Log; import com.fastbee.common.annotation.Log;
import com.fastbee.common.core.domain.entity.SysUser;
import com.fastbee.common.core.domain.model.LoginUser; import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.core.text.Convert;
import com.fastbee.common.enums.BusinessStatus; import com.fastbee.common.enums.BusinessStatus;
import com.fastbee.common.enums.HttpMethod; import com.fastbee.common.enums.HttpMethod;
import com.fastbee.common.filter.PropertyPreExcludeFilter; import com.fastbee.common.filter.PropertyPreExcludeFilter;
import com.fastbee.common.utils.ExceptionUtil;
import com.fastbee.common.utils.SecurityUtils; import com.fastbee.common.utils.SecurityUtils;
import com.fastbee.common.utils.ServletUtils; import com.fastbee.common.utils.ServletUtils;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
@@ -26,6 +16,23 @@ import com.fastbee.common.utils.ip.IpUtils;
import com.fastbee.framework.manager.AsyncManager; import com.fastbee.framework.manager.AsyncManager;
import com.fastbee.framework.manager.factory.AsyncFactory; import com.fastbee.framework.manager.factory.AsyncFactory;
import com.fastbee.system.domain.SysOperLog; import com.fastbee.system.domain.SysOperLog;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.NamedThreadLocal;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.Map;
/** /**
* 操作日志记录处理 * 操作日志记录处理
@@ -41,6 +48,18 @@ public class LogAspect
/** 排除敏感属性字段 */ /** 排除敏感属性字段 */
public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" }; public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };
/** 计算操作消耗时间 */
private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>("Cost Time");
/**
* 处理请求前执行
*/
@Before(value = "@annotation(controllerLog)")
public void doBefore(JoinPoint joinPoint, Log controllerLog)
{
TIME_THREADLOCAL.set(System.currentTimeMillis());
}
/** /**
* 处理完请求后执行 * 处理完请求后执行
* *
@@ -75,18 +94,23 @@ public class LogAspect
SysOperLog operLog = new SysOperLog(); SysOperLog operLog = new SysOperLog();
operLog.setStatus(BusinessStatus.SUCCESS.ordinal()); operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
// 请求的地址 // 请求的地址
String ip = IpUtils.getIpAddr(ServletUtils.getRequest()); String ip = IpUtils.getIpAddr();
operLog.setOperIp(ip); operLog.setOperIp(ip);
operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255)); operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));
if (loginUser != null) if (loginUser != null)
{ {
operLog.setOperName(loginUser.getUsername()); operLog.setOperName(loginUser.getUsername());
SysUser currentUser = loginUser.getUser();
if (StringUtils.isNotNull(currentUser) && StringUtils.isNotNull(currentUser.getDept()))
{
operLog.setDeptName(currentUser.getDept().getDeptName());
}
} }
if (e != null) if (e != null)
{ {
operLog.setStatus(BusinessStatus.FAIL.ordinal()); operLog.setStatus(BusinessStatus.FAIL.ordinal());
operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000)); operLog.setErrorMsg(StringUtils.substring(Convert.toStr(e.getMessage(), ExceptionUtil.getExceptionMessage(e)), 0, 2000));
} }
// 设置方法名称 // 设置方法名称
String className = joinPoint.getTarget().getClass().getName(); String className = joinPoint.getTarget().getClass().getName();
@@ -96,6 +120,8 @@ public class LogAspect
operLog.setRequestMethod(ServletUtils.getRequest().getMethod()); operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
// 处理设置注解上的参数 // 处理设置注解上的参数
getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult); getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
// 设置消耗时间
operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());
// 保存数据库 // 保存数据库
AsyncManager.me().execute(AsyncFactory.recordOper(operLog)); AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
} }
@@ -105,6 +131,10 @@ public class LogAspect
log.error("异常信息:{}", exp.getMessage()); log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace(); exp.printStackTrace();
} }
finally
{
TIME_THREADLOCAL.remove();
}
} }
/** /**
@@ -126,7 +156,7 @@ public class LogAspect
if (log.isSaveRequestData()) if (log.isSaveRequestData())
{ {
// 获取参数的信息,传入到数据库中。 // 获取参数的信息,传入到数据库中。
setRequestValue(joinPoint, operLog); setRequestValue(joinPoint, operLog, log.excludeParamNames());
} }
// 是否需要保存response参数和值 // 是否需要保存response参数和值
if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult)) if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult))
@@ -141,25 +171,25 @@ public class LogAspect
* @param operLog 操作日志 * @param operLog 操作日志
* @throws Exception 异常 * @throws Exception 异常
*/ */
private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog) throws Exception private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception
{ {
Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
String requestMethod = operLog.getRequestMethod(); String requestMethod = operLog.getRequestMethod();
if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) if (StringUtils.isEmpty(paramsMap) && StringUtils.equalsAny(requestMethod, HttpMethod.PUT.name(), HttpMethod.POST.name(), HttpMethod.DELETE.name()))
{ {
String params = argsArrayToString(joinPoint.getArgs()); String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
operLog.setOperParam(StringUtils.substring(params, 0, 2000)); operLog.setOperParam(StringUtils.substring(params, 0, 2000));
} }
else else
{ {
Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest()); operLog.setOperParam(StringUtils.substring(JSON.toJSONString(paramsMap, excludePropertyPreFilter(excludeParamNames)), 0, 2000));
operLog.setOperParam(StringUtils.substring(JSON.toJSONString(paramsMap, excludePropertyPreFilter()), 0, 2000));
} }
} }
/** /**
* 参数拼装 * 参数拼装
*/ */
private String argsArrayToString(Object[] paramsArray) private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames)
{ {
String params = ""; String params = "";
if (paramsArray != null && paramsArray.length > 0) if (paramsArray != null && paramsArray.length > 0)
@@ -170,7 +200,7 @@ public class LogAspect
{ {
try try
{ {
String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter()); String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter(excludeParamNames));
params += jsonObj.toString() + " "; params += jsonObj.toString() + " ";
} }
catch (Exception e) catch (Exception e)
@@ -185,9 +215,9 @@ public class LogAspect
/** /**
* 忽略敏感属性 * 忽略敏感属性
*/ */
public PropertyPreExcludeFilter excludePropertyPreFilter() public PropertyPreExcludeFilter excludePropertyPreFilter(String[] excludeParamNames)
{ {
return new PropertyPreExcludeFilter().addExcludes(EXCLUDE_PROPERTIES); return new PropertyPreExcludeFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES, excludeParamNames));
} }
/** /**

View File

@@ -79,7 +79,7 @@ public class RateLimiterAspect
StringBuffer stringBuffer = new StringBuffer(rateLimiter.key()); StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
if (rateLimiter.limitType() == LimitType.IP) if (rateLimiter.limitType() == LimitType.IP)
{ {
stringBuffer.append(IpUtils.getIpAddr(ServletUtils.getRequest())).append("-"); stringBuffer.append(IpUtils.getIpAddr()).append("-");
} }
MethodSignature signature = (MethodSignature) point.getSignature(); MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod(); Method method = signature.getMethod();

View File

@@ -1,6 +1,7 @@
package com.fastbee.framework.config; package com.fastbee.framework.config;
import java.util.TimeZone; import java.util.TimeZone;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@@ -15,7 +16,6 @@ import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration @Configuration
// 表示通过aop框架暴露该代理对象,AopContext能够访问 // 表示通过aop框架暴露该代理对象,AopContext能够访问
@EnableAspectJAutoProxy(exposeProxy = true) @EnableAspectJAutoProxy(exposeProxy = true)
// 指定要扫描的Mapper类的包的路径
@MapperScan("com.fastbee.**.mapper") @MapperScan("com.fastbee.**.mapper")
public class ApplicationConfig public class ApplicationConfig
{ {

View File

@@ -0,0 +1,61 @@
package com.fastbee.framework.config;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Configuration
public class DataSourceConfig {
private final DynamicDataSourceProperties properties;
private final DefaultDataSourceCreator dataSourceCreator;
public DataSourceConfig(DynamicDataSourceProperties properties,
DefaultDataSourceCreator dataSourceCreator) {
this.properties = properties;
this.dataSourceCreator = dataSourceCreator;
}
@Bean
public DynamicDataSourceProvider dynamicDataSourceProvider() {
return new AbstractDataSourceProvider(dataSourceCreator) {
@Override
public Map<String, DataSource> loadDataSources() {
Map<String, DataSource> dataSourceMap = new HashMap<>();
return dataSourceMap;
}
};
}
@Primary
@Bean
public DataSource dataSource(List<DynamicDataSourceProvider> providers) {
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(providers);
dataSource.setPrimary(properties.getPrimary());
dataSource.setStrict(properties.getStrict());
dataSource.setStrategy(properties.getStrategy());
dataSource.setP6spy(properties.getP6spy());
dataSource.setSeata(properties.getSeata());
return dataSource;
}
@Bean
public DataSourceTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}

View File

@@ -1,89 +1,26 @@
package com.fastbee.framework.config; package com.fastbee.framework.config;
import java.io.IOException; import com.alibaba.druid.spring.boot3.autoconfigure.properties.DruidStatProperties;
import java.util.HashMap; import com.alibaba.druid.util.Utils;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.sql.DataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary; import jakarta.servlet.Filter;
import com.alibaba.druid.pool.DruidDataSource; import jakarta.servlet.FilterChain;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; import jakarta.servlet.ServletException;
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; import jakarta.servlet.ServletRequest;
import com.alibaba.druid.util.Utils; import jakarta.servlet.ServletResponse;
import com.fastbee.common.enums.DataSourceType; import java.io.IOException;
import com.fastbee.common.utils.spring.SpringUtils;
import com.fastbee.framework.config.properties.DruidProperties;
import com.fastbee.framework.datasource.DynamicDataSource;
/**
* druid 配置多数据源
*
* @author ruoyi
*/
@Configuration @Configuration
public class DruidConfig public class DruidConfig {
{
@Bean
@ConfigurationProperties("spring.datasource.druid.master")
public DataSource masterDataSource(DruidProperties druidProperties)
{
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
return druidProperties.dataSource(dataSource);
}
@Bean
@ConfigurationProperties("spring.datasource.druid.slave")
@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
public DataSource slaveDataSource(DruidProperties druidProperties)
{
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
return druidProperties.dataSource(dataSource);
}
@Bean(name = "dynamicDataSource")
@Primary
public DynamicDataSource dataSource(DataSource masterDataSource)
{
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
return new DynamicDataSource(masterDataSource, targetDataSources);
}
/**
* 设置数据源
*
* @param targetDataSources 备选数据源集合
* @param sourceName 数据源名称
* @param beanName bean名称
*/
public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName)
{
try
{
DataSource dataSource = SpringUtils.getBean(beanName);
targetDataSources.put(sourceName, dataSource);
}
catch (Exception e)
{
}
}
/** /**
* 去除监控页面底部的广告 * 去除监控页面底部的广告
*/ */
@SuppressWarnings({ "rawtypes", "unchecked" }) @SuppressWarnings({ "rawtypes", "unchecked" })
@Bean @Bean
@ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true") @ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled", havingValue = "true")
public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties)
{ {
// 获取web监控页面的参数 // 获取web监控页面的参数
@@ -96,7 +33,7 @@ public class DruidConfig
Filter filter = new Filter() Filter filter = new Filter()
{ {
@Override @Override
public void init(javax.servlet.FilterConfig filterConfig) throws ServletException public void init(jakarta.servlet.FilterConfig filterConfig) throws ServletException
{ {
} }
@Override @Override

View File

@@ -2,7 +2,7 @@ package com.fastbee.framework.config;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.servlet.DispatcherType; import jakarta.servlet.DispatcherType;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;

View File

@@ -0,0 +1,43 @@
package com.fastbee.framework.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import com.fastbee.common.constant.Constants;
/**
* 资源文件配置加载
*
* @author ruoyi
*/
@Configuration
public class I18nConfig implements WebMvcConfigurer
{
@Bean
public LocaleResolver localeResolver()
{
SessionLocaleResolver slr = new SessionLocaleResolver();
// 默认语言
slr.setDefaultLocale(Constants.DEFAULT_LOCALE);
return slr;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor()
{
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
// 参数名
lci.setParamName("lang");
return lci;
}
@Override
public void addInterceptors(InterceptorRegistry registry)
{
registry.addInterceptor(localeChangeInterceptor());
}
}

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