!86 同步dev分支

Merge pull request !86 from 疯狂的狮子Li/dev
This commit is contained in:
疯狂的狮子Li 2021-09-07 05:50:21 +00:00 committed by Gitee
commit c2efaa5c3c
157 changed files with 3744 additions and 882 deletions

View File

@ -10,9 +10,6 @@ end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
[*.java]
indent_style = tab
[*.{json,yml}]
indent_size = 2

View File

@ -4,7 +4,7 @@
[![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)
<br>
[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-3.0.0-success.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus)
[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-3.1.0-success.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus)
[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-2.5-blue.svg)]()
[![JDK-8+](https://img.shields.io/badge/JDK-8+-green.svg)]()
[![JDK-11](https://img.shields.io/badge/JDK-11-green.svg)]()

View File

@ -22,11 +22,16 @@ port(){
##放置挂载文件
mount(){
#挂载配置文件
#挂载 nginx 配置文件
if test ! -f "/docker/nginx/conf/nginx.conf" ;then
mkdir -p /docker/nginx/conf
cp nginx/nginx.conf /docker/nginx/conf/nginx.conf
fi
#挂载 redis 配置文件
if test ! -f "/docker/redis/conf/redis.conf" ;then
mkdir -p /docker/redis/conf
cp redis/redis.conf /docker/redis/conf/redis.conf
fi
}
#启动基础模块

View File

@ -65,10 +65,10 @@ services:
TZ: Asia/Shanghai
volumes:
# 配置文件
- /docker/redis/conf/redis.conf:/redis.conf:rw
- /docker/redis/conf:/redis/config:rw
# 数据文件
- /docker/redis/data:/data:rw
command: "redis-server --appendonly yes"
- /docker/redis/data:/redis/data:rw
command: "redis-server /redis/config/redis.conf --appendonly yes"
privileged: true
restart: always
networks:
@ -77,7 +77,7 @@ services:
minio:
image: minio/minio:RELEASE.2021-07-08T01-15-01Z
hostname: "minio"
container_name: minio
ports:
# api 端口
- 9000:9000
@ -103,14 +103,14 @@ services:
ipv4_address: 172.30.0.54
ruoyi-server1:
image: "ruoyi/ruoyi-server:3.0.0"
image: "ruoyi/ruoyi-server:3.1.0"
container_name: ruoyi-server1
environment:
# 时区上海
TZ: Asia/Shanghai
volumes:
# 配置文件
- /docker/server1/logs/:/ruoyi/server/logs/
- /docker/ruoyi/uploadPath/:/ruoyi/server/ruoyi/uploadPath/
privileged: true
restart: always
networks:
@ -118,14 +118,14 @@ services:
ipv4_address: 172.30.0.60
ruoyi-server2:
image: "ruoyi/ruoyi-server:3.0.0"
image: "ruoyi/ruoyi-server:3.1.0"
container_name: ruoyi-server2
environment:
# 时区上海
TZ: Asia/Shanghai
volumes:
# 配置文件
- /docker/server2/logs/:/ruoyi/server/logs/
- /docker/ruoyi/uploadPath/:/ruoyi/server/ruoyi/uploadPath/
privileged: true
restart: always
networks:
@ -133,7 +133,8 @@ services:
ipv4_address: 172.30.0.61
ruoyi-monitor-admin:
image: "ruoyi/ruoyi-monitor-admin:3.0.0"
image: "ruoyi/ruoyi-monitor-admin:3.1.0"
container_name: ruoyi-monitor-admin
environment:
# 时区上海
TZ: Asia/Shanghai

View File

@ -22,6 +22,7 @@ http {
access_log /var/log/nginx/access.log main;
upstream server {
ip_hash;
server 172.30.0.60:8080;
server 172.30.0.61:8080;
}

2
docker/redis/redis.conf Normal file
View File

@ -0,0 +1,2 @@
# redis 密码
# requirepass 123456

24
pom.xml
View File

@ -6,41 +6,41 @@
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-vue-plus</artifactId>
<version>3.0.0</version>
<version>3.1.0</version>
<name>RuoYi-Vue-Plus</name>
<url>https://gitee.com/JavaLionLi/RuoYi-Vue-Plus</url>
<description>RuoYi-Vue-Plus后台管理系统</description>
<properties>
<ruoyi-vue-plus.version>3.0.0</ruoyi-vue-plus.version>
<spring-boot.version>2.5.3</spring-boot.version>
<ruoyi-vue-plus.version>3.1.0</ruoyi-vue-plus.version>
<spring-boot.version>2.5.4</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<maven-jar-plugin.version>3.2.0</maven-jar-plugin.version>
<druid.version>1.2.6</druid.version>
<knife4j.version>3.0.3</knife4j.version>
<poi.version>4.1.2</poi.version>
<easyexcel.version>2.2.10</easyexcel.version>
<velocity.version>1.7</velocity.version>
<jwt.version>0.9.1</jwt.version>
<mybatis-plus.version>3.4.3</mybatis-plus.version>
<mybatis-plus.version>3.4.3.3</mybatis-plus.version>
<p6spy.version>3.9.1</p6spy.version>
<hutool.version>5.7.7</hutool.version>
<hutool.version>5.7.11</hutool.version>
<feign.version>3.0.3</feign.version>
<feign-okhttp.version>11.2</feign-okhttp.version>
<feign-okhttp.version>11.6</feign-okhttp.version>
<okhttp.version>4.9.1</okhttp.version>
<spring-boot-admin.version>2.5.0</spring-boot-admin.version>
<redisson.version>3.16.1</redisson.version>
<spring-boot-admin.version>2.5.1</spring-boot-admin.version>
<redisson.version>3.16.2</redisson.version>
<lock4j.version>2.2.1</lock4j.version>
<dynamic-ds.version>3.4.1</dynamic-ds.version>
<!-- OSS 配置 -->
<qiniu.version>7.8.0</qiniu.version>
<aliyun.oss.version>3.13.0</aliyun.oss.version>
<qcloud.cos.version>5.6.47</qcloud.cos.version>
<minio.version>8.2.0</minio.version>
<aliyun.oss.version>3.13.1</aliyun.oss.version>
<qcloud.cos.version>5.6.51</qcloud.cos.version>
<minio.version>8.3.0</minio.version>
<!-- docker 配置 -->
<docker.registry.url>localhost</docker.registry.url>

View File

@ -4,7 +4,6 @@ MAINTAINER Lion Li
RUN mkdir -p /ruoyi/server
RUN mkdir -p /ruoyi/server/logs
RUN mkdir -p /ruoyi/server/ruoyi/uploadPath
WORKDIR /ruoyi/server

View File

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

View File

@ -1,25 +1,22 @@
package com.ruoyi.web.controller.common;
import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.captcha.ShearCaptcha;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.captcha.generator.RandomGenerator;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.framework.captcha.UnsignedMathGenerator;
import com.ruoyi.common.enums.CaptchaType;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.reflect.ReflectUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.config.properties.CaptchaProperties;
import com.ruoyi.system.service.ISysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@ -32,19 +29,6 @@ import java.util.concurrent.TimeUnit;
@RestController
public class CaptchaController {
// 圆圈干扰验证码
@Resource(name = "CircleCaptcha")
private CircleCaptcha circleCaptcha;
// 线段干扰的验证码
@Resource(name = "LineCaptcha")
private LineCaptcha lineCaptcha;
// 扭曲干扰验证码
@Resource(name = "ShearCaptcha")
private ShearCaptcha shearCaptcha;
@Autowired
private RedisCache redisCache;
@Autowired
private CaptchaProperties captchaProperties;
@ -65,41 +49,16 @@ public class CaptchaController {
// 保存验证码信息
String uuid = IdUtil.simpleUUID();
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
String code = null;
// 生成验证码
CodeGenerator codeGenerator;
AbstractCaptcha captcha;
switch (captchaProperties.getType()) {
case "math":
codeGenerator = new UnsignedMathGenerator(captchaProperties.getNumberLength());
break;
case "char":
codeGenerator = new RandomGenerator(captchaProperties.getCharLength());
break;
default:
throw new IllegalArgumentException("验证码类型异常");
}
switch (captchaProperties.getCategory()) {
case "line":
captcha = lineCaptcha;
break;
case "circle":
captcha = circleCaptcha;
break;
case "shear":
captcha = shearCaptcha;
break;
default:
throw new IllegalArgumentException("验证码类别异常");
}
CaptchaType captchaType = captchaProperties.getType();
boolean isMath = CaptchaType.MATH == captchaType;
Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength();
CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length);
AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz());
captcha.setGenerator(codeGenerator);
captcha.createCode();
if ("math".equals(captchaProperties.getType())) {
code = getCodeResult(captcha.getCode());
} else if ("char".equals(captchaProperties.getType())) {
code = captcha.getCode();
}
redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
String code = isMath ? getCodeResult(captcha.getCode()) : captcha.getCode();
RedisUtils.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
ajax.put("uuid", uuid);
ajax.put("img", captcha.getImageBase64());
return AjaxResult.success(ajax);
@ -112,13 +71,13 @@ public class CaptchaController {
int b = Convert.toInt(StringUtils.substring(capStr, numberLength + 1, numberLength + 1 + numberLength).trim());
switch (operator) {
case '*':
return a * b + "";
return Convert.toStr(a * b);
case '+':
return a + b + "";
return Convert.toStr(a + b);
case '-':
return a - b + "";
return Convert.toStr(a - b);
default:
return "";
return StringUtils.EMPTY;
}
}

View File

@ -6,9 +6,9 @@ import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysUserOnline;
import com.ruoyi.system.service.ISysUserOnlineService;
@ -33,18 +33,15 @@ public class SysUserOnlineController extends BaseController
@Autowired
private ISysUserOnlineService userOnlineService;
@Autowired
private RedisCache redisCache;
@PreAuthorize("@ss.hasPermi('monitor:online:list')")
@GetMapping("/list")
public TableDataInfo list(String ipaddr, String userName)
{
Collection<String> keys = redisCache.keys(Constants.LOGIN_TOKEN_KEY + "*");
Collection<String> keys = RedisUtils.keys(Constants.LOGIN_TOKEN_KEY + "*");
List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
for (String key : keys)
{
LoginUser user = redisCache.getCacheObject(key);
LoginUser user = RedisUtils.getCacheObject(key);
if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
{
if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername()))
@ -84,7 +81,7 @@ public class SysUserOnlineController extends BaseController
@DeleteMapping("/{tokenId}")
public AjaxResult forceLogout(@PathVariable String tokenId)
{
redisCache.deleteObject(Constants.LOGIN_TOKEN_KEY + tokenId);
RedisUtils.deleteObject(Constants.LOGIN_TOKEN_KEY + tokenId);
return AjaxResult.success();
}
}

View File

@ -70,6 +70,7 @@ public class SysDeptController extends BaseController
@GetMapping(value = "/{deptId}")
public AjaxResult getInfo(@PathVariable Long deptId)
{
deptService.checkDeptDataScope(deptId);
return AjaxResult.success(deptService.selectDeptById(deptId));
}

View File

@ -5,12 +5,9 @@ import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.framework.web.service.SysLoginService;
import com.ruoyi.framework.web.service.SysPermissionService;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.service.ISysMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
@ -40,9 +37,6 @@ public class SysLoginController
@Autowired
private SysPermissionService permissionService;
@Autowired
private TokenService tokenService;
/**
* 登录方法
*
@ -68,8 +62,7 @@ public class SysLoginController
@GetMapping("getInfo")
public AjaxResult getInfo()
{
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
SysUser user = loginUser.getUser();
SysUser user = SecurityUtils.getLoginUser().getUser();
// 角色集合
Set<String> roles = permissionService.getRolePermission(user);
// 权限集合

View File

@ -7,6 +7,7 @@ import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.bo.SysOssConfigBo;
import com.ruoyi.system.domain.vo.SysOssConfigVo;
@ -45,7 +46,7 @@ public class SysOssConfigController extends BaseController {
@ApiOperation("查询云存储配置列表")
@PreAuthorize("@ss.hasPermi('system:oss:list')")
@GetMapping("/list")
public TableDataInfo<SysOssConfigVo> list(@Validated SysOssConfigBo bo) {
public TableDataInfo<SysOssConfigVo> list(@Validated(QueryGroup.class) SysOssConfigBo bo) {
return iSysOssConfigService.queryPageList(bo);
}

View File

@ -10,6 +10,7 @@ import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.JsonUtils;
@ -63,7 +64,7 @@ public class SysOssController extends BaseController {
@ApiOperation("查询OSS云存储列表")
@PreAuthorize("@ss.hasPermi('system:oss:list')")
@GetMapping("/list")
public TableDataInfo<SysOssVo> list(@Validated SysOssBo bo) {
public TableDataInfo<SysOssVo> list(@Validated(QueryGroup.class) SysOssBo bo) {
return iSysOssService.queryPageList(bo);
}

View File

@ -8,7 +8,6 @@ import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.domain.SysOss;
@ -46,7 +45,7 @@ public class SysProfileController extends BaseController
@GetMapping
public AjaxResult profile()
{
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
LoginUser loginUser = getLoginUser();
SysUser user = loginUser.getUser();
Map<String,Object> ajax = new HashMap<>();
ajax.put("user", user);
@ -72,17 +71,17 @@ public class SysProfileController extends BaseController
{
return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
}
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
LoginUser loginUser = getLoginUser();
SysUser sysUser = loginUser.getUser();
user.setUserId(sysUser.getUserId());
user.setPassword(null);
if (userService.updateUserProfile(user) > 0)
{
// 更新缓存用户信息
loginUser.getUser().setNickName(user.getNickName());
loginUser.getUser().setPhonenumber(user.getPhonenumber());
loginUser.getUser().setEmail(user.getEmail());
loginUser.getUser().setSex(user.getSex());
sysUser.setNickName(user.getNickName());
sysUser.setPhonenumber(user.getPhonenumber());
sysUser.setEmail(user.getEmail());
sysUser.setSex(user.getSex());
tokenService.setLoginUser(loginUser);
return AjaxResult.success();
}
@ -96,7 +95,7 @@ public class SysProfileController extends BaseController
@PutMapping("/updatePwd")
public AjaxResult updatePwd(String oldPassword, String newPassword)
{
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
LoginUser loginUser = getLoginUser();
String userName = loginUser.getUsername();
String password = loginUser.getPassword();
if (!SecurityUtils.matchesPassword(oldPassword, password))
@ -126,7 +125,7 @@ public class SysProfileController extends BaseController
{
if (!file.isEmpty())
{
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
LoginUser loginUser = getLoginUser();
SysOss oss = iSysOssService.upload(file);
String avatar = oss.getUrl();
if (userService.updateUserAvatar(loginUser.getUsername(), avatar))

View File

@ -9,7 +9,6 @@ import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.service.SysPermissionService;
@ -69,6 +68,7 @@ public class SysRoleController extends BaseController
@GetMapping(value = "/{roleId}")
public AjaxResult getInfo(@PathVariable Long roleId)
{
roleService.checkRoleDataScope(roleId);
return AjaxResult.success(roleService.selectRoleById(roleId));
}
@ -115,7 +115,7 @@ public class SysRoleController extends BaseController
if (roleService.updateRole(role) > 0)
{
// 更新缓存用户权限
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
LoginUser loginUser = getLoginUser();
if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin())
{
loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));

View File

@ -10,14 +10,11 @@ import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.domain.vo.SysUserExportVo;
import com.ruoyi.system.domain.vo.SysUserImportVo;
import com.ruoyi.system.service.ISysPostService;
@ -54,9 +51,6 @@ public class SysUserController extends BaseController
@Autowired
private ISysPostService postService;
@Autowired
private TokenService tokenService;
/**
* 获取用户列表
*/
@ -92,8 +86,7 @@ public class SysUserController extends BaseController
{
List<SysUserImportVo> userListVo = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class);
List<SysUser> userList = BeanUtil.copyToList(userListVo, SysUser.class);
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
String operName = loginUser.getUsername();
String operName = getUsername();
String message = userService.importUser(userList, updateSupport, operName);
return AjaxResult.success(message);
}
@ -111,6 +104,7 @@ public class SysUserController extends BaseController
@GetMapping(value = { "/", "/{userId}" })
public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
{
userService.checkUserDataScope(userId);
Map<String, Object> ajax = new HashMap<>();
List<SysRole> roles = roleService.selectRoleAll();
ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));

View File

@ -38,7 +38,7 @@ spring:
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
validationQuery: SELECT 1
testWhileIdle: true
testOnBorrow: false
testOnReturn: false

View File

@ -38,7 +38,7 @@ spring:
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
validationQuery: SELECT 1
testWhileIdle: true
testOnBorrow: false
testOnReturn: false

View File

@ -12,10 +12,11 @@ ruoyi:
addressEnabled: true
captcha:
# 页面 <参数设置> 可开启关闭 验证码校验
# 验证码类型 math 数组计算 char 字符验证
type: math
type: MATH
# line 线段干扰 circle 圆圈干扰 shear 扭曲干扰
category: circle
category: CIRCLE
# 数字验证码位数
numberLength: 1
# 字符验证码长度
@ -133,8 +134,6 @@ mybatis-plus:
# REUSE该执行器类型会复用预处理语句PreparedStatement
# BATCH该执行器类型会批量执行所有的更新语句
executorType: SIMPLE
# 指定外部化 MyBatis Properties 配置,通过该配置可以抽离配置,实现不同环境的配置部署
configurationProperties: null
configuration:
# 自动驼峰命名规则camel case映射
# 如果您的数据库命名符合规则无需使用 @TableField 注解指定数据库字段名
@ -199,11 +198,11 @@ mybatis-plus:
# NOT_EMPTY 非空判断(只对字符串类型字段,其他类型字段依然为非NULL判断)
# DEFAULT 默认的,一般只用于注解里
# NEVER 不加入 SQL
insertStrategy: NOT_EMPTY
insertStrategy: NOT_NULL
# 字段验证策略之 update,在 update 的时候的字段验证策略
updateStrategy: NOT_EMPTY
updateStrategy: NOT_NULL
# 字段验证策略之 select,在 select 的时候的字段验证策略既 wrapper 根据内部 entity 生成的 where 条件
selectStrategy: NOT_EMPTY
where-strategy: NOT_NULL
# Swagger配置
swagger:
@ -245,11 +244,11 @@ thread-pool:
# 线程池维护线程所允许的空闲时间
keepAliveSeconds: 300
# 线程池对拒绝任务(无线程可用)的处理策略
# CallerRunsPolicy 等待
# DiscardOldestPolicy 放弃最旧的
# DiscardPolicy 丢弃
# AbortPolicy 中止
rejectedExecutionHandler: CallerRunsPolicy
# CALLER_RUNS_POLICY 等待
# DISCARD_OLDEST_POLICY 放弃最旧的
# DISCARD_POLICY 丢弃
# ABORT_POLICY 中止
rejectedExecutionHandler: CALLER_RUNS_POLICY
# feign 相关配置
feign:

View File

@ -1,26 +1,26 @@
# p6spy 性能分析插件配置文件
# p6spy 性能分析插件配置文件
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
# 设置 p6spy driver 代理
#deregisterdrivers=true
# 取消JDBC URL前缀
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
# 慢SQL记录标准 2 秒
outagedetectioninterval=2
# 是否过滤 Log
# 是否过滤 Log
filter=true
# 过滤 Log 时所排除的表名列表,以逗号分隔
# 过滤 Log 时所排除的表名列表,以逗号分隔
exclude=QRTZ_

View File

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

View File

@ -1,4 +1,4 @@
package com.ruoyi.framework.captcha;
package com.ruoyi.common.captcha;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.math.Calculator;

View File

@ -139,4 +139,8 @@ public class Constants
*/
public static final String LOOKUP_RMI = "rmi://";
/**
* LDAP 远程方法调用
*/
public static final String LOOKUP_LDAP = "ldap://";
}

View File

@ -0,0 +1,51 @@
package com.ruoyi.common.convert;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
/**
* 大数值转换
* Excel 数值长度位15位 大于15位的数值转换位字符串
*
* @author Lion Li
*/
@Slf4j
public class ExcelBigNumberConvert implements Converter<Long> {
@Override
public Class<Long> supportJavaTypeKey() {
return Long.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
public Long convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
return Convert.toLong(cellData.getData());
}
@Override
public CellData<Object> convertToExcelData(Long object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
if (ObjectUtil.isNotNull(object)) {
String str = Convert.toStr(object);
if (str.length() > 15) {
return new CellData<>(str);
}
}
CellData<Object> cellData = new CellData<>(new BigDecimal(object));
cellData.setType(CellDataTypeEnum.NUMBER);
return cellData;
}
}

View File

@ -16,28 +16,6 @@ public class BaseController
{
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 响应返回结果
*
* @param rows 影响行数
* @return 操作结果
*/
protected AjaxResult<Void> toAjax(int rows)
{
return rows > 0 ? AjaxResult.success() : AjaxResult.error();
}
/**
* 响应返回结果
*
* @param result 结果
* @return 操作结果
*/
protected AjaxResult<Void> toAjax(boolean result)
{
return result ? success() : error();
}
/**
* 返回成功
*/
@ -70,6 +48,28 @@ public class BaseController
return AjaxResult.error(message);
}
/**
* 响应返回结果
*
* @param rows 影响行数
* @return 操作结果
*/
protected AjaxResult<Void> toAjax(int rows)
{
return rows > 0 ? AjaxResult.success() : AjaxResult.error();
}
/**
* 响应返回结果
*
* @param result 结果
* @return 操作结果
*/
protected AjaxResult<Void> toAjax(boolean result)
{
return result ? success() : error();
}
/**
* 页面跳转
*/

View File

@ -78,6 +78,11 @@ public class SysUser implements Serializable {
/**
* 密码
*/
@TableField(
insertStrategy = FieldStrategy.NOT_EMPTY,
updateStrategy = FieldStrategy.NOT_EMPTY,
whereStrategy = FieldStrategy.NOT_EMPTY
)
private String password;
@JsonIgnore

View File

@ -1,7 +1,7 @@
package com.ruoyi.common.core.mybatisplus.cache;
import cn.hutool.extra.spring.SpringUtil;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.connection.RedisServerCommands;
@ -25,8 +25,6 @@ public class MybatisPlusRedisCache implements Cache {
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
private RedisCache redisCache;
private String id;
public MybatisPlusRedisCache(final String id) {
@ -43,23 +41,16 @@ public class MybatisPlusRedisCache implements Cache {
@Override
public void putObject(Object key, Object value) {
if (redisCache == null) {
redisCache = SpringUtil.getBean(RedisCache.class);
}
if (value != null) {
redisCache.setCacheObject(key.toString(), value);
RedisUtils.setCacheObject(key.toString(), value);
}
}
@Override
public Object getObject(Object key) {
if (redisCache == null) {
//由于启动期间注入失败只能运行期间注入这段代码可以删除
redisCache = SpringUtil.getBean(RedisCache.class);
}
try {
if (key != null) {
return redisCache.getCacheObject(key.toString());
return RedisUtils.getCacheObject(key.toString());
}
} catch (Exception e) {
e.printStackTrace();
@ -70,11 +61,8 @@ public class MybatisPlusRedisCache implements Cache {
@Override
public Object removeObject(Object key) {
if (redisCache == null) {
redisCache = SpringUtil.getBean(RedisCache.class);
}
if (key != null) {
redisCache.deleteObject(key.toString());
RedisUtils.deleteObject(key.toString());
}
return null;
}
@ -82,12 +70,9 @@ public class MybatisPlusRedisCache implements Cache {
@Override
public void clear() {
log.debug("清空缓存");
if (redisCache == null) {
redisCache = SpringUtil.getBean(RedisCache.class);
}
Collection<String> keys = redisCache.keys("*:" + this.id + "*");
Collection<String> keys = RedisUtils.keys("*:" + this.id + "*");
if (!CollectionUtils.isEmpty(keys)) {
redisCache.deleteObject(keys);
RedisUtils.deleteObject(keys);
}
}

View File

@ -14,8 +14,7 @@ import java.util.Collection;
public interface BaseMapperPlus<T> extends BaseMapper<T> {
/**
* 单sql批量插入( 全量填充 无视数据库默认值 )
* 适用于无脑插入
* 单sql批量插入( 全量填充 )
*/
int insertAll(@Param("list") Collection<T> batchList);

View File

@ -15,45 +15,46 @@ import java.util.function.Function;
/**
* 自定义 Service 接口, 实现 数据库实体与 vo 对象转换返回
*
* @param <T> 数据实体类
* @param <V> vo类
* @author Lion Li
* @since 2021-05-13
*/
public interface IServicePlus<T, K> extends IService<T> {
public interface IServicePlus<T, V> extends IService<T> {
/**
* @param id 主键id
* @param copyOptions copy条件
* @return K对象
* @return V对象
*/
K getVoById(Serializable id, CopyOptions copyOptions);
V getVoById(Serializable id, CopyOptions copyOptions);
default K getVoById(Serializable id) {
default V getVoById(Serializable id) {
return getVoById(id, new CopyOptions());
}
/**
* @param convertor 自定义转换器
*/
default K getVoById(Serializable id, Function<T, K> convertor) {
default V getVoById(Serializable id, Function<T, V> convertor) {
return convertor.apply(getById(id));
}
/**
* @param idList id列表
* @param copyOptions copy条件
* @return K对象
* @return V对象
*/
List<K> listVoByIds(Collection<? extends Serializable> idList, CopyOptions copyOptions);
List<V> listVoByIds(Collection<? extends Serializable> idList, CopyOptions copyOptions);
default List<K> listVoByIds(Collection<? extends Serializable> idList) {
default List<V> listVoByIds(Collection<? extends Serializable> idList) {
return listVoByIds(idList, new CopyOptions());
}
/**
* @param convertor 自定义转换器
*/
default List<K> listVoByIds(Collection<? extends Serializable> idList,
Function<Collection<T>, List<K>> convertor) {
default List<V> listVoByIds(Collection<? extends Serializable> idList,
Function<Collection<T>, List<V>> convertor) {
List<T> list = getBaseMapper().selectBatchIds(idList);
if (list == null) {
return null;
@ -64,19 +65,19 @@ public interface IServicePlus<T, K> extends IService<T> {
/**
* @param columnMap 表字段 map 对象
* @param copyOptions copy条件
* @return K对象
* @return V对象
*/
List<K> listVoByMap(Map<String, Object> columnMap, CopyOptions copyOptions);
List<V> listVoByMap(Map<String, Object> columnMap, CopyOptions copyOptions);
default List<K> listVoByMap(Map<String, Object> columnMap) {
default List<V> listVoByMap(Map<String, Object> columnMap) {
return listVoByMap(columnMap, new CopyOptions());
}
/**
* @param convertor 自定义转换器
*/
default List<K> listVoByMap(Map<String, Object> columnMap,
Function<Collection<T>, List<K>> convertor) {
default List<V> listVoByMap(Map<String, Object> columnMap,
Function<Collection<T>, List<V>> convertor) {
List<T> list = getBaseMapper().selectByMap(columnMap);
if (list == null) {
return null;
@ -87,36 +88,36 @@ public interface IServicePlus<T, K> extends IService<T> {
/**
* @param queryWrapper 查询条件
* @param copyOptions copy条件
* @return K对象
* @return V对象
*/
K getVoOne(Wrapper<T> queryWrapper, CopyOptions copyOptions);
V getVoOne(Wrapper<T> queryWrapper, CopyOptions copyOptions);
default K getVoOne(Wrapper<T> queryWrapper) {
default V getVoOne(Wrapper<T> queryWrapper) {
return getVoOne(queryWrapper, new CopyOptions());
}
/**
* @param convertor 自定义转换器
*/
default K getVoOne(Wrapper<T> queryWrapper, Function<T, K> convertor) {
default V getVoOne(Wrapper<T> queryWrapper, Function<T, V> convertor) {
return convertor.apply(getOne(queryWrapper, true));
}
/**
* @param queryWrapper 查询条件
* @param copyOptions copy条件
* @return K对象
* @return V对象
*/
List<K> listVo(Wrapper<T> queryWrapper, CopyOptions copyOptions);
List<V> listVo(Wrapper<T> queryWrapper, CopyOptions copyOptions);
default List<K> listVo(Wrapper<T> queryWrapper) {
default List<V> listVo(Wrapper<T> queryWrapper) {
return listVo(queryWrapper, new CopyOptions());
}
/**
* @param convertor 自定义转换器
*/
default List<K> listVo(Wrapper<T> queryWrapper, Function<Collection<T>, List<K>> convertor) {
default List<V> listVo(Wrapper<T> queryWrapper, Function<Collection<T>, List<V>> convertor) {
List<T> list = getBaseMapper().selectList(queryWrapper);
if (list == null) {
return null;
@ -124,14 +125,14 @@ public interface IServicePlus<T, K> extends IService<T> {
return convertor.apply(list);
}
default List<K> listVo() {
default List<V> listVo() {
return listVo(Wrappers.emptyWrapper());
}
/**
* @param convertor 自定义转换器
*/
default List<K> listVo(Function<Collection<T>, List<K>> convertor) {
default List<V> listVo(Function<Collection<T>, List<V>> convertor) {
return listVo(Wrappers.emptyWrapper(), convertor);
}
@ -139,34 +140,36 @@ public interface IServicePlus<T, K> extends IService<T> {
* @param page 分页对象
* @param queryWrapper 查询条件
* @param copyOptions copy条件
* @return K对象
* @return V对象
*/
PagePlus<T, K> pageVo(PagePlus<T, K> page, Wrapper<T> queryWrapper, CopyOptions copyOptions);
PagePlus<T, V> pageVo(PagePlus<T, V> page, Wrapper<T> queryWrapper, CopyOptions copyOptions);
default PagePlus<T, K> pageVo(PagePlus<T, K> page, Wrapper<T> queryWrapper) {
default PagePlus<T, V> pageVo(PagePlus<T, V> page, Wrapper<T> queryWrapper) {
return pageVo(page, queryWrapper, new CopyOptions());
}
/**
* @param convertor 自定义转换器
*/
default PagePlus<T, K> pageVo(PagePlus<T, K> page, Wrapper<T> queryWrapper,
Function<Collection<T>, List<K>> convertor) {
PagePlus<T, K> result = getBaseMapper().selectPage(page, queryWrapper);
default PagePlus<T, V> pageVo(PagePlus<T, V> page, Wrapper<T> queryWrapper,
Function<Collection<T>, List<V>> convertor) {
PagePlus<T, V> result = getBaseMapper().selectPage(page, queryWrapper);
return result.setRecordsVo(convertor.apply(result.getRecords()));
}
default PagePlus<T, K> pageVo(PagePlus<T, K> page) {
default PagePlus<T, V> pageVo(PagePlus<T, V> page) {
return pageVo(page, Wrappers.emptyWrapper());
}
/**
* @param convertor 自定义转换器
*/
default PagePlus<T, K> pageVo(PagePlus<T, K> page, Function<Collection<T>, List<K>> convertor) {
default PagePlus<T, V> pageVo(PagePlus<T, V> page, Function<Collection<T>, List<V>> convertor) {
return pageVo(page, Wrappers.emptyWrapper(), convertor);
}
boolean saveAll(Collection<T> entityList);
boolean saveOrUpdateAll(Collection<T> entityList);
}

View File

@ -1,16 +1,22 @@
package com.ruoyi.common.core.mybatisplus.core;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.ClassUtils;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.page.PagePlus;
import com.ruoyi.common.utils.BeanCopyUtils;
import com.ruoyi.common.utils.reflect.ReflectUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ResolvableType;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@ -18,11 +24,14 @@ import java.util.Map;
/**
* IServicePlus 实现类
*
* @param <M> Mapper类
* @param <T> 数据实体类
* @param <V> vo类
* @author Lion Li
*/
@Slf4j
@SuppressWarnings("unchecked")
public class ServicePlusImpl<M extends BaseMapperPlus<T>, T, K> extends ServiceImpl<M, T> implements IServicePlus<T, K> {
public class ServicePlusImpl<M extends BaseMapperPlus<T>, T, V> extends ServiceImpl<M, T> implements IServicePlus<T, V> {
@Autowired
protected M baseMapper;
@ -40,31 +49,26 @@ public class ServicePlusImpl<M extends BaseMapperPlus<T>, T, K> extends ServiceI
return entityClass;
}
protected Class<T> mapperClass = currentMapperClass();
protected Class<M> mapperClass = currentMapperClass();
protected Class<K> voClass = currentVoClass();
protected Class<V> voClass = currentVoClass();
public Class<K> getVoClass() {
public Class<V> getVoClass() {
return voClass;
}
@Override
protected Class<T> currentMapperClass() {
return (Class<T>) this.getResolvableType().as(ServicePlusImpl.class).getGeneric(0).getType();
protected Class<M> currentMapperClass() {
return (Class<M>) ReflectionKit.getSuperClassGenericType(this.getClass(), ServicePlusImpl.class, 0);
}
@Override
protected Class<T> currentModelClass() {
return (Class<T>) this.getResolvableType().as(ServicePlusImpl.class).getGeneric(1).getType();
return (Class<T>) ReflectionKit.getSuperClassGenericType(this.getClass(), ServicePlusImpl.class, 1);
}
protected Class<K> currentVoClass() {
return (Class<K>) this.getResolvableType().as(ServicePlusImpl.class).getGeneric(2).getType();
}
@Override
protected ResolvableType getResolvableType() {
return ResolvableType.forClass(ClassUtils.getUserClass(getClass()));
protected Class<V> currentVoClass() {
return (Class<V>) ReflectionKit.getSuperClassGenericType(this.getClass(), ServicePlusImpl.class, 2);
}
/**
@ -113,21 +117,55 @@ public class ServicePlusImpl<M extends BaseMapperPlus<T>, T, K> extends ServiceI
}
/**
* 单sql批量插入( 全量填充 无视数据库默认值 )
* 适用于无脑插入
* 单sql批量插入( 全量填充 )
*/
@Override
public boolean saveAll(Collection<T> entityList) {
if (CollUtil.isEmpty(entityList)) {
return false;
}
return baseMapper.insertAll(entityList) == entityList.size();
}
/**
* 全量保存或更新 ( 按主键区分 )
*/
@Override
public boolean saveOrUpdateAll(Collection<T> entityList) {
if (CollUtil.isEmpty(entityList)) {
return false;
}
TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
String keyProperty = tableInfo.getKeyProperty();
Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
List<T> addList = new ArrayList<>();
List<T> updateList = new ArrayList<>();
int row = 0;
for (T entity : entityList) {
Object id = ReflectUtils.invokeGetter(entity, keyProperty);
if (ObjectUtil.isNull(id)) {
addList.add(entity);
} else {
updateList.add(entity);
}
}
if (CollUtil.isNotEmpty(updateList) && updateBatchById(updateList)) {
row += updateList.size();
}
if (CollUtil.isNotEmpty(addList)) {
row += baseMapper.insertAll(addList);
}
return row == entityList.size();
}
/**
* 根据 ID 查询
*
* @param id 主键ID
*/
@Override
public K getVoById(Serializable id, CopyOptions copyOptions) {
public V getVoById(Serializable id, CopyOptions copyOptions) {
T t = getBaseMapper().selectById(id);
return BeanCopyUtils.oneCopy(t, copyOptions, voClass);
}
@ -138,7 +176,7 @@ public class ServicePlusImpl<M extends BaseMapperPlus<T>, T, K> extends ServiceI
* @param idList 主键ID列表
*/
@Override
public List<K> listVoByIds(Collection<? extends Serializable> idList, CopyOptions copyOptions) {
public List<V> listVoByIds(Collection<? extends Serializable> idList, CopyOptions copyOptions) {
List<T> list = getBaseMapper().selectBatchIds(idList);
if (list == null) {
return null;
@ -152,7 +190,7 @@ public class ServicePlusImpl<M extends BaseMapperPlus<T>, T, K> extends ServiceI
* @param columnMap 表字段 map 对象
*/
@Override
public List<K> listVoByMap(Map<String, Object> columnMap, CopyOptions copyOptions) {
public List<V> listVoByMap(Map<String, Object> columnMap, CopyOptions copyOptions) {
List<T> list = getBaseMapper().selectByMap(columnMap);
if (list == null) {
return null;
@ -167,7 +205,7 @@ public class ServicePlusImpl<M extends BaseMapperPlus<T>, T, K> extends ServiceI
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
@Override
public K getVoOne(Wrapper<T> queryWrapper, CopyOptions copyOptions) {
public V getVoOne(Wrapper<T> queryWrapper, CopyOptions copyOptions) {
T t = getOne(queryWrapper, true);
return BeanCopyUtils.oneCopy(t, copyOptions, voClass);
}
@ -178,7 +216,7 @@ public class ServicePlusImpl<M extends BaseMapperPlus<T>, T, K> extends ServiceI
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
@Override
public List<K> listVo(Wrapper<T> queryWrapper, CopyOptions copyOptions) {
public List<V> listVo(Wrapper<T> queryWrapper, CopyOptions copyOptions) {
List<T> list = getBaseMapper().selectList(queryWrapper);
if (list == null) {
return null;
@ -193,9 +231,9 @@ public class ServicePlusImpl<M extends BaseMapperPlus<T>, T, K> extends ServiceI
* @param queryWrapper 实体对象封装操作类
*/
@Override
public PagePlus<T, K> pageVo(PagePlus<T, K> page, Wrapper<T> queryWrapper, CopyOptions copyOptions) {
PagePlus<T, K> result = getBaseMapper().selectPage(page, queryWrapper);
List<K> volist = BeanCopyUtils.listCopy(result.getRecords(), copyOptions, voClass);
public PagePlus<T, V> pageVo(PagePlus<T, V> page, Wrapper<T> queryWrapper, CopyOptions copyOptions) {
PagePlus<T, V> result = getBaseMapper().selectPage(page, queryWrapper);
List<V> volist = BeanCopyUtils.listCopy(result.getRecords(), copyOptions, voClass);
result.setRecordsVo(volist);
return result;
}

View File

@ -2,6 +2,7 @@ package com.ruoyi.common.core.mybatisplus.methods;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.ruoyi.common.utils.StringUtils;
@ -11,13 +12,17 @@ import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import java.util.List;
/**
* 单sql批量插入( 全量填充 无视数据库默认值 )
* 单sql批量插入( 全量填充 )
*
* @author Lion Li
*/
public class InsertAll extends AbstractMethod {
private final static String[] FILL_PROPERTY = {"createTime", "createBy", "updateTime", "updateBy"};
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
final String sql = "<script>insert into %s %s values %s</script>";
@ -63,10 +68,32 @@ public class InsertAll extends AbstractMethod {
final StringBuilder valueSql = new StringBuilder();
valueSql.append("<foreach collection=\"list\" item=\"item\" index=\"index\" open=\"(\" separator=\"),(\" close=\")\">");
if (StringUtils.isNotBlank(tableInfo.getKeyColumn())) {
valueSql.append("#{item.").append(tableInfo.getKeyProperty()).append("},");
valueSql.append("\n#{item.").append(tableInfo.getKeyProperty()).append("},\n");
}
List<TableFieldInfo> fieldList = tableInfo.getFieldList();
int last = fieldList.size() - 1;
for (int i = 0; i < fieldList.size(); i++) {
String property = fieldList.get(i).getProperty();
if (!StringUtils.equalsAny(property, FILL_PROPERTY)) {
valueSql.append("<if test=\"item.").append(property).append(" != null\">");
valueSql.append("#{item.").append(property).append("}");
if (i != last) {
valueSql.append(",");
}
valueSql.append("</if>");
valueSql.append("<if test=\"item.").append(property).append(" == null\">");
valueSql.append("DEFAULT");
if (i != last) {
valueSql.append(",");
}
valueSql.append("</if>");
} else {
valueSql.append("#{item.").append(property).append("}");
if (i != last) {
valueSql.append(",");
}
}
}
tableInfo.getFieldList().forEach(x -> valueSql.append("#{item.").append(x.getProperty()).append("},"));
valueSql.delete(valueSql.length() - 1, valueSql.length());
valueSql.append("</foreach>");
return valueSql.toString();
}

View File

@ -5,21 +5,58 @@ import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
* spring redis 工具类
*
* @author shenxinquan
* @see com.ruoyi.common.utils.RedisUtils
* @deprecated 3.2.0 删除此类
**/
@SuppressWarnings(value = {"unchecked", "rawtypes"})
@Component
@Deprecated
public class RedisCache {
@Autowired
private RedissonClient redissonClient;
/**
* 发布通道消息
*
* @param channelKey 通道key
* @param msg 发送数据
* @param consumer 自定义处理
*/
public <T> void publish(String channelKey, T msg, Consumer<T> consumer) {
RTopic topic = redissonClient.getTopic(channelKey);
topic.publish(msg);
consumer.accept(msg);
}
public <T> void publish(String channelKey, T msg) {
RTopic topic = redissonClient.getTopic(channelKey);
topic.publish(msg);
}
/**
* 订阅通道接收消息
*
* @param channelKey 通道key
* @param clazz 消息类型
* @param consumer 自定义处理
*/
public <T> void subscribe(String channelKey, Class<T> clazz, Consumer<T> consumer) {
RTopic topic = redissonClient.getTopic(channelKey);
topic.addListener(clazz, (channel, msg) -> consumer.accept(msg));
}
/**
* 缓存基本的对象IntegerString实体类等
*

View File

@ -0,0 +1,9 @@
package com.ruoyi.common.core.validate;
/**
* 校验分组 query
*
* @author Lion Li
*/
public interface QueryGroup {
}

View File

@ -0,0 +1,35 @@
package com.ruoyi.common.enums;
import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.captcha.ShearCaptcha;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 验证码类别
*
* @author Lion Li
*/
@Getter
@AllArgsConstructor
public enum CaptchaCategory {
/**
* 线段干扰
*/
LINE(LineCaptcha.class),
/**
* 圆圈干扰
*/
CIRCLE(CircleCaptcha.class),
/**
* 扭曲干扰
*/
SHEAR(ShearCaptcha.class);
private final Class<? extends AbstractCaptcha> clazz;
}

View File

@ -0,0 +1,29 @@
package com.ruoyi.common.enums;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.captcha.generator.RandomGenerator;
import com.ruoyi.common.captcha.UnsignedMathGenerator;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 验证码类型
*
* @author Lion Li
*/
@Getter
@AllArgsConstructor
public enum CaptchaType {
/**
* 数字
*/
MATH(UnsignedMathGenerator.class),
/**
* 字符
*/
CHAR(RandomGenerator.class);
private final Class<? extends CodeGenerator> clazz;
}

View File

@ -0,0 +1,26 @@
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

@ -65,8 +65,8 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
// xss过滤
json = HtmlUtil.cleanHtmlTag(json).trim();
final ByteArrayInputStream bis = IoUtil.toStream(json, StandardCharsets.UTF_8);
byte[] jsonBytes = json.getBytes(StandardCharsets.UTF_8);
final ByteArrayInputStream bis = IoUtil.toStream(jsonBytes);
return new ServletInputStream()
{
@Override
@ -81,6 +81,12 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
return true;
}
@Override
public int available() throws IOException
{
return jsonBytes.length;
}
@Override
public void setReadListener(ReadListener readListener)
{
@ -104,4 +110,4 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
String header = super.getHeader(HttpHeaders.CONTENT_TYPE);
return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
}
}
}

View File

@ -2,6 +2,8 @@ package com.ruoyi.common.utils;
import cn.hutool.core.bean.copier.BeanCopier;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import java.util.List;
@ -36,6 +38,9 @@ public class BeanCopyUtils {
* @return desc
*/
public static <T, V> V oneCopy(T source, CopyOptions copyOptions, V desc) {
if (ObjectUtil.isNull(source)) {
return null;
}
return BeanCopier.create(source, desc, copyOptions).copy();
}
@ -48,6 +53,12 @@ public class BeanCopyUtils {
* @return desc
*/
public static <T, V> List<V> listCopy(List<T> sourceList, CopyOptions copyOptions, Class<V> desc) {
if (ObjectUtil.isNull(sourceList)) {
return null;
}
if (CollUtil.isEmpty(sourceList)) {
return CollUtil.newArrayList();
}
return sourceList.stream()
.map(source -> oneCopy(source, copyOptions, desc))
.collect(Collectors.toList());

View File

@ -3,8 +3,6 @@ package com.ruoyi.common.utils;
import cn.hutool.core.collection.CollUtil;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.spring.SpringUtils;
import java.util.Collection;
import java.util.List;
@ -29,7 +27,7 @@ public class DictUtils
*/
public static void setDictCache(String key, List<SysDictData> dictDatas)
{
SpringUtils.getBean(RedisCache.class).setCacheObject(getCacheKey(key), dictDatas);
RedisUtils.setCacheObject(getCacheKey(key), dictDatas);
}
/**
@ -40,7 +38,7 @@ public class DictUtils
*/
public static List<SysDictData> getDictCache(String key)
{
Object cacheObj = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
Object cacheObj = RedisUtils.getCacheObject(getCacheKey(key));
if (StringUtils.isNotNull(cacheObj))
{
List<SysDictData> dictDatas = (List<SysDictData>)cacheObj;
@ -160,7 +158,7 @@ public class DictUtils
*/
public static void removeDictCache(String key)
{
SpringUtils.getBean(RedisCache.class).deleteObject(getCacheKey(key));
RedisUtils.deleteObject(getCacheKey(key));
}
/**
@ -168,8 +166,8 @@ public class DictUtils
*/
public static void clearDictCache()
{
Collection<String> keys = SpringUtils.getBean(RedisCache.class).keys(Constants.SYS_DICT_KEY + "*");
SpringUtils.getBean(RedisCache.class).deleteObject(keys);
Collection<String> keys = RedisUtils.keys(Constants.SYS_DICT_KEY + "*");
RedisUtils.deleteObject(keys);
}
/**

View File

@ -4,6 +4,9 @@ import cn.hutool.core.util.ArrayUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.io.IOException;
import java.util.ArrayList;
@ -15,20 +18,10 @@ import java.util.Map;
*
* @author 芋道源码
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class JsonUtils {
private static ObjectMapper objectMapper = new ObjectMapper();
/**
* 初始化 objectMapper 属性
* <p>
* 通过这样的方式使用 Spring 创建的 ObjectMapper Bean
*
* @param objectMapper ObjectMapper 对象
*/
public static void init(ObjectMapper objectMapper) {
JsonUtils.objectMapper = objectMapper;
}
private static ObjectMapper objectMapper = SpringUtils.getBean(ObjectMapper.class);
public static String toJsonString(Object object) {
if (StringUtils.isNull(object)) {

View File

@ -57,15 +57,12 @@ public class PageUtils {
Integer pageSize = ServletUtils.getParameterToInt(PAGE_SIZE, DEFAULT_PAGE_SIZE);
String orderByColumn = ServletUtils.getParameter(ORDER_BY_COLUMN);
String isAsc = ServletUtils.getParameter(IS_ASC);
PagePlus<T, K> page = new PagePlus<>(pageNum, pageSize);
if (StringUtils.isNotBlank(orderByColumn)) {
String orderBy = SqlUtil.escapeOrderBySql(orderByColumn);
if ("asc".equals(isAsc)) {
page.addOrder(OrderItem.asc(orderBy));
} else if ("desc".equals(isAsc)) {
page.addOrder(OrderItem.desc(orderBy));
}
if (pageNum <= 0) {
pageNum = DEFAULT_PAGE_NUM;
}
PagePlus<T, K> page = new PagePlus<>(pageNum, pageSize);
OrderItem orderItem = buildOrderItem(orderByColumn, isAsc);
page.addOrder(orderItem);
return page;
}
@ -83,23 +80,32 @@ public class PageUtils {
Integer pageSize = ServletUtils.getParameterToInt(PAGE_SIZE, DEFAULT_PAGE_SIZE);
String orderByColumn = ServletUtils.getParameter(ORDER_BY_COLUMN, defaultOrderByColumn);
String isAsc = ServletUtils.getParameter(IS_ASC, defaultIsAsc);
// 兼容前端排序类型
if ("ascending".equals(isAsc)) {
isAsc = "asc";
} else if ("descending".equals(isAsc)) {
isAsc = "desc";
}
if (pageNum <= 0) {
pageNum = DEFAULT_PAGE_NUM;
}
Page<T> page = new Page<>(pageNum, pageSize);
OrderItem orderItem = buildOrderItem(orderByColumn, isAsc);
page.addOrder(orderItem);
return page;
}
private static OrderItem buildOrderItem(String orderByColumn, String isAsc) {
// 兼容前端排序类型
if ("ascending".equals(isAsc)) {
isAsc = "asc";
} else if ("descending".equals(isAsc)) {
isAsc = "desc";
}
if (StringUtils.isNotBlank(orderByColumn)) {
String orderBy = SqlUtil.escapeOrderBySql(orderByColumn);
orderBy = StringUtils.toUnderScoreCase(orderBy);
if ("asc".equals(isAsc)) {
page.addOrder(OrderItem.asc(orderBy));
return OrderItem.asc(orderBy);
} else if ("desc".equals(isAsc)) {
page.addOrder(OrderItem.desc(orderBy));
return OrderItem.desc(orderBy);
}
}
return page;
return null;
}
public static <T, K> TableDataInfo<K> buildDataInfo(PagePlus<T, K> page) {
@ -129,4 +135,11 @@ public class PageUtils {
return rspData;
}
public static <T> TableDataInfo<T> buildDataInfo() {
TableDataInfo<T> rspData = new TableDataInfo<>();
rspData.setCode(HttpStatus.HTTP_OK);
rspData.setMsg("查询成功");
return rspData;
}
}

View File

@ -0,0 +1,258 @@
package com.ruoyi.common.utils;
import com.google.common.collect.Lists;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.redisson.api.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
* redis 工具类
*
* @author Lion Li
* @version 3.1.0 新增
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public class RedisUtils {
private static RedissonClient client = SpringUtils.getBean(RedissonClient.class);
/**
* 发布通道消息
*
* @param channelKey 通道key
* @param msg 发送数据
* @param consumer 自定义处理
*/
public static <T> void publish(String channelKey, T msg, Consumer<T> consumer) {
RTopic topic = client.getTopic(channelKey);
topic.publish(msg);
consumer.accept(msg);
}
public static <T> void publish(String channelKey, T msg) {
RTopic topic = client.getTopic(channelKey);
topic.publish(msg);
}
/**
* 订阅通道接收消息
*
* @param channelKey 通道key
* @param clazz 消息类型
* @param consumer 自定义处理
*/
public static <T> void subscribe(String channelKey, Class<T> clazz, Consumer<T> consumer) {
RTopic topic = client.getTopic(channelKey);
topic.addListener(clazz, (channel, msg) -> consumer.accept(msg));
}
/**
* 缓存基本的对象IntegerString实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
*/
public static <T> void setCacheObject(final String key, final T value) {
client.getBucket(key).set(value);
}
/**
* 缓存基本的对象IntegerString实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/
public static <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
RBucket<T> result = client.getBucket(key);
result.set(value);
result.expire(timeout, timeUnit);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @return true=设置成功false=设置失败
*/
public static boolean expire(final String key, final long timeout) {
return expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @param unit 时间单位
* @return true=设置成功false=设置失败
*/
public static boolean expire(final String key, final long timeout, final TimeUnit unit) {
RBucket rBucket = client.getBucket(key);
return rBucket.expire(timeout, unit);
}
/**
* 获得缓存的基本对象
*
* @param key 缓存键值
* @return 缓存键值对应的数据
*/
public static <T> T getCacheObject(final String key) {
RBucket<T> rBucket = client.getBucket(key);
return rBucket.get();
}
/**
* 删除单个对象
*
* @param key
*/
public static boolean deleteObject(final String key) {
return client.getBucket(key).delete();
}
/* */
/**
* 删除集合对象
*
* @param collection 多个对象
* @return
*/
public static void deleteObject(final Collection collection) {
RBatch batch = client.createBatch();
collection.forEach(t -> {
batch.getBucket(t.toString()).deleteAsync();
});
batch.execute();
}
/**
* 缓存List数据
*
* @param key 缓存的键值
* @param dataList 待缓存的List数据
* @return 缓存的对象
*/
public static <T> boolean setCacheList(final String key, final List<T> dataList) {
RList<T> rList = client.getList(key);
return rList.addAll(dataList);
}
/**
* 获得缓存的list对象
*
* @param key 缓存的键值
* @return 缓存键值对应的数据
*/
public static <T> List<T> getCacheList(final String key) {
RList<T> rList = client.getList(key);
return rList.readAll();
}
/**
* 缓存Set
*
* @param key 缓存键值
* @param dataSet 缓存的数据
* @return 缓存数据的对象
*/
public static <T> boolean setCacheSet(final String key, final Set<T> dataSet) {
RSet<T> rSet = client.getSet(key);
return rSet.addAll(dataSet);
}
/**
* 获得缓存的set
*
* @param key
* @return
*/
public static <T> Set<T> getCacheSet(final String key) {
RSet<T> rSet = client.getSet(key);
return rSet.readAll();
}
/**
* 缓存Map
*
* @param key
* @param dataMap
*/
public static <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
if (dataMap != null) {
RMap<String, T> rMap = client.getMap(key);
rMap.putAll(dataMap);
}
}
/**
* 获得缓存的Map
*
* @param key
* @return
*/
public static <T> Map<String, T> getCacheMap(final String key) {
RMap<String, T> rMap = client.getMap(key);
return rMap.getAll(rMap.keySet());
}
/**
* 往Hash中存入数据
*
* @param key Redis键
* @param hKey Hash键
* @param value
*/
public static <T> void setCacheMapValue(final String key, final String hKey, final T value) {
RMap<String, T> rMap = client.getMap(key);
rMap.put(hKey, value);
}
/**
* 获取Hash中的数据
*
* @param key Redis键
* @param hKey Hash键
* @return Hash中的对象
*/
public static <T> T getCacheMapValue(final String key, final String hKey) {
RMap<String, T> rMap = client.getMap(key);
return rMap.get(hKey);
}
/**
* 获取多个Hash中的数据
*
* @param key Redis键
* @param hKeys Hash键集合
* @return Hash对象集合
*/
public static <K, V> Map<K, V> getMultiCacheMapValue(final String key, final Set<K> hKeys) {
RMap<K, V> rMap = client.getMap(key);
return rMap.getAll(hKeys);
}
/**
* 获得缓存的基本对象列表
*
* @param pattern 字符串前缀
* @return 对象列表
*/
public static Collection<String> keys(final String pattern) {
Iterable<String> iterable = client.getKeys().getKeysByPattern(pattern);
return Lists.newArrayList(iterable);
}
}

View File

@ -48,12 +48,26 @@ public class ServletUtils extends ServletUtil {
return Convert.toInt(getRequest().getParameter(name), defaultValue);
}
/**
* 获取request
*/
public static HttpServletRequest getRequest() {
return getRequestAttributes().getRequest();
}
/**
* 获取Boolean参数
*/
public static Boolean getParameterToBool(String name) {
return Convert.toBool(getRequest().getParameter(name));
}
/**
* 获取Boolean参数
*/
public static Boolean getParameterToBool(String name, Boolean defaultValue) {
return Convert.toBool(getRequest().getParameter(name), defaultValue);
}
/**
* 获取request
*/
public static HttpServletRequest getRequest() {
return getRequestAttributes().getRequest();
}
/**
* 获取response

View File

@ -3,6 +3,7 @@ package com.ruoyi.common.utils.poi;
import cn.hutool.core.util.IdUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.ruoyi.common.convert.ExcelBigNumberConvert;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
@ -52,6 +53,8 @@ public class ExcelUtil {
.autoCloseStream(false)
// 自动适配
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
// 大数值自动转换 防止失真
.registerConverter(new ExcelBigNumberConvert())
.sheet(sheetName).doWrite(list);
} catch (IOException e) {
throw new RuntimeException("导出Excel异常");

View File

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

View File

@ -2,6 +2,8 @@ package com.ruoyi.demo.controller;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.demo.feign.FeignTestService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
@ -14,6 +16,7 @@ import org.springframework.web.bind.annotation.RestController;
*
* @author Lion Li
*/
@Api(value = "feign测试", tags = {"feign测试"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/feign/test")
@ -21,6 +24,10 @@ public class FeignTestController {
private final FeignTestService feignTestService;
/**
* 搜索数据
*/
@ApiOperation("测试使用feign请求数据")
@GetMapping("/search/{wd}")
public AjaxResult search(@PathVariable String wd) {
String search = feignTestService.search(wd);

View File

@ -1,6 +1,8 @@
package com.ruoyi.demo.controller;
import com.ruoyi.common.core.domain.AjaxResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
@ -17,6 +19,7 @@ import org.springframework.web.bind.annotation.RestController;
*/
// 类级别 缓存统一配置
//@CacheConfig(cacheNames = "redissonCacheMap")
@Api(value = "spring-cache 演示案例", tags = {"spring-cache 演示案例"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/demo/cache")
@ -33,6 +36,7 @@ public class RedisCacheController {
*
* cacheNames 为配置文件内 groupId
*/
@ApiOperation("测试 @Cacheable")
@Cacheable(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
@GetMapping("/test1")
public AjaxResult<String> test1(String key, String value){
@ -47,6 +51,7 @@ public class RedisCacheController {
*
* cacheNames 配置文件内 groupId
*/
@ApiOperation("测试 @CachePut")
@CachePut(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
@GetMapping("/test2")
public AjaxResult<String> test2(String key, String value){
@ -61,6 +66,7 @@ public class RedisCacheController {
*
* cacheNames 配置文件内 groupId
*/
@ApiOperation("测试 @CacheEvict")
@CacheEvict(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
@GetMapping("/test3")
public AjaxResult<String> test3(String key, String value){

View File

@ -5,6 +5,8 @@ import com.baomidou.lock.LockTemplate;
import com.baomidou.lock.annotation.Lock4j;
import com.baomidou.lock.executor.RedissonLockExecutor;
import com.ruoyi.common.core.domain.AjaxResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
@ -20,6 +22,7 @@ import java.time.LocalTime;
*
* @author shenxinquan
*/
@Api(value = "测试分布式锁的样例", tags = {"测试分布式锁的样例"})
@Slf4j
@RestController
@RequestMapping("/demo/redisLock")
@ -31,6 +34,7 @@ public class RedisLockController {
/**
* 测试lock4j 注解
*/
@ApiOperation("测试lock4j 注解")
@Lock4j(keys = {"#key"})
@GetMapping("/testLock4j")
public AjaxResult<String> testLock4j(String key,String value){
@ -47,6 +51,7 @@ public class RedisLockController {
/**
* 测试lock4j 工具
*/
@ApiOperation("测试lock4j 工具")
@GetMapping("/testLock4jLockTemaplate")
public AjaxResult<String> testLock4jLockTemaplate(String key,String value){
final LockInfo lockInfo = lockTemplate.lock(key, 30000L, 5000L, RedissonLockExecutor.class);
@ -72,6 +77,7 @@ public class RedisLockController {
/**
* 测试spring-cache注解
*/
@ApiOperation("测试spring-cache注解")
@Cacheable(value = "test", key = "#key")
@GetMapping("/testCache")
public AjaxResult<String> testCache(String key) {

View File

@ -0,0 +1,42 @@
package com.ruoyi.demo.controller;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.RedisUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Redis 发布订阅 演示案例
*
* @author Lion Li
*/
@Api(value = "Redis发布订阅 演示案例", tags = {"Redis发布订阅"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/demo/redis/pubsub")
public class RedisPubSubController {
@ApiOperation("发布消息")
@GetMapping("/pub")
public AjaxResult<Void> pub(String key, String value){
RedisUtils.publish(key, value, consumer -> {
System.out.println("发布通道 => " + key + ", 发送值 => " + value);
});
return AjaxResult.success("操作成功");
}
@ApiOperation("订阅消息")
@GetMapping("/sub")
public AjaxResult<Void> sub(String key){
RedisUtils.subscribe(key, String.class, msg -> {
System.out.println("订阅通道 => " + key + ", 接收值 => " + msg);
});
return AjaxResult.success("操作成功");
}
}

View File

@ -32,10 +32,10 @@ public class TestBatchController extends BaseController {
private final ITestDemoService iTestDemoService;
/**
* 新增批量方法 ( 全量覆盖填充 )
* 新增批量方法 可完美替代 saveBatch 秒级插入上万数据 (对mysql负荷较大)
*/
@ApiOperation(value = "新增批量方法")
@PostMapping()
@PostMapping("/add")
// @DataSource(DataSourceType.SLAVE)
public AjaxResult<Void> add() {
List<TestDemo> list = new ArrayList<>();
@ -45,6 +45,28 @@ public class TestBatchController extends BaseController {
return toAjax(iTestDemoService.saveAll(list) ? 1 : 0);
}
/**
* 新增或更新 可完美替代 saveOrUpdateBatch 高性能
*/
@ApiOperation(value = "新增或更新批量方法")
@PostMapping("/addOrUpdate")
// @DataSource(DataSourceType.SLAVE)
public AjaxResult<Void> addOrUpdate() {
List<TestDemo> list = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
list.add(new TestDemo().setOrderNum(-1L).setTestKey("批量新增").setValue("测试新增"));
}
iTestDemoService.saveAll(list);
for (int i = 0; i < list.size(); i++) {
TestDemo testDemo = list.get(i);
testDemo.setTestKey("批量新增或修改").setValue("批量新增或修改");
if (i % 2 == 0) {
testDemo.setId(null);
}
}
return toAjax(iTestDemoService.saveOrUpdateAll(list) ? 1 : 0);
}
/**
* 删除批量方法
*/

View File

@ -7,6 +7,7 @@ import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.demo.domain.bo.TestDemoBo;
@ -48,7 +49,7 @@ public class TestDemoController extends BaseController {
@ApiOperation("查询测试单表列表")
@PreAuthorize("@ss.hasPermi('demo:demo:list')")
@GetMapping("/list")
public TableDataInfo<TestDemoVo> list(@Validated TestDemoBo bo) {
public TableDataInfo<TestDemoVo> list(@Validated(QueryGroup.class) TestDemoBo bo) {
return iTestDemoService.queryPageList(bo);
}
@ -71,6 +72,10 @@ public class TestDemoController extends BaseController {
@GetMapping("/export")
public void export(@Validated TestDemoBo bo, HttpServletResponse response) {
List<TestDemoVo> list = iTestDemoService.queryList(bo);
// 测试雪花id导出
// for (TestDemoVo vo : list) {
// vo.setId(1234567891234567893L);
// }
ExcelUtil.exportExcel(list, "测试单表", TestDemoVo.class, response);
}

View File

@ -2,6 +2,8 @@ package com.ruoyi.demo.controller;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.MessageUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -12,6 +14,7 @@ import org.springframework.web.bind.annotation.RestController;
*
* @author Lion Li
*/
@Api(value = "测试国际化控制器", tags = {"测试国际化管理"})
@RestController
@RequestMapping("/demo/i18n")
public class TestI18nController {
@ -22,6 +25,7 @@ public class TestI18nController {
*
* 测试使用 user.register.success
*/
@ApiOperation("通过code获取国际化内容")
@GetMapping()
public AjaxResult<Void> get(String code) {
return AjaxResult.success(MessageUtils.message(code));

View File

@ -6,6 +6,7 @@ import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.demo.domain.bo.TestTreeBo;
@ -46,7 +47,7 @@ public class TestTreeController extends BaseController {
@ApiOperation("查询测试树表列表")
@PreAuthorize("@ss.hasPermi('demo:tree:list')")
@GetMapping("/list")
public AjaxResult<List<TestTreeVo>> list(@Validated TestTreeBo bo) {
public AjaxResult<List<TestTreeVo>> list(@Validated(QueryGroup.class) TestTreeBo bo) {
List<TestTreeVo> list = iTestTreeService.queryList(bo);
return AjaxResult.success(list);
}

View File

@ -1,8 +1,6 @@
package com.ruoyi.demo.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@ -29,7 +27,6 @@ public class TestDemo implements Serializable {
* 主键
*/
@TableId(value = "id")
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/**

View File

@ -26,6 +26,7 @@ public class TestDemoVo {
/**
* 主键
*/
@ExcelProperty(value = "主键")
@ApiModelProperty("主键")
private Long id;

View File

@ -10,7 +10,9 @@ import org.springframework.web.bind.annotation.RequestParam;
* feign测试service
* 规范接口 Service 无感调用
* 常量管理请求路径 更加规范
* 自定义容错处理 安全可靠
* 自定义容错处理 安全可靠 (需自行配置熔断器)
* 增加 feign 的目的为使 http 请求接口化
*
* @author Lion Li
*/
@FeignClient(

View File

@ -10,6 +10,8 @@ import org.springframework.stereotype.Component;
* 自定义封装结构体熔断
* 需重写解码器 根据自定义实体 自行解析熔断
*
* 熔断器需要自行添加配置
*
* @see {com.ruoyi.framework.config.FeignConfig#errorDecoder()}
* @author Lion Li
*/

View File

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

View File

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

View File

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

View File

@ -5,11 +5,9 @@ import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.reflect.ReflectUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.web.service.TokenService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
@ -78,7 +76,7 @@ public class DataScopeAspect {
return;
}
// 获取当前的用户
LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
LoginUser loginUser = SecurityUtils.getLoginUser();
if (StringUtils.isNotNull(loginUser)) {
SysUser currentUser = loginUser.getUser();
// 如果是超级管理员则不过滤数据

View File

@ -5,11 +5,11 @@ import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.BusinessStatus;
import com.ruoyi.common.enums.HttpMethod;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.web.service.AsyncService;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.domain.SysOperLog;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
@ -83,7 +83,7 @@ public class LogAspect
}
// 获取当前的用户
LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
LoginUser loginUser = SecurityUtils.getLoginUser();
// *========数据库日志=========*//
SysOperLog operLog = new SysOperLog();

View File

@ -1,10 +1,14 @@
package com.ruoyi.framework.config;
import java.awt.*;
import cn.hutool.captcha.*;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.captcha.ShearCaptcha;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import java.awt.*;
/**
* 验证码配置
@ -22,8 +26,9 @@ public class CaptchaConfig {
/**
* 圆圈干扰验证码
*/
@Bean(name = "CircleCaptcha")
public CircleCaptcha getCircleCaptcha() {
@Lazy
@Bean
public CircleCaptcha circleCaptcha() {
CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(width, height);
captcha.setBackground(background);
captcha.setFont(font);
@ -33,8 +38,9 @@ public class CaptchaConfig {
/**
* 线段干扰的验证码
*/
@Bean(name = "LineCaptcha")
public LineCaptcha getLineCaptcha() {
@Lazy
@Bean
public LineCaptcha lineCaptcha() {
LineCaptcha captcha = CaptchaUtil.createLineCaptcha(width, height);
captcha.setBackground(background);
captcha.setFont(font);
@ -44,8 +50,9 @@ public class CaptchaConfig {
/**
* 扭曲干扰验证码
*/
@Bean(name = "ShearCaptcha")
public ShearCaptcha getShearCaptcha() {
@Lazy
@Bean
public ShearCaptcha shearCaptcha() {
ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(width, height);
captcha.setBackground(background);
captcha.setFont(font);

View File

@ -5,17 +5,18 @@ import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.framework.jackson.BigNumberSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.jackson.JacksonProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.TimeZone;
/**
@ -27,30 +28,23 @@ import java.util.TimeZone;
@Configuration
public class JacksonConfig {
@Primary
@Bean
public BeanPostProcessor objectMapperBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (!(bean instanceof ObjectMapper)) {
return bean;
}
ObjectMapper objectMapper = (ObjectMapper) bean;
// 全局配置序列化返回 JSON 处理
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, BigNumberSerializer.INSTANCE);
simpleModule.addSerializer(Long.TYPE, BigNumberSerializer.INSTANCE);
simpleModule.addSerializer(BigInteger.class, BigNumberSerializer.INSTANCE);
simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
simpleModule.addSerializer(LocalDateTime.class, LocalDateTimeSerializer.INSTANCE);
simpleModule.addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);
objectMapper.registerModule(simpleModule);
objectMapper.setTimeZone(TimeZone.getDefault());
JsonUtils.init(objectMapper);
log.info("初始化 jackson 配置");
return bean;
}
};
public ObjectMapper getObjectMapper(Jackson2ObjectMapperBuilder builder, JacksonProperties jacksonProperties) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
// 全局配置序列化返回 JSON 处理
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, BigNumberSerializer.INSTANCE);
simpleModule.addSerializer(Long.TYPE, BigNumberSerializer.INSTANCE);
simpleModule.addSerializer(BigInteger.class, BigNumberSerializer.INSTANCE);
simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(jacksonProperties.getDateFormat());
simpleModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter));
simpleModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter));
objectMapper.registerModule(simpleModule);
objectMapper.setTimeZone(TimeZone.getDefault());
log.info("初始化 jackson 配置");
return objectMapper;
}
}

View File

@ -1,10 +1,10 @@
package com.ruoyi.framework.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
@ -46,10 +46,10 @@ public class MybatisPlusConfig {
*/
public PaginationInnerInterceptor paginationInnerInterceptor() {
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
// 设置数据库类型为mysql
paginationInnerInterceptor.setDbType(DbType.MYSQL);
// 设置最大单页限制数量默认 500 -1 不受限制
paginationInnerInterceptor.setMaxLimit(-1L);
// 分页合理化
paginationInnerInterceptor.setOverflow(true);
return paginationInnerInterceptor;
}
@ -104,8 +104,8 @@ public class MybatisPlusConfig {
public ISqlInjector sqlInjector() {
return new DefaultSqlInjector() {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass);
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
methodList.add(new InsertAll());
return methodList;
}

View File

@ -3,6 +3,7 @@ package com.ruoyi.framework.config;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.config.properties.RedissonProperties;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
@ -29,6 +30,7 @@ import java.util.Map;
*
* @author Lion Li
*/
@Slf4j
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@ -73,7 +75,9 @@ public class RedisConfig extends CachingConfigurerSupport {
.setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize())
.setConnectionPoolSize(singleServerConfig.getConnectionPoolSize())
.setDnsMonitoringInterval(singleServerConfig.getDnsMonitoringInterval());
return Redisson.create(config);
RedissonClient redissonClient = Redisson.create(config);
log.info("初始化 redis 配置");
return redissonClient;
}
/**

View File

@ -1,6 +1,7 @@
package com.ruoyi.framework.config;
import com.ruoyi.common.utils.Threads;
import com.ruoyi.common.utils.reflect.ReflectUtils;
import com.ruoyi.framework.config.properties.ThreadPoolProperties;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -12,7 +13,6 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 线程池配置
@ -33,21 +33,7 @@ public class ThreadPoolConfig {
executor.setCorePoolSize(threadPoolProperties.getCorePoolSize());
executor.setQueueCapacity(threadPoolProperties.getQueueCapacity());
executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds());
RejectedExecutionHandler handler;
switch (threadPoolProperties.getRejectedExecutionHandler()) {
case "CallerRunsPolicy":
handler = new ThreadPoolExecutor.CallerRunsPolicy();
break;
case "DiscardOldestPolicy":
handler = new ThreadPoolExecutor.DiscardOldestPolicy();
break;
case "DiscardPolicy":
handler = new ThreadPoolExecutor.DiscardPolicy();
break;
default:
handler = new ThreadPoolExecutor.AbortPolicy();
break;
}
RejectedExecutionHandler handler = ReflectUtils.newInstance(threadPoolProperties.getRejectedExecutionHandler().getClazz());
executor.setRejectedExecutionHandler(handler);
return executor;
}

View File

@ -1,5 +1,7 @@
package com.ruoyi.framework.config.properties;
import com.ruoyi.common.enums.CaptchaCategory;
import com.ruoyi.common.enums.CaptchaType;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ -17,12 +19,12 @@ public class CaptchaProperties {
/**
* 验证码类型
*/
private String type;
private CaptchaType type;
/**
* 验证码类别
*/
private String category;
private CaptchaCategory category;
/**
* 数字验证码位数

View File

@ -1,5 +1,6 @@
package com.ruoyi.framework.config.properties;
import com.ruoyi.common.enums.ThreadPoolRejectedPolicy;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ -42,6 +43,6 @@ public class ThreadPoolProperties {
/**
* 线程池对拒绝任务(无线程可用)的处理策略
*/
private String rejectedExecutionHandler;
private ThreadPoolRejectedPolicy rejectedExecutionHandler;
}

View File

@ -4,9 +4,9 @@ import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.filter.RepeatedlyRequestWrapper;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.config.properties.RepeatSubmitProperties;
import com.ruoyi.framework.config.properties.TokenProperties;
@ -38,7 +38,6 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor {
private final TokenProperties tokenProperties;
private final RepeatSubmitProperties repeatSubmitProperties;
private final RedisCache redisCache;
@SuppressWarnings("unchecked")
@ -79,7 +78,7 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor {
// 唯一标识指定key + 消息头
String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + submitKey;
Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);
Object sessionObj = RedisUtils.getCacheObject(cacheRepeatKey);
if (sessionObj != null) {
Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
if (sessionMap.containsKey(url)) {
@ -91,7 +90,7 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor {
}
Map<String, Object> cacheMap = new HashMap<String, Object>();
cacheMap.put(url, nowDataMap);
redisCache.setCacheObject(cacheRepeatKey, cacheMap, Convert.toInt(intervalTime), TimeUnit.MILLISECONDS);
RedisUtils.setCacheObject(cacheRepeatKey, cacheMap, Convert.toInt(intervalTime), TimeUnit.MILLISECONDS);
return false;
}

View File

@ -1,10 +1,9 @@
package com.ruoyi.framework.web.service;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.ServletUtils;
import org.springframework.beans.factory.annotation.Autowired;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
@ -28,9 +27,6 @@ public class PermissionService
private static final String PERMISSION_DELIMETER = ",";
@Autowired
private TokenService tokenService;
/**
* 验证用户是否具备某权限
*
@ -43,7 +39,7 @@ public class PermissionService
{
return false;
}
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
LoginUser loginUser = SecurityUtils.getLoginUser();
if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
{
return false;
@ -74,7 +70,7 @@ public class PermissionService
{
return false;
}
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
LoginUser loginUser = SecurityUtils.getLoginUser();
if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
{
return false;
@ -102,7 +98,7 @@ public class PermissionService
{
return false;
}
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
LoginUser loginUser = SecurityUtils.getLoginUser();
if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
{
return false;
@ -141,7 +137,7 @@ public class PermissionService
{
return false;
}
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
LoginUser loginUser = SecurityUtils.getLoginUser();
if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
{
return false;

View File

@ -3,13 +3,13 @@ package com.ruoyi.framework.web.service;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.user.CaptchaException;
import com.ruoyi.common.exception.user.CaptchaExpireException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;
@ -37,9 +37,6 @@ public class SysLoginService
@Resource
private AuthenticationManager authenticationManager;
@Autowired
private RedisCache redisCache;
@Autowired
private ISysUserService userService;
@ -105,8 +102,8 @@ public class SysLoginService
*/
public void validateCaptcha(String username, String code, String uuid, HttpServletRequest request) {
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
String captcha = redisCache.getCacheObject(verifyKey);
redisCache.deleteObject(verifyKey);
String captcha = RedisUtils.getCacheObject(verifyKey);
RedisUtils.deleteObject(verifyKey);
if (captcha == null) {
asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"), request);
throw new CaptchaExpireException();

View File

@ -4,13 +4,9 @@ import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.RegisterBody;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.user.CaptchaException;
import com.ruoyi.common.exception.user.CaptchaExpireException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.*;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
@ -30,9 +26,6 @@ public class SysRegisterService
@Autowired
private ISysConfigService configService;
@Autowired
private RedisCache redisCache;
@Autowired
private AsyncService asyncService;
@ -103,8 +96,8 @@ public class SysRegisterService
public void validateCaptcha(String username, String code, String uuid)
{
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
String captcha = redisCache.getCacheObject(verifyKey);
redisCache.deleteObject(verifyKey);
String captcha = RedisUtils.getCacheObject(verifyKey);
RedisUtils.deleteObject(verifyKey);
if (captcha == null)
{
throw new CaptchaExpireException();

View File

@ -5,7 +5,7 @@ import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.AddressUtils;
@ -35,9 +35,6 @@ public class TokenService {
private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;
@Autowired
private RedisCache redisCache;
@Autowired
private TokenProperties tokenProperties;
@ -55,7 +52,7 @@ public class TokenService {
// 解析对应的权限以及用户信息
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
String userKey = getTokenKey(uuid);
LoginUser user = redisCache.getCacheObject(userKey);
LoginUser user = RedisUtils.getCacheObject(userKey);
return user;
} catch (Exception e) {
@ -79,7 +76,7 @@ public class TokenService {
public void delLoginUser(String token) {
if (StringUtils.isNotEmpty(token)) {
String userKey = getTokenKey(token);
redisCache.deleteObject(userKey);
RedisUtils.deleteObject(userKey);
}
}
@ -124,7 +121,7 @@ public class TokenService {
loginUser.setExpireTime(loginUser.getLoginTime() + tokenProperties.getExpireTime() * MILLIS_MINUTE);
// 根据uuid将loginUser缓存
String userKey = getTokenKey(loginUser.getToken());
redisCache.setCacheObject(userKey, loginUser, tokenProperties.getExpireTime(), TimeUnit.MINUTES);
RedisUtils.setCacheObject(userKey, loginUser, tokenProperties.getExpireTime(), TimeUnit.MINUTES);
}
/**

View File

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

View File

@ -44,6 +44,7 @@ public class GenTableColumn implements Serializable {
/**
* 列描述
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
private String columnComment;
/**
@ -65,36 +66,43 @@ public class GenTableColumn implements Serializable {
/**
* 是否主键1是
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
private String isPk;
/**
* 是否自增1是
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
private String isIncrement;
/**
* 是否必填1是
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
private String isRequired;
/**
* 是否为插入字段1是
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
private String isInsert;
/**
* 是否编辑字段1是
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
private String isEdit;
/**
* 是否列表字段1是
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
private String isList;
/**
* 是否查询字段1是
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
private String isQuery;
/**

View File

@ -2,9 +2,7 @@ package com.ruoyi.generator.service;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import com.ruoyi.common.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.GenConstants;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
@ -13,6 +11,7 @@ import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.generator.domain.GenTable;
import com.ruoyi.generator.domain.GenTableColumn;
@ -34,10 +33,7 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@ -134,18 +130,7 @@ public class GenTableServiceImpl extends ServicePlusImpl<GenTableMapper, GenTabl
int row = baseMapper.updateById(genTable);
if (row > 0) {
for (GenTableColumn cenTableColumn : genTable.getColumns()) {
genTableColumnMapper.update(cenTableColumn,
new LambdaUpdateWrapper<GenTableColumn>()
.set(StringUtils.isBlank(cenTableColumn.getColumnComment()), GenTableColumn::getColumnComment, null)
.set(StringUtils.isBlank(cenTableColumn.getIsPk()), GenTableColumn::getIsPk, null)
.set(StringUtils.isBlank(cenTableColumn.getIsIncrement()), GenTableColumn::getIsIncrement, null)
.set(StringUtils.isBlank(cenTableColumn.getIsInsert()), GenTableColumn::getIsInsert, null)
.set(StringUtils.isBlank(cenTableColumn.getIsEdit()), GenTableColumn::getIsEdit, null)
.set(StringUtils.isBlank(cenTableColumn.getIsList()), GenTableColumn::getIsList, null)
.set(StringUtils.isBlank(cenTableColumn.getIsQuery()), GenTableColumn::getIsQuery, null)
.set(StringUtils.isBlank(cenTableColumn.getIsRequired()), GenTableColumn::getIsRequired, null)
.set(StringUtils.isBlank(cenTableColumn.getDictType()), GenTableColumn::getDictType, "")
.eq(GenTableColumn::getColumnId,cenTableColumn.getColumnId()));
genTableColumnMapper.updateById(cenTableColumn);
}
}
}
@ -178,13 +163,17 @@ public class GenTableServiceImpl extends ServicePlusImpl<GenTableMapper, GenTabl
String tableName = table.getTableName();
GenUtils.initTable(table, operName);
int row = baseMapper.insert(table);
if (row > 0) {
// 保存列信息
List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
for (GenTableColumn column : genTableColumns) {
GenUtils.initColumnField(column, table);
genTableColumnMapper.insert(column);
}
if (row > 0) {
// 保存列信息
List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
List<GenTableColumn> saveColumns = new ArrayList<>();
for (GenTableColumn column : genTableColumns) {
GenUtils.initColumnField(column, table);
saveColumns.add(column);
}
if (CollUtil.isNotEmpty(saveColumns)) {
genTableColumnMapper.insertAll(saveColumns);
}
}
}
} catch (Exception e) {
@ -292,12 +281,16 @@ public class GenTableServiceImpl extends ServicePlusImpl<GenTableMapper, GenTabl
}
List<String> dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList());
dbTableColumns.forEach(column -> {
if (!tableColumnNames.contains(column.getColumnName())) {
GenUtils.initColumnField(column, table);
genTableColumnMapper.insert(column);
List<GenTableColumn> saveColumns = new ArrayList<>();
dbTableColumns.forEach(column -> {
if (!tableColumnNames.contains(column.getColumnName())) {
GenUtils.initColumnField(column, table);
saveColumns.add(column);
}
});
if (CollUtil.isNotEmpty(saveColumns)) {
genTableColumnMapper.insertAll(saveColumns);
}
List<GenTableColumn> delColumns = tableColumns.stream().filter(column -> !dbTableColumnNames.contains(column.getColumnName())).collect(Collectors.toList());
if (CollUtil.isNotEmpty(delColumns)) {

View File

@ -164,9 +164,10 @@ public class GenUtils
*/
public static String getBusinessName(String tableName)
{
int lastIndex = tableName.lastIndexOf("_");
int firstIndex = tableName.indexOf("_");
int nameLength = tableName.length();
String businessName = StringUtils.substring(tableName, lastIndex + 1, nameLength);
String businessName = StringUtils.substring(tableName, firstIndex + 1, nameLength);
businessName = StringUtils.toCamelCase(businessName);
return businessName;
}

View File

@ -92,6 +92,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="genTable.params.endTime != null and genTable.params.endTime != ''"><!-- 结束时间检索 -->
AND date_format(create_time,'%y%m%d') &lt;= date_format(#{genTable.params.endTime},'%y%m%d')
</if>
order by create_time desc
</select>
@ -130,6 +131,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<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 id="selectDbTableListByNames" resultMap="GenTableResult">
@ -162,7 +164,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
LEFT JOIN gen_table_column c ON t.table_id = c.table_id
where t.table_name = #{tableName} order by c.sort
</select>
<select id="selectGenTableAll" parameterType="String" resultMap="GenTableResult">
SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark,
c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort

View File

@ -17,6 +17,7 @@ import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import ${packageName}.domain.vo.${ClassName}Vo;
@ -51,11 +52,11 @@ public class ${ClassName}Controller extends BaseController {
@PreAuthorize("@ss.hasPermi('${permissionPrefix}:list')")
@GetMapping("/list")
#if($table.crud || $table.sub)
public TableDataInfo<${ClassName}Vo> list(@Validated ${ClassName}Bo bo) {
public TableDataInfo<${ClassName}Vo> list(@Validated(QueryGroup.class) ${ClassName}Bo bo) {
return i${ClassName}Service.queryPageList(bo);
}
#elseif($table.tree)
public AjaxResult<List<${ClassName}Vo>> list(@Validated ${ClassName}Bo bo) {
public AjaxResult<List<${ClassName}Vo>> list(@Validated(QueryGroup.class) ${ClassName}Bo bo) {
List<${ClassName}Vo> list = i${ClassName}Service.queryList(bo);
return AjaxResult.success(list);
}

View File

@ -106,7 +106,11 @@
</template>
</el-table-column>
#elseif($column.list && $column.dictType && "" != $column.dictType)
<el-table-column label="${comment}" align="center" prop="${javaField}" :formatter="${javaField}Format" />
<el-table-column label="${comment}" align="center" prop="${javaField}">
<template slot-scope="scope">
<dict-tag :options="${javaField}Options" :value="scope.row.${javaField}"/>
</template>
</el-table-column>
#elseif($column.list && "" != $javaField)
#if(${foreach.index} == 1)
<el-table-column label="${comment}" prop="${javaField}" />
@ -378,20 +382,6 @@ export default {
this.${businessName}Options.push(data);
});
},
#foreach ($column in $columns)
#if(${column.dictType} && ${column.dictType} != '')
#set($parentheseIndex=$column.columnComment.indexOf(""))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
// $comment字典翻译
${column.javaField}Format(row, column) {
return this.selectDictLabel#if($column.htmlType == "checkbox")s#end(this.${column.javaField}Options, row.${column.javaField});
},
#end
#end
// 取消按钮
cancel() {
this.open = false;

View File

@ -135,7 +135,11 @@
</template>
</el-table-column>
#elseif($column.list && $column.dictType && "" != $column.dictType)
<el-table-column label="${comment}" align="center" prop="${javaField}" :formatter="${javaField}Format" />
<el-table-column label="${comment}" align="center" prop="${javaField}">
<template slot-scope="scope">
<dict-tag :options="${javaField}Options" :value="scope.row.${javaField}"/>
</template>
</el-table-column>
#elseif($column.list && "" != $javaField)
<el-table-column label="${comment}" align="center" prop="${javaField}" />
#end
@ -308,7 +312,6 @@
<script>
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
import { downLoadExcel } from "@/utils/download";
export default {
name: "${BusinessName}",
@ -427,20 +430,6 @@ export default {
this.loading = false;
});
},
#foreach ($column in $columns)
#if(${column.dictType} && ${column.dictType} != '')
#set($parentheseIndex=$column.columnComment.indexOf(""))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
// $comment字典翻译
${column.javaField}Format(row, column) {
return this.selectDictLabel#if($column.htmlType == "checkbox")s#end(this.${column.javaField}Options, row.${column.javaField});
},
#end
#end
// 取消按钮
cancel() {
this.open = false;
@ -601,7 +590,7 @@ export default {
#end
/** 导出按钮操作 */
handleExport() {
downLoadExcel('/${moduleName}/${businessName}/export', this.queryParams);
this.downLoadExcel('/${moduleName}/${businessName}/export', this.queryParams);
}
}
};

View File

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

View File

@ -1,19 +1,18 @@
package com.ruoyi.oss.factory;
import cn.hutool.core.convert.Convert;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.reflect.ReflectUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.oss.constant.CloudConstant;
import com.ruoyi.oss.enumd.CloudServiceEnumd;
import com.ruoyi.oss.exception.OssException;
import com.ruoyi.oss.properties.CloudStorageProperties;
import com.ruoyi.oss.service.ICloudStorageStrategy;
import com.ruoyi.oss.service.abstractd.AbstractCloudStorageStrategy;
import lombok.extern.slf4j.Slf4j;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -22,12 +21,14 @@ import java.util.concurrent.ConcurrentHashMap;
*
* @author Lion Li
*/
@Slf4j
public class OssFactory {
private static RedisCache redisCache;
static {
OssFactory.redisCache = SpringUtils.getBean(RedisCache.class);
RedisUtils.subscribe(CloudConstant.CACHE_CONFIG_KEY, String.class, msg -> {
refreshService(msg);
log.info("订阅刷新OSS配置 => " + msg);
});
}
/**
@ -35,17 +36,12 @@ public class OssFactory {
*/
private static final Map<String, ICloudStorageStrategy> SERVICES = new ConcurrentHashMap<>();
/**
* 服务配置更新时间缓存
*/
private static final Map<String, Date> SERVICES_UPDATE_TIME = new ConcurrentHashMap<>();
/**
* 获取默认实例
*/
public static ICloudStorageStrategy instance() {
// 获取redis 默认类型
String type = Convert.toStr(redisCache.getCacheObject(CloudConstant.CACHE_CONFIG_KEY));
String type = Convert.toStr(RedisUtils.getCacheObject(CloudConstant.CACHE_CONFIG_KEY));
if (StringUtils.isEmpty(type)) {
throw new OssException("文件存储服务类型无法找到!");
}
@ -57,23 +53,23 @@ public class OssFactory {
*/
public static ICloudStorageStrategy instance(String type) {
ICloudStorageStrategy service = SERVICES.get(type);
Date oldDate = SERVICES_UPDATE_TIME.get(type);
Object json = redisCache.getCacheObject(CloudConstant.SYS_OSS_KEY + type);
if (service == null) {
refreshService(type);
service = SERVICES.get(type);
}
return service;
}
private static void refreshService(String type) {
Object json = RedisUtils.getCacheObject(CloudConstant.SYS_OSS_KEY + type);
CloudStorageProperties properties = JsonUtils.parseObject(json.toString(), CloudStorageProperties.class);
if (properties == null) {
throw new OssException("系统异常, '" + type + "'配置信息不存在!");
}
Date nowDate = properties.getUpdateTime();
// 服务存在并更新时间相同则返回(使用更新时间确保配置最终一致性)
if (service != null && oldDate.equals(nowDate)) {
return service;
}
// 获取redis配置信息 创建对象 并缓存
service = (ICloudStorageStrategy) ReflectUtils.newInstance(CloudServiceEnumd.getServiceClass(type));
ICloudStorageStrategy service = (ICloudStorageStrategy) ReflectUtils.newInstance(CloudServiceEnumd.getServiceClass(type));
((AbstractCloudStorageStrategy)service).init(properties);
SERVICES.put(type, service);
SERVICES_UPDATE_TIME.put(type, nowDate);
return service;
}
}

View File

@ -1,15 +1,14 @@
package com.ruoyi.oss.service.abstractd;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.oss.entity.UploadResult;
import com.ruoyi.oss.properties.CloudStorageProperties;
import com.ruoyi.oss.service.ICloudStorageStrategy;
import java.io.InputStream;
import java.util.Date;
/**
* 云存储策略(支持七牛阿里云腾讯云minio)
@ -33,7 +32,7 @@ public abstract class AbstractCloudStorageStrategy implements ICloudStorageStrat
// 生成uuid
String uuid = IdUtil.fastSimpleUUID();
// 文件路径
String path = DateUtil.format(new Date(), "yyyyMMdd") + "/" + uuid;
String path = DateUtils.datePath() + "/" + uuid;
if (StringUtils.isNotBlank(prefix)) {
path = prefix + "/" + path;
}

View File

@ -36,7 +36,7 @@ public class AliyunCloudStorageStrategy extends AbstractCloudStorageStrategy {
client = new OSSClient(properties.getEndpoint(), credentialProvider, configuration);
createBucket();
} catch (Exception e) {
throw new OssException("阿里云存储配置错误! 请检查系统配置!");
throw new OssException("阿里云存储配置错误! 请检查系统配置:[" + e.getMessage() + "]");
}
}
@ -51,7 +51,7 @@ public class AliyunCloudStorageStrategy extends AbstractCloudStorageStrategy {
createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
client.createBucket(createBucketRequest);
} catch (Exception e) {
throw new OssException("创建Bucket失败, 请核对阿里云配置信息");
throw new OssException("创建Bucket失败, 请核对阿里云配置信息:[" + e.getMessage() + "]");
}
}
@ -72,7 +72,7 @@ public class AliyunCloudStorageStrategy extends AbstractCloudStorageStrategy {
metadata.setContentType(contentType);
client.putObject(new PutObjectRequest(properties.getBucketName(), path, inputStream, metadata));
} catch (Exception e) {
throw new OssException("上传文件失败,请检查阿里云配置信息");
throw new OssException("上传文件失败,请检查阿里云配置信息:[" + e.getMessage() + "]");
}
return new UploadResult().setUrl(getEndpointLink() + "/" + path).setFilename(path);
}
@ -83,7 +83,7 @@ public class AliyunCloudStorageStrategy extends AbstractCloudStorageStrategy {
try {
client.deleteObject(properties.getBucketName(), path);
} catch (Exception e) {
throw new OssException("上传文件失败,请检查阿里云配置信息");
throw new OssException("上传文件失败,请检查阿里云配置信息:[" + e.getMessage() + "]");
}
}

View File

@ -32,7 +32,7 @@ public class MinioCloudStorageStrategy extends AbstractCloudStorageStrategy {
.build();
createBucket();
} catch (Exception e) {
throw new OssException("Minio存储配置错误! 请检查系统配置!");
throw new OssException("Minio存储配置错误! 请检查系统配置:[" + e.getMessage() + "]");
}
}
@ -51,7 +51,7 @@ public class MinioCloudStorageStrategy extends AbstractCloudStorageStrategy {
.config(getPolicy(bucketName, PolicyType.READ))
.build());
} catch (Exception e) {
throw new OssException("创建Bucket失败, 请核对Minio配置信息");
throw new OssException("创建Bucket失败, 请核对Minio配置信息:[" + e.getMessage() + "]");
}
}
@ -75,7 +75,7 @@ public class MinioCloudStorageStrategy extends AbstractCloudStorageStrategy {
.stream(inputStream, inputStream.available(), -1)
.build());
} catch (Exception e) {
throw new OssException("上传文件失败请核对Minio配置信息");
throw new OssException("上传文件失败请核对Minio配置信息:[" + e.getMessage() + "]");
}
return new UploadResult().setUrl(getEndpointLink() + "/" + path).setFilename(path);
}
@ -95,7 +95,7 @@ public class MinioCloudStorageStrategy extends AbstractCloudStorageStrategy {
@Override
public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) {
return upload(data, getPath("", suffix), contentType);
return upload(data, getPath(properties.getPrefix(), suffix), contentType);
}
@Override

View File

@ -44,7 +44,7 @@ public class QcloudCloudStorageStrategy extends AbstractCloudStorageStrategy {
client = new COSClient(credentials, clientConfig);
createBucket();
} catch (Exception e) {
throw new OssException("腾讯云存储配置错误! 请检查系统配置!");
throw new OssException("腾讯云存储配置错误! 请检查系统配置:[" + e.getMessage() + "]");
}
}
@ -59,7 +59,7 @@ public class QcloudCloudStorageStrategy extends AbstractCloudStorageStrategy {
createBucketRequest.setCannedAcl(CannedAccessControlList.PublicRead);
client.createBucket(createBucketRequest);
} catch (Exception e) {
throw new OssException("创建Bucket失败, 请核对腾讯云配置信息");
throw new OssException("创建Bucket失败, 请核对腾讯云配置信息:[" + e.getMessage() + "]");
}
}
@ -80,7 +80,7 @@ public class QcloudCloudStorageStrategy extends AbstractCloudStorageStrategy {
metadata.setContentType(contentType);
client.putObject(new PutObjectRequest(properties.getBucketName(), path, inputStream, metadata));
} catch (Exception e) {
throw new OssException("上传文件失败,请检查腾讯云配置信息");
throw new OssException("上传文件失败,请检查腾讯云配置信息:[" + e.getMessage() + "]");
}
return new UploadResult().setUrl(getEndpointLink() + "/" + path).setFilename(path);
}
@ -91,7 +91,7 @@ public class QcloudCloudStorageStrategy extends AbstractCloudStorageStrategy {
try {
client.deleteObject(new DeleteObjectRequest(properties.getBucketName(), path));
} catch (Exception e) {
throw new OssException("上传文件失败,请检腾讯云查配置信息");
throw new OssException("上传文件失败,请检腾讯云查配置信息:[" + e.getMessage() + "]");
}
}

View File

@ -44,7 +44,7 @@ public class QiniuCloudStorageStrategy extends AbstractCloudStorageStrategy {
bucketManager.createBucket(bucketName, properties.getRegion());
}
} catch (Exception e) {
throw new OssException("七牛云存储配置错误! 请检查系统配置!");
throw new OssException("七牛云存储配置错误! 请检查系统配置:[" + e.getMessage() + "]");
}
}
@ -57,7 +57,7 @@ public class QiniuCloudStorageStrategy extends AbstractCloudStorageStrategy {
}
bucketManager.createBucket(bucketName, properties.getRegion());
} catch (Exception e) {
throw new OssException("创建Bucket失败, 请核对七牛云配置信息");
throw new OssException("创建Bucket失败, 请核对七牛云配置信息:[" + e.getMessage() + "]");
}
}
@ -74,7 +74,7 @@ public class QiniuCloudStorageStrategy extends AbstractCloudStorageStrategy {
throw new RuntimeException("上传七牛出错:" + res.toString());
}
} catch (Exception e) {
throw new OssException("上传文件失败,请核对七牛配置信息");
throw new OssException("上传文件失败,请核对七牛配置信息:[" + e.getMessage() + "]");
}
return new UploadResult().setUrl(getEndpointLink() + "/" + path).setFilename(path);
}

View File

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

View File

@ -80,6 +80,10 @@ public class SysJobController extends BaseController
{
return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi://'调用");
}
else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_LDAP))
{
return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap://'调用");
}
else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
{
return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)//'调用");
@ -104,6 +108,10 @@ public class SysJobController extends BaseController
{
return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi://'调用");
}
else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_LDAP))
{
return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap://'调用");
}
else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
{
return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)//'调用");

View File

@ -87,7 +87,7 @@ public class SysJobServiceImpl extends ServicePlusImpl<SysJobMapper, SysJob, Sys
* @param job 调度信息
*/
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public int pauseJob(SysJob job) throws SchedulerException {
Long jobId = job.getJobId();
String jobGroup = job.getJobGroup();
@ -105,7 +105,7 @@ public class SysJobServiceImpl extends ServicePlusImpl<SysJobMapper, SysJob, Sys
* @param job 调度信息
*/
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public int resumeJob(SysJob job) throws SchedulerException {
Long jobId = job.getJobId();
String jobGroup = job.getJobGroup();
@ -123,7 +123,7 @@ public class SysJobServiceImpl extends ServicePlusImpl<SysJobMapper, SysJob, Sys
* @param job 调度信息
*/
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public int deleteJob(SysJob job) throws SchedulerException {
Long jobId = job.getJobId();
String jobGroup = job.getJobGroup();
@ -141,7 +141,7 @@ public class SysJobServiceImpl extends ServicePlusImpl<SysJobMapper, SysJob, Sys
* @return 结果
*/
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public void deleteJobByIds(Long[] jobIds) throws SchedulerException {
for (Long jobId : jobIds) {
SysJob job = getById(jobId);
@ -155,7 +155,7 @@ public class SysJobServiceImpl extends ServicePlusImpl<SysJobMapper, SysJob, Sys
* @param job 调度信息
*/
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public int changeStatus(SysJob job) throws SchedulerException {
int rows = 0;
String status = job.getStatus();
@ -173,7 +173,7 @@ public class SysJobServiceImpl extends ServicePlusImpl<SysJobMapper, SysJob, Sys
* @param job 调度信息
*/
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public void run(SysJob job) throws SchedulerException {
Long jobId = job.getJobId();
String jobGroup = job.getJobGroup();
@ -190,7 +190,7 @@ public class SysJobServiceImpl extends ServicePlusImpl<SysJobMapper, SysJob, Sys
* @param job 调度信息 调度信息
*/
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public int insertJob(SysJob job) throws SchedulerException, TaskException {
job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
int rows = baseMapper.insert(job);
@ -206,7 +206,7 @@ public class SysJobServiceImpl extends ServicePlusImpl<SysJobMapper, SysJob, Sys
* @param job 调度信息
*/
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public int updateJob(SysJob job) throws SchedulerException, TaskException {
SysJob properties = selectJobById(job.getJobId());
int rows = baseMapper.updateById(job);

View File

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

View File

@ -58,7 +58,7 @@ public interface ISysDeptService extends IService<SysDept> {
* @param deptId 部门ID
* @return 子部门数
*/
public int selectNormalChildrenDeptById(Long deptId);
public long selectNormalChildrenDeptById(Long deptId);
/**
* 是否存在部门子节点
@ -84,6 +84,13 @@ public interface ISysDeptService extends IService<SysDept> {
*/
public String checkDeptNameUnique(SysDept dept);
/**
* 校验部门是否有数据权限
*
* @param deptId 部门id
*/
public void checkDeptDataScope(Long deptId);
/**
* 新增保存部门信息
*

View File

@ -69,7 +69,7 @@ public interface ISysPostService extends IService<SysPost> {
* @param postId 岗位ID
* @return 结果
*/
public int countUserPostById(Long postId);
public long countUserPostById(Long postId);
/**
* 删除岗位信息

View File

@ -88,13 +88,20 @@ public interface ISysRoleService extends IService<SysRole> {
*/
public void checkRoleAllowed(SysRole role);
/**
* 校验角色是否有数据权限
*
* @param roleId 角色id
*/
public void checkRoleDataScope(Long roleId);
/**
* 通过角色ID查询角色使用数量
*
* @param roleId 角色ID
* @return 结果
*/
public int countUserRoleByRoleId(Long roleId);
public long countUserRoleByRoleId(Long roleId);
/**
* 新增保存角色信息

View File

@ -103,6 +103,13 @@ public interface ISysUserService extends IService<SysUser> {
*/
public void checkUserAllowed(SysUser user);
/**
* 校验用户是否有数据权限
*
* @param userId 用户id
*/
public void checkUserDataScope(Long userId);
/**
* 新增用户信息
*

View File

@ -1,21 +1,20 @@
package com.ruoyi.system.service.impl;
import cn.hutool.core.convert.Convert;
import com.ruoyi.common.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.annotation.DataSource;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.DataSourceType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.system.service.ISysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
@ -32,9 +31,6 @@ import java.util.Map;
@Service
public class SysConfigServiceImpl extends ServicePlusImpl<SysConfigMapper, SysConfig, SysConfig> implements ISysConfigService {
@Autowired
private RedisCache redisCache;
/**
* 项目启动时初始化参数到缓存
*/
@ -79,14 +75,14 @@ public class SysConfigServiceImpl extends ServicePlusImpl<SysConfigMapper, SysCo
*/
@Override
public String selectConfigByKey(String configKey) {
String configValue = Convert.toStr(redisCache.getCacheObject(getCacheKey(configKey)));
String configValue = Convert.toStr(RedisUtils.getCacheObject(getCacheKey(configKey)));
if (StringUtils.isNotEmpty(configValue)) {
return configValue;
}
SysConfig retConfig = baseMapper.selectOne(new LambdaQueryWrapper<SysConfig>()
.eq(SysConfig::getConfigKey, configKey));
if (StringUtils.isNotNull(retConfig)) {
redisCache.setCacheObject(getCacheKey(configKey), retConfig.getConfigValue());
RedisUtils.setCacheObject(getCacheKey(configKey), retConfig.getConfigValue());
return retConfig.getConfigValue();
}
return StringUtils.EMPTY;
@ -138,7 +134,7 @@ public class SysConfigServiceImpl extends ServicePlusImpl<SysConfigMapper, SysCo
public int insertConfig(SysConfig config) {
int row = baseMapper.insert(config);
if (row > 0) {
redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
RedisUtils.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
}
return row;
}
@ -153,7 +149,7 @@ public class SysConfigServiceImpl extends ServicePlusImpl<SysConfigMapper, SysCo
public int updateConfig(SysConfig config) {
int row = baseMapper.updateById(config);
if (row > 0) {
redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
RedisUtils.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
}
return row;
}
@ -171,7 +167,7 @@ public class SysConfigServiceImpl extends ServicePlusImpl<SysConfigMapper, SysCo
if (StringUtils.equals(UserConstants.YES, config.getConfigType())) {
throw new ServiceException(String.format("内置参数【%1$s】不能删除 ", config.getConfigKey()));
}
redisCache.deleteObject(getCacheKey(config.getConfigKey()));
RedisUtils.deleteObject(getCacheKey(config.getConfigKey()));
}
baseMapper.deleteBatchIds(Arrays.asList(configIds));
}
@ -183,7 +179,7 @@ public class SysConfigServiceImpl extends ServicePlusImpl<SysConfigMapper, SysCo
public void loadingConfigCache() {
List<SysConfig> configsList = selectConfigList(new SysConfig());
for (SysConfig config : configsList) {
redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
RedisUtils.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
}
}
@ -192,8 +188,8 @@ public class SysConfigServiceImpl extends ServicePlusImpl<SysConfigMapper, SysCo
*/
@Override
public void clearConfigCache() {
Collection<String> keys = redisCache.keys(Constants.SYS_CONFIG_KEY + "*");
redisCache.deleteObject(keys);
Collection<String> keys = RedisUtils.keys(Constants.SYS_CONFIG_KEY + "*");
RedisUtils.deleteObject(keys);
}
/**

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