微信公众号:Java患者
专注Java领域技术分享
Spring boot的默认异常处理机制
我们以访问一个不存在的页面的场景为例,结果是返回一个错误页面:
而我们一个前后端分离的架构,我们写的Restful API往往会被多个渠道访问,比如浏览器,app。而我们的spring boo会根据不同的渠道做出不同的响应,是浏览器发的就返回html,不是则是json。若报错回跳转到/error的URL,同一个URL不同的处理方式是由Spring boot提供的BasicErrorController错误控制器实现的。
// 如果请求头中accept有text/html这个值 @RequestMapping(produces = "text/html") public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { HttpStatus status = getStatus(request); Map model = Collections.unmodifiableMap(getErrorAttributes( request, isIncludeStackTrace(request, MediaType.TEXT_HTML))); response.setStatus(status.value()); ModelAndView modelAndView = resolveErrorView(request, response, status, model); return (modelAndView == null ? new ModelAndView("error", model) : modelAndView); } // 没有则进到到这个方法里面 @RequestMapping @ResponseBody public ResponseEntity> error(HttpServletRequest request) { Map body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL)); HttpStatus status = getStatus(request); return new ResponseEntity>(body, status); }
当我们对请求的参数进行校验,当校验不通过时,spring boot会返回一个400状态码,并且并把我们所有的错误信息放进一个error里面来告诉我们客户端哪些字段有问题,问题是什么。
{ "timestamp": 1584868482621, "status": 400, "error": "Bad Request", "exception": "org.springframework.web.bind.MethodArgumentNotValidException", "errors": [ { "codes": [ "NotBlank.user.password", "NotBlank.password", "NotBlank.java.lang.String", "NotBlank" ], "arguments": [ { "codes": [ "user.password", "password" ], "arguments": null, "defaultMessage": "password", "code": "password" } ], "defaultMessage": "密码不能为空", "objectName": "user", "field": "password", "rejectedValue": null, "bindingFailure": false, "code": "NotBlank" } ], "message": "Validation failed for object='user'. Error count: 1", "path": "/user/1"}
进入到服务里面抛出异常的处理机制
一般如果是在我们的服务里面报的错误,Spring boot默认会响应给浏览器的是一个状态码的500的服务器错误。
我们用postman模拟其他的渠道,返回的是:
{ "timestamp": 1584869332592, "status": 500, "error": "Internal Server Error", "exception": "java.lang.RuntimeException", "message": "user not exist", "path": "/user/1"}
浏览器端自定义错误处理机制
虽然由spring boot提供的默认处理机制可以很好的处理我们的异常。但有时候,我们也要去自定义异常处理来满足我们特定的需求场景。那么该如何自定义异常处理的呢?
下面我们来实现404和500跳转到我们指定的页面,在我们的resources目录下创建我们相应的的html文件。注意文件目录和文件名要固定。
浏览器访问结果是跳转到我们特定的页面,
这种方式是安装spring boot的约束来自定义的,他仅能适用于浏览器的请求,而对app返回的任然是json。
其他的客户端自定义错误处理机制
有些时候,我们的想要的异常返回结果还需要有其他的错误信息。下面我来实现用户不存在的异常。并且返回的异常包含不存在的用户得id。
public class UserNotExistException extends RuntimeException { private static final long serialVersionUID = -6112780192479692859L; private String id; public UserNotExistException(String id) { super("user not exist"); this.id = id; } public String getId() { return id; } public void setId(String id) { this.id = id; }}
我们在服务里面抛出这个异常
@GetMapping("{id:\\d+}") @JsonView(User.UserDetailView.class) public User getUserInfo(@PathVariable(name = "id") String id){ throw new UserNotExistException(id); }
用我们postman访问:
{ "timestamp": 1584870909493, "status": 500, "error": "Internal Server Error", "exception": "com.zhaohong.exception.UserNotExistException", "message": "user not exist", "path": "/user/1"}
我们可以看到异常变了,是UserNotExistException,由于默认情况下,返回的异常不会去读message之外的信息,所以返回的结果中并没有包含用户的id,那么如何把这个id返回给前台。
下面我们自定义一个异常处理器。
@ControllerAdvicepublic class ControllerExceptionHandler { @ExceptionHandler(UserNotExistException.class) @ResponseBody @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Map handleUserNotExistException(UserNotExistException ex) { Map result = new HashMap<>(); result.put("id", ex.getId()); result.put("message", ex.getMessage()); return result; }}
@ExceptionHandler指定了要捕获的异常,@ResponseStatus指定返回的状态码。
我们再次反问服务,结果是返回:
{ "id": "user not exist", "message": "user not exist"}
查看
![d0b6b10edc48fe61be1e5569121bb0fe.png](https://img-blog.csdnimg.cn/img_convert/d0b6b10edc48fe61be1e5569121bb0fe.png)