Spring MVC高級技術包括但不限於web.xml配置、異常處理、跨重定向請求傳遞數據 1、web.xml文件的配置 ContextLoaderListener是根容器,DispatcherServlet是子容器。父容器中管理的bean可以被子容器引用,反之,不行。它們都從各自的xml文件初始化 ...
Spring MVC高級技術包括但不限於web.xml配置、異常處理、跨重定向請求傳遞數據
1、web.xml文件的配置
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-*.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springMvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
ContextLoaderListener是根容器,DispatcherServlet是子容器。父容器中管理的bean可以被子容器引用,反之,不行。它們都從各自的xml文件初始化自己的上下文
ContextLoaderListener如果未指定contextConfigLocation參數,則預設載入的配置文件為/WEB-INF/applicationContext.xml
DispatcherServlet如果未指定contextConfigLocation參數,則根據<servlet-name>元素指定的名稱,在/WEB-INF/文件夾下尋找配置文件appServlet-servlet.xml
2、處理異常
Spring提供了多種方式將異常轉換為響應
- 特定的 Spring異常會自動映射為指定的HTTP狀態碼
- 異常上可以添加@ResponseStatus註解,將異常映射為某一個HTTP狀態碼
- 在方法上可以添加@ExceptionHandler註解,使其用來處理異常
1)特定的 Spring異常會自動映射為指定的HTTP狀態碼
如果在控制器中拋出了異常,該異常不在列表中,又沒有指定HTTP狀態碼,則預設為狀態碼為500
2)異常上可以添加@ResponseStatus註解,將異常映射為某一個HTTP狀態碼
@Controller
public class HelloController { @RequestMapping("/home") public String home(){ System.out.println("執行home"); throw new MyException(); // return "home"; //返回一個字元串,即邏輯視圖名 } }
package com.cn.Exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; public class MyException extends RuntimeException{ }
瀏覽器訪問 http://localhost:8080/home
修改自定義異常
package com.cn.Exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "拋出異常的原因") public class MyException extends RuntimeException{ }
瀏覽器訪問 http://localhost:8080/home
3)在方法上可以添加@ExceptionHandler註解,使其用來處理異常
- 該方式是按照處理請求的方式處理異常,@ExceptionHandler註解的方法返回值為字元串表示邏輯視圖名
package com.cn.Exception; public class MyException2 extends RuntimeException{ }
@Controller public class HelloController { @RequestMapping("/home") public String home(){ System.out.println("執行home"); throw new MyException2(); // return "home"; //返回一個字元串,即邏輯視圖名 } @ExceptionHandler(MyException2.class) public String handleMException(){ System.out.println("處理異常邏輯"); return "fail"; } }
訪問http://localhost:8080/home,後臺輸出
瀏覽器頁面
@ExceptionHandler註解的方法可以處理同一個控制器中所有處理器方法所拋出的異常(註解指定的異常),註解定義如下
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ExceptionHandler { Class<? extends Throwable>[] value() default {}; }
- spring也支持為控制器添加通知,那麼該通知對於所有的控制器中所有的處理器方法拋出的異常都起作用,實現如下
@ControllerAdvice 所標註的類會被組件掃描實例化,交給容器管理。最為實用的一個場景是將所有@ExceptionHandler標註的方法收集到一個類中,這樣所有的控制器異常就能在一個地方進行一致處理。以下HandleException類定義表明在控制器中的處理器拋出MyException2類的異常,就會被handleMException方法處理,最終跳轉fail.jsp頁面
package com.cn.advice; import com.cn.Exception.MyException2; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @ControllerAdvice public class HandleException { @ExceptionHandler(MyException2.class) public String handleMException(){ System.out.println("處理異常邏輯"); return "fail"; } }
3、跨重定向請求傳遞數據
如果是forward轉發請求,那麼處理器方法業務處理完成後,該方法所指定的模型數據會複製到請求中,作為請求的一部分,轉發到下一個處理器,下一個處理器可以從請求中獲取上一個處理的模型數據;
如果是redirect重新向,原始請求就結束了,並且會重新發起一個GET請求。因此原始請求中的模型數據也就消失了,在請求到達下一個處理器,沒有任何的模型數據,需要模型數據必須自己處理。
針對重定向傳遞數據,有兩種方案:
- 使用URL模板以路徑變數和/或查詢參數的形式傳遞數據
- 使用flash屬性傳遞數據
1)使用URL模板以路徑變數和/或查詢參數的形式傳遞數據
@Controller public class HelloController { @RequestMapping("/home2") public String home2(Model model){ model.addAttribute("id","12324131343256"); model.addAttribute("name","pick"); return "redirect:home3/{id}"; //含有redirect的字元串,表示重定向到另一個處理器; //如果含有forward的字元串,表示轉向到另一個處理器 } @RequestMapping("/home3/{id}") public String home3(@PathVariable String id, Model model){ System.out.println("傳遞的ID="+id); model.addAttribute(new User()); return "home"; } }
瀏覽器訪問localhost:8080/home2,抓包得訪問的url。從以下可以看出,處理器完成後重定向時,模型中的數據填充到了路徑變數中,路徑變數中沒有的key,則以查詢參數的形式賦在url之後,組成了新的url訪問。
2)使用flash屬性傳遞數據
重定向時候,採用1)中的方式傳遞數據,僅僅能夠傳遞簡單的數據,不能傳遞對象。如何將對象也能傳遞到下一個處理器呢?可以將要傳遞到下一個處理器的數據放入用戶會話中,然後在下一個處理器從會話的取出來,並刪除會話中的該數據。然而,spring提供了將數據發送為flash屬性的功能,不需要我們管理這些數據,flash屬性會一致攜帶這些數據直到下一次請求才消失。
Spring提供RedirectAttributes是Model介面的子介面,除了提供Model的所有功能,還提供了幾個方法用來設置flash屬性。
@Controller public class HelloController { @RequestMapping("/home2") public String home2(RedirectAttributes model){ model.addAttribute("id","12324131343256"); model.addFlashAttribute("user",new User("liming","123456"));//設置flash屬性,也可以 model.addFlashAttribute(new User("liming","123456"))
//則通過值得類型自行推斷出key為user return "redirect:home3/{id}"; } @RequestMapping("/home3/{id}") public String home3(@PathVariable String id, RedirectAttributes model){ System.out.println("傳遞的ID="+id); if (model.containsAttribute("user")) { System.out.println("傳遞的對象:" + model.getFlashAttributes().get("user")); } return "home"; }
}