標籤:異常 -name on() 沒有 查詢參數 classpath 執行個體化 row end
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{}
@Controllerpublic 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)@Documentedpublic @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模板以路徑變數和/或查詢參數的形式傳遞資料
@Controllerpublic 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屬性。
@Controllerpublic 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"; }
}
spring-mvc進階技術