修改日志打印逻辑.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package com.orion.ops.framework.common.annotation;
|
||||
|
||||
import com.orion.ops.framework.common.constant.IgnoreLogMode;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
@@ -13,4 +15,12 @@ import java.lang.annotation.*;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface IgnoreLog {
|
||||
|
||||
/**
|
||||
* 日志忽略模式
|
||||
*
|
||||
* @return 日志忽略模式
|
||||
*/
|
||||
IgnoreLogMode value() default IgnoreLogMode.ALL;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.orion.ops.framework.common.constant;
|
||||
|
||||
/**
|
||||
* 日志忽略模式
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/7/21 9:54
|
||||
*/
|
||||
public enum IgnoreLogMode {
|
||||
|
||||
/**
|
||||
* 不打印任何日志
|
||||
*/
|
||||
ALL,
|
||||
|
||||
/**
|
||||
* 不打印参数
|
||||
*/
|
||||
ARGS,
|
||||
|
||||
/**
|
||||
* 不打印返回值
|
||||
*/
|
||||
RET,
|
||||
|
||||
/**
|
||||
* 不打印参数以及返回值
|
||||
*/
|
||||
ARGS_RET,
|
||||
|
||||
;
|
||||
|
||||
}
|
||||
@@ -5,18 +5,17 @@ import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.serializer.PropertyFilter;
|
||||
import com.alibaba.fastjson.serializer.SerializeFilter;
|
||||
import com.alibaba.fastjson.serializer.ValueFilter;
|
||||
import com.orion.lang.utils.Arrays1;
|
||||
import com.orion.lang.utils.Desensitizes;
|
||||
import com.orion.lang.utils.Objects1;
|
||||
import com.orion.lang.utils.collect.Lists;
|
||||
import com.orion.lang.utils.collect.Maps;
|
||||
import com.orion.lang.utils.reflect.Classes;
|
||||
import com.orion.ops.framework.common.annotation.IgnoreLog;
|
||||
import com.orion.ops.framework.common.constant.IgnoreLogMode;
|
||||
import com.orion.ops.framework.common.meta.TraceIdHolder;
|
||||
import com.orion.ops.framework.common.security.SecurityHolder;
|
||||
import com.orion.ops.framework.log.core.config.LogPrinterConfig;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.ServletRequest;
|
||||
@@ -24,8 +23,8 @@ import javax.servlet.ServletResponse;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
@@ -37,6 +36,8 @@ import java.util.function.Predicate;
|
||||
*/
|
||||
public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterceptor {
|
||||
|
||||
private static final ThreadLocal<IgnoreLogMode> IGNORE_LOG_MODE = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 请求头过滤器
|
||||
*/
|
||||
@@ -60,9 +61,7 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce
|
||||
@Resource
|
||||
protected SecurityHolder securityHolder;
|
||||
|
||||
@SuppressWarnings("ALL")
|
||||
@Autowired(required = false)
|
||||
@Qualifier("desensitizeValueFilter")
|
||||
@Resource
|
||||
private ValueFilter desensitizeValueFilter;
|
||||
|
||||
public AbstractLogPrinterInterceptor(LogPrinterConfig config) {
|
||||
@@ -74,8 +73,6 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce
|
||||
public void init() {
|
||||
// 请求头过滤器
|
||||
this.headerFilter = header -> config.getHeaders().contains(header);
|
||||
// 字段过滤器
|
||||
List<SerializeFilter> fieldFilterList = Lists.newList();
|
||||
// 忽略字段过滤器
|
||||
PropertyFilter ignoreFilter = (Object object, String name, Object value) -> !config.getField().getIgnore().contains(name);
|
||||
// 脱敏字段过滤器
|
||||
@@ -86,31 +83,36 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce
|
||||
return value;
|
||||
}
|
||||
};
|
||||
fieldFilterList.add(ignoreFilter);
|
||||
fieldFilterList.add(desensitizeFilter);
|
||||
// 注解脱敏 未引入
|
||||
if (desensitizeValueFilter != null) {
|
||||
fieldFilterList.add(desensitizeValueFilter);
|
||||
}
|
||||
this.fieldFilters = fieldFilterList.toArray(new SerializeFilter[0]);
|
||||
this.fieldFilters = Arrays1.of(ignoreFilter, desensitizeFilter, desensitizeValueFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
// 日志忽略模式
|
||||
IgnoreLogMode ignoreLogMode = Optional.ofNullable(invocation.getMethod().getAnnotation(IgnoreLog.class))
|
||||
.map(IgnoreLog::value)
|
||||
.orElse(null);
|
||||
// 如果不打印任何日志 则直接跳出逻辑
|
||||
if (IgnoreLogMode.ALL.equals(ignoreLogMode)) {
|
||||
return invocation.proceed();
|
||||
}
|
||||
IGNORE_LOG_MODE.set(ignoreLogMode);
|
||||
Date startTime = new Date();
|
||||
String traceId = TraceIdHolder.get();
|
||||
// 打印请求日志
|
||||
this.requestPrinter(startTime, traceId, invocation);
|
||||
this.printRequestLog(startTime, traceId, invocation);
|
||||
try {
|
||||
// 执行方法
|
||||
Object ret = invocation.proceed();
|
||||
// 打印响应日志
|
||||
this.responsePrinter(startTime, traceId, invocation, ret);
|
||||
this.printResponseLog(startTime, traceId, invocation, ret);
|
||||
return ret;
|
||||
} catch (Throwable t) {
|
||||
// 打印异常日志
|
||||
this.errorPrinter(startTime, traceId, t);
|
||||
this.printExceptionLog(startTime, traceId, t);
|
||||
throw t;
|
||||
} finally {
|
||||
IGNORE_LOG_MODE.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +123,7 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce
|
||||
* @param traceId traceId
|
||||
* @param invocation invocation
|
||||
*/
|
||||
protected abstract void requestPrinter(Date startTime, String traceId, MethodInvocation invocation);
|
||||
protected abstract void printRequestLog(Date startTime, String traceId, MethodInvocation invocation);
|
||||
|
||||
/**
|
||||
* 打印响应信息
|
||||
@@ -131,7 +133,7 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce
|
||||
* @param invocation invocation
|
||||
* @param ret return
|
||||
*/
|
||||
protected abstract void responsePrinter(Date startTime, String traceId, MethodInvocation invocation, Object ret);
|
||||
protected abstract void printResponseLog(Date startTime, String traceId, MethodInvocation invocation, Object ret);
|
||||
|
||||
/**
|
||||
* 打印异常信息
|
||||
@@ -140,7 +142,7 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce
|
||||
* @param traceId traceId
|
||||
* @param throwable ex
|
||||
*/
|
||||
protected abstract void errorPrinter(Date startTime, String traceId, Throwable throwable);
|
||||
protected abstract void printExceptionLog(Date startTime, String traceId, Throwable throwable);
|
||||
|
||||
/**
|
||||
* 请求参数 json
|
||||
@@ -152,7 +154,12 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce
|
||||
protected String requestToString(Method method, Object[] args) {
|
||||
int length = args.length;
|
||||
if (length == 0) {
|
||||
return EMPTY_ARG;
|
||||
return EMPTY_TAG;
|
||||
}
|
||||
// 忽略日志
|
||||
IgnoreLogMode ignoreLogMode = IGNORE_LOG_MODE.get();
|
||||
if (IgnoreLogMode.ARGS.equals(ignoreLogMode) || IgnoreLogMode.ARGS_RET.equals(ignoreLogMode)) {
|
||||
return IGNORED_TAG;
|
||||
}
|
||||
try {
|
||||
// 检查是否需要忽略字段
|
||||
@@ -167,7 +174,7 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce
|
||||
}
|
||||
if (printCount == 0) {
|
||||
// 无打印参数
|
||||
return EMPTY_ARG;
|
||||
return EMPTY_TAG;
|
||||
} else if (printCount == 1) {
|
||||
// 单个打印参数
|
||||
return JSON.toJSONString(args[lastPrintIndex], fieldFilters);
|
||||
@@ -182,7 +189,7 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce
|
||||
return JSON.toJSONString(arr, fieldFilters);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return ERROR_ARG;
|
||||
return ERROR_TAG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,10 +200,18 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce
|
||||
* @return json
|
||||
*/
|
||||
protected String responseToString(Object o) {
|
||||
if (o == null) {
|
||||
return NULL_TAG;
|
||||
}
|
||||
// 忽略日志
|
||||
IgnoreLogMode ignoreLogMode = IGNORE_LOG_MODE.get();
|
||||
if (IgnoreLogMode.RET.equals(ignoreLogMode) || IgnoreLogMode.ARGS_RET.equals(ignoreLogMode)) {
|
||||
return IGNORED_TAG;
|
||||
}
|
||||
try {
|
||||
return JSON.toJSONString(o, fieldFilters);
|
||||
} catch (Exception e) {
|
||||
return ERROR_ARG;
|
||||
return ERROR_TAG;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,15 @@ import org.aopalliance.intercept.MethodInterceptor;
|
||||
*/
|
||||
public interface LogPrinterInterceptor extends MethodInterceptor {
|
||||
|
||||
String EMPTY_ARG = "<EMPTY>";
|
||||
String EMPTY_TAG = "<EMPTY>";
|
||||
|
||||
String ERROR_ARG = "<ERROR>";
|
||||
String ERROR_TAG = "<ERROR>";
|
||||
|
||||
String VOID_RES = "<VOID>";
|
||||
String VOID_TAG = "<VOID>";
|
||||
|
||||
String NULL_TAG = "<NULL>";
|
||||
|
||||
String IGNORED_TAG = "<IGNORED>";
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
|
||||
@@ -31,7 +31,7 @@ public class PrettyLogPrinterInterceptor extends AbstractLogPrinterInterceptor {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void requestPrinter(Date startTime, String traceId, MethodInvocation invocation) {
|
||||
protected void printRequestLog(Date startTime, String traceId, MethodInvocation invocation) {
|
||||
StringBuilder requestLog = new StringBuilder("\napi请求-开始\n");
|
||||
// http请求信息
|
||||
HttpServletRequest request = Optional.ofNullable(RequestContextHolder.getRequestAttributes())
|
||||
@@ -80,7 +80,7 @@ public class PrettyLogPrinterInterceptor extends AbstractLogPrinterInterceptor {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void responsePrinter(Date startTime, String traceId, MethodInvocation invocation, Object ret) {
|
||||
protected void printResponseLog(Date startTime, String traceId, MethodInvocation invocation, Object ret) {
|
||||
Date endTime = new Date();
|
||||
// 响应日志
|
||||
StringBuilder responseLog = new StringBuilder("\napi请求-结束\n")
|
||||
@@ -89,7 +89,7 @@ public class PrettyLogPrinterInterceptor extends AbstractLogPrinterInterceptor {
|
||||
.append("\tused: ").append(endTime.getTime() - startTime.getTime()).append("ms \n");
|
||||
|
||||
if (invocation.getMethod().getReturnType().equals(Void.TYPE)) {
|
||||
responseLog.append("\tresponse: ").append(VOID_RES);
|
||||
responseLog.append("\tresponse: ").append(VOID_TAG);
|
||||
} else {
|
||||
responseLog.append("\tresponse: ").append(this.responseToString(ret));
|
||||
}
|
||||
@@ -97,7 +97,7 @@ public class PrettyLogPrinterInterceptor extends AbstractLogPrinterInterceptor {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void errorPrinter(Date startTime, String traceId, Throwable throwable) {
|
||||
protected void printExceptionLog(Date startTime, String traceId, Throwable throwable) {
|
||||
Date endTime = new Date();
|
||||
// 异常日志
|
||||
StringBuilder errorLog = new StringBuilder("\napi请求-异常\n")
|
||||
|
||||
@@ -35,7 +35,7 @@ public class RowLogPrinterInterceptor extends AbstractLogPrinterInterceptor impl
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void requestPrinter(Date startTime, String traceId, MethodInvocation invocation) {
|
||||
protected void printRequestLog(Date startTime, String traceId, MethodInvocation invocation) {
|
||||
// http请求信息
|
||||
HttpServletRequest request = Optional.ofNullable(RequestContextHolder.getRequestAttributes())
|
||||
.map(s -> (ServletRequestAttributes) s)
|
||||
@@ -81,7 +81,7 @@ public class RowLogPrinterInterceptor extends AbstractLogPrinterInterceptor impl
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void responsePrinter(Date startTime, String traceId, MethodInvocation invocation, Object ret) {
|
||||
protected void printResponseLog(Date startTime, String traceId, MethodInvocation invocation, Object ret) {
|
||||
Date endTime = new Date();
|
||||
// 响应日志
|
||||
Map<String, Object> fields = new LinkedHashMap<>();
|
||||
@@ -89,7 +89,7 @@ public class RowLogPrinterInterceptor extends AbstractLogPrinterInterceptor impl
|
||||
fields.put(END, Dates.format(endTime, Dates.YMD_HMSS));
|
||||
fields.put(USED, endTime.getTime() - startTime.getTime() + "ms");
|
||||
if (invocation.getMethod().getReturnType().equals(Void.TYPE)) {
|
||||
fields.put(RESPONSE, VOID_RES);
|
||||
fields.put(RESPONSE, VOID_TAG);
|
||||
} else {
|
||||
fields.put(RESPONSE, this.responseToString(ret));
|
||||
}
|
||||
@@ -98,7 +98,7 @@ public class RowLogPrinterInterceptor extends AbstractLogPrinterInterceptor impl
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void errorPrinter(Date startTime, String traceId, Throwable throwable) {
|
||||
protected void printExceptionLog(Date startTime, String traceId, Throwable throwable) {
|
||||
Date endTime = new Date();
|
||||
// 异常日志
|
||||
Map<String, Object> fields = new LinkedHashMap<>();
|
||||
|
||||
@@ -3,6 +3,7 @@ package ${package.Controller};
|
||||
import com.orion.lang.define.wrapper.DataGrid;
|
||||
import com.orion.ops.framework.common.annotation.IgnoreLog;
|
||||
import com.orion.ops.framework.common.annotation.RestWrapper;
|
||||
import com.orion.ops.framework.common.constant.IgnoreLogMode;
|
||||
import ${package.Service}.*;
|
||||
#foreach($pkg in ${customFilePackages})
|
||||
import ${pkg}.*;
|
||||
@@ -58,7 +59,7 @@ public class ${table.controllerName} {
|
||||
return ${typeLower}Service.update${type}(request);
|
||||
}
|
||||
|
||||
@IgnoreLog
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "${apiComment.get}")
|
||||
@Parameter(name = "id", description = "id", required = true)
|
||||
@@ -67,7 +68,7 @@ public class ${table.controllerName} {
|
||||
return ${typeLower}Service.get${type}(id);
|
||||
}
|
||||
|
||||
@IgnoreLog
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "${apiComment.list}")
|
||||
@Parameter(name = "idList", description = "idList", required = true)
|
||||
@@ -76,7 +77,7 @@ public class ${table.controllerName} {
|
||||
return ${typeLower}Service.get${type}List(idList);
|
||||
}
|
||||
|
||||
@IgnoreLog
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@PostMapping("/query")
|
||||
@Operation(summary = "${apiComment.query}")
|
||||
@PreAuthorize("@ss.hasPermission('${package.ModuleName}:${typeHyphen}:query')")
|
||||
|
||||
@@ -151,7 +151,7 @@ orion:
|
||||
# 全局日志打印
|
||||
printer:
|
||||
mode: PRETTY
|
||||
expression: 'execution (* com.orion.ops..*.controller..*.*(..)) && !@annotation(com.orion.ops.framework.common.annotation.IgnoreLog)'
|
||||
expression: 'execution (* com.orion.ops..*.controller..*.*(..))'
|
||||
headers:
|
||||
- user-agent,accept
|
||||
- content-type
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.orion.ops.module.infra.controller;
|
||||
import com.orion.lang.define.wrapper.HttpWrapper;
|
||||
import com.orion.ops.framework.common.annotation.IgnoreLog;
|
||||
import com.orion.ops.framework.common.annotation.RestWrapper;
|
||||
import com.orion.ops.framework.common.constant.IgnoreLogMode;
|
||||
import com.orion.ops.framework.security.core.utils.SecurityUtils;
|
||||
import com.orion.ops.module.infra.entity.request.user.UserLoginRequest;
|
||||
import com.orion.ops.module.infra.entity.request.user.UserResetPasswordRequest;
|
||||
@@ -51,7 +52,7 @@ public class AuthenticationController {
|
||||
}
|
||||
|
||||
@PermitAll
|
||||
@IgnoreLog
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@Operation(summary = "登出")
|
||||
@GetMapping("/logout")
|
||||
public HttpWrapper<?> logout(HttpServletRequest servletRequest) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.orion.ops.module.infra.controller;
|
||||
import com.orion.lang.define.wrapper.HttpWrapper;
|
||||
import com.orion.ops.framework.common.annotation.IgnoreLog;
|
||||
import com.orion.ops.framework.common.annotation.RestWrapper;
|
||||
import com.orion.ops.framework.common.constant.IgnoreLogMode;
|
||||
import com.orion.ops.module.infra.entity.vo.SystemMenuVO;
|
||||
import com.orion.ops.module.infra.entity.vo.UserPermissionVO;
|
||||
import com.orion.ops.module.infra.service.PermissionService;
|
||||
@@ -45,14 +46,14 @@ public class PermissionController {
|
||||
return HttpWrapper.ok();
|
||||
}
|
||||
|
||||
@IgnoreLog
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/menu")
|
||||
@Operation(summary = "获取用户菜单")
|
||||
public List<SystemMenuVO> getUserMenuList() {
|
||||
return permissionService.getUserMenuList();
|
||||
}
|
||||
|
||||
@IgnoreLog
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/permission")
|
||||
@Operation(summary = "获取用户权限")
|
||||
public UserPermissionVO getUserPermission() {
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.orion.ops.module.infra.controller;
|
||||
|
||||
import com.orion.ops.framework.common.annotation.IgnoreLog;
|
||||
import com.orion.ops.framework.common.annotation.RestWrapper;
|
||||
import com.orion.ops.framework.common.constant.IgnoreLogMode;
|
||||
import com.orion.ops.module.infra.entity.request.menu.*;
|
||||
import com.orion.ops.module.infra.entity.vo.SystemMenuVO;
|
||||
import com.orion.ops.module.infra.service.SystemMenuService;
|
||||
@@ -67,7 +68,7 @@ public class SystemMenuController {
|
||||
return systemRoleMenuService.bindRoleMenu(request);
|
||||
}
|
||||
|
||||
@IgnoreLog
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "通过 id 查询菜单")
|
||||
@Parameter(name = "id", description = "id", required = true)
|
||||
@@ -76,7 +77,7 @@ public class SystemMenuController {
|
||||
return systemMenuService.getSystemMenu(id);
|
||||
}
|
||||
|
||||
@IgnoreLog
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@PostMapping("/list")
|
||||
@Operation(summary = "查询菜单")
|
||||
@PreAuthorize("@ss.hasPermission('infra:system-menu:query')")
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.orion.ops.module.infra.controller;
|
||||
import com.orion.lang.define.wrapper.DataGrid;
|
||||
import com.orion.ops.framework.common.annotation.IgnoreLog;
|
||||
import com.orion.ops.framework.common.annotation.RestWrapper;
|
||||
import com.orion.ops.framework.common.constant.IgnoreLogMode;
|
||||
import com.orion.ops.module.infra.entity.request.role.SystemRoleCreateRequest;
|
||||
import com.orion.ops.module.infra.entity.request.role.SystemRoleQueryRequest;
|
||||
import com.orion.ops.module.infra.entity.request.role.SystemRoleStatusRequest;
|
||||
@@ -60,7 +61,7 @@ public class SystemRoleController {
|
||||
return systemRoleService.updateRoleStatus(request);
|
||||
}
|
||||
|
||||
@IgnoreLog
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "通过 id 查询角色")
|
||||
@Parameter(name = "id", description = "id", required = true)
|
||||
@@ -69,7 +70,7 @@ public class SystemRoleController {
|
||||
return systemRoleService.getSystemRole(id);
|
||||
}
|
||||
|
||||
@IgnoreLog
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "查询所有角色")
|
||||
@PreAuthorize("@ss.hasPermission('infra:system-role:query')")
|
||||
@@ -77,7 +78,7 @@ public class SystemRoleController {
|
||||
return systemRoleService.getSystemRoleList();
|
||||
}
|
||||
|
||||
@IgnoreLog
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@PostMapping("/query")
|
||||
@Operation(summary = "分页查询角色")
|
||||
@PreAuthorize("@ss.hasPermission('infra:system-role:query')")
|
||||
|
||||
Reference in New Issue
Block a user