springMVC提供的異常處理主要有兩種方式,一種是直接實現自己的HandlerExceptionResolver,另一種是使用注解的方式實現一個專門用於處理異常的Controller——ExceptionHandler。
1、實現自己的HandlerExceptionResolver,HandlerExceptionResolver是一個接口,springMVC本身已經對其有了一個自身的實現——DefaultExceptionResolver,該解析器只是對其中的一些比較典型的異常進行了攔截處理。
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.springframework.web.servlet.HandlerExceptionResolver;
- import org.springframework.web.servlet.ModelAndView;
- public class ExceptionHandler implements HandlerExceptionResolver {
- @Override
- public ModelAndView resolveException(HttpServletRequest request,
- HttpServletResponse response, Object handler, Exception ex) {
- // TODO Auto-generated method stub
- return new ModelAndView("exception");
- }
- }
上述的resolveException的第4個參數表示對哪種類型的異常進行處理,如果想同時對多種異常進行處理,可以把它換成一個異常數組。
定義了這樣一個異常處理器之后就要在applicationContext中定義這樣一個bean對象,如:
- <bean id="exceptionResolver" class="com.tiantian.xxx.web.handler.ExceptionHandler"/>
2、使用@ExceptionHandler進行處理
使用@ExceptionHandler進行處理有一個不好的地方是進行異常處理的方法必須與出錯的方法在同一個Controller里面
如:
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.ExceptionHandler;
- import org.springframework.web.bind.annotation.RequestMapping;
- import com.tiantian.blog.web.servlet.MyException;
- @Controller
- public class GlobalController {
- /**
- * 用於處理異常的
- * @return
- */
- @ExceptionHandler({MyException.class})
- public String exception(MyException e) {
- System.out.println(e.getMessage());
- e.printStackTrace();
- return "exception";
- }
- @RequestMapping("test")
- public void test() {
- throw new MyException("出錯了!");
- }
- }
這里在頁面上訪問test方法的時候就會報錯,而擁有該test方法的Controller又擁有一個處理該異常的方法,這個時候處理異常的方法就會被調用
當發生異常的時候,上述兩種方式都使用了的時候,第一種方式會將第二種方式覆蓋
http://gaojiewyh.iteye.com/blog/1297746
最近使用spring mvc開發一個web系統,發現在controller里發生未捕獲異常時不出日志。
分析DispatcherServlet,初始化handlerExceptionResolvers
- /**
- * Initialize the strategy objects that this servlet uses.
- * <p>May be overridden in subclasses in order to initialize
- * further strategy objects.
- */
- protected void initStrategies(ApplicationContext context) {
- initMultipartResolver(context);
- initLocaleResolver(context);
- initThemeResolver(context);
- initHandlerMappings(context);
- initHandlerAdapters(context);
- // 初始化異常處理支持器
- initHandlerExceptionResolvers(context);
- initRequestToViewNameTranslator(context);
- initViewResolvers(context);
- }
- // 進入初始化處理方法,具體內容就不貼了,主要是先到上下文中搜尋我們自己定義的ExceptionResolvers,如果沒有自定義的resolvers,從默認配置中讀取。
- private void initHandlerExceptionResolvers(ApplicationContext context)
- // 從默認策略中取得默認配置,從DispatcherServlet.properties文件中取得相關的配置策略,但是在spring2.5的mvc jar包中properties文件中沒有HandlerExceptionResolver的默認配置,返回一個EmptyList給handlerExceptionResolvers
- protected List getDefaultStrategies(ApplicationContext context, Class strategyInterface)
分析DispatcherServlet,分發處理請求
- // 從dispatch方法中看到,系統對請求進行具體的邏輯處理部分被catch住了一次exception,然后會使用servlet持有的ExceptionResolver進行處理
- protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
- HttpServletRequest processedRequest = request;
- HandlerExecutionChain mappedHandler = null;
- int interceptorIndex = -1;
- // Expose current LocaleResolver and request as LocaleContext.
- LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
- LocaleContextHolder.setLocaleContext(buildLocaleContext(request), this.threadContextInheritable);
- // Expose current RequestAttributes to current thread.
- RequestAttributes previousRequestAttributes = RequestContextHolder.getRequestAttributes();
- ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request);
- RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
- if (logger.isTraceEnabled()) {
- logger.trace("Bound request context to thread: " + request);
- }
- try {
- ModelAndView mv = null;
- boolean errorView = false;
- try {
- processedRequest = checkMultipart(request);
- // Determine handler for the current request.
- mappedHandler = getHandler(processedRequest, false);
- if (mappedHandler == null || mappedHandler.getHandler() == null) {
- noHandlerFound(processedRequest, response);
- return;
- }
- // Apply preHandle methods of registered interceptors.
- HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
- if (interceptors != null) {
- for (int i = 0; i < interceptors.length; i++) {
- HandlerInterceptor interceptor = interceptors[i];
- if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
- triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
- return;
- }
- interceptorIndex = i;
- }
- }
- // Actually invoke the handler.
- HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
- mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
- // Do we need view name translation?
- if (mv != null && !mv.hasView()) {
- mv.setViewName(getDefaultViewName(request));
- }
- // Apply postHandle methods of registered interceptors.
- if (interceptors != null) {
- for (int i = interceptors.length - 1; i >= 0; i--) {
- HandlerInterceptor interceptor = interceptors[i];
- interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
- }
- }
- }
- catch (ModelAndViewDefiningException ex) {
- logger.debug("ModelAndViewDefiningException encountered", ex);
- mv = ex.getModelAndView();
- }
- // 這里catch住controller拋出的異常,使用持有的ExceptionResolver處理,當沒有配置自己的處理器時,程序會將異常繼續往上拋出,最終交給我們的容器處理
- catch (Exception ex) {
- Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
- mv = processHandlerException(processedRequest, response, handler, ex);
- errorView = (mv != null);
- }
- // Did the handler return a view to render?
- if (mv != null && !mv.wasCleared()) {
- render(mv, processedRequest, response);
- if (errorView) {
- WebUtils.clearErrorRequestAttributes(request);
- }
- }
- else {
- if (logger.isDebugEnabled()) {
- logger.debug("Null ModelAndView returned to DispatcherServlet with name '" +
- getServletName() + "': assuming HandlerAdapter completed request handling");
- }
- }
- // Trigger after-completion for successful outcome.
- triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
- }
- // 當沒有配置ExceptionResolver時,異常將到達這里,最終拋出
- catch (Exception ex) {
- // Trigger after-completion for thrown exception.
- triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
- throw ex;
- }
- catch (Error err) {
- ServletException ex = new NestedServletException("Handler processing failed", err);
- // Trigger after-completion for thrown exception.
- triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
- throw ex;
- }
- finally {
- // Clean up any resources used by a multipart request.
- if (processedRequest != request) {
- cleanupMultipart(processedRequest);
- }
- // Reset thread-bound context.
- RequestContextHolder.setRequestAttributes(previousRequestAttributes, this.threadContextInheritable);
- LocaleContextHolder.setLocaleContext(previousLocaleContext, this.threadContextInheritable);
- // Clear request attributes.
- requestAttributes.requestCompleted();
- if (logger.isTraceEnabled()) {
- logger.trace("Cleared thread-bound request context: " + request);
- }
- }
- }
http://fancyboy2050.iteye.com/blog/1300037
- 此段代碼ZZ from http://tdcq.iteye.com/blog/890957
- <!-- 全局異常配置 start -->
- <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
- <property name="exceptionMappings">
- <props>
- <prop key="java.lang.Exception">errors/error</prop>
- <prop key="java.lang.Throwable">errors/err</prop>
- </props>
- </property>
- <property name="statusCodes">
- <props>
- <prop key="errors/error">500</prop>
- <prop key="errors/404">404</prop>
- </props>
- </property>
- <!-- 設置日志輸出級別,不定義則默認不輸出警告等錯誤日志信息 -->
- <property name="warnLogCategory" value="WARN"></property>
- <!-- 默認錯誤頁面,當找不到上面mappings中指定的異常對應視圖時,使用本默認配置 -->
- <property name="defaultErrorView" value="errors/error"></property>
- <!-- 默認HTTP狀態碼 -->
- <property name="defaultStatusCode" value="500"></property>
- </bean>
- <!-- 全局異常配置 end -->
用spring mvc做了個項目,但是出現異常的情況下居然沒有日志輸出,然后各種嘗試。。。正如上面介紹的:設置日志輸出級別,不定義則默認不輸出警告等錯誤日志信息!!【當然,try catch的異常沒問題】
敬請留意。