【SpringBoot专题】统一异常处理和统一数据返回之ResponseBodyController

【SpringBoot专题】统一异常处理和统一数据返回之ResponseBodyAdvice

在这里插入图片描述
在实际开发中,我们希望对接口结果的返回,进行一次统一的封装,即便接口发生异常。今天主要是分享的是怎么接口层统一返回。

我们在做业务的时候通常都会封装一个通用的返回结果类,今天我也贴出来一个,如下所示:

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(Include.NON_NULL)
public class ApiResponse<T> {

    /**
     * 系统状态
     */
    @JsonProperty("code")
    private Integer code;

    /**
     * 错误消息
     */
    @JsonProperty("message")
    private String message;

    /**
     * 错误内容列表
     */
    @JsonProperty("errors")
    private List<ErrorEntity> errors;

    /**
     * 返回结果内容
     */
    @JsonProperty("data")
    private T data;

    /**
     * 成功,没数据
     */
    public ApiResponse() {
        this(ApiResponseErrorCode.CODE_0.getCode(),
                ApiResponseErrorCode.CODE_0.getMessage(), null, null);
    }

    /**
     * 成功,有数据
     */
    public ApiResponse(T data) {
        this(ApiResponseErrorCode.CODE_0.getCode(),
                ApiResponseErrorCode.CODE_0.getMessage(), data, null);
    }

    /**
     * 指定code/message
     */
    public ApiResponse(ApiResponseErrorCode apiResponseErrorCode) {
        this(apiResponseErrorCode.getCode(), apiResponseErrorCode.getMessage(),
                null, null);
    }

    /**
     * 指定code + data
     */
    public ApiResponse(ApiResponseErrorCode apiResponseErrorCode, T data) {
        this(apiResponseErrorCode.getCode(), apiResponseErrorCode.getMessage(),
                data, null);
    }

    /**
     * 指定code + errors
     */
    public ApiResponse(ApiResponseErrorCode apiResponseErrorCode,
                       List<ErrorEntity> errors) {
        this(apiResponseErrorCode.getCode(), apiResponseErrorCode.getMessage(),
                null, errors);
    }

    protected ApiResponse(Integer code, String message, T data,
                          List<ErrorEntity> errors) {
        this.code = code;
        this.message = message;
        this.errors = errors;
        this.data = data;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public List<ErrorEntity> getErrors() {
        return errors;
    }

    public void setErrors(List<ErrorEntity> errors) {
        this.errors = errors;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

}

然后我们写自己的controller层,这里埋个伏笔,有心的同学可以看到我还做了参数校验(下篇博客中我会分享springboot如何做国际话校验,敬请期待)

@RestController
@RequestMapping("exception")
@Validated
public class ExceptionDemoController {

    @GetMapping("demoA")
    public ApiResponse<String> demoA() {
        throw new BadRequestException("报错了。。。。");
    }

    @GetMapping("demoB")
    public ApiResponse<String> demoB() {
        throw new BadRequestException("报错了。。。。");
    }

    @GetMapping("/validate1")
    @ResponseBody
    public String validate1(
            @Size(min = 1, max = 10, message = "姓名长度必须为1到10") @RequestParam("name") String name) {
        return "validate1 测试";
    }

    /**
     * http://localhost:8888/exception/validate2?lang=en_US
     * http://localhost:8888/exception/validate2?lang=zh_CN
     * @param user
     * @return
     */
    @PostMapping("/validate2")
    @ResponseBody
    public String validate2(@Valid
            @RequestBody User user) {
        return "validate1";
    }
}

接着需要对这些带有ResponseBody注解的坐下处理,敲黑板这里将是今天的重点,我现实了ResponseBodyAdvice接口,通过这个接口的实现类来统一处理报文,代码如下:

@Slf4j
@ControllerAdvice(annotations = {RestController.class, Controller.class})
public class ApiResponseHandler implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        String returnTypeName = returnType.getParameterType().getName();
        return !"fast.cloud.nacos.common.model.response.ApiResponse".equals(returnTypeName) &&
                !"org.springframework.http.ResponseEntity".equals(returnTypeName) && returnType.hasMethodAnnotation(ResponseBody.class);
    }

    @SuppressWarnings("rawtypes")
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType,
                                  Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest,
                                  ServerHttpResponse serverHttpResponse) {
        String name = methodParameter.getParameterType().getName();
        if ("void".equals(name)) {
            return new ApiResponse<>();
        }
        if (body instanceof String) {
            return JsonUtils.toString(new ApiResponse<>(body));
        }
        return new ApiResponse<>(body);
    }
}

这里有个坑,需要注意,当我们返回是string类型的时候,SpringMVC框架的MessageConverter会报错,你却返回ApiResponse,这样会出现ClassCastException ,解决方法就是将这个对象序列化一次。

github:如果觉得写得好的,可以给个star,谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值