做出口的网站,企业信用信息公示系统河南,比 wordpress,百度前三推广接上篇文章的统一数据格式返回… 文章目录 1. 统一异常处理1.1 使用 2. 统一数据返回和统一异处理是怎么实现的2.1 initHandleAdapters2.2 initHandleExceptionResolvers 1. 统一异常处理 1.1 使用
统一异常处理的两个关键的注解是ControllerAdvice ExceptionHandler
Contro…接上篇文章的统一数据格式返回… 文章目录 1. 统一异常处理1.1 使用 2. 统一数据返回和统一异处理是怎么实现的2.1 initHandleAdapters2.2 initHandleExceptionResolvers 1. 统一异常处理 1.1 使用
统一异常处理的两个关键的注解是ControllerAdvice ExceptionHandler
ControllerAdvice 表示控制器通知类ExceptionHandler:是异常处理器
两者结合就表示:出现异常的时候执行某个通知,也就是执行某个方法具体的代码如下:
ControllerAdvice
ResponseBody
public class ErrorAdvice {ExceptionHandlerpublic Object handleException(Exception e) {//表示代码如果出现Exception(及其之类)异常,就返回Result的对象return Result.fail(e.getMessage());}
}其中Result是自定义的放回结果类:同时,我们可以针对不同的异常,返回不同的结果
ControllerAdvice
ResponseBody
public class ErrorAdvice {ExceptionHandlerpublic Object handleException(Exception e) {//表示代码如果出现Exception(及其之类)异常,就返回Result的对象return Result.fail(e.getMessage());}ExceptionHandlerpublic Object handleException(ArithmeticException e) {return Result.fail(算术异常 e.getMessage());}ExceptionHandlerpublic Object handleException(NullPointerException e) {return Result.fail(空指针异常 e.getMessage());}
}测试:
RequestMapping(/test)
RestController
public class TestController {RequestMapping(/Test1)public String Test1() {int a 10 / 0;return t1;}RequestMapping(Test2)public String Test2() {int[] arr new int[4];int b arr[4];return t2;}
}2. 统一数据返回和统一异处理是怎么实现的
统一数据返回和统一异处理是怎么实现的?我们从DispatcherServlet的代码开始分析当Tomcat启动的时候,有一个核心的类DispatcherServlet,用来控制程序的执行顺序这个对象在创建的时候,会初始化一系列的对象:其中与统一数据返回和统一异常处理相关的就是initHandleAdapters和initHandleExceptionResolvers
2.1 initHandleAdapters
这个⽅法在执时会查找使用所有的 ControllerAdvice 类把 ResponseBodyAdvice 类放在容器中当发⽣某个事件时调⽤相应的Advice⽅法⽐如返回数据前调⽤统⼀数据封装
private void initControllerAdviceCache() {if (getApplicationContext() null) {return;}//查找所有被ControllerAdvice注解的BeanListControllerAdviceBean adviceBeans ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());ListObject requestResponseBodyAdviceBeans new ArrayList();for (ControllerAdviceBean adviceBean : adviceBeans) {Class? beanType adviceBean.getBeanType();if (beanType null) {throw new IllegalStateException(Unresolvable type for ControllerAdviceBean: adviceBean);}SetMethod attrMethods MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);if (!attrMethods.isEmpty()) {this.modelAttributeAdviceCache.put(adviceBean, attrMethods);}SetMethod binderMethods MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);if (!binderMethods.isEmpty()) {this.initBinderAdviceCache.put(adviceBean, binderMethods);}//遍历adviceBeans列表检查每个ControllerAdviceBean对应的bean类型是否实现了RequestBodyAdvice或ResponseBodyAdvice接口if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {requestResponseBodyAdviceBeans.add(adviceBean);}}if (!requestResponseBodyAdviceBeans.isEmpty()) {this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);}if (logger.isDebugEnabled()) {int modelSize this.modelAttributeAdviceCache.size();int binderSize this.initBinderAdviceCache.size();int reqCount getBodyAdviceCount(RequestBodyAdvice.class);int resCount getBodyAdviceCount(ResponseBodyAdvice.class);if (modelSize 0 binderSize 0 reqCount 0 resCount 0) {logger.debug(ControllerAdvice beans: none);}else {logger.debug(ControllerAdvice beans: modelSize ModelAttribute, binderSize InitBinder, reqCount RequestBodyAdvice, resCount ResponseBodyAdvice);}}}2.2 initHandleExceptionResolvers
initHandleExceptionResolvers方法会取得所有实现了HandleExceeptionResolver接口的Bean,其中就有一个ExceptionHandlerExceptionResolver 的bean,这个Bean在应用启动的时候或获取到所有被注解ControllerAdvice标注的bean对象,做进一步处理当Controller抛出异常的时候,DispatcherServlet使用ExceptionHandlerExceptionResolver 来解析异常,而ExceptionHandlerExceptionResolver 通过ExceptionHandlerMethodResolver 来解析异常
Nullable
private Method getMappedMethod(Class? extends Throwable exceptionType) {ListClass? extends Throwable matches new ArrayList();for (Class? extends Throwable mappedException : this.mappedMethods.keySet()) {if (mappedException.isAssignableFrom(exceptionType)) {matches.add(mappedException);}}if (!matches.isEmpty()) {if (matches.size() 1) {matches.sort(new ExceptionDepthComparator(exceptionType));}return this.mappedMethods.get(matches.get(0));}else {return NO_MATCHING_EXCEPTION_HANDLER_METHOD;}
}我们通过调试来看处理异常的整个过程 断点打在这个地方(第一次执行到的时候不是我们想要的,按f9会再次跳到这个地方第二次执行)
往下执行,就会发现此时正在遍历mappedMethods,里面就是我们在ErrorAdvice里面指定的所有异常
遍历完后,实际上就是筛选出哪些异常能够处理我们当前的异常类型,由于我们当前是算术异常,那么能匹配的就留下了两个
调用sort方法之后,就会按照优先级排序好,以便我们更精确的处理异常