springboot统一异常处理(返回json)并支持所有异常格式化返回

统一异常处理

当用spring boot开发后端时,我们常采用前后端分离的开发策略,这时候要求前端与后端需要进行数据交互,传统的一般采用json数据交互。

这时候我们要对spring boot的默认异常处理方式进行修改了,要统一返回数据格式,优雅的数据交互,优雅的开发应用。

首先我们要了解一般springboot的错误发生在什么地方。

一般发生在 controller业务层filter中(如spring security)拦截器中 、还有就是 未知错误 了。

下面我分享一下我的处理方式: @RestControllerAdvice + filter + 重写BasicErrorController 的处理方式。

@RestControllerAdvice

@RestControllerAdvice+@ExceptionHandler(Exception.class)可以处理经过controller的异常错误

@RestControllerAdvicepublic class BaseExceptionHandler {     private static final Logger logger = LoggerFactory.getLogger(BaseExceptionHandler.class);    /**     * 未知异常     * @param e 异常     * @return 统一结果返回     */    @ExceptionHandler(Exception.class)    public R exception(Exception e) {         logger.error(e.getMessage(), e);        return R.error().message(e.getMessage());    }    @ExceptionHandler(NoHandlerFoundException.class)    public R noHandlerFoundException(){         return R.error().message("当前页面不存在");    }}

filter捕获所有异常

当错误没有经过controller时,@RestControllerAdvice是不能捕获的,这时候就需要在filter进行处理。

public class ExceptionHandlerFilter implements Filter {     @Override    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain){         try {             filterChain.doFilter(servletRequest, servletResponse);        } catch (Exception e) {             ResponseUtils.out((HttpServletResponse) servletResponse, R.error().message(e.getMessage()));        }    }}

记得filter一定要注册到springboot才有作用,下面是我喜欢的一种方式

@BeanFilterRegistrationBean exceptionFilterRegistrationBean() {     FilterRegistrationBean bean = new FilterRegistrationBean<>();    bean.setFilter(new ExceptionHandlerFilter());    bean.setOrder(Ordered.HIGHEST_PRECEDENCE);//放在最前面    return bean;}

未知异常处理

当发生的异常不知道在哪时,springboot会进行默认异常处理,跳转到 /error

这时我们要统一数据返回就必须要从这下手了,创建一个新的Controller处理/error,继承 BasicErrorController ,并覆盖其中的方法

@RestControllerpublic class MyErrorController extends BasicErrorController {     @Autowired    public MyErrorController(ErrorAttributes errorAttributes,                             ServerProperties serverProperties,                             List errorViewResolvers) {         super(errorAttributes, serverProperties.getError(), errorViewResolvers);    }    @Override    public ModelAndView errorHtml(HttpServletRequest request,                                  HttpServletResponse response) {         HttpStatus status = getStatus(request);        Map model = Collections                .unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));//        return new ModelAndView("error", model, status);        ResponseUtils.out(response, R.error().code(status.value()).message((String) model.get("error")));        return null;    }    @Override    public ResponseEntity> error(HttpServletRequest request) {         Map body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));        //可以换成项目中自定义的通信json        Map resultBody = new HashMap<>(16);        resultBody.put("success", false);        resultBody.put("code", body.get("status"));        resultBody.put("message", body.get("error"));        Map data = new HashMap<>();        data.put("timestamp", body.get("timestamp"));        data.put("path", body.get("path"));        resultBody.put("data", data);        return new ResponseEntity<>(resultBody, HttpStatus.OK);    }}

配置文件

spring:  mvc:    throw-exception-if-no-handler-found: true  web:    resources:      add-mappings: falseserver:  error:    include-exception: true  servlet:    encoding:      charset: utf-8

统一结果返回的工具类

ResponseUtils

public class ResponseUtils {     public static void out(HttpServletResponse response, R r) {         ObjectMapper mapper = new ObjectMapper();        response.setStatus(HttpStatus.OK.value());        response.setContentType("application/json;charset=UTF-8");        try {             mapper.writeValue(response.getWriter(), r);        } catch (IOException e) {             e.printStackTrace();        }    }
@Datapublic class R implements Serializable {    private boolean success;    private Integer code;    private String message;    private Map data;    private R(){}    public static R ok(){        R r = new R();        r.setSuccess(true);        r.setCode(200);        r.setMessage("成功");        r.setData(new HashMap<>());        return r;    }    public static R error() {        R r = new R();        r.setSuccess(false);        r.setCode(500);        r.setMessage("失败");        r.setData(new HashMap<>());        return r;    }    public R success(Boolean success){        this.success = success;        return this;    }    public R code(Integer code){        this.code = code;        return this;    }    public R message(String message){        this.message = message;        return this;    }    public R data(String key, Object value){        this.data.put(key,value);        return this;    }    public R data(Map map){        this.setData(map);        return this;    }}
发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章