这种错误交给前端无法处理。
- 需要自定义一些错误响应类给前端
package cn.yam.bloomfilter.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<Map<String, Object>> handleAllExceptions(Exception ex) {
Map<String, Object> response = new HashMap<>();
response.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value());
response.put("message", "服务器内部错误");
return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
- 创建一个全局异常处理类。
- 使用
@ControllerAdvice
和@ExceptionHandler
注解。| - 定义返回 JSON 格式的错误响应
处理完成之后,就变成如下图所示。
如何自定义发现的异常
以请求参数错误为例子:
- 定义一个 异常类
InvalidParameterException
package cn.yam.bloomfilter.exception;
public class InvalidParameterException extends RuntimeException {
public InvalidParameterException(String message) {
super(message);
}
}
- 抛出
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
User user = userService.getUserById(id);
if (user == null) {
throw new InvalidParameterException("用户ID: " + id);
}
return ResponseEntity.ok(user);
}
}
- 全局异常异常处理器
package cn.yam.bloomfilter.exception;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(InvalidParameterException.class)
public ResponseEntity<Map<String, Object>> handleInvalidParameterException(InvalidParameterException ex) {
Map<String, Object> response = new HashMap<>();
response.put("status", HttpStatus.BAD_REQUEST.value());
response.put("message", "参数错误: " + ex.getMessage());
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
}
探究 ResponseEntity
作用
场景描述
假设我们有一个 /resource/{id}
接口,用于根据 ID 查找资源。如果资源不存在,返回 404 Not Found
和错误信息;如果资源存在,返回 200 OK
和资源数据。
- 不加
ResponseEntity
的例子
package cn.yam.bloomfilter.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class ResourceController {
@GetMapping("/resource/{id}")
public Map<String, Object> getResource(@PathVariable int id) {
Map<String, Object> response = new HashMap<>();
// 模拟资源查找
if (id == 1) {
response.put("data", "Resource Data");
} else {
response.put("status", 404);
response.put("message", "资源未找到");
}
return response;
}
}
测试结果
- 请求
/resource/1
:- 响应体:
{
"data": "Resource Data"
}
- 状态码: `200 OK`(默认状态码)
- 请求
/resource/2
:- 响应体:
{
"status": 404,
"message": "资源未找到"
}
- 状态码: `200 OK`(默认状态码)
问题
- 即使资源未找到,状态码仍然是
200 OK
,这不符合 RESTful API 的设计规范。 - 客户端无法通过状态码快速判断请求是否成功。
- 加
ResponseEntity
的例子
package cn.yam.bloomfilter.controller;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class ResourceController {
@GetMapping("/resource/{id}")
public ResponseEntity<Map<String, Object>> getResource(@PathVariable int id) {
Map<String, Object> response = new HashMap<>();
// 模拟资源查找
if (id == 1) {
response.put("data", "Resource Data");
return new ResponseEntity<>(response, HttpStatus.OK);
} else {
response.put("status", 404);
response.put("message", "资源未找到");
return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
}
}
}
测试结果
- 请求
/resource/1
:- 响应体:
{
"data": "Resource Data"
}
- 状态码: `200 OK`
- 请求
/resource/2
:- 响应体:
{
"status": 404,
"message": "资源未找到"
}
- 状态码: `404 Not Found`
优点
- 状态码和响应体都符合 RESTful API 的设计规范。
- 客户端可以通过状态码快速判断请求是否成功。
- 对比总结
特性 | **不加 **ResponseEntity | **加 **ResponseEntity |
---|---|---|
状态码控制 | 无法动态设置状态码,默认返回 200 OK 。 | 可以动态设置状态码(如 200 OK 、404 Not Found )。 |
响应体 | 可以返回自定义 JSON 数据。 | 可以返回自定义 JSON 数据。 |
是否符合 RESTful 规范 | 不符合,状态码无法反映实际错误。 | 符合,状态码和响应体都能正确反映请求结果。 |
客户端处理 | 客户端需要解析响应体才能判断是否出错。 | 客户端可以通过状态码快速判断是否出错。 |
常见异常总结:
- 参数错误
// 访问的是http://localhost:8080/api/users/id
// id 默认是1-5 ,测试访问http://localhost:8080/api/users/999
- 定义
InvalidParameterException
异常类
package cn.yam.bloomfilter.exception;
public class InvalidParameterException extends RuntimeException {
public InvalidParameterException(String message) {
super(message);
}
}
- 在控制层抛出
InvalidParameterException
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
User user = userService.getUserById(id);
if (user == null) {
throw new InvalidParameterException("用户ID: " + id);
}
return ResponseEntity.ok(user);
}
}
- 在全局异常拦截类中拦截
package cn.yam.bloomfilter.exception;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public Object handleAllExceptions(Exception ex) {
Map<String, Object> response = new HashMap<>();
response.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value());
response.put("message", ex.getMessage());
return response;
}
@ExceptionHandler(InvalidParameterException.class)
public ResponseEntity<Map<String, Object>> handleInvalidParameterException(InvalidParameterException ex) {
Map<String, Object> response = new HashMap<>();
response.put("status", HttpStatus.BAD_REQUEST.value());
response.put("message", "参数错误: " + ex.getMessage());
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
}
- 路径匹配错误
// 访问的是http://localhost:8080/ap##??djjd
- 补充
yml
配置
spring:
mvc:
throw-exception-if-no-handler-found: true
web:
resources:
add-mappings: false
- 用来兜底处理所有未被特定异常处理器捕获的异常。
package cn.yam.bloomfilter.exception;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public Object handleAllExceptions(Exception ex) {
Map<String, Object> response = new HashMap<>();
response.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value());
response.put("message", ex.getMessage());
return response;
}
}