通过RequestBodyAdvice和自定义注解,实现加密参数自动解密
RequestBodyAdvice接口
它是SpringMVC提供的一个接口,类注释如下
允许在请求体被读取并转换为Object之前对请求进行定制,也允许在结果对象作为@RequestBody或HttpEntity方法参数传递给控制器方法之前对其进行处理。 该接口的实现可以直接注册到RequestMappingHandlerAdapter,或者更有可能使用@ControllerAdvice注释,在这种情况下它们会被自动检测。
它提供了四个方法
- supports:首次调用,判断这个拦截器是否适用这次请求,返回boolean
- beforeBodyRead:在转换至Controller参数对象之前调用,加工请求头和请求体
- afterBodyRead:在转换至Controller参数对象之后调用,处理这个对象
- handleEmptyBody:当参数为空时调用,可以返回请求体,也可以返回null正常触发Body为空的报错
实现方式
我们的思路是这样的,首先自定义一个注解@Encrypt
,用在被@RequestBody
标记的参数上。
然后我们实现RequestBodyAdvice
接口,首先实现supports
接口,通过判断是否标注了我们的注解,来决定是否进行解密操作
@Override
public boolean supports(
MethodParameter methodParameter, Type type,
Class<? extends HttpMessageConverter<?>> aClass) {
return methodParameter.hasParameterAnnotation(Encrypt.class);
}
然后,我们在beforeBodyRead
方法中,实现我们解密的核心操作
@Override
public HttpInputMessage beforeBodyRead(
HttpInputMessage httpInputMessage,
MethodParameter methodParameter, Type type,
Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
return new HttpInputMessage() {
@Override
public InputStream getBody() throws IOException {
logger.info("请求头参数:"+ httpInputMessage.getHeaders());
logger.info("在此处去掉请求参数外层data");
String body = IOUtils.toString(httpInputMessage.getBody());
JSONObject jasonObject = JSONObject.parseObject(body);
String content = (String)jasonObject.get("data");
//进行解密操作
String after = null;
try {
DESUtils desUtils = new DESUtils(desKey);
after = desUtils.decryptString(content);
} catch (Exception e) {
logger.error("解密失败");
}
return new ByteArrayInputStream
(after.getBytes(StandardCharsets.UTF_8));
}
@Override
public HttpHeaders getHeaders() {
return httpInputMessage.getHeaders();
}
};
}
afterBodyRead
接口直接返回Object,不做任何其他处理
根据类文档说明,要向让这个自定义的RequestBodyAdvice
起作用,我们可以给它添加上@ControllerAdvice
注解,他就可以自动注册到Spirng容器,而后注册到RequestMappingHandlerAdapter
中
至此,我们就实现了我们的功能。
思考
我们可以看到,在SpringMVC中有很多类似的Adapter,它们大部分都为我们提供了简单的扩展方式。通过探究这些接口在系统中生效的原理,也是我们看SpringMVC源码很好的切入点