为了账号安全,请及时绑定邮箱和手机立即绑定

Spring Boot:异常处理机制

标签:
SpringBoot

最近公司的项目正在重构,我正好担任了这个重任,采用的是Spring BootDocker的方式,因此很长时间没在更新博客了,在接下一段时间中我会将Spring Boot构建项目这块持续更新,最终能构建一个完整的Spring Boot基础架构,并开源出来分享给大家,Spring Cloud的那个项目在之后还会持续更新的。

Spring Boot中,当最终有未处理的异常抛出的时候,Servlet容器仍然会发送/error请求,但是和spring mvc不同的是,Spring Boot提供了内置的BasicErrorController处理全局的错误信息,不需要任何其他的配置。

下面通过一个简单的例子验证一下Spring Boot中默认的异常处理流程:

  1. 首先在SysUserController中映射index请求,接口中什么都不做,仅抛出一个RuntimeException异常。

/**
 * 系统用户
 * @Auther: hrabbit
 * @Date: 2018-12-17 6:21 PM
 * @Description:
 */@Controller@RequestMapping("user")public class SysUserController {    /**
     * 主页
     * @return
     */
    @RequestMapping("/")    @ResponseBody
    public String index(){        throw new RuntimeException("page error!");
    }

}

请求http://localhost:8080/user/页面出现如下的效果

webp

image.png


我们可以从图中看到默认Spring Boot有一个请求/error的mapping,实际上,Spring Boot已经为我们提供了/error请求的controller,它就是BasicErrorController。


BasicErrorController的源码如下:

@Controller@RequestMapping({"${server.error.path:${error.path:/error}}"})public class BasicErrorController extends AbstractErrorController {    // ... 省略构造函数
    public String getErrorPath() {        return this.errorProperties.getPath();
    }    @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.isIncludeStackTrace(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) {
        Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
        HttpStatus status = this.getStatus(request);        return new ResponseEntity(body, status);
    }    protected ErrorProperties getErrorProperties() {        return this.errorProperties;
    }    
    // ... 省略其他方法}
  • BasicErrorController处理{server.error.path:{error.path:/error}请求。意思是:

    • 如果在application.properties中设置了server.error.path,就映射该值;

    • 而如果error.path有值就映射该值

    • 最后否则映射/error
      所以,优先级=> server.error.path>error.path>/error,可以通过修改server.error.patherror.pathBasicErrorController不再处理error请求。

  • BasicErrorControllererrorHtmlerror两种不同的处理接口处理请求,其errorHtml特指http请求中accept属性值为text/html的请求。

如果请求的返回类型不同,可以为一个请求通过设置produces指定特定的返回类型。

自定义错误页面

Spring Boot默认的错误页面显然不能满足开发的正常需求,通过在src/main/resources/templates文件夹中添加error.html错误页面实现自定义错误信息。还可以通过在src/main/resources/templates/error中添加404.html等以http错误码开头的页面实现不同http错误状态的不同展现。结构如下图:

webp

image.png


当我们再次访问http://localhost:8080/user/页面出现如下的效果:

webp

image.png


统一异常处理

前文说过,/error请求的触发前提是系统中抛出的异常到最终都没有被处理掉,Spring Boot可以通过@ControllerAdvice@ExceptionHandler实现捕获系统中的异常**,需要注意的是,如果@ControllerAdvice中如果有其他异常没有捕获到,最终仍然会通过BasicErrorController处理这些异常。

统一异常处理部分代码如下:

/**
 * 异常类
 * @Auther: hrabbit
 * @Date: 2018-11-15 3:40 PM
 * @Description:
 */@ControllerAdvice("com.hrabbit.admin")@Order(-1)@Slf4jpublic class GlobalExceptionHandler {    /**
     * Shiro权限异常
     * @param model
     * @param ex
     * @return
     */
    @ExceptionHandler(SysUserException.class)    @ResponseStatus(HttpStatus.UNAUTHORIZED)    public String sysUserExceptionHandler(Model model,SysUserException ex) {
        model.addAttribute("msg",ex.getMessage());        return "login";
    }    /**
     * Shiro权限异常
     * @param response
     * @param ex
     * @return
     */
    @ExceptionHandler(UnauthorizedException.class)    @ResponseBody
    public BaseResponse shiroExceptionHandler(HttpServletResponse response, Exception ex) {
        log.error(ex.getMessage(),ex);        return new BaseResponse(CommonConstants.SHESHU_USER_SHIRO_INVALID_CODE, "对不起,你没有此权限!");
    }    /**
     * 用户未登录异常
     */
    @ExceptionHandler(AuthenticationException.class)    @ResponseStatus(HttpStatus.UNAUTHORIZED)    public String unAuth(AuthenticationException e,Model model) {
        model.addAttribute("msg","请检查用户权限!");        return "/login";
    }
}



作者:hrabbits
链接:https://www.jianshu.com/p/20aa608c4f09


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消