??xml version="1.0" encoding="utf-8" standalone="yes"?>
视图层主要由JSP|页构成Q此外还包括Resource Bundle资源文g及ActionForm Bean、Validation{,q些lg提供对国际化、接收用戯入的表单数据、表单验证和错误处理{的支持?br> 与User的视囑ֱ有关的文件有Q?br> userList.jspQ用户列表页面,用于h理权限的用户对其他用户的管理?br> userForm.jspQ用户信息页面,用于对用户信息的增、删、改
UserForm.javaQ与用户信息表单对应的ActionForm Bean
validation.xmlQ对用户信息表单q行验证的配|文?br> Resource Bundle资源文gQ中文的是ApplicationResource_Zh_cn.properties
default.jspQ用于复合网늚sitemesh文g
JavaScript、CSS文g
2. JSP面
与用L关的JSP面包括用户列表和用户信息。head及foot{通用信息攄在head.jsp、foot.jsp中,因此userList.jsp及userForm.jsp只包含与业务相关的标{。下面介l主要的标签功能Q?br>
<logic:messagesPresent>Q判断指定的消息是否存在。若指定message属性ؓtrueQ则从request范围?
索属性key为Globals.MESSAGE_KEY的ActionMessages对象。若不指定属性,则默认检索属性key?
Globals.ERROR_KEY的ActionMessages对象。在本系l中一个检索Success消息Q一个检索Error消息?br> <fmt:message>QJSTL标签。用于输出Resource Bundle中的一条消息?br>
<bean:struts>Q用于检索Struts框架内在的对象,如ActionFormBean、ActionForward?
ActionMapping。在q里用于在JSP面上定义一个ActionForward
变量以方便其它地方的引用。forward为struts-config.xml中定义的global-forward?br> <c:set>QJSTL标签。用于定义一个变量,以方便其它地方的引用?br> <c:out>QJSTL标签。用于在面上显CZ个EL表达式的|如显C?lt;c:set>定义的变量。EL是JSTL采用的简单的表达式语aQ该语言提供一个访问和操作应用E序数据的简单方式?br> <c:if><c:when><c:forEach><c:choose>QJSTL标签。用于处理条件的标记Q根据特定的逻辑条g来控制输出网内容,或者@环遍历集合中的所有元素?br> <display>QDisplay Tag的标{,用于昄控制层返回的List。可以方便的定制表格是否分页、对列排序、导出数据等?br> <html:form>Q用来定义HTML表单。Struts的HTML标签可以和标准的HTML元素完成相同的功能,Struts框架能够把表单中的数据自动映到相应的ActionForm Bean中?br> <html:text><html:password><html:hidden>Q在表单上生成相应的HTML元素?br>
<html:submit><html:cancel>Q在表单上生成提交按钮和取消按钮。当用户按下按钮Ӟ生一个提交事
件或取消事gQ由ActioncL莗本pȝ?lt;html:submit><html:cancel>的属性相同(均ؓ
methodQ,用户按下提交按钮或取消按钮后执行哪个Ҏ由lookupMethods.properties军_?br> <html-el:multibox>Q在表单上生成HTML的CheckBox标签。html-el使用了JSTL扩展Q可以用EL表达式?br>
<html:messages><html:errors>Q用于在|页中输出消息?lt;html:errors>?
于输出错误消息,本系l中用于昄表单中字D的错误信息,<html:messages>昄全局的消息?br> 自定义标{:
在你最初运行ant newӞAppFuse׃Ҏ你键入的目名自动生成一个标{文Ӟ在userForm.jsp中你会看到这个标{?br> <YOURAPPNAME:label>Q它用于昄表单输入域前的提C文本,Ҏ本添加了一些特别的样式Q如在必填项前自动加"*"L?br> <YOURAPPNAME:country>QuserForm中有讄国家一,该标{于显C国家的下拉列表?br> <YOURAPPNAME:constants>Q用于在面上显C常量类org.appfuse.Constants中的帔R的倹{?/p>
3. ActionForm Bean
ActionForm
Bean是Struts提供的表单数据传输对象,用于在视囑ֱ和控制层之间传递HTML表单数据。控制层可以从ActionForm
Bean中读取用戯入的表单数据Q也可以把来自模型层的数据存攑ֈActionForm Bean中,然后把它q回l视图?br>
User表单的ActionForm
Bean为UserForm。UserForml承BaseForm。BaseForm是ActionForm的子cd象,扩展了三个通用ҎQ?
toString()、equals(Object o)
和hashCode()。ƈ定义了一个验证,用于允许用户在点?删除"?取消"按钮时表单无验证?br> UserForm中定义了与用户信息表单中的字D对应的属性?/p>
4. Validator验证框架
Validator验证框架负责数据验证Q采用基于XML的配|文件来配置验证规则。其相关的文件有Q?br> validation.xmlQ针对具体的Struts表单QؓActionForm配置所需的验证规则?br> validator-rules.xmlQ框架自带文Ӟ包含了一l通用的验证规则?br>
validator-rules-custom.xmlQ自定义验证规则。本pȝ中定义了验证两个指定的输入域值是否相{的规则。用于验证密码和认密码
是否相等。其实将q个ҎE微修改一下,?#8220;=”变ؓ“<?gt;”可以验证一个域不能大于/于另外一个域Q非常的实用?br> Resource BundleQ定义验证失败时昄的提C文本。Resource Bundle 中以errors为前~的Keyl大部分用于Validator的错误提C?br> 下面是在validation.xml 中配|的userForm验证规则
<form name="userForm">
<field property="username"
depends="required">
<arg0 key="userForm.username"/>
</field>
……………………………
</form>
该配|通过depends="required"定义了userForm的username字段即用户名是必填项?br>
<arg0 key="userForm.username"/>声明了该字段所对应的文本在Resource
Bundle中的Key。Validator会在Resource Bundle中寻找errors.required对应的文本:'{0}'
为必填项Q将userForm.username对应的文本带入{0}。如用户没有填写该项QValidator会提C?#8220;'用户? 为必填项”的消息?br> validation.xml中用正则表辑ּ定义了一些简单的全局的规则,如电话号码的格式{?br> 默认情况下,Validator框架在Web服务器端执行表单验证。validator-rules.xml里已l定义了客户端JavaScript的生成规则,可以在JSP|页中生成JavaScript脚本。需要进行客L验证Ӟ在JSP中包含:
<html:javascript formName="userForm" cdata="false"
dynamicJavascript="true" staticJavascript="false"/>
<script type="text/javascript"
src="<c:url value="/scripts/validator.jsp"/>"></script>
q在<html:form>中定义onsubmit事gQ?br> onsubmit="return validateUserForm(this)"
在userForm表单的提交和取消按钮中包含了onclick="bCancel=false"事g。bCancel是Validator定义的是否进行验证的变量。当用户点击删除或取消按钮时Q表单无验证,此时bCancel= true?/p>
AppFuse实现的最主要的功能是对用L理。下面就以对用户的管理来说明一下AppFuse控制器的实现?/p>
与用户信息表单数据相关的FormBean是UserForm。UserForm用来存放用户的基本信息?br> UserForm的控制器是org.appfuse.webapp.action.UserAction。UserActionl承? BaseAction。BaseAction也是pȝ中几乎所有Actioncȝ父类Q它l承自Struts提供的DispatchActionQƈ提供 了控制层通用的方法?/p>
2. Action
Action是用戯求和业务逻辑之间的桥梁,每个Action充当客户的一业务代理。主要完成以下Q务:
1. 接收用户h?br> 2. Ҏ用户hQ调用合适的模型lg来执行相应的业务逻辑?br> 3. 获取业务逻辑执行l果
4. Ҏ当前状态以及业务逻辑执行l果Q选择合适的视图lgq回l用戗?/p>
3. DispatchAction
org.apache.struts.actions.DispatchAction是org.apache.struts.action.Action的子cR?br> Action的execute()Ҏ是调用模型的业务ҎQ完成用戯求的业务逻辑Q然后根据执行结果把h转发l其它合适的Weblg。通常Q在一个ActioncM只能完成一U业务操作(通过execute()ҎQ?br> DispatchAction允许用户完成一个业务逻辑所需要的q箋动作和相兛_作集中于一个ActioncM。无覆盖execute()ҎQ而是可以创徏一些实现实际业务操作的ҎQ用户通过methodh参数指定所需要用的Ҏ?/p>
4. BaseAction
BaseAction中实Cpȝ中Action子类需要用到的通用ҎQ主要有Q?br> 1. public Object getBean(String name):通过dSpring的applicationContext-service.xml配置文g来创建实例从而实?#8220;依赖注入”的方法?br> 2. public ActionMessages getMessages(HttpServletRequest request)Q初始化Struts的ActionMessagesQƈq回?br> 3. protected Object convert(Object o) QPOJO与FormBean之间的{换方法?br> 4. execute()Q置换了原始的execute()Ҏ。作用是Ҏh的urlL相关的业务方法(没有methodh参数Ӟ。例如请求的面是editUser.html,则执行edit()Ҏ?br> 5. protected ActionForm getActionForm(ActionMapping mapping, HttpServletRequest request)Q在mapping范围内得C个Action FormBean?br> 6. protected User getUser(HttpSession session) Q从Session中拿到当前登录用户信息?br>
7. protected void updateFormBean(ActionMapping
mapping, HttpServletRequest request, ActionForm form)Q在指定的范围内更新当前Action
所对应的Form Bean对象?br> 8. protected void removeFormBean(ActionMapping mapping, HttpServletRequest request)Q去除无用的Form Bean?nbsp;
5. UserAction
UserAction是用h据管理的控制器,提供了对用户数据的添加、修攏V删除、查询等操作的控Ӟ其包含的业务Ҏ有:
1. add()Q进入添加用户页面?br> 2. cancel()Q当用户在表单中点击“取消”按钮Ӟ执行该方法。如果用h通过用户列表q入该表单,卛_前用于拥有管理其它用L权限Q返回到用户列表Q否则返回到主页面?br> 3. delete()Q根据请求的用户ID调用业务层的removeUser ()Ҏ删除相应的记录,q回到用户列表?br>
4. edit()Q首先校验用戯求的URL是否为editProfile.htmlQ若是,表示当前d用户要查看自q信息Q此时请求\径中不应?
含有用户IDQ用户ID从Session中取得)或用于标识请求是通过用户列表的from参数Q如果含有这两个参数Q发?#8220;无权?#8221;的错误信息。若不是Q?
表示当前用户是通过用户列表q行h。根据请求的用户ID调用业务层的getUser ()Ҏ取得相应的记录。更新相应的FormBean?br>
5. save()Q当需要要d或修改用户信息时Q执行该Ҏ。首先校验请求参C是否?#8220;encryptPass”qgؓ“true”Q若是,表示?
码需要加密,随即密码加密。然后调用业务层的getRole ()Ҏ提交的用户权限持久化。调用业务层的saveUser
()ҎQ保存用户信息。如果用L辑的是自q信息Q更新Session中的当前d用户信息。如果用户在d旉择?#8220;C?#8221;Q更C存的
Cookie。如果用L辑的是其它用L信息Q根据version判断是新L据还是修Ҏ据,在ActionMessages中存储不同的消息Q返?
到添?修改用户信息面。若是新L据,调用sendNewUserEmail()l新用户发送一Email?br> 6. search()Q具有管理权限的用户q入用户列表时执行该Ҏ。调用业务层的getUsers ()ҎQ取得包含所有用户信息的List。返回到用户列表面?br> 7. unspecified()Q如果请求的url没有包含method参数Q通过BaseAction的execute()Ҏ也找不到指定的方法时Q执行该Ҏ。在该方法中转到search()Ҏ?br> 以上是很多Action需要用到的基本的方法?br> 8. sendNewUserEmail()Q根据FormBean中的内容l用户发送一Email?br> 9. checkForCookieLogin()Q如果用h通过CookiedQ用户在d旉择?#8220;C?#8221;Q,发出一个消息警告用户不能修改密码?br>
Ҏ久化数据的访问基于DAOQData Access ObjectQ模式实现。DAO模式提供了访问关pd数据库系l所需的所有接口操作的接口。DAO模式底层数据访问操作与高层业务逻辑分离开Q对上层提供面向对象的数据访问接口?/p>
Model层与User相关的类有:
POJOQ?br> UserQ管理员表的业务对象?br> 业务层:
UserManagerQ业务层接口Qؓ控制层所调用?br> UserManagerImplQ业务层接口的实玎ͼ调用持久层接口?br> 持久层:
UserDAOQ持久层接口Qؓ业务层实现所调用?br> UserDAOHibernateQ持久层接口的实现?br> XML配置文gQ?br> applicationContext-service.xmlQ业务层接口的配|文件?br> applicationContext-hibernate.xmlQ持久层接口的配|文件?/p>
3.3.2 Spring的IoC
IocQInversion of ControlQ即反{控制。Ioc模式即Dependency Injection模式是依赖注的意思,也就是将依赖先剥,然后在适当时候再注射q入?br>
Spring的轻量的bean容器Z务对象(business objectsQ、DAO对象和资源(如:JDBC数据源或者Hibernate
SessionFactorie{)对象提供了IoCcd的装配能力。Spring使用一个xml格式的应用配|文件ؓ开发者提供了一U通过解析定制的属
性文件来手动理单实例对象或者工厂对象的选择性。由于Spring非入R性做Z个重要的目标Q因此可以由Spring配置理的bean对象均不需
要依赖Spring自有的接口和cd可以通过它们的bean属性完成配|?br> 实C来讲Spring采取了配|文件的形式来实C赖的注射Qƈ且支持Type2 IOCQSetter InjectionQ以及Type3 IOCQConstructor InjectionQ?
在Model层,使用Spring提供的Setter Injection(type2)注入方式。以UserZQ下面是其用法?br> 在applicationContext- hibernate.xml中定?br> <bean id="userDAO" class="org.appfuse.dao.hibernate.UserDAOHibernate">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>
在UserManagercM有一句:
public void setUserDAO(UserDAO dao);
q就是一个DAO Object讄ҎQ注器Q。UserDAO被调用Q和持久层通信。以q种方式创徏UserDAO的实例,同样辑ֈ了由UserManager创徏UserDao的目的。避免了直接实例化UserDAO的实现而业务层和持久层紧密耦合?br>
在控制层调用业务层方法时Q用服务定位器q回lSpring contextQSpring的BeanFactory提供了getBeanҎ。BeanFactory是一个通用的FactoryQ它使对象能够按名称获取Qƈ且能理对象之间的关pR?br> 在applicationContext-service.xml中配|?br> <bean id="userManager" parent="txProxyTemplate">
<property name="target">
<bean class="org.appfuse.service.impl.UserManagerImpl">
<property name="userDAO"><ref bean="userDAO"/></property>
</bean>
</property>
</bean>
在控制层BaseAction定义通用ҎQ?
private static ApplicationContext ctx = null;
public Object getBean(String name) {
if (ctx == null) {
ctx = WebApplicationContextUtils
.getRequiredWebApplicationContext(servlet.getServletContext());
}
return ctx.getBean(name);
}
在UserAction中创建UserManager的实例:
UserManager mgr = (UserManager) getBean("userManager");
q样Q通过BeanFactory的getBeanҎQ以及xml配置文gQ避免了在UserActioncM直接实例化UserManagerQ消除了控制层与业务层及业务层与持久层之间的耦合Q实C依赖的注?br> ApplicationContext 是BeanFactory的子接口Qؓ下列东西提供支持Q?
信息查找Q支持着国际?
事g机制Q允许发布应用对象以及可选的注册以接收到事g
可移植的文g和资源访?
3.3.3 Spring的事务管?br> 在数据持久层的杰A献,可能是Spring最为闪亮的优点?br>
Spring提供了通过容器的集U式参数化事务机Ӟ实现事务的外部管理。容器管理的参数化事务ؓE序开发提供了相当的灵zL,同时因ؓ事务委托给容器
q行理Q应用逻辑中无需再编写事务代码,大大节省了代码量Q特别是针对需要同时操作多个事务资源的应用Q,从而提高了生率?br> AppFuse在applicationContext-service.xml文g中进行了对事务的配置
<bean id="txProxyTemplate" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
q里定义了一个名为txProxyTemplate的TransactionProxyFactoryBean服务。它对包含实际数据逻辑的持久层对象q?
行了事务的封装。在q里Q通过transactionAttributes属性,我们指定了事务的理{略Q即所有的名称以save和remove开?
的方法纳入事务管理范围。如果此Ҏ中抛出异常,则Spring当前事务回滚,如果Ҏ正常l束Q则提交事务?br> 而对所有其它方法则以只ȝ事务处理机制q行处理。设为只d事务Q可以持久层尝试对数据操作q行优化Q如对于只读事务Hibernate不执行flush操作Q而某些数据库q接池和JDBC 驱动也对只读型操作进行了特别优化?br> 如果有其他的Ҏ需要进行写数据库操作,可以在相应的Manager配置中声明。如在UserManager中,添加了属?br> <property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
<prop key="*LoginCookie">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
q样Q以LoginCookiel尾的方法也可以写数据库了?br> Spring可以Q意Java Class U_事务理Q而无需对其q行M修改Q因此我们的cd能完全不知道它正在被q行事务理?/p>
3.3.3 SpringQHibernate操作持久?br> Spring对Hibernate有很好的支持?br>
Hibernate中通过SessionFactory创徏和维护Session。Spring对SessionFactory的配|进行了整合Q无需?
通过Hibernate.cfg.xml对SessionFactoryq行讑֮。SessionFactory节点的mappingResources
属性包含了映射文g的\径,list节点下可配置多个映射文g。hibernateProperties节点则容U了所有的属性配|。可以对应传l的
Hibernate.cfg.xml文gl构对这里的SessionFactory配置q行解读?br> 下面是HibernateSessionFactory ?HibernateTransactionManager的配|:
在applicationContext-hibernate.xml中:
<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="dataSource"><ref bean="dataSource"/></property>
<property name="mappingResources">
<list>
<value>com/mycompany/model/User.hbm.xml</value>
……………………………
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">@HIBERNATE-DIALECT@</prop>
<!--prop key="hibernate.show_sql">true</prop-->
<!--prop key="hibernate.hbm2ddl.auto">update</prop-->
</props>
</property>
</bean>
Spring 提供了一?
HibernateTransactionManagerQ采用面向Hibernate的TransactionManager实现Q?
org.springframework.orm.hibernate.HibernateTransactionManager。他用线E捆l了一?
Hibernate SessionQ用它来支持transactions?br> <bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>
sessionFactory Bean引用了HibernateSessionFactoryQ而transactionManager
Bean引用了HibernateTransactionManage?transactionManager
Bean中有个sessionFactory属性?HibernateTransactionManager有个sessionFactory
setter ?getterҎQ用来在Spring启动的时候实?#8220;依赖注入” Qdependency injectionQ的?
在sessionFactory 属性里引用sessionFactory Bean。这两个对象在Spring容器初始化后pl装了v来了?br>
User使用一个TransactionProxyFactoryBeanQ它定义了一个setTransactionManager()。能很方便的?
理申明的事物q有Service Object。TransactionProxyFactoryBean q有个setter.
q会被Business service objectQUserManagerQ引用,
UserManager定义了业务层Qƈ且它q有个属性,由setUserDAO()引用?/p>
pȝ持久层中所有的c都l承自Spring提供的HibernateDaoSupportc,HibernateSupport实现?
HibernateTemplate和SessionFactory实例的关联。HibernateTemplate对Hibernate
Session操作q行了封装,提供了一个简单的方式实现了Hibernate-based
DAO对象。借助HibernateTemplate我们可以q每次数据操作必须首先获得Session实例、启动事务、提?回滚事务以及烦杂?
try/catch/finally的繁琐操作。一个简单的Hibernate讉KҎ完全解决了些麻?
无论是在多个DAO接口q是在多方事务的情况下,Spring使得多种DAO对象无缝地协同工作?br> 对于单的单步的动作,象find,
load,
saveOrUpdate或者delete的调用,HibernateTemplate提供更ؓ便利的选择以代替象一行的回调的执行。此?
HibernateDaoSupportcL供了setSessionFactoryҎ来接受一个SessionFactoryQ同时提供了
getSessionFactory和getHibernateTemplateҎ供其l承cM用。将q些l合hQ允许对于典型的需求给Z非常?
的DAO实现Q如获得所有用LҎQ?br> public List getUsers(User user) {
return getHibernateTemplate().find("from User u order by upper(u.username)");
}