提供一个整合JSF,Spring, Hibernate(JPA), Facelets, 及Annotation的基础环境。对于刚开始使用这种组合的项目,或许可以参考一下,相信使用以上整合环境的项目还是比较少。我一直很喜欢这种组合,JSF组件式的开发,Spring, Hibernate对BackingBean及数据源的管理,Facelets的模版化技术,以及Annotation都大大简化了开发。
JSF组件的高度封装及高可重用性,使得页面代码在非常简单的情况下快速实现非常复杂的功能。Spring,Hibernate的整合进一步简化了JSF的开发,特别是Annotation的配置使得现在几乎完全不需要去XML中配置Bean这些繁琐的事情,这确实很繁琐,特别是如果再加上配置JSF的导航规则,在开发过程中经常要去碰这些东西,确实很麻烦,又容易出错。所以如果项目允许,还是推荐使用Annotation,并且这也是很多专家推荐的。作为Java5新加入的特性,它确实对开发带来了很大的方便,以前不怎么喜欢,不过现在感觉它很有前途!另一个就是Facelets了,这可是用来替代JSP的视图描述技术,Facelets模版化的威力可是非常强大,虽然不少人认为它的自定义标签功能更强大,具体介绍还是大家网上搜一下吧。下面看一下大概的配置过程,仅供参考,因为网上也有不少类似的教程,所以不作啰嗦,仅取重点。
环境:Netbeans7, Tomcat6.0.18, MySQL5
相关框架:JSF1.2,Spring2.5,Hibernate3(JPA), Facelets, Annotation, MyFaces(附加), QFaces(附加)
1.相关引用的jar包
可以看到引用的jar还是不少,至少加起来有43.2M。最后一个是我自定义的组件包qfaces-1.2.1,刚升级支持Facelets(qfaces在1.2及之前未能够支持Facelets而没有说明,使一些用Facelets的朋友遇到麻烦,这里道歉哦。)
2.web.xml文件配置
2 < web-app version ="2.5" xmlns ="http://java.sun.com/xml/ns/javaee" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" >
3 < context-param >
4 < param-name > com.sun.faces.verifyObjects </ param-name >
5 < param-value > false </ param-value >
6 </ context-param >
7 < context-param >
8 < param-name > com.sun.faces.validateXml </ param-name >
9 < param-value > true </ param-value >
10 </ context-param >
11 < context-param >
12 < param-name > javax.faces.STATE_SAVING_METHOD </ param-name >
13 < param-value > client </ param-value >
14 </ context-param >
15
16 <!-- Config:Facelets -->
17
18 < context-param >
19 < param-name > javax.faces.DEFAULT_SUFFIX </ param-name >
20 < param-value > .xhtml </ param-value >
21 </ context-param >
22
23 <!-- Config:Spring -->
24
25 < servlet >
26 < servlet-name > dispatcher </ servlet-name >
27 < servlet-class > org.springframework.web.servlet.DispatcherServlet </ servlet-class >
28 < load-on-startup > 2 </ load-on-startup >
29 </ servlet >
30 < servlet-mapping >
31 < servlet-name > dispatcher </ servlet-name >
32 < url-pattern > *.htm </ url-pattern >
33 </ servlet-mapping >
34 < listener >
35 < listener-class > org.springframework.web.context.ContextLoaderListener </ listener-class >
36 </ listener >
37 < listener >
38 < listener-class > org.springframework.web.context.request.RequestContextListener </ listener-class >
39 </ listener >
40 < listener >
41 < listener-class > com.sun.faces.config.ConfigureListener </ listener-class >
42 </ listener >
43 < listener >
44 < listener-class > com.sun.faces.application.WebappLifecycleListener </ listener-class >
45 </ listener >
46
47 <!-- Config:MyFaces -->
48
49 < filter >
50 < filter-name > MyFacesExtensionsFilter </ filter-name >
51 < filter-class >
52 org.apache.myfaces.webapp.filter.ExtensionsFilter
53 </ filter-class >
54 < init-param >
55 < param-name > uploadMaxFileSize </ param-name >
56 < param-value > 100m </ param-value >
57 </ init-param >
58 < init-param >
59 < param-name > uploadThresholdSize </ param-name >
60 < param-value > 80k </ param-value >
61 </ init-param >
62 </ filter >
63 < filter-mapping >
64 < filter-name > MyFacesExtensionsFilter </ filter-name >
65 < servlet-name > Faces Servlet </ servlet-name >
66 </ filter-mapping >
67 < filter-mapping >
68 < filter-name > MyFacesExtensionsFilter </ filter-name >
69 < url-pattern > /faces/myFacesExtensionResource/* </ url-pattern >
70 </ filter-mapping >
71
72 <!-- Config:QFaces -->
73
74 < servlet >
75 < servlet-name > QFaces </ servlet-name >
76 < servlet-class > name.huliqing.qfaces.FacesServlet </ servlet-class >
77 </ servlet >
78 < servlet-mapping >
79 < servlet-name > QFaces </ servlet-name >
80 < url-pattern > *.qfaces </ url-pattern >
81 </ servlet-mapping >
82
83 <!-- End -->
84
85 < servlet >
86 < servlet-name > Faces Servlet </ servlet-name >
87 < servlet-class > javax.faces.webapp.FacesServlet </ servlet-class >
88 < load-on-startup > 1 </ load-on-startup >
89 </ servlet >
90 < servlet-mapping >
91 < servlet-name > Faces Servlet </ servlet-name >
92 < url-pattern > *.faces </ url-pattern >
93 </ servlet-mapping >
94 < session-config >
95 < session-timeout >
96 30
97 </ session-timeout >
98 </ session-config >
99 < welcome-file-list >
100 < welcome-file > welcome.jsp </ welcome-file >
101 </ welcome-file-list >
102 </ web-app >
103
这是web.xml,可以看到默认的配置很简单,并没有什么特别的,在网上大都可以看到类似。相关部分都有注识。上面Facelets配置的默认后缀就是xhtml了,这样当我们访问如 test.faces这样的页面时,就会由Facelets的ViewHandler最后解析到test.xhtml。所以我们的页面后缀就需要是.xhtml。另外两个额外的配置MyFaces,QFaces,如果不需要,都可以直接注释掉,不会影响。
3.faces-config.xml
文件位置: WEB-INF/faces-config.xml
2
3 <!-- =========== FULL CONFIGURATION FILE ================================== -->
4
5 < faces-config version ="1.2"
6 xmlns ="http://java.sun.com/xml/ns/javaee"
7 xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
8 xsi:schemaLocation ="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd" >
9 < application >
10 <!-- 国际化支持 -->
11 < locale-config >
12 < default-locale > zh </ default-locale >
13 < supported-locale > zh </ supported-locale >
14 < supported-locale > en </ supported-locale >
15 </ locale-config >
16 < message-bundle > resource </ message-bundle >
17 < resource-bundle >
18 < base-name > resource </ base-name >
19 < var > text </ var >
20 </ resource-bundle >
21 <!-- Facelet, Spring -->
22 < view-handler >
23 com.sun.facelets.FaceletViewHandler
24 </ view-handler >
25 < variable-resolver >
26 org.springframework.web.jsf.DelegatingVariableResolver
27 </ variable-resolver >
28 </ application >
29 </ faces-config >
重点注意Facelets view-handler及Spring variable-resolver的配置就可以。
4.dispatcher-servlet.xml
文件位置:WEB-INF/dispatcher-servlet.xml
< beans xmlns ="http://www.springframework.org/schema/beans"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p ="http://www.springframework.org/schema/p"
xmlns:aop ="http://www.springframework.org/schema/aop"
xmlns:tx ="http://www.springframework.org/schema/tx"
xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" >
< bean class ="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />
< bean id ="urlMapping" class ="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" >
< property name ="mappings" >
< props >
< prop key ="/index.htm" > indexController </ prop >
</ props >
</ property >
</ bean >
< bean id ="viewResolver"
class ="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix ="/WEB-INF/jsp/"
p:suffix =".jsp" />
< bean name ="indexController"
class ="org.springframework.web.servlet.mvc.ParameterizableViewController"
p:viewName ="index" />
</ beans >
这也是Spring的默认配置
5.applicationContext.xml
文件位置:WEB-INF/applicationContext.xml
< beans xmlns ="http://www.springframework.org/schema/beans"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p ="http://www.springframework.org/schema/p"
xmlns:aop ="http://www.springframework.org/schema/aop"
xmlns:tx ="http://www.springframework.org/schema/tx"
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/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd" >
< aop:aspectj-autoproxy />
< context:annotation-config />
< context:component-scan base-package ="name.huliqing.magic" />
< bean id ="propertyConfigurer" class ="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >
< property name ="location" value ="classpath:jdbc.properties" />
</ bean >
< bean id ="_data_source" class ="org.springframework.jdbc.datasource.DriverManagerDataSource" >
< property name ="driverClassName" value ="${jdbc.driverClassName}" />
< property name ="url" value ="${jdbc.url}" />
< property name ="username" value ="${jdbc.username}" />
< property name ="password" value ="${jdbc.password}" />
</ bean >
< alias name ="_data_source" alias ="dataSource" />
< bean id ="entityManagerFactory" class ="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >
< property name ="persistenceUnitName" value ="SpringJPADbUnit" />
< property name ="dataSource" ref ="dataSource" />
< property name ="jpaVendorAdapter" >
< bean class ="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" >
< property name ="databasePlatform" value ="${jdbc.dialect}" />
< property name ="showSql" value ="${jdbc.showSql}" />
< property name ="generateDdl" value ="${jdbc.generateDdl}" />
</ bean >
</ property >
</ bean >
< bean id ="jDialect" class ="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
< bean id ="transactionManager" class ="org.springframework.orm.jpa.JpaTransactionManager" >
< property name ="entityManagerFactory" ref ="entityManagerFactory" />
< property name ="dataSource" ref ="dataSource" />
< property name ="jpaDialect" ref ="jDialect" />
</ bean >
< tx:annotation-driven transaction-manager ="transactionManager" />
</ beans >
<aop:aspectj-autoproxy/> 提供对AspectJ的支持
<context:annotation-config/> 提供对annotation的支持
<context:component-scan base-package="name.huliqing.magic"/> 指定需要被Spring进行扫描的类包,base-package下的类及子包都会被扫描以提供依赖注入,注意修改为自己的包名。
<tx:annotation-driven transaction-manager="transactionManager"/> 对Annotation进行事务管理的支持。
其它定义的一些bean主要是对数据源的配置,更详细的信息请查阅相关的资料。
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"/>
</bean>
注意这里指定了数据源配置文件的位置classpath:jdbc.properties.
6.jdbc.properties
文件位置 classpath:jdbc.properties
jdbc.driverClassName = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql: // localhost:3306/magic?characterEncoding=UTF-8
jdbc.username = root
jdbc.password =
jdbc.showSql = false
jdbc.generateDdl = false
上面是jdbc文件的配置内容,下面显示了文件的位置,同时显示了Spring的两个配置文件的位置。
上面提供了对数据库的连接信息,数据库magic,用户root,密码空。基本上JSF+Spring+Hibernate+Facelets就是这个配置了。
下面为了测试环境,将在magic库中创建一个数据表test,并创建一些相应的类,进行测试一下。
7.测试环境
首先创建一个数据表magic.test
CREATE database IF NOT EXISTS magic DEFAULT charset utf8 COLLATE utf8_general_ci;
use magic;
create table magic.test (
num int not null auto_increment,
id varchar ( 32 ) not null ,
password varchar ( 64 ) not null ,
des varchar ( 64 ) not null ,
primary key (num)
) engine = InnoDB default charset = utf8;
接下来将创建以下东东:
Dao.java - Dao接口:
DaoBase.java - Dao基类,实现Dao.java的接口
TestDa.java - Dao,继承DaoBase.java
TestEn.java - Entity,持久化类,对应数据表magic.test
TestSe.java - Service,业务逻辑层
TestWe.java - BackingBean
test.xhtml - 测试页面
下面是目录结构,因为这是测试,所以我并没有把它们放在相应的目录。其它几个类可以不管。
下面是各个类的代码:
TestEn.java
import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.Table;
@Entity
@Table(name = " test " )
@NamedQueries({})
public class TestEn implements Serializable {
private static final long serialVersionUID = 1L ;
@Id
@GeneratedValue
@Basic(optional = false )
@Column(name = " num " )
private Integer num;
@Basic(optional = false )
@Column(name = " id " )
private String id;
@Basic(optional = false )
@Column(name = " password " )
private String password;
@Basic(optional = false )
@Column(name = " des " )
private String des;
public TestEn() {
}
public TestEn(Integer num) {
this .num = num;
}
public TestEn(Integer num, String id, String password, String des) {
this .num = num;
this .id = id;
this .password = password;
this .des = des;
}
public Integer getNum() {
return num;
}
public void setNum(Integer num) {
this .num = num;
}
public String getId() {
return id;
}
public void setId(String id) {
this .id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this .password = password;
}
public String getDes() {
return des;
}
public void setDes(String des) {
this .des = des;
}
@Override
public int hashCode() {
int hash = 0 ;
hash += (num != null ? num.hashCode() : 0 );
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if ( ! (object instanceof TestEn)) {
return false ;
}
TestEn other = (TestEn) object;
if (( this .num == null && other.num != null ) || ( this .num != null && ! this .num.equals(other.num))) {
return false ;
}
return true ;
}
@Override
public String toString() {
return " name.huliqing.magic.domain.TestEn[num= " + num + " ] " ;
}
}
这个Entity是Netbeans通过数据表magic.test生成的代码,相关的注解都看到了,不明白的可以查阅一下相关资料
接口Dao.java
import java.io.Serializable;
public interface Dao < T, PK extends Serializable > {
public T save( final T t);
public T update( final T t);
public void delete( final T t);
public T find( final PK id);
}
基类:BaseDao.java
import java.io.Serializable;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import javax.persistence.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTemplate;
public class DaoBase < T, PK extends Serializable > implements Dao < T, PK > {
protected Class < T > type;
protected JpaTemplate jpaTemplate;
protected EntityManagerFactory entityManagerFactory;
protected DriverManagerDataSource dateSource;
public DaoBase(Class < T > type) {
this .type = type;
}
@PersistenceUnit
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
this .entityManagerFactory = entityManagerFactory;
this .jpaTemplate = new JpaTemplate(entityManagerFactory);
}
@Autowired
public void setDataSource(DriverManagerDataSource dateSource) {
this .dateSource = dateSource;
}
public T save(T t) {
this .jpaTemplate.persist(t);
this .jpaTemplate.flush();
return t;
}
public T update(T t) {
this .jpaTemplate.merge(t);
this .jpaTemplate.flush();
return t;
}
public void delete(T t) {
T _o = this .jpaTemplate.merge(t);
this .jpaTemplate.remove(_o);
this .jpaTemplate.flush();
}
public T find(PK id) {
return (T) this .jpaTemplate.find(type, id);
}
public List < T > findByObject(T t, String

EntityManagerFactory emf = this .jpaTemplate.getEntityManagerFactory();
EntityManager em = emf.createEntityManager();
Query q = DaoQueryMake.makeQuery(em, t, fuzzy);
List < T > result = q.getResultList();
return result;
}
}
Dao.java, DaoBase.java都使用了泛型,
Dao.java主要定义了相关的基本接口,
DaoBase.java主要提供了Spring对数据源的注入及管理,同时实现了Dao.java的接口,这样其它Dao只要继承自DaoBase.java就可以毫不费劲的获得几个很基本的功能:save, update, delete, find
测试类Dao: TestDa.java
import name.huliqing.magic.dao. * ;
import org.springframework.stereotype.Component;
@Component
public class TestDa extends DaoBase{
public TestDa() {
super (TestEn. class );
}
}
测试类Service: TestSe.java
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class TestSe {
@Autowired
private TestDa testDa;
@Transactional
public TestEn save(TestEn testEn) {
return (TestEn) testDa.save(testEn);
}
@Transactional
public TestEn update(TestEn testEn) {
return (TestEn) testDa.update(testEn);
}
@Transactional
public void delete(TestEn testEn) {
testDa.delete(testEn);
}
public List<TestEn> findByObject(Object o, String... fuzzy) {
return testDa.findByObject(o, fuzzy);
}
}
测试类Backing: TestWe.java
import name.huliqing.magic.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope( " request " )
public class TestWe implements java.io.Serializable{
@Autowired
private TestSe testSe;
private TestEn testEn;
public TestWe() {
this .testEn = new TestEn();
}
public TestEn getTestEn() {
return testEn;
}
public void setTestEn(TestEn testEn) {
this .testEn = testEn;
}
public void save() {
TestEn _testEn = testSe.save(testEn);
if (_testEn != null ) {
Message.addInfoMessage( " 注册成功 " );
}
}
}
看一下几个Test类,主要用到几个注解:@Component @Autowired @Transactional
@Component 标明了获得Spring管理的Bean, 默认名称为类名的首字母小写,主要注意Component的保存scope。
@Autowired 实现Bean的快速注入。
@Transactional,通过这个注解,方法将自动获得事务支持。
下面是测试页面:test.xhtml
2 xmlns:h ="http://java.sun.com/jsf/html"
3 xmlns:f ="http://java.sun.com/jsf/core"
4 xmlns:t ="http://myfaces.apache.org/tomahawk"
5 xmlns:ui ="http://java.sun.com/jsf/facelets"
6 template ="/WEB-INF/layout/template.xhtml" >
7 < ui:define name ="content" >
8 < ui:insert name ="messages" >
9 < h:messages globalOnly ="true" showDetail ="true" infoClass ="colorGreen" errorClass ="colorRed" fatalClass ="colorOrange" />
10 </ ui:insert >
11 < h:form >
12 < h:panelGrid columns ="3" styleClass ="border" >
13 < h:outputText value ="用户ID" />
14 < h:inputText id ="id" value ="#{testWe.testEn.id}" />
15 < h:outputText value ="请填写你的ID" />
16
17 < h:outputText value ="设置密码" />
18 < h:inputSecret id ="password" value ="#{testWe.testEn.password}" />
19 < h:outputText value ="建议由字母与数字混合组成" />
20
21 < h:outputText value ="个人说明" />
22 < h:inputTextarea id ="des" value ="#{testWe.testEn.des}" />
23 < h:outputText value ="个人的一些备注" />
24
25 < h:panelGroup />
26 < h:commandButton value ="申请" action ="#{testWe.save}" />
27 < h:panelGroup />
28 </ h:panelGrid >
29 </ h:form >
30 </ ui:define >
31 </ ui:composition >
关于Facelets视图技术,不明白的请查阅相关的资料,下面是最终测试结果。
以上整合配置有经过实际正式上线项目验证,如果你觉得有什么错漏,请多多指教。
1.示例源码下载,没带jar,需要自己去下载上面所说的相关jar包。(94K)
http://www.blogjava.net/Files/huliqing/Magic-JSH-Facelets-Annotation.rar
2.示例源码下载,完整版,包含所有相关jar,不过网盘可能不够稳定。(38M)
http://cid-1c243f9a849aade7.skydrive.live.com/self.aspx/.Public/Magic/Magic%7C5JSF+Spring+Hibernate+Facelets+Annotation%7C6.rar
huliqing
huliqing@live.com