需求背景:这一天,前端 阿签 兴高采烈地来到公司,打卡后来到工位,打开电脑准备工作。昨天后端小伙伴刚提交了新的功能接口,又是联调接口的一天。原本兴致很高的 阿签 调着调着心里有点毛躁起来,这TM接口返回格式怎么和之前的接口又不一样,抛出异常时也是各种各样的。无疑增加 签哥 我的工作量吗?
为解决这一问题,对接口返回格式、异常进行了统一处理。
一、接口返回格式统一
(1)新建状态枚举类
定义状态枚举类 StatusCodeEnum 。便于后续使用
package com.hy.globalexception.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/***
* <p>
* 统一返回值状态码
* </p>
* @author hou yi
* @date 2021/7/24 19:13
**/
@Getter
@AllArgsConstructor
public enum StatusCodeEnum {
/**
* 描述
*/
PARAMETER_ERROR(102, "参数错误"),
SUCCESS(200, "请求成功"),
GLOBAL_EXCEPTION(301, "统一异常处理"),
FAIL(500, "请求失败"),
;
/**
* 状态码
*/
private final Integer code;
/**
* 状态描述
*/
private final String type;
}
(2)新建 接口、异常返回格式公用封装类
定义 ResultWrapper 返回格式公用封装类。 注:这里定义成泛型类。
package com.hy.globalexception.config;
import com.hy.globalexception.enums.StatusCodeEnum;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/***
* <p>
* 接口、异常返回格式封装类
* </p>
* @author hou yi
* @date 2021/9/30 14:58
**/
@Data
@Accessors(chain = true)
public class ResultWrapper<T> implements Serializable {
/**
* 状态码
*/
private Integer code;
/**
* 提示语
*/
private String msg;
/**
* 数据
* */
private T data;
/***
* 请求成功。无返回数据值
* @return 、
*/
public static <T> ResultWrapper<T> successBuilder(T t){
return new ResultWrapper<T>()
.setCode(StatusCodeEnum.SUCCESS.getCode())
.setMsg(StatusCodeEnum.SUCCESS.getMsg())
.setData(t);
}
/***
* 请求失败。无返回数据值
* @return 、
*/
public static <T> ResultWrapper<T> failBuilder(T t){
return new ResultWrapper<T>()
.setCode(StatusCodeEnum.FAIL.getCode())
.setMsg(StatusCodeEnum.FAIL.getMsg())
.setData(t);
}
}
(3)看一下效果
1)新建一个controller进行测试
package com.hy.globalexception.controller;
import com.hy.globalexception.config.ResultWrapper;
import com.hy.globalexception.service.ExceptionTestService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
/***
* <p>
* 统一返回值格式 测试 控制器
* </p>
* @author hou yi
* @date 2021/9/30 14:29
**/
@RestController
@RequestMapping("resultTest")
public class ResultTestController {
@GetMapping
public ResultWrapper<Object> find() {
// 注:实际开发中业务不在这里写,这里主要是方便测试
Map<String, Object> map = new HashMap<>();
map.put("name", "百里守约");
map.put("level", "T0");
map.put("property", "射手");
return ResultWrapper.successBuilder(map);
}
}
运行项目,启动完成后,使用 postman 工具看一下效果。效果如下:
二、统一异常处理
注:这里使用到上述 接口返回格式统一 中的两个工具类。
(1)新建控制层全局异常处理类
新建控制层全局异常处理类 GlobalExceptionHandle 。
package com.hy.globalexception.config;
import com.hy.globalexception.enums.StatusCodeEnum;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/***
* <p>
* 控制层全局异常处理
* </p>
* @author hou yi
* @date 2021/9/30 15:23
**/
@RestControllerAdvice
@SuppressWarnings("all")
public class GlobalExceptionHandle {
@ExceptionHandler(RuntimeException.class)
public ResultWrapper<Object> customException(RuntimeException e) {
return new ResultWrapper()
.setCode(StatusCodeEnum.GLOBAL_EXCEPTION.getCode())
.setMsg(e.getMessage());
}
}
(2)新建参数校验异常统一异常类
新建参数校验异常统一异常类 ValidateHandler 。
package com.hy.globalexception.config;
import com.hy.globalexception.enums.StatusCodeEnum;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
/***
* <p>
* 参数校验异常统一处理
* </p>
* @author hou yi
* @date 2021/9/30 15:23
**/
@ControllerAdvice
@SuppressWarnings("all")
public class ValidateHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
HttpHeaders headers,
HttpStatus status,
WebRequest request) {
final StringBuilder builder = new StringBuilder();
for (FieldError fieldError : ex.getBindingResult().getFieldErrors()) {
final String message = fieldError.getDefaultMessage();
builder.append(message);
break;
}
return ResponseEntity.ok(new ResultWrapper()
.setCode(StatusCodeEnum.PARAMETER_ERROR.getCode())
.setMsg(builder.toString()));
}
}
(3)自定义 异常类
新建 自定义异常类 CustomException 。
package com.hy.globalexception.config;
/***
* <p>
* 自定义异常
* </p>
* @author hou yi
* @date 2021/9/30 15:23
**/
public class CustomException extends RuntimeException{
public CustomException(String msg){
super(msg);
}
}
以上三种异常类创建完成后,创建一个 controller 来看看具体效果。注:有service 层及其他的工具类,具体可参考源码。
package com.hy.globalexception.controller;
import com.hy.globalexception.config.ResultWrapper;
import com.hy.globalexception.service.ExceptionTestService;
import com.hy.globalexception.vo.ParamVo;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
/***
* <p>
* 异常测试 控制器
* </p>
* @author hou yi
* @date 2021/9/30 14:29
**/
@RestController
@RequestMapping("exceptionTest")
public class ExceptionTestController {
@Resource
private ExceptionTestService exceptionTestService;
@GetMapping
public ResultWrapper<Object> find() {
// 这里定义产生一个异常,让全局异常去捕获
int i = 1/0;
return ResultWrapper.successBuilder(null);
}
@PostMapping
public ResultWrapper<Object> save() {
// 异常定义在业务层。
exceptionTestService.save();
return ResultWrapper.successBuilder(null);
}
@PostMapping("custom")
public ResultWrapper<Object> custom() {
// 业务层 抛出一个 自定义异常
exceptionTestService.custom();
return ResultWrapper.successBuilder(null);
}
@PostMapping("validate")
public ResultWrapper<Object> custom(@RequestBody @Valid ParamVo paramVo) {
// ParamVo 中参数校验失败,抛出异常, 由 ValidateHandler 处理
return ResultWrapper.successBuilder(null);
}
}
效果图如下:
以上就是整个 统一返回格式与统一异常处理 的过程,从此以后,阿签不在为接口感到心情烦躁,每一天都是美好的。
附源码地址: