※攔截器
※HandlerInterceptor
public class HelloInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("A1"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("A2"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("A3"); } }
※寫四支一模一樣的,分別是 ABCD 的 1~3
※preHandle 執行在目標方法之前
postHandle 執行在目標方法之後、view 之前
afterCompletion view 之後
※preHandle 回傳 false,那之後的都不會執行
※spring 設定
mapping 是映射什麼路徑
exclude-mapping 是排除路徑
<mvc:interceptors> <bean class="init.HelloInterceptor" /> <mvc:interceptor> <mvc:mapping path="/**" /> <bean class="init.HelloInterceptor2" /> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/ooo/xxx/a/b/*.mvc" /> <bean class="init.HelloInterceptor3" /> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**" /> <mvc:exclude-mapping path="/ooo/xxx/a/*/*.mvc" /> <bean class="init.HelloInterceptor4" /> </mvc:interceptor> </mvc:interceptors> <mvc:view-controller path="ooo/xxx/b/a/c.mvc" view-name="jump1" /> <mvc:view-controller path="ooo/xxx/a/b/c1.mvc" view-name="jump1" /> <mvc:view-controller path="ooo/xxx/a/b/c2.mvc" view-name="jump1" />
※可以不加 <mvc:annotation-driven />
※HelloInterceptor、HelloInterceptor2 可以說是一樣的
※注意 exclude-mapping 最上面一定要有 mapping,否則會報錯,也就是先指定一個大範圍,然後排除,排除可以寫好幾個
※測試
<a href="ooo/xxx/b/a/c.mvc">c</a> <a href="ooo/xxx/a/b/c1.mvc">c1</a> <a href="ooo/xxx/a/b/c2.mvc">c2</a>
※第一個執行 ABD,其他兩個都是 ABC
※執行順序
preHandle:寫在設定檔的前面最先執行,全部的 preHandle執行完才執行 postHandlepostHandle:寫在設定檔的前面最後執行,全部的 postHandle 執行完才執行 afterCompletion
afterCompletion :寫在設定檔的前面最後執行
preHandle 是正序;postHandle、afterCompletion 執行順序是倒序
※例外處理
使用 @ExceptionHandler
※controller
@RequestMapping("exception") public String testException(Integer i) { System.out.println(2/i); return "hello"; } @ExceptionHandler(ArithmeticException.class) public String exceptionMethod() { System.out.println("我錯了"); return "errPage"; }
※回傳的字串是配合 spring 設定檔的 InternalResourceViewResolver
※測試
<a href="ooo/xxx/exception.mvc?i=0">exception</a>
※網址是不變的
※不能使用 Map
@ExceptionHandler(ArithmeticException.class) public ModelAndView exceptionMethod(Exception ex /*, Model model*/) { System.out.println("我錯了" + ex); ModelAndView mav = new ModelAndView("errPage"); mav.addObject("excep", ex); return mav; }
※當然包括子類 Model,只是放在參數裡,都還沒有 put,就 500了,想塞值到前端,要用 ModelAndView
※多個 @ExceptionHandler
@ExceptionHandler(ArithmeticException.class) public String exceptionMethod(Exception ex) { System.out.println("A"); return "errPage"; } @ExceptionHandler(Exception.class) public String exceptionMethod2(Exception ex) { System.out.println("B"); return "errPage"; }
※會以完全匹配為主,沒有完全匹配才會退而求其次
※全域的例外處理 @ControllerAdvice
@ControllerAdvice public class GlobalException { @ExceptionHandler(ArithmeticException.class) public String exceptionMethod(Exception ex) { System.out.println("C"); return "errPage"; } @ExceptionHandler(Exception.class) public String exceptionMethod2(Exception ex) { System.out.println("D"); return "errPage"; } }
※區域例外處理全部都沒有 @ExceptionHandler 才會執行全域的 @ControllerAdvice
※全域必需設定
1. <context:component-scan base-package="controller" />
屬性 use-default-filters 不能是 false,預設是 true
2. <mvc:annotation-driven />
否則有寫也不會執行
※預設的例外處理
看原碼 DefaultHandlerExceptionResolver.doResolveException,Eclipse 可使用 Ctrl + Shift + T以 3.2.13 版為例,會發現有 13 個預設的例外處理
NoSuchRequestHandlingMethodException
HttpRequestMethodNotSupportedException
HttpMediaTypeNotSupportedException
HttpMediaTypeNotAcceptableException
MissingServletRequestParameterException
ServletRequestBindingException
ConversionNotSupportedException
TypeMismatchException
HttpMessageNotReadableException
HttpMessageNotWritableException
MethodArgumentNotValidException
MissingServletRequestPartException
BindException
※上圖為預設的,下圖為修改過的,想修改就必需如下設定
※自訂例外
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "我錯了") public class DefinedSelfException extends RuntimeException {}
※HttpStatus 有很多,隨便選即可
※controller
// @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "我錯了2") @RequestMapping("definedSelfExp") public String definedSelfExp(Integer i) { if (i == 0) throw new DefinedSelfException(); System.out.println(2 / i); return "hello"; }
※@ResponseStatus 若寫在方法上,i == 0 時不變;但若不是 0,不會跳頁,會產生例外,但寫在這裡的中文會亂碼,寫在另外一支 class 不會,這個我沒解
※測試
<a href="ooo/xxx/definedSelfExp.mvc?i=0">definedSelfExp</a>
※
※SimpleMappingExceptionResolver
※spring 設定檔
<bean id="simpleMappingExceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="java.lang.ArithmeticException">arithmeticPage</prop> <prop key="java.lang.ArrayIndexOutOfBoundsException">arrayIndexPage</prop> </props> </property> <property name="exceptionAttribute" value="xxx" /> </bean> <mvc:default-servlet-handler /> <mvc:annotation-driven />
※prop 包起來的字串是頁面名稱,配合 InternalResourceViewResolver
※exceptionAttribute 如果不寫,預設是 exception,可以在 JSP 用 EL
※controller
@RequestMapping("simpleExp") // @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "我錯了2") public String simpleExp(Integer i) { // if (i == 0) throw new DefinedSelfException(); System.out.println(2 / i); return "hello"; }
※方法上的 @ResponseStatus 是有用的
※測試
<a href="ooo/xxx/simpleExp.mvc?i=0">simpleExp</a>
※
沒有留言:
張貼留言