首先,我们需要有个自定义注解,它有两个参数:key 表示 SpEL 表达式;userType 表示权限
参数。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ResponseSensitiveOverride {
/**
* SPEL 表达式
*
* @return
*/
String key() default "";
/**
* 1:主账号、2:子账号
*/
int userType() default 1;
}
然后,把这个注解放在路由地址上,key 写入获取权限参数的 SpEL 表达式:
@ResponseSensitiveOverride(key = "#driverPageParam.getUserType()")
@RequestMapping(value = "/queryPage", method = RequestMethod.POST)
public ResponseData<PageVo<AdminDriverVo>> queryPage(@RequestBody
AdminDriverPageParam driverPageParam) {
return driverService.queryPageAdmin(driverPageParam);
}
回到顶部
二、SpEl + AOP 注解赋值
现在 SpEL 表达式是有了,怎么把 SpEL 表达式的结果赋值给注解的 userType 参数呢?这就
需要用 Spring AOP 、Java 反射 和 动态代理 的知识。
@Aspect
@Component
public class SensitiveAspect {
private SpelExpressionParser spelParser = new SpelExpressionParser();
/**
* 返回通知
*/
@AfterReturning("@annotation
(com.yungu.swift.base.model.annotation.ResponseSensitiveOverride) && @annotation
(sensitiveOverride)")
public void doAfter(JoinPoint joinPoint, ResponseSensitiveOverride
sensitiveOverride) throws Exception {
//获取方法的参数名和参数值
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature
();
List paramNameList = Arrays.asList
(methodSignature.getParameterNames());
List paramList = Arrays.asList(joinPoint.getArgs());
//将方法的参数名和参数值一一对应的放入上下文中
EvaluationContext ctx = new StandardEvaluationContext();
for (int i = 0; i < paramNameList.size(); i++) {
ctx.setVariable(paramNameList.get(i), paramList.get(i));
}
// 解析SpEL表达式获取结果
String value = spelParser.parseExpression(sensitiveOverride.key
()).getValue(ctx).toString();
//获取 sensitiveOverride 这个代理实例所持有的 InvocationHandler
InvocationHandler invocationHandler = Proxy.getInvocationHandler
(sensitiveOverride);
// 获取 invocationHandler 的 memberValues 字段
Field hField = invocationHandler.getClass().getDeclaredField
(“memberValues”);
// 因为这个字段是 private final 修饰,所以要打开权限
hField.setAccessible(true);
// 获取 memberValues
Map memberValues = (Map) hField.get(invocationHandler);
// 修改 value 属性值
memberValues.put(“userType”, Integer.parseInt(value));
}
}
通过这种方式,我们就实现了为注解动态赋值。
回到顶部
三、ResponseBodyAdvice 处理数据
现在要做的事情就是在 ResponseBody 数据返回前,对数据进行拦截,然后读取注解上的权限
参数,从而对数据进行处理,这里使用的是 SpringMVC 的 ResponseBodyAdvice 来实现:
@Slf4j
@RestControllerAdvice
@Order(-1)
public class ResponseBodyAdvice implements
org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice {
private static final ThreadLocal<Integer> threadLocal = new
ThreadLocal() {
@Override
protected Integer initialValue() {
return SysUserDto.USER_TYPE_PRIMARY;
}
};
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
if (returnType.hasMethodAnnotation(ResponseSensitiveOverride.class)) {
ResponseSensitiveOverride sensitiveOverride =
returnType.getMethodAnnotation(ResponseSensitiveOverride.class);
threadLocal.set(sensitiveOverride.userType());
return true;
}
return false;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType,
MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest
request, ServerHttpResponse response) {
if (body != null && SysUserDto.USER_TYPE_SUB.equals(threadLocal.get())) {
// 业务处理
}
return body;
}
}
亚马逊测评 www.yisuping.com