mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-03-25 23:04:33 +08:00
update 优化 统一补全代码注释
This commit is contained in:
@@ -47,7 +47,7 @@ import java.util.concurrent.ScheduledExecutorService;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 认证
|
* 认证控制器,提供登录、注册、社交绑定和退出能力。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@@ -103,10 +103,10 @@ public class AuthController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取跳转URL
|
* 获取第三方绑定跳转地址。
|
||||||
*
|
*
|
||||||
* @param source 登录来源
|
* @param source 登录来源
|
||||||
* @return 结果
|
* @return 跳转地址
|
||||||
*/
|
*/
|
||||||
@GetMapping("/binding/{source}")
|
@GetMapping("/binding/{source}")
|
||||||
public R<String> authBinding(@PathVariable("source") String source) {
|
public R<String> authBinding(@PathVariable("source") String source) {
|
||||||
@@ -120,10 +120,10 @@ public class AuthController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 前端回调绑定授权(需要token)
|
* 处理前端回调后的社交账号绑定。
|
||||||
*
|
*
|
||||||
* @param loginBody 请求体
|
* @param loginBody 请求体
|
||||||
* @return 结果
|
* @return 操作结果
|
||||||
*/
|
*/
|
||||||
@PostMapping("/social/callback")
|
@PostMapping("/social/callback")
|
||||||
public R<Void> socialCallback(@RequestBody SocialLoginBody loginBody) {
|
public R<Void> socialCallback(@RequestBody SocialLoginBody loginBody) {
|
||||||
@@ -144,9 +144,10 @@ public class AuthController {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取消授权(需要token)
|
* 取消当前用户的社交账号授权。
|
||||||
*
|
*
|
||||||
* @param socialId socialId
|
* @param socialId socialId
|
||||||
|
* @return 操作结果
|
||||||
*/
|
*/
|
||||||
@DeleteMapping(value = "/unlock/{socialId}")
|
@DeleteMapping(value = "/unlock/{socialId}")
|
||||||
public R<Void> unlockSocial(@PathVariable Long socialId) {
|
public R<Void> unlockSocial(@PathVariable Long socialId) {
|
||||||
@@ -167,7 +168,10 @@ public class AuthController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户注册
|
* 用户注册。
|
||||||
|
*
|
||||||
|
* @param user 注册信息
|
||||||
|
* @return 操作结果
|
||||||
*/
|
*/
|
||||||
@ApiEncrypt
|
@ApiEncrypt
|
||||||
@PostMapping("/register")
|
@PostMapping("/register")
|
||||||
@@ -180,9 +184,11 @@ public class AuthController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录页面租户下拉框
|
* 获取登录页租户下拉框数据,当前仅预留返回结构。
|
||||||
*
|
*
|
||||||
|
* @param request 当前请求
|
||||||
* @return 租户列表
|
* @return 租户列表
|
||||||
|
* @throws Exception 异常
|
||||||
*/
|
*/
|
||||||
@RateLimiter(time = 60, count = 20, limitType = LimitType.IP)
|
@RateLimiter(time = 60, count = 20, limitType = LimitType.IP)
|
||||||
@GetMapping("/tenant/list")
|
@GetMapping("/tenant/list")
|
||||||
|
|||||||
@@ -53,9 +53,10 @@ public class CaptchaController {
|
|||||||
private final MailProperties mailProperties;
|
private final MailProperties mailProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 短信验证码
|
* 发送短信验证码。
|
||||||
*
|
*
|
||||||
* @param phonenumber 用户手机号
|
* @param phonenumber 用户手机号
|
||||||
|
* @return 操作结果
|
||||||
*/
|
*/
|
||||||
@RateLimiter(key = "#phonenumber", time = 60, count = 1)
|
@RateLimiter(key = "#phonenumber", time = 60, count = 1)
|
||||||
@GetMapping("/resource/sms/code")
|
@GetMapping("/resource/sms/code")
|
||||||
@@ -77,9 +78,10 @@ public class CaptchaController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 邮箱验证码
|
* 发送邮箱验证码。
|
||||||
*
|
*
|
||||||
* @param email 邮箱
|
* @param email 邮箱
|
||||||
|
* @return 操作结果
|
||||||
*/
|
*/
|
||||||
@GetMapping("/resource/email/code")
|
@GetMapping("/resource/email/code")
|
||||||
public R<Void> emailCode(@NotBlank(message = "{user.email.not.blank}") String email) {
|
public R<Void> emailCode(@NotBlank(message = "{user.email.not.blank}") String email) {
|
||||||
@@ -91,8 +93,9 @@ public class CaptchaController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 邮箱验证码
|
* 发送邮箱验证码的实际执行方法,拆分出来避免开关关闭时仍触发限流。
|
||||||
* 独立方法避免验证码关闭之后仍然走限流
|
*
|
||||||
|
* @param email 邮箱
|
||||||
*/
|
*/
|
||||||
@RateLimiter(key = "#email", time = 60, count = 1)
|
@RateLimiter(key = "#email", time = 60, count = 1)
|
||||||
public void emailCodeImpl(String email) {
|
public void emailCodeImpl(String email) {
|
||||||
@@ -108,7 +111,9 @@ public class CaptchaController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成验证码
|
* 获取图片验证码。
|
||||||
|
*
|
||||||
|
* @return 验证码信息
|
||||||
*/
|
*/
|
||||||
@GetMapping("/auth/code")
|
@GetMapping("/auth/code")
|
||||||
public R<CaptchaVo> getCode() {
|
public R<CaptchaVo> getCode() {
|
||||||
@@ -122,8 +127,9 @@ public class CaptchaController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成验证码
|
* 实际生成图片验证码并缓存结果。
|
||||||
* 独立方法避免验证码关闭之后仍然走限流
|
*
|
||||||
|
* @return 验证码信息
|
||||||
*/
|
*/
|
||||||
@RateLimiter(time = 60, count = 10, limitType = LimitType.IP)
|
@RateLimiter(time = 60, count = 10, limitType = LimitType.IP)
|
||||||
public CaptchaVo getCodeImpl() {
|
public CaptchaVo getCodeImpl() {
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
public class IndexController {
|
public class IndexController {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 访问首页,提示语
|
* 访问首页时返回引导提示。
|
||||||
|
*
|
||||||
|
* @return 首页提示语
|
||||||
*/
|
*/
|
||||||
@GetMapping("/")
|
@GetMapping("/")
|
||||||
public String index() {
|
public String index() {
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ public class CaptchaVo {
|
|||||||
*/
|
*/
|
||||||
private Boolean captchaEnabled = true;
|
private Boolean captchaEnabled = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码唯一标识。
|
||||||
|
*/
|
||||||
private String uuid;
|
private String uuid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package org.dromara.web.domain.vo;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录租户对象
|
* 登录页租户信息返回对象。
|
||||||
*
|
*
|
||||||
* @author Michelle.Chung
|
* @author Michelle.Chung
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录验证信息
|
* 登录成功后的令牌信息返回对象。
|
||||||
*
|
*
|
||||||
* @author Michelle.Chung
|
* @author Michelle.Chung
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import org.springframework.stereotype.Component;
|
|||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户行为 侦听器的实现
|
* 用户行为监听器,用于同步在线状态和登录日志。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@@ -34,7 +34,7 @@ public class UserActionListener implements SaTokenListener {
|
|||||||
private final SysLoginService loginService;
|
private final SysLoginService loginService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 每次登录时触发
|
* 登录成功后记录在线信息并写入登录日志。
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginParameter loginParameter) {
|
public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginParameter loginParameter) {
|
||||||
@@ -71,7 +71,7 @@ public class UserActionListener implements SaTokenListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 每次注销时触发
|
* 注销时清理在线缓存。
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void doLogout(String loginType, Object loginId, String tokenValue) {
|
public void doLogout(String loginType, Object loginId, String tokenValue) {
|
||||||
@@ -80,7 +80,7 @@ public class UserActionListener implements SaTokenListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 每次被踢下线时触发
|
* 被踢下线时清理在线缓存。
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void doKickout(String loginType, Object loginId, String tokenValue) {
|
public void doKickout(String loginType, Object loginId, String tokenValue) {
|
||||||
@@ -89,7 +89,7 @@ public class UserActionListener implements SaTokenListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 每次被顶下线时触发
|
* 被顶下线时清理在线缓存。
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void doReplaced(String loginType, Object loginId, String tokenValue) {
|
public void doReplaced(String loginType, Object loginId, String tokenValue) {
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public interface IAuthStrategy {
|
|||||||
*
|
*
|
||||||
* @param body 登录对象
|
* @param body 登录对象
|
||||||
* @param client 授权管理视图对象
|
* @param client 授权管理视图对象
|
||||||
* @return 登录验证信息
|
* @return 当前策略完成认证后的登录结果
|
||||||
*/
|
*/
|
||||||
LoginVo login(String body, SysClientVo client);
|
LoginVo login(String body, SysClientVo client);
|
||||||
|
|
||||||
|
|||||||
@@ -136,7 +136,10 @@ public class SysLoginService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建登录用户
|
* 根据用户视图对象组装登录态上下文。
|
||||||
|
*
|
||||||
|
* @param user 用户基础信息
|
||||||
|
* @return 包含部门、角色、岗位与权限数据的登录用户
|
||||||
*/
|
*/
|
||||||
public LoginUser buildLoginUser(SysUserVo user) {
|
public LoginUser buildLoginUser(SysUserVo user) {
|
||||||
LoginUser loginUser = new LoginUser();
|
LoginUser loginUser = new LoginUser();
|
||||||
@@ -168,9 +171,10 @@ public class SysLoginService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 记录登录信息
|
* 更新用户最近一次登录IP与登录时间。
|
||||||
*
|
*
|
||||||
* @param userId 用户ID
|
* @param userId 用户ID
|
||||||
|
* @param ip 登录IP
|
||||||
*/
|
*/
|
||||||
public void recordLoginInfo(Long userId, String ip) {
|
public void recordLoginInfo(Long userId, String ip) {
|
||||||
SysUser sysUser = new SysUser();
|
SysUser sysUser = new SysUser();
|
||||||
@@ -182,7 +186,11 @@ public class SysLoginService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录校验
|
* 执行登录失败次数校验,并在成功后清空失败计数。
|
||||||
|
*
|
||||||
|
* @param loginType 登录类型
|
||||||
|
* @param username 登录标识
|
||||||
|
* @param supplier 返回 {@code true} 表示本次认证失败
|
||||||
*/
|
*/
|
||||||
public void checkLogin(LoginType loginType, String username, Supplier<Boolean> supplier) {
|
public void checkLogin(LoginType loginType, String username, Supplier<Boolean> supplier) {
|
||||||
String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username;
|
String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username;
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ public class SysRegisterService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 注册
|
* 注册
|
||||||
|
*
|
||||||
|
* @param registerBody 注册请求参数
|
||||||
*/
|
*/
|
||||||
public void register(RegisterBody registerBody) {
|
public void register(RegisterBody registerBody) {
|
||||||
String username = registerBody.getUsername();
|
String username = registerBody.getUsername();
|
||||||
@@ -95,7 +97,6 @@ public class SysRegisterService {
|
|||||||
* @param username 用户名
|
* @param username 用户名
|
||||||
* @param status 状态
|
* @param status 状态
|
||||||
* @param message 消息内容
|
* @param message 消息内容
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
private void recordLoginInfo(String username, String status, String message) {
|
private void recordLoginInfo(String username, String status, String message) {
|
||||||
LoginInfoEvent loginInfoEvent = new LoginInfoEvent();
|
LoginInfoEvent loginInfoEvent = new LoginInfoEvent();
|
||||||
|
|||||||
@@ -42,6 +42,13 @@ public class EmailAuthStrategy implements IAuthStrategy {
|
|||||||
private final SysLoginService loginService;
|
private final SysLoginService loginService;
|
||||||
private final SysUserMapper userMapper;
|
private final SysUserMapper userMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行邮箱验证码登录,并按客户端配置生成访问令牌。
|
||||||
|
*
|
||||||
|
* @param body 登录请求体
|
||||||
|
* @param client 当前客户端配置
|
||||||
|
* @return 登录结果
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public LoginVo login(String body, SysClientVo client) {
|
public LoginVo login(String body, SysClientVo client) {
|
||||||
EmailLoginBody loginBody = JsonUtils.parseObject(body, EmailLoginBody.class);
|
EmailLoginBody loginBody = JsonUtils.parseObject(body, EmailLoginBody.class);
|
||||||
@@ -72,7 +79,11 @@ public class EmailAuthStrategy implements IAuthStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验邮箱验证码
|
* 校验邮箱验证码是否存在且匹配。
|
||||||
|
*
|
||||||
|
* @param email 邮箱地址
|
||||||
|
* @param emailCode 用户输入的邮箱验证码
|
||||||
|
* @return 是否校验通过
|
||||||
*/
|
*/
|
||||||
private boolean validateEmailCode(String email, String emailCode) {
|
private boolean validateEmailCode(String email, String emailCode) {
|
||||||
String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email);
|
String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email);
|
||||||
@@ -83,6 +94,12 @@ public class EmailAuthStrategy implements IAuthStrategy {
|
|||||||
return code.equals(emailCode);
|
return code.equals(emailCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按邮箱加载可登录用户,并校验是否存在或被停用。
|
||||||
|
*
|
||||||
|
* @param email 邮箱地址
|
||||||
|
* @return 用户信息
|
||||||
|
*/
|
||||||
private SysUserVo loadUserByEmail(String email) {
|
private SysUserVo loadUserByEmail(String email) {
|
||||||
SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getEmail, email));
|
SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getEmail, email));
|
||||||
if (ObjectUtil.isNull(user)) {
|
if (ObjectUtil.isNull(user)) {
|
||||||
|
|||||||
@@ -46,6 +46,13 @@ public class PasswordAuthStrategy implements IAuthStrategy {
|
|||||||
private final SysLoginService loginService;
|
private final SysLoginService loginService;
|
||||||
private final SysUserMapper userMapper;
|
private final SysUserMapper userMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行账号密码登录,并按客户端配置生成访问令牌。
|
||||||
|
*
|
||||||
|
* @param body 登录请求体
|
||||||
|
* @param client 当前客户端配置
|
||||||
|
* @return 登录结果
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public LoginVo login(String body, SysClientVo client) {
|
public LoginVo login(String body, SysClientVo client) {
|
||||||
PasswordLoginBody loginBody = JsonUtils.parseObject(body, PasswordLoginBody.class);
|
PasswordLoginBody loginBody = JsonUtils.parseObject(body, PasswordLoginBody.class);
|
||||||
@@ -84,11 +91,11 @@ public class PasswordAuthStrategy implements IAuthStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验验证码
|
* 校验图形验证码是否有效且匹配。
|
||||||
*
|
*
|
||||||
* @param username 用户名
|
* @param username 用户名
|
||||||
* @param code 验证码
|
* @param code 用户输入的验证码
|
||||||
* @param uuid 唯一标识
|
* @param uuid 验证码缓存标识
|
||||||
*/
|
*/
|
||||||
private void validateCaptcha(String username, String code, String uuid) {
|
private void validateCaptcha(String username, String code, String uuid) {
|
||||||
String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, "");
|
String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, "");
|
||||||
@@ -104,6 +111,12 @@ public class PasswordAuthStrategy implements IAuthStrategy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按用户名加载可登录用户,并校验是否存在或被停用。
|
||||||
|
*
|
||||||
|
* @param username 用户名
|
||||||
|
* @return 用户信息
|
||||||
|
*/
|
||||||
private SysUserVo loadUserByUsername(String username) {
|
private SysUserVo loadUserByUsername(String username) {
|
||||||
SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, username));
|
SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, username));
|
||||||
if (ObjectUtil.isNull(user)) {
|
if (ObjectUtil.isNull(user)) {
|
||||||
|
|||||||
@@ -42,6 +42,13 @@ public class SmsAuthStrategy implements IAuthStrategy {
|
|||||||
private final SysLoginService loginService;
|
private final SysLoginService loginService;
|
||||||
private final SysUserMapper userMapper;
|
private final SysUserMapper userMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行短信验证码登录,并按客户端配置生成访问令牌。
|
||||||
|
*
|
||||||
|
* @param body 登录请求体
|
||||||
|
* @param client 当前客户端配置
|
||||||
|
* @return 登录结果
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public LoginVo login(String body, SysClientVo client) {
|
public LoginVo login(String body, SysClientVo client) {
|
||||||
SmsLoginBody loginBody = JsonUtils.parseObject(body, SmsLoginBody.class);
|
SmsLoginBody loginBody = JsonUtils.parseObject(body, SmsLoginBody.class);
|
||||||
@@ -72,7 +79,11 @@ public class SmsAuthStrategy implements IAuthStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验短信验证码
|
* 校验短信验证码是否存在且匹配。
|
||||||
|
*
|
||||||
|
* @param phonenumber 手机号
|
||||||
|
* @param smsCode 用户输入的短信验证码
|
||||||
|
* @return 是否校验通过
|
||||||
*/
|
*/
|
||||||
private boolean validateSmsCode(String phonenumber, String smsCode) {
|
private boolean validateSmsCode(String phonenumber, String smsCode) {
|
||||||
String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber);
|
String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber);
|
||||||
@@ -83,6 +94,12 @@ public class SmsAuthStrategy implements IAuthStrategy {
|
|||||||
return code.equals(smsCode);
|
return code.equals(smsCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按手机号加载可登录用户,并校验是否存在或被停用。
|
||||||
|
*
|
||||||
|
* @param phonenumber 手机号
|
||||||
|
* @return 用户信息
|
||||||
|
*/
|
||||||
private SysUserVo loadUserByPhonenumber(String phonenumber) {
|
private SysUserVo loadUserByPhonenumber(String phonenumber) {
|
||||||
SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, phonenumber));
|
SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, phonenumber));
|
||||||
if (ObjectUtil.isNull(user)) {
|
if (ObjectUtil.isNull(user)) {
|
||||||
|
|||||||
@@ -46,10 +46,11 @@ public class SocialAuthStrategy implements IAuthStrategy {
|
|||||||
private final SysLoginService loginService;
|
private final SysLoginService loginService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录-第三方授权登录
|
* 执行第三方授权登录,并校验授权账号与系统账号的绑定关系。
|
||||||
*
|
*
|
||||||
* @param body 登录信息
|
* @param body 登录信息
|
||||||
* @param client 客户端信息
|
* @param client 客户端信息
|
||||||
|
* @return 登录结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public LoginVo login(String body, SysClientVo client) {
|
public LoginVo login(String body, SysClientVo client) {
|
||||||
@@ -89,6 +90,12 @@ public class SocialAuthStrategy implements IAuthStrategy {
|
|||||||
return loginVo;
|
return loginVo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID加载用户,并校验账号状态是否允许登录。
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 用户信息
|
||||||
|
*/
|
||||||
private SysUserVo loadUser(Long userId) {
|
private SysUserVo loadUser(Long userId) {
|
||||||
SysUserVo user = userMapper.selectVoById(userId);
|
SysUserVo user = userMapper.selectVoById(userId);
|
||||||
if (ObjectUtil.isNull(user)) {
|
if (ObjectUtil.isNull(user)) {
|
||||||
|
|||||||
@@ -38,6 +38,13 @@ public class XcxAuthStrategy implements IAuthStrategy {
|
|||||||
|
|
||||||
private final SysLoginService loginService;
|
private final SysLoginService loginService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行微信小程序登录,并根据 openid 构建小程序用户登录态。
|
||||||
|
*
|
||||||
|
* @param body 登录请求体
|
||||||
|
* @param client 当前客户端配置
|
||||||
|
* @return 登录结果
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public LoginVo login(String body, SysClientVo client) {
|
public LoginVo login(String body, SysClientVo client) {
|
||||||
XcxLoginBody loginBody = JsonUtils.parseObject(body, XcxLoginBody.class);
|
XcxLoginBody loginBody = JsonUtils.parseObject(body, XcxLoginBody.class);
|
||||||
@@ -93,6 +100,12 @@ public class XcxAuthStrategy implements IAuthStrategy {
|
|||||||
return loginVo;
|
return loginVo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按 openid 查询小程序绑定用户。
|
||||||
|
*
|
||||||
|
* @param openid 小程序用户唯一标识
|
||||||
|
* @return 绑定的系统用户信息
|
||||||
|
*/
|
||||||
private SysUserVo loadUserByOpenid(String openid) {
|
private SysUserVo loadUserByOpenid(String openid) {
|
||||||
// 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户
|
// 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户
|
||||||
// todo 自行实现 userService.selectUserByOpenid(openid);
|
// todo 自行实现 userService.selectUserByOpenid(openid);
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ public class ThreadPoolConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行周期性或定时任务
|
* 执行周期性或定时任务
|
||||||
|
*
|
||||||
|
* @return 全局定时任务线程池
|
||||||
*/
|
*/
|
||||||
@Bean(name = "scheduledExecutorService")
|
@Bean(name = "scheduledExecutorService")
|
||||||
protected ScheduledExecutorService scheduledExecutorService() {
|
protected ScheduledExecutorService scheduledExecutorService() {
|
||||||
@@ -85,6 +87,9 @@ public class ThreadPoolConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 打印线程异常信息
|
* 打印线程异常信息
|
||||||
|
*
|
||||||
|
* @param r 已执行的任务
|
||||||
|
* @param t 任务执行过程中抛出的异常
|
||||||
*/
|
*/
|
||||||
public static void printException(Runnable r, Throwable t) {
|
public static void printException(Runnable r, Throwable t) {
|
||||||
if (t == null && r instanceof Future<?>) {
|
if (t == null && r instanceof Future<?>) {
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ public class ValidatorConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 配置校验框架 快速失败模式
|
* 配置校验框架 快速失败模式
|
||||||
|
*
|
||||||
|
* @param messageSource 国际化消息源
|
||||||
|
* @return 启用快速失败模式的校验器
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public Validator validator(MessageSource messageSource) {
|
public Validator validator(MessageSource messageSource) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package org.dromara.common.core.constant;
|
package org.dromara.common.core.constant;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 缓存的key 常量
|
* Redis 缓存键前缀常量。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package org.dromara.common.core.constant;
|
package org.dromara.common.core.constant;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 缓存组名称常量
|
* 缓存组名称常量,统一约定缓存名和缓存策略配置格式。
|
||||||
* <p>
|
* <p>
|
||||||
* key 格式为 cacheNames#ttl#maxIdleTime#maxSize#local
|
* key 格式为 cacheNames#ttl#maxIdleTime#maxSize#local
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package org.dromara.common.core.constant;
|
package org.dromara.common.core.constant;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通用常量信息
|
* 通用基础常量定义。
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package org.dromara.common.core.constant;
|
package org.dromara.common.core.constant;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 全局的key常量 (业务无关的key)
|
* 全局通用键常量,主要用于业务无关的 Redis Key 前缀定义。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -65,6 +65,11 @@ public class CompleteTaskDTO implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String ext;
|
private String ext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程变量并自动剔除空值。
|
||||||
|
*
|
||||||
|
* @return 流程变量
|
||||||
|
*/
|
||||||
public Map<String, Object> getVariables() {
|
public Map<String, Object> getVariables() {
|
||||||
if (variables == null) {
|
if (variables == null) {
|
||||||
variables = new HashMap<>(16);
|
variables = new HashMap<>(16);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OSS对象
|
* OSS 文件简要信息对象。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 岗位
|
* 岗位简要信息对象。
|
||||||
*
|
*
|
||||||
* @author AprilWind
|
* @author AprilWind
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,11 +7,10 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 角色
|
* 角色简要信息对象。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class RoleDTO implements Serializable {
|
public class RoleDTO implements Serializable {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启动流程对象
|
* 启动流程请求对象。
|
||||||
*
|
*
|
||||||
* @author may
|
* @author may
|
||||||
*/
|
*/
|
||||||
@@ -46,6 +46,11 @@ public class StartProcessDTO implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private FlowInstanceBizExtDTO bizExt;
|
private FlowInstanceBizExtDTO bizExt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程变量并自动剔除空值。
|
||||||
|
*
|
||||||
|
* @return 流程变量
|
||||||
|
*/
|
||||||
public Map<String, Object> getVariables() {
|
public Map<String, Object> getVariables() {
|
||||||
if (variables == null) {
|
if (variables == null) {
|
||||||
variables = new HashMap<>(16);
|
variables = new HashMap<>(16);
|
||||||
@@ -55,6 +60,11 @@ public class StartProcessDTO implements Serializable {
|
|||||||
return variables;
|
return variables;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程业务扩展信息,为空时返回默认对象。
|
||||||
|
*
|
||||||
|
* @return 业务扩展信息
|
||||||
|
*/
|
||||||
public FlowInstanceBizExtDTO getBizExt() {
|
public FlowInstanceBizExtDTO getBizExt() {
|
||||||
if (ObjectUtil.isNull(bizExt)) {
|
if (ObjectUtil.isNull(bizExt)) {
|
||||||
bizExt = new FlowInstanceBizExtDTO();
|
bizExt = new FlowInstanceBizExtDTO();
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启动流程返回对象
|
* 启动流程后的返回结果对象。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public class TaskAssigneeDTO implements Serializable {
|
|||||||
private Long total = 0L;
|
private Long total = 0L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* 受让人列表。
|
||||||
*/
|
*/
|
||||||
private List<TaskHandler> list;
|
private List<TaskHandler> list;
|
||||||
|
|
||||||
@@ -67,6 +67,9 @@ public class TaskAssigneeDTO implements Serializable {
|
|||||||
)).collect(Collectors.toList());
|
)).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务受让人明细对象。
|
||||||
|
*/
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
|||||||
@@ -7,11 +7,10 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前在线会话
|
* 当前在线会话信息对象。
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class UserOnlineDTO implements Serializable {
|
public class UserOnlineDTO implements Serializable {
|
||||||
|
|||||||
@@ -6,11 +6,10 @@ import lombok.Data;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 邮件登录对象
|
* 邮箱验证码登录请求对象。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class EmailLoginBody extends LoginBody {
|
public class EmailLoginBody extends LoginBody {
|
||||||
|
|||||||
@@ -7,11 +7,10 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户登录对象
|
* 通用登录请求对象,封装客户端、授权类型和验证码信息。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class LoginBody implements Serializable {
|
public class LoginBody implements Serializable {
|
||||||
|
|
||||||
@@ -36,7 +35,7 @@ public class LoginBody implements Serializable {
|
|||||||
private String code;
|
private String code;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 唯一标识
|
* 验证码唯一标识。
|
||||||
*/
|
*/
|
||||||
private String uuid;
|
private String uuid;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录用户身份权限
|
* 登录用户上下文对象,保存当前会话的身份、权限和终端信息。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@@ -134,7 +134,9 @@ public class LoginUser implements Serializable {
|
|||||||
private String deviceType;
|
private String deviceType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取登录id
|
* 获取 Sa-Token 使用的登录标识。
|
||||||
|
*
|
||||||
|
* @return 登录标识
|
||||||
*/
|
*/
|
||||||
public String getLoginId() {
|
public String getLoginId() {
|
||||||
if (userType == null) {
|
if (userType == null) {
|
||||||
|
|||||||
@@ -5,11 +5,10 @@ import lombok.Data;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 短信登录对象
|
* 短信验证码登录请求对象。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class SmsLoginBody extends LoginBody {
|
public class SmsLoginBody extends LoginBody {
|
||||||
|
|||||||
@@ -5,11 +5,10 @@ import lombok.Data;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 三方登录对象
|
* 第三方平台登录绑定请求对象。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class SocialLoginBody extends LoginBody {
|
public class SocialLoginBody extends LoginBody {
|
||||||
|
|||||||
@@ -5,11 +5,10 @@ import lombok.Data;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 三方登录对象
|
* 小程序登录请求对象。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class XcxLoginBody extends LoginBody {
|
public class XcxLoginBody extends LoginBody {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import lombok.NoArgsConstructor;
|
|||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 小程序登录用户身份权限
|
* 小程序登录用户上下文对象。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@@ -20,7 +20,7 @@ public class XcxLoginUser extends LoginUser {
|
|||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* openid
|
* 小程序 openid。
|
||||||
*/
|
*/
|
||||||
private String openid;
|
private String openid;
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import java.util.function.Function;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 业务状态枚举
|
* 流程业务状态枚举,统一定义单据在审批流转中的状态。
|
||||||
*
|
*
|
||||||
* @author may
|
* @author may
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设备类型
|
* 登录设备类型枚举。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录类型
|
* 登录类型枚举,同时维护不同登录方式对应的重试提示配置。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -24,7 +24,14 @@ public enum UserStatus {
|
|||||||
*/
|
*/
|
||||||
DELETED("2", "删除");
|
DELETED("2", "删除");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态编码。
|
||||||
|
*/
|
||||||
private final String code;
|
private final String code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态说明。
|
||||||
|
*/
|
||||||
private final String info;
|
private final String info;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,12 @@ public enum UserType {
|
|||||||
*/
|
*/
|
||||||
private final String userType;
|
private final String userType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据字符串内容匹配用户类型。
|
||||||
|
*
|
||||||
|
* @param str 待匹配字符串
|
||||||
|
* @return 用户类型
|
||||||
|
*/
|
||||||
public static UserType getUserType(String str) {
|
public static UserType getUserType(String str) {
|
||||||
for (UserType value : values()) {
|
for (UserType value : values()) {
|
||||||
if (StringUtils.contains(str, value.getUserType())) {
|
if (StringUtils.contains(str, value.getUserType())) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import lombok.NoArgsConstructor;
|
|||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 业务异常(支持占位符 {} )
|
* 通用业务异常,支持使用占位符拼接错误信息。
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
@@ -37,15 +37,32 @@ public final class ServiceException extends RuntimeException {
|
|||||||
*/
|
*/
|
||||||
private String detailMessage;
|
private String detailMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用错误消息构造业务异常。
|
||||||
|
*
|
||||||
|
* @param message 错误消息
|
||||||
|
*/
|
||||||
public ServiceException(String message) {
|
public ServiceException(String message) {
|
||||||
this.message = message;
|
this.message = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用错误消息和错误码构造业务异常。
|
||||||
|
*
|
||||||
|
* @param message 错误消息
|
||||||
|
* @param code 错误码
|
||||||
|
*/
|
||||||
public ServiceException(String message, Integer code) {
|
public ServiceException(String message, Integer code) {
|
||||||
this.message = message;
|
this.message = message;
|
||||||
this.code = code;
|
this.code = code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用占位符参数格式化错误消息。
|
||||||
|
*
|
||||||
|
* @param message 模板消息
|
||||||
|
* @param args 参数
|
||||||
|
*/
|
||||||
public ServiceException(String message, Object... args) {
|
public ServiceException(String message, Object... args) {
|
||||||
this.message = StrFormatter.format(message, args);
|
this.message = StrFormatter.format(message, args);
|
||||||
}
|
}
|
||||||
@@ -55,11 +72,23 @@ public final class ServiceException extends RuntimeException {
|
|||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置错误消息并返回当前异常对象。
|
||||||
|
*
|
||||||
|
* @param message 错误消息
|
||||||
|
* @return 当前异常对象
|
||||||
|
*/
|
||||||
public ServiceException setMessage(String message) {
|
public ServiceException setMessage(String message) {
|
||||||
this.message = message;
|
this.message = message;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置错误明细并返回当前异常对象。
|
||||||
|
*
|
||||||
|
* @param detailMessage 错误明细
|
||||||
|
* @return 当前异常对象
|
||||||
|
*/
|
||||||
public ServiceException setDetailMessage(String detailMessage) {
|
public ServiceException setDetailMessage(String detailMessage) {
|
||||||
this.detailMessage = detailMessage;
|
this.detailMessage = detailMessage;
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import lombok.NoArgsConstructor;
|
|||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sse 特制异常
|
* SSE 场景专用异常。
|
||||||
*
|
*
|
||||||
* @author LionLi
|
* @author LionLi
|
||||||
*/
|
*/
|
||||||
@@ -36,10 +36,21 @@ public final class SseException extends RuntimeException {
|
|||||||
*/
|
*/
|
||||||
private String detailMessage;
|
private String detailMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用错误消息构造 SSE 异常。
|
||||||
|
*
|
||||||
|
* @param message 错误消息
|
||||||
|
*/
|
||||||
public SseException(String message) {
|
public SseException(String message) {
|
||||||
this.message = message;
|
this.message = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用错误消息和错误码构造 SSE 异常。
|
||||||
|
*
|
||||||
|
* @param message 错误消息
|
||||||
|
* @param code 错误码
|
||||||
|
*/
|
||||||
public SseException(String message, Integer code) {
|
public SseException(String message, Integer code) {
|
||||||
this.message = message;
|
this.message = message;
|
||||||
this.code = code;
|
this.code = code;
|
||||||
@@ -50,11 +61,23 @@ public final class SseException extends RuntimeException {
|
|||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置错误消息并返回当前异常对象。
|
||||||
|
*
|
||||||
|
* @param message 错误消息
|
||||||
|
* @return 当前异常对象
|
||||||
|
*/
|
||||||
public SseException setMessage(String message) {
|
public SseException setMessage(String message) {
|
||||||
this.message = message;
|
this.message = message;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置错误明细并返回当前异常对象。
|
||||||
|
*
|
||||||
|
* @param detailMessage 错误明细
|
||||||
|
* @return 当前异常对象
|
||||||
|
*/
|
||||||
public SseException setDetailMessage(String detailMessage) {
|
public SseException setDetailMessage(String detailMessage) {
|
||||||
this.detailMessage = detailMessage;
|
this.detailMessage = detailMessage;
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import lombok.NoArgsConstructor;
|
|||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基础异常
|
* 基础国际化异常,支持按错误码解析最终提示信息。
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
@@ -43,18 +43,42 @@ public class BaseException extends RuntimeException {
|
|||||||
*/
|
*/
|
||||||
private String defaultMessage;
|
private String defaultMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用模块、错误码和参数构造异常。
|
||||||
|
*
|
||||||
|
* @param module 所属模块
|
||||||
|
* @param code 错误码
|
||||||
|
* @param args 参数
|
||||||
|
*/
|
||||||
public BaseException(String module, String code, Object[] args) {
|
public BaseException(String module, String code, Object[] args) {
|
||||||
this(module, code, args, null);
|
this(module, code, args, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用模块和默认消息构造异常。
|
||||||
|
*
|
||||||
|
* @param module 所属模块
|
||||||
|
* @param defaultMessage 默认消息
|
||||||
|
*/
|
||||||
public BaseException(String module, String defaultMessage) {
|
public BaseException(String module, String defaultMessage) {
|
||||||
this(module, null, null, defaultMessage);
|
this(module, null, null, defaultMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用错误码和参数构造异常。
|
||||||
|
*
|
||||||
|
* @param code 错误码
|
||||||
|
* @param args 参数
|
||||||
|
*/
|
||||||
public BaseException(String code, Object[] args) {
|
public BaseException(String code, Object[] args) {
|
||||||
this(null, code, args, null);
|
this(null, code, args, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用默认消息构造异常。
|
||||||
|
*
|
||||||
|
* @param defaultMessage 默认消息
|
||||||
|
*/
|
||||||
public BaseException(String defaultMessage) {
|
public BaseException(String defaultMessage) {
|
||||||
this(null, null, null, defaultMessage);
|
this(null, null, null, defaultMessage);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ public interface WorkflowService {
|
|||||||
* 获取流程变量
|
* 获取流程变量
|
||||||
*
|
*
|
||||||
* @param instanceId 流程实例id
|
* @param instanceId 流程实例id
|
||||||
|
* @return 流程变量详情
|
||||||
*/
|
*/
|
||||||
Map<String, Object> instanceVariable(Long instanceId);
|
Map<String, Object> instanceVariable(Long instanceId);
|
||||||
|
|
||||||
@@ -65,7 +66,7 @@ public interface WorkflowService {
|
|||||||
* 启动流程
|
* 启动流程
|
||||||
*
|
*
|
||||||
* @param startProcess 参数
|
* @param startProcess 参数
|
||||||
* @return 结果
|
* @return 启动后的流程实例与首任务信息
|
||||||
*/
|
*/
|
||||||
StartProcessReturnDTO startWorkFlow(StartProcessDTO startProcess);
|
StartProcessReturnDTO startWorkFlow(StartProcessDTO startProcess);
|
||||||
|
|
||||||
@@ -75,7 +76,7 @@ public interface WorkflowService {
|
|||||||
* completeTask.getVariables().put("ignore", true);
|
* completeTask.getVariables().put("ignore", true);
|
||||||
*
|
*
|
||||||
* @param completeTask 参数
|
* @param completeTask 参数
|
||||||
* @return 结果
|
* @return 办理成功返回 {@code true}
|
||||||
*/
|
*/
|
||||||
boolean completeTask(CompleteTaskDTO completeTask);
|
boolean completeTask(CompleteTaskDTO completeTask);
|
||||||
|
|
||||||
@@ -84,7 +85,7 @@ public interface WorkflowService {
|
|||||||
*
|
*
|
||||||
* @param taskId 任务ID
|
* @param taskId 任务ID
|
||||||
* @param message 办理意见
|
* @param message 办理意见
|
||||||
* @return 结果
|
* @return 办理成功返回 {@code true}
|
||||||
*/
|
*/
|
||||||
boolean completeTask(Long taskId, String message);
|
boolean completeTask(Long taskId, String message);
|
||||||
|
|
||||||
@@ -92,7 +93,7 @@ public interface WorkflowService {
|
|||||||
* 启动流程并办理第一个任务
|
* 启动流程并办理第一个任务
|
||||||
*
|
*
|
||||||
* @param startProcess 参数
|
* @param startProcess 参数
|
||||||
* @return 结果
|
* @return 首节点办理成功返回 {@code true}
|
||||||
*/
|
*/
|
||||||
boolean startCompleteTask(StartProcessDTO startProcess);
|
boolean startCompleteTask(StartProcessDTO startProcess);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,12 @@ public class SpringDocConfig {
|
|||||||
|
|
||||||
private final ServerProperties serverProperties;
|
private final ServerProperties serverProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建基础 OpenAPI 文档对象。
|
||||||
|
*
|
||||||
|
* @param properties SpringDoc 配置
|
||||||
|
* @return OpenAPI 对象
|
||||||
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(OpenAPI.class)
|
@ConditionalOnMissingBean(OpenAPI.class)
|
||||||
public OpenAPI openApi(SpringDocProperties properties) {
|
public OpenAPI openApi(SpringDocProperties properties) {
|
||||||
@@ -68,6 +74,12 @@ public class SpringDocConfig {
|
|||||||
return openApi;
|
return openApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将自定义文档信息配置转换为 OpenAPI Info。
|
||||||
|
*
|
||||||
|
* @param infoProperties 文档信息配置
|
||||||
|
* @return Info 对象
|
||||||
|
*/
|
||||||
private Info convertInfo(SpringDocProperties.InfoProperties infoProperties) {
|
private Info convertInfo(SpringDocProperties.InfoProperties infoProperties) {
|
||||||
Info info = new Info();
|
Info info = new Info();
|
||||||
info.setTitle(infoProperties.getTitle());
|
info.setTitle(infoProperties.getTitle());
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ public class SaTokenSecurityMetadata {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 重写mode的获取方法,返回符号而非文字
|
* 重写mode的获取方法,返回符号而非文字
|
||||||
|
*
|
||||||
* @return AND→&,OR→|,默认→&
|
* @return AND→&,OR→|,默认→&
|
||||||
*/
|
*/
|
||||||
public String getModeSymbol() {
|
public String getModeSymbol() {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public interface JavadocResolver extends Comparable<JavadocResolver>, Ordered {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查解析器是否支持解析 HandlerMethod
|
* 检查解析器是否支持解析 HandlerMethod
|
||||||
|
*
|
||||||
* @param handlerMethod 处理器方法
|
* @param handlerMethod 处理器方法
|
||||||
* @return 是否支持解析
|
* @return 是否支持解析
|
||||||
*/
|
*/
|
||||||
@@ -22,6 +23,7 @@ public interface JavadocResolver extends Comparable<JavadocResolver>, Ordered {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行解析并返回解析到的 Javadoc 内容
|
* 执行解析并返回解析到的 Javadoc 内容
|
||||||
|
*
|
||||||
* @param handlerMethod 处理器方法
|
* @param handlerMethod 处理器方法
|
||||||
* @param operation Swagger Operation实例
|
* @param operation Swagger Operation实例
|
||||||
* @return 解析到的 Javadoc 内容
|
* @return 解析到的 Javadoc 内容
|
||||||
@@ -29,7 +31,9 @@ public interface JavadocResolver extends Comparable<JavadocResolver>, Ordered {
|
|||||||
String resolve(HandlerMethod handlerMethod, Operation operation);
|
String resolve(HandlerMethod handlerMethod, Operation operation);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取解析器优先级
|
* 获取解析器优先级。
|
||||||
|
*
|
||||||
|
* @return 优先级
|
||||||
*/
|
*/
|
||||||
default int getOrder() {
|
default int getOrder() {
|
||||||
return Ordered.LOWEST_PRECEDENCE;
|
return Ordered.LOWEST_PRECEDENCE;
|
||||||
@@ -44,6 +48,12 @@ public interface JavadocResolver extends Comparable<JavadocResolver>, Ordered {
|
|||||||
return this.getClass().getSimpleName();
|
return this.getClass().getSimpleName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比较解析器执行顺序。
|
||||||
|
*
|
||||||
|
* @param o 其他解析器
|
||||||
|
* @return 比较结果
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
default int compareTo(@NotNull JavadocResolver o) {
|
default int compareTo(@NotNull JavadocResolver o) {
|
||||||
return Integer.compare(getOrder(), o.getOrder());
|
return Integer.compare(getOrder(), o.getOrder());
|
||||||
|
|||||||
@@ -54,23 +54,53 @@ public class SaTokenAnnotationMetadataJavadocResolver extends AbstractMetadataJa
|
|||||||
this(DEFAULT_METADATA_PROVIDER);
|
this(DEFAULT_METADATA_PROVIDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用自定义元数据提供者创建解析器。
|
||||||
|
*
|
||||||
|
* @param metadataProvider 元数据提供者
|
||||||
|
*/
|
||||||
public SaTokenAnnotationMetadataJavadocResolver(Supplier<SaTokenSecurityMetadata> metadataProvider) {
|
public SaTokenAnnotationMetadataJavadocResolver(Supplier<SaTokenSecurityMetadata> metadataProvider) {
|
||||||
super(metadataProvider);
|
super(metadataProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用指定顺序创建解析器。
|
||||||
|
*
|
||||||
|
* @param order 顺序值
|
||||||
|
*/
|
||||||
public SaTokenAnnotationMetadataJavadocResolver(int order) {
|
public SaTokenAnnotationMetadataJavadocResolver(int order) {
|
||||||
this(DEFAULT_METADATA_PROVIDER,order);
|
this(DEFAULT_METADATA_PROVIDER,order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用自定义元数据提供者和顺序创建解析器。
|
||||||
|
*
|
||||||
|
* @param metadataProvider 元数据提供者
|
||||||
|
* @param order 顺序值
|
||||||
|
*/
|
||||||
public SaTokenAnnotationMetadataJavadocResolver(Supplier<SaTokenSecurityMetadata> metadataProvider, int order) {
|
public SaTokenAnnotationMetadataJavadocResolver(Supplier<SaTokenSecurityMetadata> metadataProvider, int order) {
|
||||||
super(metadataProvider,order);
|
super(metadataProvider,order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断当前方法是否需要由该解析器处理。
|
||||||
|
*
|
||||||
|
* @param handlerMethod Handler 方法
|
||||||
|
* @return 是否支持
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean supports(HandlerMethod handlerMethod) {
|
public boolean supports(HandlerMethod handlerMethod) {
|
||||||
return hasAnnotation(handlerMethod, SA_CHECK_ROLE_CLASS) || hasAnnotation(handlerMethod, SA_CHECK_PERMISSION_CLASS) || hasAnnotation(handlerMethod, SA_IGNORE_CLASS);
|
return hasAnnotation(handlerMethod, SA_CHECK_ROLE_CLASS) || hasAnnotation(handlerMethod, SA_CHECK_PERMISSION_CLASS) || hasAnnotation(handlerMethod, SA_IGNORE_CLASS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析 Sa-Token 注解并转换为文档说明。
|
||||||
|
*
|
||||||
|
* @param handlerMethod Handler 方法
|
||||||
|
* @param operation OpenAPI 操作对象
|
||||||
|
* @param metadata 权限元数据
|
||||||
|
* @return Markdown 描述
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String resolve(HandlerMethod handlerMethod, Operation operation, SaTokenSecurityMetadata metadata) {
|
public String resolve(HandlerMethod handlerMethod, Operation operation, SaTokenSecurityMetadata metadata) {
|
||||||
// 检查是否忽略校验
|
// 检查是否忽略校验
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ public class OpenApiHandler extends OpenAPIService {
|
|||||||
* @param openApiBuilderCustomizers the open api builder customisers
|
* @param openApiBuilderCustomizers the open api builder customisers
|
||||||
* @param serverBaseUrlCustomizers the server base url customizers
|
* @param serverBaseUrlCustomizers the server base url customizers
|
||||||
* @param javadocProvider the javadoc provider
|
* @param javadocProvider the javadoc provider
|
||||||
|
* @param javadocResolvers Javadoc 解析器列表
|
||||||
*/
|
*/
|
||||||
public OpenApiHandler(Optional<OpenAPI> openAPI, SecurityService securityParser,
|
public OpenApiHandler(Optional<OpenAPI> openAPI, SecurityService securityParser,
|
||||||
SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils,
|
SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils,
|
||||||
@@ -152,6 +153,15 @@ public class OpenApiHandler extends OpenAPIService {
|
|||||||
TypeNameResolver.std.setUseFqn(true);
|
TypeNameResolver.std.setUseFqn(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建接口标签、权限描述与方法摘要。
|
||||||
|
*
|
||||||
|
* @param handlerMethod Handler 方法
|
||||||
|
* @param operation OpenAPI 操作对象
|
||||||
|
* @param openAPI OpenAPI 文档对象
|
||||||
|
* @param locale 当前语言环境
|
||||||
|
* @return 处理后的操作对象
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Operation buildTags(HandlerMethod handlerMethod, Operation operation, OpenAPI openAPI, Locale locale) {
|
public Operation buildTags(HandlerMethod handlerMethod, Operation operation, OpenAPI openAPI, Locale locale) {
|
||||||
|
|
||||||
@@ -247,6 +257,14 @@ public class OpenApiHandler extends OpenAPIService {
|
|||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从方法注解中提取标签信息。
|
||||||
|
*
|
||||||
|
* @param method 方法对象
|
||||||
|
* @param tags 标签集合
|
||||||
|
* @param tagsStr 标签名称集合
|
||||||
|
* @param locale 当前语言环境
|
||||||
|
*/
|
||||||
private void buildTagsFromMethod(Method method, Set<io.swagger.v3.oas.models.tags.Tag> tags, Set<String> tagsStr, Locale locale) {
|
private void buildTagsFromMethod(Method method, Set<io.swagger.v3.oas.models.tags.Tag> tags, Set<String> tagsStr, Locale locale) {
|
||||||
// method tags
|
// method tags
|
||||||
Set<Tags> tagsSet = AnnotatedElementUtils
|
Set<Tags> tagsSet = AnnotatedElementUtils
|
||||||
@@ -261,6 +279,13 @@ public class OpenApiHandler extends OpenAPIService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将注解标签转换并合并到 OpenAPI 标签集合。
|
||||||
|
*
|
||||||
|
* @param sourceTags 注解标签列表
|
||||||
|
* @param tags OpenAPI 标签集合
|
||||||
|
* @param locale 当前语言环境
|
||||||
|
*/
|
||||||
private void addTags(List<io.swagger.v3.oas.annotations.tags.Tag> sourceTags, Set<io.swagger.v3.oas.models.tags.Tag> tags, Locale locale) {
|
private void addTags(List<io.swagger.v3.oas.annotations.tags.Tag> sourceTags, Set<io.swagger.v3.oas.models.tags.Tag> tags, Locale locale) {
|
||||||
Optional<Set<io.swagger.v3.oas.models.tags.Tag>> optionalTagSet = AnnotationsUtils
|
Optional<Set<io.swagger.v3.oas.models.tags.Tag>> optionalTagSet = AnnotationsUtils
|
||||||
.getTags(sourceTags.toArray(new io.swagger.v3.oas.annotations.tags.Tag[0]), true);
|
.getTags(sourceTags.toArray(new io.swagger.v3.oas.annotations.tags.Tag[0]), true);
|
||||||
|
|||||||
@@ -28,6 +28,11 @@ import java.util.TimeZone;
|
|||||||
@AutoConfiguration(before = JacksonAutoConfiguration.class)
|
@AutoConfiguration(before = JacksonAutoConfiguration.class)
|
||||||
public class JacksonConfig {
|
public class JacksonConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册 Jackson 序列化与反序列化模块。
|
||||||
|
*
|
||||||
|
* @return Jackson 模块
|
||||||
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public SimpleModule registerJavaTimeModule() {
|
public SimpleModule registerJavaTimeModule() {
|
||||||
// 全局配置序列化返回 JSON 处理
|
// 全局配置序列化返回 JSON 处理
|
||||||
@@ -43,6 +48,11 @@ public class JacksonConfig {
|
|||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化 Jackson 构建器默认配置。
|
||||||
|
*
|
||||||
|
* @return Jackson 构建器自定义器
|
||||||
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public JsonMapperBuilderCustomizer jsonInitCustomizer() {
|
public JsonMapperBuilderCustomizer jsonInitCustomizer() {
|
||||||
return builder -> {
|
return builder -> {
|
||||||
|
|||||||
@@ -24,6 +24,11 @@ public class JsonUtils {
|
|||||||
|
|
||||||
private static final JsonMapper JSON_MAPPER = SpringUtils.getBean(JsonMapper.class);
|
private static final JsonMapper JSON_MAPPER = SpringUtils.getBean(JsonMapper.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取全局 JsonMapper 实例。
|
||||||
|
*
|
||||||
|
* @return JsonMapper
|
||||||
|
*/
|
||||||
public static JsonMapper getJsonMapper() {
|
public static JsonMapper getJsonMapper() {
|
||||||
return JSON_MAPPER;
|
return JSON_MAPPER;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,10 @@ public class LogAspect {
|
|||||||
private static final ThreadLocal<StopWatch> KEY_CACHE = new ThreadLocal<>();
|
private static final ThreadLocal<StopWatch> KEY_CACHE = new ThreadLocal<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理请求前执行
|
* 在目标方法执行前启动耗时统计。
|
||||||
|
*
|
||||||
|
* @param joinPoint 切点
|
||||||
|
* @param controllerLog 日志注解
|
||||||
*/
|
*/
|
||||||
@Before(value = "@annotation(controllerLog)")
|
@Before(value = "@annotation(controllerLog)")
|
||||||
public void doBefore(JoinPoint joinPoint, Log controllerLog) {
|
public void doBefore(JoinPoint joinPoint, Log controllerLog) {
|
||||||
@@ -56,9 +59,11 @@ public class LogAspect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理完请求后执行
|
* 在目标方法正常返回后记录操作日志。
|
||||||
*
|
*
|
||||||
* @param joinPoint 切点
|
* @param joinPoint 切点
|
||||||
|
* @param controllerLog 日志注解
|
||||||
|
* @param jsonResult 返回结果
|
||||||
*/
|
*/
|
||||||
@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
|
@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
|
||||||
public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
|
public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
|
||||||
@@ -66,9 +71,10 @@ public class LogAspect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拦截异常操作
|
* 在目标方法抛出异常后记录操作日志。
|
||||||
*
|
*
|
||||||
* @param joinPoint 切点
|
* @param joinPoint 切点
|
||||||
|
* @param controllerLog 日志注解
|
||||||
* @param e 异常
|
* @param e 异常
|
||||||
*/
|
*/
|
||||||
@AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
|
@AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
|
||||||
@@ -76,6 +82,14 @@ public class LogAspect {
|
|||||||
handleLog(joinPoint, controllerLog, e, null);
|
handleLog(joinPoint, controllerLog, e, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组装并发布操作日志事件。
|
||||||
|
*
|
||||||
|
* @param joinPoint 切点
|
||||||
|
* @param controllerLog 日志注解
|
||||||
|
* @param e 异常信息
|
||||||
|
* @param jsonResult 返回结果
|
||||||
|
*/
|
||||||
protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
|
protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@@ -119,9 +133,11 @@ public class LogAspect {
|
|||||||
/**
|
/**
|
||||||
* 获取注解中对方法的描述信息 用于Controller层注解
|
* 获取注解中对方法的描述信息 用于Controller层注解
|
||||||
*
|
*
|
||||||
|
* @param joinPoint 切点
|
||||||
* @param log 日志
|
* @param log 日志
|
||||||
* @param operLog 操作日志
|
* @param operLog 操作日志
|
||||||
* @throws Exception
|
* @param jsonResult 返回结果
|
||||||
|
* @throws Exception 异常
|
||||||
*/
|
*/
|
||||||
public void getControllerMethodDescription(JoinPoint joinPoint, Log log, OperLogEvent operLog, Object jsonResult) throws Exception {
|
public void getControllerMethodDescription(JoinPoint joinPoint, Log log, OperLogEvent operLog, Object jsonResult) throws Exception {
|
||||||
// 设置action动作
|
// 设置action动作
|
||||||
@@ -144,7 +160,9 @@ public class LogAspect {
|
|||||||
/**
|
/**
|
||||||
* 获取请求的参数,放到log中
|
* 获取请求的参数,放到log中
|
||||||
*
|
*
|
||||||
|
* @param joinPoint 切点
|
||||||
* @param operLog 操作日志
|
* @param operLog 操作日志
|
||||||
|
* @param excludeParamNames 排除参数名
|
||||||
* @throws Exception 异常
|
* @throws Exception 异常
|
||||||
*/
|
*/
|
||||||
private void setRequestValue(JoinPoint joinPoint, OperLogEvent operLog, String[] excludeParamNames) throws Exception {
|
private void setRequestValue(JoinPoint joinPoint, OperLogEvent operLog, String[] excludeParamNames) throws Exception {
|
||||||
@@ -161,7 +179,11 @@ public class LogAspect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 参数拼装
|
* 将方法参数序列化为日志字符串。
|
||||||
|
*
|
||||||
|
* @param paramsArray 参数数组
|
||||||
|
* @param excludeParamNames 排除字段名
|
||||||
|
* @return 参数字符串
|
||||||
*/
|
*/
|
||||||
private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) {
|
private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) {
|
||||||
StringJoiner params = new StringJoiner(" ");
|
StringJoiner params = new StringJoiner(" ");
|
||||||
|
|||||||
@@ -31,7 +31,9 @@ public class MailUtils {
|
|||||||
private static final MailAccount ACCOUNT = SpringUtils.getBean(MailAccount.class);
|
private static final MailAccount ACCOUNT = SpringUtils.getBean(MailAccount.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取邮件发送实例
|
* 获取默认邮件账户配置。
|
||||||
|
*
|
||||||
|
* @return 邮件账户配置
|
||||||
*/
|
*/
|
||||||
public static MailAccount getMailAccount() {
|
public static MailAccount getMailAccount() {
|
||||||
return ACCOUNT;
|
return ACCOUNT;
|
||||||
@@ -40,8 +42,10 @@ public class MailUtils {
|
|||||||
/**
|
/**
|
||||||
* 获取邮件发送实例 (自定义发送人以及授权码)
|
* 获取邮件发送实例 (自定义发送人以及授权码)
|
||||||
*
|
*
|
||||||
|
* @param from 发送人
|
||||||
* @param user 发送人
|
* @param user 发送人
|
||||||
* @param pass 授权码
|
* @param pass 授权码
|
||||||
|
* @return 邮件账户配置
|
||||||
*/
|
*/
|
||||||
public static MailAccount getMailAccount(String from, String user, String pass) {
|
public static MailAccount getMailAccount(String from, String user, String pass) {
|
||||||
ACCOUNT.setFrom(StringUtils.blankToDefault(from, ACCOUNT.getFrom()));
|
ACCOUNT.setFrom(StringUtils.blankToDefault(from, ACCOUNT.getFrom()));
|
||||||
|
|||||||
@@ -21,7 +21,11 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
|
|||||||
public class MybatisExceptionHandler {
|
public class MybatisExceptionHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 主键或UNIQUE索引,数据重复异常
|
* 处理主键或唯一索引冲突异常。
|
||||||
|
*
|
||||||
|
* @param e 异常信息
|
||||||
|
* @param request 当前请求
|
||||||
|
* @return 统一失败响应
|
||||||
*/
|
*/
|
||||||
@ExceptionHandler(DuplicateKeyException.class)
|
@ExceptionHandler(DuplicateKeyException.class)
|
||||||
public R<Void> handleDuplicateKeyException(DuplicateKeyException e, HttpServletRequest request) {
|
public R<Void> handleDuplicateKeyException(DuplicateKeyException e, HttpServletRequest request) {
|
||||||
@@ -31,7 +35,11 @@ public class MybatisExceptionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mybatis系统异常 通用处理
|
* 处理 MyBatis 系统异常。
|
||||||
|
*
|
||||||
|
* @param e 异常信息
|
||||||
|
* @param request 当前请求
|
||||||
|
* @return 统一失败响应
|
||||||
*/
|
*/
|
||||||
@ExceptionHandler(MyBatisSystemException.class)
|
@ExceptionHandler(MyBatisSystemException.class)
|
||||||
public R<Void> handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) {
|
public R<Void> handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) {
|
||||||
|
|||||||
@@ -74,7 +74,9 @@ public class DataBaseHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前加载的数据库名
|
* 获取当前注册的数据源名称列表。
|
||||||
|
*
|
||||||
|
* @return 数据源名称列表
|
||||||
*/
|
*/
|
||||||
public static List<String> getDataSourceNameList() {
|
public static List<String> getDataSourceNameList() {
|
||||||
return new ArrayList<>(DS.getDataSources().keySet());
|
return new ArrayList<>(DS.getDataSources().keySet());
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public class DataPermissionHelper {
|
|||||||
/**
|
/**
|
||||||
* 设置当前执行mapper权限注解
|
* 设置当前执行mapper权限注解
|
||||||
*
|
*
|
||||||
* @param dataPermission 数据权限注解
|
* @param dataPermission 数据权限注解
|
||||||
*/
|
*/
|
||||||
public static void setPermission(DataPermission dataPermission) {
|
public static void setPermission(DataPermission dataPermission) {
|
||||||
PERMISSION_CACHE.set(dataPermission);
|
PERMISSION_CACHE.set(dataPermission);
|
||||||
@@ -82,10 +82,20 @@ public class DataPermissionHelper {
|
|||||||
context.put(key, value);
|
context.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前数据权限访问控制对象。
|
||||||
|
*
|
||||||
|
* @return 访问控制对象
|
||||||
|
*/
|
||||||
public static DataPermissionAccess getAccess() {
|
public static DataPermissionAccess getAccess() {
|
||||||
return getVariable(ACCESS_KEY);
|
return getVariable(ACCESS_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前数据权限访问控制对象。
|
||||||
|
*
|
||||||
|
* @param access 访问控制对象
|
||||||
|
*/
|
||||||
public static void setAccess(DataPermissionAccess access) {
|
public static void setAccess(DataPermissionAccess access) {
|
||||||
setVariable(ACCESS_KEY, access);
|
setVariable(ACCESS_KEY, access);
|
||||||
}
|
}
|
||||||
@@ -109,6 +119,11 @@ public class DataPermissionHelper {
|
|||||||
throw new NullPointerException("data permission context type exception");
|
throw new NullPointerException("data permission context type exception");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前忽略策略。
|
||||||
|
*
|
||||||
|
* @return 忽略策略
|
||||||
|
*/
|
||||||
private static IgnoreStrategy getIgnoreStrategy() {
|
private static IgnoreStrategy getIgnoreStrategy() {
|
||||||
Object ignoreStrategyLocal = ReflectUtils.getStaticFieldValue(ReflectUtils.getField(InterceptorIgnoreHelper.class, "IGNORE_STRATEGY_LOCAL"));
|
Object ignoreStrategyLocal = ReflectUtils.getStaticFieldValue(ReflectUtils.getField(InterceptorIgnoreHelper.class, "IGNORE_STRATEGY_LOCAL"));
|
||||||
if (ignoreStrategyLocal instanceof ThreadLocal<?> IGNORE_STRATEGY_LOCAL) {
|
if (ignoreStrategyLocal instanceof ThreadLocal<?> IGNORE_STRATEGY_LOCAL) {
|
||||||
@@ -173,6 +188,7 @@ public class DataPermissionHelper {
|
|||||||
* 在忽略数据权限中执行
|
* 在忽略数据权限中执行
|
||||||
*
|
*
|
||||||
* @param handle 处理执行方法
|
* @param handle 处理执行方法
|
||||||
|
* @return 执行结果
|
||||||
*/
|
*/
|
||||||
public static <T> T ignore(Supplier<T> handle) {
|
public static <T> T ignore(Supplier<T> handle) {
|
||||||
enableIgnore();
|
enableIgnore();
|
||||||
|
|||||||
@@ -547,6 +547,9 @@ public class OssClient {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查配置是否相同
|
* 检查配置是否相同
|
||||||
|
*
|
||||||
|
* @param properties OSS 配置
|
||||||
|
* @return 是否与当前客户端配置一致
|
||||||
*/
|
*/
|
||||||
public boolean checkPropertiesSame(OssProperties properties) {
|
public boolean checkPropertiesSame(OssProperties properties) {
|
||||||
return this.properties.equals(properties);
|
return this.properties.equals(properties);
|
||||||
|
|||||||
@@ -10,6 +10,12 @@ import java.io.IOException;
|
|||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface WriteOutSubscriber<T> {
|
public interface WriteOutSubscriber<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将订阅到的数据写出到目标对象。
|
||||||
|
*
|
||||||
|
* @param out 写出目标
|
||||||
|
* @throws IOException 写出异常
|
||||||
|
*/
|
||||||
void writeTo(T out) throws IOException;
|
void writeTo(T out) throws IOException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,11 @@ public class OssException extends RuntimeException {
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建 OSS 业务异常。
|
||||||
|
*
|
||||||
|
* @param msg 异常消息
|
||||||
|
*/
|
||||||
public OssException(String msg) {
|
public OssException(String msg) {
|
||||||
super(msg);
|
super(msg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ public class OssFactory {
|
|||||||
private static final ReentrantLock LOCK = new ReentrantLock();
|
private static final ReentrantLock LOCK = new ReentrantLock();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取默认实例
|
* 获取默认 OSS 客户端实例。
|
||||||
|
*
|
||||||
|
* @return 默认 OSS 客户端
|
||||||
*/
|
*/
|
||||||
public static OssClient instance() {
|
public static OssClient instance() {
|
||||||
// 获取redis 默认类型
|
// 获取redis 默认类型
|
||||||
@@ -39,7 +41,10 @@ public class OssFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据类型获取实例
|
* 根据配置键获取 OSS 客户端实例。
|
||||||
|
*
|
||||||
|
* @param configKey 配置键
|
||||||
|
* @return OSS 客户端
|
||||||
*/
|
*/
|
||||||
public static OssClient instance(String configKey) {
|
public static OssClient instance(String configKey) {
|
||||||
String json = CacheUtils.get(CacheNames.SYS_OSS_CONFIG, configKey);
|
String json = CacheUtils.get(CacheNames.SYS_OSS_CONFIG, configKey);
|
||||||
|
|||||||
@@ -14,13 +14,21 @@ public class KeyPrefixHandler implements NameMapper {
|
|||||||
|
|
||||||
private final String keyPrefix;
|
private final String keyPrefix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建 Redis Key 前缀处理器。
|
||||||
|
*
|
||||||
|
* @param keyPrefix Key 前缀
|
||||||
|
*/
|
||||||
public KeyPrefixHandler(String keyPrefix) {
|
public KeyPrefixHandler(String keyPrefix) {
|
||||||
//前缀为空 则返回空前缀
|
//前缀为空 则返回空前缀
|
||||||
this.keyPrefix = StringUtils.isBlank(keyPrefix) ? "" : keyPrefix + ":";
|
this.keyPrefix = StringUtils.isBlank(keyPrefix) ? "" : keyPrefix + ":";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 增加前缀
|
* 为原始 Key 增加前缀。
|
||||||
|
*
|
||||||
|
* @param name 原始 Key
|
||||||
|
* @return 带前缀的 Key
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String map(String name) {
|
public String map(String name) {
|
||||||
@@ -34,7 +42,10 @@ public class KeyPrefixHandler implements NameMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 去除前缀
|
* 去除 Key 前缀。
|
||||||
|
*
|
||||||
|
* @param name 带前缀的 Key
|
||||||
|
* @return 原始 Key
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String unmap(String name) {
|
public String unmap(String name) {
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
|
|||||||
public class RedisExceptionHandler {
|
public class RedisExceptionHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分布式锁Lock4j异常
|
* 处理 Lock4j 分布式锁获取失败异常。
|
||||||
|
*
|
||||||
|
* @param e 异常信息
|
||||||
|
* @param request 当前请求
|
||||||
|
* @return 统一失败响应
|
||||||
*/
|
*/
|
||||||
@ExceptionHandler(LockFailureException.class)
|
@ExceptionHandler(LockFailureException.class)
|
||||||
public R<Void> handleLockFailureException(LockFailureException e, HttpServletRequest request) {
|
public R<Void> handleLockFailureException(LockFailureException e, HttpServletRequest request) {
|
||||||
|
|||||||
@@ -18,31 +18,66 @@ public class CaffeineCacheDecorator implements Cache {
|
|||||||
private final String name;
|
private final String name;
|
||||||
private final Cache cache;
|
private final Cache cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建带 Caffeine 一级缓存的缓存装饰器。
|
||||||
|
*
|
||||||
|
* @param name 缓存名称
|
||||||
|
* @param cache 被装饰的缓存实例
|
||||||
|
*/
|
||||||
public CaffeineCacheDecorator(String name, Cache cache) {
|
public CaffeineCacheDecorator(String name, Cache cache) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.cache = cache;
|
this.cache = cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存名称。
|
||||||
|
*
|
||||||
|
* @return 缓存名称
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取底层原生缓存对象。
|
||||||
|
*
|
||||||
|
* @return 原生缓存对象
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object getNativeCache() {
|
public Object getNativeCache() {
|
||||||
return cache.getNativeCache();
|
return cache.getNativeCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造 Caffeine 一级缓存使用的唯一键。
|
||||||
|
*
|
||||||
|
* @param key 缓存键
|
||||||
|
* @return 唯一键
|
||||||
|
*/
|
||||||
public String getUniqueKey(Object key) {
|
public String getUniqueKey(Object key) {
|
||||||
return name + ":" + key;
|
return name + ":" + key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存值。
|
||||||
|
*
|
||||||
|
* @param key 缓存键
|
||||||
|
* @return 缓存值包装对象
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ValueWrapper get(Object key) {
|
public ValueWrapper get(Object key) {
|
||||||
Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key));
|
Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key));
|
||||||
return (ValueWrapper) o;
|
return (ValueWrapper) o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按指定类型获取缓存值。
|
||||||
|
*
|
||||||
|
* @param key 缓存键
|
||||||
|
* @param type 值类型
|
||||||
|
* @return 缓存值
|
||||||
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public <T> T get(Object key, Class<T> type) {
|
public <T> T get(Object key, Class<T> type) {
|
||||||
@@ -50,23 +85,47 @@ public class CaffeineCacheDecorator implements Cache {
|
|||||||
return (T) o;
|
return (T) o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入缓存值,并清理本地一级缓存。
|
||||||
|
*
|
||||||
|
* @param key 缓存键
|
||||||
|
* @param value 缓存值
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void put(Object key, Object value) {
|
public void put(Object key, Object value) {
|
||||||
CAFFEINE.invalidate(getUniqueKey(key));
|
CAFFEINE.invalidate(getUniqueKey(key));
|
||||||
cache.put(key, value);
|
cache.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当键不存在时写入缓存值。
|
||||||
|
*
|
||||||
|
* @param key 缓存键
|
||||||
|
* @param value 缓存值
|
||||||
|
* @return 原缓存值包装对象
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ValueWrapper putIfAbsent(Object key, Object value) {
|
public ValueWrapper putIfAbsent(Object key, Object value) {
|
||||||
CAFFEINE.invalidate(getUniqueKey(key));
|
CAFFEINE.invalidate(getUniqueKey(key));
|
||||||
return cache.putIfAbsent(key, value);
|
return cache.putIfAbsent(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除缓存值。
|
||||||
|
*
|
||||||
|
* @param key 缓存键
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void evict(Object key) {
|
public void evict(Object key) {
|
||||||
evictIfPresent(key);
|
evictIfPresent(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除缓存值并返回是否删除成功。
|
||||||
|
*
|
||||||
|
* @param key 缓存键
|
||||||
|
* @return 是否删除成功
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean evictIfPresent(Object key) {
|
public boolean evictIfPresent(Object key) {
|
||||||
boolean b = cache.evictIfPresent(key);
|
boolean b = cache.evictIfPresent(key);
|
||||||
@@ -76,17 +135,32 @@ public class CaffeineCacheDecorator implements Cache {
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空缓存。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
CAFFEINE.invalidateAll();
|
CAFFEINE.invalidateAll();
|
||||||
cache.clear();
|
cache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使缓存整体失效。
|
||||||
|
*
|
||||||
|
* @return 是否失效成功
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean invalidate() {
|
public boolean invalidate() {
|
||||||
return cache.invalidate();
|
return cache.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存值,不存在时通过回调加载。
|
||||||
|
*
|
||||||
|
* @param key 缓存键
|
||||||
|
* @param valueLoader 回调加载器
|
||||||
|
* @return 缓存值
|
||||||
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public <T> T get(Object key, Callable<T> valueLoader) {
|
public <T> T get(Object key, Callable<T> valueLoader) {
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public class PlusSpringCacheManager implements CacheManager {
|
|||||||
ConcurrentMap<String, Cache> instanceMap = new ConcurrentHashMap<>();
|
ConcurrentMap<String, Cache> instanceMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates CacheManager supplied by Redisson instance
|
* 创建基于 Redisson 的缓存管理器。
|
||||||
*/
|
*/
|
||||||
public PlusSpringCacheManager() {
|
public PlusSpringCacheManager() {
|
||||||
}
|
}
|
||||||
@@ -113,10 +113,21 @@ public class PlusSpringCacheManager implements CacheManager {
|
|||||||
this.configMap = (Map<String, CacheConfig>) config;
|
this.configMap = (Map<String, CacheConfig>) config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建默认缓存配置。
|
||||||
|
*
|
||||||
|
* @return 默认缓存配置
|
||||||
|
*/
|
||||||
protected CacheConfig createDefaultConfig() {
|
protected CacheConfig createDefaultConfig() {
|
||||||
return new CacheConfig();
|
return new CacheConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按缓存名称获取缓存实例,并支持通过扩展参数动态设置 TTL、最大空闲时间和容量。
|
||||||
|
*
|
||||||
|
* @param name 缓存名称,支持 `cacheName#ttl#maxIdle#maxSize#local` 格式
|
||||||
|
* @return 缓存实例
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Cache getCache(String name) {
|
public Cache getCache(String name) {
|
||||||
// 重写 cacheName 支持多参数
|
// 重写 cacheName 支持多参数
|
||||||
@@ -158,6 +169,14 @@ public class PlusSpringCacheManager implements CacheManager {
|
|||||||
return createMapCache(name, config, local);
|
return createMapCache(name, config, local);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建普通 Map 类型缓存。
|
||||||
|
*
|
||||||
|
* @param name 缓存名称
|
||||||
|
* @param config 缓存配置
|
||||||
|
* @param local 是否启用本地一级缓存
|
||||||
|
* @return 缓存实例
|
||||||
|
*/
|
||||||
private Cache createMap(String name, CacheConfig config, int local) {
|
private Cache createMap(String name, CacheConfig config, int local) {
|
||||||
RMap<Object, Object> map = RedisUtils.getClient().getMap(name);
|
RMap<Object, Object> map = RedisUtils.getClient().getMap(name);
|
||||||
|
|
||||||
@@ -175,6 +194,14 @@ public class PlusSpringCacheManager implements CacheManager {
|
|||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建带过期策略的 MapCache 类型缓存。
|
||||||
|
*
|
||||||
|
* @param name 缓存名称
|
||||||
|
* @param config 缓存配置
|
||||||
|
* @param local 是否启用本地一级缓存
|
||||||
|
* @return 缓存实例
|
||||||
|
*/
|
||||||
private Cache createMapCache(String name, CacheConfig config, int local) {
|
private Cache createMapCache(String name, CacheConfig config, int local) {
|
||||||
RMapCache<Object, Object> map = RedisUtils.getClient().getMapCache(name);
|
RMapCache<Object, Object> map = RedisUtils.getClient().getMapCache(name);
|
||||||
|
|
||||||
@@ -197,6 +224,11 @@ public class PlusSpringCacheManager implements CacheManager {
|
|||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前缓存名称集合。
|
||||||
|
*
|
||||||
|
* @return 缓存名称集合
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Collection<String> getCacheNames() {
|
public Collection<String> getCacheNames() {
|
||||||
return Collections.unmodifiableSet(configMap.keySet());
|
return Collections.unmodifiableSet(configMap.keySet());
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ public class CacheUtils {
|
|||||||
*
|
*
|
||||||
* @param cacheNames 缓存组名称
|
* @param cacheNames 缓存组名称
|
||||||
* @param key 缓存key
|
* @param key 缓存key
|
||||||
|
* @return 缓存值
|
||||||
*/
|
*/
|
||||||
public static <T> T get(String cacheNames, Object key) {
|
public static <T> T get(String cacheNames, Object key) {
|
||||||
Cache.ValueWrapper wrapper = CACHE_MANAGER.getCache(cacheNames).get(key);
|
Cache.ValueWrapper wrapper = CACHE_MANAGER.getCache(cacheNames).get(key);
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ public class QueueUtils {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取客户端实例
|
* 获取 Redisson 客户端实例。
|
||||||
|
*
|
||||||
|
* @return Redisson 客户端
|
||||||
*/
|
*/
|
||||||
public static RedissonClient getClient() {
|
public static RedissonClient getClient() {
|
||||||
return CLIENT;
|
return CLIENT;
|
||||||
@@ -36,6 +38,7 @@ public class QueueUtils {
|
|||||||
*
|
*
|
||||||
* @param queueName 队列名
|
* @param queueName 队列名
|
||||||
* @param data 数据
|
* @param data 数据
|
||||||
|
* @return 是否添加成功
|
||||||
*/
|
*/
|
||||||
public static <T> boolean addQueueObject(String queueName, T data) {
|
public static <T> boolean addQueueObject(String queueName, T data) {
|
||||||
RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
|
RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
|
||||||
@@ -46,6 +49,7 @@ public class QueueUtils {
|
|||||||
* 通用获取一个队列数据 没有数据返回 null(不支持延迟队列)
|
* 通用获取一个队列数据 没有数据返回 null(不支持延迟队列)
|
||||||
*
|
*
|
||||||
* @param queueName 队列名
|
* @param queueName 队列名
|
||||||
|
* @return 队列数据
|
||||||
*/
|
*/
|
||||||
public static <T> T getQueueObject(String queueName) {
|
public static <T> T getQueueObject(String queueName) {
|
||||||
RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
|
RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
|
||||||
@@ -53,7 +57,11 @@ public class QueueUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通用删除队列数据(不支持延迟队列)
|
* 删除普通队列中的指定数据。
|
||||||
|
*
|
||||||
|
* @param queueName 队列名
|
||||||
|
* @param data 数据
|
||||||
|
* @return 是否删除成功
|
||||||
*/
|
*/
|
||||||
public static <T> boolean removeQueueObject(String queueName, T data) {
|
public static <T> boolean removeQueueObject(String queueName, T data) {
|
||||||
RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
|
RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
|
||||||
@@ -61,7 +69,10 @@ public class QueueUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通用销毁队列 所有阻塞监听 报错(不支持延迟队列)
|
* 销毁普通队列。
|
||||||
|
*
|
||||||
|
* @param queueName 队列名
|
||||||
|
* @return 是否销毁成功
|
||||||
*/
|
*/
|
||||||
public static <T> boolean destroyQueue(String queueName) {
|
public static <T> boolean destroyQueue(String queueName) {
|
||||||
RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
|
RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
|
||||||
@@ -73,6 +84,7 @@ public class QueueUtils {
|
|||||||
*
|
*
|
||||||
* @param queueName 队列名
|
* @param queueName 队列名
|
||||||
* @param data 数据
|
* @param data 数据
|
||||||
|
* @return 是否添加成功
|
||||||
*/
|
*/
|
||||||
public static <T> boolean addPriorityQueueObject(String queueName, T data) {
|
public static <T> boolean addPriorityQueueObject(String queueName, T data) {
|
||||||
RPriorityBlockingQueue<T> priorityBlockingQueue = CLIENT.getPriorityBlockingQueue(queueName);
|
RPriorityBlockingQueue<T> priorityBlockingQueue = CLIENT.getPriorityBlockingQueue(queueName);
|
||||||
@@ -83,6 +95,7 @@ public class QueueUtils {
|
|||||||
* 优先队列获取一个队列数据 没有数据返回 null(不支持延迟队列)
|
* 优先队列获取一个队列数据 没有数据返回 null(不支持延迟队列)
|
||||||
*
|
*
|
||||||
* @param queueName 队列名
|
* @param queueName 队列名
|
||||||
|
* @return 队列数据
|
||||||
*/
|
*/
|
||||||
public static <T> T getPriorityQueueObject(String queueName) {
|
public static <T> T getPriorityQueueObject(String queueName) {
|
||||||
RPriorityBlockingQueue<T> queue = CLIENT.getPriorityBlockingQueue(queueName);
|
RPriorityBlockingQueue<T> queue = CLIENT.getPriorityBlockingQueue(queueName);
|
||||||
@@ -90,7 +103,11 @@ public class QueueUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 优先队列删除队列数据(不支持延迟队列)
|
* 删除优先队列中的指定数据。
|
||||||
|
*
|
||||||
|
* @param queueName 队列名
|
||||||
|
* @param data 数据
|
||||||
|
* @return 是否删除成功
|
||||||
*/
|
*/
|
||||||
public static <T> boolean removePriorityQueueObject(String queueName, T data) {
|
public static <T> boolean removePriorityQueueObject(String queueName, T data) {
|
||||||
RPriorityBlockingQueue<T> queue = CLIENT.getPriorityBlockingQueue(queueName);
|
RPriorityBlockingQueue<T> queue = CLIENT.getPriorityBlockingQueue(queueName);
|
||||||
@@ -98,7 +115,10 @@ public class QueueUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 优先队列销毁队列 所有阻塞监听 报错(不支持延迟队列)
|
* 销毁优先队列。
|
||||||
|
*
|
||||||
|
* @param queueName 队列名
|
||||||
|
* @return 是否销毁成功
|
||||||
*/
|
*/
|
||||||
public static <T> boolean destroyPriorityQueue(String queueName) {
|
public static <T> boolean destroyPriorityQueue(String queueName) {
|
||||||
RPriorityBlockingQueue<T> queue = CLIENT.getPriorityBlockingQueue(queueName);
|
RPriorityBlockingQueue<T> queue = CLIENT.getPriorityBlockingQueue(queueName);
|
||||||
@@ -106,7 +126,10 @@ public class QueueUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 订阅阻塞队列(可订阅所有实现类)
|
* 订阅阻塞队列元素。
|
||||||
|
*
|
||||||
|
* @param queueName 队列名
|
||||||
|
* @param consumer 消费逻辑
|
||||||
*/
|
*/
|
||||||
public static <T> void subscribeBlockingQueue(String queueName, Function<T, CompletionStage<Void>> consumer) {
|
public static <T> void subscribeBlockingQueue(String queueName, Function<T, CompletionStage<Void>> consumer) {
|
||||||
RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
|
RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
|
||||||
|
|||||||
@@ -546,6 +546,7 @@ public class RedisUtils {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过扫描参数获取缓存的基本对象列表
|
* 通过扫描参数获取缓存的基本对象列表
|
||||||
|
*
|
||||||
* @param keysScanOptions 扫描参数
|
* @param keysScanOptions 扫描参数
|
||||||
* <P>
|
* <P>
|
||||||
* limit-设置扫描的限制数量(默认为0,查询全部)
|
* limit-设置扫描的限制数量(默认为0,查询全部)
|
||||||
@@ -554,6 +555,7 @@ public class RedisUtils {
|
|||||||
* type-设置键的类型(默认为null,查询全部类型)
|
* type-设置键的类型(默认为null,查询全部类型)
|
||||||
* </P>
|
* </P>
|
||||||
* @see KeysScanOptions
|
* @see KeysScanOptions
|
||||||
|
* @return 对象列表
|
||||||
*/
|
*/
|
||||||
public static Collection<String> keys(final KeysScanOptions keysScanOptions) {
|
public static Collection<String> keys(final KeysScanOptions keysScanOptions) {
|
||||||
Stream<String> keysStream = CLIENT.getKeys().getKeysStream(keysScanOptions);
|
Stream<String> keysStream = CLIENT.getKeys().getKeysStream(keysScanOptions);
|
||||||
@@ -573,6 +575,7 @@ public class RedisUtils {
|
|||||||
* 检查redis中是否存在key
|
* 检查redis中是否存在key
|
||||||
*
|
*
|
||||||
* @param key 键
|
* @param key 键
|
||||||
|
* @return 是否存在
|
||||||
*/
|
*/
|
||||||
public static Boolean hasKey(String key) {
|
public static Boolean hasKey(String key) {
|
||||||
RKeys rKeys = CLIENT.getKeys();
|
RKeys rKeys = CLIENT.getKeys();
|
||||||
|
|||||||
@@ -22,7 +22,11 @@ import java.util.List;
|
|||||||
public class SaPermissionImpl implements StpInterface {
|
public class SaPermissionImpl implements StpInterface {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取菜单权限列表
|
* 获取指定登录对象的菜单权限列表。
|
||||||
|
*
|
||||||
|
* @param loginId 登录ID
|
||||||
|
* @param loginType 登录类型
|
||||||
|
* @return 菜单权限列表
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<String> getPermissionList(Object loginId, String loginType) {
|
public List<String> getPermissionList(Object loginId, String loginType) {
|
||||||
@@ -49,7 +53,11 @@ public class SaPermissionImpl implements StpInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取角色权限列表
|
* 获取指定登录对象的角色权限列表。
|
||||||
|
*
|
||||||
|
* @param loginId 登录ID
|
||||||
|
* @param loginType 登录类型
|
||||||
|
* @return 角色权限列表
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<String> getRoleList(Object loginId, String loginType) {
|
public List<String> getRoleList(Object loginId, String loginType) {
|
||||||
@@ -75,6 +83,11 @@ public class SaPermissionImpl implements StpInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取权限服务实现。
|
||||||
|
*
|
||||||
|
* @return 权限服务
|
||||||
|
*/
|
||||||
private PermissionService getPermissionService() {
|
private PermissionService getPermissionService() {
|
||||||
try {
|
try {
|
||||||
return SpringUtils.getBean(PermissionService.class);
|
return SpringUtils.getBean(PermissionService.class);
|
||||||
|
|||||||
@@ -20,7 +20,11 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
|
|||||||
public class SaTokenExceptionHandler {
|
public class SaTokenExceptionHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 权限码异常
|
* 处理权限码校验失败异常。
|
||||||
|
*
|
||||||
|
* @param e 异常信息
|
||||||
|
* @param request 当前请求
|
||||||
|
* @return 统一失败响应
|
||||||
*/
|
*/
|
||||||
@ExceptionHandler(NotPermissionException.class)
|
@ExceptionHandler(NotPermissionException.class)
|
||||||
public R<Void> handleNotPermissionException(NotPermissionException e, HttpServletRequest request) {
|
public R<Void> handleNotPermissionException(NotPermissionException e, HttpServletRequest request) {
|
||||||
@@ -30,7 +34,11 @@ public class SaTokenExceptionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 角色权限异常
|
* 处理角色权限校验失败异常。
|
||||||
|
*
|
||||||
|
* @param e 异常信息
|
||||||
|
* @param request 当前请求
|
||||||
|
* @return 统一失败响应
|
||||||
*/
|
*/
|
||||||
@ExceptionHandler(NotRoleException.class)
|
@ExceptionHandler(NotRoleException.class)
|
||||||
public R<Void> handleNotRoleException(NotRoleException e, HttpServletRequest request) {
|
public R<Void> handleNotRoleException(NotRoleException e, HttpServletRequest request) {
|
||||||
@@ -40,7 +48,11 @@ public class SaTokenExceptionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 认证失败
|
* 处理未登录或登录态失效异常。
|
||||||
|
*
|
||||||
|
* @param e 异常信息
|
||||||
|
* @param request 当前请求
|
||||||
|
* @return 统一失败响应
|
||||||
*/
|
*/
|
||||||
@ExceptionHandler(NotLoginException.class)
|
@ExceptionHandler(NotLoginException.class)
|
||||||
public R<Void> handleNotLoginException(NotLoginException e, HttpServletRequest request) {
|
public R<Void> handleNotLoginException(NotLoginException e, HttpServletRequest request) {
|
||||||
|
|||||||
@@ -55,7 +55,9 @@ public class LoginHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户(多级缓存)
|
* 获取当前 Token 对应的登录用户信息。
|
||||||
|
*
|
||||||
|
* @return 登录用户
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T extends LoginUser> T getLoginUser() {
|
public static <T extends LoginUser> T getLoginUser() {
|
||||||
@@ -67,7 +69,10 @@ public class LoginHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户基于token
|
* 根据指定 Token 获取登录用户信息。
|
||||||
|
*
|
||||||
|
* @param token Token
|
||||||
|
* @return 登录用户
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T extends LoginUser> T getLoginUser(String token) {
|
public static <T extends LoginUser> T getLoginUser(String token) {
|
||||||
@@ -79,42 +84,54 @@ public class LoginHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户id
|
* 获取当前登录用户 ID。
|
||||||
|
*
|
||||||
|
* @return 用户 ID
|
||||||
*/
|
*/
|
||||||
public static Long getUserId() {
|
public static Long getUserId() {
|
||||||
return Convert.toLong(getExtra(USER_KEY));
|
return Convert.toLong(getExtra(USER_KEY));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户id
|
* 获取当前登录用户 ID 字符串。
|
||||||
|
*
|
||||||
|
* @return 用户 ID 字符串
|
||||||
*/
|
*/
|
||||||
public static String getUserIdStr() {
|
public static String getUserIdStr() {
|
||||||
return Convert.toStr(getExtra(USER_KEY));
|
return Convert.toStr(getExtra(USER_KEY));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户账户
|
* 获取当前登录用户名。
|
||||||
|
*
|
||||||
|
* @return 用户名
|
||||||
*/
|
*/
|
||||||
public static String getUsername() {
|
public static String getUsername() {
|
||||||
return Convert.toStr(getExtra(USER_NAME_KEY));
|
return Convert.toStr(getExtra(USER_NAME_KEY));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取部门ID
|
* 获取当前登录用户部门 ID。
|
||||||
|
*
|
||||||
|
* @return 部门 ID
|
||||||
*/
|
*/
|
||||||
public static Long getDeptId() {
|
public static Long getDeptId() {
|
||||||
return Convert.toLong(getExtra(DEPT_KEY));
|
return Convert.toLong(getExtra(DEPT_KEY));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取部门名
|
* 获取当前登录用户部门名称。
|
||||||
|
*
|
||||||
|
* @return 部门名称
|
||||||
*/
|
*/
|
||||||
public static String getDeptName() {
|
public static String getDeptName() {
|
||||||
return Convert.toStr(getExtra(DEPT_NAME_KEY));
|
return Convert.toStr(getExtra(DEPT_NAME_KEY));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取部门类别编码
|
* 获取当前登录用户部门类别编码。
|
||||||
|
*
|
||||||
|
* @return 部门类别编码
|
||||||
*/
|
*/
|
||||||
public static String getDeptCategory() {
|
public static String getDeptCategory() {
|
||||||
return Convert.toStr(getExtra(DEPT_CATEGORY_KEY));
|
return Convert.toStr(getExtra(DEPT_CATEGORY_KEY));
|
||||||
@@ -135,7 +152,9 @@ public class LoginHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户类型
|
* 获取当前登录用户类型。
|
||||||
|
*
|
||||||
|
* @return 用户类型
|
||||||
*/
|
*/
|
||||||
public static UserType getUserType() {
|
public static UserType getUserType() {
|
||||||
String loginType = StpUtil.getLoginIdAsString();
|
String loginType = StpUtil.getLoginIdAsString();
|
||||||
@@ -146,7 +165,7 @@ public class LoginHelper {
|
|||||||
* 是否为超级管理员
|
* 是否为超级管理员
|
||||||
*
|
*
|
||||||
* @param userId 用户ID
|
* @param userId 用户ID
|
||||||
* @return 结果
|
* @return 是否为超级管理员
|
||||||
*/
|
*/
|
||||||
public static boolean isSuperAdmin(Long userId) {
|
public static boolean isSuperAdmin(Long userId) {
|
||||||
return SystemConstants.SUPER_ADMIN_ID.equals(userId);
|
return SystemConstants.SUPER_ADMIN_ID.equals(userId);
|
||||||
@@ -155,7 +174,7 @@ public class LoginHelper {
|
|||||||
/**
|
/**
|
||||||
* 是否为超级管理员
|
* 是否为超级管理员
|
||||||
*
|
*
|
||||||
* @return 结果
|
* @return 是否为超级管理员
|
||||||
*/
|
*/
|
||||||
public static boolean isSuperAdmin() {
|
public static boolean isSuperAdmin() {
|
||||||
return isSuperAdmin(getUserId());
|
return isSuperAdmin(getUserId());
|
||||||
@@ -164,7 +183,7 @@ public class LoginHelper {
|
|||||||
/**
|
/**
|
||||||
* 检查当前用户是否已登录
|
* 检查当前用户是否已登录
|
||||||
*
|
*
|
||||||
* @return 结果
|
* @return 是否已登录
|
||||||
*/
|
*/
|
||||||
public static boolean isLogin() {
|
public static boolean isLogin() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ public class SecurityConfig implements WebMvcConfigurer {
|
|||||||
private String ssePath;
|
private String ssePath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注册sa-token的拦截器
|
* 注册 Sa-Token 路由拦截器并配置鉴权规则。
|
||||||
|
*
|
||||||
|
* @param registry 拦截器注册器
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
@@ -87,7 +89,9 @@ public class SecurityConfig implements WebMvcConfigurer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对 actuator 健康检查接口 做账号密码鉴权
|
* 为 actuator 健康检查接口配置 Basic Auth 鉴权过滤器。
|
||||||
|
*
|
||||||
|
* @return Sa-Token Servlet 过滤器
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public SaServletFilter getSaServletFilter() {
|
public SaServletFilter getSaServletFilter() {
|
||||||
|
|||||||
@@ -16,6 +16,4 @@ public class SecurityProperties {
|
|||||||
* 排除路径
|
* 排除路径
|
||||||
*/
|
*/
|
||||||
private String[] excludes;
|
private String[] excludes;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ public class AllUrlHandler implements InitializingBean {
|
|||||||
|
|
||||||
private List<String> urls = new ArrayList<>();
|
private List<String> urls = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化并收集系统中的全部请求路径。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() {
|
public void afterPropertiesSet() {
|
||||||
Set<String> set = new HashSet<>();
|
Set<String> set = new HashSet<>();
|
||||||
|
|||||||
@@ -9,12 +9,18 @@ import org.springframework.context.annotation.Bean;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Social 配置属性
|
* Social 配置属性
|
||||||
|
*
|
||||||
* @author thiszhc
|
* @author thiszhc
|
||||||
*/
|
*/
|
||||||
@AutoConfiguration
|
@AutoConfiguration
|
||||||
@EnableConfigurationProperties(SocialProperties.class)
|
@EnableConfigurationProperties(SocialProperties.class)
|
||||||
public class SocialAutoConfiguration {
|
public class SocialAutoConfiguration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册第三方授权状态缓存实现。
|
||||||
|
*
|
||||||
|
* @return 授权状态缓存
|
||||||
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public AuthStateCache authStateCache() {
|
public AuthStateCache authStateCache() {
|
||||||
return new AuthRedisStateCache();
|
return new AuthRedisStateCache();
|
||||||
|
|||||||
@@ -23,6 +23,16 @@ public class SocialUtils {
|
|||||||
|
|
||||||
private static final AuthRedisStateCache STATE_CACHE = SpringUtils.getBean(AuthRedisStateCache.class);
|
private static final AuthRedisStateCache STATE_CACHE = SpringUtils.getBean(AuthRedisStateCache.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行第三方登录授权回调。
|
||||||
|
*
|
||||||
|
* @param source 社交平台类型
|
||||||
|
* @param code 授权码
|
||||||
|
* @param state 状态值
|
||||||
|
* @param socialProperties 社交平台配置
|
||||||
|
* @return 授权响应
|
||||||
|
* @throws AuthException 授权异常
|
||||||
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static AuthResponse<AuthUser> loginAuth(String source, String code, String state, SocialProperties socialProperties) throws AuthException {
|
public static AuthResponse<AuthUser> loginAuth(String source, String code, String state, SocialProperties socialProperties) throws AuthException {
|
||||||
AuthRequest authRequest = getAuthRequest(source, socialProperties);
|
AuthRequest authRequest = getAuthRequest(source, socialProperties);
|
||||||
@@ -32,6 +42,14 @@ public class SocialUtils {
|
|||||||
return authRequest.login(callback);
|
return authRequest.login(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据平台类型构建授权请求实例。
|
||||||
|
*
|
||||||
|
* @param source 社交平台类型
|
||||||
|
* @param socialProperties 社交平台配置
|
||||||
|
* @return 授权请求
|
||||||
|
* @throws AuthException 授权异常
|
||||||
|
*/
|
||||||
public static AuthRequest getAuthRequest(String source, SocialProperties socialProperties) throws AuthException {
|
public static AuthRequest getAuthRequest(String source, SocialProperties socialProperties) throws AuthException {
|
||||||
SocialLoginConfigProperties obj = socialProperties.getType().get(source);
|
SocialLoginConfigProperties obj = socialProperties.getType().get(source);
|
||||||
if (ObjectUtil.isNull(obj)) {
|
if (ObjectUtil.isNull(obj)) {
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ public class SseController implements DisposableBean {
|
|||||||
private final SseEmitterManager sseEmitterManager;
|
private final SseEmitterManager sseEmitterManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 建立 SSE 连接
|
* 建立当前登录用户的 SSE 连接。
|
||||||
|
*
|
||||||
|
* @return SSE 发射器
|
||||||
*/
|
*/
|
||||||
@GetMapping(value = "${sse.path}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
@GetMapping(value = "${sse.path}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||||
public SseEmitter connect() {
|
public SseEmitter connect() {
|
||||||
@@ -39,7 +41,9 @@ public class SseController implements DisposableBean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关闭 SSE 连接
|
* 关闭当前登录用户的 SSE 连接。
|
||||||
|
*
|
||||||
|
* @return 操作结果
|
||||||
*/
|
*/
|
||||||
@SaIgnore
|
@SaIgnore
|
||||||
@GetMapping(value = "${sse.path}/close")
|
@GetMapping(value = "${sse.path}/close")
|
||||||
@@ -78,7 +82,9 @@ public class SseController implements DisposableBean {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清理资源。此方法目前不执行任何操作,但避免因未实现而导致错误
|
* 容器销毁时释放资源占位实现。
|
||||||
|
*
|
||||||
|
* @throws Exception 销毁异常
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void destroy() throws Exception {
|
public void destroy() throws Exception {
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ public class SseEmitterManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SSE 心跳检测,关闭无效连接
|
* 执行 SSE 心跳检测并清理失效连接。
|
||||||
*/
|
*/
|
||||||
public void sseMonitor() {
|
public void sseMonitor() {
|
||||||
final SseEmitter.SseEventBuilder heartbeat = SseEmitter.event().comment("heartbeat");
|
final SseEmitter.SseEventBuilder heartbeat = SseEmitter.event().comment("heartbeat");
|
||||||
@@ -154,7 +154,7 @@ public class SseEmitterManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 订阅SSE消息主题,并提供一个消费者函数来处理接收到的消息
|
* 订阅 SSE 广播主题消息。
|
||||||
*
|
*
|
||||||
* @param consumer 处理SSE消息的消费者函数
|
* @param consumer 处理SSE消息的消费者函数
|
||||||
*/
|
*/
|
||||||
@@ -163,7 +163,7 @@ public class SseEmitterManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 向指定的用户会话发送消息
|
* 向指定用户的全部本地 SSE 会话发送消息。
|
||||||
*
|
*
|
||||||
* @param userId 要发送消息的用户id
|
* @param userId 要发送消息的用户id
|
||||||
* @param message 要发送的消息内容
|
* @param message 要发送的消息内容
|
||||||
@@ -189,7 +189,7 @@ public class SseEmitterManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 本机全用户会话发送消息
|
* 向当前节点所有 SSE 会话发送消息。
|
||||||
*
|
*
|
||||||
* @param message 要发送的消息内容
|
* @param message 要发送的消息内容
|
||||||
*/
|
*/
|
||||||
@@ -200,7 +200,7 @@ public class SseEmitterManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发布SSE订阅消息
|
* 发布 SSE 订阅消息。
|
||||||
*
|
*
|
||||||
* @param sseMessageDTO 要发布的SSE消息对象
|
* @param sseMessageDTO 要发布的SSE消息对象
|
||||||
*/
|
*/
|
||||||
@@ -215,7 +215,7 @@ public class SseEmitterManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 向所有的用户发布订阅的消息(群发)
|
* 发布 SSE 广播消息。
|
||||||
*
|
*
|
||||||
* @param message 要发布的消息内容
|
* @param message 要发布的消息内容
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public class SseMessageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 向指定的SSE会话发送消息
|
* 向指定用户的 SSE 会话发送消息。
|
||||||
*
|
*
|
||||||
* @param userId 要发送消息的用户id
|
* @param userId 要发送消息的用户id
|
||||||
* @param message 要发送的消息内容
|
* @param message 要发送的消息内容
|
||||||
@@ -39,7 +39,7 @@ public class SseMessageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 本机全用户会话发送消息
|
* 向当前节点上的所有 SSE 会话发送消息。
|
||||||
*
|
*
|
||||||
* @param message 要发送的消息内容
|
* @param message 要发送的消息内容
|
||||||
*/
|
*/
|
||||||
@@ -51,7 +51,7 @@ public class SseMessageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发布SSE订阅消息
|
* 发布 SSE 订阅消息。
|
||||||
*
|
*
|
||||||
* @param sseMessageDTO 要发布的SSE消息对象
|
* @param sseMessageDTO 要发布的SSE消息对象
|
||||||
*/
|
*/
|
||||||
@@ -63,7 +63,7 @@ public class SseMessageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 向所有的用户发布订阅的消息(群发)
|
* 向所有用户发布 SSE 广播消息。
|
||||||
*
|
*
|
||||||
* @param message 要发布的消息内容
|
* @param message 要发布的消息内容
|
||||||
*/
|
*/
|
||||||
@@ -75,7 +75,9 @@ public class SseMessageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否开启
|
* 判断 SSE 功能是否启用。
|
||||||
|
*
|
||||||
|
* @return 是否启用
|
||||||
*/
|
*/
|
||||||
public static Boolean isEnable() {
|
public static Boolean isEnable() {
|
||||||
return SSE_ENABLE;
|
return SSE_ENABLE;
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ import org.dromara.common.translation.annotation.TranslationType;
|
|||||||
public interface TranslationInterface<T> {
|
public interface TranslationInterface<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 翻译
|
* 按翻译键执行转换。
|
||||||
*
|
*
|
||||||
* @param key 需要被翻译的键(不为空)
|
* @param key 需要被翻译的键(不为空)
|
||||||
* @param other 其他参数
|
* @param other 其他参数
|
||||||
* @return 返回键对应的值
|
* @return 返回键对应的翻译值
|
||||||
*/
|
*/
|
||||||
T translation(Object key, String other);
|
T translation(Object key, String other);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,14 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class TranslationBeanSerializerModifier extends ValueSerializerModifier {
|
public class TranslationBeanSerializerModifier extends ValueSerializerModifier {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为翻译字段补充空值序列化器,确保字段值为 {@code null} 时仍能走翻译处理链。
|
||||||
|
*
|
||||||
|
* @param config 当前序列化配置
|
||||||
|
* @param beanDesc Bean 描述提供者
|
||||||
|
* @param beanProperties 当前 Bean 的属性写入器列表
|
||||||
|
* @return 调整后的属性写入器列表
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription.Supplier beanDesc,
|
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription.Supplier beanDesc,
|
||||||
List<BeanPropertyWriter> beanProperties) {
|
List<BeanPropertyWriter> beanProperties) {
|
||||||
|
|||||||
@@ -38,10 +38,23 @@ public class TranslationHandler extends ValueSerializer<Object> {
|
|||||||
this.translation = null;
|
this.translation = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建绑定指定翻译注解的序列化处理器。
|
||||||
|
*
|
||||||
|
* @param translation 当前字段上声明的翻译注解
|
||||||
|
*/
|
||||||
public TranslationHandler(Translation translation) {
|
public TranslationHandler(Translation translation) {
|
||||||
this.translation = translation;
|
this.translation = translation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将原始字段值翻译为展示值并写回序列化结果。
|
||||||
|
*
|
||||||
|
* @param value 原始字段值
|
||||||
|
* @param gen Json 输出器
|
||||||
|
* @param ctxt 序列化上下文
|
||||||
|
* @throws JacksonException Json 序列化异常
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void serialize(Object value, JsonGenerator gen, SerializationContext ctxt) throws JacksonException {
|
public void serialize(Object value, JsonGenerator gen, SerializationContext ctxt) throws JacksonException {
|
||||||
TranslationInterface<?> trans = TRANSLATION_MAPPER.get(translation.type());
|
TranslationInterface<?> trans = TRANSLATION_MAPPER.get(translation.type());
|
||||||
@@ -68,6 +81,13 @@ public class TranslationHandler extends ValueSerializer<Object> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按字段上的 {@link Translation} 注解创建上下文相关的翻译序列化器。
|
||||||
|
*
|
||||||
|
* @param ctxt 序列化上下文
|
||||||
|
* @param property 当前序列化属性
|
||||||
|
* @return 存在翻译注解时返回新的翻译处理器,否则沿用默认序列化器
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ValueSerializer<?> createContextual(SerializationContext ctxt, BeanProperty property) {
|
public ValueSerializer<?> createContextual(SerializationContext ctxt, BeanProperty property) {
|
||||||
Translation translation = property.getAnnotation(Translation.class);
|
Translation translation = property.getAnnotation(Translation.class);
|
||||||
|
|||||||
@@ -17,6 +17,13 @@ public class DeptNameTranslationImpl implements TranslationInterface<String> {
|
|||||||
|
|
||||||
private final DeptService deptService;
|
private final DeptService deptService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将部门 ID 或 ID 集合翻译为部门名称。
|
||||||
|
*
|
||||||
|
* @param key 部门 ID 或逗号分隔的 ID 字符串
|
||||||
|
* @param other 额外参数
|
||||||
|
* @return 部门名称
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String translation(Object key, String other) {
|
public String translation(Object key, String other) {
|
||||||
if (key instanceof String ids) {
|
if (key instanceof String ids) {
|
||||||
|
|||||||
@@ -18,6 +18,13 @@ public class DictTypeTranslationImpl implements TranslationInterface<String> {
|
|||||||
|
|
||||||
private final DictService dictService;
|
private final DictService dictService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据字典类型和字典值翻译显示标签。
|
||||||
|
*
|
||||||
|
* @param key 字典值
|
||||||
|
* @param other 字典类型
|
||||||
|
* @return 字典标签
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String translation(Object key, String other) {
|
public String translation(Object key, String other) {
|
||||||
if (key instanceof String dictValue && StringUtils.isNotBlank(other)) {
|
if (key instanceof String dictValue && StringUtils.isNotBlank(other)) {
|
||||||
|
|||||||
@@ -17,6 +17,13 @@ public class NicknameTranslationImpl implements TranslationInterface<String> {
|
|||||||
|
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将用户 ID 或 ID 集合翻译为用户昵称。
|
||||||
|
*
|
||||||
|
* @param key 用户 ID 或逗号分隔的 ID 字符串
|
||||||
|
* @param other 额外参数
|
||||||
|
* @return 用户昵称
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String translation(Object key, String other) {
|
public String translation(Object key, String other) {
|
||||||
if (key instanceof Long id) {
|
if (key instanceof Long id) {
|
||||||
|
|||||||
@@ -17,6 +17,13 @@ public class OssUrlTranslationImpl implements TranslationInterface<String> {
|
|||||||
|
|
||||||
private final OssService ossService;
|
private final OssService ossService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 OSS ID 或 ID 集合翻译为访问地址。
|
||||||
|
*
|
||||||
|
* @param key OSS ID 或逗号分隔的 ID 字符串
|
||||||
|
* @param other 额外参数
|
||||||
|
* @return 访问地址
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String translation(Object key, String other) {
|
public String translation(Object key, String other) {
|
||||||
if (key instanceof String ids) {
|
if (key instanceof String ids) {
|
||||||
|
|||||||
@@ -18,6 +18,13 @@ public class UserNameTranslationImpl implements TranslationInterface<String> {
|
|||||||
|
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将用户 ID 翻译为用户名。
|
||||||
|
*
|
||||||
|
* @param key 用户 ID
|
||||||
|
* @param other 额外参数
|
||||||
|
* @return 用户名
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String translation(Object key, String other) {
|
public String translation(Object key, String other) {
|
||||||
return userService.selectUserNameById(Convert.toLong(key));
|
return userService.selectUserNameById(Convert.toLong(key));
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ import org.springframework.context.annotation.Bean;
|
|||||||
@EnableConfigurationProperties(XssProperties.class)
|
@EnableConfigurationProperties(XssProperties.class)
|
||||||
public class FilterConfig {
|
public class FilterConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册 XSS 过滤器。
|
||||||
|
*
|
||||||
|
* @return XSS 请求过滤器实例
|
||||||
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
|
@ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
|
||||||
@FilterRegistration(
|
@FilterRegistration(
|
||||||
@@ -32,6 +37,11 @@ public class FilterConfig {
|
|||||||
return new XssFilter();
|
return new XssFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册可重复读取请求体过滤器。
|
||||||
|
*
|
||||||
|
* @return 请求包装过滤器实例
|
||||||
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@FilterRegistration(name = "repeatableFilter", urlPatterns = "/*")
|
@FilterRegistration(name = "repeatableFilter", urlPatterns = "/*")
|
||||||
public RepeatableFilter repeatableFilter() {
|
public RepeatableFilter repeatableFilter() {
|
||||||
|
|||||||
@@ -14,6 +14,11 @@ import org.springframework.web.servlet.LocaleResolver;
|
|||||||
@AutoConfiguration(before = WebMvcAutoConfiguration.class)
|
@AutoConfiguration(before = WebMvcAutoConfiguration.class)
|
||||||
public class I18nConfig {
|
public class I18nConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册自定义国际化区域解析器。
|
||||||
|
*
|
||||||
|
* @return Locale 解析器实例
|
||||||
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public LocaleResolver localeResolver() {
|
public LocaleResolver localeResolver() {
|
||||||
return new I18nLocaleResolver();
|
return new I18nLocaleResolver();
|
||||||
|
|||||||
@@ -25,12 +25,22 @@ import java.util.Date;
|
|||||||
@AutoConfiguration
|
@AutoConfiguration
|
||||||
public class ResourcesConfig implements WebMvcConfigurer {
|
public class ResourcesConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册全局拦截器。
|
||||||
|
*
|
||||||
|
* @param registry 拦截器注册表
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
// 全局访问性能拦截
|
// 全局访问性能拦截
|
||||||
registry.addInterceptor(new PlusWebInvokeTimeInterceptor());
|
registry.addInterceptor(new PlusWebInvokeTimeInterceptor());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册全局格式转换器。
|
||||||
|
*
|
||||||
|
* @param registry 格式化器注册表
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void addFormatters(FormatterRegistry registry) {
|
public void addFormatters(FormatterRegistry registry) {
|
||||||
// 全局日期格式转换配置
|
// 全局日期格式转换配置
|
||||||
@@ -43,12 +53,19 @@ public class ResourcesConfig implements WebMvcConfigurer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册静态资源处理器。
|
||||||
|
*
|
||||||
|
* @param registry 资源处理器注册表
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 跨域配置
|
* 跨域配置
|
||||||
|
*
|
||||||
|
* @return 全局 Cors 过滤器
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public CorsFilter corsFilter() {
|
public CorsFilter corsFilter() {
|
||||||
@@ -71,6 +88,8 @@ public class ResourcesConfig implements WebMvcConfigurer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 全局异常处理器
|
* 全局异常处理器
|
||||||
|
*
|
||||||
|
* @return 全局异常处理器实例
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public GlobalExceptionHandler globalExceptionHandler() {
|
public GlobalExceptionHandler globalExceptionHandler() {
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
|||||||
@ConfigurationProperties(prefix = "captcha")
|
@ConfigurationProperties(prefix = "captcha")
|
||||||
public class CaptchaProperties {
|
public class CaptchaProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否启用验证码校验。
|
||||||
|
*/
|
||||||
private Boolean enable;
|
private Boolean enable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* xss过滤 配置属性
|
* XSS 过滤配置属性,用于控制过滤器开关及排除路径。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@@ -16,12 +16,12 @@ import java.util.List;
|
|||||||
public class XssProperties {
|
public class XssProperties {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Xss开关
|
* XSS 过滤总开关。
|
||||||
*/
|
*/
|
||||||
private Boolean enabled;
|
private Boolean enabled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 排除路径
|
* 跳过 XSS 过滤的请求路径集合。
|
||||||
*/
|
*/
|
||||||
private List<String> excludeUrls = new ArrayList<>();
|
private List<String> excludeUrls = new ArrayList<>();
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ public class BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 页面跳转
|
* 页面跳转
|
||||||
|
*
|
||||||
|
* @param url 目标跳转地址
|
||||||
|
* @return Spring MVC 重定向路径表达式
|
||||||
*/
|
*/
|
||||||
public String redirect(String url) {
|
public String redirect(String url) {
|
||||||
return StringUtils.format("redirect:{}", url);
|
return StringUtils.format("redirect:{}", url);
|
||||||
|
|||||||
@@ -7,12 +7,18 @@ import jakarta.servlet.http.HttpServletResponse;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取请求头国际化信息
|
* 基于请求头解析国际化区域信息的语言解析器。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
public class I18nLocaleResolver implements LocaleResolver {
|
public class I18nLocaleResolver implements LocaleResolver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从请求头 {@code content-language} 中解析本次请求的区域信息,缺省时回退到系统默认区域。
|
||||||
|
*
|
||||||
|
* @param httpServletRequest 当前请求
|
||||||
|
* @return 当前请求对应的区域设置
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Locale resolveLocale(HttpServletRequest httpServletRequest) {
|
public Locale resolveLocale(HttpServletRequest httpServletRequest) {
|
||||||
String language = httpServletRequest.getHeader("content-language");
|
String language = httpServletRequest.getHeader("content-language");
|
||||||
@@ -23,6 +29,13 @@ public class I18nLocaleResolver implements LocaleResolver {
|
|||||||
return locale;
|
return locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前项目不在服务端主动切换区域信息,因此保留空实现。
|
||||||
|
*
|
||||||
|
* @param httpServletRequest 当前请求
|
||||||
|
* @param httpServletResponse 当前响应
|
||||||
|
* @param locale 目标区域
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
|
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import java.io.Serial;
|
|||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 带干扰线、波浪、圆的验证码
|
* 带干扰线、波浪和圆形干扰元素的验证码实现,用于增强验证码识别难度。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@@ -23,27 +23,70 @@ public class WaveAndCircleCaptcha extends AbstractCaptcha {
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
// 构造方法(略,与之前一致)
|
/**
|
||||||
|
* 构造默认长度为 4 的验证码。
|
||||||
|
*
|
||||||
|
* @param width 图片宽度
|
||||||
|
* @param height 图片高度
|
||||||
|
*/
|
||||||
public WaveAndCircleCaptcha(int width, int height) {
|
public WaveAndCircleCaptcha(int width, int height) {
|
||||||
this(width, height, 4);
|
this(width, height, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造指定验证码长度的验证码对象。
|
||||||
|
*
|
||||||
|
* @param width 图片宽度
|
||||||
|
* @param height 图片高度
|
||||||
|
* @param codeCount 验证码字符数
|
||||||
|
*/
|
||||||
public WaveAndCircleCaptcha(int width, int height, int codeCount) {
|
public WaveAndCircleCaptcha(int width, int height, int codeCount) {
|
||||||
this(width, height, codeCount, 6);
|
this(width, height, codeCount, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造指定字符数与干扰数的验证码对象。
|
||||||
|
*
|
||||||
|
* @param width 图片宽度
|
||||||
|
* @param height 图片高度
|
||||||
|
* @param codeCount 验证码字符数
|
||||||
|
* @param interfereCount 干扰元素数量
|
||||||
|
*/
|
||||||
public WaveAndCircleCaptcha(int width, int height, int codeCount, int interfereCount) {
|
public WaveAndCircleCaptcha(int width, int height, int codeCount, int interfereCount) {
|
||||||
this(width, height, new RandomGenerator(codeCount), interfereCount);
|
this(width, height, new RandomGenerator(codeCount), interfereCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用指定验证码生成器构造验证码对象。
|
||||||
|
*
|
||||||
|
* @param width 图片宽度
|
||||||
|
* @param height 图片高度
|
||||||
|
* @param generator 验证码生成器
|
||||||
|
* @param interfereCount 干扰元素数量
|
||||||
|
*/
|
||||||
public WaveAndCircleCaptcha(int width, int height, CodeGenerator generator, int interfereCount) {
|
public WaveAndCircleCaptcha(int width, int height, CodeGenerator generator, int interfereCount) {
|
||||||
super(width, height, generator, interfereCount);
|
super(width, height, generator, interfereCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造带字体缩放比例的验证码对象。
|
||||||
|
*
|
||||||
|
* @param width 图片宽度
|
||||||
|
* @param height 图片高度
|
||||||
|
* @param codeCount 验证码字符数
|
||||||
|
* @param interfereCount 干扰元素数量
|
||||||
|
* @param size 字体相对尺寸
|
||||||
|
*/
|
||||||
public WaveAndCircleCaptcha(int width, int height, int codeCount, int interfereCount, float size) {
|
public WaveAndCircleCaptcha(int width, int height, int codeCount, int interfereCount, float size) {
|
||||||
super(width, height, new RandomGenerator(codeCount), interfereCount, size);
|
super(width, height, new RandomGenerator(codeCount), interfereCount, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成验证码图片并绘制文字、扭曲效果及干扰图形。
|
||||||
|
*
|
||||||
|
* @param code 验证码文本
|
||||||
|
* @return 生成后的验证码图片
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Image createImage(String code) {
|
public Image createImage(String code) {
|
||||||
final BufferedImage image = new BufferedImage(
|
final BufferedImage image = new BufferedImage(
|
||||||
@@ -65,6 +108,12 @@ public class WaveAndCircleCaptcha extends AbstractCaptcha {
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制验证码文本并开启文字抗锯齿。
|
||||||
|
*
|
||||||
|
* @param g 图形上下文
|
||||||
|
* @param code 验证码文本
|
||||||
|
*/
|
||||||
private void drawString(Graphics2D g, String code) {
|
private void drawString(Graphics2D g, String code) {
|
||||||
// 设置抗锯齿(让字体渲染更清晰)
|
// 设置抗锯齿(让字体渲染更清晰)
|
||||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
@@ -77,6 +126,11 @@ public class WaveAndCircleCaptcha extends AbstractCaptcha {
|
|||||||
GraphicsUtil.drawStringColourful(g, code, this.font, this.width, this.height);
|
GraphicsUtil.drawStringColourful(g, code, this.font, this.width, this.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制圆形与波浪线干扰元素。
|
||||||
|
*
|
||||||
|
* @param g 图形上下文
|
||||||
|
*/
|
||||||
protected void drawInterfere(Graphics2D g) {
|
protected void drawInterfere(Graphics2D g) {
|
||||||
ThreadLocalRandom random = RandomUtil.getRandom();
|
ThreadLocalRandom random = RandomUtil.getRandom();
|
||||||
int circleCount = Math.max(0, this.interfereCount - 1);
|
int circleCount = Math.max(0, this.interfereCount - 1);
|
||||||
@@ -98,6 +152,12 @@ public class WaveAndCircleCaptcha extends AbstractCaptcha {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制平滑波浪线干扰轨迹。
|
||||||
|
*
|
||||||
|
* @param g 图形上下文
|
||||||
|
* @param random 随机数生成器
|
||||||
|
*/
|
||||||
private void drawSmoothWave(Graphics2D g, ThreadLocalRandom random) {
|
private void drawSmoothWave(Graphics2D g, ThreadLocalRandom random) {
|
||||||
int amplitude = random.nextInt(8) + 5; // 波动幅度
|
int amplitude = random.nextInt(8) + 5; // 波动幅度
|
||||||
int wavelength = random.nextInt(40) + 30; // 波长
|
int wavelength = random.nextInt(40) + 30; // 波长
|
||||||
@@ -122,6 +182,14 @@ public class WaveAndCircleCaptcha extends AbstractCaptcha {
|
|||||||
g.drawPolyline(xPoints, yPoints, width);
|
g.drawPolyline(xPoints, yPoints, width);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成指定 RGB 范围内的随机颜色。
|
||||||
|
*
|
||||||
|
* @param min 最小颜色值
|
||||||
|
* @param max 最大颜色值
|
||||||
|
* @param random 随机数生成器
|
||||||
|
* @return 随机颜色
|
||||||
|
*/
|
||||||
private Color getRandomColor(int min, int max, ThreadLocalRandom random) {
|
private Color getRandomColor(int min, int max, ThreadLocalRandom random) {
|
||||||
int range = max - min;
|
int range = max - min;
|
||||||
return new Color(
|
return new Color(
|
||||||
|
|||||||
@@ -8,16 +8,32 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Repeatable 过滤器
|
* 可重复读取请求体的过滤器,仅对 JSON 请求包装可重复消费的请求对象。
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
public class RepeatableFilter implements Filter {
|
public class RepeatableFilter implements Filter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过滤器初始化入口,当前无额外初始化逻辑。
|
||||||
|
*
|
||||||
|
* @param filterConfig 过滤器配置
|
||||||
|
* @throws ServletException 过滤器初始化异常
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void init(FilterConfig filterConfig) throws ServletException {
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为 JSON 请求创建可重复读取的包装器,便于日志、验签等场景多次读取请求体。
|
||||||
|
*
|
||||||
|
* @param request 原始请求
|
||||||
|
* @param response 当前响应
|
||||||
|
* @param chain 过滤器链
|
||||||
|
* @throws IOException IO 异常
|
||||||
|
* @throws ServletException Servlet 异常
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
@@ -33,6 +49,9 @@ public class RepeatableFilter implements Filter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过滤器销毁入口,当前无额外资源需要释放。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
|
|
||||||
|
|||||||
@@ -15,13 +15,20 @@ import java.io.IOException;
|
|||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建可重复读取inputStream的request
|
* 构建可重复读取输入流的请求包装器,缓存请求体以支持多次读取。
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
|
public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
|
||||||
private final byte[] body;
|
private final byte[] body;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取原始请求体并缓存到内存,统一设置请求与响应编码。
|
||||||
|
*
|
||||||
|
* @param request 原始请求
|
||||||
|
* @param response 当前响应
|
||||||
|
* @throws IOException 读取请求体异常
|
||||||
|
*/
|
||||||
public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException {
|
public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException {
|
||||||
super(request);
|
super(request);
|
||||||
request.setCharacterEncoding(Constants.UTF8);
|
request.setCharacterEncoding(Constants.UTF8);
|
||||||
@@ -30,11 +37,23 @@ public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
|
|||||||
body = IoUtil.readBytes(request.getInputStream(), false);
|
body = IoUtil.readBytes(request.getInputStream(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于缓存的请求体构造字符读取器。
|
||||||
|
*
|
||||||
|
* @return 可重复读取的字符流
|
||||||
|
* @throws IOException IO 异常
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public BufferedReader getReader() throws IOException {
|
public BufferedReader getReader() throws IOException {
|
||||||
return new BufferedReader(new InputStreamReader(getInputStream()));
|
return new BufferedReader(new InputStreamReader(getInputStream()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回基于缓存请求体重新生成的输入流。
|
||||||
|
*
|
||||||
|
* @return 可重复读取的输入流
|
||||||
|
* @throws IOException IO 异常
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ServletInputStream getInputStream() throws IOException {
|
public ServletInputStream getInputStream() throws IOException {
|
||||||
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
|
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
|
||||||
|
|||||||
@@ -13,22 +13,37 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 防止XSS攻击的过滤器
|
* 防止 XSS 攻击的过滤器,对非排除请求执行参数与请求体清洗。
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
public class XssFilter implements Filter {
|
public class XssFilter implements Filter {
|
||||||
/**
|
/**
|
||||||
* 排除链接
|
* 跳过 XSS 过滤的请求路径集合。
|
||||||
*/
|
*/
|
||||||
public List<String> excludes = new ArrayList<>();
|
public List<String> excludes = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化过滤器并加载配置中的排除路径。
|
||||||
|
*
|
||||||
|
* @param filterConfig 过滤器配置
|
||||||
|
* @throws ServletException 过滤器初始化异常
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void init(FilterConfig filterConfig) throws ServletException {
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
XssProperties properties = SpringUtils.getBean(XssProperties.class);
|
XssProperties properties = SpringUtils.getBean(XssProperties.class);
|
||||||
excludes.addAll(properties.getExcludeUrls());
|
excludes.addAll(properties.getExcludeUrls());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对请求执行 XSS 包装处理,命中排除规则时直接放行。
|
||||||
|
*
|
||||||
|
* @param request 原始请求
|
||||||
|
* @param response 当前响应
|
||||||
|
* @param chain 过滤器链
|
||||||
|
* @throws IOException IO 异常
|
||||||
|
* @throws ServletException Servlet 异常
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
@@ -42,6 +57,13 @@ public class XssFilter implements Filter {
|
|||||||
chain.doFilter(xssRequest, response);
|
chain.doFilter(xssRequest, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断当前请求是否需要跳过 XSS 过滤。
|
||||||
|
*
|
||||||
|
* @param request 当前请求
|
||||||
|
* @param response 当前响应
|
||||||
|
* @return true 表示跳过过滤
|
||||||
|
*/
|
||||||
private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) {
|
private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) {
|
||||||
String url = request.getServletPath();
|
String url = request.getServletPath();
|
||||||
String method = request.getMethod();
|
String method = request.getMethod();
|
||||||
@@ -52,6 +74,9 @@ public class XssFilter implements Filter {
|
|||||||
return StringUtils.matches(url, excludes);
|
return StringUtils.matches(url, excludes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过滤器销毁入口,当前无额外资源需要释放。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
|
|
||||||
|
|||||||
@@ -20,18 +20,27 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XSS过滤处理
|
* XSS 请求包装器,统一清洗参数与 JSON 请求体中的 HTML 标签内容。
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param request
|
* 使用原始请求构造 XSS 包装器。
|
||||||
|
*
|
||||||
|
* @param request 原始请求
|
||||||
*/
|
*/
|
||||||
public XssHttpServletRequestWrapper(HttpServletRequest request) {
|
public XssHttpServletRequestWrapper(HttpServletRequest request) {
|
||||||
super(request);
|
super(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取并清洗单个请求参数。
|
||||||
|
*
|
||||||
|
* @param name 参数名
|
||||||
|
* @return 清洗后的参数值
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getParameter(String name) {
|
public String getParameter(String name) {
|
||||||
String value = super.getParameter(name);
|
String value = super.getParameter(name);
|
||||||
@@ -41,6 +50,11 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
|||||||
return HtmlUtil.cleanHtmlTag(value).trim();
|
return HtmlUtil.cleanHtmlTag(value).trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取并清洗整组请求参数。
|
||||||
|
*
|
||||||
|
* @return 清洗后的参数映射
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Map<String, String[]> getParameterMap() {
|
public Map<String, String[]> getParameterMap() {
|
||||||
Map<String, String[]> valueMap = super.getParameterMap();
|
Map<String, String[]> valueMap = super.getParameterMap();
|
||||||
@@ -65,6 +79,12 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取并清洗指定参数的多值数组。
|
||||||
|
*
|
||||||
|
* @param name 参数名
|
||||||
|
* @return 清洗后的参数值数组
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String[] getParameterValues(String name) {
|
public String[] getParameterValues(String name) {
|
||||||
String[] values = super.getParameterValues(name);
|
String[] values = super.getParameterValues(name);
|
||||||
@@ -80,6 +100,12 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
|||||||
return escapseValues;
|
return escapseValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取输入流并在 JSON 场景下对请求体执行清洗。
|
||||||
|
*
|
||||||
|
* @return 清洗后的输入流
|
||||||
|
* @throws IOException 读取请求体异常
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ServletInputStream getInputStream() throws IOException {
|
public ServletInputStream getInputStream() throws IOException {
|
||||||
// 非json类型,直接返回
|
// 非json类型,直接返回
|
||||||
@@ -125,7 +151,9 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否是Json请求
|
* 判断当前请求是否为 JSON 请求。
|
||||||
|
*
|
||||||
|
* @return true 表示 JSON 请求
|
||||||
*/
|
*/
|
||||||
public boolean isJsonRequest() {
|
public boolean isJsonRequest() {
|
||||||
String header = super.getHeader(HttpHeaders.CONTENT_TYPE);
|
String header = super.getHeader(HttpHeaders.CONTENT_TYPE);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* web的调用时间统计拦截器
|
* Web 调用时间统计拦截器,同时记录请求参数并对敏感字段做脱敏处理。
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
* @since 3.3.0
|
* @since 3.3.0
|
||||||
@@ -36,6 +36,15 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
|
|||||||
|
|
||||||
private final static ThreadLocal<StopWatch> KEY_CACHE = new ThreadLocal<>();
|
private final static ThreadLocal<StopWatch> KEY_CACHE = new ThreadLocal<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求进入控制器前记录入参并启动耗时统计。
|
||||||
|
*
|
||||||
|
* @param request 当前请求
|
||||||
|
* @param response 当前响应
|
||||||
|
* @param handler 目标处理器
|
||||||
|
* @return 始终返回 true,继续后续处理流程
|
||||||
|
* @throws Exception 读取请求体或解析 JSON 失败时抛出
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
String url = request.getMethod() + " " + request.getRequestURI();
|
String url = request.getMethod() + " " + request.getRequestURI();
|
||||||
@@ -71,6 +80,12 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归移除 JSON 节点中的敏感字段,避免在日志中输出密码等敏感信息。
|
||||||
|
*
|
||||||
|
* @param node 当前 JSON 节点
|
||||||
|
* @param excludeProperties 需要排除的字段名集合
|
||||||
|
*/
|
||||||
private void removeSensitiveFields(JsonNode node, String[] excludeProperties) {
|
private void removeSensitiveFields(JsonNode node, String[] excludeProperties) {
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
return;
|
return;
|
||||||
@@ -100,6 +115,15 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求完成后输出最终耗时,并清理线程内缓存的计时器。
|
||||||
|
*
|
||||||
|
* @param request 当前请求
|
||||||
|
* @param response 当前响应
|
||||||
|
* @param handler 目标处理器
|
||||||
|
* @param ex 请求处理过程中的异常
|
||||||
|
* @throws Exception 拦截器链路抛出的异常
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||||
StopWatch stopWatch = KEY_CACHE.get();
|
StopWatch stopWatch = KEY_CACHE.get();
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user