前言

如果一个项目都包含了各种各样的服务。每个服务都又以不同的方式返回异常信息,这样排查的时候就会比较麻烦。如果我们定义一个标准的异常处理体系。并在所有的服务中使用。那样开发起来就可以快速定位。节约时间来摸🐟,并且页面也会更加的简单和直观。

本文开发环境

本文将会模拟异常

案例:查询数据库,发现返回的是 null,就抛出异常。

代码实现

new 一个 Springboot 应用

新建 entity 包,创建 User 实体类

1
2
3
4
5
6
7
8
@Data 	// 注意导Lombok,不然你也可以手动生成getter、setter
@NoArgsConstructor
@AllArgsConstructor
public class User {

private int id;
private String name;
}

new 一个 service 包,创建 UserService

1
2
3
4
5
6
7
8
@Service
public class UserService {

public User getOne(int id) {
// 模拟异常、向数据库查询User,但是数据库没有,返回null
return null;
}
}

这里就是模拟发生异常的案例,并没有真正的操作数据库。当调用 getOne 方法时,直接返回 null 就好啦

new 一个 exception 包,创建 NotFoundException 类

1
2
3
4
5
6
7
public class NotFoundException extends RuntimeException {

public NotFoundException(String message) {
super(message);
System.out.println("oh! bad 发生异常啦,异常info:" + message);
}
}

这里自定义了一个异常类继承了 RuntimeException,其作用就是当数据库查询的时候一旦发现返回值为 null,就直接抛出这个异常信息。

接着 new 一个 controlle r包,创建 UserController 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RestController
public class UserController {

@Autowired
private UserService userService;

@GetMapping("{id}")
public User getUser(@PathVariable int id) throws NotFoundException {
User user = userService.getOne(id);
if (user == null) {
throw new NotFoundException("id: " + id);
}
return user;
}
}

然后启动 Springboot,浏览器进行访问

500

可以发现报 500 服务器内部错误,但是你觉得这样好吗,用户看得懂 500 吗,我们项目里没有某个资源或者没有找到的话总不能提示服务器内部错误吧。所以呢,现在要对抛出的异常进行一个处理。

异常处理

1
2
3
4
5
6
7
8
@ResponseStatus(HttpStatus.NOT_FOUND)
public class NotFoundException extends RuntimeException {

public NotFoundException(String message) {
super(message);
System.out.println("oh! bad 发生异常啦,异常info:" + message);
}
}

在自定义异常类上加一个 @ResponseStatus 的注解来生成 404 Not Found 状态。

当然还有其他的状态。自己可以点击 HttpStatus 源码详看,根据自己的需要去返回。

我们使用 HttpStatus.NOT_FOUND,其作用就是用户访问的时候,一旦发生异常就会显示 404 错误。

启动 Springboot

404

可以发现不是服务器内部错误了

通用的异常处理

  1. 添加依赖(pom.xml)

    1
    2
    3
    4
    5
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.2</version>
    <dependency>
  2. 在 entity 包下创建异常实体类 ExceptionResponse

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @NoArgsConstructor
    @AllArgsConstructor
    public class ExceptionResponse {

    @Getter
    private Date date;
    @Getter
    private String msg;
    @Getter
    private String requestUrl;
    }

    这里只需要 getter 方法,setter 方法就不需要了,这个类的作用就是当有异常发生时,就把信息展示在页面上

  3. 在 exception 包下创建通用异常处理类 GeneralEntityExceptionHandler

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    @ControllerAdvice
    @RestController
    public class GeneralEntityExceptionHandler extends ResponseEntityExceptionHandler {

    /**
    * 此方法主要处理所有的异常信息(500)
    *
    * @param ex
    * @param request
    * @return
    */
    @ExceptionHandler(Exception.class)
    public final ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request) {
    // 当出现异常时,我们输出的信息,这里被封装在了ExceptionResponse
    ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), ex.getMessage(), request.getDescription(false));
    return new ResponseEntity(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    /**
    * 当页面资源没有找到时,抛出的异常(404)
    *
    * @param ex
    * @param request
    * @return
    */
    @ExceptionHandler(NotFoundException.class)
    public final ResponseEntity<Object> handleUserNotFoundExceptions(NotFoundException ex, WebRequest request) {
    ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), ex.getMessage(), request.getDescription(false));
    return new ResponseEntity(exceptionResponse, HttpStatus.NOT_FOUND);
    }
    }
  1. 启动 spring boot

    img

    这三个字段就是我们在 ExceptionResponse 自己定义的

    本文 Spring Boot 自定义通用异常 就到这了