領(lǐng)略Spring 3.x時(shí)代的Spring MVC
鼎鼎大名的Spring框架3.0版在12月5日由其作者之一——Juergen Hoeller先生在博客里宣告問世,并命為里程碑版,給Spring粉絲們帶來了震撼的快感。筆者即開“快車”拉了兩個(gè)包回來,遺憾的是參考文檔至今還沒有出來(僅有API文檔),這為學(xué)習(xí)Spring 3.0帶來了非常大的困難,但沒有阻擋筆者對(duì)新產(chǎn)品的興趣。
Spring之父Rod Johnson先生早在2003年就預(yù)言EJB將死(觀點(diǎn)頗具爭(zhēng)議),攻擊EJB之臃腫是在虐待程序員。然而EJB 3.0出來后幾乎宣判Spring死刑,但自2.0版以后Spring火爆程度已經(jīng)超過EJB,兩者的爭(zhēng)斗至今仍不停息,這也是Spring 3.0連文檔還沒有整理出來就匆匆推出的原因。當(dāng)然,Spring與EJB有很多各自獨(dú)特優(yōu)勢(shì)之處,例如EJB的分布式運(yùn)算、標(biāo)準(zhǔn)規(guī)范,Spring的IoC、AOP切面編程、偶合集成、MVC等等,取各自之長(zhǎng)在企業(yè)中應(yīng)用如虎添翼。Spring目前已經(jīng)加入了J2EE規(guī)范,J2EE世界將更加精彩......
或許是用膩了Struts1那死板的WEB框架,才對(duì)Spring MVC愛不釋手,尤其是2.5版本以后,支持全注解配置方式,已經(jīng)使很久沒有再寫過xml文件了。
3.0版是完全兼容2.5,因此了解2.5版的@MVC則更容易接受。正如Arjen Poutsma小伙子在他的博客里說的那樣,3.0時(shí)代將集中致力于表述性狀態(tài)轉(zhuǎn)移(REST,希望我沒有翻譯錯(cuò),金山詞霸翻譯為“休息”)的網(wǎng)絡(luò)服務(wù)和更容易的網(wǎng)絡(luò)編程。的確增加了更多的控制器類型,并增強(qiáng)了SOAP/WSDL/WS這些基于分布式體系結(jié)構(gòu)。
先回憶下2.5注解方式的@MVC,來一個(gè)示例:
- @Controller
- public class ArticleController{
- @RequestMapping("/articleView")
- public String getArticle(@RequestParam("id") String id, HttpServletRequest request){
- request.setAttribute("article", service.find(Article.class, id));
- return "articleView";
- }
- }
ArticleController沒有實(shí)現(xiàn)任何接口,是一個(gè)最普通不過的pojo,如果瀏覽器來了articleView.do?id=xxx這個(gè)請(qǐng)求,Spring會(huì)找到getArticle()這個(gè)方法,該方法第一個(gè)參數(shù)綁定到了URL上的請(qǐng)求參數(shù),第二個(gè)是J2EE標(biāo)準(zhǔn)的request對(duì)象(可見Spring MVC是非侵入式的,不像變態(tài)的Struts2),事實(shí)上還可以給定HttpServletResponse,ModelMap,甚至自己的類型,Spring都會(huì)為你將值傳入進(jìn)來。通過一個(gè)邏輯層service組件根據(jù)id參數(shù)值去底層查找Article對(duì)象,并放入request作用域中,最后返回的是面頁視圖名,這個(gè)例子中是返回到articleView.jsp中。
上例再變通下:
- @Controller
- public class ArticleController{
- @RequestMapping("/articleView_*")
- public String getArticle(HttpServletRequest request){
- String id = StringUtil.getParam(request.getRequestURI(),"articleView_*");
- request.setAttribute("article", service.find(Article.class, id));
- return "articleView";
- }
- }
對(duì)于articleView_aaa.do,articleView_bbbb.do,articleView_c5h8j2.do,articleView_xxx.do,這樣的請(qǐng)求都會(huì)由getArticle()這個(gè)方法來應(yīng)付,是不是很有意思?
Spring 3.0增加了一個(gè)@ PathVariable注解來支持可變的請(qǐng)求路徑,將上面的代碼在3.0版中再變通下:
- @Controller
- public class ArticleController{
- @RequestMapping("/articleView/${id}") //可以接受articleView/aaa.do,articleView/xxx.do...
- public String getArticle(@PathVariable String id, HttpServletRequest request){
- request.setAttribute("article", service.find(Article.class, id));
- return "articleView";
- }
- }
再變得復(fù)雜些:
- @Controller
- public class ArticleController{
- @RequestMapping("/articleList/${pageSize}/channel/*/category/${id}")
- public String getArticles((@PathVariable Integer pageSize, @PathVariable int id, HttpServletRequest request){
- Integer channelId = StringUtil.getParam(request.getRequestURI(),"channel/*/");
- request.setAttribute("articles", service.findScroll(Article.class, pageSize,50,"channel=? and category=?",new Object[]{channelId,id}));
- return "articleList";
- }
- }
它已經(jīng)靈活到URL地址完全可以自己隨意編制。
根據(jù)內(nèi)容協(xié)商制的視圖解析機(jī)制:
2.5版是由@MVC控制器來決定視圖解析器,3.0版將變得更加靈活,似乎可以通過擴(kuò)展名來轉(zhuǎn)到不同的解析器中,例如請(qǐng)求一個(gè).pdf文件將是如何效果呢?3.0版都會(huì)帶來不可思議的模式。
HTTP方法的轉(zhuǎn)換:
先看前臺(tái)頁面一段Html代碼
- <form:form method="delete">
- <p class="submit"><input type="submit" value="Delete Pet"/></p>
- </form:form>
HTTP規(guī)范中form表單只有兩種方法——POST和GET,而3.0做了一個(gè)過濾器,可以轉(zhuǎn)換這些方法至四種——GET, PUT, POST, 和 DELETE。控制器接受請(qǐng)求:
- @Controller("/deleteArticle")
- public class ArticleController{
- @RequestMapping(method = RequestMethod.DELETE)
- public String deleteArticle(@PathVariable String id, HttpServletRequest request){
- service.delete(Article.class, id);
- return "message";
- }
- }
3.0版僅在MVC子集中就增加了很多新特性,如果在IoC、AOP等等其它子集所有的變革,絕對(duì)可以稱得上Srping創(chuàng)始人所述的里程碑版本。3.0版使用的注解列表如下:
- • @Autowired
- • @Component
- • @Controller
- • @InitBinder
- • @ManagedAttribute
- • @ManagedOperation
- • @ManagedOperationParameters
- • @ManagedOperationParameter
- • @ManagedResource
- • @PathVariable
- • @PostConstruct
- • @PreDestroy
- • @Repository
- • @RequestMapping
- • @Required
- • @Resource
- • @Service
- • @Transactional
目前Spring 3版本已經(jīng)到了M2,應(yīng)該是M3完成后將推出最終正式版本,我想很快會(huì)來臨,按照Spring的創(chuàng)始人羅德.約翰遜的預(yù)言,未來J2EE應(yīng)用中Spring+Tomcat將占主導(dǎo)地位,是否引起爭(zhēng)議,筆者不敢點(diǎn)評(píng),不過Oracle收購Sun后,Java社區(qū)將是如何,還無從知曉,似乎羅德.約翰遜對(duì)這宗收購案也有些緊張,因?yàn)镺racle不像Sun的第一個(gè)談判者IBM那樣有過開放技術(shù)的先例(可以回憶下IBM早期的主板總線開放掀起的兼容機(jī)潮至今波濤不熄)。目前國(guó)內(nèi)對(duì)新東西消化尚慢,我到圖書城看了下,Spring 2.5的資料都很難找到。且很多企業(yè)都是抱著Struts1.x在做開發(fā),盡管筆者這樣說會(huì)引來很多爭(zhēng)議,但Struts1時(shí)代的滅亡只是時(shí)間問題。Struts2雖然改進(jìn)了很多,依筆者看,與Spring MVC相比仍有諸多的不足,尤其看不慣那種變態(tài)的侵入模式,看看它把HttpServletRequest、HttpSession、HttpServletResponse等servlet標(biāo)準(zhǔn)組件干成什么樣?開源時(shí)代,至少我不愿意接受那種變態(tài)的潛規(guī)則。
筆者早先常用Struts1.x框架,它搭配了一套自己的ActionForm,使得編程工作量增加,雖然可以變通使用自己的Pojo,但對(duì)于沒有掌握J(rèn)2EE底層工具類(BeanUtil)的開發(fā)人員來說,其類型匹配是非常復(fù)雜的事。事實(shí)上Spring MVC早在1.x版本就完全使用自己的pojo來對(duì)應(yīng)表單的填充,配上屬性編輯器,可以解決類型轉(zhuǎn)換問題,完全實(shí)現(xiàn)領(lǐng)域模型驅(qū)動(dòng)的設(shè)計(jì)模式。由于MVC層的控制器也是Spring容器的Bean而已,因此對(duì)整個(gè)項(xiàng)目的控制、擴(kuò)展變得非常容易。同時(shí)上文也順便點(diǎn)評(píng)了Struts2,可見Spring MVC在各類MVC框架的優(yōu)勢(shì)所在。本身羅德.約翰遜先生是設(shè)計(jì)模式高手,一個(gè)優(yōu)秀的框架給我們帶來的遠(yuǎn)遠(yuǎn)不只是開發(fā)效率,還有更先進(jìn)的開發(fā)模式和理念...
筆者對(duì)Spring框架研究膚淺,待日后了解掌握更多時(shí)會(huì)常在博客中述之。