[记录] 使用WebExceptionHandler/ResponseBodyAdvice 全局异常捕获时的一点小错误

362 阅读2分钟

场景: 了解到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;
    }