本文想法是在Controller最外层返回时封装一个结构,减少冗余代码。

本文涉及技术点:枚举,范型,重写框架ResponseBody返回代码 2020.1.2—1.0 初版 对于controller类返回统一封装 2020.1.2—1.1 对异常情况处理,利用aop切面实现

一、前提背景

1、Controller代码如下

  1. @Controller
  2. public class TestController {
  3. @GetMapping("/test")
  4. @ResponseBody //当类使用RestController可以不需要此标注
  5. public String test() {
  6. String text = "do something";
  7. System.out.println(text);
  8. return text;
  9. }
  10. }

2、此时postman测试调用后发现结果不美观

image.png

3、发生错误时,返回信息也没有进行封装。

image.png

二、设计思路

1、构建一个配置类实现InitializingBean接口,

2、在创建bean时修改HandlerMethodReturnValueHandler中RequestResponseBodyMethodProcessor代码

3、封装一个统一返回结果

4、封装一个自定义异常类,继承RuntimeException异常,结合返回枚举。

5、处理类利用@ControllerAdvice切面处理,方法使用@ExceptionHandler,@ResponseBody直接返回前台

三、代码演示

1、回参信息枚举类

  1. package com.vvvv.util.returnHandler;
  2. /**
  3. * 返回信息枚举
  4. */
  5. public enum ReturnInfoEnum {
  6. SUCCESS(0,"success"),
  7. ERROR(-1,"error"),
  8. NET_ERROR(-9001,"network error."),
  9. UNKNOWN_ERROR(-9999,"unknow error."),
  10. ;
  11. private Integer code;
  12. private String msg;
  13. ReturnInfoEnum(int code, String msg) {
  14. this.code = code;
  15. this.msg = msg;
  16. }
  17. public int getCode() {
  18. return code;
  19. }
  20. public String getMsg() {
  21. return msg;
  22. }
  23. }

2、统一返回类方法封装

  1. package com.vvvv.util.returnHandler;
  2. import lombok.Data;
  3. /**
  4. * @ClassName Return
  5. * @Description 返回类方法封装
  6. * @Author vvvv
  7. * @Date 2021/1/2 19:37
  8. * @Version V1.0
  9. */
  10. @Data
  11. public class Return<T> {
  12. private Integer code;
  13. private String msg;
  14. private T data;
  15. private Return(Integer code, String msg) {
  16. this.code = code;
  17. this.msg = msg;
  18. }
  19. private Return(Integer code, String msg, T data) {
  20. this.code = code;
  21. this.msg = msg;
  22. this.data = data;
  23. }
  24. public static <T> Return<T> success() {
  25. return new Return<T>(ReturnInfoEnum.SUCCESS.getCode(),
  26. ReturnInfoEnum.SUCCESS.getMsg());
  27. }
  28. public static <T> Return<T> success(T data) {
  29. return new Return<>(ReturnInfoEnum.SUCCESS.getCode(),
  30. ReturnInfoEnum.SUCCESS.getMsg(), data);
  31. }
  32. public static <T> Return<T> error(Integer code, String msg) {
  33. return new Return<>(code, msg);
  34. }
  35. }

3、构建配置类 RenturnHandlerAdapter

  1. /**
  2. * @ClassName RenturnHandlerAdapter
  3. * @Description 接口返回统一处理配置类
  4. * @Author vvvv
  5. * @Date 2021/1/2 19:41
  6. * @Version V1.0
  7. */
  8. @Configuration // 声明是spring配置,创建bean
  9. @RequiredArgsConstructor // 构建有参构造函数
  10. public class RenturnHandlerAdapter implements InitializingBean {
  11. // 获取到RequestMappingHandlerAdapter的结果
  12. private final RequestMappingHandlerAdapter handlerAdapter;
  13. @Override
  14. public void afterPropertiesSet() {
  15. // 根据适配器拿到返回处理集合
  16. List<HandlerMethodReturnValueHandler> returnValueHandlers =
  17. handlerAdapter.getReturnValueHandlers();
  18. List<HandlerMethodReturnValueHandler> newList = new ArrayList<>();
  19. // RequestResponseBodyMethodProcessor
  20. // 构建新类实现HandlerMethodReturnValueHandler接口
  21. // 重写接口,完成
  22. Objects.requireNonNull(returnValueHandlers).forEach(
  23. t -> {
  24. if (t instanceof RequestResponseBodyMethodProcessor)
  25. newList.add(new ReturnHandlerAdaptProxy(t));
  26. else newList.add(t);
  27. }
  28. );
  29. // 将新处理集合放回适配器中
  30. handlerAdapter.setReturnValueHandlers(newList);
  31. }
  32. }

4、接口返回统一处理类 ReturnHandlerAdaptProxy

  1. /**
  2. * @ClassName ReturnHandlerAdaptProxy
  3. * @Description 接口返回统一处理类
  4. * @Author vvvv
  5. * @Date 2021/1/2 19:49
  6. * @Version V1.0
  7. */
  8. public class ReturnHandlerAdaptProxy implements HandlerMethodReturnValueHandler {
  9. private final HandlerMethodReturnValueHandler proxyObject;
  10. public ReturnHandlerAdaptProxy(HandlerMethodReturnValueHandler proxyObject) {
  11. this.proxyObject = proxyObject;
  12. }
  13. @Override
  14. public boolean supportsReturnType(MethodParameter returnType) {
  15. return proxyObject.supportsReturnType(returnType);
  16. }
  17. @Override
  18. public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer,
  19. NativeWebRequest webRequest) throws Exception {
  20. Return result =
  21. returnValue == null ? Return.success() : Return.success(returnValue);
  22. // 此处对Object进行封装返回即可
  23. proxyObject.handleReturnValue(result, returnType, mavContainer, webRequest);
  24. }
  25. }

5、自定义异常类

  1. @Getter //lombok getter注解
  2. //继承RuntimeException
  3. public class VurxException extends RuntimeException {
  4. //错误编码
  5. private final Integer code;
  6. public VurxException(ReturnInfoEnum resultEnum) {
  7. // 调用父类构造方法,将错误信息写入
  8. super(resultEnum.getMsg());
  9. // 补充错误编码
  10. this.code = resultEnum.getCode();
  11. }
  12. }

6、异常处理类

  1. @ControllerAdvice // 环绕controller切面
  2. @Slf4j // lombok注解
  3. public class ExceptionHandle {
  4. // !!!抛出异常自动进入该方法!!!
  5. @ExceptionHandler(value = Exception.class)
  6. @ResponseBody // 返回前台结果
  7. public Return<Object> handle(Exception e) {
  8. log.error("======ERROR=========================================================================", e);
  9. // 异常类型属于自定义异常时封装返回前台
  10. if (e instanceof VurxException) {
  11. VurxException vurxException = (VurxException) e;
  12. return Return.error(vurxException.getCode(), vurxException.getMessage());
  13. }
  14. // 其他异常抛出未知异常
  15. return Return.error(ReturnInfoEnum.UNKNOWN_ERROR.getCode(), e.getMessage());
  16. }
  17. }

四、测试代码

1、统一返回测试

a、测试controller

  1. @Controller
  2. public class TestController {
  3. @GetMapping("/test")
  4. @ResponseBody //当类使用RestController可以不需要此标注
  5. public String test() {
  6. String text = "do something";
  7. System.out.println(text);
  8. return text;
  9. }
  10. }

b、成功结果

image.png

2、异常测试

a、Controller类

  1. @Controller
  2. public class TestController {
  3. @GetMapping("/test")
  4. @ResponseBody
  5. public String test() {
  6. String text = "do something";
  7. if (text.startsWith("do")) {
  8. throw new VurxException(ReturnInfoEnum.NET_ERROR);
  9. } else {
  10. return text;
  11. }
  12. }
  13. }

b、效果演示

image.png