java RestControllerAdvice 封装返回
bluesky 人气:01.为什么要把结果封装成统一格式?
异常和正常情况无法区分:异常情况返回数据为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; } }
不封装:
封装:
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); } }
加载全部内容