diff --git a/README.md b/README.md
index a414f9d39..c91056066 100644
--- a/README.md
+++ b/README.md
@@ -4,16 +4,19 @@
[](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/blob/master/LICENSE)
[](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
-[](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus)
+[](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus)
[]()
-[]()
+[]()
[]()
+[]()
RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 `分布式集群` 场景升级(不兼容原框架)
| 功能介绍 | 使用技术 | 文档地址 | 特性注意事项 |
|---|---|---|---|
| 当前框架 | RuoYi-Vue-Plus | [RuoYi-Vue-Plus文档](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages) | 重写RuoYi-Vue全方位升级(不兼容原框架) |
+| satoken分支 | RuoYi-Vue-Plus-satoken | [satoken分支地址](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/satoken/) | 使用satoken重构权限鉴权(仅供学习不推荐上生产) |
+| 单体分支 | RuoYi-Vue-Plus-fast | [fast分支地址](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/fast/) | 单体应用结构 |
| 原框架 | RuoYi-Vue | [RuoYi-Vue官网](http://ruoyi.vip/) | 定期同步需要的功能 |
| 前端开发框架 | Vue、Element UI | [Element UI官网](https://element.eleme.cn/#/zh-CN) | |
| 后端开发框架 | SpringBoot | [SpringBoot官网](https://spring.io/projects/spring-boot/#learn) | |
@@ -24,10 +27,12 @@ RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 `分布式集群` 场景升级(不兼
| 数据库框架 | Mybatis-Plus | [Mybatis-Plus文档](https://baomidou.com/guide/) | 快速 CRUD 增加开发效率 |
| 数据库框架 | p6spy | [p6spy官网](https://p6spy.readthedocs.io/) | 更强劲的 SQL 分析 |
| 多数据源框架 | dynamic-datasource | [dynamic-ds文档](https://www.kancloud.cn/tracy5546/dynamic-datasource/content) | 支持主从与多种类数据库异构 |
-| Redis客户端 | Redisson | [Redisson文档](https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95) | 性能强劲、API丰富 |
| 序列化框架 | Jackson | [Jackson官网](https://github.com/FasterXML/jackson) | 统一使用 jackson 高效可靠 |
| 网络框架 | Feign、OkHttp3 | [Feign官网](https://github.com/OpenFeign/feign) | 接口化管理 HTTP 请求 |
+| Redis客户端 | Redisson | [Redisson文档](https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95) | 支持单机、集群配置 |
+| 分布式限流 | Redisson | [Redisson文档](https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95) | 全局、请求IP、集群ID 多种限流 |
| 分布式锁 | Lock4j | [Lock4j官网](https://gitee.com/baomidou/lock4j) | 注解锁、工具锁 多种多样 |
+| 分布式幂等 | Lock4j | [Lock4j文档](https://gitee.com/baomidou/lock4j) | 基于分布式锁实现 |
| 文件存储 | Minio | [Minio文档](https://docs.min.io/) | 本地存储 |
| 文件存储 | 七牛、阿里、腾讯 | [OSS使用文档](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages?sort_id=4359146&doc_id=1469725) | 云存储 |
| 监控框架 | SpringBoot-Admin | [SpringBoot-Admin文档](https://codecentric.github.io/spring-boot-admin/current/) | 全方位服务监控 |
@@ -67,6 +72,7 @@ RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 `分布式集群` 场景升级(不兼
* 同步升级 RuoYi-Vue
* GitHub 地址 [RuoYi-Vue-Plus-github](https://github.com/JavaLionLi/RuoYi-Vue-Plus)
* 单模块 fast 分支 [RuoYi-Vue-Plus-fast](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/fast/)
+* satoken 分支 [RuoYi-Vue-Plus-satoken](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/satoken/)
* 用户扩展项目 [扩展项目列表](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages?sort_id=4478302&doc_id=1469725)
## 加群与捐献
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
index 1535f3d6f..e676d5607 100644
--- a/docker/docker-compose.yml
+++ b/docker/docker-compose.yml
@@ -103,7 +103,7 @@ services:
ipv4_address: 172.30.0.54
ruoyi-server1:
- image: "ruoyi/ruoyi-server:3.1.0"
+ image: "ruoyi/ruoyi-server:3.2.0"
container_name: ruoyi-server1
environment:
# 时区上海
@@ -118,7 +118,7 @@ services:
ipv4_address: 172.30.0.60
ruoyi-server2:
- image: "ruoyi/ruoyi-server:3.1.0"
+ image: "ruoyi/ruoyi-server:3.2.0"
container_name: ruoyi-server2
environment:
# 时区上海
@@ -133,7 +133,7 @@ services:
ipv4_address: 172.30.0.61
ruoyi-monitor-admin:
- image: "ruoyi/ruoyi-monitor-admin:3.1.0"
+ image: "ruoyi/ruoyi-monitor-admin:3.2.0"
container_name: ruoyi-monitor-admin
environment:
# 时区上海
diff --git a/pom.xml b/pom.xml
index eba5a164c..6ccbdbeb3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,40 +6,44 @@
com.ruoyi
ruoyi-vue-plus
- 3.1.0
+ 3.2.0
RuoYi-Vue-Plus
https://gitee.com/JavaLionLi/RuoYi-Vue-Plus
RuoYi-Vue-Plus后台管理系统
- 3.1.0
- 2.5.4
+ 3.2.0
+ 2.5.5
UTF-8
UTF-8
1.8
3.2.0
1.2.6
3.0.3
+ 1.5.22
4.1.2
- 2.2.10
+ 2.2.11
1.7
0.9.1
- 3.4.3.3
+ 3.4.3.4
3.9.1
- 5.7.11
+ 5.7.13
3.0.3
11.6
4.9.1
2.5.1
- 3.16.2
+ 3.16.3
2.2.1
3.4.1
+
+ 3.0.1
+
7.8.0
3.13.1
- 5.6.51
+ 5.6.55
8.3.0
@@ -48,7 +52,7 @@
ruoyi
1.2.2
-
+
@@ -73,6 +77,18 @@
com.github.xiaoymin
knife4j-spring-boot-starter
${knife4j.version}
+
+
+ swagger-annotations
+ io.swagger
+
+
+
+
+
+ io.swagger
+ swagger-annotations
+ ${swagger-annotations.version}
@@ -86,6 +102,16 @@
com.alibaba
easyexcel
${easyexcel.version}
+
+
+ org.apache.poi
+ poi
+
+
+ org.apache.poi
+ poi-ooxml-schemas
+
+
@@ -136,6 +162,12 @@
org.springframework.cloud
spring-cloud-starter-openfeign
${feign.version}
+
+
+ feign-core
+ io.github.openfeign
+
+
@@ -239,7 +271,12 @@
-
+
+
+ com.sun.xml.bind
+ jaxb-impl
+ ${jaxb.version}
+
@@ -318,48 +355,9 @@
prod
warn
- health,info
+ health, info, logfile
-
-
-
- jdk8
-
- true
- 1.8
-
-
- 1.8
-
-
-
- jdk11
-
- 11
-
-
- 11
- 3.0.1
-
-
-
-
-
- com.sun.xml.bind
- jaxb-impl
- ${jaxb.version}
-
-
-
-
-
-
- com.sun.xml.bind
- jaxb-impl
-
-
-
-
+
\ No newline at end of file
diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml
index b455a5e47..12327e305 100644
--- a/ruoyi-admin/pom.xml
+++ b/ruoyi-admin/pom.xml
@@ -5,7 +5,7 @@
ruoyi-vue-plus
com.ruoyi
- 3.1.0
+ 3.2.0
4.0.0
jar
@@ -36,6 +36,11 @@
ruoyi-framework
+
+ com.ruoyi
+ ruoyi-system
+
+
com.ruoyi
@@ -82,7 +87,7 @@
org.apache.maven.plugins
maven-war-plugin
- 3.1.0
+ 3.2.0
false
${project.artifactId}
@@ -110,4 +115,4 @@
-
+
\ No newline at end of file
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 76141b9b7..287d4c587 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,8 +6,8 @@ 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.utils.SecurityUtils;
-import com.ruoyi.framework.web.service.SysLoginService;
-import com.ruoyi.framework.web.service.SysPermissionService;
+import com.ruoyi.system.service.SysLoginService;
+import com.ruoyi.system.service.SysPermissionService;
import com.ruoyi.system.service.ISysMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
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
index 55f25dfa7..e72bd1f18 100644
--- 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
@@ -25,14 +25,14 @@ import javax.validation.constraints.NotNull;
import java.util.Arrays;
/**
- * 云存储配置Controller
+ * 对象存储配置Controller
*
* @author Lion Li
* @author 孤舟烟雨
* @date 2021-08-13
*/
@Validated
-@Api(value = "云存储配置控制器", tags = {"云存储配置管理"})
+@Api(value = "对象存储配置控制器", tags = {"对象存储配置管理"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/system/oss/config")
@@ -41,9 +41,9 @@ public class SysOssConfigController extends BaseController {
private final ISysOssConfigService iSysOssConfigService;
/**
- * 查询云存储配置列表
+ * 查询对象存储配置列表
*/
- @ApiOperation("查询云存储配置列表")
+ @ApiOperation("查询对象存储配置列表")
@PreAuthorize("@ss.hasPermi('system:oss:list')")
@GetMapping("/list")
public TableDataInfo list(@Validated(QueryGroup.class) SysOssConfigBo bo) {
@@ -51,9 +51,9 @@ public class SysOssConfigController extends BaseController {
}
/**
- * 获取云存储配置详细信息
+ * 获取对象存储配置详细信息
*/
- @ApiOperation("获取云存储配置详细信息")
+ @ApiOperation("获取对象存储配置详细信息")
@PreAuthorize("@ss.hasPermi('system:oss:query')")
@GetMapping("/{ossConfigId}")
public AjaxResult getInfo(@NotNull(message = "主键不能为空")
@@ -62,11 +62,11 @@ public class SysOssConfigController extends BaseController {
}
/**
- * 新增云存储配置
+ * 新增对象存储配置
*/
- @ApiOperation("新增云存储配置")
+ @ApiOperation("新增对象存储配置")
@PreAuthorize("@ss.hasPermi('system:oss:add')")
- @Log(title = "云存储配置", businessType = BusinessType.INSERT)
+ @Log(title = "对象存储配置", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public AjaxResult add(@Validated(AddGroup.class) @RequestBody SysOssConfigBo bo) {
@@ -74,11 +74,11 @@ public class SysOssConfigController extends BaseController {
}
/**
- * 修改云存储配置
+ * 修改对象存储配置
*/
- @ApiOperation("修改云存储配置")
+ @ApiOperation("修改对象存储配置")
@PreAuthorize("@ss.hasPermi('system:oss:edit')")
- @Log(title = "云存储配置", businessType = BusinessType.UPDATE)
+ @Log(title = "对象存储配置", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public AjaxResult edit(@Validated(EditGroup.class) @RequestBody SysOssConfigBo bo) {
@@ -86,11 +86,11 @@ public class SysOssConfigController extends BaseController {
}
/**
- * 删除云存储配置
+ * 删除对象存储配置
*/
- @ApiOperation("删除云存储配置")
+ @ApiOperation("删除对象存储配置")
@PreAuthorize("@ss.hasPermi('system:oss:remove')")
- @Log(title = "云存储配置", businessType = BusinessType.DELETE)
+ @Log(title = "对象存储配置", businessType = BusinessType.DELETE)
@DeleteMapping("/{ossConfigIds}")
public AjaxResult remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ossConfigIds) {
@@ -101,7 +101,7 @@ public class SysOssConfigController extends BaseController {
* 状态修改
*/
@PreAuthorize("@ss.hasPermi('system:oss:edit')")
- @Log(title = "云存储状态修改", businessType = BusinessType.UPDATE)
+ @Log(title = "对象存储状态修改", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus")
public AjaxResult changeStatus(@RequestBody SysOssConfigBo bo) {
return toAjax(iSysOssConfigService.updateOssConfigStatus(bo));
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java
index ff379910a..3c043534d 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java
@@ -3,6 +3,7 @@ package com.ruoyi.web.controller.system;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.http.HttpException;
import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.annotation.Log;
@@ -49,7 +50,7 @@ import java.util.Map;
* @author Lion Li
*/
@Validated
-@Api(value = "OSS云存储控制器", tags = {"OSS云存储管理"})
+@Api(value = "OSS对象存储控制器", tags = {"OSS对象存储管理"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/system/oss")
@@ -59,9 +60,9 @@ public class SysOssController extends BaseController {
private final ISysConfigService iSysConfigService;
/**
- * 查询OSS云存储列表
+ * 查询OSS对象存储列表
*/
- @ApiOperation("查询OSS云存储列表")
+ @ApiOperation("查询OSS对象存储列表")
@PreAuthorize("@ss.hasPermi('system:oss:list')")
@GetMapping("/list")
public TableDataInfo list(@Validated(QueryGroup.class) SysOssBo bo) {
@@ -69,14 +70,14 @@ public class SysOssController extends BaseController {
}
/**
- * 上传OSS云存储
+ * 上传OSS对象存储
*/
- @ApiOperation("上传OSS云存储")
+ @ApiOperation("上传OSS对象存储")
@ApiImplicitParams({
@ApiImplicitParam(name = "file", value = "文件", dataType = "java.io.File", required = true),
})
@PreAuthorize("@ss.hasPermi('system:oss:upload')")
- @Log(title = "OSS云存储", businessType = BusinessType.INSERT)
+ @Log(title = "OSS对象存储", businessType = BusinessType.INSERT)
@RepeatSubmit
@PostMapping("/upload")
public AjaxResult
+
+ io.swagger
+ swagger-annotations
+
+
org.springframework.boot
spring-boot-starter-actuator
@@ -147,22 +152,10 @@
redisson-spring-boot-starter
-
-
- com.baomidou
- dynamic-datasource-spring-boot-starter
-
-
-
- p6spy
- p6spy
-
-
com.baomidou
lock4j-redisson-spring-boot-starter
-
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java
index eb05dc7ce..ca02c6c4a 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java
@@ -38,4 +38,9 @@ public @interface Log
* 是否保存请求的参数
*/
public boolean isSaveRequestData() default true;
+
+ /**
+ * 是否保存响应的参数
+ */
+ public boolean isSaveResponseData() default true;
}
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 c2bbee476..512f4bf52 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
@@ -20,10 +20,15 @@ import java.util.concurrent.TimeUnit;
public @interface RepeatSubmit {
/**
- * 默认使用全局配置
+ * 间隔时间(ms),小于此时间视为重复提交
*/
- int intervalTime() default 0;
+ int interval() default 5000;
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
+ /**
+ * 提示消息
+ */
+ String message() default "不允许重复提交,请稍后再试";
+
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
index 1fa328e45..072fb403c 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
@@ -44,16 +44,21 @@ public class GenConstants
public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer",
"bit", "bigint", "float", "double", "decimal" };
+ /** 页面不需要添加字段 */
+ public static final String[] COLUMNNAME_NOT_ADD = { "create_by", "create_time", "del_flag", "update_by",
+ "update_time", "version" };
+
/** 页面不需要编辑字段 */
- public static final String[] COLUMNNAME_NOT_EDIT = { "id", "create_by", "create_time", "del_flag" };
+ public static final String[] COLUMNNAME_NOT_EDIT = { "create_by", "create_time", "del_flag", "update_by",
+ "update_time", "version" };
/** 页面不需要显示的列表字段 */
public static final String[] COLUMNNAME_NOT_LIST = { "id", "create_by", "create_time", "del_flag", "update_by",
- "update_time" };
+ "update_time", "version" };
/** 页面不需要查询字段 */
public static final String[] COLUMNNAME_NOT_QUERY = { "id", "create_by", "create_time", "del_flag", "update_by",
- "update_time", "remark" };
+ "update_time", "remark", "version" };
/** Entity基类字段 */
public static final String[] BASE_ENTITY = { "createBy", "createTime", "updateBy", "updateTime", "remark" };
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 72d624a9c..a5a92f4d3 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 com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -62,6 +63,7 @@ public class BaseEntity implements Serializable {
/**
* 请求参数
*/
+ @JsonIgnore
@ApiModelProperty(value = "请求参数")
private Map params = new HashMap<>();
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/dto/OperLogDTO.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/dto/OperLogDTO.java
new file mode 100644
index 000000000..f5132efe6
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/dto/OperLogDTO.java
@@ -0,0 +1,107 @@
+package com.ruoyi.common.core.domain.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 操作日志记录表 oper_log
+ *
+ * @author ruoyi
+ */
+
+@Data
+@NoArgsConstructor
+@Accessors(chain = true)
+public class OperLogDTO implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 日志主键
+ */
+ private Long operId;
+
+ /**
+ * 操作模块
+ */
+ private String title;
+
+ /**
+ * 业务类型(0其它 1新增 2修改 3删除)
+ */
+ private Integer businessType;
+
+ /**
+ * 业务类型数组
+ */
+ private Integer[] businessTypes;
+
+ /**
+ * 请求方法
+ */
+ private String method;
+
+ /**
+ * 请求方式
+ */
+ private String requestMethod;
+
+ /**
+ * 操作类别(0其它 1后台用户 2手机端用户)
+ */
+ private Integer operatorType;
+
+ /**
+ * 操作人员
+ */
+ private String operName;
+
+ /**
+ * 部门名称
+ */
+ private String deptName;
+
+ /**
+ * 请求url
+ */
+ private String operUrl;
+
+ /**
+ * 操作地址
+ */
+ private String operIp;
+
+ /**
+ * 操作地点
+ */
+ private String operLocation;
+
+ /**
+ * 请求参数
+ */
+ private String operParam;
+
+ /**
+ * 返回参数
+ */
+ private String jsonResult;
+
+ /**
+ * 操作状态(0正常 1异常)
+ */
+ private Integer status;
+
+ /**
+ * 错误消息
+ */
+ private String errorMsg;
+
+ /**
+ * 操作时间
+ */
+ private Date operTime;
+
+}
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 e8bc0f156..89ee1c1bc 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
@@ -90,7 +90,7 @@ public class SysDictData implements Serializable {
* 状态(0正常 1停用)
*/
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
- @ExcelDictFormat(dictType = "sys_common_status")
+ @ExcelDictFormat(dictType = "sys_normal_disable")
private String status;
/**
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 1108671d8..35d9a60fe 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
@@ -57,7 +57,7 @@ public class SysDictType implements Serializable {
* 状态(0正常 1停用)
*/
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
- @ExcelDictFormat(dictType = "sys_common_status")
+ @ExcelDictFormat(dictType = "sys_normal_disable")
private String status;
/**
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 6fc86418e..d2c5bbf94 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
@@ -66,6 +66,11 @@ public class SysMenu implements Serializable {
@Size(min = 0, max = 200, message = "组件路径不能超过255个字符")
private String component;
+ /**
+ * 路由参数
+ */
+ private String query;
+
/**
* 是否为外链(0是 1否)
*/
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 6e44a3b95..770998126 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
@@ -91,11 +91,6 @@ public class SysUser implements Serializable {
return password;
}
- /**
- * 盐加密
- */
- private String salt;
-
/**
* 帐号状态(0正常 1停用)
*/
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java
deleted file mode 100644
index 23a25e045..000000000
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java
+++ /dev/null
@@ -1,260 +0,0 @@
-package com.ruoyi.common.core.redis;
-
-import com.google.common.collect.Lists;
-import org.redisson.api.*;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
-
-/**
- * spring redis 工具类
- *
- * @author shenxinquan
- * @see com.ruoyi.common.utils.RedisUtils
- * @deprecated 3.2.0 删除此类
- **/
-@SuppressWarnings(value = {"unchecked", "rawtypes"})
-@Component
-@Deprecated
-public class RedisCache {
-
- @Autowired
- private RedissonClient redissonClient;
-
- /**
- * 发布通道消息
- *
- * @param channelKey 通道key
- * @param msg 发送数据
- * @param consumer 自定义处理
- */
- public void publish(String channelKey, T msg, Consumer consumer) {
- RTopic topic = redissonClient.getTopic(channelKey);
- topic.publish(msg);
- consumer.accept(msg);
- }
-
- public void publish(String channelKey, T msg) {
- RTopic topic = redissonClient.getTopic(channelKey);
- topic.publish(msg);
- }
-
- /**
- * 订阅通道接收消息
- *
- * @param channelKey 通道key
- * @param clazz 消息类型
- * @param consumer 自定义处理
- */
- public void subscribe(String channelKey, Class clazz, Consumer consumer) {
- RTopic topic = redissonClient.getTopic(channelKey);
- topic.addListener(clazz, (channel, msg) -> consumer.accept(msg));
- }
-
- /**
- * 缓存基本的对象,Integer、String、实体类等
- *
- * @param key 缓存的键值
- * @param value 缓存的值
- */
- public void setCacheObject(final String key, final T value) {
- redissonClient.getBucket(key).set(value);
- }
-
- /**
- * 缓存基本的对象,Integer、String、实体类等
- *
- * @param key 缓存的键值
- * @param value 缓存的值
- * @param timeout 时间
- * @param timeUnit 时间颗粒度
- */
- public void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
- RBucket result = redissonClient.getBucket(key);
- result.set(value);
- result.expire(timeout, timeUnit);
- }
-
- /**
- * 设置有效时间
- *
- * @param key Redis键
- * @param timeout 超时时间
- * @return true=设置成功;false=设置失败
- */
- public boolean expire(final String key, final long timeout) {
- return expire(key, timeout, TimeUnit.SECONDS);
- }
-
- /**
- * 设置有效时间
- *
- * @param key Redis键
- * @param timeout 超时时间
- * @param unit 时间单位
- * @return true=设置成功;false=设置失败
- */
- public boolean expire(final String key, final long timeout, final TimeUnit unit) {
- RBucket rBucket = redissonClient.getBucket(key);
- return rBucket.expire(timeout, unit);
- }
-
- /**
- * 获得缓存的基本对象。
- *
- * @param key 缓存键值
- * @return 缓存键值对应的数据
- */
- public T getCacheObject(final String key) {
- RBucket rBucket = redissonClient.getBucket(key);
- return rBucket.get();
- }
-
- /**
- * 删除单个对象
- *
- * @param key
- */
- public boolean deleteObject(final String key) {
- return redissonClient.getBucket(key).delete();
- }
-
- /* */
-
- /**
- * 删除集合对象
- *
- * @param collection 多个对象
- * @return
- */
- public void deleteObject(final Collection collection) {
- RBatch batch = redissonClient.createBatch();
- collection.forEach(t->{
- batch.getBucket(t.toString()).deleteAsync();
- });
- batch.execute();
- }
-
- /**
- * 缓存List数据
- *
- * @param key 缓存的键值
- * @param dataList 待缓存的List数据
- * @return 缓存的对象
- */
- public boolean setCacheList(final String key, final List dataList) {
- RList rList = redissonClient.getList(key);
- return rList.addAll(dataList);
- }
-
- /**
- * 获得缓存的list对象
- *
- * @param key 缓存的键值
- * @return 缓存键值对应的数据
- */
- public List getCacheList(final String key) {
- RList rList = redissonClient.getList(key);
- return rList.readAll();
- }
-
- /**
- * 缓存Set
- *
- * @param key 缓存键值
- * @param dataSet 缓存的数据
- * @return 缓存数据的对象
- */
- public boolean setCacheSet(final String key, final Set dataSet) {
- RSet rSet = redissonClient.getSet(key);
- return rSet.addAll(dataSet);
- }
-
- /**
- * 获得缓存的set
- *
- * @param key
- * @return
- */
- public Set getCacheSet(final String key) {
- RSet rSet = redissonClient.getSet(key);
- return rSet.readAll();
- }
-
- /**
- * 缓存Map
- *
- * @param key
- * @param dataMap
- */
- public void setCacheMap(final String key, final Map dataMap) {
- if (dataMap != null) {
- RMap rMap = redissonClient.getMap(key);
- rMap.putAll(dataMap);
- }
- }
-
- /**
- * 获得缓存的Map
- *
- * @param key
- * @return
- */
- public Map getCacheMap(final String key) {
- RMap rMap = redissonClient.getMap(key);
- return rMap.getAll(rMap.keySet());
- }
-
- /**
- * 往Hash中存入数据
- *
- * @param key Redis键
- * @param hKey Hash键
- * @param value 值
- */
- public void setCacheMapValue(final String key, final String hKey, final T value) {
- RMap rMap = redissonClient.getMap(key);
- rMap.put(hKey, value);
- }
-
- /**
- * 获取Hash中的数据
- *
- * @param key Redis键
- * @param hKey Hash键
- * @return Hash中的对象
- */
- public T getCacheMapValue(final String key, final String hKey) {
- RMap rMap = redissonClient.getMap(key);
- return rMap.get(hKey);
- }
-
- /**
- * 获取多个Hash中的数据
- *
- * @param key Redis键
- * @param hKeys Hash键集合
- * @return Hash对象集合
- */
- public Map getMultiCacheMapValue(final String key, final Set hKeys) {
- RMap rMap = redissonClient.getMap(key);
- return rMap.getAll(hKeys);
- }
-
- /**
- * 获得缓存的基本对象列表
- *
- * @param pattern 字符串前缀
- * @return 对象列表
- */
- public Collection keys(final String pattern) {
- Iterable iterable = redissonClient.getKeys().getKeysByPattern(pattern);
- return Lists.newArrayList(iterable);
- }
-}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/service/LogininforService.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/service/LogininforService.java
new file mode 100644
index 000000000..1bf34d526
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/service/LogininforService.java
@@ -0,0 +1,9 @@
+package com.ruoyi.common.core.service;
+
+import javax.servlet.http.HttpServletRequest;
+
+public interface LogininforService {
+
+ void recordLogininfor(String username, String status, String message,
+ HttpServletRequest request, Object... args);
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/service/OperLogService.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/service/OperLogService.java
new file mode 100644
index 000000000..71e5647ee
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/service/OperLogService.java
@@ -0,0 +1,9 @@
+package com.ruoyi.common.core.service;
+
+import com.ruoyi.common.core.domain.dto.OperLogDTO;
+import org.springframework.scheduling.annotation.Async;
+
+public interface OperLogService {
+ @Async
+ void recordOper(OperLogDTO operLogDTO);
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/service/TokenService.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/service/TokenService.java
new file mode 100644
index 000000000..d9a9f0acf
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/service/TokenService.java
@@ -0,0 +1,69 @@
+package com.ruoyi.common.core.service;
+
+import com.ruoyi.common.core.domain.model.LoginUser;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * token验证处理
+ *
+ * @author Lion Li
+ */
+public interface TokenService {
+
+ /**
+ * 获取用户身份信息
+ *
+ * @return 用户信息
+ */
+ LoginUser getLoginUser(HttpServletRequest request);
+
+ /**
+ * 设置用户身份信息
+ */
+ void setLoginUser(LoginUser loginUser);
+
+ /**
+ * 删除用户身份信息
+ */
+ void delLoginUser(String token);
+
+ /**
+ * 创建令牌
+ *
+ * @param loginUser 用户信息
+ * @return 令牌
+ */
+ String createToken(LoginUser loginUser);
+
+ /**
+ * 验证令牌有效期,相差不足20分钟,自动刷新缓存
+ *
+ * @param loginUser
+ * @return 令牌
+ */
+ void verifyToken(LoginUser loginUser);
+
+ /**
+ * 刷新令牌有效期
+ *
+ * @param loginUser 登录信息
+ */
+ void refreshToken(LoginUser loginUser);
+
+ /**
+ * 设置用户代理信息
+ *
+ * @param loginUser 登录信息
+ */
+ void setUserAgent(LoginUser loginUser);
+
+ /**
+ * 从令牌中获取用户名
+ *
+ * @param token 令牌
+ * @return 用户名
+ */
+ String getUsernameFromToken(String token);
+
+}
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
index ad01659dc..02c2b3d30 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java
@@ -16,5 +16,10 @@ public enum LimitType
/**
* 根据请求者IP进行限流
*/
- IP
+ IP,
+
+ /**
+ * 实例限流(集群多后端实例)
+ */
+ CLUSTER
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/ThreadPoolRejectedPolicy.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/ThreadPoolRejectedPolicy.java
index 0c40f341c..5529bb336 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/ThreadPoolRejectedPolicy.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/ThreadPoolRejectedPolicy.java
@@ -15,7 +15,7 @@ import java.util.concurrent.ThreadPoolExecutor;
@AllArgsConstructor
public enum ThreadPoolRejectedPolicy {
- CALLER_RUNS_POLICY("等待", ThreadPoolExecutor.CallerRunsPolicy.class),
+ CALLER_RUNS_POLICY("调用方执行", ThreadPoolExecutor.CallerRunsPolicy.class),
DISCARD_OLDEST_POLICY("放弃最旧的", ThreadPoolExecutor.DiscardOldestPolicy.class),
DISCARD_POLICY("丢弃", ThreadPoolExecutor.DiscardPolicy.class),
ABORT_POLICY("中止", ThreadPoolExecutor.AbortPolicy.class);
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/TokenProperties.java b/ruoyi-common/src/main/java/com/ruoyi/common/properties/TokenProperties.java
similarity index 91%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/TokenProperties.java
rename to ruoyi-common/src/main/java/com/ruoyi/common/properties/TokenProperties.java
index f695c1c62..927a9413d 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/TokenProperties.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/properties/TokenProperties.java
@@ -1,4 +1,4 @@
-package com.ruoyi.framework.config.properties;
+package com.ruoyi.common.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/RedisUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/RedisUtils.java
index 5fcfb9dee..769ee7153 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/RedisUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/RedisUtils.java
@@ -25,6 +25,32 @@ public class RedisUtils {
private static RedissonClient client = SpringUtils.getBean(RedissonClient.class);
+ /**
+ * 限流
+ *
+ * @param key 限流key
+ * @param rateType 限流类型
+ * @param rate 速率
+ * @param rateInterval 速率间隔
+ * @return -1 表示失败
+ */
+ public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval) {
+ RRateLimiter rateLimiter = client.getRateLimiter(key);
+ rateLimiter.trySetRate(rateType, rate, rateInterval, RateIntervalUnit.SECONDS);
+ if (rateLimiter.tryAcquire()) {
+ return rateLimiter.availablePermits();
+ } else {
+ return -1L;
+ }
+ }
+
+ /**
+ * 获取实例id
+ */
+ public static String getClientId() {
+ return client.getId();
+ }
+
/**
* 发布通道消息
*
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 dc3aea2c0..3ab304c0c 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
@@ -35,6 +35,7 @@ public class FileUtils extends FileUtil
.append(percentEncodedFileName);
response.setHeader("Content-disposition", contentDispositionValue.toString());
+ response.setHeader("download-filename", percentEncodedFileName);
}
/**
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 03c608af8..bd7522c51 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
@@ -27,6 +27,9 @@ public class AddressUtils {
public static String getRealAddressByIP(String ip) {
String address = UNKNOWN;
+ if (StringUtils.isBlank(ip)){
+ return address;
+ }
// 内网不查询
ip = "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : HtmlUtil.cleanHtmlTag(ip);
if (NetUtil.isInnerIP(ip)) {
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 4060b1794..e3001c605 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
@@ -46,7 +46,7 @@ public class ExcelUtil {
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()));
+ FileUtils.setAttachmentResponseHeader(response, filename);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
ServletOutputStream os = response.getOutputStream();
EasyExcel.write(os, clazz)
diff --git a/ruoyi-demo/pom.xml b/ruoyi-demo/pom.xml
index 2eff3c2db..339cbde44 100644
--- a/ruoyi-demo/pom.xml
+++ b/ruoyi-demo/pom.xml
@@ -5,7 +5,7 @@
ruoyi-vue-plus
com.ruoyi
- 3.1.0
+ 3.2.0
4.0.0
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java
index 6877aed2d..5ef9d49cd 100644
--- a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java
@@ -34,6 +34,9 @@ public class RedisCacheController {
* 如果没有,就调用方法,然后把结果缓存起来
* 这个注解「一般用在查询方法上」
*
+ * 重点说明: 缓存注解严谨与其他筛选数据功能一起使用
+ * 例如: 数据权限注解 会造成 缓存击穿 与 数据不一致问题
+ *
* cacheNames 为配置文件内 groupId
*/
@ApiOperation("测试 @Cacheable")
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisRateLimiterController.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisRateLimiterController.java
new file mode 100644
index 000000000..33d75093b
--- /dev/null
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisRateLimiterController.java
@@ -0,0 +1,58 @@
+package com.ruoyi.demo.controller;
+
+import com.ruoyi.common.annotation.RateLimiter;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.LimitType;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+/**
+ * 测试分布式限流样例
+ *
+ * @author Lion Li
+ */
+@Api(value = "测试分布式限流样例", tags = {"测试分布式限流样例"})
+@Slf4j
+@RestController
+@RequestMapping("/demo/rateLimiter")
+public class RedisRateLimiterController {
+
+ /**
+ * 测试全局限流
+ * 全局影响
+ */
+ @ApiOperation("测试全局限流")
+ @RateLimiter(count = 2, time = 10)
+ @GetMapping("/test")
+ public AjaxResult test(String value){
+ return AjaxResult.success("操作成功",value);
+ }
+
+ /**
+ * 测试请求IP限流
+ * 同一IP请求受影响
+ */
+ @ApiOperation("测试请求IP限流")
+ @RateLimiter(count = 2, time = 10, limitType = LimitType.IP)
+ @GetMapping("/testip")
+ public AjaxResult testip(String value){
+ return AjaxResult.success("操作成功",value);
+ }
+
+ /**
+ * 测试集群实例限流
+ * 启动两个后端服务互不影响
+ */
+ @ApiOperation("测试集群实例限流")
+ @RateLimiter(count = 2, time = 10, limitType = LimitType.CLUSTER)
+ @GetMapping("/testcluster")
+ public AjaxResult testcluster(String value){
+ return AjaxResult.success("操作成功",value);
+ }
+
+}
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 563704e05..a3a9d2224 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
@@ -96,7 +96,7 @@ public class TestDemoController extends BaseController {
@ApiOperation("新增测试单表")
@PreAuthorize("@ss.hasPermi('demo:demo:add')")
@Log(title = "测试单表", businessType = BusinessType.INSERT)
- @RepeatSubmit(intervalTime = 2, timeUnit = TimeUnit.SECONDS)
+ @RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "不允许重复提交")
@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/service/impl/TestDemoServiceImpl.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestDemoServiceImpl.java
index fe103ef88..4280d509d 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
@@ -75,7 +75,11 @@ public class TestDemoServiceImpl extends ServicePlusImpl
ruoyi-vue-plus
com.ruoyi
- 3.1.0
+ 3.2.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 dc0830373..d63b110b9 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
- 3.1.0
+ 3.2.0
4.0.0
jar
diff --git a/ruoyi-framework/pom.xml b/ruoyi-framework/pom.xml
index 918a4cc58..20176a0be 100644
--- a/ruoyi-framework/pom.xml
+++ b/ruoyi-framework/pom.xml
@@ -5,7 +5,7 @@
ruoyi-vue-plus
com.ruoyi
- 3.1.0
+ 3.2.0
4.0.0
@@ -61,12 +61,23 @@
druid-spring-boot-starter
+
+
+ com.baomidou
+ dynamic-datasource-spring-boot-starter
+
+
+
+ p6spy
+ p6spy
+
+
com.ruoyi
- ruoyi-system
+ ruoyi-common
-
+
\ No newline at end of file
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 a2c101e3d..e4a6cdcdb 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
@@ -9,14 +9,10 @@ import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.reflect.ReflectUtils;
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.springframework.stereotype.Component;
-import java.lang.reflect.Method;
import java.util.Map;
/**
@@ -58,23 +54,13 @@ public class DataScopeAspect {
*/
public static final String DATA_SCOPE = "dataScope";
- // 配置织入点
- @Pointcut("@annotation(com.ruoyi.common.annotation.DataScope)")
- public void dataScopePointCut() {
- }
-
- @Before("dataScopePointCut()")
- public void doBefore(JoinPoint point) throws Throwable {
+ @Before("@annotation(controllerDataScope)")
+ public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable {
clearDataScope(point);
- handleDataScope(point);
+ handleDataScope(point, controllerDataScope);
}
- protected void handleDataScope(final JoinPoint joinPoint) {
- // 获得注解
- DataScope controllerDataScope = getAnnotationLog(joinPoint);
- if (controllerDataScope == null) {
- return;
- }
+ protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope) {
// 获取当前的用户
LoginUser loginUser = SecurityUtils.getLoginUser();
if (StringUtils.isNotNull(loginUser)) {
@@ -133,20 +119,6 @@ public class DataScopeAspect {
}
}
- /**
- * 是否存在注解,如果存在就获取
- */
- private DataScope getAnnotationLog(JoinPoint joinPoint) {
- Signature signature = joinPoint.getSignature();
- MethodSignature methodSignature = (MethodSignature) signature;
- Method method = methodSignature.getMethod();
-
- if (method != null) {
- return method.getAnnotation(DataScope.class);
- }
- return null;
- }
-
/**
* 拼接权限sql前先清空params.dataScope参数防止注入
*/
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 47e774265..55ec84595 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
@@ -6,33 +6,21 @@ import com.ruoyi.common.utils.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Pointcut;
-import org.aspectj.lang.reflect.MethodSignature;
-import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
-import java.util.Objects;
-
/**
* 多数据源处理
*
- * @author ruoyi
+ * @author Lion Li
*/
@Aspect
@Order(-500)
@Component
public class DataSourceAspect {
- @Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)"
- + "|| @within(com.ruoyi.common.annotation.DataSource)")
- public void dsPointCut() {
- }
-
- @Around("dsPointCut()")
- public Object around(ProceedingJoinPoint point) throws Throwable {
- DataSource dataSource = getDataSource(point);
-
+ @Around("@annotation(dataSource) || @within(dataSource)")
+ public Object around(ProceedingJoinPoint point, DataSource dataSource) throws Throwable {
if (StringUtils.isNotNull(dataSource)) {
DynamicDataSourceContextHolder.poll();
String source = dataSource.value().getSource();
@@ -47,16 +35,4 @@ public class DataSourceAspect {
}
}
- /**
- * 获取需要切换的数据源
- */
- public DataSource getDataSource(ProceedingJoinPoint point) {
- MethodSignature signature = (MethodSignature) point.getSignature();
- DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
- if (Objects.nonNull(dataSource)) {
- return dataSource;
- }
-
- return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);
- }
}
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 e8c47a364..642076d9e 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,7 +1,9 @@
package com.ruoyi.framework.aspectj;
import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.domain.dto.OperLogDTO;
import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.core.service.OperLogService;
import com.ruoyi.common.enums.BusinessStatus;
import com.ruoyi.common.enums.HttpMethod;
import com.ruoyi.common.utils.JsonUtils;
@@ -9,17 +11,11 @@ import com.ruoyi.common.utils.SecurityUtils;
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.system.domain.SysOperLog;
+import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Pointcut;
-import org.aspectj.lang.reflect.MethodSignature;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;
@@ -27,81 +23,58 @@ import org.springframework.web.servlet.HandlerMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
/**
* 操作日志记录处理
*
- * @author ruoyi
+ * @author Lion Li
*/
+@Slf4j
@Aspect
@Component
-public class LogAspect
-{
- private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
-
- // 配置织入点
- @Pointcut("@annotation(com.ruoyi.common.annotation.Log)")
- public void logPointCut()
- {
- }
+public class LogAspect {
/**
* 处理完请求后执行
*
* @param joinPoint 切点
*/
- @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
- public void doAfterReturning(JoinPoint joinPoint, Object jsonResult)
- {
- handleLog(joinPoint, null, jsonResult);
+ @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
+ public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
+ handleLog(joinPoint, controllerLog, null, jsonResult);
}
/**
* 拦截异常操作
*
* @param joinPoint 切点
- * @param e 异常
+ * @param e 异常
*/
- @AfterThrowing(value = "logPointCut()", throwing = "e")
- public void doAfterThrowing(JoinPoint joinPoint, Exception e)
- {
- handleLog(joinPoint, e, null);
+ @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
+ public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
+ handleLog(joinPoint, controllerLog, e, null);
}
- protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult)
- {
- try
- {
- // 获得注解
- Log controllerLog = getAnnotationLog(joinPoint);
- if (controllerLog == null)
- {
- return;
- }
+ protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
+ try {
// 获取当前的用户
LoginUser loginUser = SecurityUtils.getLoginUser();
// *========数据库日志=========*//
- SysOperLog operLog = new SysOperLog();
+ OperLogDTO operLog = new OperLogDTO();
operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
// 请求的地址
String ip = ServletUtils.getClientIP();
operLog.setOperIp(ip);
- // 返回参数
- operLog.setJsonResult(JsonUtils.toJsonString(jsonResult));
-
operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
- if (loginUser != null)
- {
+ if (loginUser != null) {
operLog.setOperName(loginUser.getUsername());
}
- if (e != null)
- {
+ if (e != null) {
operLog.setStatus(BusinessStatus.FAIL.ordinal());
operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
}
@@ -112,12 +85,10 @@ public class LogAspect
// 设置请求方式
operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
// 处理设置注解上的参数
- getControllerMethodDescription(joinPoint, controllerLog, operLog);
+ getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
// 保存数据库
- SpringUtils.getBean(AsyncService.class).recordOper(operLog);
- }
- catch (Exception exp)
- {
+ SpringUtils.getBean(OperLogService.class).recordOper(operLog);
+ } catch (Exception exp) {
// 记录本地异常日志
log.error("==前置通知异常==");
log.error("异常信息:{}", exp.getMessage());
@@ -128,12 +99,11 @@ public class LogAspect
/**
* 获取注解中对方法的描述信息 用于Controller层注解
*
- * @param log 日志
+ * @param log 日志
* @param operLog 操作日志
* @throws Exception
*/
- public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog) throws Exception
- {
+ public void getControllerMethodDescription(JoinPoint joinPoint, Log log, OperLogDTO operLog, Object jsonResult) throws Exception {
// 设置action动作
operLog.setBusinessType(log.businessType().ordinal());
// 设置标题
@@ -141,11 +111,14 @@ public class LogAspect
// 设置操作人类别
operLog.setOperatorType(log.operatorType().ordinal());
// 是否需要保存request,参数和值
- if (log.isSaveRequestData())
- {
+ if (log.isSaveRequestData()) {
// 获取参数的信息,传入到数据库中。
setRequestValue(joinPoint, operLog);
}
+ // 是否需要保存response,参数和值
+ if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult)) {
+ operLog.setJsonResult(StringUtils.substring(JsonUtils.toJsonString(jsonResult), 0, 2000));
+ }
}
/**
@@ -154,50 +127,32 @@ public class LogAspect
* @param operLog 操作日志
* @throws Exception 异常
*/
- private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog) throws Exception
- {
+ private void setRequestValue(JoinPoint joinPoint, OperLogDTO operLog) throws Exception {
String requestMethod = operLog.getRequestMethod();
- if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod))
- {
+ if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
String params = argsArrayToString(joinPoint.getArgs());
operLog.setOperParam(StringUtils.substring(params, 0, 2000));
- }
- else
- {
+ } else {
Map, ?> paramsMap = (Map, ?>) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
operLog.setOperParam(StringUtils.substring(paramsMap.toString(), 0, 2000));
}
}
- /**
- * 是否存在注解,如果存在就获取
- */
- private Log getAnnotationLog(JoinPoint joinPoint) throws Exception
- {
- Signature signature = joinPoint.getSignature();
- MethodSignature methodSignature = (MethodSignature) signature;
- Method method = methodSignature.getMethod();
-
- if (method != null)
- {
- return method.getAnnotation(Log.class);
- }
- return null;
- }
-
/**
* 参数拼装
*/
- private String argsArrayToString(Object[] paramsArray)
- {
+ private String argsArrayToString(Object[] paramsArray) {
StringBuilder params = new StringBuilder();
- if (paramsArray != null && paramsArray.length > 0)
- {
- for (Object o : paramsArray) {
- if (StringUtils.isNotNull(o) && !isFilterObject(o)) {
- params.append(JsonUtils.toJsonString(o)).append(" ");
- }
- }
+ if (paramsArray != null && paramsArray.length > 0) {
+ for (Object o : paramsArray) {
+ if (StringUtils.isNotNull(o) && !isFilterObject(o)) {
+ try {
+ params.append(JsonUtils.toJsonString(o)).append(" ");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
}
return params.toString().trim();
}
@@ -209,27 +164,21 @@ public class LogAspect
* @return 如果是需要过滤的对象,则返回true;否则返回false。
*/
@SuppressWarnings("rawtypes")
- public boolean isFilterObject(final Object o)
- {
+ public boolean isFilterObject(final Object o) {
Class> clazz = o.getClass();
- if (clazz.isArray())
- {
+ if (clazz.isArray()) {
return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
- }
- else if (Collection.class.isAssignableFrom(clazz))
- {
+ } else if (Collection.class.isAssignableFrom(clazz)) {
Collection collection = (Collection) o;
- for (Object value : collection) {
- return value instanceof MultipartFile;
- }
- }
- else if (Map.class.isAssignableFrom(clazz))
- {
+ for (Object value : collection) {
+ return value instanceof MultipartFile;
+ }
+ } else if (Map.class.isAssignableFrom(clazz)) {
Map map = (Map) o;
- for (Object value : map.entrySet()) {
- Map.Entry entry = (Map.Entry) value;
- return entry.getValue() instanceof MultipartFile;
- }
+ for (Object value : map.entrySet()) {
+ Map.Entry entry = (Map.Entry) value;
+ return entry.getValue() instanceof MultipartFile;
+ }
}
return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
|| o instanceof BindingResult;
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
index 1e21e376d..dc140e22b 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
@@ -3,114 +3,63 @@ 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.RedisUtils;
import com.ruoyi.common.utils.ServletUtils;
-import com.ruoyi.common.utils.StringUtils;
+import lombok.extern.slf4j.Slf4j;
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.redisson.api.RateType;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
-import java.util.Collections;
-import java.util.List;
/**
* 限流处理
*
- * @author ruoyi
+ * @author Lion Li
*/
+@Slf4j
@Aspect
@Component
-public class RateLimiterAspect
-{
- private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);
+public class RateLimiterAspect {
- private RedisTemplate