Merge remote-tracking branch 'origin/dev' into 4.X

This commit is contained in:
疯狂的狮子li 2022-04-24 13:32:10 +08:00
commit 0700c60636
153 changed files with 7091 additions and 1935 deletions

View File

@ -1,4 +1,4 @@
### 使用版本 ### 使用版本(未按照模板填写直接删除)
### 问题描述 ### 问题描述

View File

@ -4,8 +4,8 @@
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/blob/master/LICENSE) [![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) [![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
<br> <br>
[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-4.0.1-success.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus) [![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-4.1.0-success.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus)
[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-2.5-blue.svg)]() [![Spring Boot](https://img.shields.io/badge/Spring%20Boot-2.6-blue.svg)]()
[![JDK-8+](https://img.shields.io/badge/JDK-8-green.svg)]() [![JDK-8+](https://img.shields.io/badge/JDK-8-green.svg)]()
[![JDK-11](https://img.shields.io/badge/JDK-11-green.svg)]() [![JDK-11](https://img.shields.io/badge/JDK-11-green.svg)]()
@ -25,6 +25,9 @@
| 容器框架 | Undertow | [Undertow官网](https://undertow.io/) | 基于 XNIO 的高性能容器 | | 容器框架 | Undertow | [Undertow官网](https://undertow.io/) | 基于 XNIO 的高性能容器 |
| 权限认证框架 | Sa-Token、Jwt | [Sa-Token官网](https://sa-token.dev33.cn/) | 强解耦、强扩展 | | 权限认证框架 | Sa-Token、Jwt | [Sa-Token官网](https://sa-token.dev33.cn/) | 强解耦、强扩展 |
| 关系数据库 | MySQL | [MySQL官网](https://dev.mysql.com/) | 适配 8.X 最低 5.7 | | 关系数据库 | MySQL | [MySQL官网](https://dev.mysql.com/) | 适配 8.X 最低 5.7 |
| 关系数据库 | Oracle | [Oracle官网](https://www.oracle.com/cn/database/) | 适配 11g 12c |
| 关系数据库 | PostgreSQL | [PostgreSQL官网](https://www.postgresql.org/) | 适配 13 14 |
| 关系数据库 | SQLServer | [SQLServer官网](https://docs.microsoft.com/zh-cn/sql/sql-server) | 适配 2017 2019 |
| 缓存数据库 | Redis | [Redis官网](https://redis.io/) | 适配 6.X 最低 4.X | | 缓存数据库 | Redis | [Redis官网](https://redis.io/) | 适配 6.X 最低 4.X |
| 数据库框架 | Mybatis-Plus | [Mybatis-Plus文档](https://baomidou.com/guide/) | 快速 CRUD 增加开发效率 | | 数据库框架 | Mybatis-Plus | [Mybatis-Plus文档](https://baomidou.com/guide/) | 快速 CRUD 增加开发效率 |
| 数据库框架 | p6spy | [p6spy官网](https://p6spy.readthedocs.io/) | 更强劲的 SQL 分析 | | 数据库框架 | p6spy | [p6spy官网](https://p6spy.readthedocs.io/) | 更强劲的 SQL 分析 |

61
pom.xml
View File

@ -6,46 +6,49 @@
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-vue-plus</artifactId> <artifactId>ruoyi-vue-plus</artifactId>
<version>4.0.1</version> <version>4.1.0</version>
<name>RuoYi-Vue-Plus</name> <name>RuoYi-Vue-Plus</name>
<url>https://gitee.com/JavaLionLi/RuoYi-Vue-Plus</url> <url>https://gitee.com/JavaLionLi/RuoYi-Vue-Plus</url>
<description>RuoYi-Vue-Plus后台管理系统</description> <description>RuoYi-Vue-Plus后台管理系统</description>
<properties> <properties>
<ruoyi-vue-plus.version>4.0.1</ruoyi-vue-plus.version> <ruoyi-vue-plus.version>4.1.0</ruoyi-vue-plus.version>
<spring-boot.version>2.6.4</spring-boot.version> <spring-boot.version>2.6.7</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version> <java.version>1.8</java.version>
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version> <maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
<spring-boot.mybatis>2.2.0</spring-boot.mybatis>
<druid.version>1.2.8</druid.version> <druid.version>1.2.8</druid.version>
<knife4j.version>3.0.3</knife4j.version> <knife4j.version>3.0.3</knife4j.version>
<swagger-annotations.version>1.5.22</swagger-annotations.version> <swagger-annotations.version>1.5.22</swagger-annotations.version>
<poi.version>4.1.2</poi.version> <poi.version>4.1.2</poi.version>
<commons-compress.version>1.21</commons-compress.version>
<easyexcel.version>3.0.5</easyexcel.version> <easyexcel.version>3.0.5</easyexcel.version>
<cglib.version>3.3.0</cglib.version>
<velocity.version>2.3</velocity.version> <velocity.version>2.3</velocity.version>
<satoken.version>1.29.0</satoken.version> <satoken.version>1.29.0</satoken.version>
<mybatis-plus.version>3.5.1</mybatis-plus.version> <mybatis-plus.version>3.5.1</mybatis-plus.version>
<p6spy.version>3.9.1</p6spy.version> <p6spy.version>3.9.1</p6spy.version>
<hutool.version>5.7.21</hutool.version> <hutool.version>5.7.22</hutool.version>
<okhttp.version>4.9.2</okhttp.version> <okhttp.version>4.9.3</okhttp.version>
<spring-boot-admin.version>2.6.2</spring-boot-admin.version> <spring-boot-admin.version>2.6.6</spring-boot-admin.version>
<redisson.version>3.16.8</redisson.version> <redisson.version>3.17.0</redisson.version>
<lock4j.version>2.2.1</lock4j.version> <lock4j.version>2.2.1</lock4j.version>
<dynamic-ds.version>3.5.0</dynamic-ds.version> <dynamic-ds.version>3.5.1</dynamic-ds.version>
<tlog.version>1.3.6</tlog.version> <tlog.version>1.3.6</tlog.version>
<xxl-job.version>2.3.0</xxl-job.version> <xxl-job.version>2.3.0</xxl-job.version>
<!-- jdk11 缺失依赖 jaxb--> <!-- jdk11 缺失依赖 jaxb-->
<jaxb.version>3.0.1</jaxb.version> <jaxb.version>3.0.1</jaxb.version>
<!-- 统一 guava 版本 解决隐式漏洞问题 -->
<guava.version>30.0-jre</guava.version>
<!-- OSS 配置 --> <!-- OSS 配置 -->
<qiniu.version>7.9.3</qiniu.version> <qiniu.version>7.9.5</qiniu.version>
<aliyun.oss.version>3.14.0</aliyun.oss.version> <aliyun.oss.version>3.14.0</aliyun.oss.version>
<qcloud.cos.version>5.6.68</qcloud.cos.version> <qcloud.cos.version>5.6.72</qcloud.cos.version>
<minio.version>8.3.7</minio.version> <minio.version>8.3.8</minio.version>
<!-- docker 配置 --> <!-- docker 配置 -->
<docker.registry.url>localhost</docker.registry.url> <docker.registry.url>localhost</docker.registry.url>
@ -109,6 +112,13 @@
<version>${poi.version}</version> <version>${poi.version}</version>
</dependency> </dependency>
<!-- 修复poi漏洞 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>${commons-compress.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId> <artifactId>easyexcel</artifactId>
@ -125,12 +135,6 @@
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>${cglib.version}</version>
</dependency>
<!-- velocity代码生成使用模板 --> <!-- velocity代码生成使用模板 -->
<dependency> <dependency>
<groupId>org.apache.velocity</groupId> <groupId>org.apache.velocity</groupId>
@ -222,6 +226,20 @@
<groupId>com.yomahub</groupId> <groupId>com.yomahub</groupId>
<artifactId>tlog-web-spring-boot-starter</artifactId> <artifactId>tlog-web-spring-boot-starter</artifactId>
<version>${tlog.version}</version> <version>${tlog.version}</version>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
<exclusion>
<artifactId>dom4j</artifactId>
<groupId>dom4j</groupId>
</exclusion>
<exclusion>
<artifactId>commons-beanutils</artifactId>
<groupId>commons-beanutils</groupId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
@ -230,6 +248,13 @@
<version>${tlog.version}</version> <version>${tlog.version}</version>
</dependency> </dependency>
<!-- 统一 guava 版本 解决隐式漏洞问题 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!-- 定时任务 --> <!-- 定时任务 -->
<dependency> <dependency>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi-vue-plus</artifactId> <artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>4.0.1</version> <version>4.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -29,6 +29,21 @@
<groupId>mysql</groupId> <groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId> <artifactId>mysql-connector-java</artifactId>
</dependency> </dependency>
<!-- Oracle -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
</dependency>
<!-- PostgreSql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<!-- SqlServer -->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
</dependency>
<!-- 核心模块--> <!-- 核心模块-->
<dependency> <dependency>

View File

@ -7,6 +7,7 @@ import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.entity.SysMenu; import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginBody; import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.core.domain.model.SmsLoginBody;
import com.ruoyi.common.helper.LoginHelper; import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.system.domain.vo.RouterVo; import com.ruoyi.system.domain.vo.RouterVo;
import com.ruoyi.system.service.ISysMenuService; import com.ruoyi.system.service.ISysMenuService;
@ -22,6 +23,7 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.NotBlank;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -60,6 +62,38 @@ public class SysLoginController {
return R.ok(ajax); return R.ok(ajax);
} }
/**
* 短信登录(示例)
*
* @param smsLoginBody 登录信息
* @return 结果
*/
@ApiOperation("短信登录(示例)")
@PostMapping("/smsLogin")
public R<Map<String, Object>> smsLogin(@Validated @RequestBody SmsLoginBody smsLoginBody) {
Map<String, Object> ajax = new HashMap<>();
// 生成令牌
String token = loginService.smsLogin(smsLoginBody.getPhonenumber(), smsLoginBody.getSmsCode());
ajax.put(Constants.TOKEN, token);
return R.ok(ajax);
}
/**
* 小程序登录(示例)
*
* @param xcxCode 小程序code
* @return 结果
*/
@ApiOperation("小程序登录(示例)")
@PostMapping("/xcxLogin")
public R<Map<String, Object>> xcxLogin(@NotBlank(message = "{xcx.code.not.blank}") String xcxCode) {
Map<String, Object> ajax = new HashMap<>();
// 生成令牌
String token = loginService.xcxLogin(xcxCode);
ajax.put(Constants.TOKEN, token);
return R.ok(ajax);
}
@ApiOperation("登出方法") @ApiOperation("登出方法")
@PostMapping("/logout") @PostMapping("/logout")
public R<Void> logout() { public R<Void> logout() {

View File

@ -59,7 +59,7 @@ public class SysOssConfigController extends BaseController {
@GetMapping("/{ossConfigId}") @GetMapping("/{ossConfigId}")
public R<SysOssConfigVo> getInfo(@ApiParam("OSS配置ID") public R<SysOssConfigVo> getInfo(@ApiParam("OSS配置ID")
@NotNull(message = "主键不能为空") @NotNull(message = "主键不能为空")
@PathVariable("ossConfigId") Integer ossConfigId) { @PathVariable("ossConfigId") Long ossConfigId) {
return R.ok(iSysOssConfigService.queryById(ossConfigId)); return R.ok(iSysOssConfigService.queryById(ossConfigId));
} }

View File

@ -18,7 +18,6 @@ import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.system.domain.SysOss; import com.ruoyi.system.domain.SysOss;
import com.ruoyi.system.domain.bo.SysOssBo; import com.ruoyi.system.domain.bo.SysOssBo;
import com.ruoyi.system.domain.vo.SysOssVo; import com.ruoyi.system.domain.vo.SysOssVo;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysOssService; import com.ruoyi.system.service.ISysOssService;
import io.swagger.annotations.*; import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -48,7 +47,6 @@ import java.util.Map;
public class SysOssController extends BaseController { public class SysOssController extends BaseController {
private final ISysOssService iSysOssService; private final ISysOssService iSysOssService;
private final ISysConfigService iSysConfigService;
/** /**
* 查询OSS对象存储列表 * 查询OSS对象存储列表
@ -77,7 +75,8 @@ public class SysOssController extends BaseController {
SysOss oss = iSysOssService.upload(file); SysOss oss = iSysOssService.upload(file);
Map<String, String> map = new HashMap<>(2); Map<String, String> map = new HashMap<>(2);
map.put("url", oss.getUrl()); map.put("url", oss.getUrl());
map.put("fileName", oss.getFileName()); map.put("fileName", oss.getOriginalName());
map.put("ossId", oss.getOssId().toString());
return R.ok(map); return R.ok(map);
} }

View File

@ -1,41 +1,34 @@
--- # 监控配置 --- # 监控中心配置
spring: spring.boot.admin.client:
boot: # 增加客户端开关
admin: enabled: true
# Spring Boot Admin Client 客户端的相关配置 url: http://localhost:9090/admin
client: instance:
# 增加客户端开关 service-host-type: IP
enabled: true username: ruoyi
# 设置 Spring Boot Admin Server 地址 password: 123456
url: http://localhost:9090/admin
instance:
service-host-type: IP
username: ruoyi
password: 123456
--- # xxl-job 配置 --- # xxl-job 配置
xxl: xxl.job:
job: # 执行器开关
# 执行器开关 enabled: true
enabled: true # 调度中心地址:如调度中心集群部署存在多个地址则用逗号分隔。
# 调度中心地址:如调度中心集群部署存在多个地址则用逗号分隔。 admin-addresses: http://localhost:9100/xxl-job-admin
admin-addresses: http://localhost:9100/xxl-job-admin # 执行器通讯TOKEN非空时启用
# 执行器通讯TOKEN非空时启用 access-token: xxl-job
access-token: xxl-job executor:
# 执行器配置 # 执行器AppName执行器心跳注册分组依据为空则关闭自动注册
executor: appname: xxl-job-executor
# 执行器AppName执行器心跳注册分组依据为空则关闭自动注册 # 执行器端口号 执行器从9101开始往后写
appname: xxl-job-executor port: 9101
# 执行器端口号 执行器从9101开始往后写 # 执行器注册默认IP:PORT
port: 9101 address:
# 执行器注册默认IP:PORT # 执行器IP默认自动获取IP
address: ip:
# 执行器IP默认自动获取IP # 执行器运行日志文件存储磁盘路径
ip: logpath: ./logs/xxl-job
# 执行器运行日志文件存储磁盘路径 # 执行器日志文件保存天数大于3生效
logpath: ./logs/xxl-job logretentiondays: 30
# 执行器日志文件保存天数大于3生效
logretentiondays: 30
--- # 数据源配置 --- # 数据源配置
spring: spring:
@ -47,6 +40,8 @@ spring:
p6spy: true p6spy: true
# 设置默认的数据源或者数据源组,默认值即为 master # 设置默认的数据源或者数据源组,默认值即为 master
primary: master primary: master
# 严格模式 匹配不到数据源则报错
strict: true
datasource: datasource:
# 主库数据源 # 主库数据源
master: master:
@ -63,6 +58,23 @@ spring:
url: url:
username: username:
password: password:
# oracle:
# driverClassName: oracle.jdbc.OracleDriver
# url: jdbc:oracle:thin:@//localhost:1521/XE
# username: ROOT
# password: root
# druid:
# validationQuery: SELECT 1 FROM DUAL
# postgres:
# driverClassName: org.postgresql.Driver
# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
# username: root
# password: root
# sqlserver:
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;rewriteBatchedStatements=true
# username: SA
# password: root
druid: druid:
# 初始连接数 # 初始连接数
initialSize: 5 initialSize: 5
@ -79,7 +91,7 @@ spring:
# 配置一个连接在池中最大生存的时间,单位是毫秒 # 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000 maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效 # 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL validationQuery: SELECT 1
testWhileIdle: true testWhileIdle: true
testOnBorrow: false testOnBorrow: false
testOnReturn: false testOnReturn: false
@ -87,29 +99,27 @@ spring:
filters: stat filters: stat
--- # druid 配置 --- # druid 配置
spring: spring.datasource.druid:
datasource: webStatFilter:
druid: enabled: true
webStatFilter: statViewServlet:
enabled: true enabled: true
statViewServlet: # 设置白名单,不填则允许所有访问
enabled: true allow:
# 设置白名单,不填则允许所有访问 url-pattern: /druid/*
allow: # 控制台管理用户名和密码
url-pattern: /druid/* login-username: ruoyi
# 控制台管理用户名和密码 login-password: 123456
login-username: ruoyi filter:
login-password: 123456 stat:
filter: enabled: true
stat: # 慢SQL记录
enabled: true log-slow-sql: true
# 慢SQL记录 slow-sql-millis: 1000
log-slow-sql: true merge-sql: true
slow-sql-millis: 1000 wall:
merge-sql: true config:
wall: multi-statement-allow: true
config:
multi-statement-allow: true
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) --- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring: spring:
@ -132,8 +142,6 @@ redisson:
threads: 4 threads: 4
# Netty线程池数量 # Netty线程池数量
nettyThreads: 8 nettyThreads: 8
# 传输模式
transportMode: "NIO"
# 单节点配置 # 单节点配置
singleServerConfig: singleServerConfig:
# 客户端名称 # 客户端名称
@ -146,9 +154,5 @@ redisson:
idleConnectionTimeout: 10000 idleConnectionTimeout: 10000
# 命令等待超时,单位:毫秒 # 命令等待超时,单位:毫秒
timeout: 3000 timeout: 3000
# 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。
retryAttempts: 3
# 命令重试发送时间间隔,单位:毫秒
retryInterval: 1500
# 发布和订阅连接池大小 # 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50 subscriptionConnectionPoolSize: 50

View File

@ -1,48 +1,37 @@
--- # 配置临时路径存储 --- # 临时文件存储位置 避免临时文件被系统清理报错
spring: spring.servlet.multipart.location: /ruoyi/server/temp
servlet:
multipart:
# 临时文件存储位置 避免临时文件被系统清理报错
location: /ruoyi/server/temp
--- # 监控配置 --- # 监控中心配置
spring: spring.boot.admin.client:
boot: # 增加客户端开关
admin: enabled: true
# Spring Boot Admin Client 客户端的相关配置 url: http://172.30.0.90:9090/admin
client: instance:
# 增加客户端开关 service-host-type: IP
enabled: true username: ruoyi
# 设置 Spring Boot Admin Server 地址 password: 123456
url: http://172.30.0.90:9090/admin
instance:
service-host-type: IP
username: ruoyi
password: 123456
--- # xxl-job 配置 --- # xxl-job 配置
xxl: xxl.job:
job: # 执行器开关
# 执行器开关 enabled: true
enabled: true # 调度中心地址:如调度中心集群部署存在多个地址则用逗号分隔。
# 调度中心地址:如调度中心集群部署存在多个地址则用逗号分隔。 admin-addresses: http://172.30.0.92:9100/xxl-job-admin
admin-addresses: http://172.30.0.92:9100/xxl-job-admin # 执行器通讯TOKEN非空时启用
# 执行器通讯TOKEN非空时启用 access-token: xxl-job
access-token: xxl-job executor:
# 执行器配置 # 执行器AppName执行器心跳注册分组依据为空则关闭自动注册
executor: appname: xxl-job-executor
# 执行器AppName执行器心跳注册分组依据为空则关闭自动注册 # 执行器端口号 执行器从9101开始往后写
appname: xxl-job-executor port: 9101
# 执行器端口号 执行器从9101开始往后写 # 执行器注册默认IP:PORT
port: 9101 address:
# 执行器注册默认IP:PORT # 执行器IP默认自动获取IP
address: ip:
# 执行器IP默认自动获取IP # 执行器运行日志文件存储磁盘路径
ip: logpath: ./logs/xxl-job
# 执行器运行日志文件存储磁盘路径 # 执行器日志文件保存天数大于3生效
logpath: ./logs/xxl-job logretentiondays: 30
# 执行器日志文件保存天数大于3生效
logretentiondays: 30
--- # 数据源配置 --- # 数据源配置
spring: spring:
@ -54,6 +43,8 @@ spring:
p6spy: false p6spy: false
# 设置默认的数据源或者数据源组,默认值即为 master # 设置默认的数据源或者数据源组,默认值即为 master
primary: master primary: master
# 严格模式 匹配不到数据源则报错
strict: true
datasource: datasource:
# 主库数据源 # 主库数据源
master: master:
@ -70,6 +61,23 @@ spring:
url: url:
username: username:
password: password:
# oracle:
# driverClassName: oracle.jdbc.OracleDriver
# url: jdbc:oracle:thin:@//172.30.0.36:1521/XE
# username: ROOT
# password: root
# druid:
# validationQuery: SELECT 1 FROM DUAL
# postgres:
# driverClassName: org.postgresql.Driver
# url: jdbc:postgresql://172.30.0.36:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
# username: root
# password: root
# sqlserver:
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
# url: jdbc:sqlserver://172.30.0.36:1433;DatabaseName=tempdb;SelectMethod=cursor;rewriteBatchedStatements=true
# username: SA
# password: root
druid: druid:
# 初始连接数 # 初始连接数
initialSize: 5 initialSize: 5
@ -86,7 +94,7 @@ spring:
# 配置一个连接在池中最大生存的时间,单位是毫秒 # 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000 maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效 # 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL validationQuery: SELECT 1
testWhileIdle: true testWhileIdle: true
testOnBorrow: false testOnBorrow: false
testOnReturn: false testOnReturn: false
@ -94,29 +102,27 @@ spring:
filters: stat filters: stat
--- # druid 配置 --- # druid 配置
spring: spring.datasource.druid:
datasource: webStatFilter:
druid: enabled: true
webStatFilter: statViewServlet:
enabled: true enabled: true
statViewServlet: # 设置白名单,不填则允许所有访问
enabled: true allow:
# 设置白名单,不填则允许所有访问 url-pattern: /druid/*
allow: # 控制台管理用户名和密码
url-pattern: /druid/* login-username: ruoyi
# 控制台管理用户名和密码 login-password: 123456
login-username: ruoyi filter:
login-password: 123456 stat:
filter: enabled: true
stat: # 慢SQL记录
enabled: true log-slow-sql: true
# 慢SQL记录 slow-sql-millis: 1000
log-slow-sql: true merge-sql: true
slow-sql-millis: 1000 wall:
merge-sql: true config:
wall: multi-statement-allow: true
config:
multi-statement-allow: true
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) --- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring: spring:
@ -139,8 +145,6 @@ redisson:
threads: 16 threads: 16
# Netty线程池数量 # Netty线程池数量
nettyThreads: 32 nettyThreads: 32
# 传输模式
transportMode: "NIO"
# 单节点配置 # 单节点配置
singleServerConfig: singleServerConfig:
# 客户端名称 # 客户端名称
@ -153,9 +157,5 @@ redisson:
idleConnectionTimeout: 10000 idleConnectionTimeout: 10000
# 命令等待超时,单位:毫秒 # 命令等待超时,单位:毫秒
timeout: 3000 timeout: 3000
# 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。
retryAttempts: 3
# 命令重试发送时间间隔,单位:毫秒
retryInterval: 1500
# 发布和订阅连接池大小 # 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50 subscriptionConnectionPoolSize: 50

View File

@ -75,10 +75,6 @@ spring:
restart: restart:
# 热部署开关 # 热部署开关
enabled: true enabled: true
# 与vue整合部署使用
thymeleaf:
# 将系统模板放置到最前面 否则会与 springboot-admin 页面冲突
template-resolver-order: 1
mvc: mvc:
pathmatch: pathmatch:
# 适配 boot 2.6 路由与 springfox 兼容 # 适配 boot 2.6 路由与 springfox 兼容
@ -107,16 +103,12 @@ sa-token:
is-concurrent: true is-concurrent: true
# 在多人登录同一账号时是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) # 在多人登录同一账号时是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
is-share: false is-share: false
# 是否尝试从请求体里读取token
is-read-body: false
# 是否尝试从header里读取token # 是否尝试从header里读取token
is-read-head: true is-read-head: true
# 是否尝试从cookie里读取token # 是否尝试从cookie里读取token
is-read-cookie: false is-read-cookie: false
# token前缀 # token前缀
token-prefix: "Bearer" token-prefix: "Bearer"
# token风格
token-style: uuid
# jwt秘钥 # jwt秘钥
jwt-secret-key: abcdefghijklmnopqrstuvwxyz jwt-secret-key: abcdefghijklmnopqrstuvwxyz
# 是否输出操作日志 # 是否输出操作日志
@ -127,6 +119,8 @@ security:
# 排除路径 # 排除路径
excludes: excludes:
- /login - /login
- /smsLogin
- /xcxLogin
- /logout - /logout
- /register - /register
- /captchaImage - /captchaImage
@ -136,23 +130,17 @@ security:
- /**/*.css - /**/*.css
- /**/*.js - /**/*.js
# swagger 文档配置 # swagger 文档配置
- /favicon.ico
- /doc.html - /doc.html
- /swagger-resources/** - /swagger-resources/**
- /webjars/** - /webjars/**
- /*/api-docs - /*/api-docs
# druid 监控配置 # druid 监控配置
- /druid/** - /druid/**
# 用户放行
permit-all:
# actuator 监控配置 # actuator 监控配置
- /actuator - /actuator
- /actuator/** - /actuator/**
# 重复提交
repeat-submit:
# 全局间隔时间(毫秒)
interval: 5000
# MyBatisPlus配置 # MyBatisPlus配置
# https://baomidou.com/config/ # https://baomidou.com/config/
mybatis-plus: mybatis-plus:
@ -165,25 +153,15 @@ mybatis-plus:
typeAliasesPackage: com.ruoyi.**.domain typeAliasesPackage: com.ruoyi.**.domain
# 启动时是否检查 MyBatis XML 文件的存在,默认不检查 # 启动时是否检查 MyBatis XML 文件的存在,默认不检查
checkConfigLocation: false checkConfigLocation: false
# 通过该属性可指定 MyBatis 的执行器MyBatis 的执行器总共有三种:
# SIMPLE每个语句创建新的预处理器 REUSE会复用预处理器 BATCH批量执行所有的更新
executorType: SIMPLE
configuration: configuration:
# 自动驼峰命名规则camel case映射 # 自动驼峰命名规则camel case映射
mapUnderscoreToCamelCase: true mapUnderscoreToCamelCase: true
# 当设置为 true 的时候,懒加载的对象可能被任何懒属性全部加载,否则,每个属性都按需加载。需要和 lazyLoadingEnabled 一起使用。
aggressiveLazyLoading: true
# MyBatis 自动映射策略 # MyBatis 自动映射策略
# NONE不启用 PARTIAL只对非嵌套 resultMap 自动映射 FULL对所有 resultMap 自动映射 # NONE不启用 PARTIAL只对非嵌套 resultMap 自动映射 FULL对所有 resultMap 自动映射
autoMappingBehavior: PARTIAL autoMappingBehavior: PARTIAL
# MyBatis 自动映射时未知列或未知属性处理策 # MyBatis 自动映射时未知列或未知属性处理策
# NONE不做处理 WARNING打印相关警告 FAILING抛出异常和详细信息 # NONE不做处理 WARNING打印相关警告 FAILING抛出异常和详细信息
autoMappingUnknownColumnBehavior: NONE autoMappingUnknownColumnBehavior: NONE
# Mybatis一级缓存默认为 SESSION
# SESSION session级别缓存 STATEMENT 关闭一级缓存
localCacheScope: SESSION
# 开启Mybatis二级缓存默认为 true
cacheEnabled: false
# 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl
# 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl
# 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl
@ -191,16 +169,10 @@ mybatis-plus:
global-config: global-config:
# 是否打印 Logo banner # 是否打印 Logo banner
banner: true banner: true
# 是否初始化 SqlRunner
enableSqlRunner: false
dbConfig: dbConfig:
# 主键类型 # 主键类型
# AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
idType: AUTO idType: ASSIGN_ID
# 表名是否使用驼峰转下划线命名,只对表名生效
tableUnderline: true
# 大写命名,对表名和字段名均生效
capitalMode: false
# 逻辑已删除值 # 逻辑已删除值
logicDeleteValue: 2 logicDeleteValue: 2
# 逻辑未删除值 # 逻辑未删除值
@ -271,20 +243,10 @@ xss:
thread-pool: thread-pool:
# 是否开启线程池 # 是否开启线程池
enabled: false enabled: false
# 核心线程池大小
corePoolSize: 8
# 最大可创建的线程数
maxPoolSize: 16
# 队列最大长度 # 队列最大长度
queueCapacity: 128 queueCapacity: 128
# 线程池维护线程所允许的空闲时间 # 线程池维护线程所允许的空闲时间
keepAliveSeconds: 300 keepAliveSeconds: 300
# 线程池对拒绝任务(无线程可用)的处理策略
# CALLER_RUNS_POLICY 调用方执行
# DISCARD_OLDEST_POLICY 放弃最旧的
# DISCARD_POLICY 丢弃
# ABORT_POLICY 中止
rejectedExecutionHandler: CALLER_RUNS_POLICY
--- # redisson 缓存配置 --- # redisson 缓存配置
redisson: redisson:
@ -312,8 +274,6 @@ lock4j:
management: management:
endpoints: endpoints:
web: web:
# Actuator 提供的 API 接口的根目录。默认为 /actuator
base-path: /actuator
exposure: exposure:
# 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
# 生产环境不建议放开所有 根据项目需求放开即可 # 生产环境不建议放开所有 根据项目需求放开即可

View File

@ -18,6 +18,7 @@ user.password.not.blank=用户密码不能为空
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
user.password.not.valid=* 5-50个字符 user.password.not.valid=* 5-50个字符
user.email.not.valid=邮箱格式错误 user.email.not.valid=邮箱格式错误
user.phonenumber.not.blank=用户手机号不能为空
user.mobile.phone.number.not.valid=手机号格式错误 user.mobile.phone.number.not.valid=手机号格式错误
user.login.success=登录成功 user.login.success=登录成功
user.register.success=注册成功 user.register.success=注册成功
@ -36,3 +37,9 @@ no.update.permission=您没有修改数据的权限,请联系管理员添加
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]
repeat.submit.message=不允许重复提交,请稍候再试
rate.limiter.message=访问过于频繁,请稍候再试
sms.code.not.blank=短信验证码不能为空
sms.code.retry.limit.count=短信验证码输入错误{0}次
sms.code.retry.limit.exceed=短信验证码错误次数过多,帐户锁定{0}分钟
xcx.code.not.blank=小程序code不能为空

View File

@ -18,6 +18,7 @@ user.password.not.blank=Password cannot be empty
user.password.length.valid=Password length must be between {min} and {max} characters user.password.length.valid=Password length must be between {min} and {max} characters
user.password.not.valid=* 5-50 characters user.password.not.valid=* 5-50 characters
user.email.not.valid=Mailbox format error user.email.not.valid=Mailbox format error
user.phonenumber.not.blank=Phone number cannot be blank
user.mobile.phone.number.not.valid=Phone number format error user.mobile.phone.number.not.valid=Phone number format error
user.login.success=Login successful user.login.success=Login successful
user.register.success=Register successful user.register.success=Register successful
@ -36,3 +37,9 @@ no.update.permission=You do not have permission to modify dataplease contact
no.delete.permission=You do not have permission to delete dataplease contact your administrator to add permissions [{0}] no.delete.permission=You do not have permission to delete dataplease contact your administrator to add permissions [{0}]
no.export.permission=You do not have permission to export dataplease contact your administrator to add permissions [{0}] no.export.permission=You do not have permission to export dataplease contact your administrator to add permissions [{0}]
no.view.permission=You do not have permission to view dataplease contact your administrator to add permissions [{0}] no.view.permission=You do not have permission to view dataplease contact your administrator to add permissions [{0}]
repeat.submit.message=Repeat submit is not allowed, please try again later
rate.limiter.message=Visit too frequently, please try again later
sms.code.not.blank=Sms code cannot be blank
sms.code.retry.limit.count=Sms code input error {0} times
sms.code.retry.limit.exceed=Too many sms code errors, account locked for {0} minutes
xcx.code.not.blank=Mini program code cannot be blank

View File

@ -18,6 +18,7 @@ user.password.not.blank=用户密码不能为空
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
user.password.not.valid=* 5-50个字符 user.password.not.valid=* 5-50个字符
user.email.not.valid=邮箱格式错误 user.email.not.valid=邮箱格式错误
user.phonenumber.not.blank=用户手机号不能为空
user.mobile.phone.number.not.valid=手机号格式错误 user.mobile.phone.number.not.valid=手机号格式错误
user.login.success=登录成功 user.login.success=登录成功
user.register.success=注册成功 user.register.success=注册成功
@ -36,3 +37,9 @@ no.update.permission=您没有修改数据的权限,请联系管理员添加
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]
repeat.submit.message=不允许重复提交,请稍候再试
rate.limiter.message=访问过于频繁,请稍候再试
sms.code.not.blank=短信验证码不能为空
sms.code.retry.limit.count=短信验证码输入错误{0}次
sms.code.retry.limit.exceed=短信验证码错误次数过多,帐户锁定{0}分钟
xcx.code.not.blank=小程序code不能为空

View File

@ -77,6 +77,26 @@
</filter> </filter>
</appender> </appender>
<!-- info异步输出 -->
<appender name="async_info" class="com.yomahub.tlog.core.enhance.logback.async.AspectLogbackAsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>512</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_info"/>
</appender>
<!-- error异步输出 -->
<appender name="async_error" class="com.yomahub.tlog.core.enhance.logback.async.AspectLogbackAsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>512</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_error"/>
</appender>
<!-- 系统模块日志级别控制 --> <!-- 系统模块日志级别控制 -->
<logger name="com.ruoyi" level="info" /> <logger name="com.ruoyi" level="info" />
<!-- Spring日志级别控制 --> <!-- Spring日志级别控制 -->
@ -88,8 +108,8 @@
<!--系统操作日志--> <!--系统操作日志-->
<root level="info"> <root level="info">
<appender-ref ref="file_info" /> <appender-ref ref="async_info" />
<appender-ref ref="file_error" /> <appender-ref ref="async_error" />
<appender-ref ref="file_console" /> <appender-ref ref="file_console" />
</root> </root>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi-vue-plus</artifactId> <artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>4.0.1</version> <version>4.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -69,11 +69,6 @@
<artifactId>easyexcel</artifactId> <artifactId>easyexcel</artifactId>
</dependency> </dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</dependency>
<!-- yml解析器 --> <!-- yml解析器 -->
<dependency> <dependency>
<groupId>org.yaml</groupId> <groupId>org.yaml</groupId>

View File

@ -22,8 +22,8 @@ public @interface RepeatSubmit {
TimeUnit timeUnit() default TimeUnit.MILLISECONDS; TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
/** /**
* 提示消息 * 提示消息 支持国际化 格式为 {code}
*/ */
String message() default "不允许重复提交,请稍候再试"; String message() default "{repeat.submit.message}";
} }

View File

@ -65,12 +65,12 @@ public interface Constants {
/** /**
* 登录用户 redis key * 登录用户 redis key
*/ */
public static final String LOGIN_TOKEN_KEY = "Authorization:login:token:"; String LOGIN_TOKEN_KEY = "Authorization:login:token:";
/** /**
* 在线用户 redis key * 在线用户 redis key
*/ */
public static final String ONLINE_TOKEN_KEY = "online_tokens:"; String ONLINE_TOKEN_KEY = "online_tokens:";
/** /**
* 防重提交 redis key * 防重提交 redis key

View File

@ -22,11 +22,21 @@ public interface UserConstants {
*/ */
String EXCEPTION = "1"; String EXCEPTION = "1";
/**
* 用户正常状态
*/
String USER_NORMAL = "0";
/** /**
* 用户封禁状态 * 用户封禁状态
*/ */
String USER_DISABLE = "1"; String USER_DISABLE = "1";
/**
* 角色正常状态
*/
String ROLE_NORMAL = "0";
/** /**
* 角色封禁状态 * 角色封禁状态
*/ */
@ -62,6 +72,16 @@ public interface UserConstants {
*/ */
String NO_FRAME = "1"; String NO_FRAME = "1";
/**
* 菜单正常状态
*/
String MENU_NORMAL = "0";
/**
* 菜单停用状态
*/
String MENU_DISABLE = "1";
/** /**
* 菜单类型目录 * 菜单类型目录
*/ */

View File

@ -16,7 +16,7 @@ import java.util.List;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class TreeEntity extends BaseEntity { public class TreeEntity<T> extends BaseEntity {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -38,6 +38,6 @@ public class TreeEntity extends BaseEntity {
*/ */
@TableField(exist = false) @TableField(exist = false)
@ApiModelProperty(value = "子部门") @ApiModelProperty(value = "子部门")
private List<?> children = new ArrayList<>(); private List<T> children = new ArrayList<>();
} }

View File

@ -24,7 +24,7 @@ import javax.validation.constraints.Size;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@TableName("sys_dept") @TableName("sys_dept")
@ApiModel("部门业务对象") @ApiModel("部门业务对象")
public class SysDept extends TreeEntity { public class SysDept extends TreeEntity<SysDept> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
@ -47,7 +47,7 @@ public class SysDept extends TreeEntity {
*/ */
@ApiModelProperty(value = "显示顺序") @ApiModelProperty(value = "显示顺序")
@NotNull(message = "显示顺序不能为空") @NotNull(message = "显示顺序不能为空")
private Long orderNum; private Integer orderNum;
/** /**
* 负责人 * 负责人

View File

@ -42,7 +42,7 @@ public class SysDictData extends BaseEntity {
*/ */
@ApiModelProperty(value = "字典排序") @ApiModelProperty(value = "字典排序")
@ExcelProperty(value = "字典排序") @ExcelProperty(value = "字典排序")
private Long dictSort; private Integer dictSort;
/** /**
* 字典标签 * 字典标签

View File

@ -14,6 +14,7 @@ import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
/** /**
@ -53,6 +54,7 @@ public class SysDictType extends BaseEntity {
@ExcelProperty(value = "字典类型") @ExcelProperty(value = "字典类型")
@NotBlank(message = "字典类型不能为空") @NotBlank(message = "字典类型不能为空")
@Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符") @Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符")
@Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)")
private String dictType; private String dictType;
/** /**

View File

@ -1,8 +1,8 @@
package com.ruoyi.common.core.domain.entity; package com.ruoyi.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.ruoyi.common.core.domain.TreeEntity; import com.ruoyi.common.core.domain.TreeEntity;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
@ -23,7 +23,7 @@ import javax.validation.constraints.Size;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@TableName("sys_menu") @TableName("sys_menu")
@ApiModel("菜单权限业务对象") @ApiModel("菜单权限业务对象")
public class SysMenu extends TreeEntity { public class SysMenu extends TreeEntity<SysMenu> {
/** /**
* 菜单ID * 菜单ID
@ -45,7 +45,7 @@ public class SysMenu extends TreeEntity {
*/ */
@ApiModelProperty(value = "显示顺序") @ApiModelProperty(value = "显示顺序")
@NotNull(message = "显示顺序不能为空") @NotNull(message = "显示顺序不能为空")
private Long orderNum; private Integer orderNum;
/** /**
* 路由地址 * 路由地址
@ -65,8 +65,7 @@ public class SysMenu extends TreeEntity {
* 路由参数 * 路由参数
*/ */
@ApiModelProperty(value = "路由参数") @ApiModelProperty(value = "路由参数")
@TableField("`query`") private String queryParam;
private String query;
/** /**
* 是否为外链0是 1否 * 是否为外链0是 1否
@ -103,6 +102,7 @@ public class SysMenu extends TreeEntity {
* 权限字符串 * 权限字符串
*/ */
@ApiModelProperty(value = "权限字符串") @ApiModelProperty(value = "权限字符串")
@JsonInclude(JsonInclude.Include.NON_NULL)
@Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符") @Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符")
private String perms; private String perms;

View File

@ -16,6 +16,7 @@ import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
/** /**
@ -62,8 +63,8 @@ public class SysRole extends BaseEntity {
*/ */
@ApiModelProperty(value = "角色排序") @ApiModelProperty(value = "角色排序")
@ExcelProperty(value = "角色排序") @ExcelProperty(value = "角色排序")
@NotBlank(message = "显示顺序不能为空") @NotNull(message = "显示顺序不能为空")
private String roleSort; private Integer roleSort;
/** /**
* 数据范围1所有数据权限2自定义数据权限3本部门数据权限4本部门及以下数据权限5仅本人数据权限 * 数据范围1所有数据权限2自定义数据权限3本部门数据权限4本部门及以下数据权限5仅本人数据权限
@ -77,13 +78,13 @@ public class SysRole extends BaseEntity {
* 菜单树选择项是否关联显示 0父子不互相关联显示 1父子互相关联显示 * 菜单树选择项是否关联显示 0父子不互相关联显示 1父子互相关联显示
*/ */
@ApiModelProperty(value = "菜单树选择项是否关联显示( 0父子不互相关联显示 1父子互相关联显示") @ApiModelProperty(value = "菜单树选择项是否关联显示( 0父子不互相关联显示 1父子互相关联显示")
private boolean menuCheckStrictly; private Boolean menuCheckStrictly;
/** /**
* 部门树选择项是否关联显示0父子不互相关联显示 1父子互相关联显示 * 部门树选择项是否关联显示0父子不互相关联显示 1父子互相关联显示
*/ */
@ApiModelProperty(value = "部门树选择项是否关联显示0父子不互相关联显示 1父子互相关联显示 ") @ApiModelProperty(value = "部门树选择项是否关联显示0父子不互相关联显示 1父子互相关联显示 ")
private boolean deptCheckStrictly; private Boolean deptCheckStrictly;
/** /**
* 角色状态0正常 1停用 * 角色状态0正常 1停用
@ -135,5 +136,4 @@ public class SysRole extends BaseEntity {
public boolean isAdmin() { public boolean isAdmin() {
return UserConstants.ADMIN_ID.equals(this.roleId); return UserConstants.ADMIN_ID.equals(this.roleId);
} }
} }

View File

@ -0,0 +1,33 @@
package com.ruoyi.common.core.domain.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 短信登录对象
*
* @author Lion Li
*/
@Data
@ApiModel("短信登录对象")
public class SmsLoginBody {
/**
* 用户名
*/
@NotBlank(message = "{user.phonenumber.not.blank}")
@ApiModelProperty(value = "用户手机号")
private String phonenumber;
/**
* 用户密码
*/
@NotBlank(message = "{sms.code.not.blank}")
@ApiModelProperty(value = "短信验证码")
private String smsCode;
}

View File

@ -0,0 +1,24 @@
package com.ruoyi.common.core.domain.model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* 小程序登录用户身份权限
*
* @author Lion Li
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public class XcxLoginUser extends LoginUser {
private static final long serialVersionUID = 1L;
/**
* openid
*/
private String openid;
}

View File

@ -0,0 +1,49 @@
package com.ruoyi.common.enums;
import com.ruoyi.common.utils.StringUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 数据库类型
*
* @author Lion Li
*/
@Getter
@AllArgsConstructor
public enum DataBaseType {
/**
* MySQL
*/
MY_SQL("MySQL"),
/**
* Oracle
*/
ORACLE("Oracle"),
/**
* PostgreSQL
*/
POSTGRE_SQL("PostgreSQL"),
/**
* SQL Server
*/
SQL_SERVER("Microsoft SQL Server");
private final String type;
public static DataBaseType find(String databaseProductName) {
if (StringUtils.isBlank(databaseProductName)) {
return null;
}
for (DataBaseType type : values()) {
if (type.getType().equals(databaseProductName)) {
return type;
}
}
return null;
}
}

View File

@ -21,7 +21,12 @@ public enum DeviceType {
/** /**
* app端 * app端
*/ */
APP("app"); APP("app"),
/**
* 小程序端
*/
XCX("xcx");
private final String device; private final String device;
} }

View File

@ -0,0 +1,39 @@
package com.ruoyi.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 登录类型
*
* @author Lion Li
*/
@Getter
@AllArgsConstructor
public enum LoginType {
/**
* 密码登录
*/
PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"),
/**
* 短信登录
*/
SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"),
/**
* 小程序登录
*/
XCX("", "");
/**
* 登录重试超出限制提示
*/
final String retryLimitExceed;
/**
* 登录重试限制计数提示
*/
final String retryLimitCount;
}

View File

@ -1,26 +0,0 @@
package com.ruoyi.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 线程池 拒绝策略 泛型
*
* @author Lion Li
*/
@Getter
@AllArgsConstructor
public enum ThreadPoolRejectedPolicy {
CALLER_RUNS_POLICY("调用方执行", ThreadPoolExecutor.CallerRunsPolicy.class),
DISCARD_OLDEST_POLICY("放弃最旧的", ThreadPoolExecutor.DiscardOldestPolicy.class),
DISCARD_POLICY("丢弃", ThreadPoolExecutor.DiscardPolicy.class),
ABORT_POLICY("中止", ThreadPoolExecutor.AbortPolicy.class);
private final String name;
private final Class<? extends RejectedExecutionHandler> clazz;
}

View File

@ -0,0 +1,72 @@
package com.ruoyi.common.helper;
import cn.hutool.core.convert.Convert;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.ruoyi.common.enums.DataBaseType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
/**
* 数据库助手
*
* @author Lion Li
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class DataBaseHelper {
private static final DynamicRoutingDataSource DS = SpringUtils.getBean(DynamicRoutingDataSource.class);
/**
* 获取当前数据库类型
*/
public static DataBaseType getDataBaseType() {
DataSource dataSource = DS.determineDataSource();
try (Connection conn = dataSource.getConnection()) {
DatabaseMetaData metaData = conn.getMetaData();
String databaseProductName = metaData.getDatabaseProductName();
return DataBaseType.find(databaseProductName);
} catch (SQLException e) {
throw new ServiceException(e.getMessage());
}
}
public static boolean isMySql() {
return DataBaseType.MY_SQL == getDataBaseType();
}
public static boolean isOracle() {
return DataBaseType.ORACLE == getDataBaseType();
}
public static boolean isPostgerSql() {
return DataBaseType.POSTGRE_SQL == getDataBaseType();
}
public static boolean isSqlServer() {
return DataBaseType.SQL_SERVER == getDataBaseType();
}
public static String findInSet(Object var1, String var2) {
DataBaseType dataBasyType = getDataBaseType();
String var = Convert.toStr(var1);
if (dataBasyType == DataBaseType.SQL_SERVER) {
// charindex(',100,' , ',0,100,101,') <> 0
return "charindex('," + var + ",' , ','+" + var2 + "+',') <> 0";
} else if (dataBasyType == DataBaseType.POSTGRE_SQL) {
// (select position(',100,' in ',0,100,101,')) <> 0
return "(select position('," + var + ",' in ','||" + var2 + "||',')) <> 0";
} else if (dataBasyType == DataBaseType.ORACLE) {
// instr(',0,100,101,' , ',100,') <> 0
return "instr(','||" + var2 + "||',' , '," + var + ",') <> 0";
}
// find_in_set(100 , '0,100,101')
return "find_in_set(" + var + " , " + var2 + ") <> 0";
}
}

View File

@ -1,15 +1,20 @@
package com.ruoyi.common.utils; package com.ruoyi.common.utils;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.SimpleCache;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.ReflectUtil;
import cn.hutool.extra.cglib.CglibUtil; import cn.hutool.core.util.StrUtil;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.cglib.core.Converter;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
/** /**
* bean深拷贝工具(基于 cglib 性能优异) * bean深拷贝工具(基于 cglib 性能优异)
@ -37,7 +42,8 @@ public class BeanCopyUtils {
if (ObjectUtil.isNull(desc)) { if (ObjectUtil.isNull(desc)) {
return null; return null;
} }
return CglibUtil.copy(source, desc); final V target = ReflectUtil.newInstanceIfPossible(desc);
return copy(source, target);
} }
/** /**
@ -54,7 +60,8 @@ public class BeanCopyUtils {
if (ObjectUtil.isNull(desc)) { if (ObjectUtil.isNull(desc)) {
return null; return null;
} }
CglibUtil.copy(source, desc); BeanCopier beanCopier = BeanCopierCache.INSTANCE.get(source.getClass(), desc.getClass(), null);
beanCopier.copy(source, desc, null);
return desc; return desc;
} }
@ -72,7 +79,11 @@ public class BeanCopyUtils {
if (CollUtil.isEmpty(sourceList)) { if (CollUtil.isEmpty(sourceList)) {
return CollUtil.newArrayList(); return CollUtil.newArrayList();
} }
return CglibUtil.copyList(sourceList, () -> ReflectUtil.newInstanceIfPossible(desc)); return sourceList.stream().map(source -> {
V target = ReflectUtil.newInstanceIfPossible(desc);
copy(source, target);
return target;
}).collect(Collectors.toList());
} }
/** /**
@ -81,11 +92,12 @@ public class BeanCopyUtils {
* @param bean 数据来源实体 * @param bean 数据来源实体
* @return map对象 * @return map对象
*/ */
@SuppressWarnings("unchecked")
public static <T> Map<String, Object> copyToMap(T bean) { public static <T> Map<String, Object> copyToMap(T bean) {
if (ObjectUtil.isNull(bean)) { if (ObjectUtil.isNull(bean)) {
return null; return null;
} }
return CglibUtil.toMap(bean); return BeanMap.create(bean);
} }
/** /**
@ -102,7 +114,8 @@ public class BeanCopyUtils {
if (ObjectUtil.isNull(beanClass)) { if (ObjectUtil.isNull(beanClass)) {
return null; return null;
} }
return CglibUtil.toBean(map, beanClass); T bean = ReflectUtil.newInstanceIfPossible(beanClass);
return mapToBean(map, bean);
} }
/** /**
@ -119,6 +132,54 @@ public class BeanCopyUtils {
if (ObjectUtil.isNull(bean)) { if (ObjectUtil.isNull(bean)) {
return null; return null;
} }
return CglibUtil.fillBean(map, bean); BeanMap.create(bean).putAll(map);
return bean;
} }
/**
* BeanCopier属性缓存<br>
* 缓存用于防止多次反射造成的性能问题
*
* @author Looly
* @since 5.4.1
*/
public enum BeanCopierCache {
/**
* BeanCopier属性缓存单例
*/
INSTANCE;
private final SimpleCache<String, BeanCopier> cache = new SimpleCache<>();
/**
* 获得类与转换器生成的key在{@link BeanCopier}的Map中对应的元素
*
* @param srcClass 源Bean的类
* @param targetClass 目标Bean的类
* @param converter 转换器
* @return Map中对应的BeanCopier
*/
public BeanCopier get(Class<?> srcClass, Class<?> targetClass, Converter converter) {
final String key = genKey(srcClass, targetClass, converter);
return cache.get(key, () -> BeanCopier.create(srcClass, targetClass, converter != null));
}
/**
* 获得类与转换器生成的key
*
* @param srcClass 源Bean的类
* @param targetClass 目标Bean的类
* @param converter 转换器
* @return 属性名和Map映射的key
*/
private String genKey(Class<?> srcClass, Class<?> targetClass, Converter converter) {
final StringBuilder key = StrUtil.builder()
.append(srcClass.getName()).append('#').append(targetClass.getName());
if(null != converter){
key.append('#').append(converter.getClass().getName());
}
return key.toString();
}
}
} }

View File

@ -22,17 +22,17 @@ import java.util.Date;
@NoArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PRIVATE)
public class DateUtils extends org.apache.commons.lang3.time.DateUtils { public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
public static String YYYY = "yyyy"; public static final String YYYY = "yyyy";
public static String YYYY_MM = "yyyy-MM"; public static final String YYYY_MM = "yyyy-MM";
public static String YYYY_MM_DD = "yyyy-MM-dd"; public static final String YYYY_MM_DD = "yyyy-MM-dd";
public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss"; public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
private static String[] parsePatterns = { private static final String[] PARSE_PATTERNS = {
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"}; "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
@ -55,27 +55,27 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
return dateTimeNow(YYYY_MM_DD); return dateTimeNow(YYYY_MM_DD);
} }
public static final String getTime() { public static String getTime() {
return dateTimeNow(YYYY_MM_DD_HH_MM_SS); return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
} }
public static final String dateTimeNow() { public static String dateTimeNow() {
return dateTimeNow(YYYYMMDDHHMMSS); return dateTimeNow(YYYYMMDDHHMMSS);
} }
public static final String dateTimeNow(final String format) { public static String dateTimeNow(final String format) {
return parseDateToStr(format, new Date()); return parseDateToStr(format, new Date());
} }
public static final String dateTime(final Date date) { public static String dateTime(final Date date) {
return parseDateToStr(YYYY_MM_DD, date); return parseDateToStr(YYYY_MM_DD, date);
} }
public static final String parseDateToStr(final String format, final Date date) { public static String parseDateToStr(final String format, final Date date) {
return new SimpleDateFormat(format).format(date); return new SimpleDateFormat(format).format(date);
} }
public static final Date dateTime(final String format, final String ts) { public static Date dateTime(final String format, final String ts) {
try { try {
return new SimpleDateFormat(format).parse(ts); return new SimpleDateFormat(format).parse(ts);
} catch (ParseException e) { } catch (ParseException e) {
@ -86,7 +86,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
/** /**
* 日期路径 即年// 如2018/08/08 * 日期路径 即年// 如2018/08/08
*/ */
public static final String datePath() { public static String datePath() {
Date now = new Date(); Date now = new Date();
return DateFormatUtils.format(now, "yyyy/MM/dd"); return DateFormatUtils.format(now, "yyyy/MM/dd");
} }
@ -94,7 +94,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
/** /**
* 日期路径 即年// 如20180808 * 日期路径 即年// 如20180808
*/ */
public static final String dateTime() { public static String dateTime() {
Date now = new Date(); Date now = new Date();
return DateFormatUtils.format(now, "yyyyMMdd"); return DateFormatUtils.format(now, "yyyyMMdd");
} }
@ -107,7 +107,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
return null; return null;
} }
try { try {
return parseDate(str.toString(), parsePatterns); return parseDate(str.toString(), PARSE_PATTERNS);
} catch (ParseException e) { } catch (ParseException e) {
return null; return null;
} }
@ -124,8 +124,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
/** /**
* 计算相差天数 * 计算相差天数
*/ */
public static int differentDaysByMillisecond(Date date1, Date date2) public static int differentDaysByMillisecond(Date date1, Date date2) {
{
return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24))); return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
} }

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi-vue-plus</artifactId> <artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>4.0.1</version> <version>4.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -45,7 +45,7 @@ public class TestBatchController extends BaseController {
List<TestDemo> list = new ArrayList<>(); List<TestDemo> list = new ArrayList<>();
for (int i = 0; i < 1000; i++) { for (int i = 0; i < 1000; i++) {
TestDemo testDemo = new TestDemo(); TestDemo testDemo = new TestDemo();
testDemo.setOrderNum(-1L); testDemo.setOrderNum(-1);
testDemo.setTestKey("批量新增"); testDemo.setTestKey("批量新增");
testDemo.setValue("测试新增"); testDemo.setValue("测试新增");
list.add(testDemo); list.add(testDemo);
@ -65,7 +65,7 @@ public class TestBatchController extends BaseController {
List<TestDemo> list = new ArrayList<>(); List<TestDemo> list = new ArrayList<>();
for (int i = 0; i < 1000; i++) { for (int i = 0; i < 1000; i++) {
TestDemo testDemo = new TestDemo(); TestDemo testDemo = new TestDemo();
testDemo.setOrderNum(-1L); testDemo.setOrderNum(-1);
testDemo.setTestKey("批量新增"); testDemo.setTestKey("批量新增");
testDemo.setValue("测试新增"); testDemo.setValue("测试新增");
list.add(testDemo); } list.add(testDemo); }

View File

@ -117,7 +117,7 @@ public class TestDemoController extends BaseController {
@ApiOperation("新增测试单表") @ApiOperation("新增测试单表")
@SaCheckPermission("demo:demo:add") @SaCheckPermission("demo:demo:add")
@Log(title = "测试单表", businessType = BusinessType.INSERT) @Log(title = "测试单表", businessType = BusinessType.INSERT)
@RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "不允许重复提交") @RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "{repeat.submit.message}")
@PostMapping() @PostMapping()
public R<Void> add(@RequestBody TestDemoBo bo) { public R<Void> add(@RequestBody TestDemoBo bo) {
// 使用校验工具对标 @Validated(AddGroup.class) 注解 // 使用校验工具对标 @Validated(AddGroup.class) 注解

View File

@ -39,7 +39,7 @@ public class TestDemo extends BaseEntity {
* 排序号 * 排序号
*/ */
@OrderBy(asc = false, sort = 1) @OrderBy(asc = false, sort = 1)
private Long orderNum; private Integer orderNum;
/** /**
* key键 * key键

View File

@ -17,7 +17,7 @@ import lombok.EqualsAndHashCode;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@TableName("test_tree") @TableName("test_tree")
public class TestTree extends TreeEntity { public class TestTree extends TreeEntity<TestTree> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -21,7 +21,7 @@ import javax.validation.constraints.NotNull;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ApiModel("测试树表业务对象") @ApiModel("测试树表业务对象")
public class TestTreeBo extends TreeEntity { public class TestTreeBo extends TreeEntity<TestTreeBo> {
/** /**
* 主键 * 主键

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi-vue-plus</artifactId> <artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>4.0.1</version> <version>4.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-extend</artifactId> <artifactId>ruoyi-extend</artifactId>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi-extend</artifactId> <artifactId>ruoyi-extend</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>4.0.1</version> <version>4.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -4,14 +4,12 @@
<parent> <parent>
<artifactId>ruoyi-extend</artifactId> <artifactId>ruoyi-extend</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>4.0.1</version> <version>4.1.0</version>
</parent> </parent>
<artifactId>ruoyi-xxl-job-admin</artifactId> <artifactId>ruoyi-xxl-job-admin</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<properties> <properties>
<mybatis-spring-boot-starter.version>2.1.4</mybatis-spring-boot-starter.version>
<mysql-connector-java.version>8.0.23</mysql-connector-java.version>
</properties> </properties>
<dependencyManagement> <dependencyManagement>
@ -62,13 +60,12 @@
<dependency> <dependency>
<groupId>org.mybatis.spring.boot</groupId> <groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId> <artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot-starter.version}</version> <version>${spring-boot.mybatis}</version>
</dependency> </dependency>
<!-- mysql --> <!-- mysql -->
<dependency> <dependency>
<groupId>mysql</groupId> <groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId> <artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi-vue-plus</artifactId> <artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>4.0.1</version> <version>4.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -3,6 +3,7 @@ package com.ruoyi.framework.aspectj;
import com.ruoyi.common.annotation.RateLimiter; import com.ruoyi.common.annotation.RateLimiter;
import com.ruoyi.common.enums.LimitType; import com.ruoyi.common.enums.LimitType;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.redis.RedisUtils; import com.ruoyi.common.utils.redis.RedisUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -37,7 +38,7 @@ public class RateLimiterAspect {
} }
long number = RedisUtils.rateLimiter(combineKey, rateType, count, time); long number = RedisUtils.rateLimiter(combineKey, rateType, count, time);
if (number == -1) { if (number == -1) {
throw new ServiceException("访问过于频繁,请稍候再试"); throw new ServiceException(MessageUtils.message("rate.limiter.message"));
} }
log.info("限制令牌 => {}, 剩余令牌 => {}, 缓存key => '{}'", count, number, combineKey); log.info("限制令牌 => {}, 剩余令牌 => {}, 缓存key => '{}'", count, number, combineKey);
} catch (ServiceException e) { } catch (ServiceException e) {

View File

@ -5,15 +5,18 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.SecureUtil;
import com.ruoyi.common.annotation.RepeatSubmit; import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.JsonUtils; import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.redis.RedisUtils; import com.ruoyi.common.utils.redis.RedisUtils;
import com.ruoyi.framework.config.properties.RepeatSubmitProperties;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -27,7 +30,7 @@ import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* 防止重复提交 * 防止重复提交(参考美团GTIS防重系统)
* *
* @author Lion Li * @author Lion Li
*/ */
@ -37,12 +40,12 @@ import java.util.concurrent.TimeUnit;
@Component @Component
public class RepeatSubmitAspect { public class RepeatSubmitAspect {
private final RepeatSubmitProperties repeatSubmitProperties; private static final ThreadLocal<String> KEY_CACHE = new ThreadLocal<>();
@Before("@annotation(repeatSubmit)") @Before("@annotation(repeatSubmit)")
public void doBefore(JoinPoint point, RepeatSubmit repeatSubmit) throws Throwable { public void doBefore(JoinPoint point, RepeatSubmit repeatSubmit) throws Throwable {
// 如果注解不为0 则使用注解数值 // 如果注解不为0 则使用注解数值
long interval = repeatSubmitProperties.getInterval(); long interval = 0;
if (repeatSubmit.interval() > 0) { if (repeatSubmit.interval() > 0) {
interval = repeatSubmit.timeUnit().toMillis(repeatSubmit.interval()); interval = repeatSubmit.timeUnit().toMillis(repeatSubmit.interval());
} }
@ -64,11 +67,45 @@ public class RepeatSubmitAspect {
String key = RedisUtils.getCacheObject(cacheRepeatKey); String key = RedisUtils.getCacheObject(cacheRepeatKey);
if (key == null) { if (key == null) {
RedisUtils.setCacheObject(cacheRepeatKey, "", interval, TimeUnit.MILLISECONDS); RedisUtils.setCacheObject(cacheRepeatKey, "", interval, TimeUnit.MILLISECONDS);
KEY_CACHE.set(cacheRepeatKey);
} else { } else {
throw new ServiceException(repeatSubmit.message()); String message = repeatSubmit.message();
if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) {
message = MessageUtils.message(StringUtils.substring(message, 1, message.length() - 1));
}
throw new ServiceException(message);
} }
} }
/**
* 处理完请求后执行
*
* @param joinPoint 切点
*/
@AfterReturning(pointcut = "@annotation(repeatSubmit)", returning = "jsonResult")
public void doAfterReturning(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Object jsonResult) {
if (jsonResult instanceof R) {
R<?> r = (R<?>) jsonResult;
if (r.getCode() == R.SUCCESS) {
return;
}
RedisUtils.deleteObject(KEY_CACHE.get());
KEY_CACHE.remove();
}
}
/**
* 拦截异常操作
*
* @param joinPoint 切点
* @param e 异常
*/
@AfterThrowing(value = "@annotation(repeatSubmit)", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Exception e) {
RedisUtils.deleteObject(KEY_CACHE.get());
KEY_CACHE.remove();
}
/** /**
* 参数拼装 * 参数拼装
*/ */

View File

@ -18,10 +18,10 @@ import java.awt.*;
@Configuration @Configuration
public class CaptchaConfig { public class CaptchaConfig {
private final int width = 160; private static final int WIDTH = 160;
private final int height = 60; private static final int HEIGHT = 60;
private final Color background = Color.PINK; private static final Color BACKGROUND = Color.PINK;
private final Font font = new Font("Arial", Font.BOLD, 48); private static final Font FONT = new Font("Arial", Font.BOLD, 48);
/** /**
* 圆圈干扰验证码 * 圆圈干扰验证码
@ -29,9 +29,9 @@ public class CaptchaConfig {
@Lazy @Lazy
@Bean @Bean
public CircleCaptcha circleCaptcha() { public CircleCaptcha circleCaptcha() {
CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(width, height); CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(WIDTH, HEIGHT);
captcha.setBackground(background); captcha.setBackground(BACKGROUND);
captcha.setFont(font); captcha.setFont(FONT);
return captcha; return captcha;
} }
@ -41,9 +41,9 @@ public class CaptchaConfig {
@Lazy @Lazy
@Bean @Bean
public LineCaptcha lineCaptcha() { public LineCaptcha lineCaptcha() {
LineCaptcha captcha = CaptchaUtil.createLineCaptcha(width, height); LineCaptcha captcha = CaptchaUtil.createLineCaptcha(WIDTH, HEIGHT);
captcha.setBackground(background); captcha.setBackground(BACKGROUND);
captcha.setFont(font); captcha.setFont(FONT);
return captcha; return captcha;
} }
@ -53,9 +53,9 @@ public class CaptchaConfig {
@Lazy @Lazy
@Bean @Bean
public ShearCaptcha shearCaptcha() { public ShearCaptcha shearCaptcha() {
ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(width, height); ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(WIDTH, HEIGHT);
captcha.setBackground(background); captcha.setBackground(BACKGROUND);
captcha.setFont(font); captcha.setFont(FONT);
return captcha; return captcha;
} }

View File

@ -53,8 +53,7 @@ public class RedisConfig extends CachingConfigurerSupport {
Config config = new Config(); Config config = new Config();
config.setThreads(redissonProperties.getThreads()) config.setThreads(redissonProperties.getThreads())
.setNettyThreads(redissonProperties.getNettyThreads()) .setNettyThreads(redissonProperties.getNettyThreads())
.setCodec(JsonJacksonCodec.INSTANCE) .setCodec(JsonJacksonCodec.INSTANCE);
.setTransportMode(redissonProperties.getTransportMode());
RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig(); RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig();
if (ObjectUtil.isNotNull(singleServerConfig)) { if (ObjectUtil.isNotNull(singleServerConfig)) {
@ -65,8 +64,6 @@ public class RedisConfig extends CachingConfigurerSupport {
.setDatabase(redisProperties.getDatabase()) .setDatabase(redisProperties.getDatabase())
.setPassword(StringUtils.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null) .setPassword(StringUtils.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null)
.setTimeout(singleServerConfig.getTimeout()) .setTimeout(singleServerConfig.getTimeout())
.setRetryAttempts(singleServerConfig.getRetryAttempts())
.setRetryInterval(singleServerConfig.getRetryInterval())
.setClientName(singleServerConfig.getClientName()) .setClientName(singleServerConfig.getClientName())
.setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout()) .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout())
.setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize()) .setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize())
@ -87,11 +84,8 @@ public class RedisConfig extends CachingConfigurerSupport {
.setConnectTimeout(((Long) redisProperties.getTimeout().toMillis()).intValue()) .setConnectTimeout(((Long) redisProperties.getTimeout().toMillis()).intValue())
.setPassword(StringUtils.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null) .setPassword(StringUtils.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null)
.setTimeout(clusterServersConfig.getTimeout()) .setTimeout(clusterServersConfig.getTimeout())
.setRetryAttempts(clusterServersConfig.getRetryAttempts())
.setRetryInterval(clusterServersConfig.getRetryInterval())
.setClientName(clusterServersConfig.getClientName()) .setClientName(clusterServersConfig.getClientName())
.setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout()) .setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout())
.setPingConnectionInterval(clusterServersConfig.getPingConnectionInterval())
.setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize()) .setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize())
.setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize()) .setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize())
.setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize()) .setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize())
@ -144,8 +138,6 @@ public class RedisConfig extends CachingConfigurerSupport {
* threads: 16 * threads: 16
* # Netty线程池数量 * # Netty线程池数量
* nettyThreads: 32 * nettyThreads: 32
* # 传输模式
* transportMode: "NIO"
* # 集群配置 * # 集群配置
* clusterServersConfig: * clusterServersConfig:
* # 客户端名称 * # 客户端名称
@ -160,14 +152,8 @@ public class RedisConfig extends CachingConfigurerSupport {
* slaveConnectionPoolSize: 64 * slaveConnectionPoolSize: 64
* # 连接空闲超时单位毫秒 * # 连接空闲超时单位毫秒
* idleConnectionTimeout: 10000 * idleConnectionTimeout: 10000
* # ping连接间隔
* pingConnectionInterval: 1000
* # 命令等待超时单位毫秒 * # 命令等待超时单位毫秒
* timeout: 3000 * timeout: 3000
* # 如果尝试在此限制之内发送成功则开始启用 timeout 计时
* retryAttempts: 3
* # 命令重试发送时间间隔单位毫秒
* retryInterval: 1500
* # 发布和订阅连接池大小 * # 发布和订阅连接池大小
* subscriptionConnectionPoolSize: 50 * subscriptionConnectionPoolSize: 50
* # 读取模式 * # 读取模式

View File

@ -5,7 +5,7 @@ import cn.dev33.satoken.interceptor.SaRouteInterceptor;
import cn.dev33.satoken.jwt.StpLogicJwtForStyle; import cn.dev33.satoken.jwt.StpLogicJwtForStyle;
import cn.dev33.satoken.router.SaRouter; import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpLogic;
import cn.hutool.core.util.ObjectUtil; import cn.dev33.satoken.stp.StpUtil;
import com.ruoyi.common.helper.LoginHelper; import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.framework.config.properties.SecurityProperties; import com.ruoyi.framework.config.properties.SecurityProperties;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -43,15 +43,17 @@ public class SaTokenConfig implements WebMvcConfigurer {
.match("/**") .match("/**")
// 排除下不需要拦截的 // 排除下不需要拦截的
.notMatch(securityProperties.getExcludes()) .notMatch(securityProperties.getExcludes())
// 对未排除的路径进行检查
.check(() -> { .check(() -> {
Long userId = LoginHelper.getUserId(); // 检查是否登录 是否有token
if (ObjectUtil.isNotNull(userId)) { StpUtil.checkLogin();
// 有效率影响 用于临时测试
// if (log.isDebugEnabled()) { // 有效率影响 用于临时测试
// log.debug("剩余有效时间: {}", StpUtil.getTokenTimeout()); // if (log.isDebugEnabled()) {
// log.debug("临时有效时间: {}", StpUtil.getTokenActivityTimeout()); // log.debug("剩余有效时间: {}", StpUtil.getTokenTimeout());
// } // log.debug("临时有效时间: {}", StpUtil.getTokenActivityTimeout());
} // }
}); });
}) { }) {
@SuppressWarnings("all") @SuppressWarnings("all")

View File

@ -1,7 +1,6 @@
package com.ruoyi.framework.config; package com.ruoyi.framework.config;
import com.ruoyi.common.utils.Threads; import com.ruoyi.common.utils.Threads;
import com.ruoyi.common.utils.reflect.ReflectUtils;
import com.ruoyi.framework.config.properties.ThreadPoolProperties; import com.ruoyi.framework.config.properties.ThreadPoolProperties;
import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -10,7 +9,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
@ -23,6 +21,11 @@ import java.util.concurrent.ThreadPoolExecutor;
@Configuration @Configuration
public class ThreadPoolConfig { public class ThreadPoolConfig {
/**
* 核心线程数 = cpu 核心数 + 1
*/
private final int core = Runtime.getRuntime().availableProcessors() + 1;
@Autowired @Autowired
private ThreadPoolProperties threadPoolProperties; private ThreadPoolProperties threadPoolProperties;
@ -30,12 +33,11 @@ public class ThreadPoolConfig {
@ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true") @ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true")
public ThreadPoolTaskExecutor threadPoolTaskExecutor() { public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(threadPoolProperties.getMaxPoolSize()); executor.setMaxPoolSize(core);
executor.setCorePoolSize(threadPoolProperties.getCorePoolSize()); executor.setCorePoolSize(core * 2);
executor.setQueueCapacity(threadPoolProperties.getQueueCapacity()); executor.setQueueCapacity(threadPoolProperties.getQueueCapacity());
executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds()); executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds());
RejectedExecutionHandler handler = ReflectUtils.newInstance(threadPoolProperties.getRejectedExecutionHandler().getClazz()); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setRejectedExecutionHandler(handler);
return executor; return executor;
} }
@ -44,7 +46,7 @@ public class ThreadPoolConfig {
*/ */
@Bean(name = "scheduledExecutorService") @Bean(name = "scheduledExecutorService")
protected ScheduledExecutorService scheduledExecutorService() { protected ScheduledExecutorService scheduledExecutorService() {
return new ScheduledThreadPoolExecutor(threadPoolProperties.getCorePoolSize(), return new ScheduledThreadPoolExecutor(core,
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(), new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
new ThreadPoolExecutor.CallerRunsPolicy()) { new ThreadPoolExecutor.CallerRunsPolicy()) {
@Override @Override

View File

@ -4,7 +4,6 @@ import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.redisson.config.ReadMode; import org.redisson.config.ReadMode;
import org.redisson.config.SubscriptionMode; import org.redisson.config.SubscriptionMode;
import org.redisson.config.TransportMode;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -30,11 +29,6 @@ public class RedissonProperties {
*/ */
private int nettyThreads; private int nettyThreads;
/**
* 传输模式
*/
private TransportMode transportMode;
/** /**
* 单机服务配置 * 单机服务配置
*/ */
@ -79,16 +73,6 @@ public class RedissonProperties {
*/ */
private int timeout; private int timeout;
/**
* 如果尝试在此限制之内发送成功则开始启用 timeout 计时
*/
private int retryAttempts;
/**
* 命令重试发送时间间隔单位毫秒
*/
private int retryInterval;
/** /**
* 发布和订阅连接池大小 * 发布和订阅连接池大小
*/ */
@ -130,26 +114,11 @@ public class RedissonProperties {
*/ */
private int idleConnectionTimeout; private int idleConnectionTimeout;
/**
* ping超时
*/
private int pingConnectionInterval;
/** /**
* 命令等待超时单位毫秒 * 命令等待超时单位毫秒
*/ */
private int timeout; private int timeout;
/**
* 如果尝试在此限制之内发送成功则开始启用 timeout 计时
*/
private int retryAttempts;
/**
* 命令重试发送时间间隔单位毫秒
*/
private int retryInterval;
/** /**
* 发布和订阅连接池大小 * 发布和订阅连接池大小
*/ */

View File

@ -1,22 +0,0 @@
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 interval;
}

View File

@ -1,6 +1,5 @@
package com.ruoyi.framework.config.properties; package com.ruoyi.framework.config.properties;
import com.ruoyi.common.enums.ThreadPoolRejectedPolicy;
import lombok.Data; import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -20,16 +19,6 @@ public class ThreadPoolProperties {
*/ */
private boolean enabled; private boolean enabled;
/**
* 核心线程池大小
*/
private int corePoolSize;
/**
* 最大可创建的线程数
*/
private int maxPoolSize;
/** /**
* 队列最大长度 * 队列最大长度
*/ */
@ -40,9 +29,4 @@ public class ThreadPoolProperties {
*/ */
private int keepAliveSeconds; private int keepAliveSeconds;
/**
* 线程池对拒绝任务(无线程可用)的处理策略
*/
private ThreadPoolRejectedPolicy rejectedExecutionHandler;
} }

View File

@ -53,7 +53,7 @@ public class UserActionListener implements SaTokenListener {
dto.setUserName(user.getUsername()); dto.setUserName(user.getUsername());
dto.setDeptName(user.getDeptName()); dto.setDeptName(user.getDeptName());
RedisUtils.setCacheObject(Constants.ONLINE_TOKEN_KEY + tokenValue, dto, tokenConfig.getTimeout(), TimeUnit.SECONDS); RedisUtils.setCacheObject(Constants.ONLINE_TOKEN_KEY + tokenValue, dto, tokenConfig.getTimeout(), TimeUnit.SECONDS);
log.info("user doLogin, useId:{}, token:{}", loginId, tokenValue); log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue);
} else if (userType == UserType.APP_USER) { } else if (userType == UserType.APP_USER) {
// app端 自行根据业务编写 // app端 自行根据业务编写
} }
@ -65,7 +65,7 @@ public class UserActionListener implements SaTokenListener {
@Override @Override
public void doLogout(String loginType, Object loginId, String tokenValue) { public void doLogout(String loginType, Object loginId, String tokenValue) {
RedisUtils.deleteObject(Constants.ONLINE_TOKEN_KEY + tokenValue); RedisUtils.deleteObject(Constants.ONLINE_TOKEN_KEY + tokenValue);
log.info("user doLogout, useId:{}, token:{}", loginId, tokenValue); log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue);
} }
/** /**
@ -74,7 +74,7 @@ public class UserActionListener implements SaTokenListener {
@Override @Override
public void doKickout(String loginType, Object loginId, String tokenValue) { public void doKickout(String loginType, Object loginId, String tokenValue) {
RedisUtils.deleteObject(Constants.ONLINE_TOKEN_KEY + tokenValue); RedisUtils.deleteObject(Constants.ONLINE_TOKEN_KEY + tokenValue);
log.info("user doLogoutByLoginId, useId:{}, token:{}", loginId, tokenValue); log.info("user doLogoutByLoginId, userId:{}, token:{}", loginId, tokenValue);
} }
/** /**
@ -83,7 +83,7 @@ public class UserActionListener implements SaTokenListener {
@Override @Override
public void doReplaced(String loginType, Object loginId, String tokenValue) { public void doReplaced(String loginType, Object loginId, String tokenValue) {
RedisUtils.deleteObject(Constants.ONLINE_TOKEN_KEY + tokenValue); RedisUtils.deleteObject(Constants.ONLINE_TOKEN_KEY + tokenValue);
log.info("user doReplaced, useId:{}, token:{}", loginId, tokenValue); log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue);
} }
/** /**

View File

@ -9,9 +9,17 @@ import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/**
* sa-token 权限管理实现类
*
* @author Lion Li
*/
@Component @Component
public class SaInterfaceImpl implements StpInterface { public class SaPermissionImpl implements StpInterface {
/**
* 获取菜单权限列表
*/
@Override @Override
public List<String> getPermissionList(Object loginId, String loginType) { public List<String> getPermissionList(Object loginId, String loginType) {
LoginUser loginUser = LoginHelper.getLoginUser(); LoginUser loginUser = LoginHelper.getLoginUser();
@ -19,11 +27,14 @@ public class SaInterfaceImpl implements StpInterface {
if (userType == UserType.SYS_USER) { if (userType == UserType.SYS_USER) {
return new ArrayList<>(loginUser.getMenuPermission()); return new ArrayList<>(loginUser.getMenuPermission());
} else if (userType == UserType.APP_USER) { } else if (userType == UserType.APP_USER) {
// app端权限返回 自行根据业务编写 // 其他端 自行根据业务编写
} }
return new ArrayList<>(); return new ArrayList<>();
} }
/**
* 获取角色权限列表
*/
@Override @Override
public List<String> getRoleList(Object loginId, String loginType) { public List<String> getRoleList(Object loginId, String loginType) {
LoginUser loginUser = LoginHelper.getLoginUser(); LoginUser loginUser = LoginHelper.getLoginUser();
@ -31,7 +42,7 @@ public class SaInterfaceImpl implements StpInterface {
if (userType == UserType.SYS_USER) { if (userType == UserType.SYS_USER) {
return new ArrayList<>(loginUser.getRolePermission()); return new ArrayList<>(loginUser.getRolePermission());
} else if (userType == UserType.APP_USER) { } else if (userType == UserType.APP_USER) {
// app端权限返回 自行根据业务编写 // 其他端 自行根据业务编写
} }
return new ArrayList<>(); return new ArrayList<>();
} }

View File

@ -9,7 +9,9 @@ import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.exception.DemoModeException; import com.ruoyi.common.exception.DemoModeException;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.validation.BindException; import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MethodArgumentNotValidException;
@ -71,6 +73,31 @@ public class GlobalExceptionHandler {
return R.fail(e.getMessage()); return R.fail(e.getMessage());
} }
/**
* 主键或UNIQUE索引数据重复异常
*/
@ExceptionHandler(DuplicateKeyException.class)
public R<Void> handleDuplicateKeyException(DuplicateKeyException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',数据库中已存在记录'{}'", requestURI, e.getMessage());
return R.fail("数据库中已存在该记录,请联系管理员确认");
}
/**
* Mybatis系统异常 通用处理
*/
@ExceptionHandler(MyBatisSystemException.class)
public R<Void> handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
String message = e.getMessage();
if (message.contains("CannotFindDataSourceException")) {
log.error("请求地址'{}', 未找到数据源", requestURI);
return R.fail("未找到数据源,请联系管理员确认");
}
log.error("请求地址'{}', Mybatis系统异常", requestURI, e);
return R.fail(message);
}
/** /**
* 业务异常 * 业务异常
*/ */

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi-vue-plus</artifactId> <artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>4.0.1</version> <version>4.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -5,13 +5,12 @@ import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.IoUtil;
import com.ruoyi.common.annotation.Log; import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.PageQuery; import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.generator.domain.GenTable; import com.ruoyi.generator.domain.GenTable;
import com.ruoyi.generator.domain.GenTableColumn; import com.ruoyi.generator.domain.GenTableColumn;
import com.ruoyi.generator.service.IGenTableColumnService;
import com.ruoyi.generator.service.IGenTableService; import com.ruoyi.generator.service.IGenTableService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
@ -38,7 +37,6 @@ import java.util.Map;
public class GenController extends BaseController { public class GenController extends BaseController {
private final IGenTableService genTableService; private final IGenTableService genTableService;
private final IGenTableColumnService genTableColumnService;
/** /**
* 查询代码生成列表 * 查询代码生成列表
@ -55,11 +53,11 @@ public class GenController extends BaseController {
*/ */
@ApiOperation("修改代码生成业务") @ApiOperation("修改代码生成业务")
@SaCheckPermission("tool:gen:query") @SaCheckPermission("tool:gen:query")
@GetMapping(value = "/{talbleId}") @GetMapping(value = "/{tableId}")
public R<Map<String, Object>> getInfo(@PathVariable Long talbleId) { public R<Map<String, Object>> getInfo(@PathVariable Long tableId) {
GenTable table = genTableService.selectGenTableById(talbleId); GenTable table = genTableService.selectGenTableById(tableId);
List<GenTable> tables = genTableService.selectGenTableAll(); List<GenTable> tables = genTableService.selectGenTableAll();
List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(talbleId); List<GenTableColumn> list = genTableService.selectGenTableColumnListByTableId(tableId);
Map<String, Object> map = new HashMap<String, Object>(); Map<String, Object> map = new HashMap<String, Object>();
map.put("info", table); map.put("info", table);
map.put("rows", list); map.put("rows", list);
@ -82,10 +80,10 @@ public class GenController extends BaseController {
*/ */
@ApiOperation("查询数据表字段列表") @ApiOperation("查询数据表字段列表")
@SaCheckPermission("tool:gen:list") @SaCheckPermission("tool:gen:list")
@GetMapping(value = "/column/{talbleId}") @GetMapping(value = "/column/{tableId}")
public TableDataInfo<GenTableColumn> columnList(Long tableId) { public TableDataInfo<GenTableColumn> columnList(Long tableId) {
TableDataInfo<GenTableColumn> dataInfo = new TableDataInfo<>(); TableDataInfo<GenTableColumn> dataInfo = new TableDataInfo<>();
List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId); List<GenTableColumn> list = genTableService.selectGenTableColumnListByTableId(tableId);
dataInfo.setRows(list); dataInfo.setRows(list);
dataInfo.setTotal(list.size()); dataInfo.setTotal(list.size());
return dataInfo; return dataInfo;

View File

@ -150,6 +150,12 @@ public class GenTable extends BaseEntity {
@TableField(exist = false) @TableField(exist = false)
private String treeName; private String treeName;
/*
* 菜单id列表
*/
@TableField(exist = false)
private List<Long> menuIds;
/** /**
* 上级菜单ID字段 * 上级菜单ID字段
*/ */

View File

@ -8,7 +8,7 @@ import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import org.apache.ibatis.type.JdbcType;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
@ -42,7 +42,7 @@ public class GenTableColumn extends BaseEntity {
/** /**
* 列描述 * 列描述
*/ */
@TableField(updateStrategy = FieldStrategy.IGNORED) @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
private String columnComment; private String columnComment;
/** /**
@ -64,43 +64,43 @@ public class GenTableColumn extends BaseEntity {
/** /**
* 是否主键1是 * 是否主键1是
*/ */
@TableField(updateStrategy = FieldStrategy.IGNORED) @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
private String isPk; private String isPk;
/** /**
* 是否自增1是 * 是否自增1是
*/ */
@TableField(updateStrategy = FieldStrategy.IGNORED) @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
private String isIncrement; private String isIncrement;
/** /**
* 是否必填1是 * 是否必填1是
*/ */
@TableField(updateStrategy = FieldStrategy.IGNORED) @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
private String isRequired; private String isRequired;
/** /**
* 是否为插入字段1是 * 是否为插入字段1是
*/ */
@TableField(updateStrategy = FieldStrategy.IGNORED) @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
private String isInsert; private String isInsert;
/** /**
* 是否编辑字段1是 * 是否编辑字段1是
*/ */
@TableField(updateStrategy = FieldStrategy.IGNORED) @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
private String isEdit; private String isEdit;
/** /**
* 是否列表字段1是 * 是否列表字段1是
*/ */
@TableField(updateStrategy = FieldStrategy.IGNORED) @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
private String isList; private String isList;
/** /**
* 是否查询字段1是 * 是否查询字段1是
*/ */
@TableField(updateStrategy = FieldStrategy.IGNORED) @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
private String isQuery; private String isQuery;
/** /**

View File

@ -16,26 +16,13 @@ import java.util.List;
@InterceptorIgnore(dataPermission = "true") @InterceptorIgnore(dataPermission = "true")
public interface GenTableMapper extends BaseMapperPlus<GenTableMapper, GenTable, GenTable> { public interface GenTableMapper extends BaseMapperPlus<GenTableMapper, GenTable, GenTable> {
Page<GenTable> selectPageGenTableList(@Param("page") Page<GenTable> page, @Param("genTable") GenTable genTable);
Page<GenTable> selectPageDbTableList(@Param("page") Page<GenTable> page, @Param("genTable") GenTable genTable);
/**
* 查询业务列表
*
* @param genTable 业务信息
* @return 业务集合
*/
List<GenTable> selectGenTableList(GenTable genTable);
/** /**
* 查询据库列表 * 查询据库列表
* *
* @param genTable 业务信息 * @param genTable 查询条件
* @return 数据库表集合 * @return 数据库表集合
*/ */
List<GenTable> selectDbTableList(GenTable genTable); Page<GenTable> selectPageDbTableList(@Param("page") Page<GenTable> page, @Param("genTable") GenTable genTable);
/** /**
* 查询据库列表 * 查询据库列表

View File

@ -1,68 +0,0 @@
package com.ruoyi.generator.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.generator.domain.GenTableColumn;
import com.ruoyi.generator.mapper.GenTableColumnMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
/**
* 业务字段 服务层实现
*
* @author Lion Li
*/
@RequiredArgsConstructor
@Service
public class GenTableColumnServiceImpl implements IGenTableColumnService {
private final GenTableColumnMapper baseMapper;
/**
* 查询业务字段列表
*
* @param tableId 业务字段编号
* @return 业务字段集合
*/
@Override
public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId) {
return baseMapper.selectList(new LambdaQueryWrapper<GenTableColumn>()
.eq(GenTableColumn::getTableId, tableId)
.orderByAsc(GenTableColumn::getSort));
}
/**
* 新增业务字段
*
* @param genTableColumn 业务字段信息
* @return 结果
*/
@Override
public int insertGenTableColumn(GenTableColumn genTableColumn) {
return baseMapper.insert(genTableColumn);
}
/**
* 修改业务字段
*
* @param genTableColumn 业务字段信息
* @return 结果
*/
@Override
public int updateGenTableColumn(GenTableColumn genTableColumn) {
return baseMapper.updateById(genTableColumn);
}
/**
* 删除业务字段对象
*
* @param ids 需要删除的数据ID
* @return 结果
*/
@Override
public int deleteGenTableColumnByIds(String ids) {
return baseMapper.deleteBatchIds(Arrays.asList(ids.split(",")));
}
}

View File

@ -3,8 +3,13 @@ package com.ruoyi.generator.service;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Dict; import cn.hutool.core.lang.Dict;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.GenConstants; import com.ruoyi.common.constant.GenConstants;
@ -28,7 +33,6 @@ import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext; import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity; import org.apache.velocity.app.Velocity;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
@ -46,6 +50,7 @@ import java.util.zip.ZipOutputStream;
* *
* @author Lion Li * @author Lion Li
*/ */
@DS("#header.datasource")
@Slf4j @Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
@Service @Service
@ -54,6 +59,19 @@ public class GenTableServiceImpl implements IGenTableService {
private final GenTableMapper baseMapper; private final GenTableMapper baseMapper;
private final GenTableColumnMapper genTableColumnMapper; private final GenTableColumnMapper genTableColumnMapper;
/**
* 查询业务字段列表
*
* @param tableId 业务字段编号
* @return 业务字段集合
*/
@Override
public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId) {
return genTableColumnMapper.selectList(new LambdaQueryWrapper<GenTableColumn>()
.eq(GenTableColumn::getTableId, tableId)
.orderByAsc(GenTableColumn::getSort));
}
/** /**
* 查询业务信息 * 查询业务信息
* *
@ -69,38 +87,27 @@ public class GenTableServiceImpl implements IGenTableService {
@Override @Override
public TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable, PageQuery pageQuery) { public TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable, PageQuery pageQuery) {
Page<GenTable> page = baseMapper.selectPageGenTableList(pageQuery.build(), genTable); Page<GenTable> page = baseMapper.selectPage(pageQuery.build(), this.buildGenTableQueryWrapper(genTable));
return TableDataInfo.build(page); return TableDataInfo.build(page);
} }
private QueryWrapper<GenTable> buildGenTableQueryWrapper(GenTable genTable) {
Map<String, Object> params = genTable.getParams();
QueryWrapper<GenTable> wrapper = Wrappers.query();
wrapper.like(StringUtils.isNotBlank(genTable.getTableName()), "lower(table_name)", StringUtils.lowerCase(genTable.getTableName()))
.like(StringUtils.isNotBlank(genTable.getTableComment()), "lower(table_comment)", StringUtils.lowerCase(genTable.getTableComment()))
.between(params.get("beginTime") != null && params.get("endTime") != null,
"create_time", params.get("beginTime"), params.get("endTime"));
return wrapper;
}
@Override @Override
public TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable, PageQuery pageQuery) { public TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable, PageQuery pageQuery) {
Page<GenTable> page = baseMapper.selectPageDbTableList(pageQuery.build(), genTable); Page<GenTable> page = baseMapper.selectPageDbTableList(pageQuery.build(), genTable);
return TableDataInfo.build(page); return TableDataInfo.build(page);
} }
/**
* 查询业务列表
*
* @param genTable 业务信息
* @return 业务集合
*/
@Override
public List<GenTable> selectGenTableList(GenTable genTable) {
return baseMapper.selectGenTableList(genTable);
}
/**
* 查询据库列表
*
* @param genTable 业务信息
* @return 数据库表集合
*/
@Override
public List<GenTable> selectDbTableList(GenTable genTable) {
return baseMapper.selectDbTableList(genTable);
}
/** /**
* 查询据库列表 * 查询据库列表
* *
@ -129,7 +136,6 @@ public class GenTableServiceImpl implements IGenTableService {
* @return 结果 * @return 结果
*/ */
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void updateGenTable(GenTable genTable) { public void updateGenTable(GenTable genTable) {
String options = JsonUtils.toJsonString(genTable.getParams()); String options = JsonUtils.toJsonString(genTable.getParams());
genTable.setOptions(options); genTable.setOptions(options);
@ -148,7 +154,6 @@ public class GenTableServiceImpl implements IGenTableService {
* @return 结果 * @return 结果
*/ */
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void deleteGenTableByIds(Long[] tableIds) { public void deleteGenTableByIds(Long[] tableIds) {
List<Long> ids = Arrays.asList(tableIds); List<Long> ids = Arrays.asList(tableIds);
baseMapper.deleteBatchIds(ids); baseMapper.deleteBatchIds(ids);
@ -161,7 +166,6 @@ public class GenTableServiceImpl implements IGenTableService {
* @param tableList 导入表列表 * @param tableList 导入表列表
*/ */
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void importGenTable(List<GenTable> tableList) { public void importGenTable(List<GenTable> tableList) {
String operName = LoginHelper.getUsername(); String operName = LoginHelper.getUsername();
try { try {
@ -198,6 +202,12 @@ public class GenTableServiceImpl implements IGenTableService {
Map<String, String> dataMap = new LinkedHashMap<>(); Map<String, String> dataMap = new LinkedHashMap<>();
// 查询表信息 // 查询表信息
GenTable table = baseMapper.selectGenTableById(tableId); GenTable table = baseMapper.selectGenTableById(tableId);
Snowflake snowflake = IdUtil.getSnowflake();
List<Long> menuIds = new ArrayList<>();
for (int i = 0; i < 6; i++) {
menuIds.add(snowflake.nextId());
}
table.setMenuIds(menuIds);
// 设置主子表信息 // 设置主子表信息
setSubTable(table); setSubTable(table);
// 设置主键列信息 // 设置主键列信息
@ -275,7 +285,6 @@ public class GenTableServiceImpl implements IGenTableService {
* @param tableName 表名称 * @param tableName 表名称
*/ */
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void synchDb(String tableName) { public void synchDb(String tableName) {
GenTable table = baseMapper.selectGenTableByName(tableName); GenTable table = baseMapper.selectGenTableByName(tableName);
List<GenTableColumn> tableColumns = table.getColumns(); List<GenTableColumn> tableColumns = table.getColumns();
@ -299,9 +308,8 @@ public class GenTableServiceImpl implements IGenTableService {
column.setQueryType(prevColumn.getQueryType()); column.setQueryType(prevColumn.getQueryType());
} }
if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk() if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk()
&& (column.isInsert() || column.isEdit()) && (column.isInsert() || column.isEdit())
&& ((column.isUsableColumn()) || (!column.isSuperColumn()))) && ((column.isUsableColumn()) || (!column.isSuperColumn()))) {
{
// 如果是(新增/修改&非主键/非忽略及父属性)继续保留必填/显示类型选项 // 如果是(新增/修改&非主键/非忽略及父属性)继续保留必填/显示类型选项
column.setIsRequired(prevColumn.getIsRequired()); column.setIsRequired(prevColumn.getIsRequired());
column.setHtmlType(prevColumn.getHtmlType()); column.setHtmlType(prevColumn.getHtmlType());
@ -345,6 +353,12 @@ public class GenTableServiceImpl implements IGenTableService {
private void generatorCode(String tableName, ZipOutputStream zip) { private void generatorCode(String tableName, ZipOutputStream zip) {
// 查询表信息 // 查询表信息
GenTable table = baseMapper.selectGenTableByName(tableName); GenTable table = baseMapper.selectGenTableByName(tableName);
Snowflake snowflake = IdUtil.getSnowflake();
List<Long> menuIds = new ArrayList<>();
for (int i = 0; i < 6; i++) {
menuIds.add(snowflake.nextId());
}
table.setMenuIds(menuIds);
// 设置主子表信息 // 设置主子表信息
setSubTable(table); setSubTable(table);
// 设置主键列信息 // 设置主键列信息
@ -477,3 +491,4 @@ public class GenTableServiceImpl implements IGenTableService {
return genPath + File.separator + VelocityUtils.getFileName(template, table); return genPath + File.separator + VelocityUtils.getFileName(template, table);
} }
} }

View File

@ -1,44 +0,0 @@
package com.ruoyi.generator.service;
import com.ruoyi.generator.domain.GenTableColumn;
import java.util.List;
/**
* 业务字段 服务层
*
* @author Lion Li
*/
public interface IGenTableColumnService {
/**
* 查询业务字段列表
*
* @param tableId 业务字段编号
* @return 业务字段集合
*/
List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId);
/**
* 新增业务字段
*
* @param genTableColumn 业务字段信息
* @return 结果
*/
int insertGenTableColumn(GenTableColumn genTableColumn);
/**
* 修改业务字段
*
* @param genTableColumn 业务字段信息
* @return 结果
*/
int updateGenTableColumn(GenTableColumn genTableColumn);
/**
* 删除业务字段信息
*
* @param ids 需要删除的数据ID
* @return 结果
*/
int deleteGenTableColumnByIds(String ids);
}

View File

@ -3,6 +3,7 @@ package com.ruoyi.generator.service;
import com.ruoyi.common.core.domain.PageQuery; import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.generator.domain.GenTable; import com.ruoyi.generator.domain.GenTable;
import com.ruoyi.generator.domain.GenTableColumn;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -14,11 +15,13 @@ import java.util.Map;
*/ */
public interface IGenTableService { public interface IGenTableService {
/**
TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable, PageQuery pageQuery); * 查询业务字段列表
*
* @param tableId 业务字段编号
TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable, PageQuery pageQuery); * @return 业务字段集合
*/
List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId);
/** /**
* 查询业务列表 * 查询业务列表
@ -26,7 +29,7 @@ public interface IGenTableService {
* @param genTable 业务信息 * @param genTable 业务信息
* @return 业务集合 * @return 业务集合
*/ */
List<GenTable> selectGenTableList(GenTable genTable); TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable, PageQuery pageQuery);
/** /**
* 查询据库列表 * 查询据库列表
@ -34,7 +37,7 @@ public interface IGenTableService {
* @param genTable 业务信息 * @param genTable 业务信息
* @return 数据库表集合 * @return 数据库表集合
*/ */
List<GenTable> selectDbTableList(GenTable genTable); TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable, PageQuery pageQuery);
/** /**
* 查询据库列表 * 查询据库列表

View File

@ -5,6 +5,8 @@ import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.generator.config.GenConfig; import com.ruoyi.generator.config.GenConfig;
import com.ruoyi.generator.domain.GenTable; import com.ruoyi.generator.domain.GenTable;
import com.ruoyi.generator.domain.GenTableColumn; import com.ruoyi.generator.domain.GenTableColumn;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.RegExUtils; import org.apache.commons.lang3.RegExUtils;
import java.util.Arrays; import java.util.Arrays;
@ -14,6 +16,7 @@ import java.util.Arrays;
* *
* @author ruoyi * @author ruoyi
*/ */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class GenUtils { public class GenUtils {
/** /**

View File

@ -1,6 +1,8 @@
package com.ruoyi.generator.util; package com.ruoyi.generator.util;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.Constants;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.velocity.app.Velocity; import org.apache.velocity.app.Velocity;
import java.util.Properties; import java.util.Properties;
@ -10,6 +12,7 @@ import java.util.Properties;
* *
* @author ruoyi * @author ruoyi
*/ */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class VelocityInitializer { public class VelocityInitializer {
/** /**

View File

@ -5,11 +5,14 @@ import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Dict; import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.constant.GenConstants; import com.ruoyi.common.constant.GenConstants;
import com.ruoyi.common.helper.DataBaseHelper;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.JsonUtils; import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.generator.domain.GenTable; import com.ruoyi.generator.domain.GenTable;
import com.ruoyi.generator.domain.GenTableColumn; import com.ruoyi.generator.domain.GenTableColumn;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.velocity.VelocityContext; import org.apache.velocity.VelocityContext;
import java.util.*; import java.util.*;
@ -19,6 +22,7 @@ import java.util.*;
* *
* @author ruoyi * @author ruoyi
*/ */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class VelocityUtils { public class VelocityUtils {
/** /**
@ -135,7 +139,15 @@ public class VelocityUtils {
templates.add("vm/java/serviceImpl.java.vm"); templates.add("vm/java/serviceImpl.java.vm");
templates.add("vm/java/controller.java.vm"); templates.add("vm/java/controller.java.vm");
templates.add("vm/xml/mapper.xml.vm"); templates.add("vm/xml/mapper.xml.vm");
templates.add("vm/sql/sql.vm"); if (DataBaseHelper.isOracle()) {
templates.add("vm/sql/oracle/sql.vm");
} else if (DataBaseHelper.isPostgerSql()) {
templates.add("vm/sql/postgres/sql.vm");
} else if (DataBaseHelper.isSqlServer()) {
templates.add("vm/sql/sqlserver/sql.vm");
} else {
templates.add("vm/sql/sql.vm");
}
templates.add("vm/js/api.js.vm"); templates.add("vm/js/api.js.vm");
if (GenConstants.TPL_CRUD.equals(tplCategory)) { if (GenConstants.TPL_CRUD.equals(tplCategory)) {
templates.add("vm/vue/index.vue.vm"); templates.add("vm/vue/index.vue.vm");

View File

@ -30,9 +30,85 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap> </resultMap>
<select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult"> <select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult">
select column_name, (case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else null end) as is_required, (case when column_key = 'PRI' then '1' else '0' end) as is_pk, ordinal_position as sort, column_comment, (case when extra = 'auto_increment' then '1' else '0' end) as is_increment, column_type <if test="@com.ruoyi.common.helper.DataBaseHelper@isMySql()">
from information_schema.columns where table_schema = (select database()) and table_name = (#{tableName}) select column_name,
order by ordinal_position (case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else null end) as is_required,
(case when column_key = 'PRI' then '1' else '0' end) as is_pk,
ordinal_position as sort,
column_comment,
(case when extra = 'auto_increment' then '1' else '0' end) as is_increment,
column_type
from information_schema.columns where table_schema = (select database()) and table_name = (#{tableName})
order by ordinal_position
</if>
<if test="@com.ruoyi.common.helper.DataBaseHelper@isOracle()">
select lower(temp.column_name) as column_name,
(case when (temp.nullable = 'N' and temp.constraint_type != 'P') then '1' else null end) as is_required,
(case when temp.constraint_type = 'P' then '1' else '0' end) as is_pk,
temp.column_id as sort,
temp.comments as column_comment,
(case when temp.constraint_type = 'P' then '1' else '0' end) as is_increment,
lower(temp.data_type) as column_type
from (
select col.column_id, col.column_name,col.nullable, col.data_type, colc.comments, uc.constraint_type, row_number()
over (partition by col.column_name order by uc.constraint_type desc) as row_flg
from user_tab_columns col
left join user_col_comments colc on colc.table_name = col.table_name and colc.column_name = col.column_name
left join user_cons_columns ucc on ucc.table_name = col.table_name and ucc.column_name = col.column_name
left join user_constraints uc on uc.constraint_name = ucc.constraint_name
where col.table_name = upper(#{tableName})
) temp
WHERE temp.row_flg = 1
ORDER BY temp.column_id
</if>
<if test="@com.ruoyi.common.helper.DataBaseHelper@isPostgerSql()">
SELECT column_name, is_required, is_pk, sort, column_comment, is_increment, column_type
FROM (
SELECT c.relname AS table_name,
a.attname AS column_name,
d.description AS column_comment,
CASE WHEN a.attnotnull AND con.conname IS NULL THEN 1 ELSE 0
END AS is_required,
CASE WHEN con.conname IS NOT NULL THEN 1 ELSE 0
END AS is_pk,
a.attnum AS sort,
CASE WHEN "position"(pg_get_expr(ad.adbin, ad.adrelid),
((c.relname::text || '_'::text) || a.attname::text) || '_seq'::text) > 0 THEN 1 ELSE 0
END AS is_increment,
btrim(
CASE WHEN t.typelem <![CDATA[ <> ]]> 0::oid AND t.typlen = '-1'::integer THEN 'ARRAY'::text ELSE
CASE WHEN t.typtype = 'd'::"char" THEN format_type(t.typbasetype, NULL::integer)
ELSE format_type(a.atttypid, NULL::integer) END
END, '"'::text
) AS column_type
FROM pg_attribute a
JOIN (pg_class c JOIN pg_namespace n ON c.relnamespace = n.oid) ON a.attrelid = c.oid
LEFT JOIN pg_description d ON d.objoid = c.oid AND a.attnum = d.objsubid
LEFT JOIN pg_constraint con ON con.conrelid = c.oid AND (a.attnum = ANY (con.conkey))
LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum
LEFT JOIN pg_type t ON a.atttypid = t.oid
WHERE (c.relkind = ANY (ARRAY ['r'::"char", 'p'::"char"]))
AND a.attnum > 0
AND n.nspname = 'public'::name
ORDER BY c.relname, a.attnum
) temp
WHERE table_name = (#{tableName})
</if>
<if test="@com.ruoyi.common.helper.DataBaseHelper@isSqlServer()">
SELECT
cast(A.NAME as nvarchar) as column_name,
cast(B.NAME as nvarchar) + (case when B.NAME = 'numeric' then '(' + cast(A.prec as nvarchar) + ',' + cast(A.scale as nvarchar) + ')' else '' end) as column_type,
cast(G.[VALUE] as nvarchar) as column_comment,
(SELECT 1 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE Z WHERE TABLE_NAME = D.NAME and A.NAME = Z.column_name ) as is_pk,
colorder as sort
FROM SYSCOLUMNS A
LEFT JOIN SYSTYPES B ON A.XTYPE = B.XUSERTYPE
INNER JOIN SYSOBJECTS D ON A.ID = D.ID AND D.XTYPE='U' AND D.NAME != 'DTPROPERTIES'
LEFT JOIN SYS.EXTENDED_PROPERTIES G ON A.ID = G.MAJOR_ID AND A.COLID = G.MINOR_ID
LEFT JOIN SYS.EXTENDED_PROPERTIES F ON D.ID = F.MAJOR_ID AND F.MINOR_ID = 0
WHERE D.NAME = #{tableName}
ORDER BY A.COLORDER
</if>
</select> </select>
</mapper> </mapper>

View File

@ -53,100 +53,183 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="updateTime" column="update_time" /> <result property="updateTime" column="update_time" />
</resultMap> </resultMap>
<sql id="selectGenTableVo"> <select id="selectPageDbTableList" resultMap="GenTableResult">
select table_id, table_name, table_comment, sub_table_name, sub_table_fk_name, class_name, tpl_category, package_name, module_name, business_name, function_name, function_author, gen_type, gen_path, options, create_by, create_time, update_by, update_time, remark from gen_table <if test="@com.ruoyi.common.helper.DataBaseHelper@isMySql()">
</sql> select table_name, table_comment, create_time, update_time
from information_schema.tables
<select id="selectPageGenTableList" parameterType="GenTable" resultMap="GenTableResult"> where table_schema = (select database())
<include refid="selectGenTableVo"/> AND table_name NOT LIKE 'xxl_job_%' AND table_name NOT LIKE 'gen_%'
<where> AND table_name NOT IN (select table_name from gen_table)
<if test="genTable.tableName != null and genTable.tableName != ''"> <if test="genTable.tableName != null and genTable.tableName != ''">
AND lower(table_name) like lower(concat('%', #{genTable.tableName}, '%')) AND lower(table_name) like lower(concat('%', #{genTable.tableName}, '%'))
</if> </if>
<if test="genTable.tableComment != null and genTable.tableComment != ''"> <if test="genTable.tableComment != null and genTable.tableComment != ''">
AND lower(table_comment) like lower(concat('%', #{genTable.tableComment}, '%')) AND lower(table_comment) like lower(concat('%', #{genTable.tableComment}, '%'))
</if> </if>
<if test="genTable.params.beginTime != null and genTable.params.beginTime != ''"><!-- 开始时间检索 --> order by create_time desc
AND date_format(create_time,'%y%m%d') &gt;= date_format(#{genTable.params.beginTime},'%y%m%d') </if>
<if test="@com.ruoyi.common.helper.DataBaseHelper@isOracle()">
select lower(dt.table_name) as table_name, dtc.comments as table_comment, uo.created as create_time, uo.last_ddl_time as update_time
from user_tables dt, user_tab_comments dtc, user_objects uo
where dt.table_name = dtc.table_name
and dt.table_name = uo.object_name
and uo.object_type = 'TABLE'
AND dt.table_name NOT LIKE 'XXL_JOB_%' AND dt.table_name NOT LIKE 'GEN_%'
AND lower(dt.table_name) NOT IN (select table_name from gen_table)
<if test="genTable.tableName != null and genTable.tableName != ''">
AND lower(dt.table_name) like lower(concat(concat('%', #{genTable.tableName}), '%'))
</if> </if>
<if test="genTable.params.endTime != null and genTable.params.endTime != ''"><!-- 结束时间检索 --> <if test="genTable.tableComment != null and genTable.tableComment != ''">
AND date_format(create_time,'%y%m%d') &lt;= date_format(#{genTable.params.endTime},'%y%m%d') AND lower(dtc.comments) like lower(concat(concat('%', #{genTable.tableComment}), '%'))
</if> </if>
</where> order by create_time desc
</select>
<select id="selectPageDbTableList" parameterType="GenTable" resultMap="GenTableResult">
select table_name, table_comment, create_time, update_time from information_schema.tables
where table_schema = (select database())
AND table_name NOT LIKE 'xxl_job_%' AND table_name NOT LIKE 'gen_%'
AND table_name NOT IN (select table_name from gen_table)
<if test="genTable.tableName != null and genTable.tableName != ''">
AND lower(table_name) like lower(concat('%', #{genTable.tableName}, '%'))
</if> </if>
<if test="genTable.tableComment != null and genTable.tableComment != ''"> <if test="@com.ruoyi.common.helper.DataBaseHelper@isPostgerSql()">
AND lower(table_comment) like lower(concat('%', #{genTable.tableComment}, '%')) select table_name, table_comment, create_time, update_time
</if> from (
<if test="genTable.params.beginTime != null and genTable.params.beginTime != ''"><!-- 开始时间检索 --> SELECT c.relname AS table_name,
AND date_format(create_time,'%y%m%d') &gt;= date_format(#{genTable.params.beginTime},'%y%m%d') obj_description(c.oid) AS table_comment,
</if> CURRENT_TIMESTAMP AS create_time,
<if test="genTable.params.endTime != null and genTable.params.endTime != ''"><!-- 结束时间检索 --> CURRENT_TIMESTAMP AS update_time
AND date_format(create_time,'%y%m%d') &lt;= date_format(#{genTable.params.endTime},'%y%m%d') FROM pg_class c
</if> LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
order by create_time desc WHERE (c.relkind = ANY (ARRAY ['r'::"char", 'p'::"char"]))
</select> AND c.relname != 'spatial_%'::text
AND n.nspname = 'public'::name
AND n.nspname <![CDATA[ <> ]]> ''::name
<select id="selectGenTableList" parameterType="GenTable" resultMap="GenTableResult"> ) list_table
<include refid="selectGenTableVo"/> where table_name NOT LIKE 'xxl_job_%' AND table_name NOT LIKE 'gen_%'
<where> AND table_name NOT IN (select table_name from gen_table)
<if test="tableName != null and tableName != ''"> <if test="genTable.tableName != null and genTable.tableName != ''">
AND lower(table_name) like lower(concat('%', #{tableName}, '%')) AND lower(table_name) like lower(concat('%', #{genTable.tableName}, '%'))
</if> </if>
<if test="tableComment != null and tableComment != ''"> <if test="genTable.tableComment != null and genTable.tableComment != ''">
AND lower(table_comment) like lower(concat('%', #{tableComment}, '%')) AND lower(table_comment) like lower(concat('%', #{genTable.tableComment}, '%'))
</if> </if>
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 --> order by create_time desc
AND date_format(create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d') </if>
<if test="@com.ruoyi.common.helper.DataBaseHelper@isSqlServer()">
SELECT cast(D.NAME as nvarchar) as table_name,
cast(F.VALUE as nvarchar) as table_comment,
crdate as create_time,
refdate as update_time
FROM SYSOBJECTS D
INNER JOIN SYS.EXTENDED_PROPERTIES F ON D.ID = F.MAJOR_ID
AND F.MINOR_ID = 0 AND D.XTYPE = 'U' AND D.NAME != 'DTPROPERTIES'
AND D.NAME NOT LIKE 'xxl_job_%' AND D.NAME NOT LIKE 'gen_%'
AND D.NAME NOT IN (select table_name from gen_table)
<if test="genTable.tableName != null and genTable.tableName != ''">
AND lower(D.NAME) like lower(concat(N'%', N'${genTable.tableName}', N'%'))
</if> </if>
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 --> <if test="genTable.tableComment != null and genTable.tableComment != ''">
AND date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d') AND lower(CAST(F.VALUE AS nvarchar)) like lower(concat(N'%', N'${genTable.tableComment}', N'%'))
</if> </if>
</where> order by crdate desc
</select>
<select id="selectDbTableList" parameterType="GenTable" resultMap="GenTableResult">
select table_name, table_comment, create_time, update_time from information_schema.tables
where table_schema = (select database())
AND table_name NOT LIKE 'xxl_job_%' AND table_name NOT LIKE 'gen_%'
AND table_name NOT IN (select table_name from gen_table)
<if test="tableName != null and tableName != ''">
AND lower(table_name) like lower(concat('%', #{tableName}, '%'))
</if> </if>
<if test="tableComment != null and tableComment != ''">
AND lower(table_comment) like lower(concat('%', #{tableComment}, '%'))
</if>
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
AND date_format(create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
</if>
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
AND date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if>
order by create_time desc
</select> </select>
<select id="selectDbTableListByNames" resultMap="GenTableResult"> <select id="selectDbTableListByNames" resultMap="GenTableResult">
select table_name, table_comment, create_time, update_time from information_schema.tables <if test="@com.ruoyi.common.helper.DataBaseHelper@isMySql()">
where table_name NOT LIKE 'xxl_job_%' and table_name NOT LIKE 'gen_%' and table_schema = (select database()) select table_name, table_comment, create_time, update_time from information_schema.tables
and table_name in where table_name NOT LIKE 'xxl_job_%' and table_name NOT LIKE 'gen_%' and table_schema = (select database())
<foreach collection="array" item="name" open="(" separator="," close=")"> and table_name in
#{name} <foreach collection="array" item="name" open="(" separator="," close=")">
</foreach> #{name}
</foreach>
</if>
<if test="@com.ruoyi.common.helper.DataBaseHelper@isOracle()">
select lower(dt.table_name) as table_name, dtc.comments as table_comment, uo.created as create_time, uo.last_ddl_time as update_time
from user_tables dt, user_tab_comments dtc, user_objects uo
where dt.table_name = dtc.table_name
and dt.table_name = uo.object_name
and uo.object_type = 'TABLE'
AND dt.table_name NOT LIKE 'XXL_JOB_%' AND dt.table_name NOT LIKE 'GEN_%'
AND dt.table_name NOT IN (select table_name from gen_table)
and lower(dt.table_name) in
<foreach collection="array" item="name" open="(" separator="," close=")">
#{name}
</foreach>
</if>
<if test="@com.ruoyi.common.helper.DataBaseHelper@isPostgerSql()">
select table_name, table_comment, create_time, update_time
from (
SELECT c.relname AS table_name,
obj_description(c.oid) AS table_comment,
CURRENT_TIMESTAMP AS create_time,
CURRENT_TIMESTAMP AS update_time
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE (c.relkind = ANY (ARRAY ['r'::"char", 'p'::"char"]))
AND c.relname != 'spatial_%'::text
AND n.nspname = 'public'::name
AND n.nspname <![CDATA[ <> ]]> ''::name
) list_table
where table_name NOT LIKE 'xxl_job_%' and table_name NOT LIKE 'gen_%'
and table_name in
<foreach collection="array" item="name" open="(" separator="," close=")">
#{name}
</foreach>
</if>
<if test="@com.ruoyi.common.helper.DataBaseHelper@isSqlServer()">
SELECT cast(D.NAME as nvarchar) as table_name,
cast(F.VALUE as nvarchar) as table_comment,
crdate as create_time,
refdate as update_time
FROM SYSOBJECTS D
INNER JOIN SYS.EXTENDED_PROPERTIES F ON D.ID = F.MAJOR_ID
AND F.MINOR_ID = 0 AND D.XTYPE = 'U' AND D.NAME != 'DTPROPERTIES'
AND D.NAME NOT LIKE 'xxl_job_%' AND D.NAME NOT LIKE 'gen_%'
AND D.NAME in
<foreach collection="array" item="name" open="(" separator="," close=")">
#{name}
</foreach>
</if>
</select> </select>
<select id="selectTableByName" parameterType="String" resultMap="GenTableResult"> <select id="selectTableByName" parameterType="String" resultMap="GenTableResult">
select table_name, table_comment, create_time, update_time from information_schema.tables <if test="@com.ruoyi.common.helper.DataBaseHelper@isMySql()">
where table_comment <![CDATA[ <> ]]> '' and table_schema = (select database()) select table_name, table_comment, create_time, update_time from information_schema.tables
and table_name = #{tableName} where table_name NOT LIKE 'xxl_job_%' and table_name NOT LIKE 'gen_%' and table_schema = (select database())
and table_name = #{tableName}
</if>
<if test="@com.ruoyi.common.helper.DataBaseHelper@isOracle()">
select lower(dt.table_name) as table_name, dtc.comments as table_comment, uo.created as create_time, uo.last_ddl_time as update_time
from user_tables dt, user_tab_comments dtc, user_objects uo
where dt.table_name = dtc.table_name
and dt.table_name = uo.object_name
and uo.object_type = 'TABLE'
AND dt.table_name NOT LIKE 'XXL_JOB_%' AND dt.table_name NOT LIKE 'GEN_%'
AND dt.table_name NOT IN (select table_name from gen_table)
and lower(dt.table_name) = #{tableName}
</if>
<if test="@com.ruoyi.common.helper.DataBaseHelper@isPostgerSql()">
select table_name, table_comment, create_time, update_time
from (
SELECT c.relname AS table_name,
obj_description(c.oid) AS table_comment,
CURRENT_TIMESTAMP AS create_time,
CURRENT_TIMESTAMP AS update_time
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE (c.relkind = ANY (ARRAY ['r'::"char", 'p'::"char"]))
AND c.relname != 'spatial_%'::text
AND n.nspname = 'public'::name
AND n.nspname <![CDATA[ <> ]]> ''::name
) list_table
where table_name NOT LIKE 'xxl_job_%' and table_name NOT LIKE 'gen_%'
and table_name = #{tableName}
</if>
<if test="@com.ruoyi.common.helper.DataBaseHelper@isSqlServer()">
SELECT cast(D.NAME as nvarchar) as table_name,
cast(F.VALUE as nvarchar) as table_comment,
crdate as create_time,
refdate as update_time
FROM SYSOBJECTS D
INNER JOIN SYS.EXTENDED_PROPERTIES F ON D.ID = F.MAJOR_ID
AND F.MINOR_ID = 0 AND D.XTYPE = 'U' AND D.NAME != 'DTPROPERTIES'
AND D.NAME NOT LIKE 'xxl_job_%' AND D.NAME NOT LIKE 'gen_%'
AND D.NAME = #{tableName}
</if>
</select> </select>
<select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult"> <select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult">

View File

@ -28,7 +28,7 @@ import com.ruoyi.common.core.domain.TreeEntity;
#if($table.crud || $table.sub) #if($table.crud || $table.sub)
#set($Entity="BaseEntity") #set($Entity="BaseEntity")
#elseif($table.tree) #elseif($table.tree)
#set($Entity="TreeEntity") #set($Entity="TreeEntity<${ClassName}Bo>")
#end #end
@Data @Data

View File

@ -25,7 +25,7 @@ import com.ruoyi.common.core.domain.TreeEntity;
#if($table.crud || $table.sub) #if($table.crud || $table.sub)
#set($Entity="BaseEntity") #set($Entity="BaseEntity")
#elseif($table.tree) #elseif($table.tree)
#set($Entity="TreeEntity") #set($Entity="TreeEntity<${ClassName}>")
#end #end
@Data @Data
@TableName("${tableName}") @TableName("${tableName}")

View File

@ -0,0 +1,19 @@
-- 菜单 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', sysdate, '', null, '${functionName}菜单');
-- 按钮 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', sysdate, '', null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', sysdate, '', null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', sysdate, '', null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', sysdate, '', null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', sysdate, '', null, '');

View File

@ -0,0 +1,20 @@
-- 菜单 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', now(), '', null, '${functionName}菜单');
-- 按钮 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', now(), '', null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', now(), '', null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', now(), '', null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', now(), '', null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', now(), '', null, '');

View File

@ -1,22 +1,19 @@
-- 菜单 SQL -- 菜单 SQL
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', sysdate(), '', null, '${functionName}菜单'); values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', sysdate(), '', null, '${functionName}菜单');
-- 按钮父菜单ID
SELECT @parentId := LAST_INSERT_ID();
-- 按钮 SQL -- 按钮 SQL
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}查询', @parentId, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', sysdate(), '', null, ''); values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}新增', @parentId, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', sysdate(), '', null, ''); values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}修改', @parentId, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', sysdate(), '', null, ''); values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}删除', @parentId, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', sysdate(), '', null, ''); values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}导出', @parentId, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', sysdate(), '', null, ''); values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', sysdate(), '', null, '');

View File

@ -0,0 +1,19 @@
-- 菜单 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', getdate(), '', null, '${functionName}菜单');
-- 按钮 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', getdate(), '', null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', getdate(), '', null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', getdate(), '', null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', getdate(), '', null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', getdate(), '', null, '');

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px"> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
#foreach($column in $columns) #foreach($column in $columns)
#if($column.query) #if($column.query)
#set($dictType=$column.dictType) #set($dictType=$column.dictType)
@ -17,13 +17,12 @@
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
placeholder="请输入${comment}" placeholder="请输入${comment}"
clearable clearable
size="small"
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option <el-option
v-for="dict in dict.type.${dictType}" v-for="dict in dict.type.${dictType}"
:key="dict.value" :key="dict.value"
@ -34,13 +33,13 @@
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option label="请选择字典生成" value="" /> <el-option label="请选择字典生成" value="" />
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN") #elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
type="date" type="date"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
@ -51,7 +50,6 @@
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<el-date-picker <el-date-picker
v-model="daterange${AttrName}" v-model="daterange${AttrName}"
size="small"
style="width: 240px" style="width: 240px"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
type="daterange" type="daterange"
@ -80,14 +78,24 @@
v-hasPermi="['${moduleName}:${businessName}:add']" v-hasPermi="['${moduleName}:${businessName}:add']"
>新增</el-button> >新增</el-button>
</el-col> </el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="el-icon-sort"
size="mini"
@click="toggleExpandAll"
>展开/折叠</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row> </el-row>
<el-table <el-table
v-if="refreshTable"
v-loading="loading" v-loading="loading"
:data="${businessName}List" :data="${businessName}List"
row-key="${treeCode}" row-key="${treeCode}"
default-expand-all :default-expand-all="isExpandAll"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}" :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
> >
#foreach($column in $columns) #foreach($column in $columns)
@ -243,7 +251,7 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime") #elseif($column.htmlType == "datetime")
<el-form-item label="${comment}" prop="${field}"> <el-form-item label="${comment}" prop="${field}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="form.${field}" v-model="form.${field}"
type="datetime" type="datetime"
value-format="yyyy-MM-dd HH:mm:ss" value-format="yyyy-MM-dd HH:mm:ss"
@ -295,6 +303,10 @@ export default {
title: "", title: "",
// 是否显示弹出层 // 是否显示弹出层
open: false, open: false,
// 是否展开,默认全部展开
isExpandAll: true,
// 重新渲染表格状态
refreshTable: true,
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
@ -425,6 +437,14 @@ export default {
this.open = true; this.open = true;
this.title = "添加${functionName}"; this.title = "添加${functionName}";
}, },
/** 展开/折叠操作 */
toggleExpandAll() {
this.refreshTable = false;
this.isExpandAll = !this.isExpandAll;
this.$nextTick(() => {
this.refreshTable = true;
});
},
/** 修改按钮操作 */ /** 修改按钮操作 */
handleUpdate(row) { handleUpdate(row) {
this.loading = true; this.loading = true;

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px"> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
#foreach($column in $columns) #foreach($column in $columns)
#if($column.query) #if($column.query)
#set($dictType=$column.dictType) #set($dictType=$column.dictType)
@ -17,13 +17,12 @@
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
placeholder="请输入${comment}" placeholder="请输入${comment}"
clearable clearable
size="small"
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option <el-option
v-for="dict in dict.type.${dictType}" v-for="dict in dict.type.${dictType}"
:key="dict.value" :key="dict.value"
@ -34,13 +33,13 @@
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option label="请选择字典生成" value="" /> <el-option label="请选择字典生成" value="" />
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN") #elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
type="date" type="date"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
@ -51,7 +50,6 @@
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<el-date-picker <el-date-picker
v-model="daterange${AttrName}" v-model="daterange${AttrName}"
size="small"
style="width: 240px" style="width: 240px"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
type="daterange" type="daterange"
@ -264,7 +262,7 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime") #elseif($column.htmlType == "datetime")
<el-form-item label="${comment}" prop="${field}"> <el-form-item label="${comment}" prop="${field}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="form.${field}" v-model="form.${field}"
type="datetime" type="datetime"
value-format="yyyy-MM-dd HH:mm:ss" value-format="yyyy-MM-dd HH:mm:ss"

View File

@ -76,14 +76,23 @@
v-hasPermi="['${moduleName}:${businessName}:add']" v-hasPermi="['${moduleName}:${businessName}:add']"
>新增</el-button> >新增</el-button>
</el-col> </el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="Sort"
@click="toggleExpandAll"
>展开/折叠</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row> </el-row>
<el-table <el-table
v-if="refreshTable"
v-loading="loading" v-loading="loading"
:data="${businessName}List" :data="${businessName}List"
row-key="${treeCode}" row-key="${treeCode}"
default-expand-all :default-expand-all="isExpandAll"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}" :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
> >
#foreach($column in $columns) #foreach($column in $columns)
@ -282,6 +291,8 @@ const buttonLoading = ref(false);
const loading = ref(true); const loading = ref(true);
const showSearch = ref(true); const showSearch = ref(true);
const title = ref(""); const title = ref("");
const isExpandAll = ref(true);
const refreshTable = ref(true);
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
@ -404,6 +415,15 @@ async function handleAdd(row) {
title.value = "添加${functionName}"; title.value = "添加${functionName}";
} }
/** 展开/折叠操作 */
function toggleExpandAll() {
refreshTable.value = false;
isExpandAll.value = !isExpandAll.value;
nextTick(() => {
refreshTable.value = true;
});
}
/** 修改按钮操作 */ /** 修改按钮操作 */
async function handleUpdate(row) { async function handleUpdate(row) {
loading.value = true; loading.value = true;

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi-vue-plus</artifactId> <artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>4.0.1</version> <version>4.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi-vue-plus</artifactId> <artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>4.0.1</version> <version>4.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -42,6 +42,10 @@
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId> <artifactId>slf4j-log4j12</artifactId>
</exclusion> </exclusion>
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -12,11 +12,14 @@ import java.io.InputStream;
*/ */
public interface IOssStrategy { public interface IOssStrategy {
/**
* 创建存储桶
*/
void createBucket(); void createBucket();
/** /**
* 获取服务商类型 * 获取服务商类型
* @return * @return 对象存储服务商枚举
*/ */
OssEnumd getServiceType(); OssEnumd getServiceType();
@ -25,6 +28,7 @@ public interface IOssStrategy {
* *
* @param data 文件字节数组 * @param data 文件字节数组
* @param path 文件路径包含文件名 * @param path 文件路径包含文件名
* @param contentType 文件类型
* @return 返回http地址 * @return 返回http地址
*/ */
UploadResult upload(byte[] data, String path, String contentType); UploadResult upload(byte[] data, String path, String contentType);
@ -41,6 +45,7 @@ public interface IOssStrategy {
* *
* @param data 文件字节数组 * @param data 文件字节数组
* @param suffix 后缀 * @param suffix 后缀
* @param contentType 文件类型
* @return 返回http地址 * @return 返回http地址
*/ */
UploadResult uploadSuffix(byte[] data, String suffix, String contentType); UploadResult uploadSuffix(byte[] data, String suffix, String contentType);
@ -50,6 +55,7 @@ public interface IOssStrategy {
* *
* @param inputStream 字节流 * @param inputStream 字节流
* @param path 文件路径包含文件名 * @param path 文件路径包含文件名
* @param contentType 文件类型
* @return 返回http地址 * @return 返回http地址
*/ */
UploadResult upload(InputStream inputStream, String path, String contentType); UploadResult upload(InputStream inputStream, String path, String contentType);
@ -59,6 +65,7 @@ public interface IOssStrategy {
* *
* @param inputStream 字节流 * @param inputStream 字节流
* @param suffix 后缀 * @param suffix 后缀
* @param contentType 文件类型
* @return 返回http地址 * @return 返回http地址
*/ */
UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType); UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType);

View File

@ -60,5 +60,10 @@ public abstract class AbstractOssStrategy implements IOssStrategy {
@Override @Override
public abstract UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType); public abstract UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType);
/**
* 获取域名访问链接
*
* @return 域名访问链接
*/
public abstract String getEndpointLink(); public abstract String getEndpointLink();
} }

View File

@ -79,6 +79,8 @@ public class MinioOssStrategy extends AbstractOssStrategy {
@Override @Override
public UploadResult upload(InputStream inputStream, String path, String contentType) { public UploadResult upload(InputStream inputStream, String path, String contentType) {
try { try {
// 解决 inputStream.available() socket 下传输延迟问题 导致获取数值不精确
Thread.sleep(1000);
minioClient.putObject(PutObjectArgs.builder() minioClient.putObject(PutObjectArgs.builder()
.bucket(properties.getBucketName()) .bucket(properties.getBucketName())
.object(path) .object(path)

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi-vue-plus</artifactId> <artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>4.0.1</version> <version>4.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -1,6 +1,5 @@
package com.ruoyi.system.domain; package com.ruoyi.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.core.domain.BaseEntity; import com.ruoyi.common.core.domain.BaseEntity;
@ -20,7 +19,7 @@ public class SysOss extends BaseEntity {
/** /**
* 对象存储主键 * 对象存储主键
*/ */
@TableId(value = "oss_id", type = IdType.AUTO) @TableId(value = "oss_id")
private Long ossId; private Long ossId;
/** /**

View File

@ -14,6 +14,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
/** /**
@ -60,8 +61,8 @@ public class SysPost extends BaseEntity {
*/ */
@ApiModelProperty(value = "岗位排序") @ApiModelProperty(value = "岗位排序")
@ExcelProperty(value = "岗位排序") @ExcelProperty(value = "岗位排序")
@NotBlank(message = "显示顺序不能为空") @NotNull(message = "显示顺序不能为空")
private String postSort; private Integer postSort;
/** /**
* 状态0正常 1停用 * 状态0正常 1停用

View File

@ -1,5 +1,7 @@
package com.ruoyi.system.mapper; package com.ruoyi.system.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.ruoyi.common.annotation.DataColumn; import com.ruoyi.common.annotation.DataColumn;
import com.ruoyi.common.annotation.DataPermission; import com.ruoyi.common.annotation.DataPermission;
import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.core.domain.entity.SysDept;
@ -18,13 +20,13 @@ public interface SysDeptMapper extends BaseMapperPlus<SysDeptMapper, SysDept, Sy
/** /**
* 查询部门管理数据 * 查询部门管理数据
* *
* @param dept 部门信息 * @param queryWrapper 查询条件
* @return 部门信息集合 * @return 部门信息集合
*/ */
@DataPermission({ @DataPermission({
@DataColumn(key = "deptName", value = "d.dept_id") @DataColumn(key = "deptName", value = "dept_id")
}) })
List<SysDept> selectDeptList(SysDept dept); List<SysDept> selectDeptList(@Param(Constants.WRAPPER) Wrapper<SysDept> queryWrapper);
/** /**
* 根据角色ID查询部门树信息 * 根据角色ID查询部门树信息
@ -35,12 +37,4 @@ public interface SysDeptMapper extends BaseMapperPlus<SysDeptMapper, SysDept, Sy
*/ */
List<Long> selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly); List<Long> selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly);
/**
* 修改子元素关系
*
* @param depts 子元素
* @return 结果
*/
int updateDeptChildren(@Param("depts") List<SysDept> depts);
} }

View File

@ -1,5 +1,9 @@
package com.ruoyi.system.mapper; package com.ruoyi.system.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.entity.SysMenu; import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.mapper.BaseMapperPlus; import com.ruoyi.common.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
@ -23,10 +27,10 @@ public interface SysMenuMapper extends BaseMapperPlus<SysMenuMapper, SysMenu, Sy
/** /**
* 根据用户查询系统菜单列表 * 根据用户查询系统菜单列表
* *
* @param menu 菜单信息 * @param queryWrapper 查询条件
* @return 菜单列表 * @return 菜单列表
*/ */
List<SysMenu> selectMenuListByUserId(SysMenu menu); List<SysMenu> selectMenuListByUserId(@Param(Constants.WRAPPER) Wrapper<SysMenu> queryWrapper);
/** /**
* 根据用户ID查询权限 * 根据用户ID查询权限
@ -41,7 +45,14 @@ public interface SysMenuMapper extends BaseMapperPlus<SysMenuMapper, SysMenu, Sy
* *
* @return 菜单列表 * @return 菜单列表
*/ */
List<SysMenu> selectMenuTreeAll(); default List<SysMenu> selectMenuTreeAll() {
LambdaQueryWrapper<SysMenu> lqw = new LambdaQueryWrapper<SysMenu>()
.in(SysMenu::getMenuType, UserConstants.TYPE_DIR, UserConstants.TYPE_MENU)
.eq(SysMenu::getStatus, UserConstants.MENU_NORMAL)
.orderByAsc(SysMenu::getParentId)
.orderByAsc(SysMenu::getOrderNum);
return this.selectList(lqw);
}
/** /**
* 根据用户ID查询菜单 * 根据用户ID查询菜单

View File

@ -1,5 +1,7 @@
package com.ruoyi.system.mapper; package com.ruoyi.system.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.annotation.DataColumn; import com.ruoyi.common.annotation.DataColumn;
import com.ruoyi.common.annotation.DataPermission; import com.ruoyi.common.annotation.DataPermission;
@ -19,18 +21,18 @@ public interface SysRoleMapper extends BaseMapperPlus<SysRoleMapper, SysRole, Sy
@DataPermission({ @DataPermission({
@DataColumn(key = "deptName", value = "d.dept_id") @DataColumn(key = "deptName", value = "d.dept_id")
}) })
Page<SysRole> selectPageRoleList(@Param("page") Page<SysRole> page, @Param("role") SysRole role); Page<SysRole> selectPageRoleList(@Param("page") Page<SysRole> page, @Param(Constants.WRAPPER) Wrapper<SysRole> queryWrapper);
/** /**
* 根据条件分页查询角色数据 * 根据条件分页查询角色数据
* *
* @param role 角色信息 * @param queryWrapper 查询条件
* @return 角色数据集合信息 * @return 角色数据集合信息
*/ */
@DataPermission({ @DataPermission({
@DataColumn(key = "deptName", value = "d.dept_id") @DataColumn(key = "deptName", value = "d.dept_id")
}) })
List<SysRole> selectRoleList(SysRole role); List<SysRole> selectRoleList(@Param(Constants.WRAPPER) Wrapper<SysRole> queryWrapper);
/** /**
* 根据用户ID查询角色 * 根据用户ID查询角色

View File

@ -1,5 +1,7 @@
package com.ruoyi.system.mapper; package com.ruoyi.system.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.annotation.DataColumn; import com.ruoyi.common.annotation.DataColumn;
import com.ruoyi.common.annotation.DataPermission; import com.ruoyi.common.annotation.DataPermission;
@ -20,43 +22,43 @@ public interface SysUserMapper extends BaseMapperPlus<SysUserMapper, SysUser, Sy
@DataColumn(key = "deptName", value = "d.dept_id"), @DataColumn(key = "deptName", value = "d.dept_id"),
@DataColumn(key = "userName", value = "u.user_id") @DataColumn(key = "userName", value = "u.user_id")
}) })
Page<SysUser> selectPageUserList(@Param("page") Page<SysUser> page, @Param("user") SysUser user); Page<SysUser> selectPageUserList(@Param("page") Page<SysUser> page, @Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
/** /**
* 根据条件分页查询用户列表 * 根据条件分页查询用户列表
* *
* @param sysUser 用户信息 * @param queryWrapper 查询条件
* @return 用户信息集合信息 * @return 用户信息集合信息
*/ */
@DataPermission({ @DataPermission({
@DataColumn(key = "deptName", value = "d.dept_id"), @DataColumn(key = "deptName", value = "d.dept_id"),
@DataColumn(key = "userName", value = "u.user_id") @DataColumn(key = "userName", value = "u.user_id")
}) })
List<SysUser> selectUserList(SysUser sysUser); List<SysUser> selectUserList(@Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
/** /**
* 根据条件分页查询已配用户角色列表 * 根据条件分页查询已配用户角色列表
* *
* @param user 用户信息 * @param queryWrapper 查询条件
* @return 用户信息集合信息 * @return 用户信息集合信息
*/ */
@DataPermission({ @DataPermission({
@DataColumn(key = "deptName", value = "d.dept_id"), @DataColumn(key = "deptName", value = "d.dept_id"),
@DataColumn(key = "userName", value = "u.user_id") @DataColumn(key = "userName", value = "u.user_id")
}) })
Page<SysUser> selectAllocatedList(@Param("page") Page<SysUser> page, @Param("user") SysUser user); Page<SysUser> selectAllocatedList(@Param("page") Page<SysUser> page, @Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
/** /**
* 根据条件分页查询未分配用户角色列表 * 根据条件分页查询未分配用户角色列表
* *
* @param user 用户信息 * @param queryWrapper 查询条件
* @return 用户信息集合信息 * @return 用户信息集合信息
*/ */
@DataPermission({ @DataPermission({
@DataColumn(key = "deptName", value = "d.dept_id"), @DataColumn(key = "deptName", value = "d.dept_id"),
@DataColumn(key = "userName", value = "u.user_id") @DataColumn(key = "userName", value = "u.user_id")
}) })
Page<SysUser> selectUnallocatedList(@Param("page") Page<SysUser> page, @Param("user") SysUser user); Page<SysUser> selectUnallocatedList(@Param("page") Page<SysUser> page, @Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
/** /**
* 通过用户名查询用户 * 通过用户名查询用户
@ -66,6 +68,14 @@ public interface SysUserMapper extends BaseMapperPlus<SysUserMapper, SysUser, Sy
*/ */
SysUser selectUserByUserName(String userName); SysUser selectUserByUserName(String userName);
/**
* 通过手机号查询用户
*
* @param phonenumber 手机号
* @return 用户对象信息
*/
SysUser selectUserByPhonenumber(String phonenumber);
/** /**
* 通过用户ID查询用户 * 通过用户ID查询用户
* *

View File

@ -3,6 +3,8 @@ package com.ruoyi.system.mapper;
import com.ruoyi.common.core.mapper.BaseMapperPlus; import com.ruoyi.common.core.mapper.BaseMapperPlus;
import com.ruoyi.system.domain.SysUserRole; import com.ruoyi.system.domain.SysUserRole;
import java.util.List;
/** /**
* 用户与角色关联表 数据层 * 用户与角色关联表 数据层
* *
@ -10,4 +12,6 @@ import com.ruoyi.system.domain.SysUserRole;
*/ */
public interface SysUserRoleMapper extends BaseMapperPlus<SysUserRoleMapper, SysUserRole, SysUserRole> { public interface SysUserRoleMapper extends BaseMapperPlus<SysUserRoleMapper, SysUserRole, SysUserRole> {
List<Long> selectUserIdsByRoleId(Long roleId);
} }

View File

@ -24,7 +24,7 @@ public interface ISysOssConfigService {
/** /**
* 查询单个 * 查询单个
*/ */
SysOssConfigVo queryById(Integer ossConfigId); SysOssConfigVo queryById(Long ossConfigId);
/** /**
* 查询列表 * 查询列表

View File

@ -48,6 +48,14 @@ public interface ISysUserService {
*/ */
SysUser selectUserByUserName(String userName); SysUser selectUserByUserName(String userName);
/**
* 通过手机号查询用户
*
* @param phonenumber 手机号
* @return 用户对象信息
*/
SysUser selectUserByPhonenumber(String phonenumber);
/** /**
* 通过用户ID查询用户 * 通过用户ID查询用户
* *

View File

@ -8,8 +8,10 @@ import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.dto.RoleDTO; import com.ruoyi.common.core.domain.dto.RoleDTO;
import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.domain.model.XcxLoginUser;
import com.ruoyi.common.core.service.LogininforService; import com.ruoyi.common.core.service.LogininforService;
import com.ruoyi.common.enums.DeviceType; import com.ruoyi.common.enums.DeviceType;
import com.ruoyi.common.enums.LoginType;
import com.ruoyi.common.enums.UserStatus; import com.ruoyi.common.enums.UserStatus;
import com.ruoyi.common.exception.user.CaptchaException; import com.ruoyi.common.exception.user.CaptchaException;
import com.ruoyi.common.exception.user.CaptchaExpireException; import com.ruoyi.common.exception.user.CaptchaExpireException;
@ -27,6 +29,7 @@ import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
/** /**
* 登录校验方法 * 登录校验方法
@ -59,34 +62,9 @@ public class SysLoginService {
if (captchaOnOff) { if (captchaOnOff) {
validateCaptcha(username, code, uuid, request); validateCaptcha(username, code, uuid, request);
} }
// 获取用户登录错误次数(可自定义限制策略 例如: key + username + ip)
Integer errorNumber = RedisUtils.getCacheObject(Constants.LOGIN_ERROR + username);
// 锁定时间内登录 则踢出
if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(Constants.LOGIN_ERROR_NUMBER)) {
asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME), request);
throw new UserException("user.password.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME);
}
SysUser user = loadUserByUsername(username); SysUser user = loadUserByUsername(username);
checkLogin(LoginType.PASSWORD, username, () -> !BCrypt.checkpw(password, user.getPassword()));
if (!BCrypt.checkpw(password, user.getPassword())) { // 此处可根据登录用户的数据不同 自行创建 loginUser
// 是否第一次
errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1;
// 达到规定错误次数 则锁定登录
if (errorNumber.equals(Constants.LOGIN_ERROR_NUMBER)) {
RedisUtils.setCacheObject(Constants.LOGIN_ERROR + username, errorNumber, Constants.LOGIN_ERROR_LIMIT_TIME, TimeUnit.MINUTES);
asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME), request);
throw new UserException("user.password.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME);
} else {
// 未达到规定错误次数 则递增
RedisUtils.setCacheObject(Constants.LOGIN_ERROR + username, errorNumber);
asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.count", errorNumber), request);
throw new UserException("user.password.retry.limit.count", errorNumber);
}
}
// 登录成功 清空错误次数
RedisUtils.deleteObject(Constants.LOGIN_ERROR + username);
LoginUser loginUser = buildLoginUser(user); LoginUser loginUser = buildLoginUser(user);
// 生成token // 生成token
LoginHelper.loginByDevice(loginUser, DeviceType.PC); LoginHelper.loginByDevice(loginUser, DeviceType.PC);
@ -96,10 +74,58 @@ public class SysLoginService {
return StpUtil.getTokenValue(); return StpUtil.getTokenValue();
} }
public String smsLogin(String phonenumber, String smsCode) {
// 通过手机号查找用户
SysUser user = loadUserByPhonenumber(phonenumber);
HttpServletRequest request = ServletUtils.getRequest();
checkLogin(LoginType.SMS, user.getUserName(), () -> !validateSmsCode(phonenumber, smsCode));
// 此处可根据登录用户的数据不同 自行创建 loginUser
LoginUser loginUser = buildLoginUser(user);
// 生成token
LoginHelper.loginByDevice(loginUser, DeviceType.APP);
asyncService.recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), request);
recordLoginInfo(user.getUserId(), user.getUserName());
return StpUtil.getTokenValue();
}
public String xcxLogin(String xcxCode) {
HttpServletRequest request = ServletUtils.getRequest();
// xcxCode 小程序调用 wx.login 授权后获取
// todo 以下自行实现
// 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key openid
String openid = "";
SysUser user = loadUserByOpenid(openid);
// 此处可根据登录用户的数据不同 自行创建 loginUser
XcxLoginUser loginUser = new XcxLoginUser();
loginUser.setUserId(user.getUserId());
loginUser.setUsername(user.getUserName());
loginUser.setUserType(user.getUserType());
loginUser.setOpenid(openid);
// 生成token
LoginHelper.loginByDevice(loginUser, DeviceType.XCX);
asyncService.recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), request);
recordLoginInfo(user.getUserId(), user.getUserName());
return StpUtil.getTokenValue();
}
public void logout(String loginName) { public void logout(String loginName) {
asyncService.recordLogininfor(loginName, Constants.LOGOUT, MessageUtils.message("user.logout.success"), ServletUtils.getRequest()); asyncService.recordLogininfor(loginName, Constants.LOGOUT, MessageUtils.message("user.logout.success"), ServletUtils.getRequest());
} }
/**
* 校验短信验证码
*/
private boolean validateSmsCode(String phonenumber, String smsCode) {
// todo 此处使用手机号查询redis验证码与参数验证码是否一致 用户自行实现
return true;
}
/** /**
* 校验验证码 * 校验验证码
* *
@ -136,6 +162,38 @@ public class SysLoginService {
return user; return user;
} }
private SysUser loadUserByPhonenumber(String phonenumber) {
SysUser user = userService.selectUserByPhonenumber(phonenumber);
if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", phonenumber);
throw new UserException("user.not.exists", phonenumber);
} else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
log.info("登录用户:{} 已被删除.", phonenumber);
throw new UserException("user.password.delete", phonenumber);
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", phonenumber);
throw new UserException("user.blocked", phonenumber);
}
return user;
}
private SysUser loadUserByOpenid(String openid) {
// 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户
// todo 自行实现 userService.selectUserByOpenid(openid);
SysUser user = new SysUser();
if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", openid);
// todo 用户不存在 业务逻辑自行实现
} else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
log.info("登录用户:{} 已被删除.", openid);
// todo 用户已被删除 业务逻辑自行实现
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", openid);
// todo 用户已被停用 业务逻辑自行实现
}
return user;
}
/** /**
* 构建登录用户 * 构建登录用户
*/ */
@ -166,4 +224,42 @@ public class SysLoginService {
sysUser.setUpdateBy(username); sysUser.setUpdateBy(username);
userService.updateUserProfile(sysUser); userService.updateUserProfile(sysUser);
} }
/**
* 登录校验
*/
private void checkLogin(LoginType loginType, String username, Supplier<Boolean> supplier) {
HttpServletRequest request = ServletUtils.getRequest();
String errorKey = Constants.LOGIN_ERROR + username;
Integer errorLimitTime = Constants.LOGIN_ERROR_LIMIT_TIME;
Integer setErrorNumber = Constants.LOGIN_ERROR_NUMBER;
String loginFail = Constants.LOGIN_FAIL;
// 获取用户登录错误次数(可自定义限制策略 例如: key + username + ip)
Integer errorNumber = RedisUtils.getCacheObject(errorKey);
// 锁定时间内登录 则踢出
if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(setErrorNumber)) {
asyncService.recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), errorLimitTime), request);
throw new UserException(loginType.getRetryLimitExceed(), errorLimitTime);
}
if (supplier.get()) {
// 是否第一次
errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1;
// 达到规定错误次数 则锁定登录
if (errorNumber.equals(setErrorNumber)) {
RedisUtils.setCacheObject(errorKey, errorNumber, errorLimitTime, TimeUnit.MINUTES);
asyncService.recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), errorLimitTime), request);
throw new UserException(loginType.getRetryLimitExceed(), errorLimitTime);
} else {
// 未达到规定错误次数 则递增
RedisUtils.setCacheObject(errorKey, errorNumber);
asyncService.recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber), request);
throw new UserException(loginType.getRetryLimitCount(), errorNumber);
}
}
// 登录成功 清空错误次数
RedisUtils.deleteObject(errorKey);
}
} }

View File

@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.helper.DataBaseHelper;
import com.ruoyi.system.domain.SysRoleDept; import com.ruoyi.system.domain.SysRoleDept;
import com.ruoyi.system.mapper.SysDeptMapper; import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.mapper.SysRoleDeptMapper; import com.ruoyi.system.mapper.SysRoleDeptMapper;
@ -14,6 +15,14 @@ import org.springframework.stereotype.Service;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/**
* 数据权限 实现
* <p>
* 注意: 此Service内不允许调用标注`数据权限`注解的方法
* 例如: deptMapper.selectList selectList 方法标注了`数据权限`注解 会出现循环解析的问题
*
* @author Lion Li
*/
@RequiredArgsConstructor @RequiredArgsConstructor
@Service("sdss") @Service("sdss")
public class SysDataScopeServiceImpl implements ISysDataScopeService { public class SysDataScopeServiceImpl implements ISysDataScopeService {
@ -35,11 +44,14 @@ public class SysDataScopeServiceImpl implements ISysDataScopeService {
@Override @Override
public String getDeptAndChild(Long deptId) { public String getDeptAndChild(Long deptId) {
List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
.select(SysDept::getDeptId)
.apply(DataBaseHelper.findInSet(deptId, "ancestors")));
List<Long> ids = deptList.stream().map(SysDept::getDeptId).collect(Collectors.toList());
ids.add(deptId);
List<SysDept> list = deptMapper.selectList(new LambdaQueryWrapper<SysDept>() List<SysDept> list = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
.select(SysDept::getDeptId) .select(SysDept::getDeptId)
.eq(SysDept::getDeptId, deptId) .in(SysDept::getDeptId, ids));
.or()
.apply("find_in_set({0},ancestors)", deptId));
if (CollUtil.isNotEmpty(list)) { if (CollUtil.isNotEmpty(list)) {
return list.stream().map(d -> Convert.toStr(d.getDeptId())).collect(Collectors.joining(",")); return list.stream().map(d -> Convert.toStr(d.getDeptId())).collect(Collectors.joining(","));
} }

View File

@ -11,6 +11,7 @@ import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysRole; import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.helper.DataBaseHelper;
import com.ruoyi.common.helper.LoginHelper; import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.TreeBuildUtils; import com.ruoyi.common.utils.TreeBuildUtils;
@ -21,6 +22,7 @@ import com.ruoyi.system.service.ISysDeptService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -45,7 +47,15 @@ public class SysDeptServiceImpl implements ISysDeptService {
*/ */
@Override @Override
public List<SysDept> selectDeptList(SysDept dept) { public List<SysDept> selectDeptList(SysDept dept) {
return baseMapper.selectDeptList(dept); LambdaQueryWrapper<SysDept> lqw = new LambdaQueryWrapper<>();
lqw.eq(SysDept::getDelFlag, "0")
.eq(ObjectUtil.isNotNull(dept.getDeptId()), SysDept::getDeptId, dept.getDeptId())
.eq(ObjectUtil.isNotNull(dept.getParentId()), SysDept::getParentId, dept.getParentId())
.like(StringUtils.isNotBlank(dept.getDeptName()), SysDept::getDeptName, dept.getDeptName())
.eq(StringUtils.isNotBlank(dept.getStatus()), SysDept::getStatus, dept.getStatus())
.orderByAsc(SysDept::getParentId)
.orderByAsc(SysDept::getOrderNum);
return baseMapper.selectDeptList(lqw);
} }
/** /**
@ -75,7 +85,7 @@ public class SysDeptServiceImpl implements ISysDeptService {
@Override @Override
public List<Long> selectDeptListByRoleId(Long roleId) { public List<Long> selectDeptListByRoleId(Long roleId) {
SysRole role = roleMapper.selectById(roleId); SysRole role = roleMapper.selectById(roleId);
return baseMapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly()); return baseMapper.selectDeptListByRoleId(roleId, role.getDeptCheckStrictly());
} }
/** /**
@ -99,7 +109,7 @@ public class SysDeptServiceImpl implements ISysDeptService {
public long selectNormalChildrenDeptById(Long deptId) { public long selectNormalChildrenDeptById(Long deptId) {
return baseMapper.selectCount(new LambdaQueryWrapper<SysDept>() return baseMapper.selectCount(new LambdaQueryWrapper<SysDept>()
.eq(SysDept::getStatus, UserConstants.DEPT_NORMAL) .eq(SysDept::getStatus, UserConstants.DEPT_NORMAL)
.apply("find_in_set({0}, ancestors)", deptId)); .apply(DataBaseHelper.findInSet(deptId, "ancestors")));
} }
/** /**
@ -225,12 +235,16 @@ public class SysDeptServiceImpl implements ISysDeptService {
*/ */
public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) { public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) {
List<SysDept> children = baseMapper.selectList(new LambdaQueryWrapper<SysDept>() List<SysDept> children = baseMapper.selectList(new LambdaQueryWrapper<SysDept>()
.apply("find_in_set({0},ancestors)", deptId)); .apply(DataBaseHelper.findInSet(deptId, "ancestors")));
List<SysDept> list = new ArrayList<>();
for (SysDept child : children) { for (SysDept child : children) {
child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors)); SysDept dept = new SysDept();
dept.setDeptId(child.getDeptId());
dept.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
list.add(dept);
} }
if (children.size() > 0) { if (list.size() > 0) {
baseMapper.updateDeptChildren(children); baseMapper.updateBatchById(list);
} }
} }

View File

@ -4,6 +4,8 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree; import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.entity.SysMenu; import com.ruoyi.common.core.domain.entity.SysMenu;
@ -65,8 +67,14 @@ public class SysMenuServiceImpl implements ISysMenuService {
.orderByAsc(SysMenu::getParentId) .orderByAsc(SysMenu::getParentId)
.orderByAsc(SysMenu::getOrderNum)); .orderByAsc(SysMenu::getOrderNum));
} else { } else {
menu.getParams().put("userId", userId); QueryWrapper<SysMenu> wrapper = Wrappers.query();
menuList = baseMapper.selectMenuListByUserId(menu); wrapper.eq("ur.user_id", userId)
.like(StringUtils.isNotBlank(menu.getMenuName()), "m.menu_name", menu.getMenuName())
.eq(StringUtils.isNotBlank(menu.getVisible()), "m.visible", menu.getVisible())
.eq(StringUtils.isNotBlank(menu.getStatus()), "m.status", menu.getStatus())
.orderByAsc("m.parent_id")
.orderByAsc("m.order_num");
menuList = baseMapper.selectMenuListByUserId(wrapper);
} }
return menuList; return menuList;
} }
@ -115,7 +123,7 @@ public class SysMenuServiceImpl implements ISysMenuService {
@Override @Override
public List<Long> selectMenuListByRoleId(Long roleId) { public List<Long> selectMenuListByRoleId(Long roleId) {
SysRole role = roleMapper.selectById(roleId); SysRole role = roleMapper.selectById(roleId);
return baseMapper.selectMenuListByRoleId(roleId, role.isMenuCheckStrictly()); return baseMapper.selectMenuListByRoleId(roleId, role.getMenuCheckStrictly());
} }
/** /**
@ -133,9 +141,9 @@ public class SysMenuServiceImpl implements ISysMenuService {
router.setName(getRouteName(menu)); router.setName(getRouteName(menu));
router.setPath(getRouterPath(menu)); router.setPath(getRouterPath(menu));
router.setComponent(getComponent(menu)); router.setComponent(getComponent(menu));
router.setQuery(menu.getQuery()); router.setQuery(menu.getQueryParam());
router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath())); router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
List<SysMenu> cMenus = (List<SysMenu>) menu.getChildren(); List<SysMenu> cMenus = menu.getChildren();
if (!cMenus.isEmpty() && UserConstants.TYPE_DIR.equals(menu.getMenuType())) { if (!cMenus.isEmpty() && UserConstants.TYPE_DIR.equals(menu.getMenuType())) {
router.setAlwaysShow(true); router.setAlwaysShow(true);
router.setRedirect("noRedirect"); router.setRedirect("noRedirect");
@ -148,12 +156,12 @@ public class SysMenuServiceImpl implements ISysMenuService {
children.setComponent(menu.getComponent()); children.setComponent(menu.getComponent());
children.setName(StringUtils.capitalize(menu.getPath())); children.setName(StringUtils.capitalize(menu.getPath()));
children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath())); children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
children.setQuery(menu.getQuery()); children.setQuery(menu.getQueryParam());
childrenList.add(children); childrenList.add(children);
router.setChildren(childrenList); router.setChildren(childrenList);
} else if (menu.getParentId().intValue() == 0 && isInnerLink(menu)) { } else if (menu.getParentId().intValue() == 0 && isInnerLink(menu)) {
router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon())); router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
router.setPath("/inner"); router.setPath("/");
List<RouterVo> childrenList = new ArrayList<RouterVo>(); List<RouterVo> childrenList = new ArrayList<RouterVo>();
RouterVo children = new RouterVo(); RouterVo children = new RouterVo();
String routerPath = innerLinkReplaceEach(menu.getPath()); String routerPath = innerLinkReplaceEach(menu.getPath());

View File

@ -63,7 +63,7 @@ public class SysOssConfigServiceImpl implements ISysOssConfigService {
} }
@Override @Override
public SysOssConfigVo queryById(Integer ossConfigId) { public SysOssConfigVo queryById(Long ossConfigId) {
return baseMapper.selectVoById(ossConfigId); return baseMapper.selectVoById(ossConfigId);
} }

View File

@ -2,7 +2,11 @@ package com.ruoyi.system.service.impl;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.PageQuery; import com.ruoyi.common.core.domain.PageQuery;
@ -40,7 +44,7 @@ public class SysRoleServiceImpl implements ISysRoleService {
@Override @Override
public TableDataInfo<SysRole> selectPageRoleList(SysRole role, PageQuery pageQuery) { public TableDataInfo<SysRole> selectPageRoleList(SysRole role, PageQuery pageQuery) {
Page<SysRole> page = baseMapper.selectPageRoleList(pageQuery.build(), role); Page<SysRole> page = baseMapper.selectPageRoleList(pageQuery.build(), this.buildQueryWrapper(role));
return TableDataInfo.build(page); return TableDataInfo.build(page);
} }
@ -52,7 +56,21 @@ public class SysRoleServiceImpl implements ISysRoleService {
*/ */
@Override @Override
public List<SysRole> selectRoleList(SysRole role) { public List<SysRole> selectRoleList(SysRole role) {
return baseMapper.selectRoleList(role); return baseMapper.selectRoleList(this.buildQueryWrapper(role));
}
private Wrapper<SysRole> buildQueryWrapper(SysRole role) {
Map<String, Object> params = role.getParams();
QueryWrapper<SysRole> wrapper = Wrappers.query();
wrapper.eq("r.del_flag", UserConstants.ROLE_NORMAL)
.eq(ObjectUtil.isNotNull(role.getRoleId()), "r.role_id", role.getRoleId())
.like(StringUtils.isNotBlank(role.getRoleName()), "r.role_name", role.getRoleName())
.eq(StringUtils.isNotBlank(role.getStatus()), "r.status", role.getStatus())
.like(StringUtils.isNotBlank(role.getRoleKey()), "r.role_key", role.getRoleKey())
.between(params.get("beginTime") != null && params.get("endTime") != null,
"r.create_time", params.get("beginTime"), params.get("endTime"))
.orderByAsc("r.role_sort");
return wrapper;
} }
/** /**

View File

@ -2,15 +2,20 @@ package com.ruoyi.system.service.impl;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.PageQuery; import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysRole; import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.helper.DataBaseHelper;
import com.ruoyi.common.helper.LoginHelper; import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysPost; import com.ruoyi.system.domain.SysPost;
@ -26,6 +31,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -39,6 +45,7 @@ import java.util.stream.Collectors;
public class SysUserServiceImpl implements ISysUserService { public class SysUserServiceImpl implements ISysUserService {
private final SysUserMapper baseMapper; private final SysUserMapper baseMapper;
private final SysDeptMapper deptMapper;
private final SysRoleMapper roleMapper; private final SysRoleMapper roleMapper;
private final SysPostMapper postMapper; private final SysPostMapper postMapper;
private final SysUserRoleMapper userRoleMapper; private final SysUserRoleMapper userRoleMapper;
@ -46,7 +53,7 @@ public class SysUserServiceImpl implements ISysUserService {
@Override @Override
public TableDataInfo<SysUser> selectPageUserList(SysUser user, PageQuery pageQuery) { public TableDataInfo<SysUser> selectPageUserList(SysUser user, PageQuery pageQuery) {
Page<SysUser> page = baseMapper.selectPageUserList(pageQuery.build(), user); Page<SysUser> page = baseMapper.selectPageUserList(pageQuery.build(), this.buildQueryWrapper(user));
return TableDataInfo.build(page); return TableDataInfo.build(page);
} }
@ -58,7 +65,28 @@ public class SysUserServiceImpl implements ISysUserService {
*/ */
@Override @Override
public List<SysUser> selectUserList(SysUser user) { public List<SysUser> selectUserList(SysUser user) {
return baseMapper.selectUserList(user); return baseMapper.selectUserList(this.buildQueryWrapper(user));
}
private Wrapper<SysUser> buildQueryWrapper(SysUser user) {
Map<String, Object> params = user.getParams();
QueryWrapper<SysUser> wrapper = Wrappers.query();
wrapper.eq("u.del_flag", UserConstants.USER_NORMAL)
.eq(ObjectUtil.isNotNull(user.getUserId()), "u.user_id", user.getUserId())
.like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
.eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus())
.like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber())
.between(params.get("beginTime") != null && params.get("endTime") != null,
"u.create_time", params.get("beginTime"), params.get("endTime"))
.and(ObjectUtil.isNotNull(user.getDeptId()), w -> {
List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
.select(SysDept::getDeptId)
.apply(DataBaseHelper.findInSet(user.getDeptId(), "ancestors")));
List<Long> ids = deptList.stream().map(SysDept::getDeptId).collect(Collectors.toList());
ids.add(user.getDeptId());
w.in("u.dept_id", ids);
});
return wrapper;
} }
/** /**
@ -69,7 +97,13 @@ public class SysUserServiceImpl implements ISysUserService {
*/ */
@Override @Override
public TableDataInfo<SysUser> selectAllocatedList(SysUser user, PageQuery pageQuery) { public TableDataInfo<SysUser> selectAllocatedList(SysUser user, PageQuery pageQuery) {
Page<SysUser> page = baseMapper.selectAllocatedList(pageQuery.build(), user); QueryWrapper<SysUser> wrapper = Wrappers.query();
wrapper.eq("u.del_flag", UserConstants.USER_NORMAL)
.eq(ObjectUtil.isNotNull(user.getRoleId()), "r.role_id", user.getRoleId())
.like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
.eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus())
.like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber());
Page<SysUser> page = baseMapper.selectAllocatedList(pageQuery.build(), wrapper);
return TableDataInfo.build(page); return TableDataInfo.build(page);
} }
@ -81,7 +115,14 @@ public class SysUserServiceImpl implements ISysUserService {
*/ */
@Override @Override
public TableDataInfo<SysUser> selectUnallocatedList(SysUser user, PageQuery pageQuery) { public TableDataInfo<SysUser> selectUnallocatedList(SysUser user, PageQuery pageQuery) {
Page<SysUser> page = baseMapper.selectUnallocatedList(pageQuery.build(), user); List<Long> userId = userRoleMapper.selectUserIdsByRoleId(user.getRoleId());
QueryWrapper<SysUser> wrapper = Wrappers.query();
wrapper.eq("u.del_flag", UserConstants.USER_NORMAL)
.and(w -> w.ne("r.role_id", user.getRoleId()).or().isNull("r.role_id"))
.notIn("u.user_id", userId)
.like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
.like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber());
Page<SysUser> page = baseMapper.selectUnallocatedList(pageQuery.build(), wrapper);
return TableDataInfo.build(page); return TableDataInfo.build(page);
} }
@ -96,6 +137,17 @@ public class SysUserServiceImpl implements ISysUserService {
return baseMapper.selectUserByUserName(userName); return baseMapper.selectUserByUserName(userName);
} }
/**
* 通过手机号查询用户
*
* @param phonenumber 手机号
* @return 用户对象信息
*/
@Override
public SysUser selectUserByPhonenumber(String phonenumber) {
return baseMapper.selectUserByPhonenumber(phonenumber);
}
/** /**
* 通过用户ID查询用户 * 通过用户ID查询用户
* *

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