升级到JDK21,SpringBoot3.1.8,SpringCloud2022.0.5

This commit is contained in:
AlanScipio
2024-01-31 15:32:00 +08:00
parent c3de97c825
commit 4039d79e5a
110 changed files with 2359 additions and 4017 deletions

View File

@@ -47,7 +47,7 @@
<artifactId>transmittable-thread-local</artifactId>
</dependency>
<!-- Pagehelper -->
<!-- PageHelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
@@ -74,15 +74,20 @@
<!-- Jwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<artifactId>jjwt-impl</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
</dependency>
<!-- Jaxb -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
</dependency>
<!-- Apache Lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
@@ -103,13 +108,13 @@
<!-- Java Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</dependency>
<!-- Swagger -->
<dependency>
<groupId>io.swagger</groupId>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>

View File

@@ -4,178 +4,172 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.math.BigDecimal;
import java.math.RoundingMode;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import com.ruoyi.common.core.utils.poi.ExcelHandlerAdapter;
/**
* 自定义导出Excel数据注解
*
*
* @author ruoyi
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Excel
{
public @interface Excel {
/**
* 导出时在excel中排序
*/
public int sort() default Integer.MAX_VALUE;
int sort() default Integer.MAX_VALUE;
/**
* 导出到Excel中的名字.
*/
public String name() default "";
String name() default "";
/**
* 日期格式, 如: yyyy-MM-dd
*/
public String dateFormat() default "";
String dateFormat() default "";
/**
* 读取内容转表达式 (如: 0=男,1=女,2=未知)
*/
public String readConverterExp() default "";
String readConverterExp() default "";
/**
* 分隔符,读取字符串组内容
*/
public String separator() default ",";
String separator() default ",";
/**
* BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
*/
public int scale() default -1;
int scale() default -1;
/**
* BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
*/
public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
RoundingMode roundingMode() default RoundingMode.HALF_EVEN;
/**
* 导出时在excel中每个列的高度
*/
public double height() default 14;
double height() default 14;
/**
* 导出时在excel中每个列的宽度
*/
public double width() default 16;
double width() default 16;
/**
* 文字后缀,如% 90 变成90%
*/
public String suffix() default "";
String suffix() default "";
/**
* 当值为空时,字段的默认值
*/
public String defaultValue() default "";
String defaultValue() default "";
/**
* 提示信息
*/
public String prompt() default "";
String prompt() default "";
/**
* 设置只能选择不能输入的列内容.
*/
public String[] combo() default {};
String[] combo() default {};
/**
* 是否需要纵向合并单元格,应对需求:含有list集合单元格)
*/
public boolean needMerge() default false;
boolean needMerge() default false;
/**
* 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
*/
public boolean isExport() default true;
boolean isExport() default true;
/**
* 另一个类中的属性名称,支持多级获取,以小数点隔开
*/
public String targetAttr() default "";
String targetAttr() default "";
/**
* 是否自动统计数据,在最后追加一行统计数据总和
*/
public boolean isStatistics() default false;
boolean isStatistics() default false;
/**
* 导出类型0数字 1字符串
*/
public ColumnType cellType() default ColumnType.STRING;
ColumnType cellType() default ColumnType.STRING;
/**
* 导出列头背景颜色
*/
public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
/**
* 导出列头字体颜色
*/
public IndexedColors headerColor() default IndexedColors.WHITE;
IndexedColors headerColor() default IndexedColors.WHITE;
/**
* 导出单元格背景颜色
*/
public IndexedColors backgroundColor() default IndexedColors.WHITE;
IndexedColors backgroundColor() default IndexedColors.WHITE;
/**
* 导出单元格字体颜色
*/
public IndexedColors color() default IndexedColors.BLACK;
IndexedColors color() default IndexedColors.BLACK;
/**
* 导出字段对齐方式
*/
public HorizontalAlignment align() default HorizontalAlignment.CENTER;
HorizontalAlignment align() default HorizontalAlignment.CENTER;
/**
* 自定义数据处理器
*/
public Class<?> handler() default ExcelHandlerAdapter.class;
Class<?> handler() default ExcelHandlerAdapter.class;
/**
* 自定义数据处理器参数
*/
public String[] args() default {};
String[] args() default {};
/**
* 字段类型0导出导入1仅导出2仅导入
*/
Type type() default Type.ALL;
public enum Type
{
enum Type {
ALL(0), EXPORT(1), IMPORT(2);
private final int value;
Type(int value)
{
Type(int value) {
this.value = value;
}
public int value()
{
int value() {
return this.value;
}
}
public enum ColumnType
{
enum ColumnType {
NUMERIC(0), STRING(1), IMAGE(2);
private final int value;
ColumnType(int value)
{
ColumnType(int value) {
this.value = value;
}
public int value()
{
int value() {
return this.value;
}
}

View File

@@ -20,6 +20,6 @@ public class TokenConstants
/**
* 令牌秘钥
*/
public final static String SECRET = "abcdefghijklmnopqrstuvwxyz";
public final static String SECRET = "NpdMXhdDbQM6YzdbLs8NsQqUjGtKBuGIbRWr8js6GLcdjr2GR0WbWS3guDlymBAN";
}

View File

@@ -1,20 +1,23 @@
package com.ruoyi.common.core.utils;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import com.ruoyi.common.core.constant.SecurityConstants;
import com.ruoyi.common.core.constant.TokenConstants;
import com.ruoyi.common.core.text.Convert;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import javax.crypto.SecretKey;
/**
* Jwt工具类
*
* @author ruoyi
*/
public class JwtUtils
{
public class JwtUtils {
public static String secret = TokenConstants.SECRET;
/**
@@ -23,9 +26,11 @@ public class JwtUtils
* @param claims 数据声明
* @return 令牌
*/
public static String createToken(Map<String, Object> claims)
{
String token = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, secret).compact();
public static String createToken(Map<String, Object> claims) {
String token = Jwts.builder()
.claims(claims)
.signWith(getSigningKey(secret), Jwts.SIG.HS512)
.compact();
return token;
}
@@ -35,89 +40,90 @@ public class JwtUtils
* @param token 令牌
* @return 数据声明
*/
public static Claims parseToken(String token)
{
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
public static Claims parseToken(String token) {
return Jwts.parser()
.verifyWith(getSigningKey(secret))
.build()
.parseSignedClaims(token)
.getPayload();
}
/**
* 根据令牌获取用户标识
*
*
* @param token 令牌
* @return 用户ID
*/
public static String getUserKey(String token)
{
public static String getUserKey(String token) {
Claims claims = parseToken(token);
return getValue(claims, SecurityConstants.USER_KEY);
}
/**
* 根据令牌获取用户标识
*
*
* @param claims 身份信息
* @return 用户ID
*/
public static String getUserKey(Claims claims)
{
public static String getUserKey(Claims claims) {
return getValue(claims, SecurityConstants.USER_KEY);
}
/**
* 根据令牌获取用户ID
*
*
* @param token 令牌
* @return 用户ID
*/
public static String getUserId(String token)
{
public static String getUserId(String token) {
Claims claims = parseToken(token);
return getValue(claims, SecurityConstants.DETAILS_USER_ID);
}
/**
* 根据身份信息获取用户ID
*
*
* @param claims 身份信息
* @return 用户ID
*/
public static String getUserId(Claims claims)
{
public static String getUserId(Claims claims) {
return getValue(claims, SecurityConstants.DETAILS_USER_ID);
}
/**
* 根据令牌获取用户名
*
*
* @param token 令牌
* @return 用户名
*/
public static String getUserName(String token)
{
public static String getUserName(String token) {
Claims claims = parseToken(token);
return getValue(claims, SecurityConstants.DETAILS_USERNAME);
}
/**
* 根据身份信息获取用户名
*
*
* @param claims 身份信息
* @return 用户名
*/
public static String getUserName(Claims claims)
{
public static String getUserName(Claims claims) {
return getValue(claims, SecurityConstants.DETAILS_USERNAME);
}
/**
* 根据身份信息获取键值
*
*
* @param claims 身份信息
* @param key 键
* @param key
* @return 值
*/
public static String getValue(Claims claims, String key)
{
public static String getValue(Claims claims, String key) {
return Convert.toStr(claims.get(key), "");
}
private static SecretKey getSigningKey(String secret) {
byte[] keyBytes = secret.getBytes(StandardCharsets.UTF_8);
return Keys.hmacShaKeyFor(keyBytes);
}
}

View File

@@ -8,10 +8,10 @@ import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;

View File

@@ -1,9 +1,10 @@
package com.ruoyi.common.core.utils.bean;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Validator;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
/**
* bean对象属性验证

View File

@@ -8,8 +8,8 @@ import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.ArrayUtils;
import com.ruoyi.common.core.utils.StringUtils;

View File

@@ -2,9 +2,11 @@ package com.ruoyi.common.core.utils.file;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import org.apache.poi.util.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -14,70 +16,53 @@ import org.slf4j.LoggerFactory;
*
* @author ruoyi
*/
public class ImageUtils
{
public class ImageUtils {
private static final Logger log = LoggerFactory.getLogger(ImageUtils.class);
public static byte[] getImage(String imagePath)
{
public static byte[] getImage(String imagePath) {
InputStream is = getFile(imagePath);
try
{
try {
return IOUtils.toByteArray(is);
}
catch (Exception e)
{
log.error("图片加载异常 {}", e);
} catch (Exception e) {
log.error("图片加载异常", e);
return null;
}
finally
{
} finally {
IOUtils.closeQuietly(is);
}
}
public static InputStream getFile(String imagePath)
{
try
{
public static InputStream getFile(String imagePath) {
try {
byte[] result = readFile(imagePath);
result = Arrays.copyOf(result, result.length);
return new ByteArrayInputStream(result);
}
catch (Exception e)
{
log.error("获取图片异常 {}", e);
} catch (Exception e) {
log.error("获取图片异常", e);
}
return null;
}
/**
* 读取文件为字节数据
*
*
* @param url 地址
* @return 字节数据
*/
public static byte[] readFile(String url)
{
public static byte[] readFile(String url) {
InputStream in = null;
try
{
try {
// 网络地址
URL urlObj = new URL(url);
URL urlObj = URI.create(url).toURL();
URLConnection urlConnection = urlObj.openConnection();
urlConnection.setConnectTimeout(30 * 1000);
urlConnection.setReadTimeout(60 * 1000);
urlConnection.setDoInput(true);
in = urlConnection.getInputStream();
return IOUtils.toByteArray(in);
}
catch (Exception e)
{
log.error("访问文件异常 {}", e);
} catch (Exception e) {
log.error("访问文件异常", e);
return null;
}
finally
{
} finally {
IOUtils.closeQuietly(in);
}
}

View File

@@ -2,7 +2,7 @@ package com.ruoyi.common.core.utils.ip;
import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import com.ruoyi.common.core.utils.ServletUtils;
import com.ruoyi.common.core.utils.StringUtils;

View File

@@ -6,7 +6,9 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.poi.ss.usermodel.DateUtil;
@@ -17,32 +19,29 @@ import com.ruoyi.common.core.utils.DateUtils;
/**
* 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
*
*
* @author ruoyi
*/
@SuppressWarnings("rawtypes")
public class ReflectUtils
{
public class ReflectUtils {
private static final String SETTER_PREFIX = "set";
private static final String GETTER_PREFIX = "get";
private static final String CGLIB_CLASS_SEPARATOR = "$$";
private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
private final static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
/**
* 调用Getter方法.
* 支持多级,如:对象名.对象名.方法
*/
@SuppressWarnings("unchecked")
public static <E> E invokeGetter(Object obj, String propertyName)
{
public static <E> E invokeGetter(Object obj, String propertyName) {
Object object = obj;
for (String name : StringUtils.split(propertyName, "."))
{
for (String name : StringUtils.split(propertyName, ".")) {
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
object = invokeMethod(object, getterMethodName, new Class[]{}, new Object[]{});
}
return (E) object;
}
@@ -51,21 +50,16 @@ public class ReflectUtils
* 调用Setter方法, 仅匹配方法名。
* 支持多级,如:对象名.对象名.方法
*/
public static <E> void invokeSetter(Object obj, String propertyName, E value)
{
public static <E> void invokeSetter(Object obj, String propertyName, E value) {
Object object = obj;
String[] names = StringUtils.split(propertyName, ".");
for (int i = 0; i < names.length; i++)
{
if (i < names.length - 1)
{
for (int i = 0; i < names.length; i++) {
if (i < names.length - 1) {
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
}
else
{
object = invokeMethod(object, getterMethodName, new Class[]{}, new Object[]{});
} else {
String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, setterMethodName, new Object[] { value });
invokeMethodByName(object, setterMethodName, new Object[]{value});
}
}
}
@@ -74,21 +68,16 @@ public class ReflectUtils
* 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
*/
@SuppressWarnings("unchecked")
public static <E> E getFieldValue(final Object obj, final String fieldName)
{
public static <E> E getFieldValue(final Object obj, final String fieldName) {
Field field = getAccessibleField(obj, fieldName);
if (field == null)
{
if (field == null) {
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
return null;
}
E result = null;
try
{
try {
result = (E) field.get(obj);
}
catch (IllegalAccessException e)
{
} catch (IllegalAccessException e) {
logger.error("不可能抛出的异常{}", e.getMessage());
}
return result;
@@ -97,21 +86,16 @@ public class ReflectUtils
/**
* 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
*/
public static <E> void setFieldValue(final Object obj, final String fieldName, final E value)
{
public static <E> void setFieldValue(final Object obj, final String fieldName, final E value) {
Field field = getAccessibleField(obj, fieldName);
if (field == null)
{
if (field == null) {
// throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
return;
}
try
{
try {
field.set(obj, value);
}
catch (IllegalAccessException e)
{
} catch (IllegalAccessException e) {
logger.error("不可能抛出的异常: {}", e.getMessage());
}
}
@@ -123,25 +107,19 @@ public class ReflectUtils
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
final Object[] args)
{
if (obj == null || methodName == null)
{
final Object[] args) {
if (obj == null || methodName == null) {
return null;
}
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
if (method == null)
{
if (method == null) {
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
return null;
}
try
{
try {
return (E) method.invoke(obj, args);
}
catch (Exception e)
{
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
} catch (Exception e) {
String msg = "method: " + method + ", obj: " + obj + ", args: " + Arrays.toString(args);
throw convertReflectionExceptionToUnchecked(msg, e);
}
}
@@ -152,69 +130,45 @@ public class ReflectUtils
* 只匹配函数名,如果有多个同名函数调用第一个。
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args)
{
public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
Method method = getAccessibleMethodByName(obj, methodName, args.length);
if (method == null)
{
if (method == null) {
// 如果为空不报错,直接返回空。
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
return null;
}
try
{
try {
// 类型转换(将参数数据类型转换为目标方法参数类型)
Class<?>[] cs = method.getParameterTypes();
for (int i = 0; i < cs.length; i++)
{
if (args[i] != null && !args[i].getClass().equals(cs[i]))
{
if (cs[i] == String.class)
{
for (int i = 0; i < cs.length; i++) {
if (args[i] != null && !args[i].getClass().equals(cs[i])) {
if (cs[i] == String.class) {
args[i] = Convert.toStr(args[i]);
if (StringUtils.endsWith((String) args[i], ".0"))
{
if (StringUtils.endsWith((String) args[i], ".0")) {
args[i] = StringUtils.substringBefore((String) args[i], ".0");
}
}
else if (cs[i] == Integer.class)
{
} else if (cs[i] == Integer.class) {
args[i] = Convert.toInt(args[i]);
}
else if (cs[i] == Long.class)
{
} else if (cs[i] == Long.class) {
args[i] = Convert.toLong(args[i]);
}
else if (cs[i] == Double.class)
{
} else if (cs[i] == Double.class) {
args[i] = Convert.toDouble(args[i]);
}
else if (cs[i] == Float.class)
{
} else if (cs[i] == Float.class) {
args[i] = Convert.toFloat(args[i]);
}
else if (cs[i] == Date.class)
{
if (args[i] instanceof String)
{
} else if (cs[i] == Date.class) {
if (args[i] instanceof String) {
args[i] = DateUtils.parseDate(args[i]);
}
else
{
} else {
args[i] = DateUtil.getJavaDate((Double) args[i]);
}
}
else if (cs[i] == boolean.class || cs[i] == Boolean.class)
{
} else if (cs[i] == boolean.class || cs[i] == Boolean.class) {
args[i] = Convert.toBool(args[i]);
}
}
}
return (E) method.invoke(obj, args);
}
catch (Exception e)
{
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
} catch (Exception e) {
String msg = "method: " + method + ", obj: " + obj + ", args: " + Arrays.toString(args);
throw convertReflectionExceptionToUnchecked(msg, e);
}
}
@@ -223,24 +177,18 @@ public class ReflectUtils
* 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
*/
public static Field getAccessibleField(final Object obj, final String fieldName)
{
public static Field getAccessibleField(final Object obj, final String fieldName) {
// 为空不报错。直接返回 null
if (obj == null)
{
if (obj == null) {
return null;
}
Validate.notBlank(fieldName, "fieldName can't be blank");
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass())
{
try
{
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
Field field = superClass.getDeclaredField(fieldName);
makeAccessible(field);
makeAccessible(field, obj);
return field;
}
catch (NoSuchFieldException e)
{
} catch (NoSuchFieldException e) {
continue;
}
}
@@ -254,25 +202,18 @@ public class ReflectUtils
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethod(final Object obj, final String methodName,
final Class<?>... parameterTypes)
{
final Class<?>... parameterTypes) {
// 为空不报错。直接返回 null
if (obj == null)
{
if (obj == null) {
return null;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
{
try
{
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
try {
Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
makeAccessible(method);
makeAccessible(method, obj);
return method;
}
catch (NoSuchMethodException e)
{
continue;
} catch (NoSuchMethodException ignored) {
}
}
return null;
@@ -284,22 +225,17 @@ public class ReflectUtils
* 只匹配函数名。
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum)
{
public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum) {
// 为空不报错。直接返回 null
if (obj == null)
{
if (obj == null) {
return null;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
{
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
Method[] methods = searchType.getDeclaredMethods();
for (Method method : methods)
{
if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum)
{
makeAccessible(method);
for (Method method : methods) {
if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum) {
makeAccessible(method, obj);
return method;
}
}
@@ -310,11 +246,9 @@ public class ReflectUtils
/**
* 改变private/protected的方法为public尽量不调用实际改动的语句避免JDK的SecurityManager抱怨。
*/
public static void makeAccessible(Method method)
{
public static void makeAccessible(Method method, Object obj) {
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
&& !method.isAccessible())
{
&& !method.canAccess(obj)) {
method.setAccessible(true);
}
}
@@ -322,11 +256,9 @@ public class ReflectUtils
/**
* 改变private/protected的成员变量为public尽量不调用实际改动的语句避免JDK的SecurityManager抱怨。
*/
public static void makeAccessible(Field field)
{
public static void makeAccessible(Field field, Object obj) {
if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
|| Modifier.isFinal(field.getModifiers())) && !field.isAccessible())
{
|| Modifier.isFinal(field.getModifiers())) && !field.canAccess(obj)) {
field.setAccessible(true);
}
}
@@ -336,8 +268,7 @@ public class ReflectUtils
* 如无法找到, 返回Object.class.
*/
@SuppressWarnings("unchecked")
public static <T> Class<T> getClassGenricType(final Class clazz)
{
public static <T> Class<T> getClassGenricType(final Class clazz) {
return getClassGenricType(clazz, 0);
}
@@ -345,26 +276,22 @@ public class ReflectUtils
* 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
* 如无法找到, 返回Object.class.
*/
public static Class getClassGenricType(final Class clazz, final int index)
{
public static Class getClassGenricType(final Class clazz, final int index) {
Type genType = clazz.getGenericSuperclass();
if (!(genType instanceof ParameterizedType))
{
if (!(genType instanceof ParameterizedType)) {
logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType");
return Object.class;
}
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if (index >= params.length || index < 0)
{
if (index >= params.length || index < 0) {
logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
+ params.length);
return Object.class;
}
if (!(params[index] instanceof Class))
{
if (!(params[index] instanceof Class)) {
logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
return Object.class;
}
@@ -372,18 +299,14 @@ public class ReflectUtils
return (Class) params[index];
}
public static Class<?> getUserClass(Object instance)
{
if (instance == null)
{
public static Class<?> getUserClass(Object instance) {
if (instance == null) {
throw new RuntimeException("Instance must not be null");
}
Class clazz = instance.getClass();
if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR))
{
if (clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
Class<?> superClass = clazz.getSuperclass();
if (superClass != null && !Object.class.equals(superClass))
{
if (superClass != null && !Object.class.equals(superClass)) {
return superClass;
}
}
@@ -394,15 +317,11 @@ public class ReflectUtils
/**
* 将反射时的checked exception转换为unchecked exception.
*/
public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e)
{
public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e) {
if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
|| e instanceof NoSuchMethodException)
{
|| e instanceof NoSuchMethodException) {
return new IllegalArgumentException(msg, e);
}
else if (e instanceof InvocationTargetException)
{
} else if (e instanceof InvocationTargetException) {
return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());
}
return new RuntimeException(msg, e);

View File

@@ -3,6 +3,7 @@ package com.ruoyi.common.core.web.controller;
import java.beans.PropertyEditorSupport;
import java.util.Date;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.WebDataBinder;
@@ -16,25 +17,21 @@ import com.ruoyi.common.core.web.page.TableDataInfo;
/**
* web层通用数据处理
*
*
* @author ruoyi
*/
public class BaseController
{
public class BaseController {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 将前台传递过来的日期格式的字符串自动转化为Date类型
*/
@InitBinder
public void initBinder(WebDataBinder binder)
{
public void initBinder(WebDataBinder binder) {
// Date 类型转换
binder.registerCustomEditor(Date.class, new PropertyEditorSupport()
{
binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text)
{
public void setAsText(String text) {
setValue(DateUtils.parseDate(text));
}
});
@@ -43,25 +40,22 @@ public class BaseController
/**
* 设置请求分页数据
*/
protected void startPage()
{
protected void startPage() {
PageUtils.startPage();
}
/**
* 清理分页的线程变量
*/
protected void clearPage()
{
protected void clearPage() {
PageUtils.clearPage();
}
/**
* 响应请求分页数据
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
protected TableDataInfo getDataTable(List<?> list)
{
@SuppressWarnings({"rawtypes", "unchecked"})
protected TableDataInfo getDataTable(List<?> list) {
TableDataInfo rspData = new TableDataInfo();
rspData.setCode(HttpStatus.SUCCESS);
rspData.setRows(list);
@@ -73,70 +67,62 @@ public class BaseController
/**
* 返回成功
*/
public AjaxResult success()
{
public AjaxResult success() {
return AjaxResult.success();
}
/**
* 返回成功消息
*/
public AjaxResult success(String message)
{
public AjaxResult success(String message) {
return AjaxResult.success(message);
}
/**
* 返回成功消息
*/
public AjaxResult success(Object data)
{
public AjaxResult success(Object data) {
return AjaxResult.success(data);
}
/**
* 返回失败消息
*/
public AjaxResult error()
{
public AjaxResult error() {
return AjaxResult.error();
}
/**
* 返回失败消息
*/
public AjaxResult error(String message)
{
public AjaxResult error(String message) {
return AjaxResult.error(message);
}
/**
* 返回警告消息
*/
public AjaxResult warn(String message)
{
public AjaxResult warn(String message) {
return AjaxResult.warn(message);
}
/**
* 响应返回结果
*
*
* @param rows 影响行数
* @return 操作结果
*/
protected AjaxResult toAjax(int rows)
{
protected AjaxResult toAjax(int rows) {
return rows > 0 ? AjaxResult.success() : AjaxResult.error();
}
/**
* 响应返回结果
*
*
* @param result 结果
* @return 操作结果
*/
protected AjaxResult toAjax(boolean result)
{
protected AjaxResult toAjax(boolean result) {
return result ? success() : error();
}
}

View File

@@ -1,7 +1,7 @@
package com.ruoyi.common.core.xss;
import javax.validation.Constraint;
import javax.validation.Payload;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

View File

@@ -2,8 +2,8 @@ package com.ruoyi.common.core.xss;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import com.ruoyi.common.core.utils.StringUtils;
/**

View File

@@ -2,6 +2,7 @@ package com.ruoyi.common.datascope.aspect;
import java.util.ArrayList;
import java.util.List;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@@ -18,13 +19,12 @@ import com.ruoyi.system.api.model.LoginUser;
/**
* 数据过滤处理
*
*
* @author ruoyi
*/
@Aspect
@Component
public class DataScopeAspect
{
public class DataScopeAspect {
/**
* 全部数据权限
*/
@@ -56,22 +56,18 @@ public class DataScopeAspect
public static final String DATA_SCOPE = "dataScope";
@Before("@annotation(controllerDataScope)")
public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable
{
public void doBefore(JoinPoint point, DataScope controllerDataScope) {
clearDataScope(point);
handleDataScope(point, controllerDataScope);
}
protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope)
{
protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope) {
// 获取当前的用户
LoginUser loginUser = SecurityUtils.getLoginUser();
if (StringUtils.isNotNull(loginUser))
{
if (StringUtils.isNotNull(loginUser)) {
SysUser currentUser = loginUser.getSysUser();
// 如果是超级管理员,则不过滤数据
if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin())
{
if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) {
String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), SecurityContextHolder.getPermission());
dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
controllerDataScope.userAlias(), permission);
@@ -81,60 +77,44 @@ public class DataScopeAspect
/**
* 数据范围过滤
*
* @param joinPoint 切点
* @param user 用户
* @param deptAlias 部门别名
* @param userAlias 用户别名
*
* @param joinPoint 切点
* @param user 用户
* @param deptAlias 部门别名
* @param userAlias 用户别名
* @param permission 权限字符
*/
public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias, String permission)
{
public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias, String permission) {
StringBuilder sqlString = new StringBuilder();
List<String> conditions = new ArrayList<String>();
for (SysRole role : user.getRoles())
{
for (SysRole role : user.getRoles()) {
String dataScope = role.getDataScope();
if (!DATA_SCOPE_CUSTOM.equals(dataScope) && conditions.contains(dataScope))
{
if (!DATA_SCOPE_CUSTOM.equals(dataScope) && conditions.contains(dataScope)) {
continue;
}
if (StringUtils.isNotEmpty(permission) && StringUtils.isNotEmpty(role.getPermissions())
&& !StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
{
&& !StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission))) {
continue;
}
if (DATA_SCOPE_ALL.equals(dataScope))
{
if (DATA_SCOPE_ALL.equals(dataScope)) {
sqlString = new StringBuilder();
conditions.add(dataScope);
break;
}
else if (DATA_SCOPE_CUSTOM.equals(dataScope))
{
} else if (DATA_SCOPE_CUSTOM.equals(dataScope)) {
sqlString.append(StringUtils.format(
" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias,
role.getRoleId()));
}
else if (DATA_SCOPE_DEPT.equals(dataScope))
{
} else if (DATA_SCOPE_DEPT.equals(dataScope)) {
sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
}
else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
{
} else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) {
sqlString.append(StringUtils.format(
" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
deptAlias, user.getDeptId(), user.getDeptId()));
}
else if (DATA_SCOPE_SELF.equals(dataScope))
{
if (StringUtils.isNotBlank(userAlias))
{
} else if (DATA_SCOPE_SELF.equals(dataScope)) {
if (StringUtils.isNotBlank(userAlias)) {
sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));
}
else
{
} else {
// 数据权限为仅本人且没有userAlias别名不查询任何数据
sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));
}
@@ -143,17 +123,13 @@ public class DataScopeAspect
}
// 多角色情况下所有角色都不包含传递过来的权限字符这个时候sqlString也会为空所以要限制一下,不查询任何数据
if (StringUtils.isEmpty(conditions))
{
if (StringUtils.isEmpty(conditions)) {
sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));
}
if (StringUtils.isNotBlank(sqlString.toString()))
{
if (StringUtils.isNotBlank(sqlString.toString())) {
Object params = joinPoint.getArgs()[0];
if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
{
BaseEntity baseEntity = (BaseEntity) params;
if (StringUtils.isNotNull(params) && params instanceof BaseEntity baseEntity) {
baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
}
}
@@ -162,12 +138,9 @@ public class DataScopeAspect
/**
* 拼接权限sql前先清空params.dataScope参数防止注入
*/
private void clearDataScope(final JoinPoint joinPoint)
{
private void clearDataScope(final JoinPoint joinPoint) {
Object params = joinPoint.getArgs()[0];
if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
{
BaseEntity baseEntity = (BaseEntity) params;
if (StringUtils.isNotNull(params) && params instanceof BaseEntity baseEntity) {
baseEntity.getParams().put(DATA_SCOPE, "");
}
}

View File

@@ -20,14 +20,15 @@
<!-- Druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- Dynamic DataSource -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>${dynamic-ds.version}</version>
</dependency>

View File

@@ -2,8 +2,9 @@ package com.ruoyi.common.log.aspect;
import java.util.Collection;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
@@ -31,19 +32,22 @@ import com.ruoyi.system.api.domain.SysOperLog;
/**
* 操作日志记录处理
*
*
* @author ruoyi
*/
@Aspect
@Component
public class LogAspect
{
public class LogAspect {
private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
/** 排除敏感属性字段 */
public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };
/**
* 排除敏感属性字段
*/
public static final String[] EXCLUDE_PROPERTIES = {"password", "oldPassword", "newPassword", "confirmPassword"};
/** 计算操作消耗时间 */
/**
* 计算操作消耗时间
*/
private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>("Cost Time");
@Autowired
@@ -53,8 +57,7 @@ public class LogAspect
* 处理请求前执行
*/
@Before(value = "@annotation(controllerLog)")
public void boBefore(JoinPoint joinPoint, Log controllerLog)
{
public void boBefore(JoinPoint joinPoint, Log controllerLog) {
TIME_THREADLOCAL.set(System.currentTimeMillis());
}
@@ -64,27 +67,23 @@ public class LogAspect
* @param joinPoint 切点
*/
@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult)
{
public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
handleLog(joinPoint, controllerLog, null, jsonResult);
}
/**
* 拦截异常操作
*
*
* @param joinPoint 切点
* @param e 异常
* @param e 异常
*/
@AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e)
{
public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
handleLog(joinPoint, controllerLog, e, null);
}
protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult)
{
try
{
protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
try {
// *========数据库日志=========*//
SysOperLog operLog = new SysOperLog();
operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
@@ -93,13 +92,11 @@ public class LogAspect
operLog.setOperIp(ip);
operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));
String username = SecurityUtils.getUsername();
if (StringUtils.isNotBlank(username))
{
if (StringUtils.isNotBlank(username)) {
operLog.setOperName(username);
}
if (e != null)
{
if (e != null) {
operLog.setStatus(BusinessStatus.FAIL.ordinal());
operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
}
@@ -115,28 +112,22 @@ public class LogAspect
operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());
// 保存数据库
asyncLogService.saveSysLog(operLog);
}
catch (Exception exp)
{
} catch (Exception exp) {
// 记录本地异常日志
log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace();
}
finally
{
} finally {
TIME_THREADLOCAL.remove();
}
}
/**
* 获取注解中对方法的描述信息 用于Controller层注解
*
* @param log 日志
*
* @param log 日志
* @param operLog 操作日志
* @throws Exception
*/
public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) throws Exception
{
public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) throws Exception {
// 设置action动作
operLog.setBusinessType(log.businessType().ordinal());
// 设置标题
@@ -144,36 +135,30 @@ public class LogAspect
// 设置操作人类别
operLog.setOperatorType(log.operatorType().ordinal());
// 是否需要保存request参数和值
if (log.isSaveRequestData())
{
if (log.isSaveRequestData()) {
// 获取参数的信息,传入到数据库中。
setRequestValue(joinPoint, operLog, log.excludeParamNames());
}
// 是否需要保存response参数和值
if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult))
{
if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult)) {
operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000));
}
}
/**
* 获取请求的参数放到log中
*
*
* @param operLog 操作日志
* @throws Exception 异常
*/
private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception
{
private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception {
String requestMethod = operLog.getRequestMethod();
Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
if (StringUtils.isEmpty(paramsMap)
&& (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)))
{
&& (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod))) {
String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
operLog.setOperParam(StringUtils.substring(params, 0, 2000));
}
else
{
} else {
operLog.setOperParam(StringUtils.substring(JSON.toJSONString(paramsMap, excludePropertyPreFilter(excludeParamNames)), 0, 2000));
}
}
@@ -181,64 +166,48 @@ public class LogAspect
/**
* 参数拼装
*/
private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames)
{
String params = "";
if (paramsArray != null && paramsArray.length > 0)
{
for (Object o : paramsArray)
{
if (StringUtils.isNotNull(o) && !isFilterObject(o))
{
try
{
private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) {
StringBuilder params = new StringBuilder();
if (paramsArray != null) {
for (Object o : paramsArray) {
if (StringUtils.isNotNull(o) && !isFilterObject(o)) {
try {
String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter(excludeParamNames));
params += jsonObj.toString() + " ";
}
catch (Exception e)
{
params.append(jsonObj).append(" ");
} catch (Exception ignored) {
}
}
}
}
return params.trim();
return params.toString().trim();
}
/**
* 忽略敏感属性
*/
public PropertyPreExcludeFilter excludePropertyPreFilter(String[] excludeParamNames)
{
public PropertyPreExcludeFilter excludePropertyPreFilter(String[] excludeParamNames) {
return new PropertyPreExcludeFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES, excludeParamNames));
}
/**
* 判断是否需要过滤的对象。
*
*
* @param o 对象信息。
* @return 如果是需要过滤的对象则返回true否则返回false。
*/
@SuppressWarnings("rawtypes")
public boolean isFilterObject(final Object o)
{
public boolean isFilterObject(final Object o) {
Class<?> clazz = o.getClass();
if (clazz.isArray())
{
if (clazz.isArray()) {
return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
}
else if (Collection.class.isAssignableFrom(clazz))
{
} else if (Collection.class.isAssignableFrom(clazz)) {
Collection collection = (Collection) o;
for (Object value : collection)
{
for (Object value : collection) {
return value instanceof MultipartFile;
}
}
else if (Map.class.isAssignableFrom(clazz))
{
} else if (Map.class.isAssignableFrom(clazz)) {
Map map = (Map) o;
for (Object value : map.entrySet())
{
for (Object value : map.entrySet()) {
Map.Entry entry = (Map.Entry) value;
return entry.getValue() instanceof MultipartFile;
}

View File

@@ -2,7 +2,7 @@ package com.ruoyi.common.redis.configure;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -18,7 +18,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
@EnableCaching
@AutoConfigureBefore(RedisAutoConfiguration.class)
public class RedisConfig extends CachingConfigurerSupport
public class RedisConfig implements CachingConfigurer
{
@Bean
@SuppressWarnings(value = { "unchecked", "rawtypes" })

View File

@@ -1,6 +1,8 @@
package com.ruoyi.common.security.annotation;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.*;
/**
@@ -17,11 +19,15 @@ public @interface EnableRyFeignClients
{
String[] value() default {};
@AliasFor(annotation = EnableFeignClients.class)
String[] basePackages() default { "com.ruoyi" };
@AliasFor(annotation = EnableFeignClients.class)
Class<?>[] basePackageClasses() default {};
@AliasFor(annotation = EnableFeignClients.class)
Class<?>[] defaultConfiguration() default {};
@AliasFor(annotation = EnableFeignClients.class)
Class<?>[] clients() default {};
}

View File

@@ -1,7 +1,8 @@
package com.ruoyi.common.security.feign;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import com.ruoyi.common.core.constant.SecurityConstants;
import com.ruoyi.common.core.utils.ServletUtils;
@@ -12,38 +13,31 @@ import feign.RequestTemplate;
/**
* feign 请求拦截器
*
*
* @author ruoyi
*/
@Component
public class FeignRequestInterceptor implements RequestInterceptor
{
public class FeignRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate)
{
public void apply(RequestTemplate requestTemplate) {
HttpServletRequest httpServletRequest = ServletUtils.getRequest();
if (StringUtils.isNotNull(httpServletRequest))
{
if (StringUtils.isNotNull(httpServletRequest)) {
Map<String, String> headers = ServletUtils.getHeaders(httpServletRequest);
// 传递用户信息请求头,防止丢失
String userId = headers.get(SecurityConstants.DETAILS_USER_ID);
if (StringUtils.isNotEmpty(userId))
{
if (StringUtils.isNotEmpty(userId)) {
requestTemplate.header(SecurityConstants.DETAILS_USER_ID, userId);
}
String userKey = headers.get(SecurityConstants.USER_KEY);
if (StringUtils.isNotEmpty(userKey))
{
if (StringUtils.isNotEmpty(userKey)) {
requestTemplate.header(SecurityConstants.USER_KEY, userKey);
}
String userName = headers.get(SecurityConstants.DETAILS_USERNAME);
if (StringUtils.isNotEmpty(userName))
{
if (StringUtils.isNotEmpty(userName)) {
requestTemplate.header(SecurityConstants.DETAILS_USERNAME, userName);
}
String authentication = headers.get(SecurityConstants.AUTHORIZATION_HEADER);
if (StringUtils.isNotEmpty(authentication))
{
if (StringUtils.isNotEmpty(authentication)) {
requestTemplate.header(SecurityConstants.AUTHORIZATION_HEADER, authentication);
}

View File

@@ -17,7 +17,7 @@ import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
/**
* 全局异常处理器
@@ -124,7 +124,7 @@ public class GlobalExceptionHandler
public AjaxResult handleBindException(BindException e)
{
log.error(e.getMessage(), e);
String message = e.getAllErrors().get(0).getDefaultMessage();
String message = e.getAllErrors().getFirst().getDefaultMessage();
return AjaxResult.error(message);
}

View File

@@ -1,7 +1,7 @@
package com.ruoyi.common.security.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import com.ruoyi.common.core.constant.SecurityConstants;
@@ -18,13 +18,10 @@ import com.ruoyi.system.api.model.LoginUser;
*
* @author ruoyi
*/
public class HeaderInterceptor implements AsyncHandlerInterceptor
{
public class HeaderInterceptor implements AsyncHandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
if (!(handler instanceof HandlerMethod))
{
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true;
}
@@ -33,11 +30,9 @@ public class HeaderInterceptor implements AsyncHandlerInterceptor
SecurityContextHolder.setUserKey(ServletUtils.getHeader(request, SecurityConstants.USER_KEY));
String token = SecurityUtils.getToken();
if (StringUtils.isNotEmpty(token))
{
if (StringUtils.isNotEmpty(token)) {
LoginUser loginUser = AuthUtil.getLoginUser(token);
if (StringUtils.isNotNull(loginUser))
{
if (StringUtils.isNotNull(loginUser)) {
AuthUtil.verifyLoginUserExpire(loginUser);
SecurityContextHolder.set(SecurityConstants.LOGIN_USER, loginUser);
}
@@ -47,8 +42,7 @@ public class HeaderInterceptor implements AsyncHandlerInterceptor
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception
{
throws Exception {
SecurityContextHolder.remove();
}
}

View File

@@ -3,7 +3,8 @@ package com.ruoyi.common.security.service;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -21,12 +22,11 @@ import com.ruoyi.system.api.model.LoginUser;
/**
* token验证处理
*
*
* @author ruoyi
*/
@Component
public class TokenService
{
public class TokenService {
private static final Logger log = LoggerFactory.getLogger(TokenService.class);
@Autowired
@@ -45,8 +45,7 @@ public class TokenService
/**
* 创建令牌
*/
public Map<String, Object> createToken(LoginUser loginUser)
{
public Map<String, Object> createToken(LoginUser loginUser) {
String token = IdUtils.fastUUID();
Long userId = loginUser.getSysUser().getUserId();
String userName = loginUser.getSysUser().getUserName();
@@ -74,8 +73,7 @@ public class TokenService
*
* @return 用户信息
*/
public LoginUser getLoginUser()
{
public LoginUser getLoginUser() {
return getLoginUser(ServletUtils.getRequest());
}
@@ -84,8 +82,7 @@ public class TokenService
*
* @return 用户信息
*/
public LoginUser getLoginUser(HttpServletRequest request)
{
public LoginUser getLoginUser(HttpServletRequest request) {
// 获取请求携带的令牌
String token = SecurityUtils.getToken(request);
return getLoginUser(token);
@@ -96,20 +93,15 @@ public class TokenService
*
* @return 用户信息
*/
public LoginUser getLoginUser(String token)
{
public LoginUser getLoginUser(String token) {
LoginUser user = null;
try
{
if (StringUtils.isNotEmpty(token))
{
try {
if (StringUtils.isNotEmpty(token)) {
String userkey = JwtUtils.getUserKey(token);
user = redisService.getCacheObject(getTokenKey(userkey));
return user;
}
}
catch (Exception e)
{
} catch (Exception e) {
log.error("获取用户信息异常'{}'", e.getMessage());
}
return user;
@@ -118,10 +110,8 @@ public class TokenService
/**
* 设置用户身份信息
*/
public void setLoginUser(LoginUser loginUser)
{
if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken()))
{
public void setLoginUser(LoginUser loginUser) {
if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())) {
refreshToken(loginUser);
}
}
@@ -129,10 +119,8 @@ public class TokenService
/**
* 删除用户缓存信息
*/
public void delLoginUser(String token)
{
if (StringUtils.isNotEmpty(token))
{
public void delLoginUser(String token) {
if (StringUtils.isNotEmpty(token)) {
String userkey = JwtUtils.getUserKey(token);
redisService.deleteObject(getTokenKey(userkey));
}
@@ -140,15 +128,11 @@ public class TokenService
/**
* 验证令牌有效期相差不足120分钟自动刷新缓存
*
* @param loginUser
*/
public void verifyToken(LoginUser loginUser)
{
public void verifyToken(LoginUser loginUser) {
long expireTime = loginUser.getExpireTime();
long currentTime = System.currentTimeMillis();
if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
{
if (expireTime - currentTime <= MILLIS_MINUTE_TEN) {
refreshToken(loginUser);
}
}
@@ -158,8 +142,7 @@ public class TokenService
*
* @param loginUser 登录信息
*/
public void refreshToken(LoginUser loginUser)
{
public void refreshToken(LoginUser loginUser) {
loginUser.setLoginTime(System.currentTimeMillis());
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
// 根据uuid将loginUser缓存
@@ -167,8 +150,7 @@ public class TokenService
redisService.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
}
private String getTokenKey(String token)
{
private String getTokenKey(String token) {
return ACCESS_TOKEN + token;
}
}

View File

@@ -1,6 +1,6 @@
package com.ruoyi.common.security.utils;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import com.ruoyi.common.core.constant.SecurityConstants;
import com.ruoyi.common.core.constant.TokenConstants;
@@ -11,56 +11,49 @@ import com.ruoyi.system.api.model.LoginUser;
/**
* 权限获取工具类
*
*
* @author ruoyi
*/
public class SecurityUtils
{
public class SecurityUtils {
/**
* 获取用户ID
*/
public static Long getUserId()
{
public static Long getUserId() {
return SecurityContextHolder.getUserId();
}
/**
* 获取用户名称
*/
public static String getUsername()
{
public static String getUsername() {
return SecurityContextHolder.getUserName();
}
/**
* 获取用户key
*/
public static String getUserKey()
{
public static String getUserKey() {
return SecurityContextHolder.getUserKey();
}
/**
* 获取登录用户信息
*/
public static LoginUser getLoginUser()
{
public static LoginUser getLoginUser() {
return SecurityContextHolder.get(SecurityConstants.LOGIN_USER, LoginUser.class);
}
/**
* 获取请求token
*/
public static String getToken()
{
public static String getToken() {
return getToken(ServletUtils.getRequest());
}
/**
* 根据request获取请求token
*/
public static String getToken(HttpServletRequest request)
{
public static String getToken(HttpServletRequest request) {
// 从header获取token标识
String token = request.getHeader(TokenConstants.AUTHENTICATION);
return replaceTokenPrefix(token);
@@ -69,11 +62,9 @@ public class SecurityUtils
/**
* 裁剪token前缀
*/
public static String replaceTokenPrefix(String token)
{
public static String replaceTokenPrefix(String token) {
// 如果前端设置了令牌前缀,则裁剪掉前缀
if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX))
{
if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX)) {
token = token.replaceFirst(TokenConstants.PREFIX, "");
}
return token;
@@ -81,12 +72,11 @@ public class SecurityUtils
/**
* 是否为管理员
*
*
* @param userId 用户ID
* @return 结果
*/
public static boolean isAdmin(Long userId)
{
public static boolean isAdmin(Long userId) {
return userId != null && 1L == userId;
}
@@ -96,8 +86,7 @@ public class SecurityUtils
* @param password 密码
* @return 加密字符串
*/
public static String encryptPassword(String password)
{
public static String encryptPassword(String password) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.encode(password);
}
@@ -105,12 +94,11 @@ public class SecurityUtils
/**
* 判断密码是否相同
*
* @param rawPassword 真实密码
* @param rawPassword 真实密码
* @param encodedPassword 加密后字符
* @return 结果
*/
public static boolean matchesPassword(String rawPassword, String encodedPassword)
{
public static boolean matchesPassword(String rawPassword, String encodedPassword) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.matches(rawPassword, encodedPassword);
}

View File

@@ -24,10 +24,14 @@
</dependency>
<!-- Swagger -->
<!-- <dependency>-->
<!-- <groupId>io.springfox</groupId>-->
<!-- <artifactId>springfox-swagger2</artifactId>-->
<!-- <version>${swagger.fox.version}</version>-->
<!-- </dependency>-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.fox.version}</version>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
</dependencies>

View File

@@ -9,115 +9,115 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.Contact;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.service.SecurityScheme;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.ApiSelectorBuilder;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
//import springfox.documentation.builders.ApiInfoBuilder;
//import springfox.documentation.builders.PathSelectors;
//import springfox.documentation.builders.RequestHandlerSelectors;
//import springfox.documentation.service.ApiInfo;
//import springfox.documentation.service.ApiKey;
//import springfox.documentation.service.AuthorizationScope;
//import springfox.documentation.service.Contact;
//import springfox.documentation.service.SecurityReference;
//import springfox.documentation.service.SecurityScheme;
//import springfox.documentation.spi.DocumentationType;
//import springfox.documentation.spi.service.contexts.SecurityContext;
//import springfox.documentation.spring.web.plugins.ApiSelectorBuilder;
//import springfox.documentation.spring.web.plugins.Docket;
//import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
@EnableConfigurationProperties(SwaggerProperties.class)
@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true)
@Import({SwaggerBeanPostProcessor.class, SwaggerWebConfiguration.class})
//@Configuration
//@EnableSwagger2
//@EnableConfigurationProperties(SwaggerProperties.class)
//@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true)
//@Import({SwaggerBeanPostProcessor.class, SwaggerWebConfiguration.class})
public class SwaggerAutoConfiguration
{
/**
* 默认的排除路径排除Spring Boot默认的错误处理路径和端点
*/
private static final List<String> DEFAULT_EXCLUDE_PATH = Arrays.asList("/error", "/actuator/**");
private static final String BASE_PATH = "/**";
@Bean
public Docket api(SwaggerProperties swaggerProperties)
{
// base-path处理
if (swaggerProperties.getBasePath().isEmpty())
{
swaggerProperties.getBasePath().add(BASE_PATH);
}
// noinspection unchecked
List<Predicate<String>> basePath = new ArrayList<Predicate<String>>();
swaggerProperties.getBasePath().forEach(path -> basePath.add(PathSelectors.ant(path)));
// exclude-path处理
if (swaggerProperties.getExcludePath().isEmpty())
{
swaggerProperties.getExcludePath().addAll(DEFAULT_EXCLUDE_PATH);
}
List<Predicate<String>> excludePath = new ArrayList<>();
swaggerProperties.getExcludePath().forEach(path -> excludePath.add(PathSelectors.ant(path)));
ApiSelectorBuilder builder = new Docket(DocumentationType.SWAGGER_2).host(swaggerProperties.getHost())
.apiInfo(apiInfo(swaggerProperties)).select()
.apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()));
swaggerProperties.getBasePath().forEach(p -> builder.paths(PathSelectors.ant(p)));
swaggerProperties.getExcludePath().forEach(p -> builder.paths(PathSelectors.ant(p).negate()));
return builder.build().securitySchemes(securitySchemes()).securityContexts(securityContexts()).pathMapping("/");
}
/**
* 安全模式这里指定token通过Authorization头请求头传递
*/
private List<SecurityScheme> securitySchemes()
{
List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
apiKeyList.add(new ApiKey("Authorization", "Authorization", "header"));
return apiKeyList;
}
/**
* 安全上下文
*/
private List<SecurityContext> securityContexts()
{
List<SecurityContext> securityContexts = new ArrayList<>();
securityContexts.add(
SecurityContext.builder()
.securityReferences(defaultAuth())
.operationSelector(o -> o.requestMappingPattern().matches("/.*"))
.build());
return securityContexts;
}
/**
* 默认的全局鉴权策略
*
* @return
*/
private List<SecurityReference> defaultAuth()
{
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
List<SecurityReference> securityReferences = new ArrayList<>();
securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
return securityReferences;
}
private ApiInfo apiInfo(SwaggerProperties swaggerProperties)
{
return new ApiInfoBuilder()
.title(swaggerProperties.getTitle())
.description(swaggerProperties.getDescription())
.license(swaggerProperties.getLicense())
.licenseUrl(swaggerProperties.getLicenseUrl())
.termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
.contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail()))
.version(swaggerProperties.getVersion())
.build();
}
// private static final List<String> DEFAULT_EXCLUDE_PATH = Arrays.asList("/error", "/actuator/**");
//
// private static final String BASE_PATH = "/**";
//
// @Bean
// public Docket api(SwaggerProperties swaggerProperties)
// {
// // base-path处理
// if (swaggerProperties.getBasePath().isEmpty())
// {
// swaggerProperties.getBasePath().add(BASE_PATH);
// }
// // noinspection unchecked
// List<Predicate<String>> basePath = new ArrayList<Predicate<String>>();
// swaggerProperties.getBasePath().forEach(path -> basePath.add(PathSelectors.ant(path)));
//
// // exclude-path处理
// if (swaggerProperties.getExcludePath().isEmpty())
// {
// swaggerProperties.getExcludePath().addAll(DEFAULT_EXCLUDE_PATH);
// }
//
// List<Predicate<String>> excludePath = new ArrayList<>();
// swaggerProperties.getExcludePath().forEach(path -> excludePath.add(PathSelectors.ant(path)));
//
// ApiSelectorBuilder builder = new Docket(DocumentationType.SWAGGER_2).host(swaggerProperties.getHost())
// .apiInfo(apiInfo(swaggerProperties)).select()
// .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()));
//
// swaggerProperties.getBasePath().forEach(p -> builder.paths(PathSelectors.ant(p)));
// swaggerProperties.getExcludePath().forEach(p -> builder.paths(PathSelectors.ant(p).negate()));
//
// return builder.build().securitySchemes(securitySchemes()).securityContexts(securityContexts()).pathMapping("/");
// }
//
// /**
// * 安全模式这里指定token通过Authorization头请求头传递
// */
// private List<SecurityScheme> securitySchemes()
// {
// List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
// apiKeyList.add(new ApiKey("Authorization", "Authorization", "header"));
// return apiKeyList;
// }
//
// /**
// * 安全上下文
// */
// private List<SecurityContext> securityContexts()
// {
// List<SecurityContext> securityContexts = new ArrayList<>();
// securityContexts.add(
// SecurityContext.builder()
// .securityReferences(defaultAuth())
// .operationSelector(o -> o.requestMappingPattern().matches("/.*"))
// .build());
// return securityContexts;
// }
//
// /**
// * 默认的全局鉴权策略
// *
// * @return
// */
// private List<SecurityReference> defaultAuth()
// {
// AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
// AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
// authorizationScopes[0] = authorizationScope;
// List<SecurityReference> securityReferences = new ArrayList<>();
// securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
// return securityReferences;
// }
//
// private ApiInfo apiInfo(SwaggerProperties swaggerProperties)
// {
// return new ApiInfoBuilder()
// .title(swaggerProperties.getTitle())
// .description(swaggerProperties.getDescription())
// .license(swaggerProperties.getLicense())
// .licenseUrl(swaggerProperties.getLicenseUrl())
// .termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
// .contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail()))
// .version(swaggerProperties.getVersion())
// .build();
// }
}

View File

@@ -4,8 +4,8 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider;
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
//import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider;
//import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
import java.lang.reflect.Field;
import java.util.List;
import java.util.stream.Collectors;
@@ -17,36 +17,36 @@ import java.util.stream.Collectors;
*/
public class SwaggerBeanPostProcessor implements BeanPostProcessor
{
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
{
if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider)
{
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
}
return bean;
}
private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings)
{
List<T> copy = mappings.stream().filter(mapping -> mapping.getPatternParser() == null)
.collect(Collectors.toList());
mappings.clear();
mappings.addAll(copy);
}
@SuppressWarnings("unchecked")
private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean)
{
try
{
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
field.setAccessible(true);
return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
}
catch (IllegalArgumentException | IllegalAccessException e)
{
throw new IllegalStateException(e);
}
}
// @Override
// public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
// {
// if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider)
// {
// customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
// }
// return bean;
// }
//
// private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings)
// {
// List<T> copy = mappings.stream().filter(mapping -> mapping.getPatternParser() == null)
// .collect(Collectors.toList());
// mappings.clear();
// mappings.addAll(copy);
// }
//
// @SuppressWarnings("unchecked")
// private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean)
// {
// try
// {
// Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
// field.setAccessible(true);
// return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
// }
// catch (IllegalArgumentException | IllegalAccessException e)
// {
// throw new IllegalStateException(e);
// }
// }
}