您的位置:首页 > 编程语言 > Java开发

JSF+Spring+JPA(Hibernate实现)的环境搭建

2010-06-23 09:24 501 查看
写之前的感受
刘岩
先说好的,文章后再说缺点。
JSF+Spring+JPA以我个人看来,应该说是Struts2+Spring+Hibernate的替代解决方案。
引入JPA去取代或者说包装或者说是升级Hibernate是为了符合JAVA EE的规范,达到ORM统一的结果。下次项目用EJB也好、用TOPLINK也好、用ibatis也罢,我们的开发人员代价会很小。在目前很多项目来说,引入此规范,能更好的代码复用,持久层和控制层相当于进一步的解耦合了,你只需要开启项目之前好好地建立领域模型。
那么用JSF取代Struts2或者更早一点的Struts1又是为何!答案依然是,它是规范。是符合某些标准的规范。不是说Struts2不好,这个因项目而定才行。我个人还是比较推崇apache的Struts2的,当然了,apache的JSF实现和JSF组件也是相当地杠杠的!!!!JSF更贴近事件比较多的web前端处理机制。想想我们一般要接收和处理页面的各种事件是用什么:js函数+ajax处理是吧(Flex我没有接触过,不知道它是怎么样的处理前后台交互的)。JSF可以采用事件监听机制,控件(JSF里面叫做控件)被触发了某些时间,直接优雅的和POJO进行了交互,配合ajax4jsf,处理大量的控件的事件是很简洁方便的。
言归正传,开始。。。
1. 首先利用IDE建立一个Web项目
2. 加入相应的jar包,注意:所有的开源框架都是加入jar包的时候最麻烦,尤其加入了Spring,搞不好就他妈的启动服务的时候报错。我已经将相应需要的jar包放到了csdn上面共享了,网址是http://download.csdn.net/source/2416493。大家可以去下载。
3. web项目加入JSF支持
修改web.xml,加入如下内容
<!--Spring与JSF支持-->
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!--配置JSF-->
<context-param>
<param-name>javax.faces.CONFIG_FILES</param-name>
<param-value>/WEB-INF/faces-config.xml</param-value>
</context-param>

<!--Spring配置文件地址-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/applicationContext.xml</param-value>
</context-param>
<!--客户端管理状态-->
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>

<!—加入facelets 框架支持-->
<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value> /WEB-INF/facelets/tags/arcmind.taglib.xml;/WEB-INF/tomahawk.taglib.xml
</param-value>
</context-param>

<context-param>
<description>指定facelets支持的后缀</description>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>

<!--JSF的ajax配置 AJAX4JSF-->
<filter>
<display-name>Ajax4jsf Filter</display-name>
<filter-name>ajax4jsf</filter-name>
<filter-class>org.ajax4jsf.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>ajax4jsf</filter-name>
<servlet-name>Faces Servlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>

<!—JSF支持-->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>

<!—组件支持-->
<filter>
<description>为正确使用tomahawk组件包而配置</description>
<filter-name>extensionsFilter</filter-name>
<filter-class>org.apache.myfaces.webapp.filter.ExtensionsFilter</filter-class>
<init-param>
<param-name>uploadMaxFileSize</param-name>
<param-value>10m</param-value>
</init-param>
<init-param>
<param-name>uploadThresholdSize</param-name>
<param-value>100</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>extensionsFilter</filter-name>
<url-pattern>*.faces</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>extensionsFilter</filter-name>
<url-pattern>/faces/*</url-pattern>
</filter-mapping>
在WEB-INF下面加入jsf_core.tld、html_basic.tld和tomahawk.taglib.xml文件、新建一个faces-config.xml文件,内容配置如下:
<!--配置facelets-->
<application>
<locale-config>
<default-locale>zh_CN</default-locale>
</locale-config> <view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
</application>

<!—JSF与Spring集成-->
<application>
<variable-resolver>
org.springframework.web.jsf.DelegatingVariableResolver
</variable-resolver>
</application>
再加入facelets框架的标签支持包,整个环境包大致如下图所示:



4. 上面的配置好了,JSF和Spring就集成起来了。下面我们加入JPA支持,并且将JPA和Spring集成起来。
首先加入persistence.xml文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">

<persistence-unit name="JSJDemoPU"
transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>test.vo.Test</class>
<properties>

<!-- Hibernate 方言(只有Hibernate 才需要设置) -->
<property name="hibernate.dialect"
value="org.hibernate.dialect.MySQLDialect" />
<!-- Hibernate 显示调试 SQL -->
<property name="hibernate.show_sql" value="true" />

<!-- Hibernate 格式化sql -->
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="update" />

</properties>
</persistence-unit>

</persistence>

之后建立一个值对象,代码如下:
package mangerTeam.vo;

import java.io.Serializable;
import java.util.Set;

import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

/**
* 运动员实体
*
* @author 刘岩
*/
@Entity
@Table(name = "player")
public class PlayersVO implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", unique = true, nullable = false)
private Integer id;

@Column(name = "name")
private String name;

@ManyToOne(optional=true, fetch = FetchType.LAZY)
@JoinColumn(name = "teamId")
private TeamVO teamVO;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(nullable=false,name = "nationalityId")
private NationalityVO nationalityVO;

@Lob
@Basic(fetch = FetchType.LAZY)
@Column(name = "pic")
private byte[] pic;

@Lob
@Basic(fetch = FetchType.LAZY)
@Column(name = "mess")
private String mess;

@ManyToMany(cascade = CascadeType.REFRESH, fetch = FetchType.LAZY)
@JoinTable(name = "plays_position", joinColumns = { @JoinColumn(name = "playerId") }, inverseJoinColumns = { @JoinColumn(name = "positionId") })
private Set<PositionVO> positions;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Set<PositionVO> getPositions() {
return positions;
}

public void setPositions(Set<PositionVO> positions) {
this.positions = positions;
}

public TeamVO getTeamVO() {
return teamVO;
}

public void setTeamVO(TeamVO teamVO) {
this.teamVO = teamVO;
}

public NationalityVO getNationalityVO() {
return nationalityVO;
}

public void setNationalityVO(NationalityVO nationalityVO) {
this.nationalityVO = nationalityVO;
}

public byte[] getPic() {
return pic;
}

public void setPic(byte[] pic) {
this.pic = pic;
}

public String getMess() {
return mess;
}

public void setMess(String mess) {
this.mess = mess;
}

}
之后写DAO,无论你是用IDE生成的DAO还是自己写的DAO,代码大致如下:
package mangerTeam.dao;

import java.util.HashMap;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import javax.persistence.Query;

import mangerTeam.vo.PlayersVO;

import org.springframework.context.ApplicationContext;
import org.springframework.orm.jpa.JpaCallback;
import org.springframework.orm.jpa.support.JpaDaoSupport;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public class PlayerDAO extends JpaDaoSupport implements IPlayerDAO {
// property constants
public static final String NAME = "name";
public static final String MESS = "mess";
public static final String PIC = "pic";

public void save(PlayersVO entity) {
logger.info("saving Player instance");
try {
getJpaTemplate().persist(entity);
logger.info("save successful");
} catch (RuntimeException re) {
logger.error("save failed", re);
throw re;
}
}

public void delete(PlayersVO entity) {
logger.info("deleting Player instance");
try {
entity = getJpaTemplate().getReference(PlayersVO.class,
entity.getId());
getJpaTemplate().remove(entity);
logger.info("delete successful");
} catch (RuntimeException re) {
logger.error("delete failed", re);
throw re;
}
}

public PlayersVO update(PlayersVO entity) {
logger.info("updating Player instance");
try {
PlayersVO result = getJpaTemplate().merge(entity);
logger.info("update successful");
return result;
} catch (RuntimeException re) {
logger.error("update failed", re);
throw re;
}
}

public PlayersVO findById(Integer id) {
logger.info("finding Player instance with id: " + id);
try {
PlayersVO instance = getJpaTemplate().find(PlayersVO.class, id);
return instance;
} catch (RuntimeException re) {
logger.error("find failed", re);
throw re;
}
}

@SuppressWarnings("unchecked")
public List<PlayersVO> findByProperty(String propertyName,
final Object value, final int... rowStartIdxAndCount) {
logger.info("finding Player instance with property: " + propertyName
+ ", value: " + value);
try {
final String queryString = "select model from PlayersVO model where model."
+ propertyName + "= :propertyValue";
return getJpaTemplate().executeFind(new JpaCallback() {
public Object doInJpa(EntityManager em)
throws PersistenceException {
Query query = em.createQuery(queryString);
query.setParameter("propertyValue", value);
if (rowStartIdxAndCount != null
&& rowStartIdxAndCount.length > 0) {

// 有分页
int rowStartIdx = Math.max(0, rowStartIdxAndCount[0]);

// 开始页
if (rowStartIdx > 0) {
query.setFirstResult(rowStartIdx);
}

// 一页最大记录数目
if (rowStartIdxAndCount.length > 1) {
int rowCount = Math.max(0, rowStartIdxAndCount[1]);
if (rowCount > 0) {
query.setMaxResults(rowCount);
}
}
}
return query.getResultList();
}
});
} catch (RuntimeException re) {
logger.error("find by property name failed", re);
throw re;
}
}

public List<PlayersVO> findByName(Object name, int... rowStartIdxAndCount) {
return findByProperty(NAME, name, rowStartIdxAndCount);
}

public List<PlayersVO> findByMess(Object mess, int... rowStartIdxAndCount) {
return findByProperty(MESS, mess, rowStartIdxAndCount);
}

public List<PlayersVO> findByPic(Object pic, int... rowStartIdxAndCount) {
return findByProperty(PIC, pic, rowStartIdxAndCount);
}

public List<PlayersVO> findAll(final int... rowStartIdxAndCount) {
logger.info("finding all Player instances");
try {
final String queryString = "select model from PlayersVO model";
return getJpaTemplate().executeFind(new JpaCallback() {
public Object doInJpa(EntityManager em)
throws PersistenceException {
Query query = em.createQuery(queryString);
if (rowStartIdxAndCount != null
&& rowStartIdxAndCount.length > 0) {
int rowStartIdx = Math.max(0, rowStartIdxAndCount[0]);
if (rowStartIdx > 0) {
query.setFirstResult(rowStartIdx);
}

if (rowStartIdxAndCount.length > 1) {
int rowCount = Math.max(0, rowStartIdxAndCount[1]);
if (rowCount > 0) {
query.setMaxResults(rowCount);
}
}
}
return query.getResultList();
}
});
} catch (RuntimeException re) {
logger.error("find all failed", re);
throw re;
}
}

/**
* 按条件的复杂查询
*
* @param con
* @param rowStartIdxAndCount
* @return
*/
@SuppressWarnings("unchecked")
public List<PlayersVO> serch(final HashMap<String, Object> conMap,
final String con, final int... rowStartIdxAndCount) {

try {
String queryString = "select model from PlayersVO model WHERE 1=1 ";

if (con != null && !"".equalsIgnoreCase(con)) {
queryString = queryString + con;
}

final String jpql = queryString;

return getJpaTemplate().executeFind(new JpaCallback() {
public Object doInJpa(EntityManager em)
throws PersistenceException {

Query query = em.createQuery(jpql);

for (int i = 0; i < conMap.size(); i++) {
String key = "option" + i;
query.setParameter(key, conMap.get(key));
}

if (rowStartIdxAndCount != null
&& rowStartIdxAndCount.length > 0) {
int rowStartIdx = Math.max(0, rowStartIdxAndCount[0]);
if (rowStartIdx > 0) {
query.setFirstResult(rowStartIdx);
}

if (rowStartIdxAndCount.length > 1) {
int rowCount = Math.max(0, rowStartIdxAndCount[1]);
if (rowCount > 0) {
query.setMaxResults(rowCount);
}
}
}
return query.getResultList();
}
});
} catch (RuntimeException re) {
logger.error("find all failed", re);
throw re;
}

}

/**
* 用JPQL查询计算记录总数
* @return
*/
public Long countNumJPQL(){
logger.info("finding all Team instances");
try {
final String queryString = "select COUNT(model) from PlayersVO model";
return (Long)getJpaTemplate().executeFind(new JpaCallback() {
public Object doInJpa(EntityManager em)
throws PersistenceException {
Query query = em.createQuery(queryString);

return query.getResultList();
}
}).get(0);
} catch (RuntimeException re) {
logger.error("find all failed", re);
throw re;
}
}

public static IPlayerDAO getFromApplicationContext(ApplicationContext ctx) {
return (IPlayerDAO) ctx.getBean("PlayerDAO");
}
}
注意:之所以加入注解:@Transactional,是为了AOP进行事务处理。
配置Spring文件applicationContext.xml,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" xmlns:tx="http://www.springframework.org/schema/tx" default-autowire="byName">

<!--数据源连接池,使用dbcp-->
<bean id="realPoolDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">

<!--基本连接设值-->
<property name="driverClassName" value="org.gjt.mm.mysql.Driver" />
<property name="url"
value="jdbc:mysql://127.0.0.1:3306/jsjdemo?useUnicode=true&characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="root" />

<!--连接池参数设置-->
<property name="maxIdle" value="20" />
<property name="maxWait" value="1000" />
<property name="defaultAutoCommit" value="false" />
<property name="removeAbandoned" value="true" />
<property name="removeAbandonedTimeout" value="120" />

</bean>

<!-- c3p0连接池 -->
<bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="org.gjt.mm.mysql.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/jsjdemo?useUnicode=true&characterEncoding=UTF-8" />
<!-- 当连接池耗尽时候,一次获得连接数-->
<property name="acquireIncrement" value="5" />
<!-- 连接池最大数 -->
<property name="maxPoolSize" value="20" />
<!-- 连接池最小数-->
<property name="minPoolSize" value="5" />
<!-- 用户名-->
<property name="user" value="root" />
<!-- 用户密码-->
<property name="password" value="root"></property>
</bean>

<!--
类似于hibernate的SessionFactory,指定由spring容器Bean,即:LocalContainerEntityManagerFactoryBean
-->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="JSJDemoPU" />
<property name="dataSource" ref="c3p0DataSource" />
</bean>

<!--配置事务-->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<!--支持dao事务注解-->
<tx:annotation-driven transaction-manager="transactionManager" />

<!-- Hibernate使用的SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

<!--数据源配置-->
<property name="dataSource">
<ref bean="c3p0DataSource" />
</property>
</bean>

<!--Spring注入Dao实现-->

<bean id="testDAO" class="test.dao.TestDAO">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<bean id="TeamDAO" class="mangerTeam.dao.TeamDAO">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="PositionDAO" class="mangerTeam.dao.PositionDAO">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="PlayerDAO" class="mangerTeam.dao.PlayerDAO">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="NationalityDAO" class="mangerTeam.dao.NationalityDAO">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
</beans>
5. 之后修改一下faces-config.xml里面的内容。
加入如下内容
<managed-bean>
<managed-bean-name>playersVO</managed-bean-name>
<managed-bean-class>
mangerTeam.vo.PlayersVO
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

<managed-bean>
<managed-bean-name>playerAction</managed-bean-name>
<managed-bean-class>
mangerTeam.action.PlayerAction
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>

<!--从Spring得到的DAO-->
<managed-property>
<property-name>playerDAO</property-name>
<value>#{PlayerDAO}</value>
</managed-property>
<managed-property>
<property-name>playersVO</property-name>
<value>#{playersVO}</value>
</managed-property>
</managed-bean>
这样Spring的DAO就注入了该Action(我还是喜欢叫它Action),至于该Action的代码由于过长,就不在此列出,很简单。无非就是注入DAO,setter和getter呗。
到此JSF+Spring+JPA的环境算是集成起来了,项目代码结构图如下:



JPA的缺点:
必须使用在JDK1.5以上的环境,否则只能望JPA而兴叹。
因为它是标准,还在不断的更新中,所以还是不太成熟,不敢保证之后会有很大的变动。
和Hibernate一样,对于多个表(对象)的联合查询,效率比纯JDBC的执行sql要慢很多。
JSF的缺点:
调试不是很方便。
无论是sun的实现还是apache的实现,都存在比较多的bug。
组件技术不如js开源框架灵活,有点鸡肋的感觉。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: