多元网站建设,信息网站的建设,广东seo网站优化公司,珠海建站模板使用注解方式处理全局异常使用 ControllerAdvice #xff08;RestControllerAdvice#xff09; 配合 ExceptionHandler适用于返回数据的请求#xff08;一般是RESTful接口规范下的JSON报文#xff09;package com.example.exception;import org.slf4j.Logger;
import org.s…使用注解方式处理全局异常使用 ControllerAdvice RestControllerAdvice 配合 ExceptionHandler适用于返回数据的请求一般是RESTful接口规范下的JSON报文package com.example.exception;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.example.exception.ControllerController.MyException1;RestControllerAdvice
public class RestControllerExceptionAdvice {private static transient Logger logger LoggerFactory.getLogger(RestControllerExceptionAdvice.class);ExceptionHandler(MyException1.class)public String MyException1(MyException1 e) {logger.info(RestControllerExceptionAdvice MyException1 异常-{}, e.getMessage());return error;}
}适用于返回视图的请求方法返回值如果不是ModelAndView而是字符串时字符串会被解析成视图名package com.example.exception;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import com.example.exception.ControllerController.MyException1;
import com.example.exception.ControllerController.MyException3;ControllerAdvice
public class ControllerExceptionAdvice {private static transient Logger logger LoggerFactory.getLogger(ControllerExceptionAdvice.class);ExceptionHandler(MyException1.class)public String uploadException(MyException1 e) {logger.info(ControllerExceptionAdvice MyException1 异常-{}, e.getMessage());return this is a viewName1;}ExceptionHandler(MyException3.class)public ModelAndView uploadException(MyException3 e) {logger.info(ControllerExceptionAdvice MyException3 异常-{}, e.getMessage());return new ModelAndView(this is a viewName3);}
}也可以ControllerAdvice配合使用ResponseBody完成和RestControllerAdvice一样的效果不建议这样使用个人感觉会使代码很混乱package com.example.exception;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.example.exception.ControllerController.MyException1;
import com.example.exception.ControllerController.MyException2;
import com.example.exception.ControllerController.MyException3;ControllerAdvice
public class ControllerExceptionAdvice {private static transient Logger logger LoggerFactory.getLogger(ControllerExceptionAdvice.class);ExceptionHandler(MyException2.class)ResponseBodypublic String uploadException(MyException2 e) {logger.info(ControllerExceptionAdvice MyException2 异常-{}, e.getMessage());return this is a rsp;}
}控制器私有的异常处理器优先级高于全局异常处理器package com.example.exception;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;RestController
public class RestControllerController {private static transient Logger logger LoggerFactory.getLogger(RestControllerController.class);GetMapping(/test)ResponseBodypublic String testExceptionResolver() {throw new RuntimeException(这是测试控制器异常);}// 只针对当前控制器优先级高于全局异常处理器ResponseBodyExceptionHandler(RuntimeException.class)public String uploadException(RuntimeException e) {logger.info(RestControllerController RuntimeException 异常-{}, e.getMessage());return error;}
}使用HandlerExceptionResolver接口实现处理全局异常package com.example.exception;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;Component
public class ExceptionResolver1 implements HandlerExceptionResolver {private static transient Logger logger LoggerFactory.getLogger(ExceptionResolver1.class);Overridepublic ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex) {ModelAndView mv new ModelAndView();logger.info(ExceptionResolver 异常-{}, ex.getMessage());return mv;}
}package com.example.exception;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;Component
public class ExceptionResolver2 implements HandlerExceptionResolver {private static transient Logger logger LoggerFactory.getLogger(ExceptionResolver1.class);Overridepublic ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex) {ModelAndView mv new ModelAndView();logger.info(ExceptionResolver2 异常-{}, ex.getMessage());return mv;}
}HandlerExceptionResolver接口是没有排序的所以应用程序无法保证执行顺序如果第一个执行的HandlerExceptionResolver已经返回了ModelAndView那么后续所有的HandlerExceptionResolver都将不会被执行返回null会使得后续HandlerExceptionResolver继续执行一直到返回ModelAndView的HandlerExceptionResolver结束如果你的所有实现全部返回null值也没有意义 ControllerAdvice RestControllerAdvice 配合 ExceptionHandler的全局异常处理会先于HandlerExceptionResolver执行所以ExceptionHandler注解方法中的异常可以由HandlerExceptionResolver处理保证ExceptionHandler注解方法不抛出异常才是正确的核心源码位置Spring MVC在 DispatcherServlet#processHandlerException()方法中使用上述的异常解析器关于异常处理返回值解析的问题以及异常处理顺序的问题都可以以该方法为起点打断点DEBUGNullableprotected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,Nullable Object handler, Exception ex) throws Exception {// Success and error responses may use different content typesrequest.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);// Check registered HandlerExceptionResolvers...ModelAndView exMv null;//就在这个位置if (this.handlerExceptionResolvers ! null) {for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {exMv resolver.resolveException(request, response, handler, ex);if (exMv ! null) {break;}}}if (exMv ! null) {if (exMv.isEmpty()) {request.setAttribute(EXCEPTION_ATTRIBUTE, ex);return null;}// We might still need view name translation for a plain error model...if (!exMv.hasView()) {String defaultViewName getDefaultViewName(request);if (defaultViewName ! null) {exMv.setViewName(defaultViewName);}}if (logger.isTraceEnabled()) {logger.trace(Using resolved error view: exMv, ex);}else if (logger.isDebugEnabled()) {logger.debug(Using resolved error view: exMv);}WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());return exMv;}throw ex;}Spring MVC在WebMvcConfigurationSupport#handlerExceptionResolver()方法中处理异常解析器的注入该方法返回的是一个包装器HandlerExceptionResolverComposite该包装器持有HandlerExceptionResolver Beanpublic HandlerExceptionResolver handlerExceptionResolver(Qualifier(mvcContentNegotiationManager) ContentNegotiationManager contentNegotiationManager) {ListHandlerExceptionResolver exceptionResolvers new ArrayList();configureHandlerExceptionResolvers(exceptionResolvers);if (exceptionResolvers.isEmpty()) {addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);}extendHandlerExceptionResolvers(exceptionResolvers);HandlerExceptionResolverComposite composite new HandlerExceptionResolverComposite();composite.setOrder(0);composite.setExceptionResolvers(exceptionResolvers);return composite;}WebMvcConfigurationSupport#configureHandlerExceptionResolvers()方法是一个空实现需要子类实现去注入自定义的HandlerExceptionResolverprotected void configureHandlerExceptionResolvers(ListHandlerExceptionResolver exceptionResolvers) {}如果没有提供自定义的异常解析器会默认使用WebMvcConfigurationSupport#addDefaultHandlerExceptionResolvers()方法加载异常解析器protected final void addDefaultHandlerExceptionResolvers(ListHandlerExceptionResolver exceptionResolvers,ContentNegotiationManager mvcContentNegotiationManager) {ExceptionHandlerExceptionResolver exceptionHandlerResolver createExceptionHandlerExceptionResolver();exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager);exceptionHandlerResolver.setMessageConverters(getMessageConverters());exceptionHandlerResolver.setCustomArgumentResolvers(getArgumentResolvers());exceptionHandlerResolver.setCustomReturnValueHandlers(getReturnValueHandlers());if (jackson2Present) {exceptionHandlerResolver.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));}if (this.applicationContext ! null) {exceptionHandlerResolver.setApplicationContext(this.applicationContext);}exceptionHandlerResolver.afterPropertiesSet();exceptionResolvers.add(exceptionHandlerResolver);ResponseStatusExceptionResolver responseStatusResolver new ResponseStatusExceptionResolver();responseStatusResolver.setMessageSource(this.applicationContext);exceptionResolvers.add(responseStatusResolver);exceptionResolvers.add(new DefaultHandlerExceptionResolver());}ExceptionHandlerExceptionResolver类的exceptionHandlerAdviceCache属性中存储的就是ExceptionHandler注解的异常处理器初始化核心代码 Overridepublic void afterPropertiesSet() {// Do this first, it may add ResponseBodyAdvice beansinitExceptionHandlerAdviceCache();if (this.argumentResolvers null) {ListHandlerMethodArgumentResolver resolvers getDefaultArgumentResolvers();this.argumentResolvers new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.returnValueHandlers null) {ListHandlerMethodReturnValueHandler handlers getDefaultReturnValueHandlers();this.returnValueHandlers new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}}private void initExceptionHandlerAdviceCache() {if (getApplicationContext() null) {return;}ListControllerAdviceBean adviceBeans ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());for (ControllerAdviceBean adviceBean : adviceBeans) {Class? beanType adviceBean.getBeanType();if (beanType null) {throw new IllegalStateException(Unresolvable type for ControllerAdviceBean: adviceBean);}ExceptionHandlerMethodResolver resolver new ExceptionHandlerMethodResolver(beanType);if (resolver.hasExceptionMappings()) {this.exceptionHandlerAdviceCache.put(adviceBean, resolver);}if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {this.responseBodyAdvice.add(adviceBean);}}if (logger.isDebugEnabled()) {int handlerSize this.exceptionHandlerAdviceCache.size();int adviceSize this.responseBodyAdvice.size();if (handlerSize 0 adviceSize 0) {logger.debug(ControllerAdvice beans: none);}else {logger.debug(ControllerAdvice beans: handlerSize ExceptionHandler, adviceSize ResponseBodyAdvice);}}}注意自定义实现WebMvcConfigurationSupport可能会导致 ExceptionHandler异常处理器失效比如重写WebMvcConfigurationSupport#configureHandlerExceptionResolvers()方法并添加了自己的异常处理器package com.example.config;import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;Configuration
public class WebMvcConfigurationSupportTest extends WebMvcConfigurationSupport {Overrideprotected void configureHandlerExceptionResolvers(ListHandlerExceptionResolver exceptionResolvers) {exceptionResolvers.add(new HandlerExceptionResolver() {Overridepublic ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,Object handler, Exception ex) {System.out.println(resolveException.......................);return new ModelAndView();}});}
}