diff --git a/README.md b/README.md index 2779fda93..778b901f4 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/blob/master/LICENSE) [![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
-[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-2.6.0-success.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus) -[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-2.4-blue.svg)]() +[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-3.0.0-success.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus) +[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-2.5-blue.svg)]() [![JDK-8+](https://img.shields.io/badge/JDK-8+-green.svg)]() [![JDK-11](https://img.shields.io/badge/JDK-11-green.svg)]() @@ -21,51 +21,39 @@ RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 `分布式集群` 场景升级 定期 * 权限认证框架 Spring Security、Jwt,支持多终端认证系统 * 关系数据库 MySQL 适配 8.X * 缓存数据库 Redis 适配 6.X -* 数据库开发框架 Mybatis-Plus 快速 CRUD 增加开发效率 插件化支持各类需求 +* 数据库框架 Mybatis-Plus 快速 CRUD 增加开发效率 插件化支持各类需求 +* 数据库框架 多数据源框架 dynamic-datasource 支持主从与多种类数据库异构 +* 数据库框架 Redis客户端 采用 Redisson 性能更强 +* 数据库框架 性能分析插件 p6spy 更强劲的 SQL 分析 +* 序列化框架 统一使用 jackson 高效可靠 * 网络框架 Feign、OkHttp3 接口化管理 HTTP 请求 -* 工具类框架 Hutool、Lombok 减少代码冗余 增加安全性 +* 分布式锁 Lock4j 注解锁、工具锁 多种多样 +* 文件存储 OSS 对象存储模块 支持(Minio、七牛、阿里、腾讯) * 监控框架 spring-boot-admin 全方位服务监控 * 校验框架 validation 增强接口安全性 严谨性 +* Excel框架 Alibaba EasyExcel 性能优异 扩展性强 * 文档框架 knife4j 美化接口文档 -* 序列化框架 统一使用 jackson 高效可靠 +* 工具类框架 Hutool、Lombok 减少代码冗余 增加安全性 * 代码生成器 一键生成前后端代码 -* 多数据源框架 dynamic-datasource 支持主从与多种类数据库异构 -* Redis客户端 采用 Redisson 性能更强 -* 分布式锁 Lock4j 注解锁、工具锁 多种多样 * 部署方式 Docker 容器编排 一键部署业务集群 -* 文件存储 OSS 对象存储模块 支持(Minio、七牛、阿里、腾讯) +* 国际化 Spring 标准国际化方解决方案 ## 参考文档 使用框架前请仔细阅读文档重点注意事项
>[初始化项目 必看](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于初始化项目?sort_id=4164117) +>>[https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于初始化项目?sort_id=4164117](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于初始化项目?sort_id=4164117) > >[部署项目 必看](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于应用部署?sort_id=4219382) +>>[https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于应用部署?sort_id=4219382](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于应用部署?sort_id=4219382) > >[参考文档 Wiki](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages) +>>[https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages) -## 提问四部曲 -### 一、查阅wiki -优先在`wiki->重点事项`,查找是否有相关问题及解决方案,尤其是框架更新后产生的问题,多会在wiki中提及 +## 软件架构图 -> [参考文档 Wiki](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages) - -### 二、借助issues -尝试issues中搜索问题关键字(记得选择已完成),看看是否有其他人提出相同问题 -- `如果有`那么依据评论中的解决方案自行尝试解决 -- `如果没有`那么提交一个新的issues描述清楚你的问题,需要包含以下内容(优质的issues,能够帮助作者更高效的帮你解决问题): - - 出现问题的模块或功能或类,总之你要说清楚在哪出的问题 - - 描述产生问题的相关操作流程,以便复现快速解决 - - 报错的日志截图,一定是截图,不要复制一堆报错的文本 -> [issues](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/issues) - -### 三、百度 -大家都懂,不多描述,将关键的报错信息CC->CV到百度中看看大佬们怎么解决的 -> [百度](http://www.baidu.com) - -### 四、加群 -以上三点已经能解决大家绝大部分问题了,如果还有问题没能通过这几种方式解决,那么加群,大家一起在群里探讨一下 +![Plus部署架构图](https://images.gitee.com/uploads/images/2021/0729/112230_4295e5ce_1766278.png "Plus部署架构图.png") ## 贡献代码 @@ -79,7 +67,8 @@ RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 `分布式集群` 场景升级 定期 * ORM框架 使用 Mybatis-Plus 简化CRUD (不支持主子表) * Bean简化 使用 Lombok 简化 get set toString 等等 * 容器改动 Tomcat 改为 并发性能更好的 undertow -* 分页移除 pagehelper 改为 Mybatis-Plus 分页 +* 移除 pagehelper 改为 Mybatis-Plus 分页 +* 集成 p6spy 更强劲的 SQL 分析 * 升级 swagger 为 knife4j * 集成 Hutool 5.X 并重写RuoYi部分功能 * 集成 Feign 接口化管理 Http 请求(如三方请求 支付,短信,推送等) @@ -90,7 +79,8 @@ RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 `分布式集群` 场景升级 定期 * 集成 dynamic-datasource 多数据源(默认支持MySQL,其他种类需自行适配) * 集成 Lock4j 实现分布式 注解锁、工具锁 多种多样 * 增加 Docker 容器编排 打包插件与部署脚本 -* 移除 本地文件上传 改为 OSS对象存储 支持(Minio、七牛、阿里、腾讯) +* 移除 通用上传下载 改为 OSS对象存储 支持(Minio、七牛、阿里、腾讯) +* 移除 RuoYi自带 Excel 工具 改为 EasyExcel 工具 ### 代码改动 @@ -112,8 +102,9 @@ RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 `分布式集群` 场景升级 定期 * 单模块 fast 分支 [RuoYi-Vue-Plus-fast](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/fast/) * Oracle 模块 oracle 分支 [RuoYi-Vue-Plus-oracle](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/oracle/) -## 扫码加群 一起交流 -![输入图片说明](https://images.gitee.com/uploads/images/2021/0625/160026_11d949aa_1766278.jpeg "07f7121fab14e57e03e5f6a35eff6ce.jpg") +## 加群与捐献 +>[加群与捐献](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/加群与捐献?sort_id=4104598) +>>[https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/加群与捐献?sort_id=4104598](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/加群与捐献?sort_id=4104598) ## 捐献作者 作者为兼职做开源,平时还需要工作,如果帮到了您可以请作者吃个盒饭 diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index ac065c351..228ddbf29 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -18,8 +18,6 @@ services: - /docker/mysql/data/:/var/lib/mysql/ # 配置挂载 - /docker/mysql/conf/:/etc/mysql/conf.d/ - # 主机本机时间文件映射 与本机时间同步 - - /etc/localtime:/etc/localtime:ro command: # 将mysql8.0默认密码策略 修改为 原先 策略 (mysql8.0对其默认策略做了更改 会导致密码无法匹配) --default-authentication-plugin=mysql_native_password @@ -37,6 +35,9 @@ services: # 如果需要指定版本 就把 latest 换成版本号 image: nginx:latest container_name: nginx-web + environment: + # 时区上海 + TZ: Asia/Shanghai ports: - 80:80 - 443:443 @@ -49,8 +50,6 @@ services: - /docker/nginx/html:/usr/share/nginx/html # 日志目录 - /docker/nginx/log:/var/log/nginx - # 主机本机时间文件映射 与本机时间同步 - - /etc/localtime:/etc/localtime:ro privileged: true restart: always networks: @@ -62,16 +61,13 @@ services: ports: - 6379:6379 environment: - # 设置环境变量 时区上海 编码UTF-8 + # 时区上海 TZ: Asia/Shanghai - LANG: en_US.UTF-8 volumes: # 配置文件 - /docker/redis/conf/redis.conf:/redis.conf:rw # 数据文件 - /docker/redis/data:/data:rw - # 主机本机时间文件映射 与本机时间同步 - - /etc/localtime:/etc/localtime:ro command: "redis-server --appendonly yes" privileged: true restart: always @@ -88,6 +84,8 @@ services: # 控制台端口 - 9001:9001 environment: + # 时区上海 + TZ: Asia/Shanghai # 管理后台用户名 MINIO_ACCESS_KEY: ruoyi # 管理后台密码,最小8个字符 @@ -97,8 +95,6 @@ services: - /docker/minio/data:/data # 映射配置目录 - /docker/minio/config:/root/.minio/ - # 主机本机时间文件映射 与本机时间同步 - - /etc/localtime:/etc/localtime:ro command: server --console-address ':9001' /data # 指定容器中的目录 /data privileged: true restart: always @@ -107,9 +103,10 @@ services: ipv4_address: 172.30.0.54 ruoyi-server1: - image: "ruoyi/ruoyi-server:2.6.0" + image: "ruoyi/ruoyi-server:3.0.0" environment: - - TZ=Asia/Shanghai + # 时区上海 + TZ: Asia/Shanghai volumes: # 配置文件 - /docker/server1/logs/:/ruoyi/server/logs/ @@ -121,9 +118,10 @@ services: ipv4_address: 172.30.0.60 ruoyi-server2: - image: "ruoyi/ruoyi-server:2.6.0" + image: "ruoyi/ruoyi-server:3.0.0" environment: - - TZ=Asia/Shanghai + # 时区上海 + TZ: Asia/Shanghai volumes: # 配置文件 - /docker/server2/logs/:/ruoyi/server/logs/ @@ -135,9 +133,10 @@ services: ipv4_address: 172.30.0.61 ruoyi-monitor-admin: - image: "ruoyi/ruoyi-monitor-admin:2.6.0" + image: "ruoyi/ruoyi-monitor-admin:3.0.0" environment: - - TZ=Asia/Shanghai + # 时区上海 + TZ: Asia/Shanghai privileged: true restart: always networks: diff --git a/pom.xml b/pom.xml index 7c31108c6..cdd1f9e4d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,14 +6,14 @@ com.ruoyi ruoyi-vue-plus - 2.6.0 + 3.0.0 RuoYi-Vue-Plus https://gitee.com/JavaLionLi/RuoYi-Vue-Plus RuoYi-Vue-Plus后台管理系统 - 2.6.0 + 3.0.0 2.5.3 UTF-8 UTF-8 @@ -22,16 +22,19 @@ 1.2.6 3.0.3 4.1.2 + 2.2.10 1.7 0.9.1 3.4.3 - 5.7.6 + 3.9.1 + 5.7.7 3.0.3 - 11.0 - 2.4.3 + 11.2 + 4.9.1 + 2.5.0 3.16.1 2.2.1 - 3.4.1 + 3.4.1 7.8.0 @@ -79,6 +82,12 @@ ${poi.version} + + com.alibaba + easyexcel + ${easyexcel.version} + + org.apache.velocity @@ -97,7 +106,7 @@ com.baomidou dynamic-datasource-spring-boot-starter - ${datasource.version} + ${dynamic-ds.version} @@ -110,6 +119,12 @@ mybatis-plus-extension ${mybatis-plus.version} + + + p6spy + p6spy + ${p6spy.version} + cn.hutool @@ -129,6 +144,12 @@ ${feign-okhttp.version} + + com.squareup.okhttp3 + okhttp + ${okhttp.version} + + de.codecentric spring-boot-admin-starter-server @@ -248,7 +269,7 @@ public aliyun nexus - http://maven.aliyun.com/nexus/content/groups/public/ + https://maven.aliyun.com/repository/public/ true @@ -259,7 +280,7 @@ public aliyun nexus - http://maven.aliyun.com/nexus/content/groups/public/ + https://maven.aliyun.com/repository/public/ true @@ -276,6 +297,7 @@ local debug + '*' @@ -284,6 +306,7 @@ dev debug + '*' @@ -295,6 +318,7 @@ prod warn + health,info diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index ba0ad3252..b46acd50a 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -5,7 +5,7 @@ ruoyi-vue-plus com.ruoyi - 2.6.0 + 3.0.0 4.0.0 jar diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java index 46545165f..210cceecc 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java @@ -8,7 +8,7 @@ import cn.hutool.captcha.generator.CodeGenerator; import cn.hutool.captcha.generator.RandomGenerator; import cn.hutool.core.convert.Convert; import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.redis.RedisCache; @@ -107,9 +107,9 @@ public class CaptchaController { private String getCodeResult(String capStr) { int numberLength = captchaProperties.getNumberLength(); - int a = Convert.toInt(StrUtil.sub(capStr, 0, numberLength).trim()); + int a = Convert.toInt(StringUtils.substring(capStr, 0, numberLength).trim()); char operator = capStr.charAt(numberLength); - int b = Convert.toInt(StrUtil.sub(capStr, numberLength + 1, numberLength + 1 + numberLength).trim()); + int b = Convert.toInt(StringUtils.substring(capStr, numberLength + 1, numberLength + 1 + numberLength).trim()); switch (operator) { case '*': return a * b + ""; diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java deleted file mode 100644 index 04aa77b33..000000000 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.ruoyi.web.controller.common; - -import cn.hutool.core.util.StrUtil; -import com.ruoyi.common.config.RuoYiConfig; -import com.ruoyi.common.constant.Constants; -import com.ruoyi.common.utils.file.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.File; - -/** - * 通用请求处理 - * - * @author ruoyi - */ -@RestController -public class CommonController -{ - private static final Logger log = LoggerFactory.getLogger(CommonController.class); - - /** - * 通用下载请求 - * - * @param fileName 文件名称 - * @param delete 是否删除 - */ - @GetMapping("common/download") - public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request) - { - try - { - if (!FileUtils.checkAllowDownload(fileName)) - { - throw new Exception(StrUtil.format("文件名称({})非法,不允许下载。 ", fileName)); - } - String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1); - String filePath = RuoYiConfig.getDownloadPath() + fileName; - File file = new File(filePath); - response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); - FileUtils.setAttachmentResponseHeader(response, realFileName); - FileUtils.writeToStream(file, response.getOutputStream()); - if (delete) - { - FileUtils.del(file); - } - } - catch (Exception e) - { - log.error("下载文件失败", e); - } - } - - /** - * 本地资源通用下载 - */ - @GetMapping("/common/download/resource") - public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response) - throws Exception - { - try - { - if (!FileUtils.checkAllowDownload(resource)) - { - throw new Exception(StrUtil.format("资源文件({})非法,不允许下载。 ", resource)); - } - // 本地资源路径 - String localPath = RuoYiConfig.getProfile(); - // 数据库资源地址 - String downloadPath = localPath + StrUtil.subAfter(resource, Constants.RESOURCE_PREFIX,false); - // 下载名称 - String downloadName = StrUtil.subAfter(downloadPath, "/",true); - response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); - File file = new File(downloadPath); - FileUtils.setAttachmentResponseHeader(response, downloadName); - FileUtils.writeToStream(file, response.getOutputStream()); - } - catch (Exception e) - { - log.error("下载文件失败", e); - } - } -} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java index b3efd5ace..66749ef4f 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java @@ -1,50 +1,50 @@ -package com.ruoyi.web.controller.monitor; - -import cn.hutool.core.util.StrUtil; -import com.ruoyi.common.core.domain.AjaxResult; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.RedisCallback; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.*; - -/** - * 缓存监控 - * - * @author ruoyi - */ -@RestController -@RequestMapping("/monitor/cache") -public class CacheController -{ - @Autowired - private RedisTemplate redisTemplate; - - @PreAuthorize("@ss.hasPermi('monitor:cache:list')") - @GetMapping() - public AjaxResult getInfo() throws Exception - { - Properties info = (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info()); - Properties commandStats = (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info("commandstats")); - Object dbSize = redisTemplate.execute((RedisCallback) connection -> connection.dbSize()); - - Map result = new HashMap<>(3); - result.put("info", info); - result.put("dbSize", dbSize); - - List> pieList = new ArrayList<>(); - commandStats.stringPropertyNames().forEach(key -> { - Map data = new HashMap<>(2); - String property = commandStats.getProperty(key); - data.put("name", StrUtil.removePrefix(key, "cmdstat_")); - data.put("value", StrUtil.subBetween(property, "calls=", ",usec")); - pieList.add(data); - }); - result.put("commandStats", pieList); - return AjaxResult.success(result); - } -} +package com.ruoyi.web.controller.monitor; + +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.core.domain.AjaxResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.*; + +/** + * 缓存监控 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/monitor/cache") +public class CacheController +{ + @Autowired + private RedisTemplate redisTemplate; + + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @GetMapping() + public AjaxResult getInfo() throws Exception + { + Properties info = (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info()); + Properties commandStats = (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info("commandstats")); + Object dbSize = redisTemplate.execute((RedisCallback) connection -> connection.dbSize()); + + Map result = new HashMap<>(3); + result.put("info", info); + result.put("dbSize", dbSize); + + List> pieList = new ArrayList<>(); + commandStats.stringPropertyNames().forEach(key -> { + Map data = new HashMap<>(2); + String property = commandStats.getProperty(key); + data.put("name", StringUtils.removeStart(key, "cmdstat_")); + data.put("value", StringUtils.substringBetween(property, "calls=", ",usec")); + pieList.add(data); + }); + result.put("commandStats", pieList); + return AjaxResult.success(result); + } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java index 2bb0b1351..fb0b0029f 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java @@ -12,11 +12,12 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; import java.util.List; /** * 系统访问记录 - * + * * @author ruoyi */ @RestController @@ -36,11 +37,10 @@ public class SysLogininforController extends BaseController @Log(title = "登录日志", businessType = BusinessType.EXPORT) @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')") @GetMapping("/export") - public AjaxResult export(SysLogininfor logininfor) + public void export(SysLogininfor logininfor, HttpServletResponse response) { List list = logininforService.selectLogininforList(logininfor); - ExcelUtil util = new ExcelUtil(SysLogininfor.class); - return util.exportExcel(list, "登录日志"); + ExcelUtil.exportExcel(list, "登录日志", SysLogininfor.class, response); } @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')") diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java index 97f99206c..02a926d81 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java @@ -12,11 +12,12 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; import java.util.List; /** * 操作日志记录 - * + * * @author ruoyi */ @RestController @@ -36,11 +37,10 @@ public class SysOperlogController extends BaseController @Log(title = "操作日志", businessType = BusinessType.EXPORT) @PreAuthorize("@ss.hasPermi('monitor:operlog:export')") @GetMapping("/export") - public AjaxResult export(SysOperLog operLog) + public void export(SysOperLog operLog, HttpServletResponse response) { List list = operLogService.selectOperLogList(operLog); - ExcelUtil util = new ExcelUtil(SysOperLog.class); - return util.exportExcel(list, "操作日志"); + ExcelUtil.exportExcel(list, "操作日志", SysOperLog.class, response); } @Log(title = "操作日志", businessType = BusinessType.DELETE) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java index fe630a99c..f1442cc71 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java @@ -1,7 +1,5 @@ package com.ruoyi.web.controller.monitor; -import cn.hutool.core.lang.Validator; -import cn.hutool.core.util.StrUtil; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.controller.BaseController; @@ -11,6 +9,7 @@ import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.PageUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.system.domain.SysUserOnline; import com.ruoyi.system.service.ISysUserOnlineService; import org.springframework.beans.factory.annotation.Autowired; @@ -24,7 +23,7 @@ import java.util.List; /** * 在线用户监控 - * + * * @author ruoyi */ @RestController @@ -46,23 +45,23 @@ public class SysUserOnlineController extends BaseController for (String key : keys) { LoginUser user = redisCache.getCacheObject(key); - if (Validator.isNotEmpty(ipaddr) && Validator.isNotEmpty(userName)) + if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) { - if (StrUtil.equals(ipaddr, user.getIpaddr()) && StrUtil.equals(userName, user.getUsername())) + if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername())) { userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user)); } } - else if (Validator.isNotEmpty(ipaddr)) + else if (StringUtils.isNotEmpty(ipaddr)) { - if (StrUtil.equals(ipaddr, user.getIpaddr())) + if (StringUtils.equals(ipaddr, user.getIpaddr())) { userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user)); } } - else if (Validator.isNotEmpty(userName) && Validator.isNotNull(user.getUser())) + else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser())) { - if (StrUtil.equals(userName, user.getUsername())) + if (StringUtils.equals(userName, user.getUsername())) { userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user)); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java index c8e919194..13fdc672a 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java @@ -7,7 +7,6 @@ import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; -import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.system.domain.SysConfig; import com.ruoyi.system.service.ISysConfigService; @@ -16,6 +15,7 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; import java.util.List; /** @@ -43,11 +43,10 @@ public class SysConfigController extends BaseController @Log(title = "参数管理", businessType = BusinessType.EXPORT) @PreAuthorize("@ss.hasPermi('system:config:export')") @GetMapping("/export") - public AjaxResult export(SysConfig config) + public void export(SysConfig config, HttpServletResponse response) { List list = configService.selectConfigList(config); - ExcelUtil util = new ExcelUtil(SysConfig.class); - return util.exportExcel(list, "参数数据"); + ExcelUtil.exportExcel(list, "参数数据", SysConfig.class, response); } /** @@ -82,7 +81,7 @@ public class SysConfigController extends BaseController { return AjaxResult.error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在"); } - config.setCreateBy(SecurityUtils.getUsername()); + config.setCreateBy(getUsername()); return toAjax(configService.insertConfig(config)); } @@ -98,7 +97,7 @@ public class SysConfigController extends BaseController { return AjaxResult.error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在"); } - config.setUpdateBy(SecurityUtils.getUsername()); + config.setUpdateBy(getUsername()); return toAjax(configService.updateConfig(config)); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java index ab39319a1..edf0b2287 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java @@ -1,15 +1,14 @@ package com.ruoyi.web.controller.system; -import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.ArrayUtil; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.enums.BusinessType; -import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.system.service.ISysDeptService; -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; @@ -56,7 +55,7 @@ public class SysDeptController extends BaseController { SysDept d = (SysDept) it.next(); if (d.getDeptId().intValue() == deptId - || ArrayUtils.contains(StrUtil.splitToArray(d.getAncestors(), ","), deptId + "")) + || ArrayUtil.contains(StringUtils.split(d.getAncestors(), ","), deptId + "")) { it.remove(); } @@ -109,7 +108,7 @@ public class SysDeptController extends BaseController { return AjaxResult.error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在"); } - dept.setCreateBy(SecurityUtils.getUsername()); + dept.setCreateBy(getUsername()); return toAjax(deptService.insertDept(dept)); } @@ -129,12 +128,12 @@ public class SysDeptController extends BaseController { return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己"); } - else if (StrUtil.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) + else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(dept.getDeptId()) > 0) { return AjaxResult.error("该部门包含未停用的子部门!"); } - dept.setUpdateBy(SecurityUtils.getUsername()); + dept.setUpdateBy(getUsername()); return toAjax(deptService.updateDept(dept)); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java index a272a6e97..6462a0c1e 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java @@ -1,13 +1,12 @@ package com.ruoyi.web.controller.system; -import cn.hutool.core.lang.Validator; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.entity.SysDictData; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; -import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.system.service.ISysDictDataService; import com.ruoyi.system.service.ISysDictTypeService; @@ -16,6 +15,7 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.List; @@ -44,11 +44,10 @@ public class SysDictDataController extends BaseController @Log(title = "字典数据", businessType = BusinessType.EXPORT) @PreAuthorize("@ss.hasPermi('system:dict:export')") @GetMapping("/export") - public AjaxResult export(SysDictData dictData) + public void export(SysDictData dictData, HttpServletResponse response) { List list = dictDataService.selectDictDataList(dictData); - ExcelUtil util = new ExcelUtil(SysDictData.class); - return util.exportExcel(list, "字典数据"); + ExcelUtil.exportExcel(list, "字典数据", SysDictData.class, response); } /** @@ -68,7 +67,7 @@ public class SysDictDataController extends BaseController public AjaxResult dictType(@PathVariable String dictType) { List data = dictTypeService.selectDictDataByType(dictType); - if (Validator.isNull(data)) + if (StringUtils.isNull(data)) { data = new ArrayList(); } @@ -83,7 +82,7 @@ public class SysDictDataController extends BaseController @PostMapping public AjaxResult add(@Validated @RequestBody SysDictData dict) { - dict.setCreateBy(SecurityUtils.getUsername()); + dict.setCreateBy(getUsername()); return toAjax(dictDataService.insertDictData(dict)); } @@ -95,7 +94,7 @@ public class SysDictDataController extends BaseController @PutMapping public AjaxResult edit(@Validated @RequestBody SysDictData dict) { - dict.setUpdateBy(SecurityUtils.getUsername()); + dict.setUpdateBy(getUsername()); return toAjax(dictDataService.updateDictData(dict)); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java index e2e06253e..eb5c0b5c9 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java @@ -7,7 +7,6 @@ import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.entity.SysDictType; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; -import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.system.service.ISysDictTypeService; import org.springframework.beans.factory.annotation.Autowired; @@ -15,6 +14,7 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; import java.util.List; /** @@ -39,11 +39,10 @@ public class SysDictTypeController extends BaseController @Log(title = "字典类型", businessType = BusinessType.EXPORT) @PreAuthorize("@ss.hasPermi('system:dict:export')") @GetMapping("/export") - public AjaxResult export(SysDictType dictType) + public void export(SysDictType dictType, HttpServletResponse response) { List list = dictTypeService.selectDictTypeList(dictType); - ExcelUtil util = new ExcelUtil(SysDictType.class); - return util.exportExcel(list, "字典类型"); + ExcelUtil.exportExcel(list, "字典类型", SysDictType.class, response); } /** @@ -68,7 +67,7 @@ public class SysDictTypeController extends BaseController { return AjaxResult.error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在"); } - dict.setCreateBy(SecurityUtils.getUsername()); + dict.setCreateBy(getUsername()); return toAjax(dictTypeService.insertDictType(dict)); } @@ -84,7 +83,7 @@ public class SysDictTypeController extends BaseController { return AjaxResult.error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); } - dict.setUpdateBy(SecurityUtils.getUsername()); + dict.setUpdateBy(getUsername()); return toAjax(dictTypeService.updateDictType(dict)); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java index a29620c4f..bfb532e36 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java @@ -1,6 +1,6 @@ package com.ruoyi.web.controller.system; -import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.config.RuoYiConfig; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; @@ -24,6 +24,6 @@ public class SysIndexController @RequestMapping("/") public String index() { - return StrUtil.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion()); + return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion()); } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java index b2b9efb3d..9971ac464 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java @@ -6,6 +6,7 @@ import com.ruoyi.common.core.domain.entity.SysMenu; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.model.LoginBody; import com.ruoyi.common.core.domain.model.LoginUser; +import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.framework.web.service.SysLoginService; import com.ruoyi.framework.web.service.SysPermissionService; @@ -88,10 +89,8 @@ public class SysLoginController @GetMapping("getRouters") public AjaxResult getRouters() { - LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); - // 用户信息 - SysUser user = loginUser.getUser(); - List menus = menuService.selectMenuTreeByUserId(user.getUserId()); + Long userId = SecurityUtils.getUserId(); + List menus = menuService.selectMenuTreeByUserId(userId); return AjaxResult.success(menuService.buildMenus(menus)); } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java index 246abf406..d679bfb31 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java @@ -1,16 +1,12 @@ package com.ruoyi.web.controller.system; -import cn.hutool.core.lang.Validator; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.entity.SysMenu; -import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.enums.BusinessType; -import com.ruoyi.common.utils.SecurityUtils; -import com.ruoyi.common.utils.ServletUtils; -import com.ruoyi.framework.web.service.TokenService; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.system.service.ISysMenuService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; @@ -33,9 +29,6 @@ public class SysMenuController extends BaseController @Autowired private ISysMenuService menuService; - @Autowired - private TokenService tokenService; - /** * 获取菜单列表 */ @@ -43,9 +36,7 @@ public class SysMenuController extends BaseController @GetMapping("/list") public AjaxResult list(SysMenu menu) { - LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); - Long userId = loginUser.getUser().getUserId(); - List menus = menuService.selectMenuList(menu, userId); + List menus = menuService.selectMenuList(menu, getUserId()); return AjaxResult.success(menus); } @@ -65,9 +56,7 @@ public class SysMenuController extends BaseController @GetMapping("/treeselect") public AjaxResult treeselect(SysMenu menu) { - LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); - Long userId = loginUser.getUser().getUserId(); - List menus = menuService.selectMenuList(menu, userId); + List menus = menuService.selectMenuList(menu, getUserId()); return AjaxResult.success(menuService.buildMenuTreeSelect(menus)); } @@ -77,8 +66,7 @@ public class SysMenuController extends BaseController @GetMapping(value = "/roleMenuTreeselect/{roleId}") public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId) { - LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); - List menus = menuService.selectMenuList(loginUser.getUser().getUserId()); + List menus = menuService.selectMenuList(getUserId()); Map ajax = new HashMap<>(); ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId)); ajax.put("menus", menuService.buildMenuTreeSelect(menus)); @@ -97,11 +85,11 @@ public class SysMenuController extends BaseController { return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); } - else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !Validator.isUrl(menu.getPath())) + else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); } - menu.setCreateBy(SecurityUtils.getUsername()); + menu.setCreateBy(getUsername()); return toAjax(menuService.insertMenu(menu)); } @@ -117,7 +105,7 @@ public class SysMenuController extends BaseController { return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); } - else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !Validator.isUrl(menu.getPath())) + else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); } @@ -125,7 +113,7 @@ public class SysMenuController extends BaseController { return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); } - menu.setUpdateBy(SecurityUtils.getUsername()); + menu.setUpdateBy(getUsername()); return toAjax(menuService.updateMenu(menu)); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java index 48d1e088f..55375a9d8 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java @@ -17,13 +17,12 @@ import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; -import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.system.domain.SysNotice; import com.ruoyi.system.service.ISysNoticeService; /** * 公告 信息操作处理 - * + * * @author ruoyi */ @RestController @@ -61,7 +60,7 @@ public class SysNoticeController extends BaseController @PostMapping public AjaxResult add(@Validated @RequestBody SysNotice notice) { - notice.setCreateBy(SecurityUtils.getUsername()); + notice.setCreateBy(getUsername()); return toAjax(noticeService.insertNotice(notice)); } @@ -73,7 +72,7 @@ public class SysNoticeController extends BaseController @PutMapping public AjaxResult edit(@Validated @RequestBody SysNotice notice) { - notice.setUpdateBy(SecurityUtils.getUsername()); + notice.setUpdateBy(getUsername()); return toAjax(noticeService.updateNotice(notice)); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssConfigController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssConfigController.java new file mode 100644 index 000000000..60fed2a41 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssConfigController.java @@ -0,0 +1,108 @@ +package com.ruoyi.web.controller.system; + +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.annotation.RepeatSubmit; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.system.domain.bo.SysOssConfigBo; +import com.ruoyi.system.domain.vo.SysOssConfigVo; +import com.ruoyi.system.service.ISysOssConfigService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +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 javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Arrays; + +/** + * 云存储配置Controller + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +@Validated +@Api(value = "云存储配置控制器", tags = {"云存储配置管理"}) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@RestController +@RequestMapping("/system/oss/config") +public class SysOssConfigController extends BaseController { + + private final ISysOssConfigService iSysOssConfigService; + + /** + * 查询云存储配置列表 + */ + @ApiOperation("查询云存储配置列表") + @PreAuthorize("@ss.hasPermi('system:oss:list')") + @GetMapping("/list") + public TableDataInfo list(@Validated SysOssConfigBo bo) { + return iSysOssConfigService.queryPageList(bo); + } + + /** + * 获取云存储配置详细信息 + */ + @ApiOperation("获取云存储配置详细信息") + @PreAuthorize("@ss.hasPermi('system:oss:query')") + @GetMapping("/{ossConfigId}") + public AjaxResult getInfo(@NotNull(message = "主键不能为空") + @PathVariable("ossConfigId") Integer ossConfigId) { + return AjaxResult.success(iSysOssConfigService.queryById(ossConfigId)); + } + + /** + * 新增云存储配置 + */ + @ApiOperation("新增云存储配置") + @PreAuthorize("@ss.hasPermi('system:oss:add')") + @Log(title = "云存储配置", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public AjaxResult add(@Validated(AddGroup.class) @RequestBody SysOssConfigBo bo) { + return toAjax(iSysOssConfigService.insertByBo(bo) ? 1 : 0); + } + + /** + * 修改云存储配置 + */ + @ApiOperation("修改云存储配置") + @PreAuthorize("@ss.hasPermi('system:oss:edit')") + @Log(title = "云存储配置", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public AjaxResult edit(@Validated(EditGroup.class) @RequestBody SysOssConfigBo bo) { + return toAjax(iSysOssConfigService.updateByBo(bo) ? 1 : 0); + } + + /** + * 删除云存储配置 + */ + @ApiOperation("删除云存储配置") + @PreAuthorize("@ss.hasPermi('system:oss:remove')") + @Log(title = "云存储配置", businessType = BusinessType.DELETE) + @DeleteMapping("/{ossConfigIds}") + public AjaxResult remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ossConfigIds) { + return toAjax(iSysOssConfigService.deleteWithValidByIds(Arrays.asList(ossConfigIds), true) ? 1 : 0); + } + + /** + * 状态修改 + */ + @PreAuthorize("@ss.hasPermi('system:oss:edit')") + @Log(title = "云存储状态修改", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody SysOssConfigBo bo) { + return toAjax(iSysOssConfigService.updateOssConfigStatus(bo)); + } +} diff --git a/ruoyi-oss/src/main/java/com/ruoyi/system/controller/SysOssController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java similarity index 74% rename from ruoyi-oss/src/main/java/com/ruoyi/system/controller/SysOssController.java rename to ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java index 8a84c42e3..c7772ab9c 100644 --- a/ruoyi-oss/src/main/java/com/ruoyi/system/controller/SysOssController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java @@ -1,20 +1,26 @@ -package com.ruoyi.system.controller; +package com.ruoyi.web.controller.system; import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.http.HttpUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.annotation.RepeatSubmit; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; -import com.ruoyi.common.exception.CustomException; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.JsonUtils; import com.ruoyi.common.utils.file.FileUtils; -import com.ruoyi.system.domain.bo.SysOssBo; +import com.ruoyi.oss.constant.CloudConstant; +import com.ruoyi.system.domain.SysConfig; import com.ruoyi.system.domain.SysOss; -import com.ruoyi.system.service.ISysOssService; +import com.ruoyi.system.domain.bo.SysOssBo; import com.ruoyi.system.domain.vo.SysOssVo; +import com.ruoyi.system.service.ISysConfigService; +import com.ruoyi.system.service.ISysOssService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; @@ -49,6 +55,7 @@ import java.util.Map; public class SysOssController extends BaseController { private final ISysOssService iSysOssService; + private final ISysConfigService iSysConfigService; /** * 查询OSS云存储列表 @@ -72,8 +79,8 @@ public class SysOssController extends BaseController { @RepeatSubmit @PostMapping("/upload") public AjaxResult> upload(@RequestPart("file") MultipartFile file) { - if (file.isEmpty()) { - throw new CustomException("上传文件不能为空"); + if (ObjectUtil.isNull(file)) { + throw new ServiceException("上传文件不能为空"); } SysOss oss = iSysOssService.upload(file); Map map = new HashMap<>(2); @@ -87,8 +94,8 @@ public class SysOssController extends BaseController { @GetMapping("/download/{ossId}") public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException { SysOss sysOss = iSysOssService.getById(ossId); - if (sysOss == null) { - throw new CustomException("文件数据不存在!"); + if (ObjectUtil.isNull(sysOss)) { + throw new ServiceException("文件数据不存在!"); } response.reset(); response.addHeader("Access-Control-Allow-Origin", "*"); @@ -111,4 +118,19 @@ public class SysOssController extends BaseController { return toAjax(iSysOssService.deleteWithValidByIds(Arrays.asList(ossIds), true) ? 1 : 0); } + /** + * 变更图片列表预览状态 + */ + @ApiOperation("变更图片列表预览状态") + @PreAuthorize("@ss.hasPermi('system:oss:edit')") + @Log(title = "OSS云存储" , businessType = BusinessType.UPDATE) + @PutMapping("/changePreviewListResource") + public AjaxResult changePreviewListResource(@RequestBody String body) { + Map map = JsonUtils.parseMap(body); + SysConfig config = iSysConfigService.getOne(new LambdaQueryWrapper() + .eq(SysConfig::getConfigKey, CloudConstant.PEREVIEW_LIST_RESOURCE_KEY)); + config.setConfigValue(map.get("previewListResource").toString()); + return toAjax(iSysConfigService.updateConfig(config)); + } + } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java index b63c155e4..93d4d46bb 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java @@ -1,31 +1,25 @@ package com.ruoyi.web.controller.system; -import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; -import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.system.domain.SysPost; import com.ruoyi.system.service.ISysPostService; +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 javax.servlet.http.HttpServletResponse; +import java.util.List; /** * 岗位信息操作处理 - * + * * @author ruoyi */ @RestController @@ -44,15 +38,14 @@ public class SysPostController extends BaseController { return postService.selectPagePostList(post); } - + @Log(title = "岗位管理", businessType = BusinessType.EXPORT) @PreAuthorize("@ss.hasPermi('system:post:export')") @GetMapping("/export") - public AjaxResult export(SysPost post) + public void export(SysPost post, HttpServletResponse response) { List list = postService.selectPostList(post); - ExcelUtil util = new ExcelUtil(SysPost.class); - return util.exportExcel(list, "岗位数据"); + ExcelUtil.exportExcel(list, "岗位数据", SysPost.class, response); } /** @@ -81,7 +74,7 @@ public class SysPostController extends BaseController { return AjaxResult.error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在"); } - post.setCreateBy(SecurityUtils.getUsername()); + post.setCreateBy(getUsername()); return toAjax(postService.insertPost(post)); } @@ -101,7 +94,7 @@ public class SysPostController extends BaseController { return AjaxResult.error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在"); } - post.setUpdateBy(SecurityUtils.getUsername()); + post.setUpdateBy(getUsername()); return toAjax(postService.updatePost(post)); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java index 39f5bc6d7..e106fa127 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java @@ -1,8 +1,6 @@ package com.ruoyi.web.controller.system; -import cn.hutool.core.util.StrUtil; import com.ruoyi.common.annotation.Log; -import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; @@ -11,8 +9,10 @@ import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.ServletUtils; -import com.ruoyi.common.utils.file.FileUploadUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.web.service.TokenService; +import com.ruoyi.system.domain.SysOss; +import com.ruoyi.system.service.ISysOssService; import com.ruoyi.system.service.ISysUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -37,6 +37,9 @@ public class SysProfileController extends BaseController @Autowired private TokenService tokenService; + @Autowired + private ISysOssService iSysOssService; + /** * 个人信息 */ @@ -59,12 +62,12 @@ public class SysProfileController extends BaseController @PutMapping public AjaxResult updateProfile(@RequestBody SysUser user) { - if (StrUtil.isNotEmpty(user.getPhonenumber()) + if (StringUtils.isNotEmpty(user.getPhonenumber()) && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) { return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); } - if (StrUtil.isNotEmpty(user.getEmail()) + if (StringUtils.isNotEmpty(user.getEmail()) && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) { return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); @@ -124,7 +127,8 @@ public class SysProfileController extends BaseController if (!file.isEmpty()) { LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); - String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file); + SysOss oss = iSysOssService.upload(file); + String avatar = oss.getUrl(); if (userService.updateUserAvatar(loginUser.getUsername(), avatar)) { Map ajax = new HashMap<>(); diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java new file mode 100644 index 000000000..4c2cc7c66 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java @@ -0,0 +1,38 @@ +package com.ruoyi.web.controller.system; + +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.domain.model.RegisterBody; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.framework.web.service.SysRegisterService; +import com.ruoyi.system.service.ISysConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +/** + * 注册验证 + * + * @author ruoyi + */ +@RestController +public class SysRegisterController extends BaseController +{ + @Autowired + private SysRegisterService registerService; + + @Autowired + private ISysConfigService configService; + + @PostMapping("/register") + public AjaxResult register(@RequestBody RegisterBody user) + { + if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) + { + return error("当前系统没有开启注册功能!"); + } + String msg = registerService.register(user); + return StringUtils.isEmpty(msg) ? success() : error(msg); + } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java index 5701aa1a4..c8344b86b 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java @@ -1,6 +1,5 @@ package com.ruoyi.web.controller.system; -import cn.hutool.core.lang.Validator; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.core.controller.BaseController; @@ -10,8 +9,8 @@ import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; -import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.web.service.SysPermissionService; import com.ruoyi.framework.web.service.TokenService; @@ -23,6 +22,7 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; import java.util.List; /** @@ -56,11 +56,10 @@ public class SysRoleController extends BaseController @Log(title = "角色管理", businessType = BusinessType.EXPORT) @PreAuthorize("@ss.hasPermi('system:role:export')") @GetMapping("/export") - public AjaxResult export(SysRole role) + public void export(SysRole role, HttpServletResponse response) { List list = roleService.selectRoleList(role); - ExcelUtil util = new ExcelUtil(SysRole.class); - return util.exportExcel(list, "角色数据"); + ExcelUtil.exportExcel(list, "角色数据", SysRole.class, response); } /** @@ -89,7 +88,7 @@ public class SysRoleController extends BaseController { return AjaxResult.error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); } - role.setCreateBy(SecurityUtils.getUsername()); + role.setCreateBy(getUsername()); return toAjax(roleService.insertRole(role)); } @@ -111,13 +110,13 @@ public class SysRoleController extends BaseController { return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); } - role.setUpdateBy(SecurityUtils.getUsername()); + role.setUpdateBy(getUsername()); if (roleService.updateRole(role) > 0) { // 更新缓存用户权限 LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); - if (Validator.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())); @@ -149,7 +148,7 @@ public class SysRoleController extends BaseController public AjaxResult changeStatus(@RequestBody SysRole role) { roleService.checkRoleAllowed(role); - role.setUpdateBy(SecurityUtils.getUsername()); + role.setUpdateBy(getUsername()); return toAjax(roleService.updateRoleStatus(role)); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java index a67615f39..9e0633c85 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java @@ -1,10 +1,13 @@ package com.ruoyi.web.controller.system; -import cn.hutool.core.lang.Validator; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.core.domain.entity.SysRole; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.model.LoginUser; @@ -12,8 +15,11 @@ import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.web.service.TokenService; +import com.ruoyi.system.domain.vo.SysUserExportVo; +import com.ruoyi.system.domain.vo.SysUserImportVo; import com.ruoyi.system.service.ISysPostService; import com.ruoyi.system.service.ISysRoleService; import com.ruoyi.system.service.ISysUserService; @@ -23,6 +29,8 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -62,11 +70,19 @@ public class SysUserController extends BaseController @Log(title = "用户管理", businessType = BusinessType.EXPORT) @PreAuthorize("@ss.hasPermi('system:user:export')") @GetMapping("/export") - public AjaxResult export(SysUser user) + public void export(SysUser user, HttpServletResponse response) { List list = userService.selectUserList(user); - ExcelUtil util = new ExcelUtil(SysUser.class); - return util.exportExcel(list, "用户数据"); + List listVo = BeanUtil.copyToList(list, SysUserExportVo.class); + for (int i = 0; i < list.size(); i++) { + SysDept dept = list.get(i).getDept(); + SysUserExportVo vo = listVo.get(i); + if (ObjectUtil.isNotEmpty(dept)) { + vo.setDeptName(dept.getDeptName()); + vo.setLeader(dept.getLeader()); + } + } + ExcelUtil.exportExcel(listVo, "用户数据", SysUserExportVo.class, response); } @Log(title = "用户管理", businessType = BusinessType.IMPORT) @@ -74,19 +90,18 @@ public class SysUserController extends BaseController @PostMapping("/importData") public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception { - ExcelUtil util = new ExcelUtil(SysUser.class); - List userList = util.importExcel(file.getInputStream()); - LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); + List userListVo = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class); + List userList = BeanUtil.copyToList(userListVo, SysUser.class); + LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); String operName = loginUser.getUsername(); String message = userService.importUser(userList, updateSupport, operName); return AjaxResult.success(message); } @GetMapping("/importTemplate") - public AjaxResult importTemplate() + public void importTemplate(HttpServletResponse response) { - ExcelUtil util = new ExcelUtil(SysUser.class); - return util.importTemplateExcel("用户数据"); + ExcelUtil.exportExcel(new ArrayList<>(), "用户数据", SysUserImportVo.class, response); } /** @@ -100,7 +115,7 @@ public class SysUserController extends BaseController List 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 (Validator.isNotNull(userId)) + if (StringUtils.isNotNull(userId)) { ajax.put("user", userService.selectUserById(userId)); ajax.put("postIds", postService.selectPostListByUserId(userId)); @@ -121,17 +136,17 @@ public class SysUserController extends BaseController { return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,登录账号已存在"); } - else if (Validator.isNotEmpty(user.getPhonenumber()) + else if (StringUtils.isNotEmpty(user.getPhonenumber()) && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) { return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,手机号码已存在"); } - else if (Validator.isNotEmpty(user.getEmail()) + else if (StringUtils.isNotEmpty(user.getEmail()) && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) { return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在"); } - user.setCreateBy(SecurityUtils.getUsername()); + user.setCreateBy(getUsername()); user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); return toAjax(userService.insertUser(user)); } @@ -145,17 +160,17 @@ public class SysUserController extends BaseController public AjaxResult edit(@Validated @RequestBody SysUser user) { userService.checkUserAllowed(user); - if (Validator.isNotEmpty(user.getPhonenumber()) + if (StringUtils.isNotEmpty(user.getPhonenumber()) && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) { return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); } - else if (Validator.isNotEmpty(user.getEmail()) + else if (StringUtils.isNotEmpty(user.getEmail()) && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) { return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); } - user.setUpdateBy(SecurityUtils.getUsername()); + user.setUpdateBy(getUsername()); return toAjax(userService.updateUser(user)); } @@ -167,6 +182,10 @@ public class SysUserController extends BaseController @DeleteMapping("/{userIds}") public AjaxResult remove(@PathVariable Long[] userIds) { + if (ArrayUtil.contains(userIds, getUserId())) + { + return error("当前用户不能删除"); + } return toAjax(userService.deleteUserByIds(userIds)); } @@ -180,7 +199,7 @@ public class SysUserController extends BaseController { userService.checkUserAllowed(user); user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); - user.setUpdateBy(SecurityUtils.getUsername()); + user.setUpdateBy(getUsername()); return toAjax(userService.resetPwd(user)); } @@ -193,7 +212,7 @@ public class SysUserController extends BaseController public AjaxResult changeStatus(@RequestBody SysUser user) { userService.checkUserAllowed(user); - user.setUpdateBy(SecurityUtils.getUsername()); + user.setUpdateBy(getUsername()); return toAjax(userService.updateUserStatus(user)); } diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index 6491c8557..780499400 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -4,7 +4,9 @@ spring: type: com.alibaba.druid.pool.DruidDataSource # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content dynamic: - #设置默认的数据源或者数据源组,默认值即为 master + # 性能分析插件(有性能损耗 不建议生产环境使用) + p6spy: true + # 设置默认的数据源或者数据源组,默认值即为 master primary: master datasource: # 主库数据源 @@ -122,62 +124,11 @@ spring: admin: # Spring Boot Admin Client 客户端的相关配置 client: + # 增加客户端开关 + enabled: true # 设置 Spring Boot Admin Server 地址 url: http://localhost:9090/admin instance: prefer-ip: true # 注册实例时,优先使用 IP username: ruoyi password: 123456 - -# Actuator 监控端点的配置项 -management: - endpoints: - web: - # Actuator 提供的 API 接口的根目录。默认为 /actuator - base-path: /actuator - exposure: - # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 - # 生产环境不建议放开所有 根据项目需求放开即可 - include: '*' - endpoint: - logfile: - external-file: ./logs/sys-console.log - ---- # OSS 云存储(界面 <参数设置> 可切换) -cloud-storage: - # minio配置 - minio: - endpoint: http://localhost:9000 - accessKey: ruoyi - secretKey: ruoyi123 - bucketName: ruoyi - # 七牛云配置 - qiniu: - domain: http://XXX.XXXX.com - prefix: - accessKey: XXXXXXXXXXXXXXX - secretKey: XXXXXXXXXXXXXXX - bucketName: ruoyi - isHttps: false - # z0 华东 z1 华北 z2 华南 na0 北美 as0 东南亚 - # 不填为自动获取(性能低 易出问题) - region: z0 - # 阿里云配置 - aliyun: - endpoint: http://oss-cn-beijing.aliyuncs.com - prefix: - accessKeyId: XXXXXXXXXXXXXXX - accessKeySecret: XXXXXXXXXXXXXXX - bucketName: ruoyi - # 腾讯云配置 - qcloud: - endpoint: http://cos.ap-beijing.myqcloud.com - prefix: - secretId: XXXXXXXXXXXXXXX - secretKey: XXXXXXXXXXXXXXX - # 腾讯云bucket名规则 格式为 BucketName-APPID 此处填写的存储桶名称必须为此格式 - bucketName: ruoyi-1250000000 - isHttps: false - # 地域名参考官方文档 - # https://cloud.tencent.com/document/product/436/6224 - region: ap-beijing diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml index 2640bc0eb..446d54d45 100644 --- a/ruoyi-admin/src/main/resources/application-prod.yml +++ b/ruoyi-admin/src/main/resources/application-prod.yml @@ -4,7 +4,9 @@ spring: type: com.alibaba.druid.pool.DruidDataSource # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content dynamic: - #设置默认的数据源或者数据源组,默认值即为 master + # 性能分析插件(有性能损耗 不建议生产环境使用) + p6spy: false + # 设置默认的数据源或者数据源组,默认值即为 master primary: master datasource: # 主库数据源 @@ -122,62 +124,11 @@ spring: admin: # Spring Boot Admin Client 客户端的相关配置 client: + # 增加客户端开关 + enabled: true # 设置 Spring Boot Admin Server 地址 url: http://172.30.0.90:9090/admin instance: prefer-ip: true # 注册实例时,优先使用 IP username: ruoyi password: 123456 - -# Actuator 监控端点的配置项 -management: - endpoints: - web: - # Actuator 提供的 API 接口的根目录。默认为 /actuator - base-path: /actuator - exposure: - # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 - # 生产环境不建议放开所有 根据项目需求放开即可 - include: health,info - endpoint: - logfile: - external-file: ./logs/sys-console.log - ---- # OSS 云存储(界面 <参数设置> 可切换) -cloud-storage: - # minio配置 - minio: - endpoint: http://172.30.0.54:9000 - accessKey: ruoyi - secretKey: ruoyi123 - bucketName: ruoyi - # 七牛云配置 - qiniu: - domain: http://XXX.XXXX.com - prefix: - accessKey: XXXXXXXXXXXXXXX - secretKey: XXXXXXXXXXXXXXX - bucketName: ruoyi - isHttps: false - # z0 华东 z1 华北 z2 华南 na0 北美 as0 东南亚 - # 不填为自动获取(性能低 易出问题) - region: z0 - # 阿里云配置 - aliyun: - endpoint: http://oss-cn-beijing.aliyuncs.com - prefix: - accessKeyId: XXXXXXXXXXXXXXX - accessKeySecret: XXXXXXXXXXXXXXX - bucketName: ruoyi - # 腾讯云配置 - qcloud: - endpoint: http://cos.ap-beijing.myqcloud.com - prefix: - secretId: XXXXXXXXXXXXXXX - secretKey: XXXXXXXXXXXXXXX - # 腾讯云bucket名规则 格式为 BucketName-APPID 此处填写的存储桶名称必须为此格式 - bucketName: ruoyi-1250000000 - isHttps: false - # 地域名参考官方文档 - # https://cloud.tencent.com/document/product/436/6224 - region: ap-beijing diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 4a52958a3..8b633f852 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -8,8 +8,6 @@ ruoyi: copyrightYear: 2021 # 实例演示开关 demoEnabled: true - # 文件路径 - profile: ./ruoyi/uploadPath # 获取ip地址开关 addressEnabled: true @@ -107,6 +105,11 @@ token: # 令牌有效期(默认30分钟) expireTime: 30 +# 重复提交 +repeat-submit: + # 全局间隔时间(毫秒) + intervalTime: 1000 + # MyBatisPlus配置 # https://baomidou.com/config/ mybatis-plus: @@ -159,8 +162,10 @@ mybatis-plus: localCacheScope: SESSION # 开启Mybatis二级缓存,默认为 true cacheEnabled: false - # 更详细的日志输出 会有性能损耗 - # logImpl: org.apache.ibatis.logging.stdout.StdOutImpl + # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl + # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl + # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl + logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl global-config: # 是否打印 Logo banner banner: true @@ -223,7 +228,7 @@ xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) - excludes: /system/notice/* + excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* @@ -284,6 +289,20 @@ lock4j: # 分布式锁的超时时间,默认为 30 毫秒 expire: 30000 +--- # Actuator 监控端点的配置项 +management: + endpoints: + web: + # Actuator 提供的 API 接口的根目录。默认为 /actuator + base-path: /actuator + exposure: + # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + # 生产环境不建议放开所有 根据项目需求放开即可 + include: @endpoints.include@ + endpoint: + logfile: + external-file: ./logs/sys-console.log + --- # 定时任务配置 spring: quartz: diff --git a/ruoyi-admin/src/main/resources/i18n/messages.properties b/ruoyi-admin/src/main/resources/i18n/messages.properties index d63aa1f8a..3e4694f62 100644 --- a/ruoyi-admin/src/main/resources/i18n/messages.properties +++ b/ruoyi-admin/src/main/resources/i18n/messages.properties @@ -15,10 +15,11 @@ length.not.valid=长度必须在{min}到{max}个字符之间 user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 user.password.not.valid=* 5-50个字符 - + user.email.not.valid=邮箱格式错误 user.mobile.phone.number.not.valid=手机号格式错误 user.login.success=登录成功 +user.register.success=注册成功 user.notfound=请重新登录 user.forcelogout=管理员强制退出,请重新登录 user.unknown.error=未知错误,请重新登录 diff --git a/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties index 418706543..8a3fba3fd 100644 --- a/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties +++ b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties @@ -16,8 +16,8 @@ user.password.not.valid= user.email.not.valid= user.mobile.phone.number.not.valid= user.login.success= +user.register.success=register success user.notfound= -user.forcelogout= user.unknown.error= ##文件上传消息 diff --git a/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties index d63aa1f8a..3e4694f62 100644 --- a/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties +++ b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties @@ -15,10 +15,11 @@ length.not.valid=长度必须在{min}到{max}个字符之间 user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 user.password.not.valid=* 5-50个字符 - + user.email.not.valid=邮箱格式错误 user.mobile.phone.number.not.valid=手机号格式错误 user.login.success=登录成功 +user.register.success=注册成功 user.notfound=请重新登录 user.forcelogout=管理员强制退出,请重新登录 user.unknown.error=未知错误,请重新登录 diff --git a/ruoyi-admin/src/main/resources/spy.properties b/ruoyi-admin/src/main/resources/spy.properties new file mode 100644 index 000000000..b361dbbef --- /dev/null +++ b/ruoyi-admin/src/main/resources/spy.properties @@ -0,0 +1,26 @@ +# p6spy ܷļ +modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory +# Զ־ӡ +logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger +#־̨ +appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger +# ʹ־ϵͳ¼ sql +#appender=com.p6spy.engine.spy.appender.Slf4JLogger +# p6spy driver +#deregisterdrivers=true +# ȡJDBC URLǰ׺ +useprefix=true +# ü¼ Log ,ȥĽerror,info,batch,debug,statement,commit,rollback,result,resultset. +excludecategories=info,debug,result,commit,resultset +# ڸʽ +dateformat=yyyy-MM-dd HH:mm:ss +# ʵɶ +#driverlist=org.h2.Driver +# ǷSQL¼ +outagedetection=true +# SQL¼׼ 2 +outagedetectioninterval=2 +# Ƿ Log +filter=true +# Log ʱųıбԶŷָ +exclude=QRTZ_ diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index 016c4576d..c242a0823 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -5,7 +5,7 @@ ruoyi-vue-plus com.ruoyi - 2.6.0 + 3.0.0 4.0.0 @@ -59,6 +59,11 @@ poi-ooxml + + com.alibaba + easyexcel + + org.yaml @@ -147,6 +152,11 @@ com.baomidou dynamic-datasource-spring-boot-starter + + + p6spy + p6spy + com.baomidou diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java deleted file mode 100644 index 50482c572..000000000 --- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java +++ /dev/null @@ -1,165 +0,0 @@ -package com.ruoyi.common.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.math.BigDecimal; - -/** - * 自定义导出Excel数据注解 - * - * @author ruoyi - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface Excel -{ - /** - * 导出时在excel中排序 - */ - public int sort() default Integer.MAX_VALUE; - - /** - * 导出到Excel中的名字. - */ - public String name() default ""; - - /** - * 日期格式, 如: yyyy-MM-dd - */ - public String dateFormat() default ""; - - /** - * 如果是字典类型,请设置字典的type值 (如: sys_user_sex) - */ - public String dictType() default ""; - - /** - * 读取内容转表达式 (如: 0=男,1=女,2=未知) - */ - public String readConverterExp() default ""; - - /** - * 分隔符,读取字符串组内容 - */ - public String separator() default ","; - - /** - * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化) - */ - public int scale() default -1; - - /** - * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN - */ - public int roundingMode() default BigDecimal.ROUND_HALF_EVEN; - - /** - * 导出类型(0数字 1字符串) - */ - public ColumnType cellType() default ColumnType.STRING; - - /** - * 导出时在excel中每个列的高度 单位为字符 - */ - public double height() default 14; - - /** - * 导出时在excel中每个列的宽 单位为字符 - */ - public double width() default 16; - - /** - * 文字后缀,如% 90 变成90% - */ - public String suffix() default ""; - - /** - * 当值为空时,字段的默认值 - */ - public String defaultValue() default ""; - - /** - * 提示信息 - */ - public String prompt() default ""; - - /** - * 设置只能选择不能输入的列内容. - */ - public String[] combo() default {}; - - /** - * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写. - */ - public boolean isExport() default true; - - /** - * 另一个类中的属性名称,支持多级获取,以小数点隔开 - */ - public String targetAttr() default ""; - - /** - * 是否自动统计数据,在最后追加一行统计数据总和 - */ - public boolean isStatistics() default false; - - /** - * 导出字段对齐方式(0:默认;1:靠左;2:居中;3:靠右) - */ - Align align() default Align.AUTO; - - public enum Align - { - AUTO(0), LEFT(1), CENTER(2), RIGHT(3); - private final int value; - - Align(int value) - { - this.value = value; - } - - public int value() - { - return this.value; - } - } - - /** - * 字段类型(0:导出导入;1:仅导出;2:仅导入) - */ - Type type() default Type.ALL; - - public enum Type - { - ALL(0), EXPORT(1), IMPORT(2); - private final int value; - - Type(int value) - { - this.value = value; - } - - public int value() - { - return this.value; - } - } - - public enum ColumnType - { - NUMERIC(0), STRING(1), IMAGE(2); - private final int value; - - ColumnType(int value) - { - this.value = value; - } - - public int value() - { - return this.value; - } - } -} \ No newline at end of file diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/ExcelDictFormat.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/ExcelDictFormat.java new file mode 100644 index 000000000..a51116b5c --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/ExcelDictFormat.java @@ -0,0 +1,30 @@ +package com.ruoyi.common.annotation; + +import java.lang.annotation.*; + +/** + * 字典格式化 + * + * @author Lion Li + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelDictFormat { + + /** + * 如果是字典类型,请设置字典的type值 (如: sys_user_sex) + */ + String dictType() default ""; + + /** + * 读取内容转表达式 (如: 0=男,1=女,2=未知) + */ + String readConverterExp() default ""; + + /** + * 分隔符,读取字符串组内容 + */ + String separator() default ","; + +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java deleted file mode 100644 index 940763f06..000000000 --- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.ruoyi.common.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Excel注解集 - * - * @author ruoyi - */ -@Target(ElementType.FIELD) -@Retention(RetentionPolicy.RUNTIME) -public @interface Excels -{ - Excel[] value(); -} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java new file mode 100644 index 000000000..564203861 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java @@ -0,0 +1,40 @@ +package com.ruoyi.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.ruoyi.common.constant.Constants; +import com.ruoyi.common.enums.LimitType; + +/** + * 限流注解 + * + * @author ruoyi + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RateLimiter +{ + /** + * 限流key + */ + public String key() default Constants.RATE_LIMIT_KEY; + + /** + * 限流时间,单位秒 + */ + public int time() default 60; + + /** + * 限流次数 + */ + public int count() default 100; + + /** + * 限流类型 + */ + public LimitType limitType() default LimitType.DEFAULT; +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java index 628eef1ef..c2bbee476 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java @@ -1,23 +1,29 @@ -package com.ruoyi.common.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * 自定义注解防止表单重复提交 - * - * @author ruoyi - * - */ -@Inherited -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface RepeatSubmit -{ - -} +package com.ruoyi.common.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.concurrent.TimeUnit; + +/** + * 自定义注解防止表单重复提交 + * + * @author Lion Li + */ +@Inherited +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RepeatSubmit { + + /** + * 默认使用全局配置 + */ + int intervalTime() default 0; + + TimeUnit timeUnit() default TimeUnit.MILLISECONDS; + +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java index 682bebda4..408295a36 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java @@ -9,7 +9,7 @@ import org.springframework.stereotype.Component; /** * 读取项目相关配置 - * + * * @author ruoyi */ @@ -32,45 +32,13 @@ public class RuoYiConfig /** 实例演示开关 */ private boolean demoEnabled; - /** 上传路径 */ - @Getter - private static String profile; - /** 获取地址开关 */ @Getter private static boolean addressEnabled; - public void setProfile(String profile) - { - RuoYiConfig.profile = profile; - } - public void setAddressEnabled(boolean addressEnabled) { RuoYiConfig.addressEnabled = addressEnabled; } - /** - * 获取头像上传路径 - */ - public static String getAvatarPath() - { - return getProfile() + "/avatar"; - } - - /** - * 获取下载路径 - */ - public static String getDownloadPath() - { - return getProfile() + "/download/"; - } - - /** - * 获取上传路径 - */ - public static String getUploadPath() - { - return getProfile() + "/upload"; - } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java index a87117893..c1a6469d7 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java @@ -1,5 +1,7 @@ package com.ruoyi.common.constant; +import io.jsonwebtoken.Claims; + /** * 通用常量信息 * @@ -47,6 +49,11 @@ public class Constants */ public static final String LOGOUT = "Logout"; + /** + * 注册 + */ + public static final String REGISTER = "Register"; + /** * 登录失败 */ @@ -67,6 +74,11 @@ public class Constants */ public static final String REPEAT_SUBMIT_KEY = "repeat_submit:"; + /** + * 限流 redis key + */ + public static final String RATE_LIMIT_KEY = "rate_limit:"; + /** * 验证码有效期(分钟) */ @@ -95,7 +107,7 @@ public class Constants /** * 用户名称 */ - public static final String JWT_USERNAME = "sub"; + public static final String JWT_USERNAME = Claims.SUBJECT; /** * 用户头像 @@ -122,18 +134,9 @@ public class Constants */ public static final String SYS_DICT_KEY = "sys_dict:"; - /** - * 资源映射路径 前缀 - */ - public static final String RESOURCE_PREFIX = "/profile"; - /** * RMI 远程方法调用 */ public static final String LOOKUP_RMI = "rmi://"; - /** - * 资源映射路径 前缀 - */ - public static final String REDIS_LOCK_KEY = "redis_lock:"; } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java index eda4ab6a8..a936cd838 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java @@ -63,4 +63,16 @@ public class UserConstants /** 校验返回结果码 */ public final static String UNIQUE = "0"; public final static String NOT_UNIQUE = "1"; + + /** + * 用户名长度限制 + */ + public static final int USERNAME_MIN_LENGTH = 2; + public static final int USERNAME_MAX_LENGTH = 20; + + /** + * 密码长度限制 + */ + public static final int PASSWORD_MIN_LENGTH = 5; + public static final int PASSWORD_MAX_LENGTH = 20; } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/convert/ExcelDictConvert.java b/ruoyi-common/src/main/java/com/ruoyi/common/convert/ExcelDictConvert.java new file mode 100644 index 000000000..58560d0b1 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/convert/ExcelDictConvert.java @@ -0,0 +1,69 @@ +package com.ruoyi.common.convert; + +import cn.hutool.core.annotation.AnnotationUtil; +import cn.hutool.core.convert.Convert; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.ruoyi.common.annotation.ExcelDictFormat; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.poi.ExcelUtil; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; + +/** + * 字典格式化转换处理 + * + * @author Lion Li + */ +@Slf4j +public class ExcelDictConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Object.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return null; + } + + @Override + public Object convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + ExcelDictFormat anno = getAnnotation(contentProperty.getField()); + String type = anno.dictType(); + String label = cellData.getStringValue(); + String value; + if (StringUtils.isBlank(type)) { + value = ExcelUtil.reverseByExp(label, anno.readConverterExp(), anno.separator()); + } else { + value = ExcelUtil.reverseDictByExp(label, type, anno.separator()); + } + return Convert.convert(contentProperty.getField().getType(), value); + } + + @Override + public CellData convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (StringUtils.isNull(object)) { + return new CellData<>(""); + } + ExcelDictFormat anno = getAnnotation(contentProperty.getField()); + String type = anno.dictType(); + String value = Convert.toStr(object); + String label; + if (StringUtils.isBlank(type)) { + label = ExcelUtil.convertByExp(value, anno.readConverterExp(), anno.separator()); + } else { + label = ExcelUtil.convertDictByExp(value, type, anno.separator()); + } + return new CellData<>(label); + } + + private ExcelDictFormat getAnnotation(Field field) { + return AnnotationUtil.getAnnotation(field, ExcelDictFormat.class); + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java index 632c0fb4d..39158678f 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java @@ -1,7 +1,9 @@ package com.ruoyi.common.core.controller; -import cn.hutool.core.util.StrUtil; import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.domain.model.LoginUser; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -73,6 +75,38 @@ public class BaseController */ public String redirect(String url) { - return StrUtil.format("redirect:{}", url); + return StringUtils.format("redirect:{}", url); + } + + /** + * 获取用户缓存信息 + */ + public LoginUser getLoginUser() + { + return SecurityUtils.getLoginUser(); + } + + /** + * 获取登录用户id + */ + public Long getUserId() + { + return getLoginUser().getUserId(); + } + + /** + * 获取登录部门id + */ + public Long getDeptId() + { + return getLoginUser().getDeptId(); + } + + /** + * 获取登录用户名 + */ + public String getUsername() + { + return getLoginUser().getUsername(); } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java index d66686be1..72d624a9c 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java @@ -1,5 +1,6 @@ package com.ruoyi.common.core.domain; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; @@ -18,29 +19,50 @@ import java.util.Map; @Data @NoArgsConstructor @Accessors(chain = true) -public class BaseEntity implements Serializable -{ - private static final long serialVersionUID = 1L; +public class BaseEntity implements Serializable { - /** 搜索值 */ - private String searchValue; + private static final long serialVersionUID = 1L; - /** 创建者 */ - private String createBy; + /** + * 搜索值 + */ + @ApiModelProperty(value = "搜索值") + private String searchValue; - /** 创建时间 */ - private Date createTime; + /** + * 创建者 + */ + @ApiModelProperty(value = "创建者") + private String createBy; - /** 更新者 */ - private String updateBy; + /** + * 创建时间 + */ + @ApiModelProperty(value = "创建时间") + private Date createTime; - /** 更新时间 */ - private Date updateTime; + /** + * 更新者 + */ + @ApiModelProperty(value = "更新者") + private String updateBy; - /** 备注 */ - private String remark; + /** + * 更新时间 + */ + @ApiModelProperty(value = "更新时间") + private Date updateTime; - /** 请求参数 */ - private Map params = new HashMap<>(); + /** + * 备注 + */ + @ApiModelProperty(value = "备注") + private String remark; + + /** + * 请求参数 + */ + @ApiModelProperty(value = "请求参数") + private Map params = new HashMap<>(); } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java index 2569fac21..8db10aa2b 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java @@ -1,38 +1,56 @@ -package com.ruoyi.common.core.domain; - -import lombok.*; -import lombok.experimental.Accessors; - -import java.util.ArrayList; -import java.util.List; - -/** - * Tree基类 - * - * @author ruoyi - */ - -@EqualsAndHashCode(callSuper = true) -@Data -@NoArgsConstructor -@Accessors(chain = true) -public class TreeEntity extends BaseEntity -{ - private static final long serialVersionUID = 1L; - - /** 父菜单名称 */ - private String parentName; - - /** 父菜单ID */ - private Long parentId; - - /** 显示顺序 */ - private Integer orderNum; - - /** 祖级列表 */ - private String ancestors; - - /** 子部门 */ - private List children = new ArrayList<>(); - -} +package com.ruoyi.common.core.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.util.ArrayList; +import java.util.List; + +/** + * Tree基类 + * + * @author ruoyi + */ + +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@Accessors(chain = true) +public class TreeEntity extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 父菜单名称 + */ + @ApiModelProperty(value = "父菜单名称") + private String parentName; + + /** + * 父菜单ID + */ + @ApiModelProperty(value = "父菜单ID") + private Long parentId; + + /** + * 显示顺序 + */ + @ApiModelProperty(value = "显示顺序") + private Integer orderNum; + + /** + * 祖级列表 + */ + @ApiModelProperty(value = "祖级列表") + private String ancestors; + + /** + * 子部门 + */ + @ApiModelProperty(value = "子部门") + private List children = new ArrayList<>(); + +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java index 72240bc18..62056e027 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java @@ -1,7 +1,6 @@ package com.ruoyi.common.core.domain.entity; import com.baomidou.mybatisplus.annotation.*; -import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; @@ -14,7 +13,7 @@ import java.util.*; /** * 部门表 sys_dept - * + * * @author ruoyi */ @@ -22,78 +21,107 @@ import java.util.*; @NoArgsConstructor @Accessors(chain = true) @TableName("sys_dept") -public class SysDept implements Serializable -{ - private static final long serialVersionUID = 1L; +public class SysDept implements Serializable { + private static final long serialVersionUID = 1L; - /** 部门ID */ - @TableId(value = "dept_id",type = IdType.AUTO) - private Long deptId; + /** + * 部门ID + */ + @TableId(value = "dept_id", type = IdType.AUTO) + private Long deptId; - /** 父部门ID */ - private Long parentId; + /** + * 父部门ID + */ + private Long parentId; - /** 祖级列表 */ - private String ancestors; + /** + * 祖级列表 + */ + private String ancestors; - /** 部门名称 */ - @NotBlank(message = "部门名称不能为空") - @Size(min = 0, max = 30, message = "部门名称长度不能超过30个字符") - private String deptName; + /** + * 部门名称 + */ + @NotBlank(message = "部门名称不能为空") + @Size(min = 0, max = 30, message = "部门名称长度不能超过30个字符") + private String deptName; - /** 显示顺序 */ - @NotBlank(message = "显示顺序不能为空") - private String orderNum; + /** + * 显示顺序 + */ + @NotBlank(message = "显示顺序不能为空") + private String orderNum; - /** 负责人 */ - private String leader; + /** + * 负责人 + */ + private String leader; - /** 联系电话 */ - @Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符") - private String phone; + /** + * 联系电话 + */ + @Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符") + private String phone; - /** 邮箱 */ - @Email(message = "邮箱格式不正确") - @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符") - private String email; + /** + * 邮箱 + */ + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符") + private String email; - /** 部门状态:0正常,1停用 */ - private String status; + /** + * 部门状态:0正常,1停用 + */ + private String status; - /** 删除标志(0代表存在 2代表删除) */ - @TableLogic - private String delFlag; + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; - /** 父部门名称 */ - @TableField(exist = false) - private String parentName; + /** + * 父部门名称 + */ + @TableField(exist = false) + private String parentName; - /** 创建者 */ - @TableField(fill = FieldFill.INSERT) - private String createBy; + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private String createBy; - /** 创建时间 */ - @TableField(fill = FieldFill.INSERT) - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date createTime; + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; - /** 更新者 */ - @TableField(fill = FieldFill.INSERT_UPDATE) - private String updateBy; + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updateBy; - /** 更新时间 */ - @TableField(fill = FieldFill.INSERT_UPDATE) - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date updateTime; - - /** 子部门 */ - @TableField(exist = false) - private List children = new ArrayList(); + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; - /** - * 请求参数 - */ - @TableField(exist = false) - private Map params = new HashMap<>(); + /** + * 子部门 + */ + @TableField(exist = false) + private List children = new ArrayList(); + + /** + * 请求参数 + */ + @TableField(exist = false) + private Map params = new HashMap<>(); } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java index c98f9fc37..e8bc0f156 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java @@ -1,10 +1,11 @@ package com.ruoyi.common.core.domain.entity; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; import com.baomidou.mybatisplus.annotation.*; -import com.fasterxml.jackson.annotation.JsonFormat; -import com.ruoyi.common.annotation.Excel; -import com.ruoyi.common.annotation.Excel.ColumnType; +import com.ruoyi.common.annotation.ExcelDictFormat; import com.ruoyi.common.constant.UserConstants; +import com.ruoyi.common.convert.ExcelDictConvert; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; @@ -18,7 +19,7 @@ import java.util.Map; /** * 字典数据表 sys_dict_data - * + * * @author ruoyi */ @@ -26,82 +27,109 @@ import java.util.Map; @NoArgsConstructor @Accessors(chain = true) @TableName("sys_dict_data") -public class SysDictData implements Serializable -{ - private static final long serialVersionUID = 1L; +@ExcelIgnoreUnannotated +public class SysDictData implements Serializable { + private static final long serialVersionUID = 1L; - /** 字典编码 */ - @Excel(name = "字典编码", cellType = ColumnType.NUMERIC) - @TableId(value = "dict_code",type = IdType.AUTO) - private Long dictCode; + /** + * 字典编码 + */ + @ExcelProperty(value = "字典编码") + @TableId(value = "dict_code", type = IdType.AUTO) + private Long dictCode; - /** 字典排序 */ - @Excel(name = "字典排序", cellType = ColumnType.NUMERIC) - private Long dictSort; + /** + * 字典排序 + */ + @ExcelProperty(value = "字典排序") + private Long dictSort; - /** 字典标签 */ - @Excel(name = "字典标签") - @NotBlank(message = "字典标签不能为空") - @Size(min = 0, max = 100, message = "字典标签长度不能超过100个字符") - private String dictLabel; + /** + * 字典标签 + */ + @ExcelProperty(value = "字典标签") + @NotBlank(message = "字典标签不能为空") + @Size(min = 0, max = 100, message = "字典标签长度不能超过100个字符") + private String dictLabel; - /** 字典键值 */ - @Excel(name = "字典键值") - @NotBlank(message = "字典键值不能为空") - @Size(min = 0, max = 100, message = "字典键值长度不能超过100个字符") - private String dictValue; + /** + * 字典键值 + */ + @ExcelProperty(value = "字典键值") + @NotBlank(message = "字典键值不能为空") + @Size(min = 0, max = 100, message = "字典键值长度不能超过100个字符") + private String dictValue; - /** 字典类型 */ - @Excel(name = "字典类型") - @NotBlank(message = "字典类型不能为空") - @Size(min = 0, max = 100, message = "字典类型长度不能超过100个字符") - private String dictType; + /** + * 字典类型 + */ + @ExcelProperty(value = "字典类型") + @NotBlank(message = "字典类型不能为空") + @Size(min = 0, max = 100, message = "字典类型长度不能超过100个字符") + private String dictType; - /** 样式属性(其他样式扩展) */ - @Size(min = 0, max = 100, message = "样式属性长度不能超过100个字符") - private String cssClass; + /** + * 样式属性(其他样式扩展) + */ + @Size(min = 0, max = 100, message = "样式属性长度不能超过100个字符") + private String cssClass; - /** 表格字典样式 */ - private String listClass; + /** + * 表格字典样式 + */ + private String listClass; - /** 是否默认(Y是 N否) */ - @Excel(name = "是否默认", readConverterExp = "Y=是,N=否") - private String isDefault; + /** + * 是否默认(Y是 N否) + */ + @ExcelProperty(value = "是否默认", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_yes_no") + private String isDefault; - /** 状态(0正常 1停用) */ - @Excel(name = "状态", readConverterExp = "0=正常,1=停用") - private String status; + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_common_status") + private String status; - /** 创建者 */ - @TableField(fill = FieldFill.INSERT) - private String createBy; + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private String createBy; - /** 创建时间 */ - @TableField(fill = FieldFill.INSERT) - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date createTime; + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; - /** 更新者 */ - @TableField(fill = FieldFill.INSERT_UPDATE) - private String updateBy; + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updateBy; - /** 更新时间 */ - @TableField(fill = FieldFill.INSERT_UPDATE) - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date updateTime; + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; - /** 备注 */ - private String remark; + /** + * 备注 + */ + private String remark; - /** - * 请求参数 - */ - @TableField(exist = false) - private Map params = new HashMap<>(); + /** + * 请求参数 + */ + @TableField(exist = false) + private Map params = new HashMap<>(); - public boolean getDefault() - { - return UserConstants.YES.equals(this.isDefault) ? true : false; - } + public boolean getDefault() { + return UserConstants.YES.equals(this.isDefault) ? true : false; + } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java index 48ed2529f..1108671d8 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java @@ -1,9 +1,10 @@ package com.ruoyi.common.core.domain.entity; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; import com.baomidou.mybatisplus.annotation.*; -import com.fasterxml.jackson.annotation.JsonFormat; -import com.ruoyi.common.annotation.Excel; -import com.ruoyi.common.annotation.Excel.ColumnType; +import com.ruoyi.common.annotation.ExcelDictFormat; +import com.ruoyi.common.convert.ExcelDictConvert; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; @@ -17,7 +18,7 @@ import java.util.Map; /** * 字典类型表 sys_dict_type - * + * * @author ruoyi */ @@ -25,56 +26,73 @@ import java.util.Map; @NoArgsConstructor @Accessors(chain = true) @TableName("sys_dict_type") -public class SysDictType implements Serializable -{ - private static final long serialVersionUID = 1L; +@ExcelIgnoreUnannotated +public class SysDictType implements Serializable { + private static final long serialVersionUID = 1L; - /** 字典主键 */ - @Excel(name = "字典主键", cellType = ColumnType.NUMERIC) - @TableId(value = "dict_id",type = IdType.AUTO) - private Long dictId; + /** + * 字典主键 + */ + @ExcelProperty(value = "字典主键") + @TableId(value = "dict_id", type = IdType.AUTO) + private Long dictId; - /** 字典名称 */ - @Excel(name = "字典名称") - @NotBlank(message = "字典名称不能为空") - @Size(min = 0, max = 100, message = "字典类型名称长度不能超过100个字符") - private String dictName; + /** + * 字典名称 + */ + @ExcelProperty(value = "字典名称") + @NotBlank(message = "字典名称不能为空") + @Size(min = 0, max = 100, message = "字典类型名称长度不能超过100个字符") + private String dictName; - /** 字典类型 */ - @Excel(name = "字典类型") - @NotBlank(message = "字典类型不能为空") - @Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符") - private String dictType; + /** + * 字典类型 + */ + @ExcelProperty(value = "字典类型") + @NotBlank(message = "字典类型不能为空") + @Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符") + private String dictType; - /** 状态(0正常 1停用) */ - @Excel(name = "状态", readConverterExp = "0=正常,1=停用") - private String status; + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_common_status") + private String status; - /** 创建者 */ - @TableField(fill = FieldFill.INSERT) - private String createBy; + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private String createBy; - /** 创建时间 */ - @TableField(fill = FieldFill.INSERT) - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date createTime; + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; - /** 更新者 */ - @TableField(fill = FieldFill.INSERT_UPDATE) - private String updateBy; + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updateBy; - /** 更新时间 */ - @TableField(fill = FieldFill.INSERT_UPDATE) - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date updateTime; + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; - /** 备注 */ - private String remark; + /** + * 备注 + */ + private String remark; - /** - * 请求参数 - */ - @TableField(exist = false) - private Map params = new HashMap<>(); + /** + * 请求参数 + */ + @TableField(exist = false) + private Map params = new HashMap<>(); } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java index b9d0e8dff..6fc86418e 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java @@ -13,7 +13,7 @@ import java.util.*; /** * 菜单权限表 sys_menu - * + * * @author ruoyi */ @@ -21,88 +21,129 @@ import java.util.*; @NoArgsConstructor @Accessors(chain = true) @TableName("sys_menu") -public class SysMenu implements Serializable -{ - private static final long serialVersionUID = 1L; +public class SysMenu implements Serializable { + private static final long serialVersionUID = 1L; - /** 菜单ID */ - @TableId(value = "menu_id",type = IdType.AUTO) - private Long menuId; + /** + * 菜单ID + */ + @TableId(value = "menu_id", type = IdType.AUTO) + private Long menuId; - /** 菜单名称 */ - @NotBlank(message = "菜单名称不能为空") - @Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符") - private String menuName; + /** + * 菜单名称 + */ + @NotBlank(message = "菜单名称不能为空") + @Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符") + private String menuName; - /** 父菜单名称 */ - @TableField(exist = false) - private String parentName; + /** + * 父菜单名称 + */ + @TableField(exist = false) + private String parentName; - /** 父菜单ID */ - private Long parentId; + /** + * 父菜单ID + */ + private Long parentId; - /** 显示顺序 */ - @NotBlank(message = "显示顺序不能为空") - private String orderNum; + /** + * 显示顺序 + */ + @NotBlank(message = "显示顺序不能为空") + private String orderNum; - /** 路由地址 */ - @Size(min = 0, max = 200, message = "路由地址不能超过200个字符") - private String path; + /** + * 路由地址 + */ + @Size(min = 0, max = 200, message = "路由地址不能超过200个字符") + private String path; - /** 组件路径 */ - @Size(min = 0, max = 200, message = "组件路径不能超过255个字符") - private String component; + /** + * 组件路径 + */ + @Size(min = 0, max = 200, message = "组件路径不能超过255个字符") + private String component; - /** 是否为外链(0是 1否) */ - private String isFrame; + /** + * 是否为外链(0是 1否) + */ + private String isFrame; - /** 是否缓存(0缓存 1不缓存) */ - private String isCache; + /** + * 是否缓存(0缓存 1不缓存) + */ + private String isCache; - /** 类型(M目录 C菜单 F按钮) */ - @NotBlank(message = "菜单类型不能为空") - private String menuType; + /** + * 类型(M目录 C菜单 F按钮) + */ + @NotBlank(message = "菜单类型不能为空") + private String menuType; - /** 显示状态(0显示 1隐藏) */ - private String visible; - - /** 菜单状态(0显示 1隐藏) */ - private String status; + /** + * 显示状态(0显示 1隐藏) + */ + private String visible; - /** 权限字符串 */ - @Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符") - private String perms; + /** + * 菜单状态(0显示 1隐藏) + */ + private String status; - /** 菜单图标 */ - private String icon; + /** + * 权限字符串 + */ + @Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符") + private String perms; - /** 创建者 */ - @TableField(fill = FieldFill.INSERT) - private String createBy; + /** + * 菜单图标 + */ + private String icon; - /** 创建时间 */ - @TableField(fill = FieldFill.INSERT) - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date createTime; + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private String createBy; - /** 更新者 */ - @TableField(fill = FieldFill.INSERT_UPDATE) - private String updateBy; + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; - /** 更新时间 */ - @TableField(fill = FieldFill.INSERT_UPDATE) - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date updateTime; + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updateBy; - /** 备注 */ - private String remark; + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; - /** 请求参数 */ - @TableField(exist = false) - private Map params = new HashMap<>(); + /** + * 备注 + */ + private String remark; - /** 子菜单 */ - @TableField(exist = false) - private List children = new ArrayList(); + /** + * 请求参数 + */ + @TableField(exist = false) + private Map params = new HashMap<>(); + + /** + * 子菜单 + */ + @TableField(exist = false) + private List children = new ArrayList(); } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java index a65855940..516352458 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java @@ -1,9 +1,10 @@ package com.ruoyi.common.core.domain.entity; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; import com.baomidou.mybatisplus.annotation.*; -import com.fasterxml.jackson.annotation.JsonFormat; -import com.ruoyi.common.annotation.Excel; -import com.ruoyi.common.annotation.Excel.ColumnType; +import com.ruoyi.common.annotation.ExcelDictFormat; +import com.ruoyi.common.convert.ExcelDictConvert; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; @@ -25,102 +26,133 @@ import java.util.Map; @NoArgsConstructor @Accessors(chain = true) @TableName("sys_role") -public class SysRole implements Serializable -{ - private static final long serialVersionUID = 1L; +@ExcelIgnoreUnannotated +public class SysRole implements Serializable { + private static final long serialVersionUID = 1L; - /** 角色ID */ - @Excel(name = "角色序号", cellType = ColumnType.NUMERIC) - @TableId(value = "role_id",type = IdType.AUTO) - private Long roleId; + /** + * 角色ID + */ + @ExcelProperty(value = "角色序号") + @TableId(value = "role_id", type = IdType.AUTO) + private Long roleId; - /** 角色名称 */ - @Excel(name = "角色名称") - @NotBlank(message = "角色名称不能为空") - @Size(min = 0, max = 30, message = "角色名称长度不能超过30个字符") - private String roleName; + /** + * 角色名称 + */ + @ExcelProperty(value = "角色名称") + @NotBlank(message = "角色名称不能为空") + @Size(min = 0, max = 30, message = "角色名称长度不能超过30个字符") + private String roleName; - /** 角色权限 */ - @Excel(name = "角色权限") - @NotBlank(message = "权限字符不能为空") - @Size(min = 0, max = 100, message = "权限字符长度不能超过100个字符") - private String roleKey; + /** + * 角色权限 + */ + @ExcelProperty(value = "角色权限") + @NotBlank(message = "权限字符不能为空") + @Size(min = 0, max = 100, message = "权限字符长度不能超过100个字符") + private String roleKey; - /** 角色排序 */ - @Excel(name = "角色排序") - @NotBlank(message = "显示顺序不能为空") - private String roleSort; + /** + * 角色排序 + */ + @ExcelProperty(value = "角色排序") + @NotBlank(message = "显示顺序不能为空") + private String roleSort; - /** 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) */ - @Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限") - private String dataScope; + /** + * 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) + */ + @ExcelProperty(value = "数据范围", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限") + private String dataScope; - /** 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示) */ - private boolean menuCheckStrictly; + /** + * 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示) + */ + private boolean menuCheckStrictly; - /** 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 ) */ - private boolean deptCheckStrictly; + /** + * 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 ) + */ + private boolean deptCheckStrictly; - /** 角色状态(0正常 1停用) */ - @Excel(name = "角色状态", readConverterExp = "0=正常,1=停用") - private String status; + /** + * 角色状态(0正常 1停用) + */ + @ExcelProperty(value = "角色状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_common_status") + private String status; - /** 删除标志(0代表存在 2代表删除) */ - @TableLogic - private String delFlag; + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; - /** 创建者 */ - @TableField(fill = FieldFill.INSERT) - private String createBy; + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private String createBy; - /** 创建时间 */ - @TableField(fill = FieldFill.INSERT) - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date createTime; + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; - /** 更新者 */ - @TableField(fill = FieldFill.INSERT_UPDATE) - private String updateBy; + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updateBy; - /** 更新时间 */ - @TableField(fill = FieldFill.INSERT_UPDATE) - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date updateTime; + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; - /** 备注 */ - private String remark; + /** + * 备注 + */ + private String remark; - /** - * 请求参数 - */ - @TableField(exist = false) - private Map params = new HashMap<>(); + /** + * 请求参数 + */ + @TableField(exist = false) + private Map params = new HashMap<>(); - /** 用户是否存在此角色标识 默认不存在 */ - @TableField(exist = false) - private boolean flag = false; + /** + * 用户是否存在此角色标识 默认不存在 + */ + @TableField(exist = false) + private boolean flag = false; - /** 菜单组 */ - @TableField(exist = false) - private Long[] menuIds; + /** + * 菜单组 + */ + @TableField(exist = false) + private Long[] menuIds; - /** 部门组(数据权限) */ - @TableField(exist = false) - private Long[] deptIds; + /** + * 部门组(数据权限) + */ + @TableField(exist = false) + private Long[] deptIds; - public SysRole(Long roleId) - { - this.roleId = roleId; - } + public SysRole(Long roleId) { + this.roleId = roleId; + } - public boolean isAdmin() - { - return isAdmin(this.roleId); - } + public boolean isAdmin() { + return isAdmin(this.roleId); + } - public static boolean isAdmin(Long roleId) - { - return roleId != null && 1L == roleId; - } + public static boolean isAdmin(Long roleId) { + return roleId != null && 1L == roleId; + } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java index 898138b0b..c5c82fd6c 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java @@ -1,13 +1,8 @@ package com.ruoyi.common.core.domain.entity; import com.baomidou.mybatisplus.annotation.*; -import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import com.ruoyi.common.annotation.Excel; -import com.ruoyi.common.annotation.Excel.ColumnType; -import com.ruoyi.common.annotation.Excel.Type; -import com.ruoyi.common.annotation.Excels; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; @@ -31,140 +26,167 @@ import java.util.Map; @NoArgsConstructor @Accessors(chain = true) @TableName("sys_user") -public class SysUser implements Serializable -{ - private static final long serialVersionUID = 1L; +public class SysUser implements Serializable { + private static final long serialVersionUID = 1L; - /** 用户ID */ - @Excel(name = "用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号") - @TableId(value = "user_id",type = IdType.AUTO) - private Long userId; + /** + * 用户ID + */ + @TableId(value = "user_id", type = IdType.AUTO) + private Long userId; - /** 部门ID */ - @Excel(name = "部门编号", type = Type.IMPORT) - private Long deptId; + /** + * 部门ID + */ + private Long deptId; - /** 用户账号 */ - @NotBlank(message = "用户账号不能为空") - @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符") - @Excel(name = "登录名称") - private String userName; + /** + * 用户账号 + */ + @NotBlank(message = "用户账号不能为空") + @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符") + private String userName; - /** 用户昵称 */ - @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符") - @Excel(name = "用户名称") - private String nickName; + /** + * 用户昵称 + */ + @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符") + private String nickName; - /** 用户邮箱 */ - @Email(message = "邮箱格式不正确") - @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符") - @Excel(name = "用户邮箱") - private String email; + /** + * 用户邮箱 + */ + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符") + private String email; - /** 手机号码 */ - @Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符") - @Excel(name = "手机号码") - private String phonenumber; + /** + * 手机号码 + */ + private String phonenumber; - /** 用户性别 */ - @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知") - private String sex; + /** + * 用户性别 + */ + private String sex; - /** 用户头像 */ - private String avatar; + /** + * 用户头像 + */ + private String avatar; - /** 密码 */ - private String password; + /** + * 密码 + */ + private String password; - @JsonIgnore - @JsonProperty - public String getPassword() { - return password; - } + @JsonIgnore + @JsonProperty + public String getPassword() { + return password; + } - /** 盐加密 */ - private String salt; + /** + * 盐加密 + */ + private String salt; - /** 帐号状态(0正常 1停用) */ - @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用") - private String status; + /** + * 帐号状态(0正常 1停用) + */ + private String status; - /** 删除标志(0代表存在 2代表删除) */ - @TableLogic - private String delFlag; + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; - /** 最后登录IP */ - @Excel(name = "最后登录IP", type = Type.EXPORT) - private String loginIp; + /** + * 最后登录IP + */ + private String loginIp; - /** 最后登录时间 */ - @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT) - private Date loginDate; + /** + * 最后登录时间 + */ + private Date loginDate; - /** 创建者 */ - @TableField(fill = FieldFill.INSERT) - private String createBy; + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private String createBy; - /** 创建时间 */ - @TableField(fill = FieldFill.INSERT) - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date createTime; + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; - /** 更新者 */ - @TableField(fill = FieldFill.INSERT_UPDATE) - private String updateBy; + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updateBy; - /** 更新时间 */ - @TableField(fill = FieldFill.INSERT_UPDATE) - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date updateTime; + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; - /** 备注 */ - private String remark; + /** + * 备注 + */ + private String remark; - /** - * 请求参数 - */ - @TableField(exist = false) - private Map params = new HashMap<>(); + /** + * 请求参数 + */ + @TableField(exist = false) + private Map params = new HashMap<>(); - /** 部门对象 */ - @Excels({ - @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT), - @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT) - }) - @TableField(exist = false) - private SysDept dept; + /** + * 部门对象 + */ + @TableField(exist = false) + private SysDept dept; - /** 角色对象 */ - @TableField(exist = false) - private List roles; + /** + * 角色对象 + */ + @TableField(exist = false) + private List roles; - /** 角色组 */ - @TableField(exist = false) - private Long[] roleIds; + /** + * 角色组 + */ + @TableField(exist = false) + private Long[] roleIds; - /** 岗位组 */ - @TableField(exist = false) - private Long[] postIds; + /** + * 岗位组 + */ + @TableField(exist = false) + private Long[] postIds; - /** 角色ID */ + /** + * 角色ID + */ @TableField(exist = false) private Long roleId; - public SysUser(Long userId) - { - this.userId = userId; - } + public SysUser(Long userId) { + this.userId = userId; + } - public boolean isAdmin() - { - return isAdmin(this.userId); - } + public boolean isAdmin() { + return isAdmin(this.userId); + } - public static boolean isAdmin(Long userId) - { - return userId != null && 1L == userId; - } + public static boolean isAdmin(Long userId) { + return userId != null && 1L == userId; + } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java index e13ec1ee7..7bc072af7 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java @@ -23,6 +23,16 @@ public class LoginUser implements UserDetails { private static final long serialVersionUID = 1L; + /** + * 用户ID + */ + private Long userId; + + /** + * 部门ID + */ + private Long deptId; + /** * 用户唯一标识 */ @@ -74,6 +84,14 @@ public class LoginUser implements UserDetails this.permissions = permissions; } + public LoginUser(Long userId, Long deptId, SysUser user, Set permissions) + { + this.userId = userId; + this.deptId = deptId; + this.user = user; + this.permissions = permissions; + } + @JsonIgnore @Override public String getPassword() @@ -81,7 +99,6 @@ public class LoginUser implements UserDetails return user.getPassword(); } - @JsonIgnore @Override public String getUsername() { @@ -134,7 +151,6 @@ public class LoginUser implements UserDetails return true; } - @JsonIgnore @Override public Collection getAuthorities() { diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java new file mode 100644 index 000000000..5baa88781 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java @@ -0,0 +1,11 @@ +package com.ruoyi.common.core.domain.model; + +/** + * 用户注册对象 + * + * @author ruoyi + */ +public class RegisterBody extends LoginBody +{ + +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/methods/InsertAll.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/methods/InsertAll.java index 66cf34c9b..2aba06e0e 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/methods/InsertAll.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/methods/InsertAll.java @@ -1,11 +1,10 @@ package com.ruoyi.common.core.mybatisplus.methods; -import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.core.enums.SqlMethod; import com.baomidou.mybatisplus.core.injector.AbstractMethod; import com.baomidou.mybatisplus.core.metadata.TableInfo; import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; +import com.ruoyi.common.utils.StringUtils; import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator; import org.apache.ibatis.executor.keygen.KeyGenerator; import org.apache.ibatis.executor.keygen.NoKeyGenerator; @@ -25,11 +24,11 @@ public class InsertAll extends AbstractMethod { final String fieldSql = prepareFieldSql(tableInfo); final String valueSql = prepareValuesSqlForMysqlBatch(tableInfo); KeyGenerator keyGenerator = new NoKeyGenerator(); - SqlMethod sqlMethod = SqlMethod.INSERT_ONE; + String sqlMethod = "insertAll"; String keyProperty = null; String keyColumn = null; // 表包含主键处理逻辑,如果不包含主键当普通字段处理 - if (StrUtil.isNotBlank(tableInfo.getKeyProperty())) { + if (StringUtils.isNotBlank(tableInfo.getKeyProperty())) { if (tableInfo.getIdType() == IdType.AUTO) { /** 自增主键 */ keyGenerator = new Jdbc3KeyGenerator(); @@ -37,7 +36,7 @@ public class InsertAll extends AbstractMethod { keyColumn = tableInfo.getKeyColumn(); } else { if (null != tableInfo.getKeySequence()) { - keyGenerator = TableInfoHelper.genKeyGenerator(getMethod(sqlMethod), tableInfo, builderAssistant); + keyGenerator = TableInfoHelper.genKeyGenerator(sqlMethod, tableInfo, builderAssistant); keyProperty = tableInfo.getKeyProperty(); keyColumn = tableInfo.getKeyColumn(); } @@ -45,12 +44,12 @@ public class InsertAll extends AbstractMethod { } final String sqlResult = String.format(sql, tableInfo.getTableName(), fieldSql, valueSql); SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass); - return this.addInsertMappedStatement(mapperClass, modelClass, "insertAll", sqlSource, keyGenerator, keyProperty, keyColumn); + return this.addInsertMappedStatement(mapperClass, modelClass, sqlMethod, sqlSource, keyGenerator, keyProperty, keyColumn); } private String prepareFieldSql(TableInfo tableInfo) { StringBuilder fieldSql = new StringBuilder(); - if (StrUtil.isNotBlank(tableInfo.getKeyColumn())) { + if (StringUtils.isNotBlank(tableInfo.getKeyColumn())) { fieldSql.append(tableInfo.getKeyColumn()).append(","); } tableInfo.getFieldList().forEach(x -> fieldSql.append(x.getColumn()).append(",")); @@ -63,7 +62,7 @@ public class InsertAll extends AbstractMethod { private String prepareValuesSqlForMysqlBatch(TableInfo tableInfo) { final StringBuilder valueSql = new StringBuilder(); valueSql.append(""); - if (StrUtil.isNotBlank(tableInfo.getKeyColumn())) { + if (StringUtils.isNotBlank(tableInfo.getKeyColumn())) { valueSql.append("#{item.").append(tableInfo.getKeyProperty()).append("},"); } tableInfo.getFieldList().forEach(x -> valueSql.append("#{item.").append(x.getProperty()).append("},")); diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java new file mode 100644 index 000000000..ad01659dc --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java @@ -0,0 +1,20 @@ +package com.ruoyi.common.enums; + +/** + * 限流类型 + * + * @author ruoyi + */ + +public enum LimitType +{ + /** + * 默认策略全局限流 + */ + DEFAULT, + + /** + * 根据请求者IP进行限流 + */ + IP +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/CustomException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/CustomException.java deleted file mode 100644 index d96c7ba7b..000000000 --- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/CustomException.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.ruoyi.common.exception; - -/** - * 自定义异常 - * - * @author ruoyi - */ -public class CustomException extends RuntimeException -{ - private static final long serialVersionUID = 1L; - - private Integer code; - - private String message; - - public CustomException(String message) - { - this.message = message; - } - - public CustomException(String message, Integer code) - { - this.message = message; - this.code = code; - } - - public CustomException(String message, Throwable e) - { - super(message, e); - this.message = message; - } - - @Override - public String getMessage() - { - return message; - } - - public Integer getCode() - { - return code; - } -} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java new file mode 100644 index 000000000..318b9aecc --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java @@ -0,0 +1,58 @@ +package com.ruoyi.common.exception; + +/** + * 全局异常 + * + * @author ruoyi + */ +public class GlobalException extends RuntimeException +{ + + private static final long serialVersionUID = 1L; + + /** + * 错误提示 + */ + private String message; + + /** + * 错误明细,内部调试错误 + * + * 和 {@link CommonResult#getDetailMessage()} 一致的设计 + */ + private String detailMessage; + + /** + * 空构造方法,避免反序列化问题 + */ + public GlobalException() + { + } + + public GlobalException(String message) + { + this.message = message; + } + + public String getDetailMessage() + { + return detailMessage; + } + + public GlobalException setDetailMessage(String detailMessage) + { + this.detailMessage = detailMessage; + return this; + } + + public String getMessage() + { + return message; + } + + public GlobalException setMessage(String message) + { + this.message = message; + return this; + } +} \ No newline at end of file diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java new file mode 100644 index 000000000..734e8fc5d --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java @@ -0,0 +1,73 @@ +package com.ruoyi.common.exception; + +/** + * 业务异常 + * + * @author ruoyi + */ +public final class ServiceException extends RuntimeException +{ + private static final long serialVersionUID = 1L; + + /** + * 错误码 + */ + private Integer code; + + /** + * 错误提示 + */ + private String message; + + /** + * 错误明细,内部调试错误 + * + * 和 {@link CommonResult#getDetailMessage()} 一致的设计 + */ + private String detailMessage; + + /** + * 空构造方法,避免反序列化问题 + */ + public ServiceException() + { + } + + public ServiceException(String message) + { + this.message = message; + } + + public ServiceException(String message, Integer code) + { + this.message = message; + this.code = code; + } + + public String getDetailMessage() + { + return detailMessage; + } + + public String getMessage() + { + return message; + } + + public Integer getCode() + { + return code; + } + + public ServiceException setMessage(String message) + { + this.message = message; + return this; + } + + public ServiceException setDetailMessage(String detailMessage) + { + this.detailMessage = detailMessage; + return this; + } +} \ No newline at end of file diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/BaseException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java similarity index 93% rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/BaseException.java rename to ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java index 026cc0abb..5f97a3bab 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/BaseException.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java @@ -1,11 +1,11 @@ -package com.ruoyi.common.exception; +package com.ruoyi.common.exception.base; -import cn.hutool.core.lang.Validator; import com.ruoyi.common.utils.MessageUtils; +import com.ruoyi.common.utils.StringUtils; /** * 基础异常 - * + * * @author ruoyi */ public class BaseException extends RuntimeException @@ -64,7 +64,7 @@ public class BaseException extends RuntimeException public String getMessage() { String message = null; - if (!Validator.isEmpty(code)) + if (!StringUtils.isEmpty(code)) { message = MessageUtils.message(code, args); } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java index 75d6dbf1a..b4c57f6d3 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java @@ -1,10 +1,10 @@ package com.ruoyi.common.exception.file; -import com.ruoyi.common.exception.BaseException; +import com.ruoyi.common.exception.base.BaseException; /** * 文件信息异常类 - * + * * @author ruoyi */ public class FileException extends BaseException diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java index aa015f88a..f25afc5eb 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java @@ -1,10 +1,10 @@ package com.ruoyi.common.exception.user; -import com.ruoyi.common.exception.BaseException; +import com.ruoyi.common.exception.base.BaseException; /** * 用户信息异常类 - * + * * @author ruoyi */ public class UserException extends BaseException diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java index c7193e20c..ffe614ceb 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java @@ -1,48 +1,48 @@ -package com.ruoyi.common.filter; - -import cn.hutool.core.util.StrUtil; -import org.springframework.http.MediaType; - -import javax.servlet.*; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; - -/** - * Repeatable 过滤器 - * - * @author ruoyi - */ -public class RepeatableFilter implements Filter -{ - @Override - public void init(FilterConfig filterConfig) throws ServletException - { - - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException - { - ServletRequest requestWrapper = null; - if (request instanceof HttpServletRequest - && StrUtil.startWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) - { - requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response); - } - if (null == requestWrapper) - { - chain.doFilter(request, response); - } - else - { - chain.doFilter(requestWrapper, response); - } - } - - @Override - public void destroy() - { - - } -} +package com.ruoyi.common.filter; + +import com.ruoyi.common.utils.StringUtils; +import org.springframework.http.MediaType; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +/** + * Repeatable 过滤器 + * + * @author ruoyi + */ +public class RepeatableFilter implements Filter +{ + @Override + public void init(FilterConfig filterConfig) throws ServletException + { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException + { + ServletRequest requestWrapper = null; + if (request instanceof HttpServletRequest + && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) + { + requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response); + } + if (null == requestWrapper) + { + chain.doFilter(request, response); + } + else + { + chain.doFilter(requestWrapper, response); + } + } + + @Override + public void destroy() + { + + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java index 86fcd2ec4..7c141671a 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java @@ -1,6 +1,6 @@ package com.ruoyi.common.filter; -import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.utils.StringUtils; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; @@ -8,12 +8,10 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * 防止XSS攻击的过滤器 - * + * * @author ruoyi */ public class XssFilter implements Filter @@ -23,17 +21,11 @@ public class XssFilter implements Filter */ public List excludes = new ArrayList<>(); - /** - * xss过滤开关 - */ - public boolean enabled = false; - @Override public void init(FilterConfig filterConfig) throws ServletException { String tempExcludes = filterConfig.getInitParameter("excludes"); - String tempEnabled = filterConfig.getInitParameter("enabled"); - if (StrUtil.isNotEmpty(tempExcludes)) + if (StringUtils.isNotEmpty(tempExcludes)) { String[] url = tempExcludes.split(","); for (int i = 0; url != null && i < url.length; i++) @@ -41,10 +33,6 @@ public class XssFilter implements Filter excludes.add(url[i]); } } - if (StrUtil.isNotEmpty(tempEnabled)) - { - enabled = Boolean.valueOf(tempEnabled); - } } @Override @@ -64,25 +52,14 @@ public class XssFilter implements Filter private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) { - if (!enabled) + String url = request.getServletPath(); + String method = request.getMethod(); + // GET DELETE 不过滤 + if (method == null || method.matches("GET") || method.matches("DELETE")) { return true; } - if (excludes == null || excludes.isEmpty()) - { - return false; - } - String url = request.getServletPath(); - for (String pattern : excludes) - { - Pattern p = Pattern.compile("^" + pattern); - Matcher m = p.matcher(url); - if (m.find()) - { - return true; - } - } - return false; + return StringUtils.matches(url, excludes); } @Override @@ -90,4 +67,4 @@ public class XssFilter implements Filter { } -} \ No newline at end of file +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java index 4d36a92ec..700a88dcc 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java @@ -1,9 +1,8 @@ package com.ruoyi.common.filter; import cn.hutool.core.io.IoUtil; -import cn.hutool.core.lang.Validator; -import cn.hutool.core.util.StrUtil; import cn.hutool.http.HtmlUtil; +import com.ruoyi.common.utils.StringUtils; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; @@ -59,7 +58,7 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper // 为空,直接返回 String json = IoUtil.read(super.getInputStream(), StandardCharsets.UTF_8); - if (Validator.isEmpty(json)) + if (StringUtils.isEmpty(json)) { return super.getInputStream(); } @@ -103,6 +102,6 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper public boolean isJsonRequest() { String header = super.getHeader(HttpHeaders.CONTENT_TYPE); - return StrUtil.startWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE); + return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE); } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java index 5d1fef18f..64ac8efdc 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java @@ -1,187 +1,185 @@ -package com.ruoyi.common.utils; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.Validator; -import cn.hutool.core.util.StrUtil; -import com.ruoyi.common.constant.Constants; -import com.ruoyi.common.core.domain.entity.SysDictData; -import com.ruoyi.common.core.redis.RedisCache; -import com.ruoyi.common.utils.spring.SpringUtils; - -import java.util.Collection; -import java.util.List; - -/** - * 字典工具类 - * - * @author ruoyi - */ -public class DictUtils -{ - /** - * 分隔符 - */ - public static final String SEPARATOR = ","; - - /** - * 设置字典缓存 - * - * @param key 参数键 - * @param dictDatas 字典数据列表 - */ - public static void setDictCache(String key, List dictDatas) - { - SpringUtils.getBean(RedisCache.class).setCacheObject(getCacheKey(key), dictDatas); - } - - /** - * 获取字典缓存 - * - * @param key 参数键 - * @return dictDatas 字典数据列表 - */ - public static List getDictCache(String key) - { - Object cacheObj = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key)); - if (Validator.isNotNull(cacheObj)) - { - List dictDatas = (List)cacheObj; - return dictDatas; - } - return null; - } - - /** - * 根据字典类型和字典值获取字典标签 - * - * @param dictType 字典类型 - * @param dictValue 字典值 - * @return 字典标签 - */ - public static String getDictLabel(String dictType, String dictValue) - { - return getDictLabel(dictType, dictValue, SEPARATOR); - } - - /** - * 根据字典类型和字典标签获取字典值 - * - * @param dictType 字典类型 - * @param dictLabel 字典标签 - * @return 字典值 - */ - public static String getDictValue(String dictType, String dictLabel) - { - return getDictValue(dictType, dictLabel, SEPARATOR); - } - - /** - * 根据字典类型和字典值获取字典标签 - * - * @param dictType 字典类型 - * @param dictValue 字典值 - * @param separator 分隔符 - * @return 字典标签 - */ - public static String getDictLabel(String dictType, String dictValue, String separator) - { - StringBuilder propertyString = new StringBuilder(); - List datas = getDictCache(dictType); - - if (StrUtil.containsAny(dictValue, separator) && CollUtil.isNotEmpty(datas)) - { - for (SysDictData dict : datas) - { - for (String value : dictValue.split(separator)) - { - if (value.equals(dict.getDictValue())) - { - propertyString.append(dict.getDictLabel() + separator); - break; - } - } - } - } - else - { - for (SysDictData dict : datas) - { - if (dictValue.equals(dict.getDictValue())) - { - return dict.getDictLabel(); - } - } - } - return StrUtil.strip(propertyString.toString(), null, separator); - } - - /** - * 根据字典类型和字典标签获取字典值 - * - * @param dictType 字典类型 - * @param dictLabel 字典标签 - * @param separator 分隔符 - * @return 字典值 - */ - public static String getDictValue(String dictType, String dictLabel, String separator) - { - StringBuilder propertyString = new StringBuilder(); - List datas = getDictCache(dictType); - - if (StrUtil.containsAny(dictLabel, separator) && CollUtil.isNotEmpty(datas)) - { - for (SysDictData dict : datas) - { - for (String label : dictLabel.split(separator)) - { - if (label.equals(dict.getDictLabel())) - { - propertyString.append(dict.getDictValue() + separator); - break; - } - } - } - } - else - { - for (SysDictData dict : datas) - { - if (dictLabel.equals(dict.getDictLabel())) - { - return dict.getDictValue(); - } - } - } - return StrUtil.strip(propertyString.toString(), null, separator); - } - - /** - * 删除指定字典缓存 - * - * @param key 字典键 - */ - public static void removeDictCache(String key) - { - SpringUtils.getBean(RedisCache.class).deleteObject(getCacheKey(key)); - } - - /** - * 清空字典缓存 - */ - public static void clearDictCache() - { - Collection keys = SpringUtils.getBean(RedisCache.class).keys(Constants.SYS_DICT_KEY + "*"); - SpringUtils.getBean(RedisCache.class).deleteObject(keys); - } - - /** - * 设置cache key - * - * @param configKey 参数键 - * @return 缓存键key - */ - public static String getCacheKey(String configKey) - { - return Constants.SYS_DICT_KEY + configKey; - } -} +package com.ruoyi.common.utils; + +import cn.hutool.core.collection.CollUtil; +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.core.domain.entity.SysDictData; +import com.ruoyi.common.core.redis.RedisCache; +import com.ruoyi.common.utils.spring.SpringUtils; + +import java.util.Collection; +import java.util.List; + +/** + * 字典工具类 + * + * @author ruoyi + */ +public class DictUtils +{ + /** + * 分隔符 + */ + public static final String SEPARATOR = ","; + + /** + * 设置字典缓存 + * + * @param key 参数键 + * @param dictDatas 字典数据列表 + */ + public static void setDictCache(String key, List dictDatas) + { + SpringUtils.getBean(RedisCache.class).setCacheObject(getCacheKey(key), dictDatas); + } + + /** + * 获取字典缓存 + * + * @param key 参数键 + * @return dictDatas 字典数据列表 + */ + public static List getDictCache(String key) + { + Object cacheObj = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key)); + if (StringUtils.isNotNull(cacheObj)) + { + List dictDatas = (List)cacheObj; + return dictDatas; + } + return null; + } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @return 字典标签 + */ + public static String getDictLabel(String dictType, String dictValue) + { + return getDictLabel(dictType, dictValue, SEPARATOR); + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @return 字典值 + */ + public static String getDictValue(String dictType, String dictLabel) + { + return getDictValue(dictType, dictLabel, SEPARATOR); + } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @param separator 分隔符 + * @return 字典标签 + */ + public static String getDictLabel(String dictType, String dictValue, String separator) + { + StringBuilder propertyString = new StringBuilder(); + List datas = getDictCache(dictType); + + if (StringUtils.containsAny(dictValue, separator) && CollUtil.isNotEmpty(datas)) + { + for (SysDictData dict : datas) + { + for (String value : dictValue.split(separator)) + { + if (value.equals(dict.getDictValue())) + { + propertyString.append(dict.getDictLabel() + separator); + break; + } + } + } + } + else + { + for (SysDictData dict : datas) + { + if (dictValue.equals(dict.getDictValue())) + { + return dict.getDictLabel(); + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @param separator 分隔符 + * @return 字典值 + */ + public static String getDictValue(String dictType, String dictLabel, String separator) + { + StringBuilder propertyString = new StringBuilder(); + List datas = getDictCache(dictType); + + if (StringUtils.containsAny(dictLabel, separator) && CollUtil.isNotEmpty(datas)) + { + for (SysDictData dict : datas) + { + for (String label : dictLabel.split(separator)) + { + if (label.equals(dict.getDictLabel())) + { + propertyString.append(dict.getDictValue() + separator); + break; + } + } + } + } + else + { + for (SysDictData dict : datas) + { + if (dictLabel.equals(dict.getDictLabel())) + { + return dict.getDictValue(); + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 删除指定字典缓存 + * + * @param key 字典键 + */ + public static void removeDictCache(String key) + { + SpringUtils.getBean(RedisCache.class).deleteObject(getCacheKey(key)); + } + + /** + * 清空字典缓存 + */ + public static void clearDictCache() + { + Collection keys = SpringUtils.getBean(RedisCache.class).keys(Constants.SYS_DICT_KEY + "*"); + SpringUtils.getBean(RedisCache.class).deleteObject(keys); + } + + /** + * 设置cache key + * + * @param configKey 参数键 + * @return 缓存键key + */ + public static String getCacheKey(String configKey) + { + return Constants.SYS_DICT_KEY + configKey; + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/JsonUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/JsonUtils.java index ae6cc11be..676de013a 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/JsonUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/JsonUtils.java @@ -1,8 +1,6 @@ package com.ruoyi.common.utils; -import cn.hutool.core.lang.Validator; import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.StrUtil; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -33,7 +31,7 @@ public class JsonUtils { } public static String toJsonString(Object object) { - if (Validator.isEmpty(object)) { + if (StringUtils.isNull(object)) { return null; } try { @@ -44,7 +42,7 @@ public class JsonUtils { } public static T parseObject(String text, Class clazz) { - if (StrUtil.isEmpty(text)) { + if (StringUtils.isEmpty(text)) { return null; } try { @@ -66,7 +64,7 @@ public class JsonUtils { } public static T parseObject(String text, TypeReference typeReference) { - if (StrUtil.isBlank(text)) { + if (StringUtils.isBlank(text)) { return null; } try { @@ -77,7 +75,7 @@ public class JsonUtils { } public static Map parseMap(String text) { - if (StrUtil.isBlank(text)) { + if (StringUtils.isBlank(text)) { return null; } try { @@ -88,7 +86,7 @@ public class JsonUtils { } public static List parseArray(String text, Class clazz) { - if (StrUtil.isEmpty(text)) { + if (StringUtils.isEmpty(text)) { return new ArrayList<>(); } try { diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java index bb3d3e2de..27125ab8f 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java @@ -1,6 +1,5 @@ package com.ruoyi.common.utils; -import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpStatus; import com.baomidou.mybatisplus.core.metadata.OrderItem; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -59,7 +58,7 @@ public class PageUtils { String orderByColumn = ServletUtils.getParameter(ORDER_BY_COLUMN); String isAsc = ServletUtils.getParameter(IS_ASC); PagePlus page = new PagePlus<>(pageNum, pageSize); - if (StrUtil.isNotBlank(orderByColumn)) { + if (StringUtils.isNotBlank(orderByColumn)) { String orderBy = SqlUtil.escapeOrderBySql(orderByColumn); if ("asc".equals(isAsc)) { page.addOrder(OrderItem.asc(orderBy)); @@ -91,9 +90,9 @@ public class PageUtils { isAsc = "desc"; } Page page = new Page<>(pageNum, pageSize); - if (StrUtil.isNotBlank(orderByColumn)) { + if (StringUtils.isNotBlank(orderByColumn)) { String orderBy = SqlUtil.escapeOrderBySql(orderByColumn); - orderBy = StrUtil.toUnderlineCase(orderBy); + orderBy = StringUtils.toUnderScoreCase(orderBy); if ("asc".equals(isAsc)) { page.addOrder(OrderItem.asc(orderBy)); } else if ("desc".equals(isAsc)) { diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java index bdcc9eb1e..969eaf579 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java @@ -5,15 +5,45 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import com.ruoyi.common.core.domain.model.LoginUser; -import com.ruoyi.common.exception.CustomException; +import com.ruoyi.common.exception.ServiceException; /** * 安全服务工具类 - * + * * @author ruoyi */ public class SecurityUtils { + /** + * 用户ID + **/ + public static Long getUserId() + { + try + { + return getLoginUser().getUserId(); + } + catch (Exception e) + { + throw new ServiceException("获取用户ID异常", HttpStatus.HTTP_UNAUTHORIZED); + } + } + + /** + * 获取部门ID + **/ + public static Long getDeptId() + { + try + { + return getLoginUser().getDeptId(); + } + catch (Exception e) + { + throw new ServiceException("获取部门ID异常", HttpStatus.HTTP_UNAUTHORIZED); + } + } + /** * 获取用户账户 **/ @@ -25,7 +55,7 @@ public class SecurityUtils } catch (Exception e) { - throw new CustomException("获取用户账户异常", HttpStatus.HTTP_UNAUTHORIZED); + throw new ServiceException("获取用户账户异常", HttpStatus.HTTP_UNAUTHORIZED); } } @@ -40,7 +70,7 @@ public class SecurityUtils } catch (Exception e) { - throw new CustomException("获取用户信息异常", HttpStatus.HTTP_UNAUTHORIZED); + throw new ServiceException("获取用户信息异常", HttpStatus.HTTP_UNAUTHORIZED); } } @@ -79,7 +109,7 @@ public class SecurityUtils /** * 是否为管理员 - * + * * @param userId 用户ID * @return 结果 */ diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java index 159429163..beaa26c6e 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java @@ -1,7 +1,6 @@ package com.ruoyi.common.utils; import cn.hutool.core.convert.Convert; -import cn.hutool.core.util.StrUtil; import cn.hutool.extra.servlet.ServletUtil; import cn.hutool.http.HttpStatus; import org.springframework.http.MediaType; @@ -112,12 +111,12 @@ public class ServletUtils extends ServletUtil { } String uri = request.getRequestURI(); - if (StrUtil.equalsAnyIgnoreCase(uri, ".json", ".xml")) { + if (StringUtils.equalsAnyIgnoreCase(uri, ".json", ".xml")) { return true; } String ajax = request.getParameter("__ajax"); - if (StrUtil.equalsAnyIgnoreCase(ajax, "json", "xml")) { + if (StringUtils.equalsAnyIgnoreCase(ajax, "json", "xml")) { return true; } return false; diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java new file mode 100644 index 000000000..c6371cc32 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java @@ -0,0 +1,354 @@ +package com.ruoyi.common.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Validator; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.ReUtil; +import cn.hutool.core.util.StrUtil; + +import java.util.*; + +/** + * 字符串工具类 + * + * @author ruoyi + */ +public class StringUtils extends org.apache.commons.lang3.StringUtils { + + /** + * 获取参数不为空值 + * + * @param value defaultValue 要判断的value + * @return value 返回值 + */ + public static T nvl(T value, T defaultValue) { + return ObjectUtil.defaultIfNull(value, defaultValue); + } + + /** + * 获取参数不为空值 + * + * @param str defaultValue 要判断的value + * @return value 返回值 + */ + public static String blankToDefault(String str, String defaultValue) { + return StrUtil.blankToDefault(str, defaultValue); + } + + /** + * * 判断一个Collection是否为空, 包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Collection coll) { + return CollUtil.isEmpty(coll); + } + + /** + * * 判断一个Collection是否非空,包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Collection coll) { + return !isEmpty(coll); + } + + /** + * * 判断一个对象数组是否为空 + * + * @param objects 要判断的对象数组 + * * @return true:为空 false:非空 + */ + public static boolean isEmpty(Object[] objects) { + return ArrayUtil.isEmpty(objects); + } + + /** + * * 判断一个对象数组是否非空 + * + * @param objects 要判断的对象数组 + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Object[] objects) { + return !isEmpty(objects); + } + + /** + * * 判断一个对象是否为空 + * + * @param object 要判断的对象数组 + * * @return true:为空 false:非空 + */ + public static boolean isEmpty(Object object) { + return ObjectUtil.isEmpty(object); + } + + /** + * * 判断一个对象是否非空 + * + * @param object 要判断的对象数组 + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Object object) { + return !isEmpty(object); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Map map) { + return MapUtil.isEmpty(map); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Map map) { + return !isEmpty(map); + } + + /** + * * 判断一个字符串是否为空串 + * + * @param str String + * @return true:为空 false:非空 + */ + public static boolean isEmpty(String str) { + return StrUtil.isEmpty(str); + } + + /** + * * 判断一个字符串是否为非空串 + * + * @param str String + * @return true:非空串 false:空串 + */ + public static boolean isNotEmpty(String str) { + return !isEmpty(str); + } + + /** + * * 判断一个对象是否为空 + * + * @param object Object + * @return true:为空 false:非空 + */ + public static boolean isNull(Object object) { + return ObjectUtil.isNull(object); + } + + /** + * * 判断一个对象是否非空 + * + * @param object Object + * @return true:非空 false:空 + */ + public static boolean isNotNull(Object object) { + return !isNull(object); + } + + /** + * * 判断一个对象是否是数组类型(Java基本型别的数组) + * + * @param object 对象 + * @return true:是数组 false:不是数组 + */ + public static boolean isArray(Object object) { + return ArrayUtil.isArray(object); + } + + /** + * 去空格 + */ + public static String trim(String str) { + return StrUtil.trim(str); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @return 结果 + */ + public static String substring(final String str, int start) { + return substring(str, start, str.length()); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @param end 结束 + * @return 结果 + */ + public static String substring(final String str, int start, int end) { + return StrUtil.sub(str, start, end); + } + + /** + * 格式化文本, {} 表示占位符
+ * 此方法只是简单将占位符 {} 按照顺序替换为参数
+ * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
+ * 例:
+ * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
+ * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
+ * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
+ * + * @param template 文本模板,被替换的部分用 {} 表示 + * @param params 参数值 + * @return 格式化后的文本 + */ + public static String format(String template, Object... params) { + return StrUtil.format(template, params); + } + + /** + * 是否为http(s)://开头 + * + * @param link 链接 + * @return 结果 + */ + public static boolean ishttp(String link) { + return Validator.isUrl(link); + } + + /** + * 字符串转set + * + * @param str 字符串 + * @param sep 分隔符 + * @return set集合 + */ + public static Set str2Set(String str, String sep) { + return new HashSet<>(str2List(str, sep, true, false)); + } + + /** + * 字符串转list + * + * @param str 字符串 + * @param sep 分隔符 + * @param filterBlank 过滤纯空白 + * @param trim 去掉首尾空白 + * @return list集合 + */ + public static List str2List(String str, String sep, boolean filterBlank, boolean trim) { + List list = new ArrayList<>(); + if (isEmpty(str)) { + return list; + } + + // 过滤空白字符串 + if (filterBlank && isBlank(str)) { + return list; + } + String[] split = str.split(sep); + for (String string : split) { + if (filterBlank && isBlank(string)) { + continue; + } + if (trim) { + string = trim(string); + } + list.add(string); + } + + return list; + } + + /** + * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写 + * + * @param cs 指定字符串 + * @param searchCharSequences 需要检查的字符串数组 + * @return 是否包含任意一个字符串 + */ + public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) { + return StrUtil.containsAnyIgnoreCase(cs, searchCharSequences); + } + + /** + * 驼峰转下划线命名 + */ + public static String toUnderScoreCase(String str) { + return StrUtil.toUnderlineCase(str); + } + + /** + * 是否包含字符串 + * + * @param str 验证字符串 + * @param strs 字符串组 + * @return 包含返回true + */ + public static boolean inStringIgnoreCase(String str, String... strs) { + return StrUtil.equalsAnyIgnoreCase(str, strs); + } + + /** + * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld + * + * @param name 转换前的下划线大写方式命名的字符串 + * @return 转换后的驼峰式命名的字符串 + */ + public static String convertToCamelCase(String name) { + return StrUtil.upperFirst(StrUtil.toCamelCase(name)); + } + + /** + * 驼峰式命名法 例如:user_name->userName + */ + public static String toCamelCase(String s) { + return StrUtil.toCamelCase(s); + } + + /** + * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串 + * + * @param str 指定字符串 + * @param strs 需要检查的字符串数组 + * @return 是否匹配 + */ + public static boolean matches(String str, List strs) { + if (isEmpty(str) || isEmpty(strs)) { + return false; + } + for (String pattern : strs) { + if (isMatch(pattern, str)) { + return true; + } + } + return false; + } + + /** + * 判断url是否与规则配置: + * ? 表示单个字符; + * * 表示一层路径内的任意字符串,不可跨层级; + * ** 表示任意层路径; + * + * @param pattern 匹配规则 + * @param url 需要匹配的url + * @return + */ + public static boolean isMatch(String pattern, String url) { + return ReUtil.isMatch(pattern, url); + } + + @SuppressWarnings("unchecked") + public static T cast(Object obj) { + return (T) obj; + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java deleted file mode 100644 index 25f530666..000000000 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.ruoyi.common.utils.file; - -import java.io.File; -import org.apache.commons.lang3.StringUtils; - -/** - * 文件类型工具类 - * - * @author ruoyi - */ -public class FileTypeUtils -{ - /** - * 获取文件类型 - *

- * 例如: ruoyi.txt, 返回: txt - * - * @param file 文件名 - * @return 后缀(不含".") - */ - public static String getFileType(File file) - { - if (null == file) - { - return StringUtils.EMPTY; - } - return getFileType(file.getName()); - } - - /** - * 获取文件类型 - *

- * 例如: ruoyi.txt, 返回: txt - * - * @param fileName 文件名 - * @return 后缀(不含".") - */ - public static String getFileType(String fileName) - { - int separatorIndex = fileName.lastIndexOf("."); - if (separatorIndex < 0) - { - return ""; - } - return fileName.substring(separatorIndex + 1).toLowerCase(); - } - - /** - * 获取文件类型 - * - * @param photoByte 文件字节码 - * @return 后缀(不含".") - */ - public static String getFileExtendName(byte[] photoByte) - { - String strFileExtendName = "JPG"; - if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56) - && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97)) - { - strFileExtendName = "GIF"; - } - else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70)) - { - strFileExtendName = "JPG"; - } - else if ((photoByte[0] == 66) && (photoByte[1] == 77)) - { - strFileExtendName = "BMP"; - } - else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71)) - { - strFileExtendName = "PNG"; - } - return strFileExtendName; - } -} \ No newline at end of file diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java deleted file mode 100644 index 22d53c7fa..000000000 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.ruoyi.common.utils.file; - -import cn.hutool.core.io.FileUtil; -import cn.hutool.core.lang.Validator; -import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.StrUtil; -import com.ruoyi.common.config.RuoYiConfig; -import com.ruoyi.common.constant.Constants; -import com.ruoyi.common.exception.file.FileNameLengthLimitExceededException; -import com.ruoyi.common.exception.file.FileSizeLimitExceededException; -import com.ruoyi.common.exception.file.InvalidExtensionException; -import com.ruoyi.common.utils.DateUtils; -import org.apache.commons.io.FilenameUtils; -import org.springframework.web.multipart.MultipartFile; - -import java.io.File; -import java.io.IOException; - -/** - * 文件上传工具类 - * - * @author ruoyi - */ -public class FileUploadUtils -{ - /** - * 默认大小 50M - */ - public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024; - - /** - * 默认的文件名最大长度 100 - */ - public static final int DEFAULT_FILE_NAME_LENGTH = 100; - - /** - * 默认上传的地址 - */ - private static String defaultBaseDir = RuoYiConfig.getProfile(); - - public static void setDefaultBaseDir(String defaultBaseDir) - { - FileUploadUtils.defaultBaseDir = defaultBaseDir; - } - - public static String getDefaultBaseDir() - { - return defaultBaseDir; - } - - /** - * 以默认配置进行文件上传 - * - * @param file 上传的文件 - * @return 文件名称 - * @throws Exception - */ - public static final String upload(MultipartFile file) throws IOException - { - try - { - return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); - } - catch (Exception e) - { - throw new IOException(e.getMessage(), e); - } - } - - /** - * 根据文件路径上传 - * - * @param baseDir 相对应用的基目录 - * @param file 上传的文件 - * @return 文件名称 - * @throws IOException - */ - public static final String upload(String baseDir, MultipartFile file) throws IOException - { - try - { - return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); - } - catch (Exception e) - { - throw new IOException(e.getMessage(), e); - } - } - - /** - * 文件上传 - * - * @param baseDir 相对应用的基目录 - * @param file 上传的文件 - * @param allowedExtension 上传文件类型 - * @return 返回上传成功的文件名 - * @throws FileSizeLimitExceededException 如果超出最大大小 - * @throws FileNameLengthLimitExceededException 文件名太长 - * @throws IOException 比如读写文件出错时 - * @throws InvalidExtensionException 文件校验异常 - */ - public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension) - throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, - InvalidExtensionException - { - int fileNamelength = file.getOriginalFilename().length(); - if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) - { - throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); - } - - assertAllowed(file, allowedExtension); - - String fileName = extractFilename(file); - - File desc = getAbsoluteFile(baseDir, fileName); - desc = FileUtil.touch(desc); - FileUtil.writeFromStream(file.getInputStream(), desc); - String pathFileName = getPathFileName(baseDir, fileName); - return pathFileName; - } - - /** - * 编码文件名 - */ - public static final String extractFilename(MultipartFile file) - { - String fileName = file.getOriginalFilename(); - String extension = getExtension(file); - fileName = DateUtils.datePath() + "/" + IdUtil.fastUUID() + "." + extension; - return fileName; - } - - private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException - { - File desc = new File(uploadDir + File.separator + fileName); - - if (!desc.exists()) - { - if (!desc.getParentFile().exists()) - { - desc.getParentFile().mkdirs(); - } - } - return desc; - } - - private static final String getPathFileName(String uploadDir, String fileName) throws IOException - { - int dirLastIndex = RuoYiConfig.getProfile().length() + 1; - String currentDir = StrUtil.subSuf(uploadDir, dirLastIndex); - String pathFileName = Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName; - return pathFileName; - } - - /** - * 文件大小校验 - * - * @param file 上传的文件 - * @return - * @throws FileSizeLimitExceededException 如果超出最大大小 - * @throws InvalidExtensionException - */ - public static final void assertAllowed(MultipartFile file, String[] allowedExtension) - throws FileSizeLimitExceededException, InvalidExtensionException - { - long size = file.getSize(); - if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE) - { - throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024); - } - - String fileName = file.getOriginalFilename(); - String extension = getExtension(file); - if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) - { - if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) - { - throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension, - fileName); - } - else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) - { - throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension, - fileName); - } - else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) - { - throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension, - fileName); - } - else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) - { - throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension, - fileName); - } - else - { - throw new InvalidExtensionException(allowedExtension, extension, fileName); - } - } - - } - - /** - * 判断MIME类型是否是允许的MIME类型 - * - * @param extension - * @param allowedExtension - * @return - */ - public static final boolean isAllowedExtension(String extension, String[] allowedExtension) - { - for (String str : allowedExtension) - { - if (str.equalsIgnoreCase(extension)) - { - return true; - } - } - return false; - } - - /** - * 获取文件名的后缀 - * - * @param file 表单文件 - * @return 后缀名 - */ - public static final String getExtension(MultipartFile file) - { - String extension = FilenameUtils.getExtension(file.getOriginalFilename()); - if (Validator.isEmpty(extension)) - { - extension = MimeTypeUtils.getExtension(file.getContentType()); - } - return extension; - } -} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java index bc953de06..dc3aea2c0 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java @@ -1,12 +1,9 @@ package com.ruoyi.common.utils.file; import cn.hutool.core.io.FileUtil; -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.StrUtil; -import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.*; +import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -17,77 +14,6 @@ import java.nio.charset.StandardCharsets; */ public class FileUtils extends FileUtil { - public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+"; - - /** - * 文件名称验证 - * - * @param filename 文件名称 - * @return true 正常 false 非法 - */ - public static boolean isValidFilename(String filename) - { - return filename.matches(FILENAME_PATTERN); - } - - /** - * 检查文件是否可下载 - * - * @param resource 需要下载的文件 - * @return true 正常 false 非法 - */ - public static boolean checkAllowDownload(String resource) - { - // 禁止目录上跳级别 - if (StrUtil.contains(resource, "..")) - { - return false; - } - - // 检查允许下载的文件规则 - if (ArrayUtil.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource))) - { - return true; - } - - // 不在允许下载的文件规则 - return false; - } - - /** - * 下载文件名重新编码 - * - * @param request 请求对象 - * @param fileName 文件名 - * @return 编码后的文件名 - */ - public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException - { - final String agent = request.getHeader("USER-AGENT"); - String filename = fileName; - if (agent.contains("MSIE")) - { - // IE浏览器 - filename = URLEncoder.encode(filename, StandardCharsets.UTF_8.toString()); - filename = filename.replace("+", " "); - } - else if (agent.contains("Firefox")) - { - // 火狐浏览器 - filename = new String(fileName.getBytes(), "ISO8859-1"); - } - else if (agent.contains("Chrome")) - { - // google浏览器 - filename = URLEncoder.encode(filename, StandardCharsets.UTF_8.toString()); - } - else - { - // 其它浏览器 - filename = URLEncoder.encode(filename, StandardCharsets.UTF_8.toString()); - } - return filename; - } /** * 下载文件名重新编码 diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java deleted file mode 100644 index 94dcf456f..000000000 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.ruoyi.common.utils.file; - -import cn.hutool.core.util.StrUtil; -import com.ruoyi.common.config.RuoYiConfig; -import com.ruoyi.common.constant.Constants; -import org.apache.poi.util.IOUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FileInputStream; -import java.io.InputStream; -import java.net.URL; -import java.net.URLConnection; -import java.util.Arrays; - -/** - * 图片处理工具类 - * - * @author ruoyi - */ -public class ImageUtils -{ - private static final Logger log = LoggerFactory.getLogger(ImageUtils.class); - - public static byte[] getImage(String imagePath) - { - InputStream is = getFile(imagePath); - try - { - return IOUtils.toByteArray(is); - } - catch (Exception e) - { - log.error("图片加载异常 {}", e); - return null; - } - finally - { - IOUtils.closeQuietly(is); - } - } - - public static InputStream getFile(String imagePath) - { - try - { - byte[] result = readFile(imagePath); - result = Arrays.copyOf(result, result.length); - return new ByteArrayInputStream(result); - } - catch (Exception e) - { - log.error("获取图片异常 {}", e); - } - return null; - } - - /** - * 读取文件为字节数据 - * - * @param key 地址 - * @return 字节数据 - */ - public static byte[] readFile(String url) - { - InputStream in = null; - ByteArrayOutputStream baos = null; - try - { - if (url.startsWith("http")) - { - // 网络地址 - URL urlObj = new URL(url); - URLConnection urlConnection = urlObj.openConnection(); - urlConnection.setConnectTimeout(30 * 1000); - urlConnection.setReadTimeout(60 * 1000); - urlConnection.setDoInput(true); - in = urlConnection.getInputStream(); - } - else - { - // 本机地址 - String localPath = RuoYiConfig.getProfile(); - String downloadPath = localPath + StrUtil.subAfter(url, Constants.RESOURCE_PREFIX,false); - in = new FileInputStream(downloadPath); - } - return IOUtils.toByteArray(in); - } - catch (Exception e) - { - log.error("获取文件路径异常 {}", e); - return null; - } - finally - { - IOUtils.closeQuietly(in); - IOUtils.closeQuietly(baos); - } - } -} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java deleted file mode 100644 index f968f1a12..000000000 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.ruoyi.common.utils.file; - -/** - * 媒体类型工具类 - * - * @author ruoyi - */ -public class MimeTypeUtils -{ - public static final String IMAGE_PNG = "image/png"; - - public static final String IMAGE_JPG = "image/jpg"; - - public static final String IMAGE_JPEG = "image/jpeg"; - - public static final String IMAGE_BMP = "image/bmp"; - - public static final String IMAGE_GIF = "image/gif"; - - public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" }; - - public static final String[] FLASH_EXTENSION = { "swf", "flv" }; - - public static final String[] MEDIA_EXTENSION = { "swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg", - "asf", "rm", "rmvb" }; - - public static final String[] VIDEO_EXTENSION = { "mp4", "avi", "rmvb" }; - - public static final String[] DEFAULT_ALLOWED_EXTENSION = { - // 图片 - "bmp", "gif", "jpg", "jpeg", "png", - // word excel powerpoint - "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt", - // 压缩文件 - "rar", "zip", "gz", "bz2", - // 视频格式 - "mp4", "avi", "rmvb", - // pdf - "pdf" }; - - public static String getExtension(String prefix) - { - switch (prefix) - { - case IMAGE_PNG: - return "png"; - case IMAGE_JPG: - return "jpg"; - case IMAGE_JPEG: - return "jpeg"; - case IMAGE_BMP: - return "bmp"; - case IMAGE_GIF: - return "gif"; - default: - return ""; - } - } -} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java index d6c262a25..03c608af8 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java @@ -1,12 +1,12 @@ package com.ruoyi.common.utils.ip; import cn.hutool.core.net.NetUtil; -import cn.hutool.core.util.StrUtil; import cn.hutool.http.HtmlUtil; import cn.hutool.http.HttpUtil; import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.utils.JsonUtils; +import com.ruoyi.common.utils.StringUtils; import lombok.extern.slf4j.Slf4j; import java.util.Map; @@ -38,7 +38,7 @@ public class AddressUtils { .body("ip=" + ip + "&json=true", Constants.GBK) .execute() .body(); - if (StrUtil.isEmpty(rspStr)) { + if (StringUtils.isEmpty(rspStr)) { log.error("获取地理位置异常 {}", ip); return UNKNOWN; } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java index 96843d18c..f242d8cb1 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java @@ -1,1072 +1,150 @@ package com.ruoyi.common.utils.poi; -import cn.hutool.core.convert.Convert; -import cn.hutool.core.lang.Validator; -import cn.hutool.core.util.StrUtil; -import com.ruoyi.common.annotation.Excel; -import com.ruoyi.common.annotation.Excel.ColumnType; -import com.ruoyi.common.annotation.Excel.Type; -import com.ruoyi.common.annotation.Excels; -import com.ruoyi.common.config.RuoYiConfig; -import com.ruoyi.common.core.domain.AjaxResult; -import com.ruoyi.common.exception.CustomException; -import com.ruoyi.common.utils.DateUtils; +import cn.hutool.core.util.IdUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; import com.ruoyi.common.utils.DictUtils; -import com.ruoyi.common.utils.file.FileTypeUtils; -import com.ruoyi.common.utils.file.ImageUtils; -import com.ruoyi.common.utils.reflect.ReflectUtils; -import org.apache.poi.ss.usermodel.*; -import org.apache.poi.ss.util.CellRangeAddressList; -import org.apache.poi.xssf.streaming.SXSSFWorkbook; -import org.apache.poi.xssf.usermodel.XSSFClientAnchor; -import org.apache.poi.xssf.usermodel.XSSFDataValidation; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.file.FileUtils; -import java.io.*; -import java.lang.reflect.Field; -import java.math.BigDecimal; -import java.text.DecimalFormat; -import java.util.*; -import java.util.stream.Collectors; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.List; /** * Excel相关处理 * * @author ruoyi */ -public class ExcelUtil -{ - private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); +public class ExcelUtil { - /** - * Excel sheet最大行数,默认65536 - */ - public static final int sheetSize = 65536; + /** + * 对excel表单默认第一个索引名转换成list(EasyExcel) + * + * @param is 输入流 + * @return 转换后集合 + */ + public static List importExcel(InputStream is, Class clazz) { + return EasyExcel.read(is).autoCloseStream(false).sheet().doReadSync(); + } - /** - * 工作表名称 - */ - private String sheetName; + /** + * 对list数据源将其里面的数据导入到excel表单(EasyExcel) + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @return 结果 + */ + public static void exportExcel(List list, String sheetName, Class clazz, HttpServletResponse response) { + try { + String filename = encodingFilename(sheetName); + response.reset(); + response.addHeader("Access-Control-Allow-Origin", "*"); + response.addHeader("Access-Control-Expose-Headers", "Content-Disposition"); + FileUtils.setAttachmentResponseHeader(response, URLEncoder.encode(filename, StandardCharsets.UTF_8.toString())); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8"); + ServletOutputStream os = response.getOutputStream(); + EasyExcel.write(os, clazz) + .autoCloseStream(false) + // 自动适配 + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + .sheet(sheetName).doWrite(list); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } - /** - * 导出类型(EXPORT:导出数据;IMPORT:导入模板) - */ - private Type type; + /** + * 解析导出值 0=男,1=女,2=未知 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String convertByExp(String propertyValue, String converterExp, String separator) { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(","); + for (String item : convertSource) { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(separator, propertyValue)) { + for (String value : propertyValue.split(separator)) { + if (itemArray[0].equals(value)) { + propertyString.append(itemArray[1] + separator); + break; + } + } + } else { + if (itemArray[0].equals(propertyValue)) { + return itemArray[1]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } - /** - * 工作薄对象 - */ - private Workbook wb; + /** + * 反向解析值 男=0,女=1,未知=2 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String reverseByExp(String propertyValue, String converterExp, String separator) { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(","); + for (String item : convertSource) { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(separator, propertyValue)) { + for (String value : propertyValue.split(separator)) { + if (itemArray[1].equals(value)) { + propertyString.append(itemArray[0] + separator); + break; + } + } + } else { + if (itemArray[1].equals(propertyValue)) { + return itemArray[0]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } - /** - * 工作表对象 - */ - private Sheet sheet; + /** + * 解析字典值 + * + * @param dictValue 字典值 + * @param dictType 字典类型 + * @param separator 分隔符 + * @return 字典标签 + */ + public static String convertDictByExp(String dictValue, String dictType, String separator) { + return DictUtils.getDictLabel(dictType, dictValue, separator); + } - /** - * 样式列表 - */ - private Map styles; + /** + * 反向解析值字典值 + * + * @param dictLabel 字典标签 + * @param dictType 字典类型 + * @param separator 分隔符 + * @return 字典值 + */ + public static String reverseDictByExp(String dictLabel, String dictType, String separator) { + return DictUtils.getDictValue(dictType, dictLabel, separator); + } - /** - * 导入导出数据列表 - */ - private List list; + /** + * 编码文件名 + */ + public static String encodingFilename(String filename) { + return IdUtil.fastSimpleUUID() + "_" + filename + ".xlsx"; + } - /** - * 注解列表 - */ - private List fields; - - /** - * 最大高度 - */ - private short maxHeight; - - /** - * 统计列表 - */ - private Map statistics = new HashMap(); - - /** - * 数字格式 - */ - private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); - - /** - * 实体对象 - */ - public Class clazz; - - public ExcelUtil(Class clazz) - { - this.clazz = clazz; - } - - public void init(List list, String sheetName, Type type) - { - if (list == null) - { - list = new ArrayList(); - } - this.list = list; - this.sheetName = sheetName; - this.type = type; - createExcelField(); - createWorkbook(); - } - - /** - * 对excel表单默认第一个索引名转换成list - * - * @param is 输入流 - * @return 转换后集合 - */ - public List importExcel(InputStream is) throws Exception - { - return importExcel(StrUtil.EMPTY, is); - } - - /** - * 对excel表单指定表格索引名转换成list - * - * @param sheetName 表格索引名 - * @param is 输入流 - * @return 转换后集合 - */ - public List importExcel(String sheetName, InputStream is) throws Exception - { - this.type = Type.IMPORT; - this.wb = WorkbookFactory.create(is); - List list = new ArrayList(); - Sheet sheet = null; - if (Validator.isNotEmpty(sheetName)) - { - // 如果指定sheet名,则取指定sheet中的内容. - sheet = wb.getSheet(sheetName); - } - else - { - // 如果传入的sheet名不存在则默认指向第1个sheet. - sheet = wb.getSheetAt(0); - } - - if (sheet == null) - { - throw new IOException("文件sheet不存在"); - } - - int rows = sheet.getPhysicalNumberOfRows(); - - if (rows > 0) - { - // 定义一个map用于存放excel列的序号和field. - Map cellMap = new HashMap(); - // 获取表头 - Row heard = sheet.getRow(0); - for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) - { - Cell cell = heard.getCell(i); - if (Validator.isNotNull(cell)) - { - String value = this.getCellValue(heard, i).toString(); - cellMap.put(value, i); - } - else - { - cellMap.put(null, i); - } - } - // 有数据时才处理 得到类的所有field. - Field[] allFields = clazz.getDeclaredFields(); - // 定义一个map用于存放列的序号和field. - Map fieldsMap = new HashMap(); - for (int col = 0; col < allFields.length; col++) - { - Field field = allFields[col]; - Excel attr = field.getAnnotation(Excel.class); - if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) - { - // 设置类的私有字段属性可访问. - field.setAccessible(true); - Integer column = cellMap.get(attr.name()); - if (column != null) - { - fieldsMap.put(column, field); - } - } - } - for (int i = 1; i < rows; i++) - { - // 从第2行开始取数据,默认第一行是表头. - Row row = sheet.getRow(i); - if(row == null) - { - continue; - } - T entity = null; - for (Map.Entry entry : fieldsMap.entrySet()) - { - Object val = this.getCellValue(row, entry.getKey()); - - // 如果不存在实例则新建. - entity = (entity == null ? clazz.newInstance() : entity); - // 从map中得到对应列的field. - Field field = fieldsMap.get(entry.getKey()); - // 取得类型,并根据对象类型设置值. - Class fieldType = field.getType(); - if (String.class == fieldType) - { - String s = Convert.toStr(val); - if (StrUtil.endWith(s, ".0")) - { - val = StrUtil.subBefore(s, ".0",false); - } - else - { - String dateFormat = field.getAnnotation(Excel.class).dateFormat(); - if (Validator.isNotEmpty(dateFormat)) - { - val = DateUtils.parseDateToStr(dateFormat, (Date) val); - } - else - { - val = Convert.toStr(val); - } - } - } - else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && Validator.isNumber(Convert.toStr(val))) - { - val = Convert.toInt(val); - } - else if (Long.TYPE == fieldType || Long.class == fieldType) - { - val = Convert.toLong(val); - } - else if (Double.TYPE == fieldType || Double.class == fieldType) - { - val = Convert.toDouble(val); - } - else if (Float.TYPE == fieldType || Float.class == fieldType) - { - val = Convert.toFloat(val); - } - else if (BigDecimal.class == fieldType) - { - val = Convert.toBigDecimal(val); - } - else if (Date.class == fieldType) - { - if (val instanceof String) - { - val = DateUtils.parseDate(val); - } - else if (val instanceof Double) - { - val = DateUtil.getJavaDate((Double) val); - } - } - else if (Boolean.TYPE == fieldType || Boolean.class == fieldType) - { - val = Convert.toBool(val, false); - } - if (Validator.isNotNull(fieldType)) - { - Excel attr = field.getAnnotation(Excel.class); - String propertyName = field.getName(); - if (Validator.isNotEmpty(attr.targetAttr())) - { - propertyName = field.getName() + "." + attr.targetAttr(); - } - else if (Validator.isNotEmpty(attr.readConverterExp())) - { - val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); - } - else if (Validator.isNotEmpty(attr.dictType())) - { - val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator()); - } - ReflectUtils.invokeSetter(entity, propertyName, val); - } - } - list.add(entity); - } - } - return list; - } - - /** - * 对list数据源将其里面的数据导入到excel表单 - * - * @param list 导出数据集合 - * @param sheetName 工作表的名称 - * @return 结果 - */ - public AjaxResult exportExcel(List list, String sheetName) - { - this.init(list, sheetName, Type.EXPORT); - return exportExcel(); - } - - /** - * 对list数据源将其里面的数据导入到excel表单 - * - * @param sheetName 工作表的名称 - * @return 结果 - */ - public AjaxResult importTemplateExcel(String sheetName) - { - this.init(null, sheetName, Type.IMPORT); - return exportExcel(); - } - - /** - * 对list数据源将其里面的数据导入到excel表单 - * - * @return 结果 - */ - public AjaxResult exportExcel() - { - OutputStream out = null; - try - { - // 取出一共有多少个sheet. - double sheetNo = Math.ceil(list.size() / sheetSize); - for (int index = 0; index <= sheetNo; index++) - { - createSheet(sheetNo, index); - - // 产生一行 - Row row = sheet.createRow(0); - int column = 0; - // 写入各个字段的列头名称 - for (Object[] os : fields) - { - Excel excel = (Excel) os[1]; - this.createCell(excel, row, column++); - } - if (Type.EXPORT.equals(type)) - { - fillExcelData(index, row); - addStatisticsRow(); - } - } - String filename = encodingFilename(sheetName); - out = new FileOutputStream(getAbsoluteFile(filename)); - wb.write(out); - return AjaxResult.success(filename); - } - catch (Exception e) - { - log.error("导出Excel异常{}", e.getMessage()); - throw new CustomException("导出Excel失败,请联系网站管理员!"); - } - finally - { - if (wb != null) - { - try - { - wb.close(); - } - catch (IOException e1) - { - e1.printStackTrace(); - } - } - if (out != null) - { - try - { - out.close(); - } - catch (IOException e1) - { - e1.printStackTrace(); - } - } - } - } - - /** - * 填充excel数据 - * - * @param index 序号 - * @param row 单元格行 - */ - public void fillExcelData(int index, Row row) - { - int startNo = index * sheetSize; - int endNo = Math.min(startNo + sheetSize, list.size()); - for (int i = startNo; i < endNo; i++) - { - row = sheet.createRow(i + 1 - startNo); - // 得到导出对象. - T vo = (T) list.get(i); - int column = 0; - for (Object[] os : fields) - { - Field field = (Field) os[0]; - Excel excel = (Excel) os[1]; - // 设置实体类私有属性可访问 - field.setAccessible(true); - this.addCell(excel, row, vo, field, column++); - } - } - } - - /** - * 创建表格样式 - * - * @param wb 工作薄对象 - * @return 样式列表 - */ - private Map createStyles(Workbook wb) - { - // 写入各条记录,每条记录对应excel表中的一行 - Map styles = new HashMap(); - CellStyle style = wb.createCellStyle(); - style.setAlignment(HorizontalAlignment.CENTER); - 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()); - Font dataFont = wb.createFont(); - dataFont.setFontName("Arial"); - dataFont.setFontHeightInPoints((short) 10); - style.setFont(dataFont); - styles.put("data", style); - - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data")); - style.setAlignment(HorizontalAlignment.CENTER); - style.setVerticalAlignment(VerticalAlignment.CENTER); - style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); - style.setFillPattern(FillPatternType.SOLID_FOREGROUND); - Font headerFont = wb.createFont(); - headerFont.setFontName("Arial"); - headerFont.setFontHeightInPoints((short) 10); - headerFont.setBold(true); - headerFont.setColor(IndexedColors.WHITE.getIndex()); - style.setFont(headerFont); - styles.put("header", style); - - style = wb.createCellStyle(); - style.setAlignment(HorizontalAlignment.CENTER); - style.setVerticalAlignment(VerticalAlignment.CENTER); - Font totalFont = wb.createFont(); - totalFont.setFontName("Arial"); - totalFont.setFontHeightInPoints((short) 10); - style.setFont(totalFont); - styles.put("total", style); - - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data")); - style.setAlignment(HorizontalAlignment.LEFT); - styles.put("data1", style); - - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data")); - style.setAlignment(HorizontalAlignment.CENTER); - styles.put("data2", style); - - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data")); - style.setAlignment(HorizontalAlignment.RIGHT); - styles.put("data3", style); - - return styles; - } - - /** - * 创建单元格 - */ - public Cell createCell(Excel attr, Row row, int column) - { - // 创建列 - Cell cell = row.createCell(column); - // 写入列信息 - cell.setCellValue(attr.name()); - setDataValidation(attr, row, column); - cell.setCellStyle(styles.get("header")); - return cell; - } - - /** - * 设置单元格信息 - * - * @param value 单元格值 - * @param attr 注解相关 - * @param cell 单元格信息 - */ - public void setCellVo(Object value, Excel attr, Cell cell) - { - if (ColumnType.STRING == attr.cellType()) - { - cell.setCellValue(Validator.isNull(value) ? attr.defaultValue() : value + attr.suffix()); - } - else if (ColumnType.NUMERIC == attr.cellType()) - { - if (Validator.isNotNull(value)) - { - cell.setCellValue(StrUtil.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value)); - } - } - 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); - String imagePath = Convert.toStr(value); - if (Validator.isNotEmpty(imagePath)) - { - byte[] data = ImageUtils.getImage(imagePath); - getDrawingPatriarch(cell.getSheet()).createPicture(anchor, - cell.getSheet().getWorkbook().addPicture(data, getImageType(data))); - } - } - } - - /** - * 获取画布 - */ - public static Drawing getDrawingPatriarch(Sheet sheet) - { - if (sheet.getDrawingPatriarch() == null) - { - sheet.createDrawingPatriarch(); - } - return sheet.getDrawingPatriarch(); - } - - /** - * 获取图片类型,设置图片插入类型 - */ - public int getImageType(byte[] value) - { - String type = FileTypeUtils.getFileExtendName(value); - if ("JPG".equalsIgnoreCase(type)) - { - return Workbook.PICTURE_TYPE_JPEG; - } - else if ("PNG".equalsIgnoreCase(type)) - { - return Workbook.PICTURE_TYPE_PNG; - } - return Workbook.PICTURE_TYPE_JPEG; - } - - /** - * 创建表格样式 - */ - public void setDataValidation(Excel attr, Row row, int column) - { - if (attr.name().indexOf("注:") >= 0) - { - sheet.setColumnWidth(column, 6000); - } - else - { - // 设置列宽 - sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); - } - // 如果设置了提示信息则鼠标放上去提示. - if (Validator.isNotEmpty(attr.prompt())) - { - // 这里默认设了2-101列提示. - setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column); - } - // 如果设置了combo属性则本列只能选择不能输入 - if (attr.combo().length > 0) - { - // 这里默认设了2-101列只能选择不能输入. - setXSSFValidation(sheet, attr.combo(), 1, 100, column, column); - } - } - - /** - * 添加单元格 - */ - public Cell addCell(Excel attr, Row row, T vo, Field field, int column) - { - Cell cell = null; - try - { - // 设置行高 - row.setHeight(maxHeight); - // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. - if (attr.isExport()) - { - // 创建cell - cell = row.createCell(column); - int align = attr.align().value(); - cell.setCellStyle(styles.get("data" + (align >= 1 && align <= 3 ? align : ""))); - - // 用于读取对象中的属性 - Object value = getTargetValue(vo, field, attr); - String dateFormat = attr.dateFormat(); - String readConverterExp = attr.readConverterExp(); - String separator = attr.separator(); - String dictType = attr.dictType(); - if (Validator.isNotEmpty(dateFormat) && Validator.isNotNull(value)) - { - cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value)); - } - else if (Validator.isNotEmpty(readConverterExp) && Validator.isNotNull(value)) - { - cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator)); - } - else if (Validator.isNotEmpty(dictType) && Validator.isNotNull(value)) - { - cell.setCellValue(convertDictByExp(Convert.toStr(value), dictType, separator)); - } - else if (value instanceof BigDecimal && -1 != attr.scale()) - { - cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).toString()); - } - else - { - // 设置列类型 - setCellVo(value, attr, cell); - } - addStatisticsData(column, Convert.toStr(value), attr); - } - } - catch (Exception e) - { - log.error("导出Excel失败{}", e); - } - return cell; - } - - /** - * 设置 POI XSSFSheet 单元格提示 - * - * @param sheet 表单 - * @param promptTitle 提示标题 - * @param promptContent 提示内容 - * @param firstRow 开始行 - * @param endRow 结束行 - * @param firstCol 开始列 - * @param endCol 结束列 - */ - public void setXSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow, - int firstCol, int endCol) - { - DataValidationHelper helper = sheet.getDataValidationHelper(); - DataValidationConstraint constraint = helper.createCustomConstraint("DD1"); - CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); - DataValidation dataValidation = helper.createValidation(constraint, regions); - dataValidation.createPromptBox(promptTitle, promptContent); - dataValidation.setShowPromptBox(true); - sheet.addValidationData(dataValidation); - } - - /** - * 设置某些列的值只能输入预制的数据,显示下拉框. - * - * @param sheet 要设置的sheet. - * @param textlist 下拉框显示的内容 - * @param firstRow 开始行 - * @param endRow 结束行 - * @param firstCol 开始列 - * @param endCol 结束列 - * @return 设置好的sheet. - */ - public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol) - { - DataValidationHelper helper = sheet.getDataValidationHelper(); - // 加载下拉列表内容 - DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist); - // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 - CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); - // 数据有效性对象 - DataValidation dataValidation = helper.createValidation(constraint, regions); - // 处理Excel兼容性问题 - if (dataValidation instanceof XSSFDataValidation) - { - dataValidation.setSuppressDropDownArrow(true); - dataValidation.setShowErrorBox(true); - } - else - { - dataValidation.setSuppressDropDownArrow(false); - } - - sheet.addValidationData(dataValidation); - } - - /** - * 解析导出值 0=男,1=女,2=未知 - * - * @param propertyValue 参数值 - * @param converterExp 翻译注解 - * @param separator 分隔符 - * @return 解析后值 - */ - public static String convertByExp(String propertyValue, String converterExp, String separator) - { - StringBuilder propertyString = new StringBuilder(); - String[] convertSource = converterExp.split(","); - for (String item : convertSource) - { - String[] itemArray = item.split("="); - if (StrUtil.containsAny(propertyValue, separator)) - { - for (String value : propertyValue.split(separator)) - { - if (itemArray[0].equals(value)) - { - propertyString.append(itemArray[1] + separator); - break; - } - } - } - else - { - if (itemArray[0].equals(propertyValue)) - { - return itemArray[1]; - } - } - } - return StrUtil.strip(propertyString.toString(), null,separator); - } - - /** - * 反向解析值 男=0,女=1,未知=2 - * - * @param propertyValue 参数值 - * @param converterExp 翻译注解 - * @param separator 分隔符 - * @return 解析后值 - */ - public static String reverseByExp(String propertyValue, String converterExp, String separator) - { - StringBuilder propertyString = new StringBuilder(); - String[] convertSource = converterExp.split(","); - for (String item : convertSource) - { - String[] itemArray = item.split("="); - if (StrUtil.containsAny(propertyValue, separator)) - { - for (String value : propertyValue.split(separator)) - { - if (itemArray[1].equals(value)) - { - propertyString.append(itemArray[0] + separator); - break; - } - } - } - else - { - if (itemArray[1].equals(propertyValue)) - { - return itemArray[0]; - } - } - } - return StrUtil.strip(propertyString.toString(), null,separator); - } - - /** - * 解析字典值 - * - * @param dictValue 字典值 - * @param dictType 字典类型 - * @param separator 分隔符 - * @return 字典标签 - */ - public static String convertDictByExp(String dictValue, String dictType, String separator) - { - return DictUtils.getDictLabel(dictType, dictValue, separator); - } - - /** - * 反向解析值字典值 - * - * @param dictLabel 字典标签 - * @param dictType 字典类型 - * @param separator 分隔符 - * @return 字典值 - */ - public static String reverseDictByExp(String dictLabel, String dictType, String separator) - { - return DictUtils.getDictValue(dictType, dictLabel, separator); - } - - /** - * 合计统计信息 - */ - private void addStatisticsData(Integer index, String text, Excel entity) - { - if (entity != null && entity.isStatistics()) - { - Double temp = 0D; - if (!statistics.containsKey(index)) - { - statistics.put(index, temp); - } - try - { - temp = Double.valueOf(text); - } - catch (NumberFormatException e) - { - } - statistics.put(index, statistics.get(index) + temp); - } - } - - /** - * 创建统计行 - */ - public void addStatisticsRow() - { - if (statistics.size() > 0) - { - Cell cell = null; - Row row = sheet.createRow(sheet.getLastRowNum() + 1); - Set keys = statistics.keySet(); - cell = row.createCell(0); - cell.setCellStyle(styles.get("total")); - cell.setCellValue("合计"); - - for (Integer key : keys) - { - cell = row.createCell(key); - cell.setCellStyle(styles.get("total")); - cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key))); - } - statistics.clear(); - } - } - - /** - * 编码文件名 - */ - public String encodingFilename(String filename) - { - filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx"; - return filename; - } - - /** - * 获取下载路径 - * - * @param filename 文件名称 - */ - public String getAbsoluteFile(String filename) - { - String downloadPath = RuoYiConfig.getDownloadPath() + filename; - File desc = new File(downloadPath); - if (!desc.getParentFile().exists()) - { - desc.getParentFile().mkdirs(); - } - return downloadPath; - } - - /** - * 获取bean中的属性值 - * - * @param vo 实体对象 - * @param field 字段 - * @param excel 注解 - * @return 最终的属性值 - * @throws Exception - */ - private Object getTargetValue(T vo, Field field, Excel excel) throws Exception - { - Object o = field.get(vo); - if (Validator.isNotEmpty(excel.targetAttr())) - { - String target = excel.targetAttr(); - if (target.contains(".")) - { - String[] targets = target.split("[.]"); - for (String name : targets) - { - o = getValue(o, name); - } - } - else - { - o = getValue(o, target); - } - } - return o; - } - - /** - * 以类的属性的get方法方法形式获取值 - * - * @param o - * @param name - * @return value - * @throws Exception - */ - private Object getValue(Object o, String name) throws Exception - { - if (Validator.isNotNull(o) && Validator.isNotEmpty(name)) - { - Class clazz = o.getClass(); - Field field = clazz.getDeclaredField(name); - field.setAccessible(true); - o = field.get(o); - } - return o; - } - - /** - * 得到所有定义字段 - */ - private void createExcelField() - { - this.fields = new ArrayList(); - List tempFields = new ArrayList<>(); - tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); - tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); - for (Field field : tempFields) - { - // 单注解 - if (field.isAnnotationPresent(Excel.class)) - { - putToField(field, field.getAnnotation(Excel.class)); - } - - // 多注解 - if (field.isAnnotationPresent(Excels.class)) - { - Excels attrs = field.getAnnotation(Excels.class); - Excel[] excels = attrs.value(); - for (Excel excel : excels) - { - putToField(field, excel); - } - } - } - this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); - this.maxHeight = getRowHeight(); - } - - /** - * 根据注解获取最大行高 - */ - public short getRowHeight() - { - double maxHeight = 0; - for (Object[] os : this.fields) - { - Excel excel = (Excel) os[1]; - maxHeight = maxHeight > excel.height() ? maxHeight : excel.height(); - } - return (short) (maxHeight * 20); - } - - /** - * 放到字段集合中 - */ - private void putToField(Field field, Excel attr) - { - if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) - { - this.fields.add(new Object[] { field, attr }); - } - } - - /** - * 创建一个工作簿 - */ - public void createWorkbook() - { - this.wb = new SXSSFWorkbook(500); - } - - /** - * 创建工作表 - * - * @param sheetNo sheet数量 - * @param index 序号 - */ - public void createSheet(double sheetNo, int index) - { - this.sheet = wb.createSheet(); - this.styles = createStyles(wb); - // 设置工作表的名称. - if (sheetNo == 0) - { - wb.setSheetName(index, sheetName); - } - else - { - wb.setSheetName(index, sheetName + index); - } - } - - /** - * 获取单元格值 - * - * @param row 获取的行 - * @param column 获取单元格列号 - * @return 单元格值 - */ - public Object getCellValue(Row row, int column) - { - if (row == null) - { - return row; - } - Object val = ""; - try - { - Cell cell = row.getCell(column); - if (Validator.isNotNull(cell)) - { - if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA) - { - val = cell.getNumericCellValue(); - if (DateUtil.isCellDateFormatted(cell)) - { - val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换 - } - else - { - if ((Double) val % 1 != 0) - { - val = new BigDecimal(val.toString()); - } - else - { - val = new DecimalFormat("0").format(val); - } - } - } - else if (cell.getCellType() == CellType.STRING) - { - val = cell.getStringCellValue(); - } - else if (cell.getCellType() == CellType.BOOLEAN) - { - val = cell.getBooleanCellValue(); - } - else if (cell.getCellType() == CellType.ERROR) - { - val = cell.getErrorCellValue(); - } - - } - } - catch (Exception e) - { - return val; - } - return val; - } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java index c5d17d8b0..749f1abd3 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java @@ -1,10 +1,9 @@ package com.ruoyi.common.utils.reflect; import cn.hutool.core.util.ReflectUtil; -import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.utils.StringUtils; import java.lang.reflect.Method; -import java.util.List; /** * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数. @@ -25,8 +24,8 @@ public class ReflectUtils extends ReflectUtil { @SuppressWarnings("unchecked") public static E invokeGetter(Object obj, String propertyName) { Object object = obj; - for (String name : StrUtil.split(propertyName, ".")) { - String getterMethodName = GETTER_PREFIX + StrUtil.upperFirst(name); + for (String name : StringUtils.split(propertyName, ".")) { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); object = invoke(object, getterMethodName); } return (E) object; @@ -38,13 +37,13 @@ public class ReflectUtils extends ReflectUtil { */ public static void invokeSetter(Object obj, String propertyName, E value) { Object object = obj; - List names = StrUtil.split(propertyName, "."); - for (int i = 0; i < names.size(); i++) { - if (i < names.size() - 1) { - String getterMethodName = GETTER_PREFIX + StrUtil.upperFirst(names.get(i)); + String[] names = StringUtils.split(propertyName, "."); + for (int i = 0; i < names.length; i++) { + if (i < names.length - 1) { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]); object = invoke(object, getterMethodName); } else { - String setterMethodName = SETTER_PREFIX + StrUtil.upperFirst(names.get(i)); + String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); Method method = getMethodByName(object.getClass(), setterMethodName); invoke(object, method, value); } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java index a37268a9c..04731a5cf 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java @@ -1,11 +1,11 @@ package com.ruoyi.common.utils.sql; -import cn.hutool.core.lang.Validator; -import com.ruoyi.common.exception.BaseException; +import com.ruoyi.common.exception.UtilException; +import com.ruoyi.common.utils.StringUtils; /** * sql操作工具类 - * + * * @author ruoyi */ public class SqlUtil @@ -20,9 +20,9 @@ public class SqlUtil */ public static String escapeOrderBySql(String value) { - if (Validator.isNotEmpty(value) && !isValidOrderBySql(value)) + if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) { - throw new BaseException("参数不符合规范,不能进行查询"); + throw new UtilException("参数不符合规范,不能进行查询"); } return value; } diff --git a/ruoyi-demo/pom.xml b/ruoyi-demo/pom.xml index 1066d2f61..1393d491e 100644 --- a/ruoyi-demo/pom.xml +++ b/ruoyi-demo/pom.xml @@ -5,7 +5,7 @@ ruoyi-vue-plus com.ruoyi - 2.6.0 + 3.0.0 4.0.0 diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestBatchController.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestBatchController.java index 334f004cd..9a66fddff 100644 --- a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestBatchController.java +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestBatchController.java @@ -5,6 +5,8 @@ import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.demo.domain.TestDemo; import com.ruoyi.demo.service.ITestDemoService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.DeleteMapping; @@ -21,6 +23,7 @@ import java.util.List; * @author Lion Li * @date 2021-05-30 */ +@Api(value = "测试批量方法", tags = {"测试批量方法"}) @RequiredArgsConstructor(onConstructor_ = @Autowired) @RestController @RequestMapping("/demo/batch") @@ -31,7 +34,9 @@ public class TestBatchController extends BaseController { /** * 新增批量方法 ( 全量覆盖填充 ) */ + @ApiOperation(value = "新增批量方法") @PostMapping() +// @DataSource(DataSourceType.SLAVE) public AjaxResult add() { List list = new ArrayList<>(); for (int i = 0; i < 1000; i++) { @@ -41,10 +46,12 @@ public class TestBatchController extends BaseController { } /** - * 修改批量方法 + * 删除批量方法 */ + @ApiOperation(value = "删除批量方法") @DeleteMapping() - public AjaxResult edit() { +// @DataSource(DataSourceType.SLAVE) + public AjaxResult remove() { return toAjax(iTestDemoService.remove(new LambdaQueryWrapper() .eq(TestDemo::getOrderNum, -1L)) ? 1 : 0); } diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java index ade20f8d3..a393c9199 100644 --- a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java @@ -20,10 +20,12 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import java.util.Arrays; import java.util.List; +import java.util.concurrent.TimeUnit; /** * 测试单表Controller @@ -67,10 +69,9 @@ public class TestDemoController extends BaseController { @PreAuthorize("@ss.hasPermi('demo:demo:export')") @Log(title = "测试单表", businessType = BusinessType.EXPORT) @GetMapping("/export") - public AjaxResult export(@Validated TestDemoBo bo) { + public void export(@Validated TestDemoBo bo, HttpServletResponse response) { List list = iTestDemoService.queryList(bo); - ExcelUtil util = new ExcelUtil(TestDemoVo.class); - return util.exportExcel(list, "测试单表"); + ExcelUtil.exportExcel(list, "测试单表", TestDemoVo.class, response); } /** @@ -90,7 +91,7 @@ public class TestDemoController extends BaseController { @ApiOperation("新增测试单表") @PreAuthorize("@ss.hasPermi('demo:demo:add')") @Log(title = "测试单表", businessType = BusinessType.INSERT) - @RepeatSubmit + @RepeatSubmit(intervalTime = 2, timeUnit = TimeUnit.SECONDS) @PostMapping() public AjaxResult add(@Validated(AddGroup.class) @RequestBody TestDemoBo bo) { return toAjax(iTestDemoService.insertByBo(bo) ? 1 : 0); diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestI18nController.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestI18nController.java new file mode 100644 index 000000000..8ccce2a58 --- /dev/null +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestI18nController.java @@ -0,0 +1,29 @@ +package com.ruoyi.demo.controller; + +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.utils.MessageUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + + +/** + * 测试国际化 + * + * @author Lion Li + */ +@RestController +@RequestMapping("/demo/i18n") +public class TestI18nController { + + /** + * 通过code获取国际化内容 + * code为 messages.properties 中的 key + * + * 测试使用 user.register.success + */ + @GetMapping() + public AjaxResult get(String code) { + return AjaxResult.success(MessageUtils.message(code)); + } +} diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestTreeController.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestTreeController.java index 8cab868ce..63b1743ff 100644 --- a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestTreeController.java +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestTreeController.java @@ -19,6 +19,7 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import java.util.Arrays; @@ -57,10 +58,9 @@ public class TestTreeController extends BaseController { @PreAuthorize("@ss.hasPermi('demo:tree:export')") @Log(title = "测试树表", businessType = BusinessType.EXPORT) @GetMapping("/export") - public AjaxResult export(@Validated TestTreeBo bo) { + public void export(@Validated TestTreeBo bo, HttpServletResponse response) { List list = iTestTreeService.queryList(bo); - ExcelUtil util = new ExcelUtil(TestTreeVo.class); - return util.exportExcel(list, "测试树表"); + ExcelUtil.exportExcel(list, "测试树表", TestTreeVo.class, response); } /** diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestDemoVo.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestDemoVo.java index 9ab4ba952..3c8e45234 100644 --- a/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestDemoVo.java +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestDemoVo.java @@ -1,9 +1,11 @@ package com.ruoyi.demo.domain.vo; -import com.ruoyi.common.annotation.Excel; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; + import java.util.Date; @@ -16,6 +18,7 @@ import java.util.Date; */ @Data @ApiModel("测试单表视图对象") +@ExcelIgnoreUnannotated public class TestDemoVo { private static final long serialVersionUID = 1L; @@ -29,63 +32,63 @@ public class TestDemoVo { /** * 部门id */ - @Excel(name = "部门id") + @ExcelProperty(value = "部门id") @ApiModelProperty("部门id") private Long deptId; /** * 用户id */ - @Excel(name = "用户id") + @ExcelProperty(value = "用户id") @ApiModelProperty("用户id") private Long userId; /** * 排序号 */ - @Excel(name = "排序号") + @ExcelProperty(value = "排序号") @ApiModelProperty("排序号") private Long orderNum; /** * key键 */ - @Excel(name = "key键") + @ExcelProperty(value = "key键") @ApiModelProperty("key键") private String testKey; /** * 值 */ - @Excel(name = "值") + @ExcelProperty(value = "值") @ApiModelProperty("值") private String value; /** * 创建时间 */ - @Excel(name = "创建时间" , width = 30, dateFormat = "yyyy-MM-dd") + @ExcelProperty(value = "创建时间") @ApiModelProperty("创建时间") private Date createTime; /** * 创建人 */ - @Excel(name = "创建人") + @ExcelProperty(value = "创建人") @ApiModelProperty("创建人") private String createBy; /** * 更新时间 */ - @Excel(name = "更新时间" , width = 30, dateFormat = "yyyy-MM-dd") + @ExcelProperty(value = "更新时间") @ApiModelProperty("更新时间") private Date updateTime; /** * 更新人 */ - @Excel(name = "更新人") + @ExcelProperty(value = "更新人") @ApiModelProperty("更新人") private String updateBy; diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestTreeVo.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestTreeVo.java index a299c4a46..dab816243 100644 --- a/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestTreeVo.java +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestTreeVo.java @@ -1,9 +1,11 @@ package com.ruoyi.demo.domain.vo; -import com.ruoyi.common.annotation.Excel; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; + import java.util.Date; @@ -16,6 +18,7 @@ import java.util.Date; */ @Data @ApiModel("测试树表视图对象") +@ExcelIgnoreUnannotated public class TestTreeVo { private static final long serialVersionUID = 1L; @@ -29,35 +32,35 @@ public class TestTreeVo { /** * 父id */ - @Excel(name = "父id") + @ExcelProperty(value = "父id") @ApiModelProperty("父id") private Long parentId; /** * 部门id */ - @Excel(name = "部门id") + @ExcelProperty(value = "部门id") @ApiModelProperty("部门id") private Long deptId; /** * 用户id */ - @Excel(name = "用户id") + @ExcelProperty(value = "用户id") @ApiModelProperty("用户id") private Long userId; /** * 树节点名 */ - @Excel(name = "树节点名") + @ExcelProperty(value = "树节点名") @ApiModelProperty("树节点名") private String treeName; /** * 创建时间 */ - @Excel(name = "创建时间" , width = 30, dateFormat = "yyyy-MM-dd") + @ExcelProperty(value = "创建时间") @ApiModelProperty("创建时间") private Date createTime; diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestDemoServiceImpl.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestDemoServiceImpl.java index 81893dff9..fe103ef88 100644 --- a/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestDemoServiceImpl.java +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestDemoServiceImpl.java @@ -1,7 +1,7 @@ package com.ruoyi.demo.service.impl; import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.utils.StringUtils; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -62,11 +62,11 @@ public class TestDemoServiceImpl extends ServicePlusImpl params = bo.getParams(); Object dataScope = params.get("dataScope"); LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.like(StrUtil.isNotBlank(bo.getTestKey()), TestDemo::getTestKey, bo.getTestKey()); - lqw.eq(StrUtil.isNotBlank(bo.getValue()), TestDemo::getValue, bo.getValue()); + lqw.like(StringUtils.isNotBlank(bo.getTestKey()), TestDemo::getTestKey, bo.getTestKey()); + lqw.eq(StringUtils.isNotBlank(bo.getValue()), TestDemo::getValue, bo.getValue()); lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, TestDemo::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime")); - lqw.apply(dataScope != null && StrUtil.isNotBlank(dataScope.toString()), + lqw.apply(dataScope != null && StringUtils.isNotBlank(dataScope.toString()), dataScope != null ? dataScope.toString() : null); return lqw; } diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestTreeServiceImpl.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestTreeServiceImpl.java index a953412d1..1985c1ece 100644 --- a/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestTreeServiceImpl.java +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestTreeServiceImpl.java @@ -1,7 +1,7 @@ package com.ruoyi.demo.service.impl; import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.utils.StringUtils; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.ruoyi.common.annotation.DataScope; @@ -42,10 +42,10 @@ public class TestTreeServiceImpl extends ServicePlusImpl params = bo.getParams(); Object dataScope = params.get("dataScope"); LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.like(StrUtil.isNotBlank(bo.getTreeName()), TestTree::getTreeName, bo.getTreeName()); + lqw.like(StringUtils.isNotBlank(bo.getTreeName()), TestTree::getTreeName, bo.getTreeName()); lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, TestTree::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime")); - lqw.apply(dataScope != null && StrUtil.isNotBlank(dataScope.toString()), + lqw.apply(dataScope != null && StringUtils.isNotBlank(dataScope.toString()), dataScope != null ? dataScope.toString() : null); return lqw; } diff --git a/ruoyi-extend/pom.xml b/ruoyi-extend/pom.xml index 4df48bab7..3bfe77021 100644 --- a/ruoyi-extend/pom.xml +++ b/ruoyi-extend/pom.xml @@ -5,7 +5,7 @@ ruoyi-vue-plus com.ruoyi - 2.6.0 + 3.0.0 4.0.0 ruoyi-extend diff --git a/ruoyi-extend/ruoyi-monitor-admin/pom.xml b/ruoyi-extend/ruoyi-monitor-admin/pom.xml index 9aca296c1..bada747b4 100644 --- a/ruoyi-extend/ruoyi-monitor-admin/pom.xml +++ b/ruoyi-extend/ruoyi-monitor-admin/pom.xml @@ -5,7 +5,7 @@ ruoyi-extend com.ruoyi - 2.6.0 + 3.0.0 4.0.0 jar diff --git a/ruoyi-framework/pom.xml b/ruoyi-framework/pom.xml index 41e8ca431..5fca8f94b 100644 --- a/ruoyi-framework/pom.xml +++ b/ruoyi-framework/pom.xml @@ -5,7 +5,7 @@ ruoyi-vue-plus com.ruoyi - 2.6.0 + 3.0.0 4.0.0 diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java index 830dbe594..773952a6e 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java @@ -1,13 +1,12 @@ package com.ruoyi.framework.aspectj; -import cn.hutool.core.lang.Validator; -import cn.hutool.core.util.StrUtil; import com.ruoyi.common.annotation.DataScope; import com.ruoyi.common.core.domain.BaseEntity; import com.ruoyi.common.core.domain.entity.SysRole; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.reflect.ReflectUtils; import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.framework.web.service.TokenService; @@ -80,10 +79,10 @@ public class DataScopeAspect { } // 获取当前的用户 LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest()); - if (Validator.isNotNull(loginUser)) { + if (StringUtils.isNotNull(loginUser)) { SysUser currentUser = loginUser.getUser(); // 如果是超级管理员,则不过滤数据 - if (Validator.isNotNull(currentUser) && !currentUser.isAdmin()) { + if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) { dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), controllerDataScope.userAlias(), controllerDataScope.isUser()); } @@ -101,8 +100,8 @@ public class DataScopeAspect { StringBuilder sqlString = new StringBuilder(); // 将 "." 提取出,不写别名为单表查询,写别名为多表查询 - deptAlias = StrUtil.isNotBlank(deptAlias) ? deptAlias + "." : ""; - userAlias = StrUtil.isNotBlank(userAlias) ? userAlias + "." : ""; + deptAlias = StringUtils.isNotBlank(deptAlias) ? deptAlias + "." : ""; + userAlias = StringUtils.isNotBlank(userAlias) ? userAlias + "." : ""; for (SysRole role : user.getRoles()) { String dataScope = role.getDataScope(); @@ -110,19 +109,19 @@ public class DataScopeAspect { sqlString = new StringBuilder(); break; } else if (DATA_SCOPE_CUSTOM.equals(dataScope)) { - sqlString.append(StrUtil.format( + 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)) { - sqlString.append(StrUtil.format(" OR {}dept_id = {} ", + sqlString.append(StringUtils.format(" OR {}dept_id = {} ", deptAlias, user.getDeptId())); } else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) { - sqlString.append(StrUtil.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())); } else if (DATA_SCOPE_SELF.equals(dataScope)) { if (isUser) { - sqlString.append(StrUtil.format(" OR {}user_id = {} ", + sqlString.append(StringUtils.format(" OR {}user_id = {} ", userAlias, user.getUserId())); } else { // 数据权限为仅本人且没有userAlias别名不查询任何数据 @@ -131,7 +130,7 @@ public class DataScopeAspect { } } - if (StrUtil.isNotBlank(sqlString.toString())) { + if (StringUtils.isNotBlank(sqlString.toString())) { putDataScope(joinPoint, sqlString.substring(4)); } } @@ -155,14 +154,14 @@ public class DataScopeAspect { */ private void clearDataScope(final JoinPoint joinPoint) { Object params = joinPoint.getArgs()[0]; - if (Validator.isNotNull(params)) { + if (StringUtils.isNotNull(params)) { putDataScope(joinPoint, ""); } } private static void putDataScope(JoinPoint joinPoint, String sql) { Object params = joinPoint.getArgs()[0]; - if (Validator.isNotNull(params)) { + if (StringUtils.isNotNull(params)) { if (params instanceof BaseEntity) { BaseEntity baseEntity = (BaseEntity) params; baseEntity.getParams().put(DATA_SCOPE, sql); diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java index f82b2ae47..47e774265 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java @@ -1,8 +1,8 @@ package com.ruoyi.framework.aspectj; -import cn.hutool.core.lang.Validator; import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; import com.ruoyi.common.annotation.DataSource; +import com.ruoyi.common.utils.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @@ -33,7 +33,7 @@ public class DataSourceAspect { public Object around(ProceedingJoinPoint point) throws Throwable { DataSource dataSource = getDataSource(point); - if (Validator.isNotNull(dataSource)) { + if (StringUtils.isNotNull(dataSource)) { DynamicDataSourceContextHolder.poll(); String source = dataSource.value().getSource(); DynamicDataSourceContextHolder.push(source); diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java index d5c0fe8d5..c9025117a 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java @@ -1,13 +1,12 @@ package com.ruoyi.framework.aspectj; -import cn.hutool.core.lang.Validator; -import cn.hutool.core.util.StrUtil; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.enums.BusinessStatus; import com.ruoyi.common.enums.HttpMethod; import com.ruoyi.common.utils.JsonUtils; import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.framework.web.service.AsyncService; import com.ruoyi.framework.web.service.TokenService; @@ -104,7 +103,7 @@ public class LogAspect if (e != null) { operLog.setStatus(BusinessStatus.FAIL.ordinal()); - operLog.setErrorMsg(StrUtil.sub(e.getMessage(), 0, 2000)); + operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000)); } // 设置方法名称 String className = joinPoint.getTarget().getClass().getName(); @@ -161,12 +160,12 @@ public class LogAspect if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) { String params = argsArrayToString(joinPoint.getArgs()); - operLog.setOperParam(StrUtil.sub(params, 0, 2000)); + operLog.setOperParam(StringUtils.substring(params, 0, 2000)); } else { Map paramsMap = (Map) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); - operLog.setOperParam(StrUtil.sub(paramsMap.toString(), 0, 2000)); + operLog.setOperParam(StringUtils.substring(paramsMap.toString(), 0, 2000)); } } @@ -195,7 +194,7 @@ public class LogAspect if (paramsArray != null && paramsArray.length > 0) { for (Object o : paramsArray) { - if (Validator.isNotNull(o) && !isFilterObject(o)) { + if (StringUtils.isNotNull(o) && !isFilterObject(o)) { params.append(JsonUtils.toJsonString(o)).append(" "); } } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java new file mode 100644 index 000000000..1e21e376d --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java @@ -0,0 +1,116 @@ +package com.ruoyi.framework.aspectj; + +import com.ruoyi.common.annotation.RateLimiter; +import com.ruoyi.common.enums.LimitType; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.StringUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.script.RedisScript; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.List; + +/** + * 限流处理 + * + * @author ruoyi + */ +@Aspect +@Component +public class RateLimiterAspect +{ + private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class); + + private RedisTemplate redisTemplate; + + private RedisScript limitScript; + + @Autowired + public void setRedisTemplate1(RedisTemplate redisTemplate) + { + this.redisTemplate = redisTemplate; + } + + @Autowired + public void setLimitScript(RedisScript limitScript) + { + this.limitScript = limitScript; + } + + // 配置织入点 + @Pointcut("@annotation(com.ruoyi.common.annotation.RateLimiter)") + public void rateLimiterPointCut() + { + } + + @Before("rateLimiterPointCut()") + public void doBefore(JoinPoint point) throws Throwable + { + RateLimiter rateLimiter = getAnnotationRateLimiter(point); + String key = rateLimiter.key(); + int time = rateLimiter.time(); + int count = rateLimiter.count(); + + String combineKey = getCombineKey(rateLimiter, point); + List keys = Collections.singletonList(combineKey); + try + { + Long number = redisTemplate.execute(limitScript, keys, count, time); + if (StringUtils.isNull(number) || number.intValue() > count) + { + throw new ServiceException("访问过于频繁,请稍后再试"); + } + log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), key); + } + catch (ServiceException e) + { + throw e; + } + catch (Exception e) + { + throw new RuntimeException("服务器限流异常,请稍后再试"); + } + } + + /** + * 是否存在注解,如果存在就获取 + */ + private RateLimiter getAnnotationRateLimiter(JoinPoint joinPoint) + { + Signature signature = joinPoint.getSignature(); + MethodSignature methodSignature = (MethodSignature) signature; + Method method = methodSignature.getMethod(); + + if (method != null) + { + return method.getAnnotation(RateLimiter.class); + } + return null; + } + + public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) + { + StringBuffer stringBuffer = new StringBuffer(rateLimiter.key()); + if (rateLimiter.limitType() == LimitType.IP) + { + stringBuffer.append(ServletUtils.getClientIP()); + } + MethodSignature signature = (MethodSignature) point.getSignature(); + Method method = signature.getMethod(); + Class targetClass = method.getDeclaringClass(); + stringBuffer.append("-").append(targetClass.getName()).append("- ").append(method.getName()); + return stringBuffer.toString(); + } +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/captcha/UnsignedMathGenerator.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/captcha/UnsignedMathGenerator.java index b4f8bfc12..f35afdf68 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/captcha/UnsignedMathGenerator.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/captcha/UnsignedMathGenerator.java @@ -4,7 +4,7 @@ import cn.hutool.captcha.generator.CodeGenerator; import cn.hutool.core.math.Calculator; import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.RandomUtil; -import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.utils.StringUtils; /** * 无符号计算生成器 @@ -45,8 +45,8 @@ public class UnsignedMathGenerator implements CodeGenerator { int max = RandomUtil.randomInt(min, limit); String number1 = Integer.toString(max); String number2 = Integer.toString(min); - number1 = StrUtil.padAfter(number1, this.numberLength, CharUtil.SPACE); - number2 = StrUtil.padAfter(number2, this.numberLength, CharUtil.SPACE); + number1 = StringUtils.rightPad(number1, this.numberLength, CharUtil.SPACE); + number2 = StringUtils.rightPad(number2, this.numberLength, CharUtil.SPACE); return number1 + RandomUtil.randomChar(operators) + number2 + '='; } @@ -80,6 +80,6 @@ public class UnsignedMathGenerator implements CodeGenerator { * @return 最大值 */ private int getLimit() { - return Integer.parseInt("1" + StrUtil.repeat('0', this.numberLength)); + return Integer.parseInt("1" + StringUtils.repeat('0', this.numberLength)); } } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java index 183c36405..072eef96a 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java @@ -1,12 +1,8 @@ package com.ruoyi.framework.config; -import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; -import java.util.TimeZone; - /** * 程序注解配置 * @@ -16,11 +12,5 @@ import java.util.TimeZone; // 表示通过aop框架暴露该代理对象,AopContext能够访问 @EnableAspectJAutoProxy(exposeProxy = true) public class ApplicationConfig { - /** - * 时区配置 - */ - @Bean - public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() { - return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault()); - } + } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AsyncConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AsyncConfig.java index 2eb4eb3f2..e30f83c79 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AsyncConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AsyncConfig.java @@ -1,6 +1,6 @@ package com.ruoyi.framework.config; -import com.ruoyi.common.exception.CustomException; +import com.ruoyi.common.exception.ServiceException; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -41,7 +41,7 @@ public class AsyncConfig extends AsyncConfigurerSupport { public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return (throwable, method, objects) -> { throwable.printStackTrace(); - throw new CustomException( + throw new ServiceException( "Exception message - " + throwable.getMessage() + ", Method name - " + method.getName() + ", Parameter value - " + Arrays.toString(objects)); diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java index b09bc98ad..459020d87 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java @@ -1,10 +1,11 @@ package com.ruoyi.framework.config; -import cn.hutool.core.util.StrUtil; import com.ruoyi.common.filter.RepeatableFilter; import com.ruoyi.common.filter.XssFilter; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.config.properties.XssProperties; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -19,6 +20,7 @@ import java.util.Map; * @author Lion Li */ @Configuration +@ConditionalOnProperty(value = "xss.enabled", havingValue = "true") public class FilterConfig { @Autowired @@ -30,12 +32,11 @@ public class FilterConfig { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setDispatcherTypes(DispatcherType.REQUEST); registration.setFilter(new XssFilter()); - registration.addUrlPatterns(StrUtil.splitToArray(xssProperties.getUrlPatterns(), ",")); + registration.addUrlPatterns(StringUtils.split(xssProperties.getUrlPatterns(), ",")); registration.setName("xssFilter"); registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE); Map initParameters = new HashMap(); initParameters.put("excludes", xssProperties.getExcludes()); - initParameters.put("enabled", xssProperties.getEnabled()); registration.setInitParameters(initParameters); return registration; } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java new file mode 100644 index 000000000..48b341beb --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java @@ -0,0 +1,48 @@ +package com.ruoyi.framework.config; + +import cn.hutool.core.util.StrUtil; +import org.jetbrains.annotations.NotNull; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.LocaleResolver; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Locale; + +/** + * 国际化配置 + * + * @author Lion Li + */ +@Configuration +public class I18nConfig { + + @Bean + public LocaleResolver localeResolver() { + return new I18nLocaleResolver(); + } + + /** + * 获取请求头国际化信息 + */ + static class I18nLocaleResolver implements LocaleResolver { + + @NotNull + @Override + public Locale resolveLocale(HttpServletRequest httpServletRequest) { + String language = httpServletRequest.getHeader("content-language"); + Locale locale = Locale.getDefault(); + if (StrUtil.isNotBlank(language)) { + String[] split = language.split("_"); + locale = new Locale(split[0], split[1]); + } + return locale; + } + + @Override + public void setLocale(@NotNull HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) { + + } + } +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/JacksonConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/JacksonConfig.java index 8334b2a91..4346610f8 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/JacksonConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/JacksonConfig.java @@ -2,15 +2,19 @@ package com.ruoyi.framework.config; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import com.ruoyi.common.utils.JsonUtils; +import com.ruoyi.framework.jackson.BigNumberSerializer; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import java.math.BigDecimal; +import java.math.BigInteger; import java.time.LocalDateTime; import java.util.TimeZone; @@ -34,6 +38,10 @@ public class JacksonConfig { ObjectMapper objectMapper = (ObjectMapper) bean; // 全局配置序列化返回 JSON 处理 SimpleModule simpleModule = new SimpleModule(); + simpleModule.addSerializer(Long.class, BigNumberSerializer.INSTANCE); + simpleModule.addSerializer(Long.TYPE, BigNumberSerializer.INSTANCE); + simpleModule.addSerializer(BigInteger.class, BigNumberSerializer.INSTANCE); + simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance); simpleModule.addSerializer(LocalDateTime.class, LocalDateTimeSerializer.INSTANCE); simpleModule.addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE); objectMapper.registerModule(simpleModule); diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java index bc286574b..d66d86bf6 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java @@ -1,6 +1,7 @@ package com.ruoyi.framework.config; import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.config.properties.RedissonProperties; import org.redisson.Redisson; import org.redisson.api.RedissonClient; @@ -16,6 +17,7 @@ import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.script.DefaultRedisScript; import java.io.IOException; import java.util.HashMap; @@ -59,7 +61,7 @@ public class RedisConfig extends CachingConfigurerSupport { .setAddress(prefix + redisProperties.getHost() + ":" + redisProperties.getPort()) .setConnectTimeout(((Long) redisProperties.getTimeout().toMillis()).intValue()) .setDatabase(redisProperties.getDatabase()) - .setPassword(StrUtil.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null) + .setPassword(StringUtils.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null) .setTimeout(singleServerConfig.getTimeout()) .setRetryAttempts(singleServerConfig.getRetryAttempts()) .setRetryInterval(singleServerConfig.getRetryInterval()) @@ -89,4 +91,32 @@ public class RedisConfig extends CachingConfigurerSupport { return new RedissonSpringCacheManager(redissonClient, config, JsonJacksonCodec.INSTANCE); } + @Bean + public DefaultRedisScript limitScript() { + DefaultRedisScript redisScript = new DefaultRedisScript<>(); + redisScript.setScriptText(limitScriptText()); + redisScript.setResultType(Long.class); + return redisScript; + } + + /** + * 限流脚本 + */ + private String limitScriptText() { + return StrUtil.builder() + .append("local key = KEYS[1]\n") + .append("local count = tonumber(ARGV[1])\n") + .append("local time = tonumber(ARGV[2])\n") + .append("local current = redis.call('get', key);\n") + .append("if current and tonumber(current) > count then\n") + .append(" return current;\n") + .append("end\n") + .append("current = redis.call('incr', key)\n") + .append("if tonumber(current) == 1 then\n") + .append(" redis.call('expire', key, time)\n") + .append("end\n") + .append("return current;") + .toString(); + } + } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java index c3cdc943c..870af3f9a 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java @@ -1,5 +1,6 @@ package com.ruoyi.framework.config; +import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -9,9 +10,6 @@ import org.springframework.web.filter.CorsFilter; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import com.ruoyi.common.config.RuoYiConfig; -import com.ruoyi.common.constant.Constants; -import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; /** * 通用配置 @@ -27,8 +25,6 @@ public class ResourcesConfig implements WebMvcConfigurer @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { - /** 本地文件上传路径 */ - registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/"); } /** diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java index 0a8337e90..bd6ee8f36 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java @@ -96,19 +96,16 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() // 过滤请求 .authorizeRequests() - // 对于登录login 验证码captchaImage 允许匿名访问 - .antMatchers("/login", "/captchaImage").anonymous() + // 对于登录login 注册register 验证码captchaImage 允许匿名访问 + .antMatchers("/login", "/register", "/captchaImage").anonymous() .antMatchers( HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", - "/**/*.js", - "/profile/**" + "/**/*.js" ).permitAll() - .antMatchers("/common/download**").anonymous() - .antMatchers("/common/download/resource**").anonymous() .antMatchers("/doc.html").anonymous() .antMatchers("/swagger-resources/**").anonymous() .antMatchers("/webjars/**").anonymous() @@ -129,7 +126,6 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class); } - /** * 强散列哈希加密实现 */ diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RepeatSubmitProperties.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RepeatSubmitProperties.java new file mode 100644 index 000000000..b948f8340 --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RepeatSubmitProperties.java @@ -0,0 +1,22 @@ +package com.ruoyi.framework.config.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 重复提交 配置属性 + * + * @author Lion Li + */ +@Data +@Component +@ConfigurationProperties(prefix = "repeat-submit") +public class RepeatSubmitProperties { + + /** + * 间隔时间(毫秒) + */ + private int intervalTime; + +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java index bd0e99ed5..9af0a830b 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java @@ -6,7 +6,7 @@ import com.ruoyi.common.utils.JsonUtils; import com.ruoyi.common.utils.ServletUtils; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; +import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -15,42 +15,36 @@ import java.lang.reflect.Method; /** * 防止重复提交拦截器 * - * @author ruoyi + * 移除继承 HandlerInterceptorAdapter 过期类 + * 改为实现 HandlerInterceptor 接口(官方推荐写法) + * + * @author Lion Li */ @Component -public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter -{ - @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception - { - if (handler instanceof HandlerMethod) - { - HandlerMethod handlerMethod = (HandlerMethod) handler; - Method method = handlerMethod.getMethod(); - RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); - if (annotation != null) - { - if (this.isRepeatSubmit(request)) - { - AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试"); - ServletUtils.renderString(response, JsonUtils.toJsonString(ajaxResult)); - return false; - } - } - return true; - } - else - { - return super.preHandle(request, response, handler); - } - } +public abstract class RepeatSubmitInterceptor implements HandlerInterceptor { - /** - * 验证是否重复提交由子类实现具体的防重复提交的规则 - * - * @param request - * @return - * @throws Exception - */ - public abstract boolean isRepeatSubmit(HttpServletRequest request); + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + if (handler instanceof HandlerMethod) { + HandlerMethod handlerMethod = (HandlerMethod) handler; + Method method = handlerMethod.getMethod(); + RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); + if (annotation != null) { + if (this.isRepeatSubmit(annotation, request)) { + AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试"); + ServletUtils.renderString(response, JsonUtils.toJsonString(ajaxResult)); + return false; + } + } + return true; + } else { + return HandlerInterceptor.super.preHandle(request, response, handler); + } + } + + /** + * 验证是否重复提交由子类实现具体的防重复提交的规则 + */ + public abstract boolean isRepeatSubmit(RepeatSubmit annotation, HttpServletRequest request); } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java index bc0923144..d9b3464e4 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java @@ -1,15 +1,19 @@ package com.ruoyi.framework.interceptor.impl; +import cn.hutool.core.convert.Convert; import cn.hutool.core.io.IoUtil; -import cn.hutool.core.lang.Validator; +import com.ruoyi.common.annotation.RepeatSubmit; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.filter.RepeatedlyRequestWrapper; import com.ruoyi.common.utils.JsonUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.framework.config.properties.RepeatSubmitProperties; +import com.ruoyi.framework.config.properties.TokenProperties; import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; @@ -20,45 +24,34 @@ import java.util.concurrent.TimeUnit; /** * 判断请求url和数据是否和上一次相同, - * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。 + * 如果和上次相同,则是重复提交表单。 * - * @author ruoyi + * @author Lion Li */ @Slf4j +@RequiredArgsConstructor(onConstructor_ = @Autowired) @Component -public class SameUrlDataInterceptor extends RepeatSubmitInterceptor -{ - public final String REPEAT_PARAMS = "repeatParams"; +public class SameUrlDataInterceptor extends RepeatSubmitInterceptor { + public final String REPEAT_PARAMS = "repeatParams"; - public final String REPEAT_TIME = "repeatTime"; + public final String REPEAT_TIME = "repeatTime"; - // 令牌自定义标识 - @Value("${token.header}") - private String header; + private final TokenProperties tokenProperties; + private final RepeatSubmitProperties repeatSubmitProperties; + private final RedisCache redisCache; - @Autowired - private RedisCache redisCache; - /** - * 间隔时间,单位:秒 默认10秒 - * - * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据 - */ - private int intervalTime = 10; - - public void setIntervalTime(int intervalTime) - { - this.intervalTime = intervalTime; - } - - @SuppressWarnings("unchecked") - @Override - public boolean isRepeatSubmit(HttpServletRequest request) - { - String nowParams = ""; - if (request instanceof RepeatedlyRequestWrapper) - { - RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request; + @SuppressWarnings("unchecked") + @Override + public boolean isRepeatSubmit(RepeatSubmit repeatSubmit, HttpServletRequest request) { + // 如果注解不为0 则使用注解数值 + long intervalTime = repeatSubmitProperties.getIntervalTime(); + if (repeatSubmit.intervalTime() > 0) { + intervalTime = repeatSubmit.timeUnit().toMillis(repeatSubmit.intervalTime()); + } + String nowParams = ""; + if (request instanceof RepeatedlyRequestWrapper) { + RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request; try { nowParams = IoUtil.readUtf8(repeatedlyRequest.getInputStream()); } catch (IOException e) { @@ -66,68 +59,57 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor } } - // body参数为空,获取Parameter的数据 - if (Validator.isEmpty(nowParams)) - { - nowParams = JsonUtils.toJsonString(request.getParameterMap()); - } - Map nowDataMap = new HashMap(); - nowDataMap.put(REPEAT_PARAMS, nowParams); - nowDataMap.put(REPEAT_TIME, System.currentTimeMillis()); + // body参数为空,获取Parameter的数据 + if (StringUtils.isEmpty(nowParams)) { + nowParams = JsonUtils.toJsonString(request.getParameterMap()); + } + Map nowDataMap = new HashMap(); + nowDataMap.put(REPEAT_PARAMS, nowParams); + nowDataMap.put(REPEAT_TIME, System.currentTimeMillis()); - // 请求地址(作为存放cache的key值) - String url = request.getRequestURI(); + // 请求地址(作为存放cache的key值) + String url = request.getRequestURI(); - // 唯一值(没有消息头则使用请求地址) - String submitKey = request.getHeader(header); - if (Validator.isEmpty(submitKey)) - { - submitKey = url; - } + // 唯一值(没有消息头则使用请求地址) + String submitKey = request.getHeader(tokenProperties.getHeader()); + if (StringUtils.isEmpty(submitKey)) { + submitKey = url; + } - // 唯一标识(指定key + 消息头) - String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + submitKey; + // 唯一标识(指定key + 消息头) + String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + submitKey; - Object sessionObj = redisCache.getCacheObject(cacheRepeatKey); - if (sessionObj != null) - { - Map sessionMap = (Map) sessionObj; - if (sessionMap.containsKey(url)) - { - Map preDataMap = (Map) sessionMap.get(url); - if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap)) - { - return true; - } - } - } - Map cacheMap = new HashMap(); - cacheMap.put(url, nowDataMap); - redisCache.setCacheObject(cacheRepeatKey, cacheMap, intervalTime, TimeUnit.SECONDS); - return false; - } + Object sessionObj = redisCache.getCacheObject(cacheRepeatKey); + if (sessionObj != null) { + Map sessionMap = (Map) sessionObj; + if (sessionMap.containsKey(url)) { + Map preDataMap = (Map) sessionMap.get(url); + if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, intervalTime)) { + return true; + } + } + } + Map cacheMap = new HashMap(); + cacheMap.put(url, nowDataMap); + redisCache.setCacheObject(cacheRepeatKey, cacheMap, Convert.toInt(intervalTime), TimeUnit.MILLISECONDS); + return false; + } - /** - * 判断参数是否相同 - */ - private boolean compareParams(Map nowMap, Map preMap) - { - String nowParams = (String) nowMap.get(REPEAT_PARAMS); - String preParams = (String) preMap.get(REPEAT_PARAMS); - return nowParams.equals(preParams); - } + /** + * 判断参数是否相同 + */ + private boolean compareParams(Map nowMap, Map preMap) { + String nowParams = (String) nowMap.get(REPEAT_PARAMS); + String preParams = (String) preMap.get(REPEAT_PARAMS); + return nowParams.equals(preParams); + } - /** - * 判断两次间隔时间 - */ - private boolean compareTime(Map nowMap, Map preMap) - { - long time1 = (Long) nowMap.get(REPEAT_TIME); - long time2 = (Long) preMap.get(REPEAT_TIME); - if ((time1 - time2) < (this.intervalTime * 1000)) - { - return true; - } - return false; - } + /** + * 判断两次间隔时间 + */ + private boolean compareTime(Map nowMap, Map preMap, long intervalTime) { + long time1 = (Long) nowMap.get(REPEAT_TIME); + long time2 = (Long) preMap.get(REPEAT_TIME); + return (time1 - time2) < intervalTime; + } } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/jackson/BigNumberSerializer.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/jackson/BigNumberSerializer.java new file mode 100644 index 000000000..1781b94be --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/jackson/BigNumberSerializer.java @@ -0,0 +1,42 @@ +package com.ruoyi.framework.jackson; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; +import com.fasterxml.jackson.databind.ser.std.NumberSerializer; + +import java.io.IOException; + +/** + * 超出 JS 最大最小值 处理 + * + * @author Lion Li + */ +@JacksonStdImpl +public class BigNumberSerializer extends NumberSerializer { + + /** + * 根据 JS Number.MAX_SAFE_INTEGER 与 Number.MIN_SAFE_INTEGER 得来 + */ + private static final long MAX_SAFE_INTEGER = 9007199254740991L; + private static final long MIN_SAFE_INTEGER = -9007199254740991L; + + /** + * 提供实例 + */ + public static final BigNumberSerializer INSTANCE = new BigNumberSerializer(Number.class); + + public BigNumberSerializer(Class rawType) { + super(rawType); + } + + @Override + public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException { + // 超出范围 序列化位字符串 + if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) { + super.serialize(value, gen, provider); + } else { + gen.writeString(value.toString()); + } + } +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/mybatisplus/CreateAndUpdateMetaObjectHandler.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/mybatisplus/CreateAndUpdateMetaObjectHandler.java index 2479293e1..ae36fc3b4 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/mybatisplus/CreateAndUpdateMetaObjectHandler.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/mybatisplus/CreateAndUpdateMetaObjectHandler.java @@ -2,8 +2,10 @@ package com.ruoyi.framework.mybatisplus; import cn.hutool.http.HttpStatus; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; -import com.ruoyi.common.exception.CustomException; +import com.ruoyi.common.core.domain.model.LoginUser; +import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.SecurityUtils; +import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import java.util.Date; @@ -14,6 +16,7 @@ import java.util.Date; * @author Lion Li * @date 2021/4/25 */ +@Slf4j public class CreateAndUpdateMetaObjectHandler implements MetaObjectHandler { @Override @@ -21,36 +24,43 @@ public class CreateAndUpdateMetaObjectHandler implements MetaObjectHandler { try { //根据属性名字设置要填充的值 if (metaObject.hasGetter("createTime")) { - if (metaObject.getValue("createTime") == null) { - this.setFieldValByName("createTime", new Date(), metaObject); - } + this.setFieldValByName("createTime", new Date(), metaObject); } if (metaObject.hasGetter("createBy")) { - if (metaObject.getValue("createBy") == null) { - this.setFieldValByName("createBy", SecurityUtils.getUsername(), metaObject); - } + this.setFieldValByName("createBy", getLoginUsername(), metaObject); } } catch (Exception e) { - throw new CustomException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); + throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); } + updateFill(metaObject); } @Override public void updateFill(MetaObject metaObject) { try { if (metaObject.hasGetter("updateBy")) { - if (metaObject.getValue("updateBy") == null) { - this.setFieldValByName("updateBy", SecurityUtils.getUsername(), metaObject); - } + this.setFieldValByName("updateBy", getLoginUsername(), metaObject); } if (metaObject.hasGetter("updateTime")) { - if (metaObject.getValue("updateTime") == null) { - this.setFieldValByName("updateTime", new Date(), metaObject); - } + this.setFieldValByName("updateTime", new Date(), metaObject); } } catch (Exception e) { - throw new CustomException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); + throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); } } + /** + * 获取登录用户名 + */ + private String getLoginUsername() { + LoginUser loginUser; + try { + loginUser = SecurityUtils.getLoginUser(); + } catch (Exception e) { + log.error("自动注入警告 => 用户未登录"); + return null; + } + return loginUser.getUsername(); + } + } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java index fb2cdaaf4..188e24fdb 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java @@ -1,8 +1,8 @@ package com.ruoyi.framework.security.filter; -import cn.hutool.core.lang.Validator; import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.web.service.TokenService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -19,7 +19,7 @@ import java.io.IOException; /** * token过滤器 验证token有效性 - * + * * @author ruoyi */ @Component @@ -33,7 +33,7 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter throws ServletException, IOException { LoginUser loginUser = tokenService.getLoginUser(request); - if (Validator.isNotNull(loginUser) && Validator.isNull(SecurityUtils.getAuthentication())) + if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication())) { tokenService.verifyToken(loginUser); UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities()); diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java index 1cd8d6043..5757081dd 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java @@ -1,6 +1,6 @@ package com.ruoyi.framework.security.handle; -import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.utils.StringUtils; import cn.hutool.http.HttpStatus; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.utils.JsonUtils; @@ -29,7 +29,7 @@ public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, S throws IOException { int code = HttpStatus.HTTP_UNAUTHORIZED; - String msg = StrUtil.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI()); + String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI()); ServletUtils.renderString(response, JsonUtils.toJsonString(AjaxResult.error(code, msg))); } } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java index 2a12126a6..371a66121 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java @@ -1,12 +1,12 @@ package com.ruoyi.framework.security.handle; -import cn.hutool.core.lang.Validator; import cn.hutool.http.HttpStatus; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.utils.JsonUtils; import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.web.service.AsyncService; import com.ruoyi.framework.web.service.TokenService; import org.springframework.beans.factory.annotation.Autowired; @@ -40,7 +40,7 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler { public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { LoginUser loginUser = tokenService.getLoginUser(request); - if (Validator.isNotNull(loginUser)) { + if (StringUtils.isNotNull(loginUser)) { String userName = loginUser.getUsername(); // 删除用户缓存记录 tokenService.delLoginUser(loginUser.getToken()); diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java index 9614a8d52..9cf69ffb8 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java @@ -1,27 +1,25 @@ package com.ruoyi.framework.web.exception; -import cn.hutool.core.lang.Validator; import cn.hutool.http.HttpStatus; import com.ruoyi.common.core.domain.AjaxResult; -import com.ruoyi.common.exception.BaseException; -import com.ruoyi.common.exception.CustomException; import com.ruoyi.common.exception.DemoModeException; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.authentication.AccountExpiredException; -import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.validation.BindException; +import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; -import org.springframework.web.servlet.NoHandlerFoundException; +import javax.servlet.http.HttpServletRequest; import javax.validation.ConstraintViolationException; /** * 全局异常处理器 - * + * * @author ruoyi */ @RestControllerAdvice @@ -30,59 +28,58 @@ public class GlobalExceptionHandler private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** - * 基础异常 + * 权限校验异常 */ - @ExceptionHandler(BaseException.class) - public AjaxResult baseException(BaseException e) + @ExceptionHandler(AccessDeniedException.class) + public AjaxResult handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',权限校验失败'{}'", requestURI, e.getMessage()); + return AjaxResult.error(HttpStatus.HTTP_FORBIDDEN, "没有权限,请联系管理员授权"); + } + + /** + * 请求方式不支持 + */ + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, + HttpServletRequest request) + { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod()); return AjaxResult.error(e.getMessage()); } /** * 业务异常 */ - @ExceptionHandler(CustomException.class) - public AjaxResult businessException(CustomException e) - { - if (Validator.isNull(e.getCode())) - { - return AjaxResult.error(e.getMessage()); - } - return AjaxResult.error(e.getCode(), e.getMessage()); - } - - @ExceptionHandler(NoHandlerFoundException.class) - public AjaxResult handlerNoFoundException(Exception e) + @ExceptionHandler(ServiceException.class) + public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request) { log.error(e.getMessage(), e); - return AjaxResult.error(HttpStatus.HTTP_NOT_FOUND, "路径不存在,请检查路径是否正确"); + Integer code = e.getCode(); + return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage()); } - @ExceptionHandler(AccessDeniedException.class) - public AjaxResult handleAuthorizationException(AccessDeniedException e) + /** + * 拦截未知的运行时异常 + */ + @ExceptionHandler(RuntimeException.class) + public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request) { - log.error(e.getMessage()); - return AjaxResult.error(HttpStatus.HTTP_FORBIDDEN, "没有权限,请联系管理员授权"); - } - - @ExceptionHandler(AccountExpiredException.class) - public AjaxResult handleAccountExpiredException(AccountExpiredException e) - { - log.error(e.getMessage(), e); - return AjaxResult.error(e.getMessage()); - } - - @ExceptionHandler(UsernameNotFoundException.class) - public AjaxResult handleUsernameNotFoundException(UsernameNotFoundException e) - { - log.error(e.getMessage(), e); + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',发生未知异常.", requestURI, e); return AjaxResult.error(e.getMessage()); } + /** + * 系统异常 + */ @ExceptionHandler(Exception.class) - public AjaxResult handleException(Exception e) + public AjaxResult handleException(Exception e, HttpServletRequest request) { - log.error(e.getMessage(), e); + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',发生系统异常.", requestURI, e); return AjaxResult.error(e.getMessage()); } @@ -90,7 +87,7 @@ public class GlobalExceptionHandler * 自定义验证异常 */ @ExceptionHandler(BindException.class) - public AjaxResult validatedBindException(BindException e) + public AjaxResult handleBindException(BindException e) { log.error(e.getMessage(), e); String message = e.getAllErrors().get(0).getDefaultMessage(); @@ -111,7 +108,7 @@ public class GlobalExceptionHandler * 自定义验证异常 */ @ExceptionHandler(MethodArgumentNotValidException.class) - public Object validExceptionHandler(MethodArgumentNotValidException e) + public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { log.error(e.getMessage(), e); String message = e.getBindingResult().getFieldError().getDefaultMessage(); @@ -122,7 +119,7 @@ public class GlobalExceptionHandler * 演示模式异常 */ @ExceptionHandler(DemoModeException.class) - public AjaxResult demoModeException(DemoModeException e) + public AjaxResult handleDemoModeException(DemoModeException e) { return AjaxResult.error("演示模式,不允许操作"); } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/AsyncService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/AsyncService.java index e64fbc154..3199cdd3d 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/AsyncService.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/AsyncService.java @@ -1,5 +1,6 @@ package com.ruoyi.framework.web.service; +import com.ruoyi.common.utils.StringUtils; import cn.hutool.http.useragent.UserAgent; import cn.hutool.http.useragent.UserAgentUtil; import com.ruoyi.common.constant.Constants; @@ -67,7 +68,7 @@ public class AsyncService { logininfor.setOs(os); logininfor.setMsg(message); // 日志状态 - if (Constants.LOGIN_SUCCESS.equals(status) || Constants.LOGOUT.equals(status)) { + if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) { logininfor.setStatus(Constants.SUCCESS); } else if (Constants.LOGIN_FAIL.equals(status)) { logininfor.setStatus(Constants.FAIL); diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java index 064efa55b..af7fd5726 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java @@ -1,18 +1,18 @@ package com.ruoyi.framework.web.service; -import cn.hutool.core.lang.Validator; -import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.core.domain.entity.SysRole; import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.utils.ServletUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import java.util.Set; /** * RuoYi首创 自定义权限实现,ss取自SpringSecurity首字母 - * + * * @author ruoyi */ @Service("ss") @@ -33,18 +33,18 @@ public class PermissionService /** * 验证用户是否具备某权限 - * + * * @param permission 权限字符串 * @return 用户是否具备某权限 */ public boolean hasPermi(String permission) { - if (Validator.isEmpty(permission)) + if (StringUtils.isEmpty(permission)) { return false; } LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); - if (Validator.isNull(loginUser) || Validator.isEmpty(loginUser.getPermissions())) + if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) { return false; } @@ -70,12 +70,12 @@ public class PermissionService */ public boolean hasAnyPermi(String permissions) { - if (Validator.isEmpty(permissions)) + if (StringUtils.isEmpty(permissions)) { return false; } LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); - if (Validator.isNull(loginUser) || Validator.isEmpty(loginUser.getPermissions())) + if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) { return false; } @@ -92,25 +92,25 @@ public class PermissionService /** * 判断用户是否拥有某个角色 - * + * * @param role 角色字符串 * @return 用户是否具备某角色 */ public boolean hasRole(String role) { - if (Validator.isEmpty(role)) + if (StringUtils.isEmpty(role)) { return false; } LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); - if (Validator.isNull(loginUser) || Validator.isEmpty(loginUser.getUser().getRoles())) + if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles())) { return false; } for (SysRole sysRole : loginUser.getUser().getRoles()) { String roleKey = sysRole.getRoleKey(); - if (SUPER_ADMIN.equals(roleKey) || roleKey.equals(StrUtil.trim(role))) + if (SUPER_ADMIN.equals(roleKey) || roleKey.equals(StringUtils.trim(role))) { return true; } @@ -137,12 +137,12 @@ public class PermissionService */ public boolean hasAnyRoles(String roles) { - if (Validator.isEmpty(roles)) + if (StringUtils.isEmpty(roles)) { return false; } LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); - if (Validator.isNull(loginUser) || Validator.isEmpty(loginUser.getUser().getRoles())) + if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles())) { return false; } @@ -158,13 +158,13 @@ public class PermissionService /** * 判断是否包含权限 - * + * * @param permissions 权限列表 * @param permission 权限字符串 * @return 用户是否具备某权限 */ private boolean hasPermissions(Set permissions, String permission) { - return permissions.contains(ALL_PERMISSION) || permissions.contains(StrUtil.trim(permission)); + return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission)); } } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java index 3aa6d1807..e3e8e71f5 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java @@ -4,7 +4,7 @@ import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.redis.RedisCache; -import com.ruoyi.common.exception.CustomException; +import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.user.CaptchaException; import com.ruoyi.common.exception.user.CaptchaExpireException; import com.ruoyi.common.exception.user.UserPasswordNotMatchException; @@ -85,7 +85,7 @@ public class SysLoginService else { asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage(), request); - throw new CustomException(e.getMessage()); + throw new ServiceException(e.getMessage()); } } asyncService.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), request); diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java new file mode 100644 index 000000000..48d40af8a --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java @@ -0,0 +1,117 @@ +package com.ruoyi.framework.web.service; + +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.constant.UserConstants; +import com.ruoyi.common.core.domain.entity.SysUser; +import com.ruoyi.common.core.domain.model.RegisterBody; +import com.ruoyi.common.core.redis.RedisCache; +import com.ruoyi.common.exception.user.CaptchaException; +import com.ruoyi.common.exception.user.CaptchaExpireException; +import com.ruoyi.common.utils.MessageUtils; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.system.service.ISysConfigService; +import com.ruoyi.system.service.ISysUserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 注册校验方法 + * + * @author ruoyi + */ +@Component +public class SysRegisterService +{ + @Autowired + private ISysUserService userService; + + @Autowired + private ISysConfigService configService; + + @Autowired + private RedisCache redisCache; + + @Autowired + private AsyncService asyncService; + + /** + * 注册 + */ + public String register(RegisterBody registerBody) + { + String msg = "", username = registerBody.getUsername(), password = registerBody.getPassword(); + + boolean captchaOnOff = configService.selectCaptchaOnOff(); + // 验证码开关 + if (captchaOnOff) + { + validateCaptcha(username, registerBody.getCode(), registerBody.getUuid()); + } + + if (StringUtils.isEmpty(username)) + { + msg = "用户名不能为空"; + } + else if (StringUtils.isEmpty(password)) + { + msg = "用户密码不能为空"; + } + else if (username.length() < UserConstants.USERNAME_MIN_LENGTH + || username.length() > UserConstants.USERNAME_MAX_LENGTH) + { + msg = "账户长度必须在2到20个字符之间"; + } + else if (password.length() < UserConstants.PASSWORD_MIN_LENGTH + || password.length() > UserConstants.PASSWORD_MAX_LENGTH) + { + msg = "密码长度必须在5到20个字符之间"; + } + else if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(username))) + { + msg = "保存用户'" + username + "'失败,注册账号已存在"; + } + else + { + SysUser sysUser = new SysUser(); + sysUser.setUserName(username); + sysUser.setNickName(username); + sysUser.setPassword(SecurityUtils.encryptPassword(registerBody.getPassword())); + boolean regFlag = userService.registerUser(sysUser); + if (!regFlag) + { + msg = "注册失败,请联系系统管理人员"; + } + else + { + asyncService.recordLogininfor(username, Constants.REGISTER, + MessageUtils.message("user.register.success"), ServletUtils.getRequest()); + } + } + return msg; + } + + /** + * 校验验证码 + * + * @param username 用户名 + * @param code 验证码 + * @param uuid 唯一标识 + * @return 结果 + */ + public void validateCaptcha(String username, String code, String uuid) + { + String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid; + String captcha = redisCache.getCacheObject(verifyKey); + redisCache.deleteObject(verifyKey); + if (captcha == null) + { + throw new CaptchaExpireException(); + } + if (!code.equalsIgnoreCase(captcha)) + { + throw new CaptchaException(); + } + } +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java index f83457077..3414e372f 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java @@ -1,6 +1,5 @@ package com.ruoyi.framework.web.service; -import cn.hutool.core.lang.Validator; import cn.hutool.core.util.IdUtil; import cn.hutool.http.useragent.UserAgent; import cn.hutool.http.useragent.UserAgentUtil; @@ -8,6 +7,7 @@ import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.ip.AddressUtils; import com.ruoyi.framework.config.properties.TokenProperties; import io.jsonwebtoken.Claims; @@ -49,13 +49,17 @@ public class TokenService { public LoginUser getLoginUser(HttpServletRequest request) { // 获取请求携带的令牌 String token = getToken(request); - if (Validator.isNotEmpty(token)) { - Claims claims = parseToken(token); - // 解析对应的权限以及用户信息 - String uuid = (String) claims.get(Constants.LOGIN_USER_KEY); - String userKey = getTokenKey(uuid); - LoginUser user = redisCache.getCacheObject(userKey); - return user; + if (StringUtils.isNotEmpty(token)) { + try { + Claims claims = parseToken(token); + // 解析对应的权限以及用户信息 + String uuid = (String) claims.get(Constants.LOGIN_USER_KEY); + String userKey = getTokenKey(uuid); + LoginUser user = redisCache.getCacheObject(userKey); + return user; + } catch (Exception e) { + + } } return null; } @@ -64,7 +68,7 @@ public class TokenService { * 设置用户身份信息 */ public void setLoginUser(LoginUser loginUser) { - if (Validator.isNotNull(loginUser) && Validator.isNotEmpty(loginUser.getToken())) { + if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())) { refreshToken(loginUser); } } @@ -73,7 +77,7 @@ public class TokenService { * 删除用户身份信息 */ public void delLoginUser(String token) { - if (Validator.isNotEmpty(token)) { + if (StringUtils.isNotEmpty(token)) { String userKey = getTokenKey(token); redisCache.deleteObject(userKey); } @@ -182,7 +186,7 @@ public class TokenService { */ private String getToken(HttpServletRequest request) { String token = request.getHeader(tokenProperties.getHeader()); - if (Validator.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) { + if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) { token = token.replace(Constants.TOKEN_PREFIX, ""); } return token; diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java index 46b96bad1..c8b1c7b41 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java @@ -1,11 +1,5 @@ package com.ruoyi.framework.web.service; -import cn.hutool.core.lang.Validator; -import com.ruoyi.common.core.domain.entity.SysUser; -import com.ruoyi.common.core.domain.model.LoginUser; -import com.ruoyi.common.enums.UserStatus; -import com.ruoyi.common.exception.BaseException; -import com.ruoyi.system.service.ISysUserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -13,6 +7,12 @@ import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; +import com.ruoyi.common.core.domain.entity.SysUser; +import com.ruoyi.common.core.domain.model.LoginUser; +import com.ruoyi.common.enums.UserStatus; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.system.service.ISysUserService; /** * 用户验证处理 @@ -34,20 +34,20 @@ public class UserDetailsServiceImpl implements UserDetailsService public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { SysUser user = userService.selectUserByUserName(username); - if (Validator.isNull(user)) + if (StringUtils.isNull(user)) { log.info("登录用户:{} 不存在.", username); - throw new UsernameNotFoundException("登录用户:" + username + " 不存在"); + throw new ServiceException("登录用户:" + username + " 不存在"); } else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) { log.info("登录用户:{} 已被删除.", username); - throw new BaseException("对不起,您的账号:" + username + " 已被删除"); + throw new ServiceException("对不起,您的账号:" + username + " 已被删除"); } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { log.info("登录用户:{} 已被停用.", username); - throw new BaseException("对不起,您的账号:" + username + " 已停用"); + throw new ServiceException("对不起,您的账号:" + username + " 已停用"); } return createLoginUser(user); @@ -55,6 +55,6 @@ public class UserDetailsServiceImpl implements UserDetailsService public UserDetails createLoginUser(SysUser user) { - return new LoginUser(user, permissionService.getMenuPermission(user)); + return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user)); } } diff --git a/ruoyi-generator/pom.xml b/ruoyi-generator/pom.xml index 5535bd77f..a712e1fc7 100644 --- a/ruoyi-generator/pom.xml +++ b/ruoyi-generator/pom.xml @@ -5,7 +5,7 @@ ruoyi-vue-plus com.ruoyi - 2.6.0 + 3.0.0 4.0.0 diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java index 5d5c6a483..5d3217cd0 100644 --- a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java @@ -1,6 +1,6 @@ package com.ruoyi.generator.domain; -import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.utils.StringUtils; import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonFormat; import com.ruoyi.common.constant.GenConstants; @@ -204,7 +204,7 @@ public class GenTable implements Serializable { } public static boolean isSub(String tplCategory) { - return tplCategory != null && StrUtil.equals(GenConstants.TPL_SUB, tplCategory); + return tplCategory != null && StringUtils.equals(GenConstants.TPL_SUB, tplCategory); } public boolean isTree() { @@ -212,7 +212,7 @@ public class GenTable implements Serializable { } public static boolean isTree(String tplCategory) { - return tplCategory != null && StrUtil.equals(GenConstants.TPL_TREE, tplCategory); + return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory); } public boolean isCrud() { @@ -220,7 +220,7 @@ public class GenTable implements Serializable { } public static boolean isCrud(String tplCategory) { - return tplCategory != null && StrUtil.equals(GenConstants.TPL_CRUD, tplCategory); + return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory); } public boolean isSuperColumn(String javaField) { @@ -229,9 +229,9 @@ public class GenTable implements Serializable { public static boolean isSuperColumn(String tplCategory, String javaField) { if (isTree(tplCategory)) { - return StrUtil.equalsAnyIgnoreCase(javaField, + return StringUtils.equalsAnyIgnoreCase(javaField, ArrayUtils.addAll(GenConstants.TREE_ENTITY, GenConstants.BASE_ENTITY)); } - return StrUtil.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY); + return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY); } -} \ No newline at end of file +} diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java index 9e03f5d26..92ba7a982 100644 --- a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java @@ -1,6 +1,6 @@ package com.ruoyi.generator.domain; -import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.utils.StringUtils; import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.*; @@ -150,7 +150,7 @@ public class GenTableColumn implements Serializable { private Map params = new HashMap<>(); public String getCapJavaField() { - return StrUtil.upperFirst(javaField); + return StringUtils.uncapitalize(javaField); } public boolean isPk() { @@ -158,7 +158,7 @@ public class GenTableColumn implements Serializable { } public boolean isPk(String isPk) { - return isPk != null && StrUtil.equals("1", isPk); + return isPk != null && StringUtils.equals("1", isPk); } public boolean isIncrement() { @@ -166,7 +166,7 @@ public class GenTableColumn implements Serializable { } public boolean isIncrement(String isIncrement) { - return isIncrement != null && StrUtil.equals("1", isIncrement); + return isIncrement != null && StringUtils.equals("1", isIncrement); } public boolean isRequired() { @@ -174,7 +174,7 @@ public class GenTableColumn implements Serializable { } public boolean isRequired(String isRequired) { - return isRequired != null && StrUtil.equals("1", isRequired); + return isRequired != null && StringUtils.equals("1", isRequired); } public boolean isInsert() { @@ -182,7 +182,7 @@ public class GenTableColumn implements Serializable { } public boolean isInsert(String isInsert) { - return isInsert != null && StrUtil.equals("1", isInsert); + return isInsert != null && StringUtils.equals("1", isInsert); } public boolean isEdit() { @@ -190,7 +190,7 @@ public class GenTableColumn implements Serializable { } public boolean isEdit(String isEdit) { - return isEdit != null && StrUtil.equals("1", isEdit); + return isEdit != null && StringUtils.equals("1", isEdit); } public boolean isList() { @@ -198,7 +198,7 @@ public class GenTableColumn implements Serializable { } public boolean isList(String isList) { - return isList != null && StrUtil.equals("1", isList); + return isList != null && StringUtils.equals("1", isList); } public boolean isQuery() { @@ -206,7 +206,7 @@ public class GenTableColumn implements Serializable { } public boolean isQuery(String isQuery) { - return isQuery != null && StrUtil.equals("1", isQuery); + return isQuery != null && StringUtils.equals("1", isQuery); } public boolean isSuperColumn() { @@ -214,7 +214,7 @@ public class GenTableColumn implements Serializable { } public static boolean isSuperColumn(String javaField) { - return StrUtil.equalsAnyIgnoreCase(javaField, + return StringUtils.equalsAnyIgnoreCase(javaField, // BaseEntity "createBy", "createTime", "updateBy", "updateTime", "remark", // TreeEntity @@ -227,15 +227,15 @@ public class GenTableColumn implements Serializable { public static boolean isUsableColumn(String javaField) { // isSuperColumn()中的名单用于避免生成多余Domain属性,若某些属性在生成页面时需要用到不能忽略,则放在此处白名单 - return StrUtil.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark"); + return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark"); } public String readConverterExp() { - String remarks = StrUtil.subBetween(this.columnComment, "(", ")"); + String remarks = StringUtils.substringBetween(this.columnComment, "(", ")"); StringBuffer sb = new StringBuffer(); - if (StrUtil.isNotEmpty(remarks)) { + if (StringUtils.isNotEmpty(remarks)) { for (String value : remarks.split(" ")) { - if (StrUtil.isNotEmpty(value)) { + if (StringUtils.isNotEmpty(value)) { Object startStr = value.subSequence(0, 1); String endStr = value.substring(1); sb.append("").append(startStr).append("=").append(endStr).append(","); diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java index 86bd128d5..94a9975c6 100644 --- a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java @@ -2,15 +2,14 @@ package com.ruoyi.generator.service; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; -import cn.hutool.core.lang.Validator; -import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.utils.StringUtils; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.GenConstants; import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; import com.ruoyi.common.core.page.TableDataInfo; -import com.ruoyi.common.exception.CustomException; +import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.JsonUtils; import com.ruoyi.common.utils.PageUtils; import com.ruoyi.common.utils.SecurityUtils; @@ -137,15 +136,15 @@ public class GenTableServiceImpl extends ServicePlusImpl() - .set(StrUtil.isBlank(cenTableColumn.getColumnComment()), GenTableColumn::getColumnComment, null) - .set(StrUtil.isBlank(cenTableColumn.getIsPk()), GenTableColumn::getIsPk, null) - .set(StrUtil.isBlank(cenTableColumn.getIsIncrement()), GenTableColumn::getIsIncrement, null) - .set(StrUtil.isBlank(cenTableColumn.getIsInsert()), GenTableColumn::getIsInsert, null) - .set(StrUtil.isBlank(cenTableColumn.getIsEdit()), GenTableColumn::getIsEdit, null) - .set(StrUtil.isBlank(cenTableColumn.getIsList()), GenTableColumn::getIsList, null) - .set(StrUtil.isBlank(cenTableColumn.getIsQuery()), GenTableColumn::getIsQuery, null) - .set(StrUtil.isBlank(cenTableColumn.getIsRequired()), GenTableColumn::getIsRequired, null) - .set(StrUtil.isBlank(cenTableColumn.getDictType()), GenTableColumn::getDictType, "") + .set(StringUtils.isBlank(cenTableColumn.getColumnComment()), GenTableColumn::getColumnComment, null) + .set(StringUtils.isBlank(cenTableColumn.getIsPk()), GenTableColumn::getIsPk, null) + .set(StringUtils.isBlank(cenTableColumn.getIsIncrement()), GenTableColumn::getIsIncrement, null) + .set(StringUtils.isBlank(cenTableColumn.getIsInsert()), GenTableColumn::getIsInsert, null) + .set(StringUtils.isBlank(cenTableColumn.getIsEdit()), GenTableColumn::getIsEdit, null) + .set(StringUtils.isBlank(cenTableColumn.getIsList()), GenTableColumn::getIsList, null) + .set(StringUtils.isBlank(cenTableColumn.getIsQuery()), GenTableColumn::getIsQuery, null) + .set(StringUtils.isBlank(cenTableColumn.getIsRequired()), GenTableColumn::getIsRequired, null) + .set(StringUtils.isBlank(cenTableColumn.getDictType()), GenTableColumn::getDictType, "") .eq(GenTableColumn::getColumnId,cenTableColumn.getColumnId())); } } @@ -189,7 +188,7 @@ public class GenTableServiceImpl extends ServicePlusImpl templates = VelocityUtils.getTemplateList(table.getTplCategory()); for (String template : templates) { - if (!StrUtil.containsAny("sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm", template)) { + if (!StringUtils.containsAny(template, "sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm")) { // 渲染模板 StringWriter sw = new StringWriter(); Template tpl = Velocity.getTemplate(template, Constants.UTF8); tpl.merge(context, sw); - String path = getGenPath(table, template); - FileUtils.writeUtf8String(sw.toString(), path); + try { + String path = getGenPath(table, template); + FileUtils.writeUtf8String(sw.toString(), path); + } catch (Exception e) { + throw new ServiceException("渲染模板失败,表名:" + table.getTableName()); + } } } } @@ -284,8 +287,8 @@ public class GenTableServiceImpl extends ServicePlusImpl tableColumnNames = tableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList()); List dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName); - if (Validator.isEmpty(dbTableColumns)) { - throw new CustomException("同步数据失败,原表结构不存在"); + if (StringUtils.isEmpty(dbTableColumns)) { + throw new ServiceException("同步数据失败,原表结构不存在"); } List dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList()); @@ -364,17 +367,17 @@ public class GenTableServiceImpl extends ServicePlusImpl paramsObj = genTable.getParams(); - if (Validator.isEmpty(paramsObj.get(GenConstants.TREE_CODE))) { - throw new CustomException("树编码字段不能为空"); - } else if (Validator.isEmpty(paramsObj.get(GenConstants.TREE_PARENT_CODE))) { - throw new CustomException("树父编码字段不能为空"); - } else if (Validator.isEmpty(paramsObj.get(GenConstants.TREE_NAME))) { - throw new CustomException("树名称字段不能为空"); + if (StringUtils.isEmpty(paramsObj.get(GenConstants.TREE_CODE))) { + throw new ServiceException("树编码字段不能为空"); + } else if (StringUtils.isEmpty(paramsObj.get(GenConstants.TREE_PARENT_CODE))) { + throw new ServiceException("树父编码字段不能为空"); + } else if (StringUtils.isEmpty(paramsObj.get(GenConstants.TREE_NAME))) { + throw new ServiceException("树名称字段不能为空"); } else if (GenConstants.TPL_SUB.equals(genTable.getTplCategory())) { - if (Validator.isEmpty(genTable.getSubTableName())) { - throw new CustomException("关联子表的表名不能为空"); - } else if (Validator.isEmpty(genTable.getSubTableFkName())) { - throw new CustomException("子表关联的外键名不能为空"); + if (StringUtils.isEmpty(genTable.getSubTableName())) { + throw new ServiceException("关联子表的表名不能为空"); + } else if (StringUtils.isEmpty(genTable.getSubTableFkName())) { + throw new ServiceException("子表关联的外键名不能为空"); } } } @@ -392,7 +395,7 @@ public class GenTableServiceImpl extends ServicePlusImpl paramsObj = JsonUtils.parseMap(genTable.getOptions()); - if (Validator.isNotNull(paramsObj)) { + if (StringUtils.isNotNull(paramsObj)) { String treeCode = Convert.toStr(paramsObj.get(GenConstants.TREE_CODE)); String treeParentCode = Convert.toStr(paramsObj.get(GenConstants.TREE_PARENT_CODE)); String treeName = Convert.toStr(paramsObj.get(GenConstants.TREE_NAME)); @@ -451,7 +454,7 @@ public class GenTableServiceImpl extends ServicePlusImpl 0) { column.setJavaType(GenConstants.TYPE_BIGDECIMAL); @@ -98,33 +98,33 @@ public class GenUtils } // 查询字段类型 - if (StrUtil.endWithIgnoreCase(columnName, "name")) + if (StringUtils.endsWithIgnoreCase(columnName, "name")) { column.setQueryType(GenConstants.QUERY_LIKE); } // 状态字段设置单选框 - if (StrUtil.endWithIgnoreCase(columnName, "status")) + if (StringUtils.endsWithIgnoreCase(columnName, "status")) { column.setHtmlType(GenConstants.HTML_RADIO); } // 类型&性别字段设置下拉框 - else if (StrUtil.endWithIgnoreCase(columnName, "type") - || StrUtil.endWithIgnoreCase(columnName, "sex")) + else if (StringUtils.endsWithIgnoreCase(columnName, "type") + || StringUtils.endsWithIgnoreCase(columnName, "sex")) { column.setHtmlType(GenConstants.HTML_SELECT); } // 图片字段设置图片上传控件 - else if (StrUtil.endWithIgnoreCase(columnName, "image")) + else if (StringUtils.endsWithIgnoreCase(columnName, "image")) { column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD); } // 文件字段设置文件上传控件 - else if (StrUtil.endWithIgnoreCase(columnName, "file")) + else if (StringUtils.endsWithIgnoreCase(columnName, "file")) { column.setHtmlType(GenConstants.HTML_FILE_UPLOAD); } // 内容字段设置富文本控件 - else if (StrUtil.endWithIgnoreCase(columnName, "content")) + else if (StringUtils.endsWithIgnoreCase(columnName, "content")) { column.setHtmlType(GenConstants.HTML_EDITOR); } @@ -152,7 +152,7 @@ public class GenUtils { int lastIndex = packageName.lastIndexOf("."); int nameLength = packageName.length(); - String moduleName = StrUtil.sub(packageName, lastIndex + 1, nameLength); + String moduleName = StringUtils.substring(packageName, lastIndex + 1, nameLength); return moduleName; } @@ -166,7 +166,7 @@ public class GenUtils { int lastIndex = tableName.lastIndexOf("_"); int nameLength = tableName.length(); - String businessName = StrUtil.sub(tableName, lastIndex + 1, nameLength); + String businessName = StringUtils.substring(tableName, lastIndex + 1, nameLength); return businessName; } @@ -180,12 +180,12 @@ public class GenUtils { boolean autoRemovePre = GenConfig.getAutoRemovePre(); String tablePrefix = GenConfig.getTablePrefix(); - if (autoRemovePre && StrUtil.isNotEmpty(tablePrefix)) + if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix)) { - String[] searchList = StrUtil.splitToArray(tablePrefix, ","); + String[] searchList = StringUtils.split(tablePrefix, ","); tableName = replaceFirst(tableName, searchList); } - return StrUtil.upperFirst(StrUtil.toCamelCase(tableName)); + return StringUtils.convertToCamelCase(tableName); } /** @@ -228,9 +228,9 @@ public class GenUtils */ public static String getDbType(String columnType) { - if (StrUtil.indexOf(columnType, '(') > 0) + if (StringUtils.indexOf(columnType, '(') > 0) { - return StrUtil.subBefore(columnType, "(",false); + return StringUtils.substringBefore(columnType, "("); } else { @@ -246,9 +246,9 @@ public class GenUtils */ public static Integer getColumnLength(String columnType) { - if (StrUtil.indexOf(columnType, '(') > 0) + if (StringUtils.indexOf(columnType, '(') > 0) { - String length = StrUtil.subBetween(columnType, "(", ")"); + String length = StringUtils.substringBetween(columnType, "(", ")"); return Integer.valueOf(length); } else diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java index 641cf1d1e..098a91892 100644 --- a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java @@ -1,11 +1,10 @@ package com.ruoyi.generator.util; import cn.hutool.core.convert.Convert; -import cn.hutool.core.lang.Validator; -import cn.hutool.core.util.StrUtil; import com.ruoyi.common.constant.GenConstants; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.JsonUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.generator.domain.GenTable; import com.ruoyi.generator.domain.GenTableColumn; import org.apache.velocity.VelocityContext; @@ -47,11 +46,11 @@ public class VelocityUtils VelocityContext velocityContext = new VelocityContext(); velocityContext.put("tplCategory", genTable.getTplCategory()); velocityContext.put("tableName", genTable.getTableName()); - velocityContext.put("functionName", StrUtil.isNotEmpty(functionName) ? functionName : "【请填写功能名称】"); + velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】"); velocityContext.put("ClassName", genTable.getClassName()); - velocityContext.put("className", StrUtil.lowerFirst(genTable.getClassName())); + velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName())); velocityContext.put("moduleName", genTable.getModuleName()); - velocityContext.put("BusinessName", StrUtil.upperFirst(genTable.getBusinessName())); + velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName())); velocityContext.put("businessName", genTable.getBusinessName()); velocityContext.put("basePackage", getPackagePrefix(packageName)); velocityContext.put("packageName", packageName); @@ -110,15 +109,15 @@ public class VelocityUtils String subTableName = genTable.getSubTableName(); String subTableFkName = genTable.getSubTableFkName(); String subClassName = genTable.getSubTable().getClassName(); - String subTableFkClassName = StrUtil.toCamelCase(subTableFkName); + String subTableFkClassName = StringUtils.convertToCamelCase(subTableFkName); context.put("subTable", subTable); context.put("subTableName", subTableName); context.put("subTableFkName", subTableFkName); context.put("subTableFkClassName", subTableFkClassName); - context.put("subTableFkclassName", StrUtil.lowerFirst(subTableFkClassName)); + context.put("subTableFkclassName", StringUtils.uncapitalize(subTableFkClassName)); context.put("subClassName", subClassName); - context.put("subclassName", StrUtil.lowerFirst(subClassName)); + context.put("subclassName", StringUtils.uncapitalize(subClassName)); context.put("subImportList", getImportList(genTable.getSubTable())); } @@ -172,45 +171,45 @@ public class VelocityUtils // 业务名称 String businessName = genTable.getBusinessName(); - String javaPath = PROJECT_PATH + "/" + StrUtil.replace(packageName, ".", "/"); + String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/"); String mybatisPath = MYBATIS_PATH + "/" + moduleName; String vuePath = "vue"; if (template.contains("domain.java.vm")) { - fileName = StrUtil.format("{}/domain/{}.java", javaPath, className); + fileName = StringUtils.format("{}/domain/{}.java", javaPath, className); } if (template.contains("vo.java.vm")) { - fileName = StrUtil.format("{}/domain/vo/{}Vo.java", javaPath, className); + fileName = StringUtils.format("{}/domain/vo/{}Vo.java", javaPath, className); } if (template.contains("bo.java.vm")) { - fileName = StrUtil.format("{}/domain/bo/{}Bo.java", javaPath, className); + fileName = StringUtils.format("{}/domain/bo/{}Bo.java", javaPath, className); } - if (template.contains("sub-domain.java.vm") && StrUtil.equals(GenConstants.TPL_SUB, genTable.getTplCategory())) + if (template.contains("sub-domain.java.vm") && StringUtils.equals(GenConstants.TPL_SUB, genTable.getTplCategory())) { - fileName = StrUtil.format("{}/domain/{}.java", javaPath, genTable.getSubTable().getClassName()); + fileName = StringUtils.format("{}/domain/{}.java", javaPath, genTable.getSubTable().getClassName()); } else if (template.contains("mapper.java.vm")) { - fileName = StrUtil.format("{}/mapper/{}Mapper.java", javaPath, className); + fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className); } else if (template.contains("service.java.vm")) { - fileName = StrUtil.format("{}/service/I{}Service.java", javaPath, className); + fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className); } else if (template.contains("serviceImpl.java.vm")) { - fileName = StrUtil.format("{}/service/impl/{}ServiceImpl.java", javaPath, className); + fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className); } else if (template.contains("controller.java.vm")) { - fileName = StrUtil.format("{}/controller/{}Controller.java", javaPath, className); + fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className); } else if (template.contains("mapper.xml.vm")) { - fileName = StrUtil.format("{}/{}Mapper.xml", mybatisPath, className); + fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className); } else if (template.contains("sql.vm")) { @@ -218,15 +217,15 @@ public class VelocityUtils } else if (template.contains("api.js.vm")) { - fileName = StrUtil.format("{}/api/{}/{}.js", vuePath, moduleName, businessName); + fileName = StringUtils.format("{}/api/{}/{}.js", vuePath, moduleName, businessName); } else if (template.contains("index.vue.vm")) { - fileName = StrUtil.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName); + fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName); } else if (template.contains("index-tree.vue.vm")) { - fileName = StrUtil.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName); + fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName); } return fileName; } @@ -240,7 +239,7 @@ public class VelocityUtils public static String getPackagePrefix(String packageName) { int lastIndex = packageName.lastIndexOf("."); - String basePackage = StrUtil.sub(packageName, 0, lastIndex); + String basePackage = StringUtils.substring(packageName, 0, lastIndex); return basePackage; } @@ -255,7 +254,7 @@ public class VelocityUtils List columns = genTable.getColumns(); GenTable subGenTable = genTable.getSubTable(); HashSet importList = new HashSet(); - if (Validator.isNotNull(subGenTable)) + if (StringUtils.isNotNull(subGenTable)) { importList.add("java.util.List"); } @@ -283,7 +282,7 @@ public class VelocityUtils */ public static String getPermissionPrefix(String moduleName, String businessName) { - return StrUtil.format("{}:{}", moduleName, businessName); + return StringUtils.format("{}:{}", moduleName, businessName); } /** @@ -294,7 +293,8 @@ public class VelocityUtils */ public static String getParentMenuId(Map paramsObj) { - if (Validator.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID)) + if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID) + && StringUtils.isNotEmpty(Convert.toStr(paramsObj.get(GenConstants.PARENT_MENU_ID)))) { return Convert.toStr(paramsObj.get(GenConstants.PARENT_MENU_ID)); } @@ -309,11 +309,11 @@ public class VelocityUtils */ public static String getTreecode(Map paramsObj) { - if (Validator.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_CODE)) + if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_CODE)) { - return StrUtil.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_CODE))); + return StringUtils.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_CODE))); } - return StrUtil.EMPTY; + return StringUtils.EMPTY; } /** @@ -324,11 +324,11 @@ public class VelocityUtils */ public static String getTreeParentCode(Map paramsObj) { - if (Validator.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) + if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) { - return StrUtil.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_PARENT_CODE))); + return StringUtils.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_PARENT_CODE))); } - return StrUtil.EMPTY; + return StringUtils.EMPTY; } /** @@ -339,11 +339,11 @@ public class VelocityUtils */ public static String getTreeName(Map paramsObj) { - if (Validator.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_NAME)) + if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_NAME)) { - return StrUtil.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_NAME))); + return StringUtils.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_NAME))); } - return StrUtil.EMPTY; + return StringUtils.EMPTY; } /** diff --git a/ruoyi-generator/src/main/resources/vm/java/bo.java.vm b/ruoyi-generator/src/main/resources/vm/java/bo.java.vm index 40174d5c0..8831d0c2c 100644 --- a/ruoyi-generator/src/main/resources/vm/java/bo.java.vm +++ b/ruoyi-generator/src/main/resources/vm/java/bo.java.vm @@ -41,7 +41,6 @@ public class ${ClassName}Bo extends ${Entity} { /** * $column.columnComment */ - @ApiModelProperty("$column.columnComment") #if($column.isInsert && $column.isEdit) #set($Group="AddGroup.class, EditGroup.class") #elseif($column.isInsert) @@ -50,11 +49,14 @@ public class ${ClassName}Bo extends ${Entity} { #set($Group="EditGroup.class") #end #if($column.isRequired == 1) + @ApiModelProperty(value = "$column.columnComment", required = true) #if($column.javaType == 'String') @NotBlank(message = "$column.columnComment不能为空", groups = { $Group }) #else @NotNull(message = "$column.columnComment不能为空", groups = { $Group }) #end +#else + @ApiModelProperty(value = "$column.columnComment") #end private $column.javaType $column.javaField; diff --git a/ruoyi-generator/src/main/resources/vm/java/controller.java.vm b/ruoyi-generator/src/main/resources/vm/java/controller.java.vm index ba29e2014..7aad26721 100644 --- a/ruoyi-generator/src/main/resources/vm/java/controller.java.vm +++ b/ruoyi-generator/src/main/resources/vm/java/controller.java.vm @@ -2,8 +2,10 @@ package ${packageName}.controller; import java.util.List; import java.util.Arrays; +import java.util.concurrent.TimeUnit; import lombok.RequiredArgsConstructor; +import javax.servlet.http.HttpServletResponse; import javax.validation.constraints.*; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.beans.factory.annotation.Autowired; @@ -16,10 +18,10 @@ import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.validate.AddGroup; import com.ruoyi.common.core.validate.EditGroup; import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.poi.ExcelUtil; import ${packageName}.domain.vo.${ClassName}Vo; import ${packageName}.domain.bo.${ClassName}Bo; import ${packageName}.service.I${ClassName}Service; -import com.ruoyi.common.utils.poi.ExcelUtil; #if($table.crud || $table.sub) import com.ruoyi.common.core.page.TableDataInfo; #elseif($table.tree) @@ -66,10 +68,9 @@ public class ${ClassName}Controller extends BaseController { @PreAuthorize("@ss.hasPermi('${permissionPrefix}:export')") @Log(title = "${functionName}", businessType = BusinessType.EXPORT) @GetMapping("/export") - public AjaxResult<${ClassName}Vo> export(@Validated ${ClassName}Bo bo) { + public void export(@Validated ${ClassName}Bo bo, HttpServletResponse response) { List<${ClassName}Vo> list = i${ClassName}Service.queryList(bo); - ExcelUtil<${ClassName}Vo> util = new ExcelUtil<${ClassName}Vo>(${ClassName}Vo.class); - return util.exportExcel(list, "${functionName}"); + ExcelUtil.exportExcel(list, "${functionName}", ${ClassName}Vo.class, response); } /** @@ -89,7 +90,7 @@ public class ${ClassName}Controller extends BaseController { @ApiOperation("新增${functionName}") @PreAuthorize("@ss.hasPermi('${permissionPrefix}:add')") @Log(title = "${functionName}", businessType = BusinessType.INSERT) - @RepeatSubmit + @RepeatSubmit() @PostMapping() public AjaxResult add(@Validated(AddGroup.class) @RequestBody ${ClassName}Bo bo) { return toAjax(i${ClassName}Service.insertByBo(bo) ? 1 : 0); @@ -101,7 +102,7 @@ public class ${ClassName}Controller extends BaseController { @ApiOperation("修改${functionName}") @PreAuthorize("@ss.hasPermi('${permissionPrefix}:edit')") @Log(title = "${functionName}", businessType = BusinessType.UPDATE) - @RepeatSubmit + @RepeatSubmit() @PutMapping() public AjaxResult edit(@Validated(EditGroup.class) @RequestBody ${ClassName}Bo bo) { return toAjax(i${ClassName}Service.updateByBo(bo) ? 1 : 0); diff --git a/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm b/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm index ec3cac60d..32a9ac018 100644 --- a/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm +++ b/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm @@ -1,7 +1,7 @@ package ${packageName}.service.impl; import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.utils.StringUtils; #if($table.crud || $table.sub) import com.ruoyi.common.utils.PageUtils; import com.ruoyi.common.core.page.PagePlus; @@ -61,7 +61,7 @@ public class ${ClassName}ServiceImpl extends ServicePlusImpl<${ClassName}Mapper, #set($mpMethod=$column.queryType.toLowerCase()) #if($queryType != 'BETWEEN') #if($javaType == 'String') -#set($condition='StrUtil.isNotBlank(bo.get'+$AttrName+'())') +#set($condition='StringUtils.isNotBlank(bo.get'+$AttrName+'())') #else #set($condition='bo.get'+$AttrName+'() != null') #end diff --git a/ruoyi-generator/src/main/resources/vm/java/vo.java.vm b/ruoyi-generator/src/main/resources/vm/java/vo.java.vm index f14d914c9..e97cd2467 100644 --- a/ruoyi-generator/src/main/resources/vm/java/vo.java.vm +++ b/ruoyi-generator/src/main/resources/vm/java/vo.java.vm @@ -1,9 +1,12 @@ package ${packageName}.domain.vo; -import com.ruoyi.common.annotation.Excel; #foreach ($import in $importList) import ${import}; #end +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.annotation.ExcelDictFormat; +import com.ruoyi.common.convert.ExcelDictConvert; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -19,6 +22,7 @@ import java.util.Date; */ @Data @ApiModel("${functionName}视图对象") +@ExcelIgnoreUnannotated public class ${ClassName}Vo { private static final long serialVersionUID = 1L; @@ -40,12 +44,14 @@ public class ${ClassName}Vo { #else #set($comment=$column.columnComment) #end -#if($parentheseIndex != -1) - @Excel(name = "${comment}" , readConverterExp = "$column.readConverterExp()") -#elseif($column.javaType == 'Date') - @Excel(name = "${comment}" , width = 30, dateFormat = "yyyy-MM-dd") +#if(${column.dictType} && ${column.dictType} != '') + @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "${column.dictType}") +#elseif($parentheseIndex != -1) + @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "$column.readConverterExp()") #else - @Excel(name = "${comment}") + @ExcelProperty(value = "${comment}") #end @ApiModelProperty("$column.columnComment") private $column.javaType $column.javaField; diff --git a/ruoyi-generator/src/main/resources/vm/js/api.js.vm b/ruoyi-generator/src/main/resources/vm/js/api.js.vm index 296d41aed..9295524a4 100644 --- a/ruoyi-generator/src/main/resources/vm/js/api.js.vm +++ b/ruoyi-generator/src/main/resources/vm/js/api.js.vm @@ -42,12 +42,3 @@ export function del${BusinessName}(${pkColumn.javaField}) { method: 'delete' }) } - -// 导出${functionName} -export function export${BusinessName}(query) { - return request({ - url: '/${moduleName}/${businessName}/export', - method: 'get', - params: query - }) -} \ No newline at end of file diff --git a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm index 1ad93af6c..ec2f96d4a 100644 --- a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm +++ b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm @@ -253,7 +253,7 @@ \ No newline at end of file + diff --git a/ruoyi-ui/src/views/monitor/logininfor/index.vue b/ruoyi-ui/src/views/monitor/logininfor/index.vue index 07937b460..5d6c05193 100644 --- a/ruoyi-ui/src/views/monitor/logininfor/index.vue +++ b/ruoyi-ui/src/views/monitor/logininfor/index.vue @@ -119,7 +119,8 @@ + + diff --git a/ruoyi-ui/src/views/system/config/index.vue b/ruoyi-ui/src/views/system/config/index.vue index 25086a9fe..69d85640f 100644 --- a/ruoyi-ui/src/views/system/config/index.vue +++ b/ruoyi-ui/src/views/system/config/index.vue @@ -181,7 +181,8 @@ diff --git a/ruoyi-ui/src/views/system/oss/index.vue b/ruoyi-ui/src/views/system/oss/index.vue index 1171cc9c6..2bbbba060 100644 --- a/ruoyi-ui/src/views/system/oss/index.vue +++ b/ruoyi-ui/src/views/system/oss/index.vue @@ -96,7 +96,25 @@ v-hasPermi="['system:oss:remove']" >删除 - + + 预览开关 : {{previewListResource ? "禁用" : "启用"}} + + + 配置管理 + @@ -109,12 +127,12 @@ @@ -169,10 +187,8 @@