RequestBodyAdvice和ResponseBodyAdvice
这是spring 4.2新加的两个接口,这两个接口有些什么作用呢?先看看这两个接口
RequestBodyAdvice
public interface RequestBodyAdvice {
boolean supports(MethodParameter methodParameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType);
Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class<? extends HttpMessageConverter<?>> converterType);
HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException;
Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class<? extends HttpMessageConverter<?>> converterType);
}
查看一下谁调用了这个接口的这些方法,可以看到AbstractMessageConverterMethodArgumentResolver的readWithMessageConverters()方法调用了这个接口的方法。
//代码片段
for (HttpMessageConverter<?> converter : this.messageConverters) {
Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
if (converter instanceof GenericHttpMessageConverter) {
GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter;
if (genericConverter.canRead(targetType, contextClass, contentType)) {
if (logger.isDebugEnabled()) {
logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
}
if (inputMessage.getBody() != null) {
inputMessage = getAdvice().beforeBodyRead(inputMessage, param, targetType, converterType);
body = genericConverter.read(targetType, contextClass, inputMessage);
body = getAdvice().afterBodyRead(body, inputMessage, param, targetType, converterType);
}
else {
body = null;
body = getAdvice().handleEmptyBody(body, inputMessage, param, targetType, converterType);
}
break;
}
}
可以看到这接口的方法,主要是在HttpMessageConverter处理request body的前后做一些处理,和body为空的时候做处理。
而AbstractMessageConverterMethodArgumentResolver的实现类有
HttpEntityMethodProcessor(处理controller的方法参数是HttpEntity或RequestEntity的)、
RequestResponseBodyMethodProcessor(处理方法参数有@RequestBoyd的)、
RequestPartMethodArgumentResolver(处理方法参数是@RequestPart或MultipartFile,javax.servlet.http.Part)。
从这个可以看出,我们可以在使用这些HandlerMethodArgumentResolver的时候,我们能对request body进行前处理,和解析后处理。
RequestBodyAdvice怎么用
首先一个实现类,实现RequestBodyAdvice,后在类上加上注解@ControllerAdvice,比如有些请求的参数需要做加密处理,可以在此将json串解密处理,在处理
ResponseBodyAdvice
public interface ResponseBodyAdvice<T> {
boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType);
T beforeBodyWrite(T body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response);
}
此可以对@ResponseBody的返回结果在输出到响应之前做处理
@ResponseBody使用demo:
<!-- 使用spring组件扫描 -->
<context:component-scan base-package="com.game.ws,com.game.advice" />
package com.game.advice;
import javax.annotation.PostConstruct;
import org.springframework.core.MethodParameter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import com.alibaba.fastjson.JSON;
import com.game.dto.Result;
import com.gameqp.common.Utils;
import com.gameqp.common.Utils.MD5;
/**
*
* @ClassName: MyResponseBodyAdvice
* @Description: 对于@ResponseBody的返回结果加密
* @author duhai
* @date 2017年6月13日 下午2:31:36
*/
@ControllerAdvice
public class MyResponseBodyAdvice implements ResponseBodyAdvice<Result> {
/**
* 加密串一
*/
private static String md5_keyone;
/**
* 加密串二
*/
private static String md5_keytwo;
@PostConstruct
public void init() throws Exception {
md5_keyone = Utils.PT.getProps("md5_keyone");
md5_keytwo = Utils.PT.getProps("md5_keytwo");
}
/**
* 判断支持的类型
*
* @param returnType
* @param converterType
* @return
* @see org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice#supports(org.springframework.core.MethodParameter,
* java.lang.Class)
*/
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return returnType.getMethod().getReturnType().isAssignableFrom(Result.class);
}
/**
* 对于结果进行加密
*
* @param body
* @param returnType
* @param selectedContentType
* @param selectedConverterType
* @param request
* @param response
* @return
* @see org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice#beforeBodyWrite(java.lang.Object,
* org.springframework.core.MethodParameter,
* org.springframework.http.MediaType, java.lang.Class,
* org.springframework.http.server.ServerHttpRequest,
* org.springframework.http.server.ServerHttpResponse)
*/
@Override
public Result beforeBodyWrite(Result body, MethodParameter returnType,
org.springframework.http.MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
String jsonString = JSON.toJSONString(body.getData());
System.out.println(jsonString);
// 第一次加密
String data_encode_one = MD5.md5(md5_keyone + jsonString);
// 第二次加密
String data_encode_two = MD5.md5(data_encode_one + md5_keytwo);
body.setToken(data_encode_two);
return body;
}
}