写在最前
统一接口响应与异常响应是基本的开发规范,如今我们的项目已大多是前后端分离的方式,统一处理响应,能够减少前后端团队联调接口的不必要的沟通。
统一接口响应
本 Demo 改造
mingyue-springboo-api
,原接口代码如下:
@GetMapping("/{userId}")
public ResponseEntity<MingYueUser> queryUserById(@PathVariable Long userId) {
return ResponseEntity.ok(mingYueUserService.queryUserById(userId));
}
原接口响应如下:
{
"userId": 1,
"username": "mingyue"
}
1. 添加统一响应类
package com.csp.mingyue.global.util;
import com.csp.mingyue.global.constant.CommonConstants;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* 响应信息主体
*
* @param <T>
* @author Strive
*/
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class R<T> implements Serializable {
private static final long serialVersionUID = 1L;
@Getter
@Setter
private int code;
@Getter
@Setter
private String msg;
@Getter
@Setter
private T data;
public static <T> R<T> ok() {
return restResult(null, CommonConstants.SUCCESS, null);
}
public static <T> R<T> ok(T data) {
return restResult(data, CommonConstants.SUCCESS, null);
}
public static <T> R<T> ok(T data, String msg) {
return restResult(data, CommonConstants.SUCCESS, msg);
}
public static <T> R<T> failed() {
return restResult(null, CommonConstants.FAIL, null);
}
public static <T> R<T> failed(String msg) {
return restResult(null, CommonConstants.FAIL, msg);
}
public static <T> R<T> failed(T data) {
return restResult(data, CommonConstants.FAIL, null);
}
public static <T> R<T> failed(T data, String msg) {
return restResult(data, CommonConstants.FAIL, msg);
}
public static <T> R<T> restResult(T data, int code, String msg) {
R<T> apiResult = new R<>();
apiResult.setCode(code);
apiResult.setData(data);
apiResult.setMsg(msg);
return apiResult;
}
}
2. 编写响应接口
@GetMapping("/{userId}")
public R<MingYueUser> queryUserById(@PathVariable Long userId) {
return R.ok(mingYueUserService.queryUserById(userId));
}
3. 测试接口响应
curl --location --request GET 'http://127.0.0.1:8080/user/1' \
--header 'User-Agent: Apifox/1.0.0 (https://www.apifox.cn)' \
--header 'Accept: */*' \
--header 'Host: 127.0.0.1:8080' \
--header 'Connection: keep-alive'
接口响应如下:
{
"code": 0,
"msg": null,
"data": {
"userId": 1,
"username": "mingyue"
}
}
统一异常处理
1. 添加自定义业务异常
package com.csp.mingyue.global.exception;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author Strive
* @date 2018/6/22 16:21:57
*/
@Data
@NoArgsConstructor
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = 1L;
/**
* 状态码
*/
private int code;
public BusinessException(String message) {
super(message);
}
public BusinessException(int code, String message){
super(message);
this.code = code;
}
}
2. 添加全局异常处理
package com.csp.mingyue.global.handler;
import com.csp.mingyue.global.exception.BusinessException;
import com.csp.mingyue.global.util.R;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @author Strive
* @date 2023/5/8 17:16
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 捕获 Controller 中抛出的指定类型的异常,也可以指定其他异常
* @param exception
* @return
* @param <E>
*/
@ExceptionHandler(value = Exception.class)
public <E>R<E> handler(Exception exception){
if (exception instanceof BusinessException){
BusinessException businessException = (BusinessException) exception;
return R.failed(businessException.getCode(),businessException.getMessage());
} else {
return R.failed(500, "系统异常:" + exception.getMessage());
}
}
}
3. 编写异常接口
@GetMapping("/exception/{userId}")
public R<MingYueUser> queryUserByIdError(@PathVariable Long userId) {
if (1 == 1) {
throw new BusinessException(316, "测试业务异常返回");
}
return R.ok(mingYueUserService.queryUserById(userId));
}
4. 测试异常接口返回
curl --location --request GET 'http://127.0.0.1:8080/user/exception/1' \
--header 'User-Agent: Apifox/1.0.0 (https://www.apifox.cn)' \
--header 'Accept: */*' \
--header 'Host: 127.0.0.1:8080' \
--header 'Connection: keep-alive'
接口响应如下:
{
"code": 316,
"msg": "测试业务异常返回",
"data": null
}
小结
- @ControllerAdvice、@RestControllerAdvice 即可开启全局异常处理,使用该注解表示开启了全局异常的捕获。
- @ExceptionHandler 注解定义捕获异常的类型即可对这些捕获的异常进行统一的处理。