手头有一个JSF的项目(JSF+Facelets+Richfaces), 现在有要求把他变身一下,结合Spring和Hibernate的优势。这个项目虽然不算很大,但是也不是hello word级别的小app,所以还是实在要费一番事。翻新过程记录如下,为有相同需要的人做一个参考。
假定你已经添加了所有的JAR。可以参考我之前的一篇关于dependencies的总结笔记。
1. 在web.xml中添加spring listener
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/spring.xml</param-value>
</context-param>
2. 改faces-config.xml. 在原来的<application> tag里加<el-resolver>
<application>
<view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
这样做的目的是让spring去解析EL expression, 因为以后所有的bean都会是spring bean而不是JSF的managed bean。JSF碰到#{},就会去问这个resolver,然后返回一个spring bean。如此一来,JSF里面,除了Navigation的东西,原来bean的内容就都可以,喀嚓咔嚓,删了!
3. 写Spring的configuration file,我这里名字是Spring.xml。这一步先做基础建设= =||||||.....
先说一下,因为Spring强大的IOC或者叫DI特性,我们实际上可以写很少XML。我在这里将尽可能的不写XML(因为我懒。。。),而是用annotation。为了做到这点,在spring的configuration file中,要加如下东西:
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
......
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
......">
<context:component-scan base-package="tst" /> <!-- tst是我的项目名称-->
.......
</beans>
最重要的当然是context:component-scan这个tag了。这个tag会让你可以很方便在class中直接使用@Component这个annotation去表示这个class是一个bean! 很方便吧!省去很多XML!
这里再介绍一个context的tag:
<context:property-placeholder location="file:conf/tst.properties" />
添加了这个tag之后,就是定义了properties file的位置,之后可以在spring.xml里面使用${some-property}这种方式读取properties文件中的值了。方便!
这里提一句,建议一开始就用Maven打project的架构,否则,再翻新的时候,后来加maven,classpath这种东西容易出问题。本人就是之前没研究过.classpath那个file,后面把一个开始不是maven的项目,生生加上maven后,很多后患。也为此花时间研究了一下classpath。。。建议这种基础东西还是先学学好。文后会有一些有用的链接供参考。
为了使用AOP,一定还要加的就是aspectj啦!所以,再添加一个namespace:
...
xmlns:aop="http://www.springframework.org/schema/aop
...
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
并且加入
<aop:aspectj-autoproxy />
这个autoproxy的好处是,我们可以直接在class里面使用@Autowired啦!又省打很多code...
其实还有一些这个xml的基础建设,但是目前先这样。遇到的后面再加。
4. 狂改Class....= =
在写如何改之前,先说一下我目前这个不怎么好的JSF project的结构(部分省略),和修改的方向。
-----------------------------------------------------------------------------------------------------------------------------------
src/
dao/
均为DAO class,只不pro的简单使用了DBCP
*DAO.java
model/
均为business class,基本上是对应Database里面的每个table的,有少数几个没有对应
*.java
bean/
均为JSF managed bean,这些bean都属于session scope
*Bean.java
service/
均为service layer的class,但是当时做的时候没有深刻体会到service layer如何与dao layer配合,所以会直接传SQL给DAO
*Service.java
connection/
一些帮助建立DB连接的class,这里使用了DBCP
config.xml 关于DBCP需要的一些关于DB的参数
Configuration.java 这个class会parse上面的config.xml,以得到DBCP需要的相关参数
ConnectionManager.java 建立DBCP connection pool
WebContent/
WEB-INF/
lib/ 众所周知的lib folder
templates/ 装facelets的template, 里面的具体file不讲了
faces-config.xml
web.xml
META-INF/
...
...
---------------------------------------------------------------------------------------------------------------
可以看出,目前的架构并不好。改成适合spring的结构,我们真要做一些不小改动。唯一不用变的就是presentation layer的东西。不再需要的class有connection下的,因为将把这一部分链接DB的工作交给Hibernate。OK,先加Hibernate。
1)在spring.xml里面加上如下
:
<beans
......
xmlns:tx="http://www.springframework.org/schema/tx"
......
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<tx:annotation-driven />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${db.driver}" /> <property name="url" value="${db.url}" /> <property name="username" value="${db.username}" /> <property name="password" value="${db.password}" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" /> <property name="configLocation" value="classpath:/hibernate.cfg.xml" /> </bean>
<!
-- hibernate.cfg.xml 是我的hibernate configuration file -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"> </bean>
. ......
</beans>
2)将所有model变成spring bean。因为hibernate要使用这些POJO,我们将每个model加上@Entity,并做适当的configuration.
对于详细的Hibernate Mapping等内容不是本文重点,
这份Hibernate的Documentation还是做得非常不错的
3)将所有dao变成spring bean。用@Repository做annotation
以前在DAO中会链接DB,现在不用费这个事,但是当然还是要连的,不过是用Hibernate。
一点建议:建立一个GenericDAO class, 然后所有DAO都extends它。在这个GenericDAO里面,包括了SessionFactory (用Spring inject进去),还有一些最基础的处理SQL级的function。其他的DAO只要直接使用这些共用的function就可以了。
4)将所有service变成spring bean。用@Component做annotation
之前,我是在managed bean中把model object传递给service object,然后在service object中使用那个business object来创建SQL,再把SQL递交给DAO。这种方式无疑给service layer增加了没必要的负担,因为service layer应该不知道data是如何存储的,只应该负责单纯的business logic才对。所以,现在,把service改成spring bean之后,service 最终会使用DAO (用spring做injection)然后直接得到由hibernate建立好的business model object。以前从result set转到model要人工一点一点的赋值,现在,hibernate把这一切都做了!我们,什么都不用做了.......= =
5)将所有JSF managed bean变成spring bean。用@Component做annotation
基本上,改到这一层,除了添加一些annotation,让spring自动帮我们inject一些东西,大体上改动不大(假设你的service API没有什么改变)。
总结到这里,最基础的更改就大概完成。当然,我只是非常简略的做了一个总结,而且是基于某个项目架构基础上的。但是,就算你原来的JSF不是我的这个架构,也没有犯我之前架构上的问题,可能你的翻新工作会更简单。除了上面介绍的,其实Spring还有一个很重要的特征就是AOP。最常用的应该算LOGGING和TRANSACTION会非常有用。详细的内容可能以后我也会总结一下....可能吧..........= =|||||||
很好,今天的笔记就这么多!欢迎板砖!