美文网首页
SpringBoot 统一结果与异常处理

SpringBoot 统一结果与异常处理

作者: 上岸大虾米 | 来源:发表于2022-06-17 16:42 被阅读0次

    SpringBoot 统一结果与异常处理

    1. controller层 现状与优化
    1.1 现状
    @GetMapping("select")
    public Result select(@RequestParam Long productId){
        return Result.success(service.sameProduct(productId));
    }
    

    存在以下问题:

    1. return Result.success为controller层固定写法,冗余且不够简洁

    2. 不能直观看到返回值类型

    1.2 优化后
    @GetMapping("select")
    public List<String> select(@RequestParam Long productId){
        return service.sameProduct(productId);
    }
    
    1.3 全局结果统一处理
    @Configuration
    @RestControllerAdvice
    public class CommonResultResponseAdvice implements ResponseBodyAdvice<Object> {
    
        @Resource
        private ObjectMapper objectMapper;
    
        @Override
        public boolean supports(@NotNull MethodParameter returnType, @NotNull Class<? extends HttpMessageConverter<?>> converterType) {
            // 忽略 IgnoreResult 注解标识的类或方法的返回结果转换
            return !ignoreResult(returnType, IgnoreResult.class);
        }
    
        @SneakyThrows
        @Override
        public Object beforeBodyWrite(Object body, @NotNull MethodParameter returnType, @NotNull MediaType selectedContentType, @NotNull Class<? extends HttpMessageConverter<?>> selectedConverterType, @NotNull ServerHttpRequest request, @NotNull ServerHttpResponse response) {
            String typeName = returnType.getGenericParameterType().getTypeName();
            if (Void.TYPE.getName().equals(typeName)) {
                return body;
            }
            if (body instanceof Result) {
                return body;
            }
            if (body instanceof String) {
                return objectMapper.writeValueAsString(BaseResponse.success(body));
            }
            return Result.success(body);
        }
    
        private boolean ignoreResult(MethodParameter returnType, Class<? extends Annotation> ignoreAnnotation) {
            Method method = returnType.getMethod();
            return method.getAnnotation(ignoreAnnotation) != null ||
                    method.getDeclaringClass().getAnnotation(ignoreAnnotation) != null;
        }
    }
    
    1.4 自定义注解

    忽略返回结果统一处理注解

    @Target({METHOD, TYPE})
    @Retention(RUNTIME)
    @Documented
    public @interface IgnoreResult {
    }
    
    2、异常处理现状与优化
    2.1 现状
    if (product != null) {
        throw new ProductException(ProductExceptionEnum.SID_EXIST, saveProductParam.getSid());
    }
    // 或着 ,
    if (product != null) {
        CommonException.exception(ProductExceptionEnum.PARAM_ERROR);
    }
    
    public static void exception(ErrorCodeInterface errorCodeInterface) {
        throw new CommonException(errorCodeInterface);
    }
    

    数据有效性校验存在以下问题:

    1. 代码不够简洁,定义过多且大部分仅使用一次的ProductExceptionEnum
    2. 每个项目各自使用自定义异常,有一定的学习了解成本
    2.2 优化后

    使用Assert进行业务校验,校验失败后直接抛出异常,中断后续操作

    Assert.isNull(product,String.format(ProductExceptionEnum.SID_EXIST.getMessage(),saveProductParam.getSid()));
    
    2.3 统一异常处理
    @ControllerAdvice
    public class GlobalExceptionHandler {
    
        private static final String INTEREST_CLASS_NAME = "org.springframework.util.Assert";   
    
        /**
            此处捕获业务 失败 的异常,可考虑不计日志
        */
        @ExceptionHandler({IllegalArgumentException.class,IllegalStateException.class})
            @ResponseBody
            public Result illegalArgumentException(Exception e) {
                String msg = e.getMessage();
                int maxLength = 200;
                if(StringUtils.isBlank(msg) || msg.length() > maxLength){
                    msg = "请求参数异常";
                }
                StackTraceElement[] stackTraces = e.getStackTrace();
                if (Stream.of(stackTraces).anyMatch(s -> s.getClassName().equals(INTEREST_CLASS_NAME))) {
                    // 不计日志, 或设置warn级别,便于快速快速响应用户反馈
                    log.warn("业务校验失败", e);
                    return Result.error(DefaultErrorCodeEnums.ASSERT_EXCEPTION, msg);
                }else {
                     log.error("xxx", e);
                    return Result.error(DefaultErrorCodeEnums.PARAM_ERROR, msg);
                }
            }
    }
    

    建议使用 org.springframework.util.Assert 或在此基础上扩展

    执行顺序: 如果抛异常--> 全局异常捕获 --> 全局统一结果处理

    相关文章

      网友评论

          本文标题:SpringBoot 统一结果与异常处理

          本文链接:https://www.haomeiwen.com/subject/ftrhvrtx.html