1. 定义自定义异常
首先,我们需要定义一个或多个自定义异常类。这些类通常会继承 RuntimeException
或 Exception
类,取决于异常是否需要被检查。
示例定义
假设定义了一个名为 ResourceNotFoundException
的异常,它将在资源未找到时抛出:
public class ResourceNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
public ResourceNotFoundException(String message) {
super(message);
}
public ResourceNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}
2. 抛出自定义异常
接下来,在业务逻辑中,当发生特定情况时,可以抛出这些自定义异常。
示例抛出
假设我们有一个 UserService
类,它负责处理用户数据:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public User getUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + id));
}
}
3. 处理自定义异常
为了优雅地处理这些异常,可以使用 @ControllerAdvice
注解来创建一个全局的异常处理器。这样,就不必在每个控制器中重复相同的异常处理代码。
示例处理
创建一个名为 GlobalExceptionHandler
的类,该类包含一个或多个 @ExceptionHandler
方法:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ResponseEntity<ErrorResponse> handleResourceNotFoundException(ResourceNotFoundException ex) {
ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.NOT_FOUND.value(),
ex.getMessage()
);
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {
ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.INTERNAL_SERVER_ERROR.value(),
"An unexpected error occurred: " + ex.getMessage()
);
return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
class ErrorResponse {
private int status;
private String message;
public ErrorResponse(int status, String message) {
this.status = status;
this.message = message;
}
// Getters and setters...
}
在这个例子中,有两个 @ExceptionHandler
方法:
handleResourceNotFoundException
方法用于处理ResourceNotFoundException
异常,并返回一个404 Not Found
HTTP 响应。handleAllExceptions
方法用于处理所有其他未被捕获的异常,并返回一个500 Internal Server Error
HTTP 响应。
4. 测试异常处理
为了验证异常处理是否按预期工作,可以编写一个简单的 REST 控制器来测试这些异常:
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
User user = userService.getUserById(id);
return ResponseEntity.ok(user);
}
}
然后,可以发送一个请求到 /api/users/1
(假设数据库中没有这个ID对应的用户)来测试 ResourceNotFoundException
是否被正确处理。
5. 运行和调试
可以运行 Spring Boot 应用程序,并尝试访问上述 REST API 路径。如果一切正常,能够看到适当的 HTTP 响应代码以及错误消息。
6. 扩展功能
还可以扩展此设计以支持更多的异常类型,例如:
BadRequestException
当客户端请求不合法时抛出。UnauthorizedAccessException
当用户尝试访问他们无权访问的数据时抛出。
7. 使用自定义异常的好处
精确错误信息
:自定义异常允许提供更具体的错误信息,这在调试和日志记录时非常有用。更好的错误处理
:通过在特定位置捕获和处理异常,可以避免全局异常处理带来的过度捕获问题。代码可读性
:自定义异常类名和消息可以更好地反映错误的性质,提高代码的可读性和可维护性。
结论
通过定义自定义异常并在 Spring 中优雅地处理它们,可以让代码更加清晰和具有针对性。通过定义自己的异常类型,可以提供更具体的错误信息,帮助开发者更容易地定位问题所在,从而提高用户体验并简化开发流程。