(本故事除了部分點明道姓并具有故事詳細(xì)發(fā)生的具體時間點地等部分情節(jié)以外,其它內(nèi)容純屬虛構(gòu),若有雷同,純屬巧合。)
?
?
?
主演: EasyJWeb、中庸之道、Spring。
配角:Struts、webwork、Velocity、JSP、hibernate、J2EE各層程序員。
?
在前面的兩個例子中,主要給大家介紹了Spring的黃金庸俗組合以及華麗高雅組合來開發(fā)B/S應(yīng)用。在我們用到的幾個“輪子”當(dāng)中,由于hibernate是當(dāng)今公認(rèn)最好的ORM系統(tǒng),因此爭議性不大。然而,Struts就未必了,Struts也是市場上使用得多的框架(盡管有那么多技術(shù)牛人說他的不是),然而很多人對Struts很是看不起眼,總是認(rèn)為沒有華麗的IOC、無法寫出優(yōu)雅、漂亮的代碼,一些配置及FormBean搞起來很麻煩,因此,webwork或Tapestry等比他強很多。在網(wǎng)上,有時候甚至?xí)吹接行┤藢truts學(xué)習(xí)者發(fā)出藐視的目光。
Webwork就真強了嗎?市場才是王道吧,我不禁想問,不就引入了一些IOC、攔截器功能,并與一些常用的組件集成擺了。存在即合理,所以各家粉絲沒必要為這個PK。正好,現(xiàn)在struts與webwork開發(fā)團(tuán)隊已經(jīng)合并了(為什么合并?當(dāng)然是為了對付共同的敵人啊),可以不用PK了。但Tapestry、JSF、Spring MVC的粉絲又該怎么辦?呵呵,是不是很有意思,打著不發(fā)明輪子大旗,發(fā)明了一個又一個的漂亮輪子給我們,讓我們這些第三世界國家的粗人誰都舍不得丟下,一不小心就犯了選擇恐懼癥。看來作為一名程序員,身體以及精神都得健壯啊,要不,誰能折騰得起!這不,客戶正在催命似的要看項目進(jìn)展情況,而我們連選擇什么框架都還沒定呢!
有點暈了吧,還有更暈的。今天筆者不打算用大家熟悉的框架作示例,所以就不用管各家粉絲怎么PK了(看他們PK也郁悶,還得翻譯一次,有時一不小心還會跑調(diào)!)。本文將用一個你可能從沒見過的國產(chǎn)開源框架來替換掉上例中的Struts及webwork,這個框架就是由國內(nèi)EasyJF開源團(tuán)隊所開發(fā)的EasyJWeb框架。
提到EasyJWeb,我想前面提到的各種MVC框架的粉絲一定會聯(lián)合起來,組成一個要技術(shù)有技術(shù)、要資歷有資歷的超強陣容來PK了。因為EasyJWeb是國產(chǎn)的,而其它的都是進(jìn)口原裝的,再加上EasyJWeb測試版本當(dāng)前才發(fā)到0.5版,有很多地方都還不成熟,幾個開發(fā)者技術(shù)水平又不怎么樣,寫的東西也是那么平庸、樸實,一不小心就被抓住小辮子。而EasyJWeb開發(fā)團(tuán)隊又急于想把這個框架介紹給大家,讓大家?guī)椭峤ㄗh、完善。
既然還不完善,那我為什么要用EasyJWeb而不選擇其他呢?原因跟大家跟大家喜歡其它的框架也一樣,因為本人就是EasyJWeb的超級粉絲,我不支持他支持誰。說得更直白一點,這好比俺村里大眼睛、長頭發(fā)的小芳姑娘,不管從皮膚、外表、性格、習(xí)慣等各方面都比美國的小甜甜布蘭妮更適合做偶老婆的道理一樣。況且筆者大大小小框架也用了不少,自我感覺還是EasyJWeb使起來最順手,代碼少容易搞清楚框架的工作原理不說,提供的那些功能還都是我們項目中經(jīng)常所需要的。
可笑也可悲的是,國內(nèi)有的同行及媒體平臺一看到有關(guān)EasyJWeb字眼,一看是國產(chǎn)的,好歹不分盡然就說是打廣告,寫的文章也不讓登。偶滴神啊,要不是在大街上看到滿街的黃皮夫、黑眼睛的路人甲乙丙丁,我還真以為自己身處西方資本主義國家了,對俺們社會主義國家搞的東西這么抵制。同樣是開源項目,struts的心得體會你可以發(fā),為什么關(guān)于EasyJWeb的心得體會你就不讓發(fā)?(小樣,誰說不給你發(fā)了?要發(fā)可以,拿金幣來!)何苦呢,現(xiàn)在都WTO那么多年了。你整天翻譯、搜集那些亂七八糟的國外小項目的動態(tài)啊什么的,累不累啊。不知情者還認(rèn)為你是資本主義國家設(shè)在國內(nèi)的宣傳喉舌呢。
當(dāng)然,這里說的只是非常少的個別特例,大多數(shù)前輩及平臺還是很支持我們的。若沒有國內(nèi)眾多前輩的鼓勵、指點以及像“Java研究組織”類似的眾多專業(yè)技術(shù)平臺的支持,恐怕EasyJWeb早就死翹翹,今天大家也就看不到這篇文章了。
?
暈,八卦有點遠(yuǎn)了,下面進(jìn)入正題吧。今天筆者探討的一個重點就是如何在不動其它各層的情況下,替換掉上兩篇“添刪改查”示例中的MVC層。這也是我理解的多層結(jié)構(gòu)中的一門藝術(shù),這也是大家聽到的組件或者構(gòu)件的一個妙處。前輩們不都說嗎?配置時代的編程,做軟件就像搭積木,幾個框框、架架、部件搭在一起,一個龐大的系統(tǒng)就被我們堆起來了。假如其中有些部件由于各種原因需要換,隨便換就是了,其它的部分都不用動。J2EE的靈活、可維護(hù)性都體現(xiàn)在這些地方,由于Java的靈活,因此他有時候會帶給我們類似于藝術(shù)工作者所特有的那種飄飄然的感覺,這也是筆者放棄微軟的.Net,投入Java懷抱的原因。
由于本示例使用的是EasyJWeb,因此其它MVC框架的粉絲可以略過后面的技術(shù)細(xì)節(jié)內(nèi)容,直接跳到后面有關(guān)“中庸之道”的論述中,否則不小心你也會被EasyJWeb迷住。
下面請看操作步驟,大家可以對照前兩篇示例中的MVC部分的內(nèi)容來看:
1、?寫處理用戶請求的Action。
跟Struts類似,EasyJWeb有一個Action,但這個Action因為使用的接口方式,不需要繼承于框架特定的Action,只需要實現(xiàn)IWebAction即可,本例中,為了方便我們的Action直接繼承EasyJWeb Tools中提供給我們的一個Action基類(你也可以不用繼承他),下面是UserManageAction.java的代碼。
package com.easyjweb.action;
import java.util.ArrayList;
import java.util.Collection;
import com.easyjf.util.CommUtil;
import com.easyjf.web.ActionContext;
import com.easyjf.web.Globals;
import com.easyjf.web.Module;
import com.easyjf.web.Page;
import com.easyjf.web.WebForm;
import com.easyjf.web.tools.AbstractCmdAction;
import com.easyjf.web.tools.IPageList;
import com.easyjf.web.tools.ListQuery;
import com.easyjf.web.tools.PageList;
import com.easyjf.example.business.IUser;
import com.easyjf.example.business.IUserService;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
public class UserManageAction extends AbstractCmdAction {
?private IUserService userService;?
?public IUserService getUserService() {
??return userService;
?}
?public void setUserService(IUserService userService)
?{
??this.userService=userService;
?}
?public Object doBefore(WebForm form, Module? module) {
??WebApplicationContext wac =WebApplicationContextUtils.getRequiredWebApplicationContext(ActionContext.getContext().getServletContext());
??this.userService = (IUserService) wac.getBean("userService");
??return null;
?}
?public Page doInit(WebForm form, Module module) {?
??return doQuery(form,module);
?}?
?public Page doNew(WebForm form, Module module) {?
??return new Page("edit","/userEdit.html",Globals.PAGE_TEMPLATE_TYPE);
?}?
?public Page doAdd(WebForm form, Module module) {
??Page forward=null;
??IUser? obj=(IUser)form2Obj(form);????????
???? if(userService.save(obj))
???? {
???? ?form.addResult("msg","數(shù)據(jù)添加成功!");
???? ?forward=doQuery(form,module);
???? }
???? else
???? {
???? ?form.addResult("msg","數(shù)據(jù)添加失敗");?
???? ?forward=new Page("edit","/userEdit.html",Globals.PAGE_TEMPLATE_TYPE);
???? }????
??return forward;
?}
?public Page doUpdate(WebForm form, Module module) {??
??Page forward=null;
??IUser? obj=(IUser)form2Obj(form);????
???? if(userService.update(obj))
???? {
???? ?form.addResult("msg","數(shù)據(jù)修改成功!");
???? ?forward=doQuery(form,module);
???? }
???? else
???? {
???? ?form.addResult("msg","數(shù)據(jù)修改失敗");?
???? ?forward=new Page("edit","/userEdit.html",Globals.PAGE_TEMPLATE_TYPE);
???? }????
??return forward;
?}
?public Page doEdit(WebForm form, Module module) {?
??Page forward=null;
??IUser? obj=(IUser)form2Obj(form);
???? if(obj!=null)
???? {
???????? form.addPo(obj);
???? ?forward=new Page("edit","/userEdit.html",Globals.PAGE_TEMPLATE_TYPE);
???? }
???? else
???? {
???? ?form.addResult("msg","找不到數(shù)據(jù)!");?
???? ?forward=doQuery(form,module);
???? }????
??return forward;
?}
?public Page doDel(WebForm form, Module module) {??
??IUser? obj=(IUser)form2Obj(form);???
???? if(userService.del(obj))
???? {
???? ?form.addResult("msg","數(shù)據(jù)刪除成功!");???? ?
???? }
???? else
???? {
???? ?form.addResult("msg","數(shù)據(jù)修改失敗");?
???? }????
??return doQuery(form,module);
?}
?public Page doQuery(WebForm form, Module module) {??
??int currentPage=CommUtil.null2Int(form.get("page"));
??int pageSize=CommUtil.null2Int(form.get("pageSize"));
??if(currentPage<1)currentPage=1;
??if(pageSize<1)pageSize=15;
??String scope="1=1";
??Collection paras=new ArrayList();??
??String orderType=CommUtil.null2String(form.get("orderType"));
??String orderField=CommUtil.null2String(form.get("orderField"));??
??String userName=CommUtil.null2String(form.get("queryUserName"));
??String tel=CommUtil.null2String(form.get("queryTel"));????
??if(!userName.equals(""))
??{
???scope+=" and userName like ?";
???paras.add("%"+userName+"%");
??}
??if(!tel.equals(""))
??{
???scope+=" and tel like ?";
???paras.add("%"+tel+"%");
??}??
??if(orderField.equals(""))//默認(rèn)按用戶名排序
??{
??orderField="userName";
??orderType="desc";????
??}?
??if(!orderField.equals(""))
??{
??scope +=" order by "+orderField;
??if(!orderType.equals(""))scope+=" "+orderType;
??}?
??IPageList pList=new PageList(new ListQuery(userService.query(scope,paras)));
??pList.doList(pageSize,currentPage,"","");
??//保存查詢結(jié)果
??CommUtil.saveIPageList2WebForm(pList,form);
??return new Page("list","/userList.html",Globals.PAGE_TEMPLATE_TYPE);
?}
?public Object form2Obj(WebForm form) {
??String cid=(String)form.get("cid");
??IUser user=null;
??if(cid!=null && (!cid.equals("")))user=userService.read(cid);
??if(user==null)user=userService.newUser();
??return form.toPo(user);
?}?
}
?
2、?制作模板頁面
類似于Struts示例中的JSP頁面,只不過這里的模板頁面使用的是Velocity腳本引擎。因此,不在有JSP中的相關(guān)語法,也沒有一些讓人頭暈的自定義標(biāo)簽。所有標(biāo)記集中歸納起來就只有4種用法,大家可以看看筆者在EasyJF開源團(tuán)隊官網(wǎng)上的一篇文章,題為:
《淺析MVC框架中View層的優(yōu)雅設(shè)計及實例》。
模板不再存放在根目錄,而是存放在web-inf\easyjweb目錄,同樣是兩個模板,一個userEdit.html模板是用于顯示用戶錄入表單,另外一個userList.html文件是用戶列表頁面。模板的全部內(nèi)容可以從EasyJF開源團(tuán)隊官方網(wǎng)站下載,本示例中的全部完整代碼中包含了該模板。
?
3、修改web.xml文件即可,其全部內(nèi)容如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>?
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>CharsetFilter</filter-name>
<filter-class>com.easyjf.web.CharsetFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>?
</init-param>
<init-param>
<param-name>ignore</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharsetFilter</filter-name>
<servlet-name>easyjf</servlet-name>
</filter-mapping>?
? <servlet>
??? <servlet-name>easyjf</servlet-name>
??? <servlet-class>com.easyjf.web.ActionServlet</servlet-class>???
? </servlet>
? <servlet-mapping>
??? <servlet-name>easyjf</servlet-name>
??? <url-pattern>*.ejf</url-pattern>??
? </servlet-mapping>
?? <servlet-mapping>
??? <servlet-name>easyjf</servlet-name>
??? <url-pattern>/ejf/*</url-pattern>??
? </servlet-mapping>???
</web-app>
?
配置文件跟前面兩個例子中的差不多,只是多了一些中文過濾處理等內(nèi)容,EasyJWeb已經(jīng)考慮到經(jīng)常遇到的中文問題。
大家可以拿Struts與EasyJWeb對比一下,我們少了兩個步驟,一個是ActionForm Bean的定義,另外一個是配置struts-config.xml文件。其實EasyJWeb也有跟struts-config.xml類似的配置文件easyjf-web.xml,只不過我們這個例子中使用的是默認(rèn)配置而已。
?
完整的示例代碼下載:
?
當(dāng)然,為什么我們能不修改其它的代碼即換掉系統(tǒng)的MVC層,還是歸功于Spring的IOC容器為我們管理了其它層組件。當(dāng)然,這兩三個示例中只使用了Spring最簡單也是最常用的功能。
?
?
看到這里很多人一定會疑問,在前一篇演示webwork應(yīng)用的文章中,webowrk都快被捧上天了,而現(xiàn)在你又來推薦EasyJWeb,這不明擺著忽悠人嗎?EasyJWeb這個輪子跟他們有什么區(qū)別及特色呢?
要回答這個問題,說來有點話長,這得從我們中華民族儒家文化中的核心思想,“中庸之道”說起(中庸之道是本文中的一個主角,請大家鼓掌!)。“中庸者,以其記中和之為用也;庸,用也。孔子之孫子思作之,以昭明圣祖之德也。”-《中庸》鄭玄注;《中庸》中有說:“天命之謂性,率性之謂道,修道之謂教”。怎么樣,很多朋友看不懂是吧?誰叫咱們80后人注重素質(zhì)教育,搞到連老祖輩的文化思想核心都搞不懂。若長此下去,恐怕三、四十年后,咱們的后輩都將會看不懂也聽不懂中文了。
什么是中庸?這里我用通俗點的語言看能不能解釋一下。我認(rèn)識一位大伯,他以前是知識分子,但他因為他的知識而坐了10年牢,于是他把他兒子從小就帶進(jìn)了我們貴州最窮的山區(qū)里面,如今兒子變成了文盲。另外我還聽說有一個人本來住在南極的,但后來他說南極太冷了,他要搬到北極去住,到了北極他才發(fā)現(xiàn)其實北極跟南極一樣的冷。為什么會這樣,因為他們不懂中庸。
再說現(xiàn)實一點,好比我們的有些朋友,剛出學(xué)校的時候什么都敢想、敢做,但在社會中若打拼一兩年,經(jīng)歷了一些挫折或失敗后,就歇菜了。“夢想”、“激情”、“腳踏實地”可能被人利用過,我們可能因此會犯錯、吃虧,但那是“人”的錯,不是“夢想”、“激情”、“腳踏實地”本身的錯,我們不能因此就變得沒有夢想、沒有激情、投機(jī)取巧、處處設(shè)防,做人得學(xué)會中庸。
還是沒明白,對吧?那么說到Java技術(shù)上來就是不要因為有了類(Class)的存在可能會破壞我們面向?qū)ο缶幊痰木A,所以你就把類(Class)從Java中消除,而只保留接口(Interfaces)。同樣的道理,你不能因為Struts的action中的那四個討厭的參數(shù)看起不爽,你webwork就把它們?nèi)咳サ簦粋€不留。其結(jié)果就是過分的簡潔、高雅造成了很多新人的都無法理解及領(lǐng)悟其中妙處的尷尬處境。為了給頁面?zhèn)饕粋€參數(shù)得翻遍大大小的接口API說明文檔。本來一個簡單的MVC你卻暗藏那么多華麗的機(jī)關(guān),跟我們這些平庸的程序員玩起捉迷藏,有必要嗎?有時還得學(xué)學(xué)人家ASP、PHP,就那么簡單的幾條語句,還不一樣搭建起了一棟棟賞心悅目的高樓大廈嗎?這應(yīng)該也算是很多Struts粉絲不喜歡webwork的一個原因吧。
可以這么說,EasyJWeb的做法恰好就是得益于這個我們中華民族所獨用的中庸思想,即要保持一定的技術(shù)先進(jìn)性(什么[I]OC、[A]OP、OX、攔載器等值錢的我們通通都要!呵呵),又要照顧廣大的普通代碼“水泥”工人的應(yīng)用及理解方便。
?
很多人說,"Spring framework 的作者真正明白我們程序員需要什么,關(guān)心什么。",這里我想說,真切希望像EasyJF一樣的眾多國產(chǎn)開源團(tuán)隊能真正明白我們中國的程序員需要什么,關(guān)心什么。多學(xué)習(xí)國內(nèi)外優(yōu)秀的開源技術(shù),多融入一些國內(nèi)民族文化思想及思維習(xí)慣。多創(chuàng)造點實實在在,能真正提高軟件生產(chǎn)力的東西。
玩得有點瘋了哈,收斂一下。借著這陣吹Spring的風(fēng),筆者作為EasyJWeb開發(fā)團(tuán)隊成員之一,借機(jī)給大家正式的介紹一下EasyJWeb這個開源項目。
EasyJWeb是基于java技術(shù),應(yīng)用于WEB應(yīng)用程序快速開發(fā)的MVC框架,框架設(shè)計構(gòu)思來源于國內(nèi)眾多項目實踐,框架旨在借鑒當(dāng)前主要流行的開源Web框架(Struts、JSF、Tapestry 、Webwork),吸取其優(yōu)點及精華,利用Velocity作為模板頁面引擎,實現(xiàn)一個頁面及代碼完全分離的MVC開發(fā)框架。旨在構(gòu)建一個能實現(xiàn)中小型Web應(yīng)用系統(tǒng)快速開發(fā)的簡易Web框架。
根據(jù)EasyJWeb團(tuán)隊的設(shè)想,這個“輪子”并不僅僅是簡單地簡化了一些常見框架中的不必要環(huán)節(jié),把Struts、Webwork、Tapestry等框架中的一些精華功能進(jìn)行簡單拼湊,其核心的是EasyJWeb Tools代碼生成工具及業(yè)務(wù)引擎構(gòu)想部分,若能實現(xiàn)這些構(gòu)想的話將會大大提高通用軟件的開發(fā)效率。
雖然已經(jīng)有了很多基于EasyJWeb開發(fā)的完整應(yīng)用源碼在網(wǎng)上下載,然而EasyJWeb當(dāng)前還處于測試版,還有很多不足。第一個正式版本計劃于2006年7月中旬有望發(fā)布,其作為一個開源項目,非常希望能得到國內(nèi)眾多技術(shù)前輩的支持及指教,若有發(fā)現(xiàn)框架中的不足,還請大家不吝給我們提出批評及建議,當(dāng)然要是您有時間加入進(jìn)來一起開發(fā)、改進(jìn)那就更加求之不得了。
?
(
備注:由于筆者不想拐彎抹角浪費大家玩的時間,有些“表白”難免過于直接,還請不喜歡Spring或者過分喜歡Spring的同行多多見諒! 本文中的“我們”,僅指與筆者有著同樣成長經(jīng)歷的80后人,對于文章提到的觀點,多數(shù)皆屬于筆者個人觀點,不代表任何人。
本文作者:
EasyJF開源團(tuán)隊大峽 版權(quán)歸
EasyJF開源團(tuán)隊所有,歡迎轉(zhuǎn)載,轉(zhuǎn)載請保留作者版權(quán)聲明,謝謝!)
?
附