同步ruoyi-vue-plus的2023-11-17至2023-11-23的更新

(1)fix 修复 OssFactory 并发多创建实例问题
   (2)update 优化 删除无用接口实现
   (3)!454 添加excel多sheet页导出
   (4)update 优化 重构 LoginHelper 将本地存储代码操作封装
   (5)update 优化 删除无用依赖
   (6)update 优化 删除无用注解
   (7)update 优化 更新用户异常提示 使用登录账号
   (8)fix 修复 token 失效后 登录获取用户null问题
   (9)fix 修复 session 多账号共用覆盖问题 改为 tokenSession 独立存储
   (10)add 新增 RedisUtils.setObjectIfExists 如果存在则设置方法
   (11)update transmittable-thread-local 2.14.2 => 2.14.4
   (12)update 优化 删除 hikaricp 官方不推荐使用的配置 jdbc4 协议自带校验方法
   (13)update 优化 开启 redisson 脚本缓存 减少网络传输
   (14)升级依赖update easyexcel 3.3.2 => 3.3.3
     update springboot-admin 3.1.7 => 3.1.8
     update aws-java-sdk-s3 1.12.540 => 1.12.600
   (15)细化oss配置管理权限控制,需要执行更新数据库脚本update.sql
   (16)update 优化 将 OSS配置 改为全局模式
   (17)fix 修复 excel合并注解会根据第一合并列的结果来决定后续的列合并
   (18)fix 修复 MybatisSystemException 空指针问题
   (19)update 优化 删除无用异常类
   (20)update 优化 验证码接口 增加限流配置
   (21)update 优化 丰富RedisUtils对List Set类型的操作
This commit is contained in:
dataprince 2023-12-25 16:16:02 +08:00
parent 64fea077c2
commit 64685e74f9
35 changed files with 282 additions and 270 deletions

View File

@ -30,7 +30,7 @@
<oshi.version>6.4.8</oshi.version>
<commons.collections.version>3.2.2</commons.collections.version>
<poi.version>5.2.3</poi.version>
<easyexcel.version>3.3.2</easyexcel.version>
<easyexcel.version>3.3.3</easyexcel.version>
<velocity.version>2.3</velocity.version>
<jwt.version>0.9.1</jwt.version>
<servlet-api.version>6.0.0</servlet-api.version>
@ -46,13 +46,13 @@
<hutool.version>5.8.22</hutool.version>
<redisson.version>3.25.1</redisson.version>
<lock4j.version>2.2.4</lock4j.version>
<alibaba-ttl.version>2.14.3</alibaba-ttl.version>
<spring-boot-admin.version>3.1.7</spring-boot-admin.version>
<alibaba-ttl.version>2.14.4</alibaba-ttl.version>
<spring-boot-admin.version>3.1.8</spring-boot-admin.version>
<powerjob.version>4.3.6</powerjob.version>
<!-- 离线IP地址定位库 -->
<ip2region.version>2.7.0</ip2region.version>
<!-- OSS 配置 -->
<aws-java-sdk-s3.version>1.12.540</aws-java-sdk-s3.version>
<aws-java-sdk-s3.version>1.12.600</aws-java-sdk-s3.version>
<!-- 插件版本 -->
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>

View File

@ -62,7 +62,7 @@ public class AuthController {
* @return 结果
*/
@PostMapping("/login")
public R<LoginVo> login(@Validated @RequestBody LoginBody loginBody) {
public R<LoginVo> login(@RequestBody LoginBody loginBody) {
AjaxResult ajax = AjaxResult.success();
// 授权类型和客户端id

View File

@ -6,8 +6,10 @@ import java.time.Duration;
import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.IdUtil;
import com.ruoyi.common.core.annotation.RateLimiter;
import com.ruoyi.common.core.constant.GlobalConstants;
import com.ruoyi.common.core.core.domain.AjaxResult;
import com.ruoyi.common.core.enums.LimitType;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.reflect.ReflectUtils;
import com.ruoyi.common.core.utils.SpringUtils;
@ -43,6 +45,7 @@ public class CaptchaController
/**
* 生成验证码
*/
@RateLimiter(time = 60, count = 10, limitType = LimitType.IP)
@GetMapping("/captchaImage")
public AjaxResult getCode() {
CaptchaVo captchaVo = new CaptchaVo();

View File

@ -161,6 +161,9 @@ public class SysLoginService {
public void logout() {
try {
LoginUser loginUser = LoginHelper.getLoginUser();
if (ObjectUtil.isNull(loginUser)) {
return;
}
if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) {
// 超级管理员 登出清除动态租户
TenantHelper.clearDynamic();

View File

@ -15,8 +15,6 @@ spring:
idleTimeout: 600000
# 此属性控制池中连接的最长生命周期值0表示无限生命周期默认30分钟
maxLifetime: 1800000
# 连接测试query配置检测连接是否有效
connectionTestQuery: SELECT 1
# 多久检查一次连接的活性
keepaliveTime: 30000
mybatis-flex:
@ -93,7 +91,7 @@ redisson:
--- # 监控中心客户端配置
spring.boot.admin.client:
# 增加客户端开关
enabled: false
enabled: true
url: http://localhost:9090/admin
instance:
service-host-type: IP
@ -104,7 +102,7 @@ spring.boot.admin.client:
powerjob:
worker:
# 如何开启调度中心请查看文档教程
enabled: false
enabled: true
# 需要先在 powerjob 登录页执行应用注册后才能使用
app-name: ruoyi-worker
# 28080 端口 随着主应用端口飘逸 避免集群冲突
@ -112,6 +110,6 @@ powerjob:
protocol: http
server-address: 127.0.0.1:7700
store-strategy: disk
enable-test-mode: false
allow-lazy-connect-server: false
max-appended-wf-context-length: 4096
max-result-length: 4096

View File

@ -15,8 +15,6 @@ spring:
idleTimeout: 600000
# 此属性控制池中连接的最长生命周期值0表示无限生命周期默认30分钟
maxLifetime: 1800000
# 连接测试query配置检测连接是否有效
connectionTestQuery: SELECT 1
# 多久检查一次连接的活性
keepaliveTime: 30000
mybatis-flex:
@ -112,6 +110,6 @@ powerjob:
protocol: http
server-address: 127.0.0.1:7700
store-strategy: disk
enable-test-mode: false
allow-lazy-connect-server: false
max-appended-wf-context-length: 4096
max-result-length: 4096

View File

@ -125,12 +125,6 @@
<artifactId>hutool-extra</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-json</artifactId>
<scope>provided</scope>
</dependency>
<!-- mapstruct-plus -->
<dependency>
<groupId>io.github.linpeilie</groupId>

View File

@ -53,7 +53,7 @@ public interface CacheNames {
/**
* OSS配置
*/
String SYS_OSS_CONFIG = "sys_oss_config";
String SYS_OSS_CONFIG = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss_config";
/**
* 在线用户

View File

@ -1,15 +0,0 @@
package com.ruoyi.common.core.exception;
/**
* 演示模式异常
*
* @author ruoyi
*/
public class DemoModeException extends RuntimeException
{
private static final long serialVersionUID = 1L;
public DemoModeException()
{
}
}

View File

@ -1,60 +0,0 @@
package com.ruoyi.common.core.exception;
import java.io.Serial;
/**
* 全局异常
*
* @author ruoyi
*/
public class GlobalException extends RuntimeException
{
@Serial
private static final long serialVersionUID = 1L;
/**
* 错误提示
*/
private String message;
/**
* 错误明细内部调试错误
*
*/
private String detailMessage;
/**
* 空构造方法避免反序列化问题
*/
public GlobalException()
{
}
public GlobalException(String message)
{
this.message = message;
}
public String getDetailMessage()
{
return detailMessage;
}
public GlobalException setDetailMessage(String detailMessage)
{
this.detailMessage = detailMessage;
return this;
}
@Override
public String getMessage()
{
return message;
}
public GlobalException setMessage(String message)
{
this.message = message;
return this;
}
}

View File

@ -1,29 +0,0 @@
package com.ruoyi.common.core.exception;
import java.io.Serial;
/**
* 工具类异常
*
* @author ruoyi
*/
public class UtilException extends RuntimeException
{
@Serial
private static final long serialVersionUID = 8247610319171014183L;
public UtilException(Throwable e)
{
super(e.getMessage(), e);
}
public UtilException(String message)
{
super(message);
}
public UtilException(String message, Throwable throwable)
{
super(message, throwable);
}
}

View File

@ -1,19 +0,0 @@
package com.ruoyi.common.core.exception.user;
import java.io.Serial;
/**
* 用户密码不正确或不符合规范异常类
*
* @author ruoyi
*/
public class UserPasswordNotMatchException extends UserException
{
@Serial
private static final long serialVersionUID = 1L;
public UserPasswordNotMatchException()
{
super("user.password.not.match", (Object)null);
}
}

View File

@ -1,19 +0,0 @@
package com.ruoyi.common.core.exception.user;
import java.io.Serial;
/**
* 用户错误最大次数异常类
*
* @author ruoyi
*/
public class UserPasswordRetryLimitExceedException extends UserException
{
@Serial
private static final long serialVersionUID = 1L;
public UserPasswordRetryLimitExceedException(int retryLimitCount, int lockTime)
{
super("user.password.retry.limit.exceed", new Object[] { retryLimitCount, lockTime });
}
}

View File

@ -76,7 +76,6 @@ import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.core.config.RuoYiConfig;
import com.ruoyi.common.core.exception.UtilException;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.file.FileTypeUtils;
import com.ruoyi.common.core.utils.file.FileUtils;
@ -540,7 +539,7 @@ public class ExcelUtil<T> {
return AjaxResult.success(filename);
} catch (Exception e) {
log.error("导出Excel异常{}", e.getMessage());
throw new UtilException("导出Excel失败请联系网站管理员");
throw new IllegalArgumentException("导出Excel失败请联系网站管理员");
} finally {
IOUtils.closeQuietly(wb);
IOUtils.closeQuietly(out);

View File

@ -1,11 +1,10 @@
package com.ruoyi.common.core.utils.sql;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.exception.UtilException;
/**
* sql操作工具类
*
*
* @author ruoyi
*/
public class SqlUtil
@ -32,11 +31,11 @@ public class SqlUtil
{
if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value))
{
throw new UtilException("参数不符合规范,不能进行查询");
throw new IllegalArgumentException("参数不符合规范,不能进行查询");
}
if (StringUtils.length(value) > ORDER_BY_MAX_LENGTH)
{
throw new UtilException("参数已超过最大限制,不能进行查询");
throw new IllegalArgumentException("参数已超过最大限制,不能进行查询");
}
return value;
}
@ -63,7 +62,7 @@ public class SqlUtil
{
if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1)
{
throw new UtilException("参数存在SQL注入风险");
throw new IllegalArgumentException("参数存在SQL注入风险");
}
}
}

View File

@ -5,7 +5,6 @@ import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import com.ruoyi.common.core.exception.UtilException;
/**
* 提供通用唯一识别码universally unique identifierUUID实现
@ -33,7 +32,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
/**
* 私有构造
*
*
* @param data 数据
*/
private UUID(byte[] data)
@ -67,7 +66,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
/**
* 获取类型 4伪随机生成的UUID 的静态工厂
*
*
* @return 随机生成的 {@code UUID}
*/
public static UUID fastUUID()
@ -77,7 +76,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
/**
* 获取类型 4伪随机生成的UUID 的静态工厂 使用加密的强伪随机数生成器生成该 UUID
*
*
* @return 随机生成的 {@code UUID}
*/
public static UUID randomUUID()
@ -87,7 +86,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
/**
* 获取类型 4伪随机生成的UUID 的静态工厂 使用加密的强伪随机数生成器生成该 UUID
*
*
* @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码否则可以得到更好的性能
* @return 随机生成的 {@code UUID}
*/
@ -289,7 +288,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
*
* <p>
* UUID 的字符串表示形式由此 BNF 描述
*
*
* <pre>
* {@code
* UUID = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
@ -302,7 +301,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
* hexDigit = [0-9a-fA-F]
* }
* </pre>
*
*
* </blockquote>
*
* @return {@code UUID} 的字符串表现形式
@ -319,7 +318,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
*
* <p>
* UUID 的字符串表示形式由此 BNF 描述
*
*
* <pre>
* {@code
* UUID = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
@ -332,7 +331,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
* hexDigit = [0-9a-fA-F]
* }
* </pre>
*
*
* </blockquote>
*
* @param isSimple 是否简单模式简单模式为不带'-'的UUID字符串
@ -432,7 +431,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
// Private method start
/**
* 返回指定数字对应的hex值
*
*
* @param val
* @param digits
* @return
@ -456,7 +455,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
/**
* 获取{@link SecureRandom}类提供加密的强随机数生成器 (RNG)
*
*
* @return {@link SecureRandom}
*/
public static SecureRandom getSecureRandom()
@ -467,14 +466,14 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
}
catch (NoSuchAlgorithmException e)
{
throw new UtilException(e);
throw new IllegalArgumentException(e);
}
}
/**
* 获取随机数生成器对象<br>
* ThreadLocalRandom是JDK 7之后提供并发产生随机数能够解决多个线程发生的竞争争夺
*
*
* @return {@link ThreadLocalRandom}
*/
public static ThreadLocalRandom getRandom()

View File

@ -98,9 +98,30 @@ public class CellMergeStrategy extends AbstractMergeStrategy {
cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum));
}
map.put(field, new RepeatCell(val, i));
} else if (i == list.size() - 1) {
if (i > repeatCell.getCurrent()) {
cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum));
} else if (j == 0) {
if (i == list.size() - 1) {
if (i > repeatCell.getCurrent()) {
cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum));
}
}
} else {
// 判断前面的是否合并了
RepeatCell firstCell = map.get(mergeFields.get(0));
if (repeatCell.getCurrent() != firstCell.getCurrent()) {
if (i == list.size() - 1) {
if (i > repeatCell.getCurrent()) {
cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum));
}
} else if (repeatCell.getCurrent() < firstCell.getCurrent()) {
if (i - repeatCell.getCurrent() > 1) {
cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum));
}
map.put(field, new RepeatCell(val, i));
}
} else if (i == list.size() - 1) {
if (i > repeatCell.getCurrent()) {
cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum));
}
}
}
}

View File

@ -269,6 +269,27 @@ public class ExcelUtil {
}
}
/**
* 多sheet模板导出 模板格式为 {key.属性}
*
* @param filename 文件名
* @param templatePath 模板路径 resource 目录下的路径包括模板文件名
* 例如: excel/temp.xlsx
* 重点: 模板文件必须放置到启动类对应的 resource 目录下
* @param data 模板需要的数据
* @param response 响应体
*/
public static void exportTemplateMultiSheet(List<Map<String, Object>> data, String filename, String templatePath, HttpServletResponse response) {
try {
resetResponse(filename, response);
ServletOutputStream os = response.getOutputStream();
exportTemplateMultiSheet(data, templatePath, os);
} catch (IOException e) {
throw new RuntimeException("导出Excel异常");
}
}
/**
* 多表多数据模板导出 模板格式为 {key.属性}
*
@ -303,6 +324,42 @@ public class ExcelUtil {
excelWriter.finish();
}
/**
* 多sheet模板导出 模板格式为 {key.属性}
*
* @param templatePath 模板路径 resource 目录下的路径包括模板文件名
* 例如: excel/temp.xlsx
* 重点: 模板文件必须放置到启动类对应的 resource 目录下
* @param data 模板需要的数据
* @param os 输出流
*/
public static void exportTemplateMultiSheet(List<Map<String, Object>> data, String templatePath, OutputStream os) {
ClassPathResource templateResource = new ClassPathResource(templatePath);
ExcelWriter excelWriter = EasyExcel.write(os)
.withTemplate(templateResource.getStream())
.autoCloseStream(false)
// 大数值自动转换 防止失真
.registerConverter(new ExcelBigNumberConvert())
.build();
if (CollUtil.isEmpty(data)) {
throw new IllegalArgumentException("数据为空");
}
for (int i = 0; i < data.size(); i++) {
WriteSheet writeSheet = EasyExcel.writerSheet(i).build();
for (Map.Entry<String, Object> map : data.get(i).entrySet()) {
// 设置列表后续还有数据
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
if (map.getValue() instanceof Collection) {
// 多表导出必须使用 FillWrapper
excelWriter.fill(new FillWrapper(map.getKey(), (Collection<?>) map.getValue()), fillConfig, writeSheet);
} else {
excelWriter.fill(map.getValue(), writeSheet);
}
}
}
excelWriter.finish();
}
/**
* 重置响应体
*/

View File

@ -26,7 +26,7 @@ public class OperLogEvent implements Serializable {
/**
* 租户ID
*/
private String tenantId;
private Long tenantId;
/**
* 操作模块

View File

@ -35,7 +35,7 @@ public class MybatisExceptionHandler {
public R<Void> handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
String message = e.getMessage();
if (message.contains("CannotFindDataSourceException")) {
if ("CannotFindDataSourceException".contains(message)) {
log.error("请求地址'{}', 未找到数据源", requestURI);
return R.fail("未找到数据源,请联系管理员确认");
}

View File

@ -16,6 +16,11 @@
</description>
<dependencies>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common-core</artifactId>
</dependency>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common-json</artifactId>

View File

@ -1,5 +1,7 @@
package com.ruoyi.common.oss.constant;
import com.ruoyi.common.core.constant.GlobalConstants;
import java.util.Arrays;
import java.util.List;
@ -13,7 +15,7 @@ public interface OssConstant {
/**
* 默认配置KEY
*/
String DEFAULT_CONFIG_KEY = "sys_oss:default_config";
String DEFAULT_CONFIG_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss:default_config";
/**
* 预览列表资源开关Key

View File

@ -39,7 +39,7 @@ public class OssFactory {
/**
* 根据类型获取实例
*/
public static OssClient instance(String configKey) {
public static synchronized OssClient instance(String configKey) {
String json = CacheUtils.get(CacheNames.SYS_OSS_CONFIG, configKey);
if (json == null) {
throw new OssException("系统异常, '" + configKey + "'配置信息不存在!");

View File

@ -49,6 +49,8 @@ public class RedisConfig {
CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, jsonCodec, jsonCodec);
config.setThreads(redissonProperties.getThreads())
.setNettyThreads(redissonProperties.getNettyThreads())
// 缓存 Lua 脚本 减少网络传输(redisson 大部分的功能都是基于 Lua 脚本实现)
.setUseScriptCache(true)
.setCodec(codec);
RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig();
if (ObjectUtil.isNotNull(singleServerConfig)) {

View File

@ -142,6 +142,18 @@ public class RedisUtils {
return bucket.setIfAbsent(value, duration);
}
/**
* 如果存在则设置 并返回 true 如果存在则返回 false
*
* @param key 缓存的键值
* @param value 缓存的值
* @return set成功或失败
*/
public static <T> boolean setObjectIfExists(final String key, final T value, final Duration duration) {
RBucket<T> bucket = CLIENT.getBucket(key);
return bucket.setIfExists(value, duration);
}
/**
* 注册对象监听器
* <p>
@ -243,6 +255,18 @@ public class RedisUtils {
return rList.addAll(dataList);
}
/**
* 追加缓存List数据
*
* @param key 缓存的键值
* @param data 待缓存的数据
* @return 缓存的对象
*/
public static <T> boolean addCacheList(final String key, final T data) {
RList<T> rList = CLIENT.getList(key);
return rList.add(data);
}
/**
* 注册List监听器
* <p>
@ -267,6 +291,19 @@ public class RedisUtils {
return rList.readAll();
}
/**
* 获得缓存的list对象(范围)
*
* @param key 缓存的键值
* @param form 起始下标
* @param to 截止下标
* @return 缓存键值对应的数据
*/
public static <T> List<T> getCacheListRange(final String key, int form, int to) {
RList<T> rList = CLIENT.getList(key);
return rList.range(form, to);
}
/**
* 缓存Set
*
@ -279,6 +316,18 @@ public class RedisUtils {
return rSet.addAll(dataSet);
}
/**
* 追加缓存Set数据
*
* @param key 缓存的键值
* @param data 待缓存的数据
* @return 缓存的对象
*/
public static <T> boolean addCacheSet(final String key, final T data) {
RSet<T> rSet = CLIENT.getSet(key);
return rSet.add(data);
}
/**
* 注册Set监听器
* <p>

View File

@ -19,7 +19,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
*/
@AutoConfiguration
@PropertySource(value = "classpath:common-satoken.yml", factory = YmlPropertySourceFactory.class)
public class SaTokenConfig implements WebMvcConfigurer {
public class SaTokenConfig {
@Bean
public StpLogic getStpLogicJwt() {

View File

@ -45,12 +45,9 @@ public class FlexSaTokenDao implements SaTokenDao {
*/
@Override
public void update(String key, String value) {
long expire = getTimeout(key);
// -2 = 无此键
if (expire == NOT_VALUE_EXPIRE) {
return;
if (RedisUtils.hasKey(key)) {
RedisUtils.setCacheObject(key, value, true);
}
this.set(key, value, expire);
}
/**
@ -75,17 +72,6 @@ public class FlexSaTokenDao implements SaTokenDao {
*/
@Override
public void updateTimeout(String key, long timeout) {
// 判断是否想要设置为永久
if (timeout == NEVER_EXPIRE) {
long expire = getTimeout(key);
if (expire == NEVER_EXPIRE) {
// 如果其已经被设置为永久则不作任何处理
} else {
// 如果尚未被设置为永久那么再次set一次
this.set(key, this.get(key), timeout);
}
return;
}
RedisUtils.expire(key, Duration.ofSeconds(timeout));
}
@ -119,12 +105,9 @@ public class FlexSaTokenDao implements SaTokenDao {
*/
@Override
public void updateObject(String key, Object object) {
long expire = getObjectTimeout(key);
// -2 = 无此键
if (expire == NOT_VALUE_EXPIRE) {
return;
if (RedisUtils.hasKey(key)) {
RedisUtils.setCacheObject(key, object, true);
}
this.setObject(key, object, expire);
}
/**
@ -149,17 +132,6 @@ public class FlexSaTokenDao implements SaTokenDao {
*/
@Override
public void updateObjectTimeout(String key, long timeout) {
// 判断是否想要设置为永久
if (timeout == NEVER_EXPIRE) {
long expire = getObjectTimeout(key);
if (expire == NEVER_EXPIRE) {
// 如果其已经被设置为永久则不作任何处理
} else {
// 如果尚未被设置为永久那么再次set一次
this.setObject(key, this.getObject(key), timeout);
}
return;
}
RedisUtils.expire(key, Duration.ofSeconds(timeout));
}

View File

@ -11,7 +11,6 @@ import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import com.ruoyi.common.core.core.domain.R;
import com.ruoyi.common.core.exception.DemoModeException;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.StreamUtils;
import org.springframework.context.support.DefaultMessageSourceResolvable;
@ -161,12 +160,4 @@ public class GlobalExceptionHandler {
String message = e.getBindingResult().getFieldError().getDefaultMessage();
return R.fail(message);
}
/**
* 演示模式异常
*/
@ExceptionHandler(DemoModeException.class)
public R<Void> handleDemoModeException(DemoModeException e) {
return R.fail("演示模式,不允许操作");
}
}

View File

@ -15,6 +15,7 @@ import com.ruoyi.common.core.core.domain.model.LoginUser;
import com.ruoyi.common.core.enums.UserType;
import java.util.Set;
import java.util.function.Supplier;
/**
* 登录鉴权助手
@ -36,6 +37,7 @@ public class LoginHelper {
public static final String USER_KEY = "userId";
public static final String DEPT_KEY = "deptId";
public static final String CLIENT_KEY = "clientid";
public static final String TENANT_ADMIN_KEY = "isTenantAdmin";
/**
* 登录系统 基于 设备类型
@ -56,32 +58,45 @@ public class LoginHelper {
model.setExtra(TENANT_KEY, loginUser.getTenantId())
.setExtra(USER_KEY, loginUser.getUserId())
.setExtra(DEPT_KEY, loginUser.getDeptId()));
StpUtil.getSession().set(LOGIN_USER_KEY, loginUser);
//StpUtil.getSession().set(LOGIN_USER_KEY, loginUser);
StpUtil.getTokenSession().set(LOGIN_USER_KEY, loginUser);
}
/**
* 获取用户(多级缓存)
*/
public static LoginUser getLoginUser() {
LoginUser loginUser = (LoginUser) SaHolder.getStorage().get(LOGIN_USER_KEY);
if (loginUser != null) {
return loginUser;
}
SaSession session = StpUtil.getSession();
if (ObjectUtil.isNull(session)) {
return null;
}
loginUser = (LoginUser) session.get(LOGIN_USER_KEY);
SaHolder.getStorage().set(LOGIN_USER_KEY, loginUser);
return loginUser;
// LoginUser loginUser = (LoginUser) SaHolder.getStorage().get(LOGIN_USER_KEY);
// if (loginUser != null) {
// return loginUser;
// }
// SaSession session = StpUtil.getSession();
// if (ObjectUtil.isNull(session)) {
// return null;
// }
// loginUser = (LoginUser) session.get(LOGIN_USER_KEY);
// SaHolder.getStorage().set(LOGIN_USER_KEY, loginUser);
// return loginUser;
return (LoginUser) getStorageIfAbsentSet(LOGIN_USER_KEY, () -> {
SaSession session = StpUtil.getTokenSession();
if (ObjectUtil.isNull(session)) {
return null;
}
return session.get(LOGIN_USER_KEY);
});
}
/**
* 获取用户基于token
*/
public static LoginUser getLoginUser(String token) {
Object loginId = StpUtil.getLoginIdByToken(token);
SaSession session = StpUtil.getSessionByLoginId(loginId);
// Object loginId = StpUtil.getLoginIdByToken(token);
// SaSession session = StpUtil.getSessionByLoginId(loginId);
// if (ObjectUtil.isNull(session)) {
// return null;
// }
// return (LoginUser) session.get(LOGIN_USER_KEY);
SaSession session = StpUtil.getTokenSessionByToken(token);
if (ObjectUtil.isNull(session)) {
return null;
}
@ -98,8 +113,8 @@ public class LoginHelper {
/**
* 获取租户ID
*/
public static String getTenantId() {
return Convert.toStr(getExtra(TENANT_KEY));
public static Long getTenantId() {
return Convert.toLong(getExtra(TENANT_KEY));
}
/**
@ -110,17 +125,18 @@ public class LoginHelper {
}
private static Object getExtra(String key) {
Object obj;
try {
obj = SaHolder.getStorage().get(key);
if (ObjectUtil.isNull(obj)) {
obj = StpUtil.getExtra(key);
SaHolder.getStorage().set(key, obj);
}
} catch (Exception e) {
return null;
}
return obj;
// Object obj;
// try {
// obj = SaHolder.getStorage().get(key);
// if (ObjectUtil.isNull(obj)) {
// obj = StpUtil.getExtra(key);
// SaHolder.getStorage().set(key, obj);
// }
// } catch (Exception e) {
// return null;
// }
// return obj;
return getStorageIfAbsentSet(key, () -> StpUtil.getExtra(key));
}
/**
@ -163,7 +179,27 @@ public class LoginHelper {
}
public static boolean isTenantAdmin() {
return isTenantAdmin(getLoginUser().getRolePermission());
Object value = getStorageIfAbsentSet(TENANT_ADMIN_KEY, () -> {
return isTenantAdmin(getLoginUser().getRolePermission());
});
return Convert.toBool(value);
}
public static boolean isLogin() {
return getLoginUser() != null;
}
public static Object getStorageIfAbsentSet(String key, Supplier<Object> handle) {
try {
Object obj = SaHolder.getStorage().get(key);
if (ObjectUtil.isNull(obj)) {
obj = handle.get();
SaHolder.getStorage().set(key, obj);
}
return obj;
} catch (Exception e) {
return null;
}
}
}

View File

@ -24,7 +24,7 @@ public class PlusTenantLineHandler {
private final TenantProperties tenantProperties;
public Expression getTenantId() {
String tenantId = LoginHelper.getTenantId();
String tenantId = LoginHelper.getTenantId().toString();
if (StringUtils.isBlank(tenantId)) {
return new NullValue();
}
@ -38,7 +38,7 @@ public class PlusTenantLineHandler {
}
public boolean ignoreTable(String tableName) {
String tenantId = LoginHelper.getTenantId();
String tenantId = LoginHelper.getTenantId().toString();
// 判断是否有租户
if (StringUtils.isNotBlank(tenantId)) {
// 不需要过滤租户的表

View File

@ -130,7 +130,7 @@ public class TenantHelper {
public static String getTenantId() {
String tenantId = TenantHelper.getDynamic();
if (StringUtils.isBlank(tenantId)) {
tenantId = LoginHelper.getTenantId();
tenantId = LoginHelper.getTenantId().toString();
}
return tenantId;
}

View File

@ -43,7 +43,7 @@ public class SysOssConfigController extends BaseController {
/**
* 查询对象存储配置列表
*/
@SaCheckPermission("system:oss:list")
@SaCheckPermission("system:ossConfig:list")
@GetMapping("/list")
public TableDataInfo<SysOssConfigVo> list(SysOssConfigBo bo) {
return ossConfigService.queryPageList(bo);
@ -54,7 +54,7 @@ public class SysOssConfigController extends BaseController {
*
* @param ossConfigId OSS配置ID
*/
@SaCheckPermission("system:oss:query")
@SaCheckPermission("system:ossConfig:list")
@GetMapping("/{ossConfigId}")
public R<SysOssConfigVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long ossConfigId) {
@ -64,7 +64,7 @@ public class SysOssConfigController extends BaseController {
/**
* 新增对象存储配置
*/
@SaCheckPermission("system:oss:add")
@SaCheckPermission("system:ossConfig:add")
@Log(title = "对象存储配置", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
@ -79,7 +79,7 @@ public class SysOssConfigController extends BaseController {
/**
* 修改对象存储配置
*/
@SaCheckPermission("system:oss:edit")
@SaCheckPermission("system:ossConfig:edit")
@Log(title = "对象存储配置", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
@ -96,7 +96,7 @@ public class SysOssConfigController extends BaseController {
*
* @param ossConfigIds OSS配置ID串
*/
@SaCheckPermission("system:oss:remove")
@SaCheckPermission("system:ossConfig:remove")
@Log(title = "对象存储配置", businessType = BusinessType.DELETE)
@DeleteMapping("/{ossConfigIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@ -111,7 +111,7 @@ public class SysOssConfigController extends BaseController {
/**
* 状态修改
*/
@SaCheckPermission("system:oss:edit")
@SaCheckPermission("system:ossConfig:edit")
@Log(title = "对象存储状态修改", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus")
public R<Void> changeStatus(@RequestBody SysOssConfigBo bo) {

View File

@ -72,16 +72,17 @@ public class SysProfileController extends BaseController
public R<Void> updateProfile(@RequestBody SysUserProfileBo profile)
{
SysUserBo user = BeanUtil.toBean(profile, SysUserBo.class);
String username = LoginHelper.getUsername();
LoginUser loginUser = LoginHelper.getLoginUser();
SysUserVo sysUser = userService.selectUserById(loginUser.getUserId());
user.setUserName(sysUser.getUserName());
if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
{
return R.fail("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
return R.fail("修改用户'" + username + "'失败,手机号码已存在");
}
if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
{
return R.fail("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
return R.fail("修改用户'" + username + "'失败,邮箱账号已存在");
}
user.setUserId(sysUser.getUserId());
// user.setPassword(null);

View File

@ -33,3 +33,16 @@ UPDATE `pj_job_info` SET `processor_info`='com.ruoyi.job.processors.StandalonePr
UPDATE `pj_job_info` SET `processor_info`='com.ruoyi.job.processors.BroadcastProcessorDemo' WHERE `id`=2;
UPDATE `pj_job_info` SET `processor_info`='com.ruoyi.job.processors.MapProcessorDemo' WHERE `id`=3;
UPDATE `pj_job_info` SET `processor_info`='com.ruoyi.job.processors.MapReduceProcessorDemo' WHERE `id`=4;
--
ALTER TABLE `sys_menu`
CHANGE COLUMN `update_by` `update_by` BIGINT(19) NULL DEFAULT '0' COMMENT '更新者' AFTER `create_time`;
delete from sys_menu where menu_id in (1604, 1605);
insert into sys_menu values('1600', '文件查询', '118', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:query', '#', 1, sysdate(), null, null, '');
insert into sys_menu values('1601', '文件上传', '118', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:upload', '#', 1, sysdate(), null, null, '');
insert into sys_menu values('1602', '文件下载', '118', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:download', '#', 1, sysdate(), null, null, '');
insert into sys_menu values('1603', '文件删除', '118', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:remove', '#', 1, sysdate(), null, null, '');
insert into sys_menu values('1620', '配置列表', '118', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:list', '#', 1, sysdate(), null, null, '');
insert into sys_menu values('1621', '配置添加', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:add', '#', 1, sysdate(), null, null, '');
insert into sys_menu values('1622', '配置编辑', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:edit', '#', 1, sysdate(), null, null, '');
insert into sys_menu values('1623', '配置删除', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:remove', '#', 1, sysdate(), null, null, '');

View File

@ -41,3 +41,15 @@ ALTER COLUMN "node_params" TYPE TEXT,
ALTER COLUMN "node_params" DROP NOT NULL,
ALTER COLUMN "node_params" DROP DEFAULT;
COMMENT ON COLUMN "pj_workflow_node_info"."node_params" IS '';
--
delete from sys_menu where menu_id in (1604, 1605);
insert into sys_menu values('1600', '文件查询', '118', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:query', '#', 1, now(), null, null, '');
insert into sys_menu values('1601', '文件上传', '118', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:upload', '#', 1, now(), null, null, '');
insert into sys_menu values('1602', '文件下载', '118', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:download', '#', 1, now(), null, null, '');
insert into sys_menu values('1603', '文件删除', '118', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:remove', '#', 1, now(), null, null, '');
insert into sys_menu values('1620', '配置列表', '118', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:list', '#', 1, now(), null, null, '');
insert into sys_menu values('1621', '配置添加', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:add', '#', 1, now(), null, null, '');
insert into sys_menu values('1622', '配置编辑', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:edit', '#', 1, now(), null, null, '');
insert into sys_menu values('1623', '配置删除', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:remove', '#', 1, now(), null, null, '');