(本故事除了部分点明道姓并具有故事详细发生的具体时间点地等部分情节以外,其它内容纯属虚构,若有雷同,纯属巧合。)
主演: EasyJWeb、中庸之道、Spring。
配角:Struts、webwork、Velocity、JSP、hibernate、J2EE各层程序员。
在前面的两个例子中,主要给大家介绍了Spring的黄金庸俗组合以及华丽高雅组合来开发B/S应用。在我们用到的几个“轮子”当中,由于hibernate是当今公认最好的ORM系统,因此争议性不大。然而,Struts就未必了,Struts也是市场上使用得多的框架(尽管有那么多技术牛人说他的不是),然而很多人对Struts很是看不起眼,总是认为没有华丽的IOC、无法写出优雅、漂亮的代码,一些配置及FormBean搞起来很麻烦,因此,webwork或Tapestry等比他强很多。在网上,有时候甚至会看到有些人对struts学习者发出藐视的目光。
Webwork就真强了吗?市场才是王道吧,我不禁想问,不就引入了一些IOC、拦截器功能,并与一些常用的组件集成摆了。存在即合理,所以各家粉丝没必要为这个PK。正好,现在struts与webwork开发团队已经合并了(为什么合并?当然是为了对付共同的敌人啊),可以不用PK了。但Tapestry、JSF、Spring MVC的粉丝又该怎么办?呵呵,是不是很有意思,打着不发明轮子大旗,发明了一个又一个的漂亮轮子给我们,让我们这些第三世界国家的粗人谁都舍不得丢下,一不小心就犯了选择恐惧症。看来作为一名程序员,身体以及精神都得健壮啊,要不,谁能折腾得起!这不,客户正在催命似的要看项目进展情况,而我们连选择什么框架都还没定呢!
有点晕了吧,还有更晕的。今天笔者不打算用大家熟悉的框架作示例,所以就不用管各家粉丝怎么PK了(看他们PK也郁闷,还得翻译一次,有时一不小心还会跑调!)。本文将用一个你可能从没见过的国产开源框架来替换掉上例中的Struts及webwork,这个框架就是由国内EasyJF开源团队所开发的EasyJWeb框架。
提到EasyJWeb,我想前面提到的各种MVC框架的粉丝一定会联合起来,组成一个要技术有技术、要资历有资历的超强阵容来PK了。因为EasyJWeb是国产的,而其它的都是进口原装的,再加上EasyJWeb测试版本当前才发到0.5版,有很多地方都还不成熟,几个开发者技术水平又不怎么样,写的东西也是那么平庸、朴实,一不小心就被抓住小辫子。而EasyJWeb开发团队又急于想把这个框架介绍给大家,让大家帮助提建议、完善。
既然还不完善,那我为什么要用EasyJWeb而不选择其他呢?原因跟大家跟大家喜欢其它的框架也一样,因为本人就是EasyJWeb的超级粉丝,我不支持他支持谁。说得更直白一点,这好比俺村里大眼睛、长头发的小芳姑娘,不管从皮肤、外表、性格、习惯等各方面都比美国的小甜甜布兰妮更适合做偶老婆的道理一样。况且笔者大大小小框架也用了不少,自我感觉还是EasyJWeb使起来最顺手,代码少容易搞清楚框架的工作原理不说,提供的那些功能还都是我们项目中经常所需要的。
可笑也可悲的是,国内有的同行及媒体平台一看到有关EasyJWeb字眼,一看是国产的,好歹不分尽然就说是打广告,写的文章也不让登。偶滴神啊,要不是在大街上看到满街的黄皮夫、黑眼睛的路人甲乙丙丁,我还真以为自己身处西方资本主义国家了,对俺们社会主义国家搞的东西这么抵制。同样是开源项目,struts的心得体会你可以发,为什么关于EasyJWeb的心得体会你就不让发?(小样,谁说不给你发了?要发可以,拿金币来!)何苦呢,现在都WTO那么多年了。你整天翻译、搜集那些乱七八糟的国外小项目的动态啊什么的,累不累啊。不知情者还认为你是资本主义国家设在国内的宣传喉舌呢。
当然,这里说的只是非常少的个别特例,大多数前辈及平台还是很支持我们的。若没有国内众多前辈的鼓励、指点以及像“Java研究组织”类似的众多专业技术平台的支持,恐怕EasyJWeb早就死翘翘,今天大家也就看不到这篇文章了。
晕,八卦有点远了,下面进入正题吧。今天笔者探讨的一个重点就是如何在不动其它各层的情况下,替换掉上两篇“添删改查”示例中的MVC层。这也是我理解的多层结构中的一门艺术,这也是大家听到的组件或者构件的一个妙处。前辈们不都说吗?配置时代的编程,做软件就像搭积木,几个框框、架架、部件搭在一起,一个庞大的系统就被我们堆起来了。假如其中有些部件由于各种原因需要换,随便换就是了,其它的部分都不用动。J2EE的灵活、可维护性都体现在这些地方,由于Java的灵活,因此他有时候会带给我们类似于艺术工作者所特有的那种飘飘然的感觉,这也是笔者放弃微软的.Net,投入Java怀抱的原因。
由于本示例使用的是EasyJWeb,因此其它MVC框架的粉丝可以略过后面的技术细节内容,直接跳到后面有关“中庸之道”的论述中,否则不小心你也会被EasyJWeb迷住。
下面请看操作步骤,大家可以对照前两篇示例中的MVC部分的内容来看:
1、 写处理用户请求的Action。
跟Struts类似,EasyJWeb有一个Action,但这个Action因为使用的接口方式,不需要继承于框架特定的Action,只需要实现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","数据添加成功!");
forward=doQuery(form,module);
}
else
{
form.addResult("msg","数据添加失败");
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","数据修改成功!");
forward=doQuery(form,module);
}
else
{
form.addResult("msg","数据修改失败");
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","找不到数据!");
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","数据删除成功!");
}
else
{
form.addResult("msg","数据修改失败");
}
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(""))//默认按用户名排序
{
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,"","");
//保存查询结果
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中的相关语法,也没有一些让人头晕的自定义标签。所有标记集中归纳起来就只有4种用法,大家可以看看笔者在EasyJF开源团队官网上的一篇文章,题为:
《浅析MVC框架中View层的优雅设计及实例》。
模板不再存放在根目录,而是存放在web-inf\easyjweb目录,同样是两个模板,一个userEdit.html模板是用于显示用户录入表单,另外一个userList.html文件是用户列表页面。模板的全部内容可以从EasyJF开源团队官方网站下载,本示例中的全部完整代码中包含了该模板。
3、修改web.xml文件即可,其全部内容如下:
<?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>
配置文件跟前面两个例子中的差不多,只是多了一些中文过滤处理等内容,EasyJWeb已经考虑到经常遇到的中文问题。
大家可以拿Struts与EasyJWeb对比一下,我们少了两个步骤,一个是ActionForm Bean的定义,另外一个是配置struts-config.xml文件。其实EasyJWeb也有跟struts-config.xml类似的配置文件easyjf-web.xml,只不过我们这个例子中使用的是默认配置而已。
完整的示例代码下载:
当然,为什么我们能不修改其它的代码即换掉系统的MVC层,还是归功于Spring的IOC容器为我们管理了其它层组件。当然,这两三个示例中只使用了Spring最简单也是最常用的功能。
看到这里很多人一定会疑问,在前一篇演示webwork应用的文章中,webowrk都快被捧上天了,而现在你又来推荐EasyJWeb,这不明摆着忽悠人吗?EasyJWeb这个轮子跟他们有什么区别及特色呢?
要回答这个问题,说来有点话长,这得从我们中华民族儒家文化中的核心思想,“中庸之道”说起(中庸之道是本文中的一个主角,请大家鼓掌!)。“中庸者,以其记中和之为用也;庸,用也。孔子之孙子思作之,以昭明圣祖之德也。”-《中庸》郑玄注;《中庸》中有说:“天命之谓性,率性之谓道,修道之谓教”。怎么样,很多朋友看不懂是吧?谁叫咱们80后人注重素质教育,搞到连老祖辈的文化思想核心都搞不懂。若长此下去,恐怕三、四十年后,咱们的后辈都将会看不懂也听不懂中文了。
什么是中庸?这里我用通俗点的语言看能不能解释一下。我认识一位大伯,他以前是知识分子,但他因为他的知识而坐了10年牢,于是他把他儿子从小就带进了我们贵州最穷的山区里面,如今儿子变成了文盲。另外我还听说有一个人本来住在南极的,但后来他说南极太冷了,他要搬到北极去住,到了北极他才发现其实北极跟南极一样的冷。为什么会这样,因为他们不懂中庸。
再说现实一点,好比我们的有些朋友,刚出学校的时候什么都敢想、敢做,但在社会中若打拼一两年,经历了一些挫折或失败后,就歇菜了。“梦想”、“激情”、“脚踏实地”可能被人利用过,我们可能因此会犯错、吃亏,但那是“人”的错,不是“梦想”、“激情”、“脚踏实地”本身的错,我们不能因此就变得没有梦想、没有激情、投机取巧、处处设防,做人得学会中庸。
还是没明白,对吧?那么说到Java技术上来就是不要因为有了类(Class)的存在可能会破坏我们面向对象编程的精华,所以你就把类(Class)从Java中消除,而只保留接口(Interfaces)。同样的道理,你不能因为Struts的action中的那四个讨厌的参数看起不爽,你webwork就把它们全部去掉,一个不留。其结果就是过分的简洁、高雅造成了很多新人的都无法理解及领悟其中妙处的尴尬处境。为了给页面传一个参数得翻遍大大小的接口API说明文档。本来一个简单的MVC你却暗藏那么多华丽的机关,跟我们这些平庸的程序员玩起捉迷藏,有必要吗?有时还得学学人家ASP、PHP,就那么简单的几条语句,还不一样搭建起了一栋栋赏心悦目的高楼大厦吗?这应该也算是很多Struts粉丝不喜欢webwork的一个原因吧。
可以这么说,EasyJWeb的做法恰好就是得益于这个我们中华民族所独用的中庸思想,即要保持一定的技术先进性(什么[I]OC、[A]OP、OX、拦载器等值钱的我们通通都要!呵呵),又要照顾广大的普通代码“水泥”工人的应用及理解方便。
很多人说,"Spring framework 的作者真正明白我们程序员需要什么,关心什么。",这里我想说,真切希望像EasyJF一样的众多国产开源团队能真正明白我们中国的程序员需要什么,关心什么。多学习国内外优秀的开源技术,多融入一些国内民族文化思想及思维习惯。多创造点实实在在,能真正提高软件生产力的东西。
玩得有点疯了哈,收敛一下。借着这阵吹Spring的风,笔者作为EasyJWeb开发团队成员之一,借机给大家正式的介绍一下EasyJWeb这个开源项目。
EasyJWeb是基于java技术,应用于WEB应用程序快速开发的MVC框架,框架设计构思来源于国内众多项目实践,框架旨在借鉴当前主要流行的开源Web框架(Struts、JSF、Tapestry 、Webwork),吸取其优点及精华,利用Velocity作为模板页面引擎,实现一个页面及代码完全分离的MVC开发框架。旨在构建一个能实现中小型Web应用系统快速开发的简易Web框架。
根据EasyJWeb团队的设想,这个“轮子”并不仅仅是简单地简化了一些常见框架中的不必要环节,把Struts、Webwork、Tapestry等框架中的一些精华功能进行简单拼凑,其核心的是EasyJWeb Tools代码生成工具及业务引擎构想部分,若能实现这些构想的话将会大大提高通用软件的开发效率。
虽然已经有了很多基于EasyJWeb开发的完整应用源码在网上下载,然而EasyJWeb当前还处于测试版,还有很多不足。第一个正式版本计划于2006年7月中旬有望发布,其作为一个开源项目,非常希望能得到国内众多技术前辈的支持及指教,若有发现框架中的不足,还请大家不吝给我们提出批评及建议,当然要是您有时间加入进来一起开发、改进那就更加求之不得了。
(
备注:由于笔者不想拐弯抹角浪费大家玩的时间,有些“表白”难免过于直接,还请不喜欢Spring或者过分喜欢Spring的同行多多见谅! 本文中的“我们”,仅指与笔者有着同样成长经历的80后人,对于文章提到的观点,多数皆属于笔者个人观点,不代表任何人。
本文作者:
EasyJF开源团队大峡 版权归
EasyJF开源团队所有,欢迎转载,转载请保留作者版权声明,谢谢!)
附