Spring Boot统一REST API接口响应格式和异常处理
前言
在REST API接口中,非常有必要统一接口响应格式。
示例:
{
"code": 0,
"message": "OK",
"data": {
}
}
- code为结果编码,一般0表示成功,其它表示失败
- message为结果描述或错误信息
- data为业务数据,可以为空
定义统一的接口响应格式
定义ApiResponse类来作为统一的接口响应对象。
@Data
@Builder
@Slf4j
public class ApiResponse<T> implements Serializable {
private static final long serialVersionUID = 1L;
private int code;
private String message;
private T data;
public static <T> ApiResponse success(T data) {
ApiResponse response = ApiResponse.builder().code(ReturnCode.SUCCESS.getCode()).message(ReturnCode.SUCCESS.getMessage()).data(data).build();
log.info("Success API Response: {}", response.toString());
return response;
}
public static ApiResponse success() {
return success(null);
}
public static <T> ApiResponse fail(int code, String message) {
ApiResponse response = ApiResponse.builder().code(code).message(message).build();
log.error("Failed API Response: {}", response.toString());
return response;
}
public static <T> ApiResponse fail(ReturnCode returnCode) {
return fail(returnCode.getCode(), returnCode.getMessage());
}
public static <T> ApiResponse fail() {
return fail(ReturnCode.FAILED);
}
public static <T> ApiResponse fail(String message) {
return fail(ReturnCode.FAILED.getCode(), message);
}
}
定义ReturnCode枚举类来存储系统的错误代码和相应的错误信息:
@Getter
@AllArgsConstructor
public enum ReturnCode {
SUCCESS(0, "OK"),
FAILED(-1, "Failed");
private final int code;
private final String message;
}
后续增加系统错误代码时,只需要将新的错误代码和相应的错误信息添加到该枚举类中。
接口调用成功时返回统一的接口响应格式
在REST API接口调用时,通过ApiResponse.success()方法返回统一的接口响应格式。
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@PostMapping("/user")
public ApiResponse addUser(@RequestBody User user) {
userMapper.insertSelective(user);
return ApiResponse.success();
}
@GetMapping("/user/{id}")
public ApiResponse getUser(@PathVariable("id") String id) {
return ApiResponse.success(userMapper.selectByPrimaryKey(Long.valueOf(id)));
}
}
发生异常时返回统一的接口响应格式
一般是先自定义一个RuntimeException类,该类中包含错误代码和相应的错误信息。
@Getter
public class ServiceException extends RuntimeException {
private int code;
public ServiceException(int code, String message) {
super(message);
this.code = code;
}
public ServiceException(ReturnCode returnCode) {
super(returnCode.getMessage());
this.code = returnCode.getCode();
}
}
再定义一个Controller异常处理器来捕获Controller抛出的该RuntimeException,再通过ApiResponse.fail()方法返回统一的接口响应格式。
@Slf4j
@ControllerAdvice
public class ControllerExceptionHandler {
@ExceptionHandler(ServiceException.class)
@ResponseBody
public ApiResponse handleServiceException(ServiceException e) {
log.error(e.getMessage(), e);
return ApiResponse.fail(e.getCode(), e.getMessage());
}
@ExceptionHandler(BindException.class)
@ResponseBody
public AjaxResult handleBindException(BindException e)
{
log.error(e.getMessage(), e);
String message = e.getAllErrors().get(0).getDefaultMessage();
return ApiResponse.fail(message);
}
@ExceptionHandler(Exception.class)
@ResponseBody
public AjaxResult handleException(Exception e)
{
log.error(e.getMessage(), e);
return ApiResponse.fail(e.getMessage());
}
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public AjaxResult handleRuntimeException(RuntimeException e)
{
log.error(e.getMessage(), e);
return ApiResponse.fail(e.getMessage());
}
}