目录
3 使用ResponseBodyAdvice和RequestBodyAdvice给controller做环绕日志
此文的目的是想要对@ResponseBody修饰的方法的返回值,从大写下划线转成小写驼峰,而突然发现官方文档表示“HandlerInterceptor的postHandle() 不支持@ResponseBody、@ResponseEntity修饰方法输出结果的处理,应该使用@ResponseBodyAdvice”。
同时官方文档SpringWebMvc一章中1.10MvcConfig章节的1.10.7MessgeConverters小节也有类似功效。
所以写此文记录下对两者的使用。
本文提到的大写下划线转驼峰工具见 https://blog.csdn.net/qq_26950567/article/details/115102515?spm=1001.2014.3001.5501
1 使用ResponseBodyAdvice
需要用@ControllerAdvice注入
@ControllerAdvice // reponseBodyAdvice可以用@ControllerAdvice注入
public class CamelCaseResponseBodyAdvice implements ResponseBodyAdvice<BeeActionResponse> {
private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 需要满足:
* 1. 需要转换的方法被@NeedConvert(converterName="camelCaseConverter")修饰
* 2. 返回BeeActionResponse的组合类型
* @param returnType
* @param converterType
* @return
*/
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
NeedConvert methodAnnotation = returnType.getMethodAnnotation(NeedConvert.class);
if (methodAnnotation == null)
return false;
else
return "camelCaseConverter".equals(returnType.getMethodAnnotation(NeedConvert.class).converterName())
&& BeeActionResponse.class.isAssignableFrom(returnType.getMethod().getReturnType());
}
@Override
public BeeActionResponse beforeBodyWrite(BeeActionResponse body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
Object camelParse = CamelCaseUtils.underLineToCamelCase(body.getRespData());
BeeActionResponse beeActionResponse = new BeeActionResponse();
beeActionResponse.setRespCode(body.getRespCode());
beeActionResponse.setRespMsg(body.getRespMsg());
beeActionResponse.setTraceId(body.getTraceId());
beeActionResponse.setRespData(camelParse);
beeActionResponse.setPager(body.getPager());
return beeActionResponse;
//return body;
}
}
2 使用HttpMessageConverter
- 可以用@Component直接注入
- CanWrite表示哪种返回类型的方法,可被我这个HttpMessageConverter改写输出结果
- GetSupportedMediaType写空集合就行
- 具体的改写输出逻辑,在write方法中进行
@Component
public class CamelCaseConverter implements HttpMessageConverter<BeeActionResponse> {
@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
return false;
}
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return BeeActionResponse.class.isAssignableFrom(clazz);
}
@Override
public List<MediaType> getSupportedMediaTypes() {
return Collections.unmodifiableList(Collections.emptyList());
}
@Override
public BeeActionResponse read(Class<? extends BeeActionResponse> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
@Override
public void write(BeeActionResponse response, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
Object camelParse = CamelCaseUtils.underLineToCamelCase(response.getRespData());
outputMessage.getBody().write(JSONObject.toJSONString(camelParse).getBytes());
}
}
3 使用ResponseBodyAdvice和RequestBodyAdvice给controller做环绕日志
/**
*
* @author onion.li
*/
@Slf4j
@ControllerAdvice
public class AroundAdvice implements RequestBodyAdvice,ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
/**
* RequestBody读之前要做什么操作
* 什么都不做
*/
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
return httpInputMessage;
}
/**
* RequestBody读之后要做什么操作
* 打印日志
*/
@Override
public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
Method method=methodParameter.getMethod();
String eventName = method.getDeclaringClass().getSimpleName() + "#" + method.getName();
log.info("req" + JSONObject.toJSONString(o));
return o;
}
/**
* 若RequestBody为空怎么办
* 打印日志
*/
@Override
public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
Method method=methodParameter.getMethod();
String eventName = method.getDeclaringClass().getSimpleName() + "#" + method.getName();
log.info("req" + null);
return null;
}
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
return true;
}
/**
* reponseBody返回之前要做什么操作
* 写日志
*/
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
Method method=methodParameter.getMethod();
String eventName = method.getDeclaringClass().getSimpleName() + "#" + method.getName();
log.info("resp" + JSONObject.toJSONString(o));
return o;
}
}
4 源码跟踪
可以看出ReponseBodyAdvice对输出的改写,同HttpMessageConverter对输出的改写,两者是挨着的,所以我觉得一般情况,使用ResponseBodyAdvice就足够了。
下图是HttpMessageConverter在springmvc的请求链路中的作用。
每个httpMessgeConverter能告诉我们
它支持什么样的协议 application/json、text/plain 还是其他。
它能够将httpMessge转为什么对象,是字符串、对象、还是别的什么。