Struts-Spring-Hibernate集成
6.6.1环境搭建和基本配置
我们在Eclipse中可以增加对Struts2.0, Spring2.0, Hibernate3.1的支持,具体如下:
1. 搭建简单的Struts2 Web工程
1) 下载和安装Struts2框架
在此下载最新的struts-2.0.11-all完整包,里面包括apps(示例)、docs(文档)、j4(struts2支持jdk1.4的jar文件)、lib(核心类库及struts2第三方插件类库)、src(源代码)。
2) 创建web工程,添加jar包
将下载资源包中lib下的struts2-core-2.0.11.jar、xwork-2.0.4.jar和ognl-2.6.11.jar(三个为必须jar包)添加,就可以开发应用,但是会有错误消息。添加commons-logging-1.04.jar和freemarker-2.3.8.jar就不会报错。
3) 编辑web.xml文件,配置struts2的核心Filter
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Struts 2.0 Hello World</display-name>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
</web-app>
4) 写用户请求jsp
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<html>
<head>
<title>登陆页面</title>
</head>
<body>
<form action="Login.action" method="post">
<table align="center">
<h3>用户登陆</h3>
<tr align="center">
<td>用户名:<input type="text" name="username"/></td>
</tr>
<tr align="center"><td>密 码:<input type="text" name="password"/></td></tr>
<tr align="center">
<td colspan="2"><input type="submit" value="提交"/><input
type="reset" value="重置"/></td>
</tr>
</table>
</form>
</body>
</html>
5) 写Action类
package com.ascent.struts2.action;
public class LoginAction {
private String username;
private String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String execute(){
if(getUsername().equals("liang")&& getPassword().equals("liang")){
return "success";
}
return "error";
}
}
6) 在src下写struts.xml
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="struts2_helloworld" extends="struts-default">
<action name="Login" class="com.ascent.struts2.action.LoginAction">
<result name="error">/error.jsp</result>
<result name="success">/welcome.jsp</result>
</action>
</package>
</struts>
7) 添加error.jsp和welcome.jsp
8) 部署和启动,进行测试。
注意:TOMCAT 5。5有警告,说的是
警告: Settings: Could not parse struts.locale setting, substituting default VM locale)
要解决也不难,创建struts.properties这个文件,放在src目录下就可以了
struts.locale=en_GB
2. 添加Spring2.0支持,整合Spring2.0
1) 右键工程名,选择MyEclipse->Add Spring Capabilities…打开添加spring支持配置页面,如下图:
图3-26 MyEclipse配置spring页面1图
2) 打开如下配置页面,进行配置:
图3-27 MyEclipse配置spring页面2图
选择spring2.0,勾取spring2.0支持包,要选择Spring2.0 ORM/DAO/Hibernate3 Libraries ,选择Copy checked Libraty contents to project folder(TLDs always copied) ,并将其拷贝到路径为/WebRoot/WEB-INF/lib,然后选择Next,进行下一步设置。
3) 进入application生成页面,如下图:
图3-28 MyEclipse配置spring页面3图
选择New,Folder选择工程下的WebRoot/WEB-INF, File为applicationContext.xml,最后点击Finish完成对Spring2.0的添加。
4) 上面3步添加了spring2.0支持,还需要将spring2.0和struts2.0整合在一起,需要添加struts2-spring-plugin-2.0.11.jar插件,需要在web.xml中配置spring初始化监听,如下代码:
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
插件添加很简单,将下载的struts2的资源包中的lib下的struts2-spring-plugin-2.0.11.jar拷贝到工程的lib下即可。
完成上述工作,Spring的IoC容器会在Web应用启动时完成初始化,且成为Struts2框架的默认的objectFactory。
3. 添加Hibernate3.1支持,整合Hibernate3.1
1) 添加工程的包结构,分别为DAO和PO的类包,如下:
图3-29 MyEclipse配置hibernate页面1图
2) 添加Hibernate3.1支持,右键工程->MyEclipse->Add Hibernate Capabilities…,如下图:
图3-30 MyEclipse配置hibernate页面2图
3) 进入配置页面,进行如下步骤配置:
图3-31 MyEclipse配置hibernate页面3图
选择Hibernate3.1,勾取支持Libraries,选择Copy checked Library Jars to project folder and add to build-path,Library folder路径为WebRoot/WEB-INF/lib,选择Next。
4) 选择Spring configuration file (applicationContext.xml),将hibernate连接库的操作交给Spring来控制,然后Next,如下图:
图3-32 MyEclipse配置hibernate页面4图
5) 选择Existing Spring configuration file,为前配置好的Spring配置文件,SessionFaction ID写为sessionFactory,为hibernate 产生连接的bean的id,如下图,然后Next
图3-33 MyEclipse配置hibernate页面5图
6) 设置数据源,填写Bean Id 为dataSource,选择JDBC,DB Driver为设置好的mysql driver,如下图,然选择Next
图3-34 MyEclipse配置hibernate页面6图
7) 取消创建sessinFactory class,不勾取,因为前面已经将sessionFactory交给了Spring来产生,如下图配置,然后finishi完成hibernate支持的添加。
图3-35 MyEclipse配置hibernate页面7图
8) 点击finish出现如下窗口,选择Keep Existing
图3-36 MyEclipse配置hibernate页面8图
9) 完成后applicationContext.xml中已经添加了数据源和sessionFactory的配置,如下图:
图3-37 MyEclipse配置hibernate页面9图
10) 此时,已经完成了Hibernate3.1的添加,其他hibernate映射具体看struts2与hibernate整合的章节。
提示:完成了struts2.0、spring2.0和hibernate3.1的添加与整合,重新启动工程,验证连接程序时会出现如下错误:
启动Tomcat,又有新的错误;
严重: Unable to initialize Struts ActionServlet due to an unexpected exception or error thrown, so marking the servlet as unavailable. Most likely, this is due to an incorrect or missing library dependency.
java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool
at java.lang.Class.getDeclaredConstructors0(Native Method)
......
解决办法:
到http://www.apache.org/dist/commons/pool/binaries/ 下载commons-pool-1.3.zip,把里面的commons-pool-1.3.jar放到Tomcat目录下的lib文件夹!
再次启动,可能还会报下面的错误:
java.lang.NoSuchMethodError: org.objectweb.asm.ClassVisitor.visit
2007-08-08 15:36:17,406 ERROR [org.hibernate.proxy.BasicLazyInitializer] - CGLIB Enhancement failed: dao.User
java.lang.NoSuchMethodError: org.objectweb.asm.ClassVisitor.visit(IILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V
at net.sf.cglib.core.ClassEmitter.begin_class(ClassEmitter.java:77)
Spring 和 Hibernate 共用的一些 jar 文件发生了版本冲突, 删除 WEB-INF/lib/asm-2.2.3.jar 然后重启 Tomcat.
至此我们完成了Eclipse对Struts2.0, Spring2.0, Hibernate3.1的支持。我们可以看出,Spring的配置主要在WEB-INF下的applicationContext.xml文件中。由于在Struts-Spring- Hibernate的开发中,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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName"
value="com.mysql.jdbc.Driver">
</property>
<property name="url"
value="jdbc:mysql://localhost:3306/acesys">
</property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<prop key="show_sql">true</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>com/ascent/po/Productuser.hbm.xml</value>
<value>com/ascent/po/Product.hbm.xml</value>
<value>com/ascent/po/UserProduct.hbm.xml</value>
<value>com/ascent/po/Orders.hbm.xml</value>
<value>com/ascent/po/Orderitem.hbm.xml</value>
<value>com/ascent/po/Mailtb.hbm.xml</value></list>
</property></bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<!-- 事务拦截器bean需要依赖注入一个事务管理器 -->
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<!-- 下面定义事务传播属性-->
<props>
<prop key="find*,get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="save*,update*,delete*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!-- 定义BeanNameAutoProxyCreator-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<!-- 指定对满足哪些bean name的bean自动生成业务代理 -->
<property name="beanNames">
<!-- 下面是所有需要自动创建事务代理的bean-->
<list>
<value>productuserService</value>
<value>productService</value>
<value>userProductService</value>
<value>ordersService</value>
<value>orderitemService</value>
<value>mailService</value>
</list>
<!-- 此处可增加其他需要自动创建事务代理的bean-->
</property>
<!-- 下面定义BeanNameAutoProxyCreator所需的事务拦截器-->
<property name="interceptorNames">
<list>
<!-- 此处可增加其他新的Interceptor -->
<value>transactionInterceptor</value>
</list>
</property>
</bean>
<bean id="productuserDAO"
class="com.ascent.dao.impl.ProductuserDAOImpl" abstract="false"
lazy-init="default" autowire="default" dependency-check="default">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="productuserService"
class="com.ascent.service.impl.ProductuserServiceImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="productuserDAO">
<ref local="productuserDAO" />
</property>
</bean>
<bean id="productDAO" class="com.ascent.dao.impl.ProductDAOImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="productService"
class="com.ascent.service.impl.ProductServiceImpl" abstract="false"
lazy-init="default" autowire="default" dependency-check="default">
<property name="productDAO">
<ref local="productDAO" />
</property>
</bean>
<bean id="userProductDAO"
class="com.ascent.dao.impl.UserProductDAOImpl" abstract="false"
lazy-init="default" autowire="default" dependency-check="default">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="userProductService"
class="com.ascent.service.impl.UserProductServiceImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="userProductDAO">
<ref local="userProductDAO" />
</property>
</bean>
<bean id="ordersDAO" class="com.ascent.dao.impl.OrdersDAOImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="ordersService"
class="com.ascent.service.impl.OrdersServiceImpl" abstract="false"
lazy-init="default" autowire="default" dependency-check="default">
<property name="ordersDAO">
<ref local="ordersDAO" />
</property>
</bean>
<bean id="orderitemDAO" class="com.ascent.dao.impl.OrderitemDAOImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="orderitemService"
class="com.ascent.service.impl.OrderitemServiceImpl" abstract="false"
lazy-init="default" autowire="default" dependency-check="default">
<property name="orderitemDAO">
<ref local="orderitemDAO" />
</property>
</bean>
<bean id="mailDAO" class="com.ascent.dao.impl.MailDAOImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="mailService"
class="com.ascent.service.impl.MailServiceImpl" abstract="false"
lazy-init="default" autowire="default" dependency-check="default">
<property name="mailDAO">
<ref local="mailDAO" />
</property>
</bean>
</beans>
关于它的具体内容我们稍后详细讲解。
6.6.2 Spring和Hibernate集成
我们前面提到,Spring与hibernate的集成实际上是通过applicationContext.xml配置文件完成的。关于如何使用Hibernate来对数据库表做映射我们在前面已经做了介绍,这里我们关心的是如何配置Spring使它能管理Hibernate。其实只要在Spring的配置文件(我们这里是applicationContext. xml)中配置一个叫作sessionFactory的bean,Spring就可以和Hibernate联系起来了。而sessionFactory会应用dataSource的bean, 它代表的是数据源信息。如下所示:
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName"
value="com.mysql.jdbc.Driver">
</property>
<property name="url"
value="jdbc:mysql://localhost:3306/acesys">
</property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<prop key="show_sql">true</prop>
</props>
</property>
这样Spring和Hibernate的第一步整合就完成了,现在到了关键的地方,也就是如何让Spring和Hibernate双剑合璧来实现业务逻辑呢?
还是在applicationContext.xml文件中我们做了一个配置:
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
在上面你大概可以感觉到Spring给我们带来的好处了,Spring的IoC模式可以统一管理各层,而又使各层松散耦合在一起。使各层之间实现最大的解耦性,这也是Web架构一贯的追求。
但是,Spring带来的好处还不止于此,除了IoC还有AOP,Spring可以运用AOP来实现很多功能,最常用的就是事务处理。这里我们用了业务服务(business service)层和数据存取对象(Data Access Object)层,在business service层我们增加事务处理,DAO(Data Access Object)层负责数据读写
首先组装配置好Service Beans,
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<!-- 事务拦截器bean需要依赖注入一个事务管理器 -->
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<!-- 下面定义事务传播属性-->
<props>
<prop key="find*,get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="save*,update*,delete*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!-- 定义BeanNameAutoProxyCreator-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<!-- 指定对满足哪些bean name的bean自动生成业务代理 -->
<property name="beanNames">
<!-- 下面是所有需要自动创建事务代理的bean-->
<list>
<value>productuserService</value>
<value>productService</value>
<value>userProductService</value>
<value>ordersService</value>
<value>orderitemService</value>
<value>mailService</value>
</list>
<!-- 此处可增加其他需要自动创建事务代理的bean-->
</property>
<!-- 下面定义BeanNameAutoProxyCreator所需的事务拦截器-->
<property name="interceptorNames">
<list>
<!-- 此处可增加其他新的Interceptor -->
<value>transactionInterceptor</value>
</list>
</property>
</bean>
之后需要把Business Service Object和 DAO也组装起来,并把这些对象配到一个事务管理器(transaction manager)里。
在Spring中的配置信息还有以下内容:
<bean id="productuserService"
class="com.ascent.service.impl.ProductuserServiceImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="productuserDAO">
<ref local="productuserDAO" />
</property>
</bean>
<bean id="productuserDAO"
class="com.ascent.dao.impl.ProductuserDAOImpl" abstract="false"
lazy-init="default" autowire="default" dependency-check="default">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
理解了以上的配置,我们就建立了整体框架,下面我们来进行具体代码实现。
首先开发我们的DAO类吧。先说明一点,由于Spring是提倡面向接口编程的,所以我们先为每个DAO类都定义一个接口.:例如,com/ascent/dao目录下的ProductuserDAO是业务接口,而com/ascent/dao/impl目录下的ProductuserDAOImpl是业务接口的实现类。在DAO的实现中,我们使用了Spring对Hibernate的集成类:HibernateTemplate.
典型的应用经常会被重复的资源管理代码搞乱。很多项目尝试创造自己的方案解决这个问题,有时会为了编程方便牺牲适当的故障处理。对于恰当的资源处理Spring提倡令人瞩目的简单的解决方案:使用templating的IoC,比如基础的class和回调接口,或者提供AOP拦截器。基础的类负责固定的资源处理,以及将特定的异常转换为unchecked异常体系。Spring引进了DAO异常体系,可适用于任何数据访问策略。Spring提供了对Hibernate的支持:HibernateTemplate,HibernateInterceptor,以及一个Hibernate transaction manager。这样做的主要目的是:能够清晰地划分应用层次而不管使用何种数据访问和事务技术;使应用对象之间的耦合松散。业务对象(Business Object)不再依赖于数据访问和事务策略;不再有硬编码的资源查找(lookup);不再有难于替换的单点模式(singletons);不再有自定义的服务注册。一个简单且坚固的方案连接了应用对象,并且使它们可重用尽可能地不依赖容器。虽然所有的数据访问技术都能独立使用,但是与Spring application context结合更好一些,它提供了基于xml的配置和普通的与Spring无关的JavaBean实例。在典型的Spring应用中,很多重要的对象都是JavaBeans:数据访问template,数据访问对象(使用template),transaction managers, 业务对象(使用数据访问对象和transaction managers),web view resolvers, web controller(使用业务对象)等等。 代码如下:
/**
*
*/
package com.ascent.dao;
import java.util.ArrayList;
import java.util.List;
import com.ascent.po.Productuser;
public interface ProductuserDAO {
//注册
public Productuser saveProductuser(Productuser productuser);
//按用户名查用户
public Productuser findByUserName(String username);
//用户登陆验证的方法
public Productuser checkProductuser(String username,String password);
// 查询所有用户
public List findAll();
//返回查询所有行 分页
public int getTotalRows();
//查询分页设置数量的数据
public ArrayList getData(String sql,int firstRow,int maxRow);
// 按主键查询用户
public Productuser findById(String uid);
//删除用户
public boolean deleteProductuser(String uid);
//修改用户信息
public boolean updateProductuser(Productuser productuser);
}
/**
*
*/
package com.ascent.dao.impl;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.ascent.dao.ProductuserDAO;
import com.ascent.po.Productuser;
public class ProductuserDAOImpl extends HibernateDaoSupport implements
ProductuserDAO {
/**
* 注册productuser方法实现
*/
public Productuser saveProductuser(Productuser productuser) {
try{
this.getHibernateTemplate().save(productuser);
return productuser;
}catch(Exception e){
e.printStackTrace();
return null;
}
}
/**
* 根据用户名查询productuser
* 返回类型是Productuser,以备查询用户有需要得到其他信息,所以返回该对象
* 当返回是null,说明该用户名的用户库中不存在,可以用来注册
*/
public Productuser findByUserName(String username) {
String sql = "from Productuser p where p.username=? ";
List list = this.getHibernateTemplate().find(sql, username);
if(list.size()>0){
return (Productuser) list.get(0);
}
return null;
}
/**
* 用户登陆验证的方法 delFlag为0标志正常可使用用户
*/
public Productuser checkProductuser(String username, String password) {
String sql = "from Productuser p where p.username=? and p.password=? and p.delFlag=0 ";
List list = this.getHibernateTemplate().find(sql, new String []{username,password});
if(list.size()>0){
return (Productuser)list.get(0);
}
return null;
}
@SuppressWarnings("unchecked")
public List findAll() {
List list = new ArrayList();
List l = this.getHibernateTemplate().find("from Productuser p order by p.uid");
Iterator it = l.iterator();
while(it.hasNext()){
Productuser p = (Productuser)it.next();
p.setTemp4("<input type=\"checkbox\" name=\"infoid\" value=\""+p.getUid()+"\">");
list.add(p);
}
return list;
}
//查询总行数 分页 查询所有用户包括del_flag为1的标志删除用户
public int getTotalRows() {
String sql="from Productuser p order by p.uid ";
int totalRows = this.getHibernateTemplate().find(sql).size();
return totalRows;
}
/**
* @param sql
* @param firstRow
* @param maxRow
* @return list 对象,已包含一定数量的 User 在内
*/
public ArrayList getData(final String sql,final int firstRow, final int maxRow) {
return (ArrayList)this.getHibernateTemplate().executeFind( new HibernateCallback(){
public Object doInHibernate(Session session) throws SQLException,HibernateException {
Query q = session.createQuery(sql);
q.setFirstResult(firstRow);
q.setMaxResults(maxRow);
ArrayList data = (ArrayList) q.list();
return data;
}
});
}
//删除用户 需求中为软删除 所以可能不用delete方法
public boolean deleteProductuser(String uid) {
Productuser p = (Productuser)this.getHibernateTemplate().load(Productuser.class, new Integer(uid));
this.getHibernateTemplate().delete(p);
return true;
}
//根据uid查询用户
public Productuser findById(String uid) {
Productuser p = (Productuser)(this.getHibernateTemplate().find("from Productuser p where p.uid=? ", new Integer(uid))).get(0);
return p;
}
//修改用户信息
public boolean updateProductuser(Productuser productuser) {
this.getHibernateTemplate().saveOrUpdate(productuser);
System.out.println("修改成功====updateProductuser");
return true;
}
}
service的接口及实现如下:
/**
*
*/
package com.ascent.service;
import java.util.ArrayList;
import java.util.List;
import com.ascent.po.Productuser;
public interface ProductuserService {
//注册方法
public Productuser saveProductuser(Productuser productuser);
//按照姓名查询方法
public Productuser findByUserName(String username);
//用户登陆验证的方法
public Productuser checkProductuser(String username,String password);
// 查询所有用户
public List findAll();
// 返回查询所有行 分页
public int getTotalRows();
//查询分页设置数量的数据
public ArrayList getData( final String sql, final int firstRow, final int maxRow);
//按主键查询用户
public Productuser findById(String uid);
//删除用户
public boolean deleteProductuser(String uid);
//修改用户信息
public boolean updateProductuser(Productuser productuser);
}
/**
*
*/
package com.ascent.service.impl;
import java.util.ArrayList;
import java.util.List;
import com.ascent.dao.ProductuserDAO;
import com.ascent.po.Productuser;
import com.ascent.service.ProductuserService;
public class ProductuserServiceImpl implements ProductuserService {
private ProductuserDAO productuserDAO;
public void setProductuserDAO(ProductuserDAO productuserDAO) {
this.productuserDAO = productuserDAO;
}
public Productuser saveProductuser(Productuser productuser) {
return productuserDAO.saveProductuser(productuser);
}
public Productuser findByUserName(String username) {
return productuserDAO.findByUserName(username);
}
public Productuser checkProductuser(String username, String password) {
return productuserDAO.checkProductuser(username, password);
}
public List findAll() {
return productuserDAO.findAll();
}
public ArrayList getData(String sql, int firstRow, int maxRow) {
return productuserDAO.getData(sql, firstRow, maxRow);
}
public int getTotalRows() {
return productuserDAO.getTotalRows();
}
public boolean deleteProductuser(String uid) {
return productuserDAO.deleteProductuser(uid);
}
public Productuser findById(String uid) {
return productuserDAO.findById(uid);
}
public boolean updateProductuser(Productuser productuser) {
return productuserDAO.updateProductuser(productuser);
}
}
6.6.3 Spring和Struts集成
Spring和Struts的整合有很多种方式,如下三种解决方案,可以做为参考:
1.使用Spring的ActionSupport类整合Struts
2.使用Spring的DelegatingRequestProcessor覆盖Struts的RequestProcessor
3.将Struts Action管理委托给Spring框架
我们这里使用的是第三种方式,也就是通过IoC模式让Spring对Struts的Action进行管理,并且我们这里使用了Spring的自动装配功能。
先建立一个BaseAction,它继承了Action类,而其它自定义的Action都要继承这个BaseAction
/**
*
*/
package com.ascent.action;
import com.ascent.service.MailService;
import com.ascent.service.OrderitemService;
import com.ascent.service.OrdersService;
import com.ascent.service.ProductService;
import com.ascent.service.ProductuserService;
import com.ascent.service.UserProductService;
import com.opensymphony.xwork2.ActionSupport;
@SuppressWarnings("serial")
public class BaseAction extends ActionSupport {
//BaseAction中定义service接口,所有Action继承该父类 ,不用每个Action中都得引入了
protected ProductuserService productuserService;
public ProductuserService getProductuserService() {
return productuserService;
}
public void setProductuserService(ProductuserService productuserService) {
this.productuserService = productuserService;
}
protected ProductService productService;
public ProductService getProductService() {
return productService;
}
public void setProductService(ProductService productService) {
this.productService = productService;
}
protected UserProductService userProductService;
public UserProductService getUserProductService() {
return userProductService;
}
public void setUserProductService(UserProductService userProductService) {
this.userProductService = userProductService;
}
protected OrdersService ordersService;
public OrdersService getOrdersService() {
return ordersService;
}
public void setOrdersService(OrdersService ordersService) {
this.ordersService = ordersService;
}
protected OrderitemService orderitemService;
public OrderitemService getOrderitemService() {
return orderitemService;
}
public void setOrderitemService(OrderitemService orderitemService) {
this.orderitemService = orderitemService;
}
protected MailService mailService;
public MailService getMailService() {
return mailService;
}
public void setMailService(MailService mailService) {
this.mailService = mailService;
}
}
工具类AppContext的使用:
一般情况下,我们使用Spring的IoC功能将业务逻辑Service组件注入到Action对象中,这时需要在applicationContext.xml中进行配置,例如以下片段:
<bean id="productuserLoginAction"
class="com.ascent.action.ProductuserLoginAction"
scope="prototype">
<!- -依赖注入业务逻辑Service组件 - ->
<property name="productuserService"
ref local="productuserService" />
</property>
</bean>
<bean id="productuserService"
class="com.ascent.service.impl.ProductuserServiceImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="productuserDAO">
<ref local="productuserDAO" />
</property>
</bean>
这种方式有一个明显的缺陷:所有的Action都需要在applicationContext.xml中进行配置,而struts.xml文件中还需要配置同样的Action。对于有成百上千Action的一般应用,配置文件就会过于庞大臃肿和过多冗余。
为了简化,我们在Spring对Struts的集成中使用了Spring的自动装配功能。在这种策略下,Action还是由Spring插件创建,但Spring插件在创建Action实例时,会将对应业务逻辑组件自动注入Action实例。通过使用自动装配,就不再需要在applicationContext.xml中对Action进行配置,也就是省去了上面那些关于Action的相关内容。
指定Spring插件的自动装配策略通过struts.objectFactory.spring.auto Wire常量制定,该常量可以接受如下几个值:
l name: 根据属性名自动装配。Spring插件会查找容器中全部Bean,找出其中id属性与Action所需的业务逻辑组件同名的Bean,将该Bean实例注入到Action实例。
l type: 根据属性类型自动装配。Spring插件会查找容器中全部Bean,找出其类型恰好与Action所需的业务逻辑组件相同的Bean,将该Bean实例注入到Action实例。如果有多个这样的Bean,就抛出一个致命异常;如果没有匹配的Bean,则什么都不会发生,属性不会被设置。
l auto: Spring插件会自动检测需要使用哪种自动装配方式。
l constructor: 同type类似,区别是constructor使用构造器来构造注入的所需参数,而不是使用设值注入方式。
本应用使用按name来完成自动装配。如果我们不指定自动装配的方式,则系统默认使用按name自动装配,因此我们无需设置任何的Struts 2常量。
<!--
指定使用按name的自动装配策略
-->
<constant name="struts.objectFactory.spring.autoWire" value="name" />
因为使用了自动装配,Spring插件创建Action实例时,是根据配置Action的class属性指定实现类来创建Action实例的。
例如在struts.xml中,我们有以下内容:
<action name="productuserLoginAction" class="com.ascent.action.ProductuserLoginAction">
<result>/index.html</result>
<result name="success_1">/product/products.jsp</result>
<result name="success_2">/product/products.jsp</result>
<result name="success_3">/product/products_showusers.jsp</result>
<result name="error">/product/products.jsp</result>
<result name="input">/product/products.jsp</result>
</action>
ProductuserLoginAction继承了BaseAction类, 该Action所需的业务逻辑组件名为productuserService。我们查看刚才的BaseAction类代码,发现了如下的内容:
//系统所用的业务逻辑组件
protected ProductuserService productuserService;
public ProductuserService getProductuserService() {
return productuserService;
}
public void setProductuserService(ProductuserService productuserService) {
this.productuserService = productuserService;
}
配置业务逻辑组件时,我们必须在applicationContext.xml文件中指定其id属性为productuserService,那么Spring插件就可以在创建时自动地将该业务逻辑组件注入给Action实例。相关代码如下:
<bean id="productuserService"
class="com.ascent.service.impl.ProductuserServiceImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="productuserDAO">
<ref local="productuserDAO" />
</property>
</bean>
至此,Struts-Spring-Hibernate已经可以一起来工作了。
6.6.1环境搭建和基本配置
我们在Eclipse中可以增加对Struts2.0, Spring2.0, Hibernate3.1的支持,具体如下:
1. 搭建简单的Struts2 Web工程
1) 下载和安装Struts2框架
在此下载最新的struts-2.0.11-all完整包,里面包括apps(示例)、docs(文档)、j4(struts2支持jdk1.4的jar文件)、lib(核心类库及struts2第三方插件类库)、src(源代码)。
2) 创建web工程,添加jar包
将下载资源包中lib下的struts2-core-2.0.11.jar、xwork-2.0.4.jar和ognl-2.6.11.jar(三个为必须jar包)添加,就可以开发应用,但是会有错误消息。添加commons-logging-1.04.jar和freemarker-2.3.8.jar就不会报错。
3) 编辑web.xml文件,配置struts2的核心Filter
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Struts 2.0 Hello World</display-name>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
</web-app>
4) 写用户请求jsp
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<html>
<head>
<title>登陆页面</title>
</head>
<body>
<form action="Login.action" method="post">
<table align="center">
<h3>用户登陆</h3>
<tr align="center">
<td>用户名:<input type="text" name="username"/></td>
</tr>
<tr align="center"><td>密 码:<input type="text" name="password"/></td></tr>
<tr align="center">
<td colspan="2"><input type="submit" value="提交"/><input
type="reset" value="重置"/></td>
</tr>
</table>
</form>
</body>
</html>
5) 写Action类
package com.ascent.struts2.action;
public class LoginAction {
private String username;
private String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String execute(){
if(getUsername().equals("liang")&& getPassword().equals("liang")){
return "success";
}
return "error";
}
}
6) 在src下写struts.xml
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="struts2_helloworld" extends="struts-default">
<action name="Login" class="com.ascent.struts2.action.LoginAction">
<result name="error">/error.jsp</result>
<result name="success">/welcome.jsp</result>
</action>
</package>
</struts>
7) 添加error.jsp和welcome.jsp
8) 部署和启动,进行测试。
注意:TOMCAT 5。5有警告,说的是
警告: Settings: Could not parse struts.locale setting, substituting default VM locale)
要解决也不难,创建struts.properties这个文件,放在src目录下就可以了
struts.locale=en_GB
2. 添加Spring2.0支持,整合Spring2.0
1) 右键工程名,选择MyEclipse->Add Spring Capabilities…打开添加spring支持配置页面,如下图:
图3-26 MyEclipse配置spring页面1图
2) 打开如下配置页面,进行配置:
图3-27 MyEclipse配置spring页面2图
选择spring2.0,勾取spring2.0支持包,要选择Spring2.0 ORM/DAO/Hibernate3 Libraries ,选择Copy checked Libraty contents to project folder(TLDs always copied) ,并将其拷贝到路径为/WebRoot/WEB-INF/lib,然后选择Next,进行下一步设置。
3) 进入application生成页面,如下图:
图3-28 MyEclipse配置spring页面3图
选择New,Folder选择工程下的WebRoot/WEB-INF, File为applicationContext.xml,最后点击Finish完成对Spring2.0的添加。
4) 上面3步添加了spring2.0支持,还需要将spring2.0和struts2.0整合在一起,需要添加struts2-spring-plugin-2.0.11.jar插件,需要在web.xml中配置spring初始化监听,如下代码:
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
插件添加很简单,将下载的struts2的资源包中的lib下的struts2-spring-plugin-2.0.11.jar拷贝到工程的lib下即可。
完成上述工作,Spring的IoC容器会在Web应用启动时完成初始化,且成为Struts2框架的默认的objectFactory。
3. 添加Hibernate3.1支持,整合Hibernate3.1
1) 添加工程的包结构,分别为DAO和PO的类包,如下:
图3-29 MyEclipse配置hibernate页面1图
2) 添加Hibernate3.1支持,右键工程->MyEclipse->Add Hibernate Capabilities…,如下图:
图3-30 MyEclipse配置hibernate页面2图
3) 进入配置页面,进行如下步骤配置:
图3-31 MyEclipse配置hibernate页面3图
选择Hibernate3.1,勾取支持Libraries,选择Copy checked Library Jars to project folder and add to build-path,Library folder路径为WebRoot/WEB-INF/lib,选择Next。
4) 选择Spring configuration file (applicationContext.xml),将hibernate连接库的操作交给Spring来控制,然后Next,如下图:
图3-32 MyEclipse配置hibernate页面4图
5) 选择Existing Spring configuration file,为前配置好的Spring配置文件,SessionFaction ID写为sessionFactory,为hibernate 产生连接的bean的id,如下图,然后Next
图3-33 MyEclipse配置hibernate页面5图
6) 设置数据源,填写Bean Id 为dataSource,选择JDBC,DB Driver为设置好的mysql driver,如下图,然选择Next
图3-34 MyEclipse配置hibernate页面6图
7) 取消创建sessinFactory class,不勾取,因为前面已经将sessionFactory交给了Spring来产生,如下图配置,然后finishi完成hibernate支持的添加。
图3-35 MyEclipse配置hibernate页面7图
8) 点击finish出现如下窗口,选择Keep Existing
图3-36 MyEclipse配置hibernate页面8图
9) 完成后applicationContext.xml中已经添加了数据源和sessionFactory的配置,如下图:
图3-37 MyEclipse配置hibernate页面9图
10) 此时,已经完成了Hibernate3.1的添加,其他hibernate映射具体看struts2与hibernate整合的章节。
提示:完成了struts2.0、spring2.0和hibernate3.1的添加与整合,重新启动工程,验证连接程序时会出现如下错误:
启动Tomcat,又有新的错误;
严重: Unable to initialize Struts ActionServlet due to an unexpected exception or error thrown, so marking the servlet as unavailable. Most likely, this is due to an incorrect or missing library dependency.
java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool
at java.lang.Class.getDeclaredConstructors0(Native Method)
......
解决办法:
到http://www.apache.org/dist/commons/pool/binaries/ 下载commons-pool-1.3.zip,把里面的commons-pool-1.3.jar放到Tomcat目录下的lib文件夹!
再次启动,可能还会报下面的错误:
java.lang.NoSuchMethodError: org.objectweb.asm.ClassVisitor.visit
2007-08-08 15:36:17,406 ERROR [org.hibernate.proxy.BasicLazyInitializer] - CGLIB Enhancement failed: dao.User
java.lang.NoSuchMethodError: org.objectweb.asm.ClassVisitor.visit(IILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V
at net.sf.cglib.core.ClassEmitter.begin_class(ClassEmitter.java:77)
Spring 和 Hibernate 共用的一些 jar 文件发生了版本冲突, 删除 WEB-INF/lib/asm-2.2.3.jar 然后重启 Tomcat.
至此我们完成了Eclipse对Struts2.0, Spring2.0, Hibernate3.1的支持。我们可以看出,Spring的配置主要在WEB-INF下的applicationContext.xml文件中。由于在Struts-Spring- Hibernate的开发中,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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName"
value="com.mysql.jdbc.Driver">
</property>
<property name="url"
value="jdbc:mysql://localhost:3306/acesys">
</property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<prop key="show_sql">true</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>com/ascent/po/Productuser.hbm.xml</value>
<value>com/ascent/po/Product.hbm.xml</value>
<value>com/ascent/po/UserProduct.hbm.xml</value>
<value>com/ascent/po/Orders.hbm.xml</value>
<value>com/ascent/po/Orderitem.hbm.xml</value>
<value>com/ascent/po/Mailtb.hbm.xml</value></list>
</property></bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<!-- 事务拦截器bean需要依赖注入一个事务管理器 -->
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<!-- 下面定义事务传播属性-->
<props>
<prop key="find*,get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="save*,update*,delete*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!-- 定义BeanNameAutoProxyCreator-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<!-- 指定对满足哪些bean name的bean自动生成业务代理 -->
<property name="beanNames">
<!-- 下面是所有需要自动创建事务代理的bean-->
<list>
<value>productuserService</value>
<value>productService</value>
<value>userProductService</value>
<value>ordersService</value>
<value>orderitemService</value>
<value>mailService</value>
</list>
<!-- 此处可增加其他需要自动创建事务代理的bean-->
</property>
<!-- 下面定义BeanNameAutoProxyCreator所需的事务拦截器-->
<property name="interceptorNames">
<list>
<!-- 此处可增加其他新的Interceptor -->
<value>transactionInterceptor</value>
</list>
</property>
</bean>
<bean id="productuserDAO"
class="com.ascent.dao.impl.ProductuserDAOImpl" abstract="false"
lazy-init="default" autowire="default" dependency-check="default">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="productuserService"
class="com.ascent.service.impl.ProductuserServiceImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="productuserDAO">
<ref local="productuserDAO" />
</property>
</bean>
<bean id="productDAO" class="com.ascent.dao.impl.ProductDAOImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="productService"
class="com.ascent.service.impl.ProductServiceImpl" abstract="false"
lazy-init="default" autowire="default" dependency-check="default">
<property name="productDAO">
<ref local="productDAO" />
</property>
</bean>
<bean id="userProductDAO"
class="com.ascent.dao.impl.UserProductDAOImpl" abstract="false"
lazy-init="default" autowire="default" dependency-check="default">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="userProductService"
class="com.ascent.service.impl.UserProductServiceImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="userProductDAO">
<ref local="userProductDAO" />
</property>
</bean>
<bean id="ordersDAO" class="com.ascent.dao.impl.OrdersDAOImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="ordersService"
class="com.ascent.service.impl.OrdersServiceImpl" abstract="false"
lazy-init="default" autowire="default" dependency-check="default">
<property name="ordersDAO">
<ref local="ordersDAO" />
</property>
</bean>
<bean id="orderitemDAO" class="com.ascent.dao.impl.OrderitemDAOImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="orderitemService"
class="com.ascent.service.impl.OrderitemServiceImpl" abstract="false"
lazy-init="default" autowire="default" dependency-check="default">
<property name="orderitemDAO">
<ref local="orderitemDAO" />
</property>
</bean>
<bean id="mailDAO" class="com.ascent.dao.impl.MailDAOImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="mailService"
class="com.ascent.service.impl.MailServiceImpl" abstract="false"
lazy-init="default" autowire="default" dependency-check="default">
<property name="mailDAO">
<ref local="mailDAO" />
</property>
</bean>
</beans>
关于它的具体内容我们稍后详细讲解。
6.6.2 Spring和Hibernate集成
我们前面提到,Spring与hibernate的集成实际上是通过applicationContext.xml配置文件完成的。关于如何使用Hibernate来对数据库表做映射我们在前面已经做了介绍,这里我们关心的是如何配置Spring使它能管理Hibernate。其实只要在Spring的配置文件(我们这里是applicationContext. xml)中配置一个叫作sessionFactory的bean,Spring就可以和Hibernate联系起来了。而sessionFactory会应用dataSource的bean, 它代表的是数据源信息。如下所示:
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName"
value="com.mysql.jdbc.Driver">
</property>
<property name="url"
value="jdbc:mysql://localhost:3306/acesys">
</property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<prop key="show_sql">true</prop>
</props>
</property>
这样Spring和Hibernate的第一步整合就完成了,现在到了关键的地方,也就是如何让Spring和Hibernate双剑合璧来实现业务逻辑呢?
还是在applicationContext.xml文件中我们做了一个配置:
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
在上面你大概可以感觉到Spring给我们带来的好处了,Spring的IoC模式可以统一管理各层,而又使各层松散耦合在一起。使各层之间实现最大的解耦性,这也是Web架构一贯的追求。
但是,Spring带来的好处还不止于此,除了IoC还有AOP,Spring可以运用AOP来实现很多功能,最常用的就是事务处理。这里我们用了业务服务(business service)层和数据存取对象(Data Access Object)层,在business service层我们增加事务处理,DAO(Data Access Object)层负责数据读写
首先组装配置好Service Beans,
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<!-- 事务拦截器bean需要依赖注入一个事务管理器 -->
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<!-- 下面定义事务传播属性-->
<props>
<prop key="find*,get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="save*,update*,delete*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!-- 定义BeanNameAutoProxyCreator-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<!-- 指定对满足哪些bean name的bean自动生成业务代理 -->
<property name="beanNames">
<!-- 下面是所有需要自动创建事务代理的bean-->
<list>
<value>productuserService</value>
<value>productService</value>
<value>userProductService</value>
<value>ordersService</value>
<value>orderitemService</value>
<value>mailService</value>
</list>
<!-- 此处可增加其他需要自动创建事务代理的bean-->
</property>
<!-- 下面定义BeanNameAutoProxyCreator所需的事务拦截器-->
<property name="interceptorNames">
<list>
<!-- 此处可增加其他新的Interceptor -->
<value>transactionInterceptor</value>
</list>
</property>
</bean>
之后需要把Business Service Object和 DAO也组装起来,并把这些对象配到一个事务管理器(transaction manager)里。
在Spring中的配置信息还有以下内容:
<bean id="productuserService"
class="com.ascent.service.impl.ProductuserServiceImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="productuserDAO">
<ref local="productuserDAO" />
</property>
</bean>
<bean id="productuserDAO"
class="com.ascent.dao.impl.ProductuserDAOImpl" abstract="false"
lazy-init="default" autowire="default" dependency-check="default">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
理解了以上的配置,我们就建立了整体框架,下面我们来进行具体代码实现。
首先开发我们的DAO类吧。先说明一点,由于Spring是提倡面向接口编程的,所以我们先为每个DAO类都定义一个接口.:例如,com/ascent/dao目录下的ProductuserDAO是业务接口,而com/ascent/dao/impl目录下的ProductuserDAOImpl是业务接口的实现类。在DAO的实现中,我们使用了Spring对Hibernate的集成类:HibernateTemplate.
典型的应用经常会被重复的资源管理代码搞乱。很多项目尝试创造自己的方案解决这个问题,有时会为了编程方便牺牲适当的故障处理。对于恰当的资源处理Spring提倡令人瞩目的简单的解决方案:使用templating的IoC,比如基础的class和回调接口,或者提供AOP拦截器。基础的类负责固定的资源处理,以及将特定的异常转换为unchecked异常体系。Spring引进了DAO异常体系,可适用于任何数据访问策略。Spring提供了对Hibernate的支持:HibernateTemplate,HibernateInterceptor,以及一个Hibernate transaction manager。这样做的主要目的是:能够清晰地划分应用层次而不管使用何种数据访问和事务技术;使应用对象之间的耦合松散。业务对象(Business Object)不再依赖于数据访问和事务策略;不再有硬编码的资源查找(lookup);不再有难于替换的单点模式(singletons);不再有自定义的服务注册。一个简单且坚固的方案连接了应用对象,并且使它们可重用尽可能地不依赖容器。虽然所有的数据访问技术都能独立使用,但是与Spring application context结合更好一些,它提供了基于xml的配置和普通的与Spring无关的JavaBean实例。在典型的Spring应用中,很多重要的对象都是JavaBeans:数据访问template,数据访问对象(使用template),transaction managers, 业务对象(使用数据访问对象和transaction managers),web view resolvers, web controller(使用业务对象)等等。 代码如下:
/**
*
*/
package com.ascent.dao;
import java.util.ArrayList;
import java.util.List;
import com.ascent.po.Productuser;
public interface ProductuserDAO {
//注册
public Productuser saveProductuser(Productuser productuser);
//按用户名查用户
public Productuser findByUserName(String username);
//用户登陆验证的方法
public Productuser checkProductuser(String username,String password);
// 查询所有用户
public List findAll();
//返回查询所有行 分页
public int getTotalRows();
//查询分页设置数量的数据
public ArrayList getData(String sql,int firstRow,int maxRow);
// 按主键查询用户
public Productuser findById(String uid);
//删除用户
public boolean deleteProductuser(String uid);
//修改用户信息
public boolean updateProductuser(Productuser productuser);
}
/**
*
*/
package com.ascent.dao.impl;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.ascent.dao.ProductuserDAO;
import com.ascent.po.Productuser;
public class ProductuserDAOImpl extends HibernateDaoSupport implements
ProductuserDAO {
/**
* 注册productuser方法实现
*/
public Productuser saveProductuser(Productuser productuser) {
try{
this.getHibernateTemplate().save(productuser);
return productuser;
}catch(Exception e){
e.printStackTrace();
return null;
}
}
/**
* 根据用户名查询productuser
* 返回类型是Productuser,以备查询用户有需要得到其他信息,所以返回该对象
* 当返回是null,说明该用户名的用户库中不存在,可以用来注册
*/
public Productuser findByUserName(String username) {
String sql = "from Productuser p where p.username=? ";
List list = this.getHibernateTemplate().find(sql, username);
if(list.size()>0){
return (Productuser) list.get(0);
}
return null;
}
/**
* 用户登陆验证的方法 delFlag为0标志正常可使用用户
*/
public Productuser checkProductuser(String username, String password) {
String sql = "from Productuser p where p.username=? and p.password=? and p.delFlag=0 ";
List list = this.getHibernateTemplate().find(sql, new String []{username,password});
if(list.size()>0){
return (Productuser)list.get(0);
}
return null;
}
@SuppressWarnings("unchecked")
public List findAll() {
List list = new ArrayList();
List l = this.getHibernateTemplate().find("from Productuser p order by p.uid");
Iterator it = l.iterator();
while(it.hasNext()){
Productuser p = (Productuser)it.next();
p.setTemp4("<input type=\"checkbox\" name=\"infoid\" value=\""+p.getUid()+"\">");
list.add(p);
}
return list;
}
//查询总行数 分页 查询所有用户包括del_flag为1的标志删除用户
public int getTotalRows() {
String sql="from Productuser p order by p.uid ";
int totalRows = this.getHibernateTemplate().find(sql).size();
return totalRows;
}
/**
* @param sql
* @param firstRow
* @param maxRow
* @return list 对象,已包含一定数量的 User 在内
*/
public ArrayList getData(final String sql,final int firstRow, final int maxRow) {
return (ArrayList)this.getHibernateTemplate().executeFind( new HibernateCallback(){
public Object doInHibernate(Session session) throws SQLException,HibernateException {
Query q = session.createQuery(sql);
q.setFirstResult(firstRow);
q.setMaxResults(maxRow);
ArrayList data = (ArrayList) q.list();
return data;
}
});
}
//删除用户 需求中为软删除 所以可能不用delete方法
public boolean deleteProductuser(String uid) {
Productuser p = (Productuser)this.getHibernateTemplate().load(Productuser.class, new Integer(uid));
this.getHibernateTemplate().delete(p);
return true;
}
//根据uid查询用户
public Productuser findById(String uid) {
Productuser p = (Productuser)(this.getHibernateTemplate().find("from Productuser p where p.uid=? ", new Integer(uid))).get(0);
return p;
}
//修改用户信息
public boolean updateProductuser(Productuser productuser) {
this.getHibernateTemplate().saveOrUpdate(productuser);
System.out.println("修改成功====updateProductuser");
return true;
}
}
service的接口及实现如下:
/**
*
*/
package com.ascent.service;
import java.util.ArrayList;
import java.util.List;
import com.ascent.po.Productuser;
public interface ProductuserService {
//注册方法
public Productuser saveProductuser(Productuser productuser);
//按照姓名查询方法
public Productuser findByUserName(String username);
//用户登陆验证的方法
public Productuser checkProductuser(String username,String password);
// 查询所有用户
public List findAll();
// 返回查询所有行 分页
public int getTotalRows();
//查询分页设置数量的数据
public ArrayList getData( final String sql, final int firstRow, final int maxRow);
//按主键查询用户
public Productuser findById(String uid);
//删除用户
public boolean deleteProductuser(String uid);
//修改用户信息
public boolean updateProductuser(Productuser productuser);
}
/**
*
*/
package com.ascent.service.impl;
import java.util.ArrayList;
import java.util.List;
import com.ascent.dao.ProductuserDAO;
import com.ascent.po.Productuser;
import com.ascent.service.ProductuserService;
public class ProductuserServiceImpl implements ProductuserService {
private ProductuserDAO productuserDAO;
public void setProductuserDAO(ProductuserDAO productuserDAO) {
this.productuserDAO = productuserDAO;
}
public Productuser saveProductuser(Productuser productuser) {
return productuserDAO.saveProductuser(productuser);
}
public Productuser findByUserName(String username) {
return productuserDAO.findByUserName(username);
}
public Productuser checkProductuser(String username, String password) {
return productuserDAO.checkProductuser(username, password);
}
public List findAll() {
return productuserDAO.findAll();
}
public ArrayList getData(String sql, int firstRow, int maxRow) {
return productuserDAO.getData(sql, firstRow, maxRow);
}
public int getTotalRows() {
return productuserDAO.getTotalRows();
}
public boolean deleteProductuser(String uid) {
return productuserDAO.deleteProductuser(uid);
}
public Productuser findById(String uid) {
return productuserDAO.findById(uid);
}
public boolean updateProductuser(Productuser productuser) {
return productuserDAO.updateProductuser(productuser);
}
}
6.6.3 Spring和Struts集成
Spring和Struts的整合有很多种方式,如下三种解决方案,可以做为参考:
1.使用Spring的ActionSupport类整合Struts
2.使用Spring的DelegatingRequestProcessor覆盖Struts的RequestProcessor
3.将Struts Action管理委托给Spring框架
我们这里使用的是第三种方式,也就是通过IoC模式让Spring对Struts的Action进行管理,并且我们这里使用了Spring的自动装配功能。
先建立一个BaseAction,它继承了Action类,而其它自定义的Action都要继承这个BaseAction
/**
*
*/
package com.ascent.action;
import com.ascent.service.MailService;
import com.ascent.service.OrderitemService;
import com.ascent.service.OrdersService;
import com.ascent.service.ProductService;
import com.ascent.service.ProductuserService;
import com.ascent.service.UserProductService;
import com.opensymphony.xwork2.ActionSupport;
@SuppressWarnings("serial")
public class BaseAction extends ActionSupport {
//BaseAction中定义service接口,所有Action继承该父类 ,不用每个Action中都得引入了
protected ProductuserService productuserService;
public ProductuserService getProductuserService() {
return productuserService;
}
public void setProductuserService(ProductuserService productuserService) {
this.productuserService = productuserService;
}
protected ProductService productService;
public ProductService getProductService() {
return productService;
}
public void setProductService(ProductService productService) {
this.productService = productService;
}
protected UserProductService userProductService;
public UserProductService getUserProductService() {
return userProductService;
}
public void setUserProductService(UserProductService userProductService) {
this.userProductService = userProductService;
}
protected OrdersService ordersService;
public OrdersService getOrdersService() {
return ordersService;
}
public void setOrdersService(OrdersService ordersService) {
this.ordersService = ordersService;
}
protected OrderitemService orderitemService;
public OrderitemService getOrderitemService() {
return orderitemService;
}
public void setOrderitemService(OrderitemService orderitemService) {
this.orderitemService = orderitemService;
}
protected MailService mailService;
public MailService getMailService() {
return mailService;
}
public void setMailService(MailService mailService) {
this.mailService = mailService;
}
}
工具类AppContext的使用:
一般情况下,我们使用Spring的IoC功能将业务逻辑Service组件注入到Action对象中,这时需要在applicationContext.xml中进行配置,例如以下片段:
<bean id="productuserLoginAction"
class="com.ascent.action.ProductuserLoginAction"
scope="prototype">
<!- -依赖注入业务逻辑Service组件 - ->
<property name="productuserService"
ref local="productuserService" />
</property>
</bean>
<bean id="productuserService"
class="com.ascent.service.impl.ProductuserServiceImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="productuserDAO">
<ref local="productuserDAO" />
</property>
</bean>
这种方式有一个明显的缺陷:所有的Action都需要在applicationContext.xml中进行配置,而struts.xml文件中还需要配置同样的Action。对于有成百上千Action的一般应用,配置文件就会过于庞大臃肿和过多冗余。
为了简化,我们在Spring对Struts的集成中使用了Spring的自动装配功能。在这种策略下,Action还是由Spring插件创建,但Spring插件在创建Action实例时,会将对应业务逻辑组件自动注入Action实例。通过使用自动装配,就不再需要在applicationContext.xml中对Action进行配置,也就是省去了上面那些关于Action的相关内容。
指定Spring插件的自动装配策略通过struts.objectFactory.spring.auto Wire常量制定,该常量可以接受如下几个值:
l name: 根据属性名自动装配。Spring插件会查找容器中全部Bean,找出其中id属性与Action所需的业务逻辑组件同名的Bean,将该Bean实例注入到Action实例。
l type: 根据属性类型自动装配。Spring插件会查找容器中全部Bean,找出其类型恰好与Action所需的业务逻辑组件相同的Bean,将该Bean实例注入到Action实例。如果有多个这样的Bean,就抛出一个致命异常;如果没有匹配的Bean,则什么都不会发生,属性不会被设置。
l auto: Spring插件会自动检测需要使用哪种自动装配方式。
l constructor: 同type类似,区别是constructor使用构造器来构造注入的所需参数,而不是使用设值注入方式。
本应用使用按name来完成自动装配。如果我们不指定自动装配的方式,则系统默认使用按name自动装配,因此我们无需设置任何的Struts 2常量。
<!--
指定使用按name的自动装配策略
-->
<constant name="struts.objectFactory.spring.autoWire" value="name" />
因为使用了自动装配,Spring插件创建Action实例时,是根据配置Action的class属性指定实现类来创建Action实例的。
例如在struts.xml中,我们有以下内容:
<action name="productuserLoginAction" class="com.ascent.action.ProductuserLoginAction">
<result>/index.html</result>
<result name="success_1">/product/products.jsp</result>
<result name="success_2">/product/products.jsp</result>
<result name="success_3">/product/products_showusers.jsp</result>
<result name="error">/product/products.jsp</result>
<result name="input">/product/products.jsp</result>
</action>
ProductuserLoginAction继承了BaseAction类, 该Action所需的业务逻辑组件名为productuserService。我们查看刚才的BaseAction类代码,发现了如下的内容:
//系统所用的业务逻辑组件
protected ProductuserService productuserService;
public ProductuserService getProductuserService() {
return productuserService;
}
public void setProductuserService(ProductuserService productuserService) {
this.productuserService = productuserService;
}
配置业务逻辑组件时,我们必须在applicationContext.xml文件中指定其id属性为productuserService,那么Spring插件就可以在创建时自动地将该业务逻辑组件注入给Action实例。相关代码如下:
<bean id="productuserService"
class="com.ascent.service.impl.ProductuserServiceImpl"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="productuserDAO">
<ref local="productuserDAO" />
</property>
</bean>
至此,Struts-Spring-Hibernate已经可以一起来工作了。