※攔截器
※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執行完才執行 postHandle
postHandle:寫在設定檔的前面最後執行,全部的 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>
※