mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-03-18 03:32:02 +08:00
Merge remote-tracking branch 'origin/dev' into futuer/boot4
This commit is contained in:
@@ -47,7 +47,7 @@ public interface CacheNames {
|
||||
String SYS_USER_NAME = "sys_user_name#30d";
|
||||
|
||||
/**
|
||||
* 用户名称
|
||||
* 用户昵称
|
||||
*/
|
||||
String SYS_NICKNAME = "sys_nickname#30d";
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ public class FlowCopyDTO implements Serializable {
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户名称
|
||||
* 用户昵称
|
||||
*/
|
||||
private String userName;
|
||||
private String nickName;
|
||||
|
||||
}
|
||||
|
||||
@@ -48,7 +48,8 @@ public class StartProcessDTO implements Serializable {
|
||||
|
||||
public Map<String, Object> getVariables() {
|
||||
if (variables == null) {
|
||||
return new HashMap<>(16);
|
||||
variables = new HashMap<>(16);
|
||||
return variables;
|
||||
}
|
||||
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
|
||||
return variables;
|
||||
|
||||
@@ -30,7 +30,7 @@ public class UserOnlineDTO implements Serializable {
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 用户名称
|
||||
* 用户账号
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
|
||||
@@ -21,18 +21,18 @@ public interface UserService {
|
||||
String selectUserNameById(Long userId);
|
||||
|
||||
/**
|
||||
* 通过用户ID查询用户账户
|
||||
* 通过用户ID查询用户昵称
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 用户名称
|
||||
* @return 用户昵称
|
||||
*/
|
||||
String selectNicknameById(Long userId);
|
||||
|
||||
/**
|
||||
* 通过用户ID查询用户账户
|
||||
* 通过用户ID查询用户昵称
|
||||
*
|
||||
* @param userIds 用户ID 多个用逗号隔开
|
||||
* @return 用户名称
|
||||
* @return 用户昵称
|
||||
*/
|
||||
String selectNicknameByIds(String userIds);
|
||||
|
||||
@@ -93,11 +93,11 @@ public interface UserService {
|
||||
List<UserDTO> selectUsersByPostIds(List<Long> postIds);
|
||||
|
||||
/**
|
||||
* 根据用户 ID 列表查询用户名称映射关系
|
||||
* 根据用户 ID 列表查询用户昵称映射关系
|
||||
*
|
||||
* @param userIds 用户 ID 列表
|
||||
* @return Map,其中 key 为用户 ID,value 为对应的用户名称
|
||||
* @return Map,其中 key 为用户 ID,value 为对应的用户昵称
|
||||
*/
|
||||
Map<Long, String> selectUserNamesByIds(List<Long> userIds);
|
||||
Map<Long, String> selectUserNicksByIds(List<Long> userIds);
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import io.swagger.v3.oas.models.security.SecurityRequirement;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.doc.config.properties.SpringDocProperties;
|
||||
import org.dromara.common.doc.core.resolver.JavadocResolver;
|
||||
import org.dromara.common.doc.core.resolver.SaTokenAnnotationMetadataJavadocResolver;
|
||||
import org.dromara.common.doc.handler.OpenApiHandler;
|
||||
import org.springdoc.core.configuration.SpringDocConfiguration;
|
||||
import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
|
||||
@@ -84,8 +86,9 @@ public class SpringDocConfig {
|
||||
SecurityService securityParser,
|
||||
SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils,
|
||||
Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers,
|
||||
Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomisers, Optional<JavadocProvider> javadocProvider) {
|
||||
return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider);
|
||||
Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomisers, Optional<JavadocProvider> javadocProvider,
|
||||
List<JavadocResolver> javadocResolvers) {
|
||||
return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider, javadocResolvers);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,6 +115,14 @@ public class SpringDocConfig {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册SaToken JavaDoc权限注解解析器
|
||||
*/
|
||||
@Bean
|
||||
public JavadocResolver saTokenAnnotationJavadocResolver() {
|
||||
return new SaTokenAnnotationMetadataJavadocResolver();
|
||||
}
|
||||
|
||||
/**
|
||||
* 单独使用一个类便于判断 解决springdoc路径拼接重复问题
|
||||
*
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
package org.dromara.common.doc.core.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 存储权限框架注解解析后的权限和角色信息
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
@Data
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
public class SaTokenSecurityMetadata {
|
||||
|
||||
/**
|
||||
* 权限校验信息列表(对应 @SaCheckPermission 注解)
|
||||
*/
|
||||
private List<AuthInfo> permissions = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 角色校验信息列表(对应 @SaCheckRole 注解)
|
||||
*/
|
||||
private List<AuthInfo> roles = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 是否忽略校验(对应 @SaIgnore 注解)
|
||||
*/
|
||||
private boolean ignore = false;
|
||||
|
||||
/**
|
||||
* 添加权限信息
|
||||
*
|
||||
* @param values 权限值数组
|
||||
* @param mode 校验模式(AND/OR)
|
||||
* @param type 权限类型
|
||||
* @param orRoles 或角色数组
|
||||
*/
|
||||
public void addPermission(String[] values, String mode, String type, String[] orRoles) {
|
||||
if (values != null && values.length > 0) {
|
||||
AuthInfo authInfo = new AuthInfo();
|
||||
authInfo.setValues(values);
|
||||
authInfo.setMode(mode);
|
||||
authInfo.setType(type);
|
||||
if (orRoles != null && orRoles.length > 0) {
|
||||
authInfo.setOrValues(orRoles);
|
||||
authInfo.setOrType("role");
|
||||
}
|
||||
this.permissions.add(authInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加角色信息
|
||||
*
|
||||
* @param values 角色值数组
|
||||
* @param mode 校验模式(AND/OR)
|
||||
* @param type 角色类型
|
||||
*/
|
||||
public void addRole(String[] values, String mode, String type) {
|
||||
if (values != null && values.length > 0) {
|
||||
AuthInfo authInfo = new AuthInfo();
|
||||
authInfo.setValues(values);
|
||||
authInfo.setMode(mode);
|
||||
authInfo.setType(type);
|
||||
this.roles.add(authInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 Markdown 结构的权限说明
|
||||
*
|
||||
* @return Markdown 文本
|
||||
*/
|
||||
public String toMarkdownString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("<br><h3>访问权限</h3><br>");
|
||||
|
||||
if (ignore) {
|
||||
sb.append("> **权限策略**:忽略权限检查<br>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
if (!ignore && permissions.isEmpty() && roles.isEmpty()){
|
||||
sb.append("> **权限策略**:需要登录<br><br>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
if (!permissions.isEmpty()) {
|
||||
sb.append("**权限校验:**<br><br>");
|
||||
|
||||
permissions.forEach(p -> {
|
||||
String permTags = Arrays.stream(p.getValues())
|
||||
.map(v -> "`" + v + "`")
|
||||
.collect(Collectors.joining(p.getModeSymbol()));
|
||||
|
||||
sb.append("- ").append(permTags).append("<br>");
|
||||
|
||||
if (p.getOrValues() != null && p.getOrValues().length > 0) {
|
||||
String orTags = Arrays.stream(p.getOrValues())
|
||||
.map(v -> "`" + v + "`")
|
||||
.collect(Collectors.joining(p.getModeSymbol()));
|
||||
sb.append(" - 或角色:").append(orTags).append("<br>");
|
||||
}
|
||||
});
|
||||
|
||||
sb.append("<br>");
|
||||
}
|
||||
|
||||
if (!roles.isEmpty()) {
|
||||
sb.append("**角色校验:**<br><br>");
|
||||
|
||||
roles.forEach(r -> {
|
||||
|
||||
String roleTags = Arrays.stream(r.getValues())
|
||||
.map(v -> "`" + v + "`")
|
||||
.collect(Collectors.joining(r.getModeSymbol()));
|
||||
|
||||
sb.append("- ").append(roleTags).append("<br>");
|
||||
});
|
||||
}
|
||||
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* 认证信息
|
||||
*/
|
||||
@Data
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
public static class AuthInfo {
|
||||
|
||||
/**
|
||||
* 权限或角色值数组
|
||||
*/
|
||||
private String[] values;
|
||||
|
||||
/**
|
||||
* 校验模式(AND/OR)
|
||||
*/
|
||||
private String mode;
|
||||
|
||||
/**
|
||||
* 类型说明
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 或权限/角色值数组(用于权限校验时的或角色校验)
|
||||
*/
|
||||
private String[] orValues;
|
||||
|
||||
/**
|
||||
* 或值的类型(role/permission)
|
||||
*/
|
||||
private String orType;
|
||||
|
||||
/**
|
||||
* 重写mode的获取方法,返回符号而非文字
|
||||
* @return AND→&,OR→|,默认→&
|
||||
*/
|
||||
public String getModeSymbol() {
|
||||
if (mode == null) {
|
||||
return " & "; // 默认AND,返回&
|
||||
}
|
||||
return "AND".equalsIgnoreCase(mode) ? " & " : " | ";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package org.dromara.common.doc.core.resolver;
|
||||
|
||||
import cn.hutool.core.annotation.AnnotationUtil;
|
||||
import cn.hutool.core.util.ClassLoaderUtil;
|
||||
import io.swagger.v3.oas.models.Operation;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* 抽象元数据 Javadoc 解析器
|
||||
*
|
||||
* @param <M> 元数据类型
|
||||
* @author 秋辞未寒
|
||||
*/
|
||||
public abstract class AbstractMetadataJavadocResolver<M> implements JavadocResolver {
|
||||
|
||||
public static final int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
|
||||
public static final int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
|
||||
|
||||
private final Supplier<M> metadataProvider;
|
||||
|
||||
private final int order;
|
||||
|
||||
public AbstractMetadataJavadocResolver(Supplier<M> metadataProvider) {
|
||||
this(metadataProvider, LOWEST_PRECEDENCE);
|
||||
}
|
||||
|
||||
public AbstractMetadataJavadocResolver(Supplier<M> metadataProvider, int order) {
|
||||
this.metadataProvider = metadataProvider;
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolve(HandlerMethod handlerMethod, Operation operation) {
|
||||
return resolve(handlerMethod, operation, metadataProvider.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行解析并返回解析到的 Javadoc 内容
|
||||
* @param handlerMethod 处理器方法
|
||||
* @param operation Swagger Operation实例
|
||||
* @param metadata 元信息
|
||||
* @return 解析到的 Javadoc 内容
|
||||
*/
|
||||
public abstract String resolve(HandlerMethod handlerMethod, Operation operation, M metadata);
|
||||
|
||||
/**
|
||||
* 检查处理器方法所属的类上是否存在注解
|
||||
* @param handlerMethod 处理器方法
|
||||
* @param annotationClass 注解类
|
||||
* @return 是否存在注解
|
||||
*/
|
||||
public boolean hasClassAnnotation(HandlerMethod handlerMethod,Class<? extends Annotation> annotationClass){
|
||||
return AnnotationUtil.hasAnnotation(handlerMethod.getBeanType(), annotationClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查处理器方法所属的类上是否存在注解
|
||||
* @param handlerMethod 处理器方法
|
||||
* @param annotationTypeName 注解类名称
|
||||
* @return 是否存在注解
|
||||
*/
|
||||
public boolean hasClassAnnotation(HandlerMethod handlerMethod, String annotationTypeName){
|
||||
return AnnotationUtil.hasAnnotation(handlerMethod.getBeanType(), annotationTypeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查处理器方法上是否存在注解
|
||||
* @param handlerMethod 处理器方法
|
||||
* @param annotationClass 注解类
|
||||
* @return 是否存在注解
|
||||
*/
|
||||
public boolean hasMethodAnnotation(HandlerMethod handlerMethod,Class<? extends Annotation> annotationClass){
|
||||
return AnnotationUtil.hasAnnotation(handlerMethod.getMethod(), annotationClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查处理器方法上是否存在注解
|
||||
* @param handlerMethod 处理器方法
|
||||
* @param annotationTypeName 注解类名称
|
||||
* @return 是否存在注解
|
||||
*/
|
||||
public boolean hasMethodAnnotation(HandlerMethod handlerMethod, String annotationTypeName){
|
||||
return AnnotationUtil.hasAnnotation(handlerMethod.getMethod(), annotationTypeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查处理器方法上是否存在注解
|
||||
* @param handlerMethod 处理器方法
|
||||
* @param annotationClass 注解类
|
||||
* @return 是否存在注解
|
||||
*/
|
||||
public boolean hasAnnotation(HandlerMethod handlerMethod,Class<? extends Annotation> annotationClass){
|
||||
return this.hasClassAnnotation(handlerMethod, annotationClass) || this.hasMethodAnnotation(handlerMethod, annotationClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查处理器方法上是否存在注解
|
||||
* @param handlerMethod 处理器方法
|
||||
* @param annotationTypeName 注解类名称
|
||||
* @return 是否存在注解
|
||||
*/
|
||||
public boolean hasAnnotation(HandlerMethod handlerMethod, String annotationTypeName){
|
||||
return this.hasClassAnnotation(handlerMethod, annotationTypeName) || this.hasMethodAnnotation(handlerMethod, annotationTypeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取处理器方法所属类上的注解的值
|
||||
* @param handlerMethod 处理器方法
|
||||
* @param annotationClass 注解类
|
||||
* @return 注解的值
|
||||
*/
|
||||
public Map<String, Object> getClassAnnotationValueMap(HandlerMethod handlerMethod, Class<? extends Annotation> annotationClass) {
|
||||
return AnnotationUtil.getAnnotationValueMap(handlerMethod.getBeanType(), annotationClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取处理器方法所属类上的注解的值
|
||||
* @param handlerMethod 处理器方法
|
||||
* @param annotationClassName 注解类名称
|
||||
* @return 注解的值
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> getClassAnnotationValueMap(HandlerMethod handlerMethod, String annotationClassName) {
|
||||
Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) ClassLoaderUtil.loadClass(annotationClassName, false);
|
||||
return AnnotationUtil.getAnnotationValueMap(handlerMethod.getBeanType(), annotationClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取处理器方法上的注解的值
|
||||
* @param handlerMethod 处理器方法
|
||||
* @param annotationClass 注解类
|
||||
* @return 注解的值
|
||||
*/
|
||||
public Map<String, Object> getMethodAnnotationValueMap(HandlerMethod handlerMethod, Class<? extends Annotation> annotationClass) {
|
||||
return AnnotationUtil.getAnnotationValueMap(handlerMethod.getMethod(), annotationClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取处理器方法所属类上的注解的值
|
||||
* @param handlerMethod 处理器方法
|
||||
* @param annotationClassName 注解类名称
|
||||
* @return 注解的值
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> getMethodAnnotationValueMap(HandlerMethod handlerMethod, String annotationClassName) {
|
||||
Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) ClassLoaderUtil.loadClass(annotationClassName, false);
|
||||
return AnnotationUtil.getAnnotationValueMap(handlerMethod.getMethod(), annotationClass);
|
||||
}
|
||||
|
||||
private Map<String, Object> getAnnotationValueMap(AnnotatedElement annotatedElement, Class<? extends Annotation> annotationClass) {
|
||||
return AnnotationUtil.getAnnotationValueMap(annotatedElement, annotationClass);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.dromara.common.doc.core.resolver;
|
||||
|
||||
import io.swagger.v3.oas.models.Operation;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
|
||||
/**
|
||||
* Javadoc解析器接口
|
||||
*
|
||||
* @author echo
|
||||
* @author 秋辞未寒
|
||||
*/
|
||||
public interface JavadocResolver extends Comparable<JavadocResolver>, Ordered {
|
||||
|
||||
/**
|
||||
* 检查解析器是否支持解析 HandlerMethod
|
||||
* @param handlerMethod 处理器方法
|
||||
* @return 是否支持解析
|
||||
*/
|
||||
boolean supports(HandlerMethod handlerMethod);
|
||||
|
||||
/**
|
||||
* 执行解析并返回解析到的 Javadoc 内容
|
||||
* @param handlerMethod 处理器方法
|
||||
* @param operation Swagger Operation实例
|
||||
* @return 解析到的 Javadoc 内容
|
||||
*/
|
||||
String resolve(HandlerMethod handlerMethod, Operation operation);
|
||||
|
||||
/**
|
||||
* 获取解析器优先级
|
||||
*/
|
||||
default int getOrder() {
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取解析器的名称
|
||||
*
|
||||
* @return 解析器名称
|
||||
*/
|
||||
default String getName() {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
default int compareTo(@NotNull JavadocResolver o) {
|
||||
return Integer.compare(getOrder(), o.getOrder());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package org.dromara.common.doc.core.resolver;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.ClassLoaderUtil;
|
||||
import io.swagger.v3.oas.models.Operation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.doc.core.model.SaTokenSecurityMetadata;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* 基于JavaDoc的SaToken权限解析器
|
||||
*
|
||||
* @author echo
|
||||
* @author 秋辞未寒
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Slf4j
|
||||
public class SaTokenAnnotationMetadataJavadocResolver extends AbstractMetadataJavadocResolver<SaTokenSecurityMetadata> {
|
||||
|
||||
/**
|
||||
* 默认元数据提供者,每次解析都会创建一个新的元数据对象
|
||||
*/
|
||||
public static final Supplier<SaTokenSecurityMetadata> DEFAULT_METADATA_PROVIDER = SaTokenSecurityMetadata::new;
|
||||
|
||||
private static final String BASE_CLASS_NAME = "cn.dev33.satoken.annotation";
|
||||
private static final String SA_CHECK_ROLE_CLASS_NAME = BASE_CLASS_NAME + ".SaCheckRole";
|
||||
private static final String SA_CHECK_PERMISSION_CLASS_NAME = BASE_CLASS_NAME + ".SaCheckPermission";
|
||||
private static final String SA_IGNORE_CLASS_NAME = BASE_CLASS_NAME + ".SaIgnore";
|
||||
private static final String SA_CHECK_LOGIN_NAME = BASE_CLASS_NAME + ".SaCheckLogin";
|
||||
|
||||
private static final Class<? extends Annotation> SA_CHECK_ROLE_CLASS;
|
||||
private static final Class<? extends Annotation> SA_CHECK_PERMISSION_CLASS;
|
||||
private static final Class<? extends Annotation> SA_IGNORE_CLASS;
|
||||
private static final Class<? extends Annotation> SA_CHECK_LOGIN_CLASS;
|
||||
|
||||
|
||||
static {
|
||||
// 通过类加载器去加载注解类Class实例
|
||||
SA_CHECK_ROLE_CLASS = (Class<? extends Annotation>) ClassLoaderUtil.loadClass(SA_CHECK_ROLE_CLASS_NAME, false);
|
||||
SA_CHECK_PERMISSION_CLASS = (Class<? extends Annotation>) ClassLoaderUtil.loadClass(SA_CHECK_PERMISSION_CLASS_NAME, false);
|
||||
SA_IGNORE_CLASS = (Class<? extends Annotation>) ClassLoaderUtil.loadClass(SA_IGNORE_CLASS_NAME, false);
|
||||
SA_CHECK_LOGIN_CLASS = (Class<? extends Annotation>) ClassLoaderUtil.loadClass(SA_CHECK_LOGIN_NAME, false);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("SaTokenAnnotationJavadocResolver init success, load annotation class: {}", List.of(SA_CHECK_ROLE_CLASS, SA_CHECK_PERMISSION_CLASS, SA_IGNORE_CLASS, SA_CHECK_LOGIN_CLASS));
|
||||
}
|
||||
}
|
||||
|
||||
public SaTokenAnnotationMetadataJavadocResolver() {
|
||||
this(DEFAULT_METADATA_PROVIDER);
|
||||
}
|
||||
|
||||
public SaTokenAnnotationMetadataJavadocResolver(Supplier<SaTokenSecurityMetadata> metadataProvider) {
|
||||
super(metadataProvider);
|
||||
}
|
||||
|
||||
public SaTokenAnnotationMetadataJavadocResolver(int order) {
|
||||
this(DEFAULT_METADATA_PROVIDER,order);
|
||||
}
|
||||
|
||||
public SaTokenAnnotationMetadataJavadocResolver(Supplier<SaTokenSecurityMetadata> metadataProvider, int order) {
|
||||
super(metadataProvider,order);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(HandlerMethod handlerMethod) {
|
||||
return hasAnnotation(handlerMethod, SA_CHECK_ROLE_CLASS) || hasAnnotation(handlerMethod, SA_CHECK_PERMISSION_CLASS) || hasAnnotation(handlerMethod, SA_IGNORE_CLASS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolve(HandlerMethod handlerMethod, Operation operation, SaTokenSecurityMetadata metadata) {
|
||||
// 检查是否忽略校验
|
||||
if(hasAnnotation(handlerMethod, SA_IGNORE_CLASS_NAME)){
|
||||
metadata.setIgnore(true);
|
||||
return metadata.toMarkdownString();
|
||||
}
|
||||
|
||||
// 解析权限校验
|
||||
resolvePermissionCheck(handlerMethod, metadata);
|
||||
|
||||
// 解析角色校验
|
||||
resolveRoleCheck(handlerMethod, metadata);
|
||||
return metadata.toMarkdownString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析权限校验
|
||||
*/
|
||||
private void resolvePermissionCheck(HandlerMethod handlerMethod, SaTokenSecurityMetadata metadata) {
|
||||
// 解析获取方法上的注解角色信息
|
||||
if (hasMethodAnnotation(handlerMethod, SA_CHECK_PERMISSION_CLASS_NAME)) {
|
||||
Map<String, Object> annotationValueMap = getMethodAnnotationValueMap(handlerMethod, SA_CHECK_PERMISSION_CLASS);
|
||||
resolvePermissionAnnotation(metadata, annotationValueMap);
|
||||
}
|
||||
// 解析获取类上的注解角色信息
|
||||
if (hasClassAnnotation(handlerMethod, SA_CHECK_PERMISSION_CLASS_NAME)) {
|
||||
Map<String, Object> annotationValueMap = getClassAnnotationValueMap(handlerMethod, SA_CHECK_PERMISSION_CLASS);
|
||||
resolvePermissionAnnotation(metadata, annotationValueMap);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析权限注解
|
||||
*/
|
||||
private void resolvePermissionAnnotation(SaTokenSecurityMetadata metadata, Map<String, Object> annotationValueMap) {
|
||||
try {
|
||||
// 反射获取注解属性
|
||||
Object value = annotationValueMap.get( "value");
|
||||
Object mode = annotationValueMap.get( "mode");
|
||||
Object type = annotationValueMap.get( "type");
|
||||
Object orRole = annotationValueMap.get( "orRole");
|
||||
|
||||
String[] values = Convert.toStrArray(value);
|
||||
String modeStr = mode != null ? mode.toString() : "AND";
|
||||
String typeStr = type != null ? type.toString() : "";
|
||||
String[] orRoles = Convert.toStrArray(orRole);
|
||||
|
||||
metadata.addPermission(values, modeStr, typeStr, orRoles);
|
||||
} catch (Exception ignore) {
|
||||
// 忽略解析错误
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析角色校验
|
||||
*/
|
||||
private void resolveRoleCheck(HandlerMethod handlerMethod, SaTokenSecurityMetadata metadata) {
|
||||
// 解析获取方法上的注解角色信息
|
||||
if (hasMethodAnnotation(handlerMethod, SA_CHECK_ROLE_CLASS_NAME)) {
|
||||
Map<String, Object> annotationValueMap = getMethodAnnotationValueMap(handlerMethod, SA_CHECK_ROLE_CLASS);
|
||||
resolveRoleAnnotation(metadata, annotationValueMap);
|
||||
}
|
||||
// 解析获取类上的注解角色信息
|
||||
if (hasClassAnnotation(handlerMethod, SA_CHECK_ROLE_CLASS_NAME)) {
|
||||
Map<String, Object> annotationValueMap = getClassAnnotationValueMap(handlerMethod, SA_CHECK_ROLE_CLASS);
|
||||
resolveRoleAnnotation(metadata, annotationValueMap);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析角色注解
|
||||
*/
|
||||
private void resolveRoleAnnotation(SaTokenSecurityMetadata metadata, Map<String, Object> annotationValueMap) {
|
||||
try {
|
||||
// 反射获取注解属性
|
||||
Object value = annotationValueMap.get("value");
|
||||
Object mode = annotationValueMap.get("mode");
|
||||
Object type = annotationValueMap.get("type");
|
||||
|
||||
String[] values = Convert.toStrArray(value);
|
||||
String modeStr = mode != null ? mode.toString() : "AND";
|
||||
String typeStr = type != null ? type.toString() : "";
|
||||
|
||||
metadata.addRole(values, modeStr, typeStr);
|
||||
} catch (Exception ignore) {
|
||||
// 忽略解析错误
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import io.swagger.v3.oas.models.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dromara.common.core.utils.StreamUtils;
|
||||
import org.dromara.common.doc.core.resolver.JavadocResolver;
|
||||
import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
|
||||
import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
|
||||
import org.springdoc.core.properties.SpringDocConfigProperties;
|
||||
@@ -83,6 +84,11 @@ public class OpenApiHandler extends OpenAPIService {
|
||||
*/
|
||||
private final PropertyResolverUtils propertyResolverUtils;
|
||||
|
||||
/**
|
||||
* Javadoc解析器接口
|
||||
*/
|
||||
private final List<JavadocResolver> javadocResolvers;
|
||||
|
||||
/**
|
||||
* The javadoc provider.
|
||||
*/
|
||||
@@ -123,7 +129,8 @@ public class OpenApiHandler extends OpenAPIService {
|
||||
SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils,
|
||||
Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomizers,
|
||||
Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomizers,
|
||||
Optional<JavadocProvider> javadocProvider) {
|
||||
Optional<JavadocProvider> javadocProvider,
|
||||
List<JavadocResolver> javadocResolvers) {
|
||||
super(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider);
|
||||
if (openAPI.isPresent()) {
|
||||
this.openAPI = openAPI.get();
|
||||
@@ -140,6 +147,7 @@ public class OpenApiHandler extends OpenAPIService {
|
||||
this.openApiBuilderCustomisers = openApiBuilderCustomizers;
|
||||
this.serverBaseUrlCustomizers = serverBaseUrlCustomizers;
|
||||
this.javadocProvider = javadocProvider;
|
||||
this.javadocResolvers = javadocResolvers == null ? new ArrayList<>() : javadocResolvers;
|
||||
if (springDocConfigProperties.isUseFqn())
|
||||
TypeNameResolver.std.setUseFqn(true);
|
||||
}
|
||||
@@ -220,6 +228,22 @@ public class OpenApiHandler extends OpenAPIService {
|
||||
securityParser.buildSecurityRequirement(securityRequirements, operation);
|
||||
}
|
||||
|
||||
if (javadocProvider.isPresent()) {
|
||||
String description = javadocProvider.get().getMethodJavadocDescription(handlerMethod.getMethod());
|
||||
String summary = javadocProvider.get().getFirstSentence(description);
|
||||
if (StringUtils.isNotBlank(description)){
|
||||
operation.setSummary(summary);
|
||||
}
|
||||
// 调用解析器提取JavaDoc中的权限信息
|
||||
if (javadocResolvers != null && !javadocResolvers.isEmpty()) {
|
||||
for (JavadocResolver resolver : javadocResolvers) {
|
||||
String desc = resolver.resolve(handlerMethod, operation);
|
||||
description = description + desc;
|
||||
}
|
||||
operation.setDescription(description);
|
||||
}
|
||||
}
|
||||
|
||||
return operation;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,7 @@ import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.executor.parameter.ParameterHandler;
|
||||
import org.apache.ibatis.plugin.Interceptor;
|
||||
import org.apache.ibatis.plugin.Intercepts;
|
||||
import org.apache.ibatis.plugin.Invocation;
|
||||
import org.apache.ibatis.plugin.Signature;
|
||||
import org.apache.ibatis.plugin.*;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.encrypt.annotation.EncryptField;
|
||||
import org.dromara.common.encrypt.core.EncryptContext;
|
||||
@@ -42,19 +39,19 @@ public class MybatisEncryptInterceptor implements Interceptor {
|
||||
|
||||
@Override
|
||||
public Object intercept(Invocation invocation) throws Throwable {
|
||||
return invocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object plugin(Object target) {
|
||||
Object target = invocation.getTarget();
|
||||
if (target instanceof ParameterHandler parameterHandler) {
|
||||
// 进行加密操作
|
||||
Object parameterObject = parameterHandler.getParameterObject();
|
||||
if (ObjectUtil.isNotNull(parameterObject) && !(parameterObject instanceof String)) {
|
||||
this.encryptHandler(parameterObject);
|
||||
}
|
||||
}
|
||||
return target;
|
||||
return invocation.proceed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object plugin(Object target) {
|
||||
return Plugin.wrap(target, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,9 +23,24 @@ import java.util.Objects;
|
||||
@Slf4j
|
||||
public class SensitiveHandler extends ValueSerializer<String> {
|
||||
|
||||
private SensitiveStrategy strategy;
|
||||
private String[] roleKey;
|
||||
private String[] perms;
|
||||
private final SensitiveStrategy strategy;
|
||||
private final String[] roleKey;
|
||||
private final String[] perms;
|
||||
|
||||
/**
|
||||
* 提供给 jackson 创建上下文序列化器时使用 不然会报错
|
||||
*/
|
||||
public SensitiveHandler() {
|
||||
this.strategy = null;
|
||||
this.roleKey = null;
|
||||
this.perms = null;
|
||||
}
|
||||
|
||||
public SensitiveHandler(SensitiveStrategy strategy, String[] strings, String[] perms) {
|
||||
this.strategy = strategy;
|
||||
this.roleKey = strings;
|
||||
this.perms = perms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(String value, JsonGenerator gen, SerializationContext ctxt) throws JacksonException {
|
||||
@@ -46,10 +61,7 @@ public class SensitiveHandler extends ValueSerializer<String> {
|
||||
public ValueSerializer<?> createContextual(SerializationContext ctxt, BeanProperty property) {
|
||||
Sensitive annotation = property.getAnnotation(Sensitive.class);
|
||||
if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) {
|
||||
this.strategy = annotation.strategy();
|
||||
this.roleKey = annotation.roleKey();
|
||||
this.perms = annotation.perms();
|
||||
return this;
|
||||
return new SensitiveHandler(annotation.strategy(), annotation.roleKey(), annotation.perms());
|
||||
}
|
||||
return super.createContextual(ctxt, property);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ public interface TransConstant {
|
||||
String USER_ID_TO_NAME = "user_id_to_name";
|
||||
|
||||
/**
|
||||
* 用户id转用户名称
|
||||
* 用户id转用户昵称
|
||||
*/
|
||||
String USER_ID_TO_NICKNAME = "user_id_to_nickname";
|
||||
|
||||
|
||||
@@ -29,7 +29,18 @@ public class TranslationHandler extends ValueSerializer<Object> {
|
||||
*/
|
||||
public static final Map<String, TranslationInterface<?>> TRANSLATION_MAPPER = new ConcurrentHashMap<>();
|
||||
|
||||
private Translation translation;
|
||||
private final Translation translation;
|
||||
|
||||
/**
|
||||
* 提供给 jackson 创建上下文序列化器时使用 不然会报错
|
||||
*/
|
||||
public TranslationHandler() {
|
||||
this.translation = null;
|
||||
}
|
||||
|
||||
public TranslationHandler(Translation translation) {
|
||||
this.translation = translation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(Object value, JsonGenerator gen, SerializationContext ctxt) throws JacksonException {
|
||||
@@ -61,8 +72,7 @@ public class TranslationHandler extends ValueSerializer<Object> {
|
||||
public ValueSerializer<?> createContextual(SerializationContext ctxt, BeanProperty property) {
|
||||
Translation translation = property.getAnnotation(Translation.class);
|
||||
if (Objects.nonNull(translation)) {
|
||||
this.translation = translation;
|
||||
return this;
|
||||
return new TranslationHandler(translation);
|
||||
}
|
||||
return super.createContextual(ctxt, property);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import org.dromara.common.translation.constant.TransConstant;
|
||||
import org.dromara.common.translation.core.TranslationInterface;
|
||||
|
||||
/**
|
||||
* 用户名称翻译实现
|
||||
* 用户昵称翻译实现
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user