Spring Boot:异常处理机制
最近公司的项目正在重构,我正好担任了这个重任,采用的是Spring Boot
和Docker
的方式,因此很长时间没在更新博客了,在接下一段时间中我会将Spring Boot
构建项目这块持续更新,最终能构建一个完整的Spring Boot
基础架构,并开源出来分享给大家,Spring Cloud
的那个项目在之后还会持续更新的。
在Spring Boot
中,当最终有未处理的异常抛出的时候,Servlet
容器仍然会发送/error
请求,但是和spring mvc
不同的是,Spring Boot
提供了内置的BasicErrorController
处理全局的错误信息,不需要任何其他的配置。
下面通过一个简单的例子验证一下Spring Boot
中默认的异常处理流程:
首先在
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/
页面出现如下的效果
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处理{error.path:/error}请求。意思是:
如果在
application.properties
中设置了server.error.path
,就映射该值;而如果
error.path
有值就映射该值最后否则映射
/error
所以,优先级=>server.error.path
>error.path
>/error
,可以通过修改server.error.path
和error.path
让BasicErrorController
不再处理error
请求。
BasicErrorController
有errorHtml
和error
两种不同的处理接口处理请求,其errorHtml
特指http
请求中accept
属性值为text/html
的请求。
如果请求的返回类型不同,可以为一个请求通过设置produces
指定特定的返回类型。
自定义错误页面
Spring Boot
默认的错误页面显然不能满足开发的正常需求,通过在src/main/resources/templates
文件夹中添加error.html
错误页面实现自定义错误信息。还可以通过在src/main/resources/templates/error
中添加404.html等以http错误码开头的页面实现不同http错误状态的不同展现。结构如下图:
image.png
当我们再次访问http://localhost:8080/user/
页面出现如下的效果:
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
共同学习,写下你的评论
评论加载中...
作者其他优质文章