likes
comments
collection

封装返回结果与@RestControllerAdvice注解

作者站长头像
站长
· 阅读数 15

1.为什么要把结果封装成统一格式?

异常和正常情况无法区分:异常情况返回数据为null,正常情况下查询结果也为null,返回给前端无法区分

显示抛出异常信息:前端需要显示抛出的异常信息

@AllArgsConstructor
public enum ResultCode {

    CODE_200(200, "success"),
    CODE_1000(1000, "fail");

    @Getter
    private Integer code;
    @Getter
    private String msg;
}


@Data
public class Result<T> {
    private String msg;
    private Integer code;
    private T data;

    private Result(String msg, Integer code) {
        this.msg = msg;
        this.code = code;
    }

    private Result(ResultCode resultCode, String msg) {
        this(msg, resultCode.getCode());
    }

    private Result(ResultCode resultCode) {
        this(resultCode.getMsg(), resultCode.getCode());
    }

    public static <T>Result<T> result(ResultCode resultCode,T data) {
        Result result = new Result(resultCode);
        result.setData(data);
        return result;
    }

    public static <T>Result<T> fail(ResultCode resultCode,String message) {
        Result result = new Result(resultCode, message);
        result.setData(null);
        return result;
    }

    public static <T>Result<T> fail(T data) {
        Result result = new Result(ResultCode.CODE_1000);
        result.setData(data);
        return result;
    }

    public static <T>Result<T> success(T data) {
        Result result = new Result(ResultCode.CODE_200);
        result.setData(data);
        return result;
    }
}

不封装:

封装返回结果与@RestControllerAdvice注解

封装:

封装返回结果与@RestControllerAdvice注解

2.统一异常接收

为什么要用统一异常接收?

通常在service层抛异常,涉及到事务时不会进行try-catch,需要在controller里处理异常。即使能够进行try-catch的地方也需要统一返回格式,造成重复代码很多,可读性比较差。

如何实现统一的异常接收?

@Slf4j
@RestControllerAdvice
public class GlobalException {
    
    @ExceptionHandler(Exception.class)
    public Result<?> handlerException(Exception exception) {
        log.info("Exception异常信息:" + exception.getMessage());
        return Result.fail(ResultCode.CODE_1000, exception.getMessage());
    }

    @ExceptionHandler(value = {MyException.class})
    public Result<?> handlerMyException(Exception exception) {
        log.info("MyException异常信息:" + exception.getMessage());
        return Result.fail(ResultCode.CODE_1000, exception.getMessage());
    }
}

抛出异常后,会进入到@RestControllerAdvice注解的方法,过滤出和抛出异常相同的class的方法,执行相应的方法。

protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception exception) {
    //根据异常类型过滤方法
    ServletInvocableHandlerMethod exceptionHandlerMethod = this.getExceptionHandlerMethod(handlerMethod, exception);
    if (exceptionHandlerMethod == null) {
        return null;
    } else {
        if (this.argumentResolvers != null) {
            exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }

        if (this.returnValueHandlers != null) {
            exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        }

        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        ArrayList<Throwable> exceptions = new ArrayList();

        try {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Using @ExceptionHandler " + exceptionHandlerMethod);
            }

            Throwable cause;
            for(Throwable exToExpose = exception; exToExpose != null; exToExpose = cause != exToExpose ? cause : null) {
                exceptions.add(exToExpose);
                cause = ((Throwable)exToExpose).getCause();
            }

            Object[] arguments = new Object[exceptions.size() + 1];
            exceptions.toArray(arguments);
            arguments[arguments.length - 1] = handlerMethod;
            //执行方法
            exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, arguments);
        } catch (Throwable var13) {
            if (!exceptions.contains(var13) && this.logger.isWarnEnabled()) {
                this.logger.warn("Failure in @ExceptionHandler " + exceptionHandlerMethod, var13);
            }

            return null;
        }

        if (mavContainer.isRequestHandled()) {
            return new ModelAndView();
        } else {
            ModelMap model = mavContainer.getModel();
            HttpStatus status = mavContainer.getStatus();
            ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, status);
            mav.setViewName(mavContainer.getViewName());
            if (!mavContainer.isViewReference()) {
                mav.setView((View)mavContainer.getView());
            }

            if (model instanceof RedirectAttributes) {
                Map<String, ?> flashAttributes = ((RedirectAttributes)model).getFlashAttributes();
                RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
            }

            return mav;
        }
    }
}




protected ServletInvocableHandlerMethod getExceptionHandlerMethod(@Nullable HandlerMethod handlerMethod, Exception exception) {
    Class<?> handlerType = null;
    if (handlerMethod != null) {
        handlerType = handlerMethod.getBeanType();
        ExceptionHandlerMethodResolver resolver = (ExceptionHandlerMethodResolver)this.exceptionHandlerCache.get(handlerType);
        if (resolver == null) {
            resolver = new ExceptionHandlerMethodResolver(handlerType);
            this.exceptionHandlerCache.put(handlerType, resolver);
        }

        Method method = resolver.resolveMethod(exception);
        if (method != null) {
            return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method, this.applicationContext);
        }

        if (Proxy.isProxyClass(handlerType)) {
            handlerType = AopUtils.getTargetClass(handlerMethod.getBean());
        }
    }
    //初始化的时候已经将beanType作为key,标注@ExceptionHandler的方法包装成resolve作为value放到exceptionHandlerAdviceCache中

    Iterator var9 = this.exceptionHandlerAdviceCache.entrySet().iterator();

    while(var9.hasNext()) {
        Map.Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> entry = (Map.Entry)var9.next();
        ControllerAdviceBean advice = (ControllerAdviceBean)entry.getKey();
        if (advice.isApplicableToBeanType(handlerType)) {
            ExceptionHandlerMethodResolver resolver = (ExceptionHandlerMethodResolver)entry.getValue();
            //根据class进行筛选
            Method method = resolver.resolveMethod(exception);
            if (method != null) {
                return new ServletInvocableHandlerMethod(advice.resolveBean(), method, this.applicationContext);
            }
        }
    }

    return null;
}

直接在service层抛出异常,controller中返回正常的结果,由标注了@RestControllerAdvice的类对异常进行处理

@RestController
@RequestMapping("/user")
public class UserController {

    @GetMapping("/test")
    public Result<Boolean> testGlobalException() {
        globalException.throwException();
        return Result.success(Boolean.TRUE);
    }
}