场景: 了解到ResponseBodyAdvice可以将全局捕获WebExceptionHandler进行一次改造, 1\可以在Controller层返回任何类型T,再包装为期望的类型,比如Response, 2\可以将HTTP Status进行修改,产生真实的状态码 因此:今天我就返回了String,期望是将String包装为Response返回,但是却出了问题。
使用方式
1.Controller
@GetMapping(value = "/err3", produces = {"application/json"})
public String err3() {
Article tiele = Article.builder().title("tiele").build();
return JSON.toJSONString(tiele);
}
2、ResponseBodyAdvice:改造点:如果返回的不是AjaxResponse,就包装为它,这样controller层就不必非得传AjaxResponse
@ControllerAdvice
public class GlobalResponseAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
return true;
}
@Override
public Object beforeBodyWrite(Object body,
MethodParameter methodParameter,
MediaType mediaType,
Class aClass,
ServerHttpRequest serverHttpRequest,
ServerHttpResponse serverHttpResponse) {
//如果响应结果是JSON数据类型
if (mediaType.equalsTypeAndSubtype(MediaType.APPLICATION_JSON)) {
if (body instanceof AjaxResponse) {
AjaxResponse ajaxResponse = (AjaxResponse) body;
if (ajaxResponse.getCode() != 999) {
//改造点1:修改状态码
serverHttpResponse.setStatusCode(HttpStatus.valueOf(
ajaxResponse.getCode()
));
}
return body;
} else {
//改造点2:如果返回的不是AjaxResponse,就包装为它,这样controller层就不必非得传AjaxResponse
serverHttpResponse.setStatusCode(HttpStatus.OK);
return AjaxResponse.success(body);
}
}
return body;
}
}
3、AjaxResponse
@Data
public class AjaxResponse {
private boolean isok; //请求是否处理成功
private int code; //请求响应状态码(200、400、500)
private String message; //请求结果描述信息
private Object data; //请求结果数据(通常用于查询操作)
private AjaxResponse() {
}
}
4、预期:请求/err3时,返回 被AjaxResponse包装的String,结果抛出了类型转换异常。
5、问题原因: 本来对converter只是了解,debug了一个小时,最终发现,StringHttpMessageConverter,支持所有类型的Content-type,包括application/json, 所以返回String时,优先被使用。。。 所以我就将controller层的返回值,改为了其他对象,让它走 MappingJackson2HttpMessageConverter,就好了。
@GetMapping(value = "/err2", produces = {"application/json"})
//由于StringHttpConveter优先级太高,且解析的类型是ALL,包含了application/json, 所以不能用String作为返回值,应该用个其他类型,这样就不会触发StringHttpConveter
public Article err2() {
// exceptionService.systemBizError();
Article tiele = Article.builder().title("tiele").build();
return tiele;
}