Spring MVC學習(六)-------註解式控制器詳解5

6.6.二、@RequestParam綁定單個請求參數值

@RequestParam用於將請求參數區數據映射到功能處理方法的參數上。java

Java代碼   收藏代碼
  1. public String requestparam1(@RequestParam String username)  

請求中包含username參數(如/requestparam1?username=zhang),則自動傳入。web

 

此處要特別注意:右擊項目,選擇「屬性」,打開「屬性對話框」,選擇「Java Compiler」而後再打開的選項卡將「Add variable attributes to generated class files」取消勾選,意思是不將局部變量信息添加到類文件中,如圖6-12所示:數據庫



 圖6-12數組

當你在瀏覽器輸入URL,如「requestparam1?username=123」時會報以下錯誤瀏覽器

Name for argument type [java.lang.String] not available, and parameter name information not found in class file either,表示得不到功能處理方法的參數名,此時咱們須要以下方法進行入參:session

 

Java代碼   收藏代碼
  1. public String requestparam2(@RequestParam("username") String username)  

 即經過@RequestParam("username")明確告訴Spring Web MVC使用username進行入參。app

 

 

接下來咱們看一下@RequestParam註解主要有哪些參數:jvm

value:參數名字,即入參的請求參數名字,如username表示請求的參數區中的名字爲username的參數的值將傳入;ide

required:是否必須,默認是true,表示請求中必定要有相應的參數,不然將報404錯誤碼;學習

defaultValue:默認值,表示若是請求中沒有同名參數時的默認值,默認值能夠是SpEL表達式,如「#{systemProperties['java.vm.version']}」。

 

Java代碼   收藏代碼
  1. public String requestparam4(@RequestParam(value="username",required=false) String username)   

 表示請求中能夠沒有名字爲username的參數,若是沒有默認爲null,此處須要注意以下幾點:

 

     原子類型:必須有值,不然拋出異常,若是容許空值請使用包裝類代替。

     Boolean包裝類型類型:默認Boolean.FALSE,其餘引用類型默認爲null。

 

Java代碼   收藏代碼
  1. public String requestparam5(  
  2. @RequestParam(value="username", required=true, defaultValue="zhang") String username)   
  3.           

表示若是請求中沒有名字爲username的參數,默認值爲「zhang」。

 

 

若是請求中有多個同名的應該如何接收呢?如給用戶受權時,可能授予多個權限,首先看下以下代碼:

Java代碼   收藏代碼
  1. public String requestparam7(@RequestParam(value="role") String roleList)  

若是請求參數相似於url?role=admin&rule=user,則實際roleList參數入參的數據爲「admin,user」,即多個數據之間使用「,」分割;咱們應該使用以下方式來接收多個請求參數:

Java代碼   收藏代碼
  1. public String requestparam7(@RequestParam(value="role") String[] roleList)     

 

Java代碼   收藏代碼
  1. public String requestparam8(@RequestParam(value="list") List<String> list)      

 到此@RequestParam咱們就介紹完了,以上測試代碼在cn.javass.chapter6.web.controller. paramtype.RequestParamTypeController中。

 

6.6.三、@PathVariable綁定URI模板變量值

@PathVariable用於將請求URL中的模板變量映射到功能處理方法的參數上。

 

Java代碼   收藏代碼
  1. @RequestMapping(value="/users/{userId}/topics/{topicId}")  
  2. public String test(  
  3.        @PathVariable(value="userId"int userId,   
  4.        @PathVariable(value="topicId"int topicId)        

 如請求的URL爲「控制器URL/users/123/topics/456」,則自動將URL中模板變量{userId}和{topicId}綁定到經過@PathVariable註解的同名參數上,即入參後userId=12三、topicId=456。代碼在PathVariableTypeController中。

 

6.6.四、@CookieValue綁定Cookie數據值

@CookieValue用於將請求的Cookie數據映射到功能處理方法的參數上。

 

Java代碼   收藏代碼
  1. public String test(@CookieValue(value="JSESSIONID", defaultValue="") String sessionId)   

 

如上配置將自動將JSESSIONID值入參到sessionId參數上,defaultValue表示Cookie中沒有JSESSIONID時默認爲空。

Java代碼   收藏代碼
  1. public String test2(@CookieValue(value="JSESSIONID", defaultValue="") Cookie sessionId)         

傳入參數類型也能夠是javax.servlet.http.Cookie類型。

 

測試代碼在CookieValueTypeController中。@CookieValue也擁有和@RequestParam相同的三個參數,含義同樣。

6.6.五、@RequestHeader綁定請求頭數據

@RequestHeader用於將請求的頭信息區數據映射到功能處理方法的參數上。

Java代碼   收藏代碼
  1. @RequestMapping(value="/header")  
  2. public String test(  
  3.        @RequestHeader("User-Agent") String userAgent,  
  4.        @RequestHeader(value="Accept") String[] accepts)  
  5.           

如上配置將自動將請求頭「User-Agent」值入參到userAgent參數上,並將「Accept」請求頭值入參到accepts參數上。測試代碼在HeaderValueTypeController中。

 

@RequestHeader也擁有和@RequestParam相同的三個參數,含義同樣。

6.6.六、@ModelAttribute綁定請求參數到命令對象

@ModelAttribute一個具備以下三個做用:

①綁定請求參數到命令對象:放在功能處理方法的入參上時,用於將多個請求參數綁定到一個命令對象,從而簡化綁定流程,並且自動暴露爲模型數據用於視圖頁面展現時使用;

②暴露表單引用對象爲模型數據:放在處理器的通常方法(非功能處理方法)上時,是爲表單準備要展現的表單引用對象,如註冊時須要選擇的所在城市等,並且在執行功能處理方法(@RequestMapping註解的方法)以前,自動添加到模型對象中,用於視圖頁面展現時使用;

③暴露@RequestMapping方法返回值爲模型數據:放在功能處理方法的返回值上時,是暴露功能處理方法的返回值爲模型數據,用於視圖頁面展現時使用。

 

1、綁定請求參數到命令對象

如用戶登陸,咱們須要捕獲用戶登陸的請求參數(用戶名、密碼)並封裝爲用戶對象,此時咱們可使用@ModelAttribute綁定多個請求參數到咱們的命令對象。

 

Java代碼   收藏代碼
  1. public String test1(@ModelAttribute("user") UserModel user)  

和6.6.1一節中的5、命令/表單對象功能同樣。只是此處多了一個註解@ModelAttribute("user"),它的做用是將該綁定的命令對象以「user」爲名稱添加到模型對象中供視圖頁面展現使用。咱們此時能夠在視圖頁面使用${user.username}來獲取綁定的命令對象的屬性。

 

綁定請求參數到命令對象支持對象圖導航式的綁定,如請求參數包含「?username=zhang&password=123&workInfo.city=bj」自動綁定到user中的workInfo屬性的city屬性中。

Java代碼   收藏代碼
  1. @RequestMapping(value="/model2/{username}")  
  2. public String test2(@ModelAttribute("model") DataBinderTestModel model) {   

DataBinderTestModel相關模型請從第三章拷貝過來,請求參數到命令對象的綁定規則詳見【4.16.一、數據綁定】一節,URI模板變量也能自動綁定到命令對象中,當你請求的URL中包含「bool=yes&schooInfo.specialty=computer&hobbyList[0]=program&hobbyList[1]=music&map[key1]=value1&map[key2]=value2&state=blocked」會自動綁定到命令對象上。

 

URI模板變量和請求參數同名時,URI模板變量具備高優先權。

 

2、暴露表單引用對象爲模型數據

Java代碼   收藏代碼
  1. @ModelAttribute("cityList")  
  2. public List<String> cityList() {  
  3.     return Arrays.asList("北京""山東");  
  4. }   

如上代碼會在執行功能處理方法以前執行,並將其自動添加到模型對象中,在功能處理方法中調用Model 入參的containsAttribute("cityList")將會返回true。

Java代碼   收藏代碼
  1. @ModelAttribute("user")  //①  
  2. public UserModel getUser(@RequestParam(value="username", defaultValue="") String username) {  
  3. //TODO 去數據庫根據用戶名查找用戶對象  
  4. UserModel user = new UserModel();  
  5. user.setRealname("zhang");  
  6.      return user;  
  7. }   

如你要修改用戶資料時通常須要根據用戶的編號/用戶名查找用戶來進行編輯,此時能夠經過如上代碼查找要編輯的用戶。

也能夠進行一些默認值的處理。

Java代碼   收藏代碼
  1. @RequestMapping(value="/model1"//②  
  2. public String test1(@ModelAttribute("user") UserModel user, Model model)   

此處咱們看到①和②有同名的命令對象,那Spring Web MVC內部如何處理的呢:

(1首先執行@ModelAttribute註解的方法,準備視圖展現時所須要的模型數據;@ModelAttribute註解方法形式參數規則和@RequestMapping規則同樣,如能夠有@RequestParam等;

2執行@RequestMapping註解方法,進行模型綁定時首先查找模型數據中是否含有同名對象,若是有直接使用,若是沒有經過反射建立一個,所以②處的user將使用①處返回的命令對象。即②處的user等於①處的user。

 

3、暴露@RequestMapping方法返回值爲模型數據

Java代碼   收藏代碼
  1. public @ModelAttribute("user2") UserModel test3(@ModelAttribute("user2") UserModel user)  

你們能夠看到返回值類型是命令對象類型,並且經過@ModelAttribute("user2")註解,此時會暴露返回值到模型數據(名字爲user2)中供視圖展現使用。那哪一個視圖應該展現呢?此時Spring Web MVC會根據RequestToViewNameTranslator進行邏輯視圖名的翻譯,詳見【4.15.五、RequestToViewNameTranslator】一節。

 

此時又有問題了,@RequestMapping註解方法的入參user暴露到模型數據中的名字也是user2,其實咱們能猜到:

3@ModelAttribute註解的返回值會覆蓋@RequestMapping註解方法中的@ModelAttribute註解的同名命令對象。

 

4、匿名綁定命令參數

Java代碼   收藏代碼
  1. public String test4(@ModelAttribute UserModel user, Model model)  
  2. 或  
  3. public String test5(UserModel user, Model model)   

此時咱們沒有爲命令對象提供暴露到模型數據中的名字,此時的名字是什麼呢?Spring Web MVC自動將簡單類名(首字母小寫)做爲名字暴露,如「cn.javass.chapter6.model.UserModel」暴露的名字爲「userModel」。

Java代碼   收藏代碼
  1. public @ModelAttribute List<String> test6()  
  2. 或  
  3. public @ModelAttribute List<UserModel> test7()   

對於集合類型(Collection接口的實現者們,包括數組),生成的模型對象屬性名爲「簡單類名(首字母小寫)」+「List」,如List<String>生成的模型對象屬性名爲「stringList」,List<UserModel>生成的模型對象屬性名爲「userModelList」。

 

其餘狀況一概都是使用簡單類名(首字母小寫)做爲模型對象屬性名,如Map<String, UserModel>類型的模型對象屬性名爲「map」。

6.6.七、@SessionAttributes綁定命令對象到session

有時候咱們須要在屢次請求之間保持數據,通常狀況須要咱們明確的調用HttpSession的API來存取會話數據,如多步驟提交的表單。Spring Web MVC提供了@SessionAttributes進行請求間透明的存取會話數據。

Java代碼   收藏代碼
  1. //一、在控制器類頭上添加@SessionAttributes註解  
  2. @SessionAttributes(value = {"user"})    //①  
  3. public class SessionAttributeController   
  4.   
  5. //二、@ModelAttribute註解的方法進行表單引用對象的建立  
  6. @ModelAttribute("user")    //②  
  7. public UserModel initUser()   
  8.   
  9. //三、@RequestMapping註解方法的@ModelAttribute註解的參數進行命令對象的綁定  
  10. @RequestMapping("/session1")   //③  
  11. public String session1(@ModelAttribute("user") UserModel user)  
  12.   
  13. //四、經過SessionStatus的setComplete()方法清除@SessionAttributes指定的會話數據  
  14. @RequestMapping("/session2")   //③  
  15. public String session(@ModelAttribute("user") UserModel user, SessionStatus status) {  
  16.     if(true) { //④  
  17.         status.setComplete();  
  18.     }  
  19.     return "success";  
  20. }   

@SessionAttributes(value = {"user"})含義:

@SessionAttributes(value = {"user"}) 標識將模型數據中的名字爲「user」 的對象存儲到會話中(默認HttpSession),此處value指定將模型數據中的哪些數據(名字進行匹配)存儲到會話中,此外還有一個types屬性表示模型數據中的哪些類型的對象存儲到會話範圍內,若是同時指定value和types屬性則那些名字和類型都匹配的對象才能存儲到會話範圍內。

 

包含@SessionAttributes執行流程以下所示:

 首先根據@SessionAttributes註解信息查找會話內的對象放入到模型數據中;

 執行@ModelAttribute註解的方法:若是模型數據中包含同名的數據,則不執行@ModelAttribute註解方法進行準備表單引用數據,而是使用①步驟中的會話數據;若是模型數據中不包含同名的數據,執行@ModelAttribute註解的方法並將返回值添加到模型數據中;

③ 執行@RequestMapping方法,綁定@ModelAttribute註解的參數:查找模型數據中是否有@ModelAttribute註解的同名對象,若是有直接使用,不然經過反射建立一個;並將請求參數綁定到該命令對象;

此處須要注意:若是使用@SessionAttributes註解控制器類以後,③步驟必定是從模型對象中取得同名的命令對象,若是模型數據中不存在將拋出HttpSessionRequiredException Expected session attribute ‘user’(Spring3.1)

或HttpSessionRequiredException Session attribute ‘user’ required - not found in session(Spring3.0)異常。

 若是會話能夠銷燬了,如多步驟提交表單的最後一步,此時能夠調用SessionStatus對象的setComplete()標識當前會話的@SessionAttributes指定的數據能夠清理了,此時當@RequestMapping功能處理方法執行完畢會進行清理會話數據。

 

咱們經過Spring Web MVC的源代碼驗證一下吧,此處咱們分析的是Spring3.1的RequestMappingHandlerAdapter,讀者能夠自行驗證Spring3.0的AnnotationMethodHandlerAdapter,流程同樣:

一、RequestMappingHandlerAdapter.invokeHandlerMethod

Java代碼   收藏代碼
  1. //一、RequestMappingHandlerAdapter首先調用ModelFactory的initModel方法準備模型數據:  
  2. modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);  
  3. //二、調用@RequestMapping註解的功能處理方法  
  4. requestMappingMethod.invokeAndHandle(webRequest, mavContainer);  
  5. //三、更新/合併模型數據  
  6. modelFactory.updateModel(webRequest, mavContainer);   

二、ModelFactory.initModel

Java代碼   收藏代碼
  1. Map<String, ?> attributesInSession = this.sessionAttributesHandler.retrieveAttributes(request);  
  2. //1.一、將與@SessionAttributes註解相關的會話對象放入模型數據中  
  3. mavContainer.mergeAttributes(attributesInSession);  
  4. //1.二、調用@ModelAttribute方法添加表單引用對象  
  5. invokeModelAttributeMethods(request, mavContainer);  
  6. //1.三、驗證模型數據中是否包含@SessionAttributes註解相關的會話對象,不包含拋出異常  
  7. for (String name : findSessionAttributeArguments(handlerMethod)) {  
  8.     if (!mavContainer.containsAttribute(name)) {  
  9.         //1.四、此處防止在@ModelAttribute註解方法又添加了會話對象  
  10.         //如在@ModelAttribute註解方法調用session.setAttribute("user", new UserModel());  
  11.         Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);  
  12.         if (value == null) {  
  13.             throw new HttpSessionRequiredException("Expected session attribute '" + name + "'");  
  14.         }  
  15.         mavContainer.addAttribute(name, value);  
  16. }   

三、ModelFactory.invokeModelAttributeMethods

Java代碼   收藏代碼
  1. for (InvocableHandlerMethod attrMethod : this.attributeMethods) {  
  2.     String modelName = attrMethod.getMethodAnnotation(ModelAttribute.class).value();   
  3.     //1.2.一、若是模型數據中包含同名數據則再也不添加  
  4.     if (mavContainer.containsAttribute(modelName)) {  
  5.         continue;  
  6.     }  
  7.     //1.2.二、調用@ModelAttribute註解方法並將返回值添加到模型數據中,此處省略實現代碼  
  8. }   

(四、requestMappingMethod.invokeAndHandle 調用功能處理方法,此處省略

五、ModelFactory.updateMode 更新模型數據

Java代碼   收藏代碼
  1. //3.一、若是會話被標識爲完成,此時從會話中清除@SessionAttributes註解相關的會話對象  
  2. if (mavContainer.getSessionStatus().isComplete()){   
  3.     this.sessionAttributesHandler.cleanupAttributes(request);  
  4. }  
  5. //3.二、若是會話沒有完成,將模型數據中的@SessionAttributes註解相關的對象添加到會話中  
  6. else {  
  7.     this.sessionAttributesHandler.storeAttributes(request, mavContainer.getModel());  
  8. }  
  9. //省略部分代碼   

到此@SessionAtrribute介紹完畢,測試代碼在cn.javass.chapter6.web.controller.paramtype.SessionAttributeController中。

 

另外cn.javass.chapter6.web.controller.paramtype.WizardFormController是一個相似於【4.十一、AbstractWizardFormController】中介紹的多步驟表單實現,此處再也不貼代碼,多步驟提交表單須要考慮會話超時問題,這種方式可能對用戶不太友好,咱們能夠採起隱藏表單(即當前步驟將其餘步驟的表單隱藏)或表單數據存數據庫(每步驟更新下數據庫數據)等方案解決。

6.6.八、@Value綁定SpEL表示式

@Value用於將一個SpEL表達式結果映射到到功能處理方法的參數上。

Java代碼   收藏代碼
  1. public String test(@Value("#{systemProperties['java.vm.version']}") String jvmVersion)  

到此數據綁定咱們就介紹完了,對於沒有介紹的方法參數和註解(包括自定義註解)在後續章節進行介紹。接下來咱們學習下數據類型轉換吧。

相關文章
相關標籤/搜索