RequestBodyAdvice 和 ResponseBodyAdvice具有什么功能呢?
下文笔者讲述RequestBodyAdvice 和 ResponseBodyAdvice的功能简介说明,如下所示
RequestBodyAdvice
RequestBodyAdvice
是SpringMVC4.2提供一个接口
它允许请求体被读取并转换为对象
并将处理结果对象作为@RequestBody参数
或
@HttpEntity方法参数
ResponseBodyAdvice
ResponseBodyAdvice
是SpringMVC4.1提供一个接口
它允许在运行@ResponseBody后自定义返回数据
或
将返回@ResponseEntity的Controller Method
在写入主体前使用 HttpMessageConverter进行自定义操作
RequestBodyAdvice 和 ResponseBodyAdvice源码简介
//RequestBodyAdvice源码
public interface RequestBodyAdvice {
boolean supports(MethodParameter var1, Type var2, Class<? extends HttpMessageConverter<?>> var3);
HttpInputMessage beforeBodyRead(HttpInputMessage var1, MethodParameter var2, Type var3, Class<? extends HttpMessageConverter<?>> var4)
throws IOException;
Object afterBodyRead(Object var1, HttpInputMessage var2, MethodParameter var3, Type var4, Class<? extends HttpMessageConverter<?>> var5);
@Nullable
Object handleEmptyBody(@Nullable Object var1, HttpInputMessage var2, MethodParameter var3, Type var4,
Class<? extends HttpMessageConverter<?>> var5);
}
//AbstractMessageConverterMethodArgumentResolver
// readWithMessageConverters()方法调用了这个接口的方法。
@Nullable
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType)
throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
boolean noContentType = false;
MediaType contentType;
try {
contentType = inputMessage.getHeaders().getContentType();
} catch (InvalidMediaTypeException var16) {
throw new HttpMediaTypeNotSupportedException(var16.getMessage());
}
if (contentType == null) {
noContentType = true;
contentType = MediaType.APPLICATION_OCTET_STREAM;
}
Class<?> contextClass = parameter.getContainingClass();
Class<T> targetClass = targetType instanceof Class ? (Class)targetType : null;
if (targetClass == null) {
ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
targetClass = resolvableType.resolve();
}
HttpMethod httpMethod = inputMessage instanceof HttpRequest ? ((HttpRequest)inputMessage).getMethod() : null;
Object body = NO_VALUE;
AbstractMessageConverterMethodArgumentResolver.EmptyBodyCheckingHttpInputMessage message;
try {
label94: {
message = new AbstractMessageConverterMethodArgumentResolver.EmptyBodyCheckingHttpInputMessage(inputMessage);
Iterator var11 = this.messageConverters.iterator();
HttpMessageConverter converter;
Class converterType;
GenericHttpMessageConverter genericConverter;
while(true) {
if (!var11.hasNext()) {
break label94;
}
converter = (HttpMessageConverter)var11.next();
converterType = converter.getClass();
genericConverter = converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter)converter : null;
if (genericConverter != null) {
if (genericConverter.canRead(targetType, contextClass, contentType)) {
break;
}
} else if (targetClass != null && converter.canRead(targetClass, contentType)) {
break;
}
}
if (message.hasBody()) {
HttpInputMessage msgToUse = this.getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
body = genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
converter.read(targetClass, msgToUse);
body = this.getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
} else {
body = this.getAdvice().handleEmptyBody((Object)null, message, parameter, targetType, converterType);
}
}
} catch (IOException var17) {
throw new HttpMessageNotReadableException("I/O error while reading input message", var17, inputMessage);
}
if (body != NO_VALUE) {
LogFormatUtils.traceDebug(this.logger, (traceOn) -> {
String formatted = LogFormatUtils.formatValue(body, !traceOn);
return "Read \"" + contentType + "\" to [" + formatted + "]";
});
return body;
} else if (httpMethod != null && SUPPORTED_METHODS.contains(httpMethod) && (!noContentType || message.hasBody())) {
throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
} else {
return null;
}
}
RequestBodyAdvice示例
首先一个实现类实现RequestBodyAdvice
后在类上加上注解@ControllerAdvice
两者缺一不可
如:
有些请求请求体已经做加密处理
可在此将请求体解密。
核心的方法就是 supports,该方法返回的boolean值
决定运行beforeBodyRead方法
注意事项:
不用加@Component注解
//@Component
@ControllerAdvice
public class RequestBodyDecrypt implements RequestBodyAdvice {
@Reference
private EquipmentService equipmentService;
@Override
public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return true; // 必须为true才会执行beforeBodyRead和afterBodyRead方法
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
String equipmentNo = httpInputMessage.getHeaders().getFirst("equipmentNo"); // 从请求头中获取equipmentNo,getFirst()方法根据请求头的名称获取值
String privateKey = null;
list<EquipmentDTO> mapList = equipmentService.getByEquipmentNo(equipmentNo);
if (mapList.size() > 0) {
EquipmentDTO equipmentDTO = mapList.get(0);
privateKey = equipmentDTO.getProdPriKey();
}
// 提取数据
InputStream is = httpInputMessage.getBody(); // 从HTTPInputMessage中获取请求体,得到字节输入流
byte[] data = new byte[is.available()];
is.read(data);
String dataStr = new String(data, StandardCharsets.UTF_8);
JSONObject json = JSONObject.parseObject(dataStr);
String decrypt = null;
try {
decrypt = //解密逻辑
} catch (Exception e) {
throw new RuntimeException("数据错误");
} // 将解密后的请求体封装到HttpInputMessage中返回
return new DecodedHttpInputMessage(httpInputMessage.getHeaders(), new ByteArrayInputStream(decrypt.getBytes(StandardCharsets.UTF_8)));
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return body;
}
@Override
public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return body;
}
static class DecodedHttpInputMessage implements HttpInputMessage {
HttpHeaders headers;
InputStream body;
public DecodedHttpInputMessage(HttpHeaders headers, InputStream body) {
this.headers = headers;
this.body = body;
}
@Override
public InputStream getBody() throws IOException {
return body;
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
}
}
ResponseBodyAdvice示例
//对返回结果加密
//定义一个实现类实现ResponseBodyAdvice
//后在类上加上注解@ControllerAdvice
@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 = //加密
// 第二次加密
String data_encode_two = //加密
body.setToken(data_encode_two);
return body;
}
}
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。


