|
上一级 首页 下一级
增删改查(CRUD)快速开发
Jdon框架提供了基于Struts的快速开发,可以快速开发出数据的增删改查功能(CRUD),以及批量查询等功能。
本章是与Jdon框架其它功能分离的,你可以只使用Jdon框架的组件管理和AOP功能,而不必使用基于Struts的快速开发功能,随着新的表现层技术出现,Jdon框架将推出基于的技术如JSF的快速开发框架。
关于为什么使用jdon框架的CRUD功能,除了在开发速度上有极大提高以外,在设计上也有很多优点:
边界类,控制类和业务接口的关系:
http://www.jdon.com/jive/article.jsp?forum=91&thread=21245
J2EE中几种业务代理模式的实现和比较:
http://www.jdon.com/artichect/businessproxy.htm
struts基础
Jdon框架的CRUD功能是基于struts实现,主要工作是表现层的配置,那么是否需要程序员熟悉struts呢?其实完全不必。
但是,需要了解struts的一些基础:struts主要有一个配置文件,在Web目录的WEB-INF下struts-config.xml,其中主要有两部分配置:ActionForm和Action。
ActionForm配置:主要是配置你设计的ActionForm子类;例如:
<struts-config>
<form-beans>
<form-bean name="accountForm"
type="com.jdon.framework.samples.jpetstore.presentation.form.AccountForm"/>
</form-beans>
…..
</struts-config>
Action配置:相当于一个servlet,也需要在struts-config.xm中action-mappings l配置,例如:
<action-mappings>
<action name="accountForm" path="/shop/newAccountForm"
type="com.jdon.strutsutil.ModelViewAction" scope="request">
<forward name="create" path="/account/NewAccountForm.jsp" />
</action>
</action-mappings>
action中配置简要说明:
name是ActionForm名称,是前面ActionForm名称;
path是该action在浏览器中调用的url名称,使用http://xxxx/web名称/shop/newAccountForm.do就可以调用这个action,在path值后面加一个.do即可,.do是在web.xml中配置的:
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
你可以改变*.do配置,改为*.shtml,那么上面action(Servlet)调用变成http://xxxx/web名称/shop/newAccountForm.shtml
type是你继承struts的Action实现子类:如com.jdon.strutsutil.ModelViewAction是Jdon框架的实现子类。
Scope是值你的ActionForm生存周期,一般有request或session,相当于Jsp中useBean中的scope,表示ActionForm实例有效范围,request表示用户发出一个请求周期;session表示是从用户登陆到退出为止,这个ActionForm实例一直存在,你可以引用同一个实例。
<forward name="create" path="/account/NewAccountForm.jsp" />
这表示Action执行完成后,需要推出的Jsp页面,name值是你在Action执行子类中定义的名称;path是你的jsp页面相对路径。
所以,编写一个传统意义上的Jsp页面,在struts变成下面几步:
编写一个ActionForm实现子类
编写一个Action实现子类,完成其中方法execute内容。
配置struts-config.xml
使用struts标签编写Jsp页面,这时的Jsp页面和传统的Jsp相比:已经没有Java代码,完全Html语法。
由以上可见,struts在实现设计优化目的同时,实际增加编程复杂性,Jdon框架试图保证struts优点的前提下,简化标程复杂性,CRUD的功能对上述步骤优化如下:
ActionForm是Model代码复制;
无需编写Action实现子类;
模板化配置struts-config.xml,参考别的配置,稍微修改即可。
简化Jsp页面编写数量;四个功能只需编写一个Jsp。
strtus学习资源:http://www.jdon.com/idea/strutsapp/04005.htm
CRUD原始流程
我们先看看直接基于Struts的新增修改删除和查询的流程:
一般情况下,一个数据的增加修改的Struts实现流程如下:
(1)一般情况下,一个系统的操作用户(以下简称用户)新增或修改数据,首先要推送给他一个Jsp页面,如果是新增页面,就是一个空白表单的Jsp页面;如果是修改页面,则先到数据库中查询获得原来的数据,然后推出一个有数据表单的Jsp页面,用户才能在原来的数据上修改或编辑。
由于在MVC模式中,Jsp页面只是一个页面输出,或者说不能有任何Java功能实现,因此上面修改页面推出前需要查询数据库这个需要Java实现的功能不能在Jsp页面中实现,只能在Jsp页面前加一个Action,这样,修改页面的推出流程变为不是直接调用Jsp页面,而是:action.do ---> Jsp页面,首先调用Action;然后才由Action推出Jsp页面。
这个Action实现我们称为ViewAction,专门用于控制输出Jsp界面,新增Jsp页面的推出前我们也加上这个ViewAction,这样无论是新增Jsp页面或修改Jsp页面,都是由ViewAction推出,那么到底是推出新增Jsp页面还是修改Jsp页面呢?
关键是ViewAction的输入参数Action的值,根据Action的值来判断是新增还是修改。如果设置Action值如为空或为create值(如http://xxx/viewAction.do?action=create),则直接输出新增性质的JSP页面;而Action值如为edit(如http://xxx/viewAction.do?action=edit),则是要求输出进行编辑页面,根据ID查询数据库获得存在的数据,然后输出编辑修改性质的JSP页面。
当然,在ViewAction中还有一些具体参数的检查,如果是编辑,则关键字ID不能为空,因为后台要根据此ID为主键,查询数据库其相应的记录,如果数据库未查询到该主键的记录,则需要显示无此记录等信息。
(2)创建有关该数据的JSP页面,既用于新增页面,也用于修改页面。将该Jsp页面作为ViewAction的输出页面。该Jsp页面结构如下:
<html:form action=”/XXXSaveAction.do”>
<html:hidden property="action" />
<!—该action的值是调用viewAction.do?action参数的值-->
…….
</html:form>
当用户填写完该Jsp页面中的表单数据将提交给一个新Action子类实现:专门用于接受表单数据并保存持久化它们。
(3)创建SaveAction,它用来接受提交表单的数据,不同于ViewAction专门用于输出Jsp表单页面,该Action专门用于接受Jsp表单页面提交的数据。
SaveAction中主要是调用业务层Service实现数据持久化操作,调用Service之前,需要将表单的数据ActionForm转为一个对象(DTO对象),然后作为方法参数传送给Service具体方法, Service处理完成后,返回结果对象,SaveAction还需要检查Service是否操作成功等。
总结:一个数据新增删除修改流程需要创建两个Action,一个Jsp页面;当然爱Struts 1.2中已经通过DispatchAction解决了需要创建两个Action问题,只需要一个Action,但是使用Jdon框架的Struts配置,一般情况下都不需要Action,只要配置一下JdonFramework.xml如下即可:
<model key="typeId" class ="news.model.NewsType">
<actionForm name="newsTypeActionForm"/>
<handler><!--以下相当于一个action代码实现 -->
<service ref="newsManager">
<getMethod name="getNewsType" />
<createMethod name="createNewsType" />
<updateMethod name="updateNewsType" />
<deleteMethod name="deleteNewsType" />
</service>
</handler>
</model>
在以后章节将详细说明上面配置的语法。
CRUD原则:一个数据表对应一个模型Model;一个Model对应四个功能:新增;删除;修改和查询。
Model和ModelForm
Model是域模型,是采取领域模型分析法从系统需求分析中获得的,反映了应用系统的本质,Model是一个简单的POJO,属于数据类型的POJO,区别于POJO服务。从传统意义上理解,Model设计相当数据表设计,在传统的过程化编程中,一个数据库信息系统设计之前我们总是从数据表设计开始,而现在我们提倡是从域模型提炼开始。
Jdon框架对模型对象建立有两个要求,继承com.jdon.controller.model.Model,每个Model有一个主键。
每个Model需要一个主键
每个Model必须有一个主键,就如同每个数据表设计都有主键一样,Model的主键是和其对应的数据表主键在类型上是一致的。例如一个Model为Account如下:
public class Account extends Model {
private String username;
private String password;
private String email;
private String firstName;
private String lastName;
……
}
其持久化数据表account的表结构:
CREATE TABLE ACCOUNT (
username varchar(80) NOT NULL default '',
email varchar(80) NOT NULL default '',
……
PRIMARY KEY(username)
}
account表的主键是username,数据类型是varchar,通过JDBC对应可知其对应的Java类型是String,那么Account模型的主键也必须是String,当然主键名称可以不一样,Account是username,而account的表的主键可以是userId。
主键类型(包括Model和数据表)一般推荐统一使用String 或Integer/int或Long/long。缺省建议使用String(Oracle数据库处理字符串中空格有些麻烦,需要特别注意)。
下面以MySQL为例,说明JDBC缺省在对象和数据表之间的类型对应:
Model主键类型 |
数据表主键类型 |
String |
varchar或char |
Integer |
int |
Long |
BIGINT |
在使用本框架前提下,数据表字段不同类型选择所带来的性能等差异非常小,几乎忽略不计。相关数据类型讨论可见:http://www.jdon.com/jive/article.jsp?forum=91&thread=23875
如果你的数据表没有主键怎么办?那么强制给它一个主键,这可以由一个专门序列器产生。
Model配置
Model在jdonframework.xml中配置,如下:
<model key="username" class ="com.jdon.framework.samples.jpetstore.domain.Account">
…..
</model>
key的值就是指定Model的主键,这里是username,class是Account的类,这样就定义了一个Model。
Model配置除定义Model自身属性以外,还需要定义了子属性:actionForm和handler,这两个定义在下面章节描述。
ModelForm是Model的映射
Jdon框架通过映射设计,保证表现层、Jdon框架、服务层和持久层之间能够解耦独立,相互可插拔、脱离或组合。例如下图展示了表现层使用Struts;服务层/持久层使用了EJB的映射设计:

Model和ModelForm映射是通过相同字段拷贝实现的,也就是这两个类之间有相同的字段属性,那么字段属性的值可以在他们之间拷贝转移。例如Model Account的代码:
public class Account extends Model {
private String username;
private String password;
private String email;
private String firstName;
private String lastName;
……
}
那么其ModelForm的类代码如下:
public class AccountForm extends ModelForm {
private String username;
private String password;
private String email;
private String firstName;
private String lastName;
……
}
这样两者代码保证它们之间的映射,这是使用Jdon框架的规则之一。
Jdon框架是使用org.apache.commons.beanutils.PropertyUtils.copyProperties方法在这两个类的对象之间进行字段拷贝的,因此两个类对应字段类型必须一致。
ModelForm配置
ModelForm就是ActionForm,因此只需要在struts-config.xml的<form-beans>中定义ActionForm就可以,如下:
<struts-config>
<form-beans>
<form-bean name="accountFrom"
type="com.jdon.framework.samples.jpetstore.presentation.form.AccountForm"/>
</form-beans>
</struts-config>
注意ModelForm的名字是accountFrom,因为Model和ModelForm是映射对应关系,我们需要告诉Jdon框架这种对应关系。
那么,拓展前面的Model配置,在jdonframework.xml配置如下:
<model key="username" class ="com.jdon.framework.samples.jpetstore.domain.Account">
<actionForm name="accountForm"/>
……
</model>
在jdonframework.xml中的配置是让Model和ModelForm有唯一的对应关系。
在jdonframework.xml中配置的ActionForm名称必须是全局唯一的,也就是说,如果有两个ActionForm名称一样的配置,就是它们的Model class值不一样,Jdon框架也视为是一样的。
CRUD基本流程
这里首先介绍一下Jdon框架在上面思路上延伸抽象设计的思路:
一个数据的增删改查流程有上面总结的流程组成:
ViewAction-à表单Jsp 页面-à SaveAction--à结果Jsp页面
如下面流程图:通过浏览器网址(或Html链接)调用我们推出用于新增或编辑的页面,确定保存输入的数据后,激活ModelSaveAction,ModelSaveAction通过jdonframework.xml的配置,调用相应的Service类,这个Service类是你自己编制的,根据原始网址或Html链接调用的参数action不一样,调用不同的Service接口中相应的方法。

上图中,在ModelSaveAction步骤有一个ModelHandler,它其实是真正和Service接口打交道的类,必要时,你可以自己继承实现自己的ModelHandler子类,它与ModelSaveAction的关系如下:

ModelViewAction和ModelSaveAction中有关具体每个数据有不同的操作,都委托给ModelHandler实现,用户使用框架时,只要继承实现ModelHandler,填补异性方法就可以。缺省情况下,上图中的jdonframework.xml配置实际就是ModelHandlel实现,所以一般不必自己再编制ModelHandler实现了,但是特殊情况下可能还是需要的,提供缺省和特殊两种方便。
下面我们针对上面流程图对每一个环节详细描述如下:
CRUD页面显示
调用ModelViewAction
Jdon框架中的com.jdon.strutsutil.ModelViewAction主要是实现在推出让用户新增数据或编辑数据的Jsp页面的之前的准备工作。它主要是做Jsp页面推出前的准备工作,然后推出不同的Jsp页面。
ModelViewAction根据调用参数action的值,判断用户发出的是新增或编辑命令。
Action有两个规定值create 或edit,也就是说,只有三种URL调用形式:
新增URL:http://xxxx/XXXModelViewAction.do?action=create
新增URL:http://xxxx/XXXModelViewAction.do
编辑URL:http://xxxx/XXXModelViewAction.do?action=edit
如果用户在浏览器发出这三种URL调用,将激活ModelViewAction,ModelViewAction将根据参数action的值分别推出用于创建性或编辑性的页面。下面分别详细说明这两种流程:
1.在创建性Jsp页面推出之前,要做一些准备工作,由于Jsp页面中表单数据(<form></form>之间数据)是由ModelForm(ActionForm)概括的,所以,创建性Jsp页面推出前的准备工作主要是ModelForm的初始化创建,ModelForm是Struts的ActionForm继承者,ModelForm是抽象页面表单数据,它是Model在表现层的映射影子。
ModelForm的初始化创建很重要,它决定了推出给用户创建性页面的内容,需要程序员介入度很高,Jdon框架提供有几种初始化ModelForm方法:
首先检查ModelHanlder的initForm方法,检查用户有无自己实现初始化ModelForm实现;如果无,则用Struts的自动创建ActionForm(ModelForm),这时的ModelForm实例是空对象,这时还有另外一种方式提供用户初始化ModelForm实例的方法:调用Modelhandler的initModel方法,将该方法返回的Model对象拷贝到ModelForm中,这符合Model和ModelForm相互映射的关系。下面章节将描述ModelHandler的initForm和initModel方法有何区别。
2.推出编辑性页面之前的准备工作主要是:根据主键查询从服务层获得一个已经存在的数据模型,简单地说:根据主键从数据库查询已经存在的一个记录,这样,推出的Jsp页面中包括数据的表单,用户可修改编辑。
这个工作涉及两部分:ModelForm创建;然后从服务层获得一个有数据的Model,将Model数据拷贝到ModelForm实例中。
注意:从Jdon Framework 1.4以后,参数名不一定是action,可以是method,也就是可以如下调用:
新增URL:http://xxxx/XXXModelViewAction.do?method=create
新增URL:http://xxxx/XXXModelViewAction.do
编辑URL:http://xxxx/XXXModelViewAction.do?method=edit
Struts配置和Jsp
根据不同域模型,我们有相应的不同的配置,例如:有一个Model为A,那么为了推出A新增或修改或删除的页面,我们需要在struts-config.xml配置如下:
<action name="aActionForm" path="/aAction" type="com.jdon.strutsutil.ModelViewAction">
<forward name="create" path="/a.jsp" />
<forward name="edit" path="/a.jsp" />
</action>
这是一个标准的Action配置,A的ActionForm为aActionForm,新增修改删除A的Jsp页面为a.jsp,如上面配置,这样,如果用户从浏览器网址如下调用:
http://xxxxx/aAction.do?action=create
这样调用将推出a.jsp用于新增;
http://xxxxx/aAction.do?action=edit
这样调用将推出a.jsp用于修改删除。
再举例,如果Model为B,B的ActionForm为bActionForm,Jsp页面为b.jsp,那么Struts-config.xml只要如下配置:
<action name="bActionForm" path="/bAction" type="com.jdon.strutsutil.ModelViewAction">
<forward name="create" path="/b.jsp" />
<forward name="edit" path="/b.jsp" />
</action>
如果Model为c,那么struts-config.xml配置如下:
<action name="cActionForm" path="/cAction" type="com.jdon.strutsutil.ModelViewAction">
<forward name="create" path="/c.jsp" />
<forward name="edit" path="/c.jsp" />
</action>
总结上面配置,Model名称不同,只要更换一下有关Model名称即可,其余基本不变,配置具备模板化编程的特点,拷贝粘贴然后修改,修改且有规律。
接受CRUD处理
当用户在浏览器中新增或修改页面填入数据后,将按“确定submit”按钮提交后台进行保存或删除等处理,从CRUD基本流程章节的流程图可以看到看到:这主要是由ModelSaveAction
ModelSaveAction原理
ModelSaveAction是前面的SaveAction实现,它是真正的核心Action实现,专门将用户新增或修改后的数据提交到服务层,实现持久化如保存到数据库中。
ModelSaveAction主要是委托ModelHandler实现数据提交和服务激活,这个过程比较单一有规律,用户可介入程度低,因此可以使用配置来代替代码实现。
我们看看ModelSaveAction是如何将Jsp页面提交的数据传递给后台,ModelSaveAction从ModelForm(ActionForm)中获得用户提交的数据,将其拷贝到相应的Model实例,然后将Model对象打包到EventModel对象中,将EventModel作为方法参数,调用ModelHandler的serviceAction方法,ModelHandler的serviceAction则是调用服务层相应Service的对应的create/update/delete方法,所以ModelSaveAction主要工作委托给ModelHandler实现,我们将在下面研究重要的ModelHandler类。
Struts配置和Jsp
ModeSaveAction和ModelViewAction类似,根据Model不同,在struts-config.xml中配置如下:
<action name="aActionForm" path="/aSaveAction" type="com.jdon.strutsutil.ModelSaveAction">
<forward name="success" path="/aResult.jsp" />
<forward name="failure" path="/aResult.jsp" />
</action>
如果Model为B,那么struts-config.xml的配置是:
<action name="bActionForm" path="/bSaveAction" type="com.jdon.strutsutil.ModelSaveAction">
<forward name="success" path="/bResult.jsp" />
<forward name="failure" path="/bResult.jsp" />
</action>
关于ModeSaveAction使用是在Jsp页面中赋值给action:
<html:form action=”/aSaveAction.do”>
<html:hidden property=”action” />
<html:text ….
….
</html:form>
该Jsp页面是新增或修改性质的页面,例如可以是前面介绍的ModelViewAction推出的a.jsp或b.jsp。
至此,ModelViewAction -à jsp àModelSaveAction实现了首尾衔接,实现了一个CRUD操作流程。
通过配置使用Jdon框架中的ModelViewAction和ModelSaveAction,程序员避免了象开发普通Struts应用系统那样建立至少一个Action子类。
在这个流程中,需要和服务层服务交互,这需要由程序员根据具体程序定制,下面介绍程序员可介入定制的重要类ModelHandler。
配置jdonframework.xml
现在我们进入CRUD流程图的下面一个环节:表现层和业务层接口部分了。
前面我们说过,ModelViewAction和ModelSaveAction其实是委托ModelHandler和Service接口打交道的,程序员需要定制实现的部分由继承ModelHandler实现。但是缺省情况下,可以通过jdonframework.xml配置实现:
配置实现
假设,我们已经编制了一个Service接口如下:
public interface AccountService {
Account getUser(String username); //查询获得存在的Model
void createUser(EventModel em); //新增方法
void updateUser(EventModel em); //修改方法
void deleteUser(EventModel em); //删除方法
}
其中getUser方法是由调用ModelViewAction调用的,其余都是由ModelSaveAction调用的,为了让Service的具体方法告诉Jdon框架,我们可以通过jdonframework.xml配置告诉它:
<handler>
<service ref="accountService">
<getMethod name="getUser"/>//getUser对应AccountService接口的getUser方法
<createMethod name="createUser"/>//createUser对应AccountService接口createUser方法
<updateMethod name="updateUser"/>// updateUser对应AccountService接口updateUser方法
<deleteMethod name="deleteUser"/>// deleteUser对应AccountService接口deleteUser方法
</service>
</handler>
我们通过上述配置,建立了表现层ModelViewAction/ModelSaveAction和业务层Service之间的调用关系。当然这段配置应该放置在jdonframework.xml的Model配置中,以前面Model章节的配置为例子:
<model key="username" class ="com.jdon.framework.samples.jpetstore.domain.Account">
<actionForm name="accountForm"/>
……//上述配置插入在这里
</model>
这样,你自己编写的Service接口嵌入Jdon框架的CRUD流程,非常简单。
注意:这里对你的Service接口的方法的方法参数有一些限制,方法名不限。
方法参数限制:
查询方法:对方法主键必须是Model的主键,也就是model配置的key,例如,上面model配置key是username,那么你的Service接口查询方法参数必须是username,如下:
Account getUser(String username);
其中参数类型必须和Model对应的数据包的主键类型一致。
新增删除修改方法:这三个方法参数都必须是Jdon框架的com.jdon.controller.events.EventModel,方法返回类型为void,如果Service方法中有处理出错,通过将错误放入EventModel的setErrors方法中返回表现层。
简单一般以灵活牺牲为代价,如果你觉得约束太大,那么你可以自己编码实现ModelHandler,在ModelHandler中自己通过代码调用Service接口,完全回到你的自由编码阶段,下面针对配置和编码两种实现比较一下,这是以完成Jdon框架中要求的相同功能为前提的。
编辑之前的数据查询
Jdon框架的CRUD流程中,需要推出一个用于编辑的页面,既然是编辑,和新增页面不同的就是,编辑页面中各个字段已经有以前的数据,这样,你可在原来数据上修改。那么在编辑页面推出之前,Jdon框架需要调用Service接口的查询方法,如上面Account getUser(String username);方法。
Jdon框架是通过ModelHandler的findModelByKey方法实现的,两种实现方法:
1. 代码实现,继承ModelHandler实现,如果你的Model查询不是从数据库获得,如是从HttpSession获得的,那么你要继承实现自己的方法findModelByKey,如下代码:
public Model findModelByKey(String keyValue,
HttpServletRequest request) throwsException{
AccountService accountService =
(AccountService) WebAppUtil.getService("accountService", request);
return accountService.getUser(key);
}
代码实现后,记住告诉Jdon框架你的ModelHandler子类,配置jdonframework.xml:
<model ……j>
<handler class="你的ModelHandler子类" />
</model>
一般情况下,是通过服务层查询数据库获得的,那么涉及到服务层交互,可以采取配置实现。
有人可能奇怪:为什么上面ModelHandler的findModelByKey方法参数keyValue一定是String型的,难道我的Model主键类型一定是String吗?
不是,这里keyValue是主键数值,不是主键本身,主键数值一般是通过调用ModelViewAction的URL参数传入的,如下:
/xxxViewAction.do?action=edit&key=keyValue
这样,keyValue一定是字符串型的,如果你的Service的查询方法主键参数不是String,你可以将String型号转为你的主键参数。
2. 配置实现,在jdonframework.xml配置如下:
<model ….>
<handler>
<service ref="accountService">
<getMethod name="getUser" />
…..
</service>
</handler>
</model>
那么,要求你的服务层服务有相应的方法如下:
public class AccountServiceImp implements AccountService{
private ProductManager productManager;
public AccountServiceImp(ProductManager productManager){
this.productManager = productManager;
}
public Account getUser(String username) {
Account account = null;
try{
account = accountDao.getAccount(username);
account.setCategories(productManager.getCategoryList());
//other business logic
}catch(DaoException daoe){
Debug.logError(" Dao error : " + daoe, module);
}
return account;
}
….
}
数据提交保存
用户在Jsp页面填写或修改数据后,将实现保存提交,或实现删除提交,这时Jsp页面的action是提交给ModelSaveAction的,ModelSaveAction委托ModelHandler的serviceAction实现结果保存或删除。serviceAction有两种实现:
1.代码实现,这部分工作主要是实现传递工作,代码比较有规律,一般使用配置实现,如果你需要在提交之前实现一些其他特殊实现,那么使用代码实现如下:
public void serviceAction(EventModel em, HttpServletRequest request) throws
java.lang.Exception {
try { //从Httpsession获得User,保存到News中,这是特殊实现
User user = (User) ContainerUtil.getUserModelAfterLogin(request);
if (user != null) {
News news = (News) em.getModel();
news.setUser(user);
}
NewsManagerLocal newsManager = (NewsManagerLocal) WebAppUtil.
getEJBService("newsManager",request);
switch (em.getActionType()) {
case Event.CREATE:
newsManager.createNews(em); //递交service创建方法
break;
case Event.EDIT:
newsManager.updateNews(em);//递交service修改方法
break;
case Event.DELETE:
newsManager.deleteNews(em);//递交service删除方法
break;
}
}
catch (Exception ex) {
throw new Exception(" serviceAction Error:" + ex);
}
}
还需要配置jdonframework.xml你的ModelHandler代码实现:
<model ……j>
<handler class="news.web.NewsHandler" />
</model>
2.配置实现,如果在递交服务处理之前没有特殊工作实现,可使用配置,如下:
<model ….>
<handler>
<service ref="accountService">
<createMethod name=" createNews " />
<updateMethod name=" updateNews " />
<deleteMethod name=" deleteNews " />
…..
</service>
</handler>
</model>
那么,要求你的Service有insertAccount 和updateAccount或deleteAccount方法,而且这三个方法参数必须是EventModel类型,当然,方法名是可以根据你的service具体方法不同,在配置中更改,例如你的Service有insert方法,那么配置就是:
<createMethod name="insert" />
方法名可以变化,任意取,但是方法参数必须是EventModel类型的。如:
public interface AccountService {
Account initAccount();//初始化
Account getAccount(String username); //查询获得存在的Model
void insertAccount(EventModel em); //新增方法
void updateAccount(EventModel em); //修改方法
}
当然,如果你使用代码实现,就没有这些对Service类的编程规定了。
页面初始化
有些应用系统可能要求:推出新增编辑的页面必须初始化,实现装入一些其他数据,例如:我们新增人员名单的页面,可能有一个部门下拉菜单的选择,而这些部门数据是我们事先已经输入进入数据库的,这时在新增人员页面时,要装载进来。
推出新增性和编辑性页面的初始化工作是不一样的。我们知道,Jsp页面的初始化其实是ActionForm(ModelForm)的初始化,我们分别从新增和编辑页面的初始化两条线路说明。
如果你需要给ModelForm中属性字段简单初始化一些常量,那么很显然这些在ModelForm的构造方法中实现,如:
public class AccountForm extends ModelForm{
private List languages;
public AccountForm() {
languages = new ArrayList();
languages.add("english");
languages .add("japanese");
}
}
上面代码需要给languages加入一些初始值,这样,推出页面时,用户可以进行多项选择(使用html的select/options multibox等实现)。
如果初始化这些属性值需要从数据库中获得,那么就需要和服务层实现交互了,那么就要考虑继承实现ModelHandler了。
ModelForm创建可由通过服务层后台交互实现,这种交互实现也有两种方式:
1. 通过代码实现:ModelHandler提供的initForm方法,initForm程序员只要继承ModelHandler,在initForm方法中调用服务层服务,获得初始化值,再赋值入ModelForm,如下代码:
public class NewsHandlerextends ModelHandler {
public ModelForm initForm(HttpServletRequest request) throws Exception {
Debug.logVerbose("enter iniForm .", module);
NewsActionForm nf = new NewsActionForm(); //创建ModelForm
NewsManagerLocal newsManager = (NewsManagerLocal)
WebAppUtil.getEJBService("newsManager",request);
PageIterator pi = newsManager.getNewsTypePage(0, 50);
Collection newsTypes = new ArrayList();
while (pi.hasNext()) {
String id = (String) pi.next();
NewsType newsType = newsManager.getNewsType(id);
newsTypes.add(newsType);
}
nf.setNewsTypes(newsTypes); //将新闻类型列表赋值到新闻这个ModelForm
return nf;
}
……
}
还需要配置一下,告诉Jdon框架你的ModelHandler实现:
<model ……>
<handler class="news.web.NewsHandler" />
</model>
以上是代码实现直接初始化ModelForm,还有一种初始化ModelForm,思路是:初始化Model,然后将Model值拷贝到Model中,这是通过ModelHandler的initModel实现的。不过initModel和initForm只能选择其一实现,initModel还可以通过配置实现:
2. 通过配置实现,配置主要是通过initModel方法实现,在jdonframework.xml中配置如下:
<model ….>
<handler>
<service ref="accountService">
<initMethodname="initAccount" />
…..
</service>
</handler>
</model>
上面配置initMethod方法是访问accountService的initAccount方法,也就是说,ModelForm的初始化推给Model初始化,而Model初始化则由accountService的initAccount实现,程序员必须实现的accountService的initAccount方法。如:
public class AccountServiceImp implements AccountService{
private ProductManager productManager;
public AccountServiceImp(ProductManager productManager){
this.productManager = productManager;
}
public Account initAccount(){
Account account = new Account();
account.setCategories(productManager.getCategoryList());
return account;
}
….
这两种页面初始化选用依据,是根据用来初始化的数据来自何处?是来自后台或服务层,那么选择第二个方案;如果来自request相关的例如HttpSession,则选用第一个方案。
上述代码和配置比较中,案例情况不一样,实际上,如果你将代码实现中initForm方法中代码移植到Service接口的initAccount方法中实现,也就可以采取配置实现了。
ModelHandler原理
ModelHandler几个重要方法是总结了表现层和服务层三种交互操作,如果你的应用不属于这三种交互操作,那么可能就无法使用Jdon框架的CRUD功能,直接使用Struts实现。
ModelHandler有几个重要方法是:initForm方法、initModel方法、findModelByKey方法和serviceAction方法。前面两个方法是和页面初始化有关,页面初始化有可能和服务层交互访问;findModelByKey是根据主键查询数据库存在的记录,这是和编辑页面相关,编辑之前需要先查询,这个方法也需要和服务层交互访问;serviceAction则是将用户对数据的新增修改删除决定通知服务层进一步处理,这是和服务层主要交互访问。
上面章节中,jdonframework.xml配置:
<handler>
<service ref="accountService">
<getMethod name="getUser"/>//getUser对应AccountService接口的getUser方法
<createMethod name="createUser"/>//createUser对应AccountService接口createUser方法
<updateMethod name="updateUser"/>// updateUser对应AccountService接口updateUser方法
<deleteMethod name="deleteUser"/>// deleteUser对应AccountService接口deleteUser方法
</service>
</handler>
在Jdon框架中是自动调用com.jdon.model.handler.XmlModelhandler作为代码实现,也就是说,XmlModelhandler根据上面配置自动生成前面的代码,属于一种简单的代码自动生成。
注意:有时我们可能需要代码配置混合实现,ModelHandler几个方法中只代码实现一个方法,其他都可以配置实现,这也是可以的,只是这时你的代码不是继承ModelHandler,而是XmlModelHandler了,同时配置要写明你的子类实现:
<model ….>
<handler class=”你的XmlModelHandler子类”>
<service ref="accountService">
<createMethod name="insertAccount" />
<updateMethod name="updateAccount" />
<deleteMethod name="deleteAccount" />
…..
</service>
</handler>
</model>
更多配置技巧
CRUD功能实现标准配置
参考前面的ModelViewAction和ModelSaveAction配置章节,一个数据Model的标准CRUD功能实现无需编写任何Action,只要有ActionForm(还是Model的影子),通过struts-config.xml配置就可以实现:
1.推出创建性或编辑性页面:
<action name="aActionForm" path="/aAction" type="com.jdon.strutsutil.ModelViewAction">
<forward name="create" path="/a.jsp" />
<forward name="edit" path="/a.jsp" />
</action>
约束:
(1)type必须是com.jdon.strutsutil.ModelViewAction
(2)forward的name值必须是create或edit
2.接受数据提交数据并递交Service服务层处理。
<action name="aActionForm" path="/aSaveAction" type="com.jdon.strutsutil.ModelSaveAction">
<forward name="success" path="/aResult.jsp" />
<forward name="failure" path="/aResult.jsp" />
</action>
约束:
type必须是com.jdon.strutsutil.ModelSaveAction
forward的name值必须是success或failure
CRUD功能实现分离配置
CRUD可以通过两行action配置ModelViewAction ModelSaveAction合并完成,也可以将新增和修改分开配置,例如用户注册功能,用户注册(用户创建)和用户资料修改属于不同的需要分离开的两个过程,用户注册功能是针对新用户,或者说是非注册用户;而用户资料修改是针对注册用户,两者服务对象角色是不一样的,因此,不能象其他Model那样将CRUD合并在一起。
1. 推出创建性页面的配置:
<action name="accountForm" path="/shop/newAccountForm"
type="com.jdon.strutsutil.ModelViewAction" scope="session">
<forward name="create" path="/account/NewAccountForm.jsp" />
</action>
将forward的edit值为空,没有这一行。
2. 接受创建数据并并递交Service服务层处理
<action name="accountForm" path="/shop/newAccount"
type="com.jdon.strutsutil.ModelSaveAction" scope="session"
validate="true" input="/account/NewAccountForm.jsp">
<forward name="success" path="/shop/index.shtml" />
<forward name="failure" path="/shop/newAccountForm.shtml" />
</action>
3. 推出编辑性页面的配置
<action name="accountForm" path="/shop/editAccountForm"
type="com.jdon.strutsutil.ModelViewAction" scope="session">
<forward name="edit" path="/account/EditAccountForm.jsp" />
</action>
将forward的create值为空,没有这一行,不过调用/shop/editAccountForm.shtml形式还是必须要有参数的:/shop/editAccountForm.shtml?action=edit&username=XXX
4. 接受修改后的数据并并递交Service服务层处理
与第2条类似,不同的是path和jsp因为编辑页面不一样而不同:
<action name="accountForm" path="/shop/editAccount"
type="com.jdon.strutsutil.ModelSaveAction" scope="session"
validate="true" input="/account/EditAccountForm.jsp">
<forward name="failure" path="/shop/editAccountForm.shtml" />
<forward name="success" path="/shop/index.shtml" />
</action>
单纯输出Jsp页面
如果有时只是为了输出一个Jsp页面而做一个Action比较麻烦,Jdon框架实现了一个缺省的转发Action,可以简单重用在很多这样场合。只要在struts-config.xml配置如下:
<action path="/XXX" type="com.jdon.strutsutil.ForwardAction"
name="XXX" scope="request"validate="false">
<forward name="forward" path="/xxx.jsp"/>
</action>
上述配置有三点要求如下:
type必须是com.jdon.strutsutil.ForwardAction
forward的name值是forward
Jdon框架的出错信息
在服务层一旦实现数据库操作出错,Jdon框架通过EventModel的setErrors方法向表现层传递出错信息,因此,只要在你的服务层Service实现方法的出错代码调用该方法即可,如:
public void insertOrder(EventModel em) {
Order order = (Order)em.getModel();
try{
orderDao.insertOrder(order);
}catch(Exception daoe){
Debug.logError(" Dao error : " + daoe, module);
em.setErrors("db.error");
}
}
当存储orderDao调用出错,将db.error保存到EventModel中,而db.error是struts的Application.properties中定义的,,需要在你的应用系统中定义,Jdon框架应用到的信息如下:
id.required = you must input id
id.notfound = sorry, not found
db.error=sorry, database operation failure!
system.error=sorry, the operation failure cause of the system errors.
maxLengthExceeded=The maximum upload length has been exceeded by the client.
notImage=this is not Image.
主要有id.required id.notfound db.error等几个,需要在J2EE应用系统中定义。
上一级 首页 下一级
JdonFramework作为一个免费开源软件开发平台,可以商用开发大多数数据库应用软件和管理软件: 电子商务软件 在线教育软件 税务软件 Web快速开发软件 财务软件 购物车软件 医院帐务软件 crm software medical software 人事薪资软件payroll software 在线购物软件 销售软件 项目管理软件 房产不动产管理软件 生产软件 PDM软件 制造业软件 仓库软件 采购软件 进销存软件 危险源监控软件 物流软件 超市软件 银行软件 保险软件 汽车软件 医疗软件 电子软件 自动化软件 服装软件 烟草软件 分销管理软件 供应商管理软件
|