前言

在日常我的项目开发中,异样是常见的,然而如何更高效的解决好异样信息,让咱们能疾速定位到BUG,是很重要的,不仅可能进步咱们的开发效率,还能让你代码看上去更难受,SpringBoot的我的项目曾经有肯定的异样解决了,然而对于咱们开发者而言可能就不太适合了,因而咱们须要对这些异样进行对立的捕捉并解决。

SpringBoot默认的错误处理机制

返回谬误页面

默认返回 Whitelabel Error Page页面的款式太枯燥,用户体验不好。

如 果 我 们 需 要 将 所 有 的 异 常 同 一 跳 转 到 自 定 义 的 错 误 页 面 , 需 要 再 src/main/resources/templates 目录下创立 error.html 页面。

留神:名称必须叫 error

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title></head><body>        <!--SpringBoot默认存储异样信息的key为exception-->    <span th:text="${exception}" /></body></html>

返回json格局api

Json格局的后果字符串不对立,与前端人员约定对立格局不统一

源码剖析

SpringBoot在页面 产生异样的时候会主动把申请转到/error,SpringBoot内置了一个BasicErrorController对异样进行对立的解决,当然也能够自定义这个门路

@RequestMapping(        produces = {"text/html"}    )    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {        HttpStatus status = this.getStatus(request);        Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.getErrorAttributeOptions(request, MediaType.TEXT_HTML)));        response.setStatus(status.value());        ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);        return modelAndView != null ? modelAndView : new ModelAndView("error", model);    }    @RequestMapping    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {        HttpStatus status = this.getStatus(request);        if (status == HttpStatus.NO_CONTENT) {            return new ResponseEntity(status);        } else {            Map<String, Object> body = this.getErrorAttributes(request, this.getErrorAttributeOptions(request, MediaType.ALL));            return new ResponseEntity(body, status);        }    }

咱们能够看到刚好对照两个办法一个返回谬误页面,一个返回谬误字符,默认谬误门路是/error如果有自定义就用自定义的

server.error.path=/custom/error

自定义错误处理

SpringBoot提供了ErrorAttribute类型
自定义ErrorAttribute类型的bean还是默认的两种响应形式,只不过扭转了响应内容项而已

package cn.soboys.core;import cn.hutool.core.bean.BeanUtil;import cn.soboys.core.ret.Result;import cn.soboys.core.ret.ResultCode;import cn.soboys.core.ret.ResultResponse;import org.springframework.boot.web.error.ErrorAttributeOptions;import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;import org.springframework.stereotype.Component;import org.springframework.web.context.request.WebRequest;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.util.Map;/** * @author kenx * @version 1.0 * @date 2021/6/18 14:14 * 全局谬误 */@Componentpublic class GlobalErrorHandler extends DefaultErrorAttributes {    /**     * 自定义谬误返回页面     * @param request     * @param response     * @param handler     * @param ex     * @return     */    @Override    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {        return super.resolveException(request, response, handler, ex);    }    /**     * 自定义谬误返回格局     *     * @param webRequest     * @param options     * @return     */    @Override    public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {        Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, options);        Result result = ResultResponse.failure(ResultCode.NOT_FOUND, errorAttributes.get("path"));        Map map = BeanUtil.beanToMap(result, true, true);        return map;    }}

自定义业务异样类

继承RuntimeException

package cn.soboys.core.authentication;import cn.soboys.core.ret.ResultCode;import lombok.Data;/** * @author kenx * @version 1.0 * @date 2021/6/22 13:58 * 认证异样 */@Datapublic class AuthenticationException extends RuntimeException {    public AuthenticationException(String message) {        super(message);    }}

全局捕捉异样

通过SpringBoot提供的@RestControllerAdvice@ControllerAdvice 联合@ExceptionHandler应用

@RestControllerAdvice@ControllerAdvice区别和@RestController,@Controller一样如果想返回json格局也能够独自应用@ResponseBody注解在办法上

须要捕捉什么异样通过@ExceptionHandler来指定对应异样类就能够了这里准则是依照从小到大异样进行顺次执行

艰深来讲就是当小的异样没有指定捕捉时,大的异样蕴含了此异样就会被执行比方Exception 异样蕴含了所有异样类,是所有异样超级父类,当呈现没有指定异样时此时对应捕捉了Exception异样的办法会执行

@ExceptionHandler注解解决异样

@Controllerpublic class DemoController {    @RequestMapping("/show")    public String showInfo() {        String str = null;        str.length();        return "index";    }    @RequestMapping("/show2")    public String showInfo2() {        int a = 10 / 0;        return "index";    }    /**     * java.lang.ArithmeticException 该办法须要返回一个 ModelAndView:目标是能够让咱们封装异样信息以及视     * 图的指定 参数 Exception e:会将产生异样对象注入到办法中     */    @ExceptionHandler(value = { java.lang.ArithmeticException.class })    public ModelAndView arithmeticExceptionHandler(Exception e) {        ModelAndView mv = new ModelAndView();        mv.addObject("error", e.toString());        mv.setViewName("error1");        return mv;    }    /**     * java.lang.NullPointerException 该办法须要返回一个 ModelAndView:目标是能够让咱们封装异样信息以及视     * 图的指定 参数 Exception e:会将产生异样对象注入到办法中     */    @ExceptionHandler(value = { java.lang.NullPointerException.class })    public ModelAndView nullPointerExceptionHandler(Exception e) {        ModelAndView mv = new ModelAndView();        mv.addObject("error", e.toString());        mv.setViewName("error2");        return mv;    }}

长处:能够自定义异样信息存储的key,自定义跳转视图的名称

毛病:须要编写大量的异样解决办法,不能跨controller,如果两个controller中呈现同样的异样,须要从新编写异样解决的办法

@ControllerAdvice+@ExceptionHandler 注解解决异样

/** * @author kenx * @version 1.0 * @date 2021/6/17 20:19 * 全局异样对立解决 */@RestControllerAdvicepublic class GlobalExceptionHandler { /**     * 认证异样     * @param e     * @return     */    @ExceptionHandler(AuthenticationException.class)    public Result UnNoException(AuthenticationException e) {        return ResultResponse.failure(ResultCode.UNAUTHORIZED,e.getMessage());    }    /**     *     * @param e 未知异样捕捉     * @return     */    @ExceptionHandler(Exception.class)    public Result UnNoException(Exception e) {        return ResultResponse.failure(ResultCode.INTERNAL_SERVER_ERROR, e.getMessage());    }}

长处:能够自定义异样信息存储的key,自定义跳转视图的名称,跨controller对立拦挡对立捕捉,个别都是应用这种

关注公众号猿人生理解更多好文