异常通知处理和返回值统一封装

返回值结果集类

@ToString
@Data
public class Result<T> implements Serializable {
    private int code;
    private String message;
    private T data;
    public Result(ResultCode resultCode,  T data) {
        this.code = resultCode.code();
        this.message = resultCode.message();
        this.data = data;
    }
    /**
     * 返回成功
     */
    public static Result<Object> success() {
        return new Result<>(ResultCode.SUCCESS, null);
    }
    public static<T> Result<T> success(T data) {
        return new Result<>(ResultCode.SUCCESS, data);
    }

    /**
     * 失败
     * @param resultCode 错误码
     * @return 结果集
     */
    public static Result<Object> fail(ResultCode resultCode) {
        return new Result<>(resultCode, null);
    }
    /**
     * 失败
     * @param resultCode 错误码
     * @param data 错误数据
     * @return 结果集
     */
    public static<T> Result<Object> fail(ResultCode resultCode, T data) {
        return new Result<>(resultCode, data);
    }
}

返回值码

public enum ResultCode {
    /**
     * 成功
     */
    SUCCESS(200, "success"),
    SYS_ERROR(500, "系统错误");
    private Integer code;
    private String message;

    ResultCode(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
    public Integer code() {
        return code;
    }
    public String message() {
        return message;
    }
}

指定注解 @ResponseResult

/**
 * 结果集包装处理
 * @author xiaou
 * @date 2022/4/1
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
public @interface ResponseResult {}

测试 Controller

@RestController
@ResponseResult
public class TestController {
    @GetMapping(value = "test", produces = {"application/json;charset=utf-8"})
    public String test(String id) {
        if (Objects.isNull(id)) {
            throw new IllegalArgumentException("参数出现错误");
        }
        return "111";
    }
}

出现异常 java.lang.ClassCastException: xiaou.Entity.Result cannot be cast to java.lang.String

有两种解决方案。

第一种是直接使用 fastjson 来序列化,fastjson 处理的时候不会报错

@Bean
public HttpMessageConverters custHttpMessageConverter() {
    return new HttpMessageConverters(new FastJsonHttpMessageConverter());
}

第二种方案不想项目引入 fastjson,就直接用 SpringBoot 自带的 jackson 处理,需要将 jackson 序列化的处理调整到最前面。

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(0, new MappingJackson2HttpMessageConverter());
    }
}

> 注意采取第二种做法时,需要在接口上指定 produces = {"application/json;charset=utf-8"}

统一处理

@ControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        ResponseResult attribute = (ResponseResult) request.getAttribute(ResponseResultInterceptor.RESPONSE_RESULT_ANN);
        return !Objects.isNull(attribute);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof Result) {
            return body;
        }
        return Result.success(body);
    }

    /**
     * 参数异常处理
     * @return Result<Object>
     */
    @ExceptionHandler(value = IllegalArgumentException.class)
    @ResponseBody
    public Result<Object> argumentException() {
        return Result.fail(ResultCode.SYS_ERROR);
    }

}

效果

// http://localhost:8080/test
{
    "code": 500,
    "message": "系统错误",
    "data": null
}
// http://localhost:8080/test
{
    "code": 200,
    "message": "success",
    "data": "111"
}