javascript
使用 Spring 2.5 基于注解驱动的 Spring MVC(二)
我們?cè)?② 處添加了一個(gè) ModelMap 屬性,其屬性名為 currUser,而 ① 處通過(guò) @SessionAttributes 注解將 ModelMap 中名為 currUser 的屬性放置到 Session 中,所以我們不但可以在 listBoardTopic() 請(qǐng)求所對(duì)應(yīng)的 JSP 視圖頁(yè)面中通過(guò) request.getAttribute(“currUser”) 和 session.getAttribute(“currUser”) 獲取 user 對(duì)象,還可以在下一個(gè)請(qǐng)求所對(duì)應(yīng)的 JSP 視圖頁(yè)面中通過(guò) session.getAttribute(“currUser”) 或 ModelMap#get(“currUser”) 訪問(wèn)到這個(gè)屬性。
這里我們僅將一個(gè) ModelMap 的屬性放入 Session 中,其實(shí) @SessionAttributes 允許指定多個(gè)屬性。你可以通過(guò)字符串?dāng)?shù)組的方式指定多個(gè)屬性,如 @SessionAttributes({“attr1”,”attr2”})。此外,@SessionAttributes 還可以通過(guò)屬性類型指定要 session 化的 ModelMap 屬性,如 @SessionAttributes(types = User.class),當(dāng)然也可以指定多個(gè)類,如 @SessionAttributes(types = {User.class,Dept.class}),還可以聯(lián)合使用屬性名和屬性類型指定:@SessionAttributes(types = {User.class,Dept.class},value={“attr1”,”attr2”})。
上面 講述了如何往ModelMap中放置屬性以及如何使ModelMap中的屬性擁有Session域的作用范圍。除了在JSP視圖頁(yè)面中通過(guò)傳統(tǒng)的方法訪問(wèn) ModelMap中的屬性外,讀者朋友可能會(huì)問(wèn):是否可以將ModelMap中的屬性綁定到請(qǐng)求處理方法的入?yún)⒅心?#xff1f;答案是肯定的。Spring為此提供 了一個(gè)@ModelAttribute的注解,下面是使用@ModelAttribute注解的例子:
清單 11. 使模型對(duì)象的特定屬性具有 Session 范圍的作用域
| package com.baobaotao.web;import com.baobaotao.service.BbtForumService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.bind.annotation.ModelAttribute;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession;@Controller @RequestMapping("/bbtForum.do") @SessionAttributes("currUser") //①讓ModelMap的currUser屬性擁有session級(jí)作用域 public class BbtForumController {@Autowired private BbtForumService bbtForumService;@RequestMapping(params = "method=listBoardTopic")public String listBoardTopic(@RequestParam("id")int topicId, User user, ModelMap model) {bbtForumService.getBoardTopics(topicId);System.out.println("topicId:" + topicId);System.out.println("user:" + user);model.addAttribute("currUser",user); //②向ModelMap中添加一個(gè)屬性return "listTopic";}@RequestMapping(params = "method=listAllBoard")//③將ModelMap中的 public String listAllBoard(@ModelAttribute("currUser") User user) { //currUser屬性綁定到user入?yún)⒅?。bbtForumService.getAllBoard();System.out.println("user:"+user);return "listBoard";} } |
?
在 ② 處,我們向 ModelMap 中添加一個(gè)名為 currUser 的屬性,而 ① 外的注解使這個(gè) currUser 屬性擁有了 session 級(jí)的作用域。所以,我們可以在 ③ 處通過(guò) @ModelAttribute 注解將 ModelMap 中的 currUser 屬性綁定以請(qǐng)求處理方法的 user 入?yún)⒅小?/p>
所以當(dāng)我們先調(diào)用以下 URL 請(qǐng)求: http://localhost/bbtForum.do?method=listBoardTopic&id=1&userName=tom&dept.deptId=12
以執(zhí)行l(wèi)istBoardTopic()請(qǐng)求處理方法,然后再訪問(wèn)以下URL: http://localhost/sample/bbtForum.do?method=listAllBoard
你將可以看到 listAllBoard() 的 user 入?yún)⒁呀?jīng)成功綁定到 listBoardTopic() 中注冊(cè)的 session 級(jí)的 currUser 屬性上了。
?
|
請(qǐng)求處理方法的簽名規(guī)約
方法入?yún)?/font>
我們知道標(biāo)注了 @RequestMapping 注解的 Controller 方法就成為了請(qǐng)求處理方法,Spring MVC 允許極其靈活的請(qǐng)求處理方法簽名方式。對(duì)于方法入?yún)?lái)說(shuō),它允許多種類型的入?yún)?#xff0c;通過(guò)下表進(jìn)行說(shuō)明:
| Java 基本數(shù)據(jù)類型和 String | 默認(rèn)情況下將按名稱匹配的方式綁定到 URL 參數(shù)上,可以通過(guò) @RequestParam 注解改變默認(rèn)的綁定規(guī)則 |
| request/response/session | 既可以是 Servlet API 的也可以是 Portlet API 對(duì)應(yīng)的對(duì)象,Spring 會(huì)將它們綁定到 Servlet 和 Portlet 容器的相應(yīng)對(duì)象上 |
| org.springframework.web.context.request.WebRequest | 內(nèi)部包含了 request 對(duì)象 |
| java.util.Locale | 綁定到 request 對(duì)應(yīng)的 Locale 對(duì)象上 |
| java.io.InputStream/java.io.Reader | 可以借此訪問(wèn) request 的內(nèi)容 |
| java.io.OutputStream / java.io.Writer | 可以借此操作 response 的內(nèi)容 |
| 任何標(biāo)注了 @RequestParam 注解的入?yún)?/td> | 被標(biāo)注 @RequestParam 注解的入?yún)⒔壎ǖ教囟ǖ?request 參數(shù)上。 |
| java.util.Map / org.springframework.ui.ModelMap | 它綁定 Spring MVC 框架中每個(gè)請(qǐng)求所創(chuàng)建的潛在的模型對(duì)象,它們可以被 Web 視圖對(duì)象訪問(wèn)(如 JSP) |
| 命令/表單對(duì)象(注:一般稱綁定使用 HTTP GET 發(fā)送的 URL 參數(shù)的對(duì)象為命令對(duì)象,而稱綁定使用 HTTP POST 發(fā)送的 URL 參數(shù)的對(duì)象為表單對(duì)象) | 它們的屬性將以名稱匹配的規(guī)則綁定到 URL 參數(shù)上,同時(shí)完成類型的轉(zhuǎn)換。而類型轉(zhuǎn)換的規(guī)則可以通過(guò) @InitBinder 注解或通過(guò) HandlerAdapter 的配置進(jìn)行調(diào)整 |
| org.springframework.validation.Errors / org.springframework.validation.BindingResult | 為屬性列表中的命令/表單對(duì)象的校驗(yàn)結(jié)果,注意檢驗(yàn)結(jié)果參數(shù)必須緊跟在命令/表單對(duì)象的后面 |
| rg.springframework.web.bind.support.SessionStatus | 可以通過(guò)該類型 status 對(duì)象顯式結(jié)束表單的處理,這相當(dāng)于觸發(fā) session 清除其中的通過(guò) @SessionAttributes 定義的屬性 |
Spring MVC 框架的易用之處在于,你可以按任意順序定義請(qǐng)求處理方法的入?yún)?#xff08;除了 Errors 和 BindingResult 必須緊跟在命令對(duì)象/表單參數(shù)后面以外),Spring MVC 會(huì)根據(jù)反射機(jī)制自動(dòng)將對(duì)應(yīng)的對(duì)象通過(guò)入?yún)鬟f給請(qǐng)求處理方法。這種機(jī)制讓開發(fā)者完全可以不依賴 Servlet API 開發(fā)控制層的程序,當(dāng)請(qǐng)求處理方法需要特定的對(duì)象時(shí),僅僅需要在參數(shù)列表中聲明入?yún)⒓纯?#xff0c;不需要考慮如何獲取這些對(duì)象,Spring MVC 框架就象一個(gè)大管家一樣“不辭辛苦”地為我們準(zhǔn)備好了所需的一切。下面演示一下使用 SessionStatus 的例子:
清單 12. 使用 SessionStatus 控制 Session 級(jí)別的模型屬性
| @RequestMapping(method = RequestMethod.POST) public String processSubmit(@ModelAttribute Owner owner, BindingResult result, SessionStatus status) {//<——①new OwnerValidator().validate(owner, result);if (result.hasErrors()) {return "ownerForm";}else {this.clinic.storeOwner(owner);status.setComplete();//<——②return "redirect:owner.do?ownerId=" + owner.getId();} } |
?
processSubmit() 方法中的 owner 表單對(duì)象將綁定到 ModelMap 的“owner”屬性中,result 參數(shù)用于存放檢驗(yàn) owner 結(jié)果的對(duì)象,而 status 用于控制表單處理的狀態(tài)。在 ② 處,我們通過(guò)調(diào)用 status.setComplete() 方法,該 Controller 所有放在 session 級(jí)別的模型屬性數(shù)據(jù)將從 session 中清空。
方法返回參數(shù)
在低版本的 Spring MVC 中,請(qǐng)求處理方法的返回值類型都必須是 ModelAndView。而在 Spring 2.5 中,你擁有多種靈活的選擇。通過(guò)下表進(jìn)行說(shuō)明:
| void | 此時(shí)邏輯視圖名由請(qǐng)求處理方法對(duì)應(yīng)的 URL 確定,如以下的方法:
對(duì)應(yīng)的邏輯視圖名為“welcome” | |
| String | 此時(shí)邏輯視圖名為返回的字符,如以下的方法:
對(duì)應(yīng)的邏輯視圖名為“ownerForm” | |
| org.springframework.ui.ModelMap | 和返回類型為 void 一樣,邏輯視圖名取決于對(duì)應(yīng)請(qǐng)求的 URL,如下面的例子:
對(duì)應(yīng)的邏輯視圖名為“vets”,返回的 ModelMap 將被作為請(qǐng)求對(duì)應(yīng)的模型對(duì)象,可以在 JSP 視圖頁(yè)面中訪問(wèn)到。 | |
| ModelAndView | 當(dāng)然還可以是傳統(tǒng)的 ModelAndView。 |
應(yīng)該說(shuō)使用 String 作為請(qǐng)求處理方法的返回值類型是比較通用的方法,這樣返回的邏輯視圖名不會(huì)和請(qǐng)求 URL 綁定,具有很大的靈活性,而模型數(shù)據(jù)又可以通過(guò) ModelMap 控制。當(dāng)然直接使用傳統(tǒng)的 ModelAndView 也不失為一個(gè)好的選擇。
?
|
注冊(cè)自己的屬性編輯器
Spring MVC 有一套常用的屬性編輯器,這包括基本數(shù)據(jù)類型及其包裹類的屬性編輯器、String 屬性編輯器、JavaBean 的屬性編輯器等。但有時(shí)我們還需要向 Spring MVC 框架注冊(cè)一些自定義的屬性編輯器,如特定時(shí)間格式的屬性編輯器就是其中一例。
Spring MVC 允許向整個(gè) Spring 框架注冊(cè)屬性編輯器,它們對(duì)所有 Controller 都有影響。當(dāng)然 Spring MVC 也允許僅向某個(gè) Controller 注冊(cè)屬性編輯器,對(duì)其它的 Controller 沒有影響。前者可以通過(guò) AnnotationMethodHandlerAdapter 的配置做到,而后者則可以通過(guò) @InitBinder 注解實(shí)現(xiàn)。
下面先看向整個(gè) Spring MVC 框架注冊(cè)的自定義編輯器:
清單 13. 注冊(cè)框架級(jí)的自定義屬性編輯器
| >bean class="org.springframework.web.servlet.mvc.annotation. AnnotationMethodHandlerAdapter"<>property name="webBindingInitializer"<>bean class="com.baobaotao.web.MyBindingInitializer"/<>/property< >/bean< |
?
MyBindingInitializer 實(shí)現(xiàn)了 WebBindingInitializer 接口,在接口方法中通過(guò) binder 注冊(cè)多個(gè)自定義的屬性編輯器,其代碼如下所示:
清單 14.自定義屬性編輯器
| package org.springframework.samples.petclinic.web;import java.text.SimpleDateFormat; import java.util.Date;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.propertyeditors.CustomDateEditor; import org.springframework.beans.propertyeditors.StringTrimmerEditor; import org.springframework.samples.petclinic.Clinic; import org.springframework.samples.petclinic.PetType; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.support.WebBindingInitializer; import org.springframework.web.context.request.WebRequest;public class MyBindingInitializer implements WebBindingInitializer {public void initBinder(WebDataBinder binder, WebRequest request) {SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");dateFormat.setLenient(false);binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));binder.registerCustomEditor(String.class, new StringTrimmerEditor(false));} } |
?
如果希望某個(gè)屬性編輯器僅作用于特定的 Controller,可以在 Controller 中定義一個(gè)標(biāo)注 @InitBinder 注解的方法,可以在該方法中向 Controller 了注冊(cè)若干個(gè)屬性編輯器,來(lái)看下面的代碼:
清單 15. 注冊(cè) Controller 級(jí)的自定義屬性編輯器
| @Controller public class MyFormController {@InitBinderpublic void initBinder(WebDataBinder binder) {SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");dateFormat.setLenient(false);binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));}… } |
?
注意被標(biāo)注 @InitBinder 注解的方法必須擁有一個(gè) WebDataBinder 類型的入?yún)?#xff0c;以便 Spring MVC 框架將注冊(cè)屬性編輯器的 WebDataBinder 對(duì)象傳遞進(jìn)來(lái)。
?
|
如何準(zhǔn)備數(shù)據(jù)
在 編寫 Controller 時(shí),常常需要在真正進(jìn)入請(qǐng)求處理方法前準(zhǔn)備一些數(shù)據(jù),以便請(qǐng)求處理或視圖渲染時(shí)使用。在傳統(tǒng)的 SimpleFormController 里,是通過(guò)復(fù)寫其 referenceData() 方法來(lái)準(zhǔn)備引用數(shù)據(jù)的。在 Spring 2.5 時(shí),可以將任何一個(gè)擁有返回值的方法標(biāo)注上 @ModelAttribute,使其返回值將會(huì)進(jìn)入到模型對(duì)象的屬性列表中。來(lái)看下面的例子:
清單 16. 定義為處理請(qǐng)求準(zhǔn)備數(shù)據(jù)的方法
| package com.baobaotao.web;import com.baobaotao.service.BbtForumService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.SessionAttributes;import java.util.ArrayList; import java.util.List; import java.util.Set;@Controller @RequestMapping("/bbtForum.do") public class BbtForumController {@Autowiredprivate BbtForumService bbtForumService;@ModelAttribute("items")//<——①向模型對(duì)象中添加一個(gè)名為items的屬性public List<String> populateItems() {List<String> lists = new ArrayList<String>();lists.add("item1");lists.add("item2");return lists;}@RequestMapping(params = "method=listAllBoard")public String listAllBoard(@ModelAttribute("currUser")User user, ModelMap model) {bbtForumService.getAllBoard();//<——②在此訪問(wèn)模型中的items屬性System.out.println("model.items:" + ((List<String>)model.get("items")).size());return "listBoard";} } |
?
在 ① 處,通過(guò)使用 @ModelAttribute 注解,populateItem() 方法將在任何請(qǐng)求處理方法執(zhí)行前調(diào)用,Spring MVC 會(huì)將該方法返回值以“items”為名放入到隱含的模型對(duì)象屬性列表中。
所 以在 ② 處,我們就可以通過(guò) ModelMap 入?yún)⒃L問(wèn)到 items 屬性,當(dāng)執(zhí)行 listAllBoard() 請(qǐng)求處理方法時(shí),② 處將在控制臺(tái)打印出“model.items:2”的信息。當(dāng)然我們也可以在請(qǐng)求的視圖中訪問(wèn)到模型對(duì)象中的 items 屬性。
?
|
小結(jié)
Spring 2.5 對(duì) Spring MVC 進(jìn)行了很大增強(qiáng),現(xiàn)在我們幾乎完全可以使用基于注解的 Spring MVC 完全替換掉原來(lái)基于接口 Spring MVC 程序?;谧⒔獾?Spring MVC 比之于基于接口的 Spring MVC 擁有以下幾點(diǎn)好處:
- 方便請(qǐng)求和控制器的映射;
- 方便請(qǐng)求處理方法入?yún)⒔壎║RL參數(shù);
- Controller 不必繼承任何接口,它僅是一個(gè)簡(jiǎn)單的 POJO。
但 是基于注解的 Spring MVC 并不完美,還存在優(yōu)化的空間,因?yàn)樵谀承┡渲蒙纤然?XML 的配置更繁瑣。比如對(duì)于處理多個(gè)請(qǐng)求的 Controller 來(lái)說(shuō),假設(shè)我們使用一個(gè) URL 參數(shù)指定調(diào)用的處理方法(如 xxx.do?method=listBoardTopic),當(dāng)使用注解時(shí),每個(gè)請(qǐng)求處理方法都必須使用 @RequestMapping() 注解指定對(duì)應(yīng)的 URL 參數(shù)(如 @RequestMapping(params = "method=listBoardTopic")),而在 XML 配置中我們僅需要配置一個(gè) ParameterMethodNameResolver 就可以了。
轉(zhuǎn)載于:https://www.cnblogs.com/sunwei2012/archive/2010/05/11/1732521.html
總結(jié)
以上是生活随笔為你收集整理的使用 Spring 2.5 基于注解驱动的 Spring MVC(二)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: A7VU坦克介绍
- 下一篇: JavaScript学习笔记(十)——学