一.导学
- Spring boot中默认的错误处理机制
- 自定义异常处理
二.spring boot中默认的错误处理机制
- 访问一个不存在的url
http://localhost:8070/xxx
- 浏览器的默认错误如下图所示
- 浏览器的处理(我们先访问正常页面)
http://localhost:8070/user/1
-
获取用户信息的请求,返回的是json格式的用户信息
-
我们再访问不存在的url 看看浏览器是怎么处理的
总结:浏览器发的时候响应是一段html,客户端发的时候是一段json。Spring boot默认处理机制,它会判断当前请求是浏览器发的还是客户端发送的,根据不同请求有不同的处理 -
我们来看看源码是怎么操作的
-
在BasicErrorController 这个类(Spring boot内部错误处理的控制器)
- 有两个RequstMapping
- 区别在于请求头中有没有text/html参数
- ResponseBody注解 把map转换成json
- 浏览器请求头第一个就是text/html
- 而客户端并不含有text/html
- restfull api 是通过http状态码返回不同的场景,所以这里status是404.而且请求响应状态也是404,自己在设计的时候可以参考这个思想
- 还有一个提示信息 “No message available” 404 状态就是没有找到可处理的路径,没有可用的信息也符合解释
- 但是在实际开发中,只是凭借http状态码的话,是不能解决实际场景中的需求的
- 比如创建用户信息,缺少字段,需要返回哪一个字段缺少
- 在spring 默认的处理中,使用 @Valid 但是不声明BindingResult的时候,会把很详细的验证信息返回去
@PostMapping
public User create(@Valid @RequestBody User user /*,BindingResult errors*/){
/* if(errors.hasErrors()){
errors.getAllErrors().stream().forEach(System.out::println);
}*/
System.out.println(user.getId());
System.out.println(user.getUsername());
System.out.println(user.getPassword());
System.out.println(user.getBirthday());
user.setId("1");
return user;
}
- json拼装成user对象(发送一段不合法的json 或者直接为空)
- 不满足这些注解条件 直接打回去 返回400 请求错误的状态码
- 400不足以告诉它发生了什么 你需要告诉它那个字段校验不过
- Errors里面有明确的错误信息
- 当发出请求不合法时,Spring boot会默认把这些错误请求收集起来拼成Errors返回给前台 根据这些信息可以看到那些信息有问题 问题是什么
- 前两个例子都是没有进入到自己写的控制器类,被spring框架打回去了 不管400还是404,然后错误信息给前端,让前端来处理
- 开发中最常见,进入到Controller方法中 甚至调用了一些服务层的服务 由这些服务抛出的异常,Spring boot这种情况默认是怎么处理的?
@GetMapping(value = "/{id:\\d+}")
@JsonView(User.UserDetailView.class)
public User getInfo(@PathVariable(name = "id") String idxxx){
throw new RuntimeException("user not exist");//简化 不写服务层了
}
-
浏览器响应
-
客户端响应
-
spring boot 默认的处理机制已经介绍完了,大部分默认的机制就能满足需要
-
下面介绍如果不满足需求,要怎么自定义处理行为
三.自定义错误处理
1.自定义浏览器错误处理
在资源文件夹下创建对应状态码的html页面就可以了
|- resources
|- error
|- 404.html
|- 500.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>404</title>
</head>
<body>
<h1>你访问的页面并不存在</h1>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>500</title>
</head>
<body>
<h1>服务器内部错误</h1>
</body>
</html>
- 验证一下效果
- 先访问一个不存在的url
http://localhost:8070/xxx
- 再访问一下
http://localhost:8070/user/1
- 看看是不是对客户端无效
- 仍然是json返回,定义404只对浏览器发出请求有作用,两者互不影响
2.自定义客户端错误处理
- 异常错误信息,有时候异常不止包含错误信息,可能包含一些其他信息
- 先自定义一个异常类
public class UserNotExistException extends RuntimeException{
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(value = "/{id:\\d+}")
@JsonView(User.UserDetailView.class)
public User getInfo(@PathVariable(name = "id") String idxxx){
throw new UserNotExistException(idxxx);
}
- 默认spring boot不会读异常以外的其他信息的,如何把id返回包含到json信息中?
- 异常处理器(这个类写的方法都是用来处理其他Controller所抛出的异常 本身不负责处理http请求 负责其他Controller抛出的异常)
@ControllerAdvice //任何控制器任何方法抛出这个异常 都会跳到这个方法中来处理
public class ControllerExceptionHandler {
@ExceptionHandler(UserNotExistException.class) //处理什么异常
@ResponseBody //把map转成json串给前端响应
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) //状态码 500
public Map<String,Object> handlerUserNotExistException(UserNotExistException ex){
Map<String,Object> map = new HashMap<>();
map.put("id",ex.getId());
map.put("message",ex.getMessage());
return map;
}
}
- 响应的json串完全根据自己写的map来定义的