http://blog.csdn.net/nihao_201104/article/details/3548679
首先得现了解为什么他们三者要整合?整合起来能发挥什么样的作用?在我们的实际开发当中给我们带来了什么?他们又是如何来整合的?带着这么几个问题我们来说说他们之间的关系以及附带一个例子从而来讲解一下。
<1>:struts2.0的优点:
(A):运用它本身的MVC的这种框架,能方便的解决业务层与表示层的代码分离,从而达到各自处理各自的事情。
(B):与1.x相比。2.0中没有了专门的FormBean,而是直接与业务层结合到了一起。并且视图层可以通过OGNL(Object-Graph Navigation Language)—一种强大的表达式语言(以后回介绍到)语法直接获取Bean的值。
(C):支持与spring一样的IOC默认配置。
(D):自带的拦截器<Intercepter>把一些通用的业务逻辑比如:输入校验、类型转换、参数获取等独立出来了。让Actioin更专注具体的业务。
<2>:Hibernate3.x的优点:
(A):都知道hibernate是用来与数据库打交道的。但是它与以前的Hibernate2.0还是有一定的区别的
(a):包引入的变化,以前2.x是”net.sf.hibernate”。3.x是”org.hibernate”。
(b):所以说在引入包的时候得看准后再选择。
(c):2.x和3.x在session的接口方面有所变化,2.x find()、iterate()、filter()和delete(String hqlSelectQuery)、saveOrUpdateCopy()。3.x在查询时统一的采用createQuery().
(d):3.x可以批量更新和批量删除。
但是hibernate在进行事务处理的相对比较弱一些,Hibernate是对JDBC的轻量级装,
Hibernate本身不具备Transaction的功能。Hibernate是在底层对JDBC Transaction
的封装。
<3>:spring的优点:
(A):spring的IOC(Inversion of Control 控制反转) 的引入,AOP(面向方面编程),这是spring的两大特色。
(B):对struts1.x和struts2.0的封装,但是对不同的版本的封装还是有一定的区别的。
(C):对Hibernate 的整合封装,包括连接数据库、映射表之间的关系、事务配置统统的都交给spring的Bean来管理了,那么我们只需要对配置文件修改修改就行了。
上面只是简单的介绍了三者使用起来都有什么样的好处,并且比较了与以前版本的区别,其实我们在做项目过程当中完全可以使用struts+hibernate这样的架构,那为什么还要把spring加进去呢!spring也是一种MVC的模式。它里面有许多的控制器,也能处理了复杂的业务。之所以把spring加进来是因为:
1:spring它是一种轻量级的框架,使用起来很方便,它能整合了struts1.x和hibernate2.x以上的版本,把以前我们经常需要实例化的那些语句都可以丢到一边去了,直接用spring的注入方式,简单的写一些配置文件即可。
2:把hibernate中的事务替代了,完全的交给了spring了。我们只需要写一些HQL语句就能达到目的,不需要关系事务这一层。
3:spring 其本身也有控制器,但是它在整合了struts后,利用其自身的优越性,屏蔽了其不足,刚好这个不足就交给struts来处理,spring可以通过注入的方式就可得到意向不到的效果。
4:并且整合以后分层很清楚,各自处理各自的事,以后再需要扩展什么功能的话,只需要写interface就可以了,很像工厂模式的做法。
通过一副图来说明下三者之间的关系:
其实spring这个业务层
还可以分为这么个两层
理解了他们之间的关系后,以一个登陆的例子来做写详细的说明:
(一):可以直接右击项目 >> MyEclipse >> 添加所需的特性。现在开源的MyEclipse6.0~7.0还没有struts2.0的一些特性,所以说必须得手工的copy到你的lib下。或者是右击项目 >>
Build Path >> Config Bulid Path >> Add External JARS >> 找到你的jar包的目录。
自己的建议:把已经配置好的JAR包单独的放在一个文件夹下,直接按照第一步的做法做就行了。因为struts2.0中的JAR包有些是和spring 中的JAR包是冲突的,到时候找错根本无从下手。如果引进特性的包的那种方式也可以的话,也行。以前struts1.x 、hibernate3.0、spring1.2都是直接从项目的特性中引进的。
(二):现不用管这些包是用来干什么的。把他现加进来现说,随后回告诉它们的用途。我们现从jsp(显示层说起):index.jsp、 一般.jsp都是放在webroot下面的,如果.jsp多了的话,也可以分文件夹放置。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@include file="/tags.jsp"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP ''index.jsp'' starting page</title>
</head>
<body topmargin="100">
<s:form action="login" namespace="/login" method="post">
<table border="1" align="center" cellspacing="0">
<tr>
<s:textfield name="user.name" label="用户名称"></s:textfield>
</tr>
<tr>
<s:password name="user.password" label="用户密码"></s:password>
</tr>
<tr>
<s:submit value="提交"/>
</tr>
</s:form>
</body>
</html>
可以从上面的代码中看到<s:textfield>等标签引用的是struts2.0自己所带的标签,大大的减少了页面中的java代码。
Action :sturts中Form的标签是action是经过优化的,
(A):传统的html的url一般通常是这样写的:action=”http://localhost:8080/testApp/url(提交的路径)”.
(B): struts1.x中的action=”/url”(以/开头的url地址)时,其会从http://127.0.0.1:8080这个根开始附加,我们要访问具体信息必需要加上项目的上下文(context),就是tomcat安装目录下wepapps/context(具体是你工程名字)这个文件夹名字,象这样 <form action="/SpringOne/action " method="post">.
(C):struts2.0中的action=”/url”,Struts2.0帮我们做了优化,它回自动的为我们在Http://localhost:8080/后面加上项目的上下文,然后再附加上action中的url:<s:form action=”/actoin”>
Namespace指的是:命名空间的配置,说白了就是你所访问action的前置有一个url,当你指定的空间找不到时候就转向Default里。
(D):属性user.name对应LoginAction中的user实体Bean中的属性name,password也一样。
(三):LoginActin
public class LoginAction extends ActionSupport {
private Users user;
private LoginDao dao;
public LoginAction() {
}
@Override把ActonSupport中的execute进行了重写
public String execute() throws Exception {
user = dao.checkOut(user.getName(), user.getPassword());
return this.SUCCESS;
}
/**
**SUCCESS、INPUT、ERROR等,这些都是ActonSupport中封装好的方法。
**/
public Users getUser() {
return user;
}
public void setUser(Users user) {
this.user = user;
}
public LoginDao getDao() {
return dao;
}
public void setDao(LoginDao dao) {
this.dao = dao;
}
}
这里你可以看到刚刚所说的user.name对应的user实例,同时还有一个接口dao 的实例(通过spring 的 依赖注入的形式来生成实例,以前通常的写法是:LoginDao dao = new LoginDao(),那么有了依赖注入后,就不用每次都对这个实例的属性每一次new了。),其余的都是一些set、get方法。这个LoginAction可以直接调用了Dao接口的实现类,中间少了一层SERVICE层。Service交给了Dao接口的实例类实现了。
(四):struts.xml<struts2.0的核心配置文件>
<struts>
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
<constant name="struts.objectFactory.spring.autoWire" value="name"></constant>
<constant name="struts.objectFactory.spring.useClassCache" value="true"></constant>
<constant name="struts.devMode" value="true"></constant>
<constant name="struts.objectFactory" value="spring"></constant>
<constant name="struts.i18n.reload" value="true"></constant>
<include file="login.xml"></include>
</struts>
<1>:struts.i18n.encoding是struts2.0的编码格式。
<2>:struts.objectFactory.spring.autoWire
这是定义struts2的action在注入业务逻辑类的时候使用那种方式匹配spring context中的对象,是基于名字匹配,如果设置成type,则是基于类型匹配。对应的有:type、auto、constructor。
<3>:struts.objectFactory.spring.useClassCache是否spring用自身的cache.
<4>:struts.devMode是否为struts的开发模式
<5>:struts.i18n.reload是否国际化信息加载
<6>:struts.objectFactory 关键的一句:struts交给spring来管理,这个与struts1.x有很大的区别。
<7>:<include file=”login.xml”/>可能以后的配置文件回很多,但只有一个struts.xml.怎么办呢?写好每一个.xml后,直接来include就ok了。
看看login.xml
<struts>
<package name="struts-portlet-default" namespace="/login" extends="struts-default">
<action name="login" class="loginAction">
<result name="success">/show.jsp</result>
</action>
</package>
</struts>
这里是些简单的配置其中注意:namespace、extends。
下面的dao,都不说了,里面定义的是一些接口。关键说一下daoImpl:这里面是接口的实现类,最主要的一点是:继承了HibernateDaoSupport。这个类它是在:
org.springframework.orm.hibernate3.support.HibernateDaoSupport;
是spring对hibernate的封装,直接用getHibernaTemplete().就可以直接调用了。和以前创建session的实例是一样的。只不过这里给在底层封装了,这些东西交给了底层实现了。
void delete(Object entity)删除指定持久化实例。
deleteAll(Collection entities)删除集合内全部持久化实例。
find(String queryString)根据HQL查询字符串返回实例集合。
findByNamedQuery(Striing QueryName)根据命名查询返回实例集合。
Get(Class entityClass,Serializable id)割据主键加载特定持久化类的实例。
save(Object entity)保存实例。
saveOrUpdate(Object entity)根据实例状态,选择保存或者更新。
update(Object entity)更新实例的状态。
setMaxResults(int maxResults)设置分页大小。
HibernateCallback的复杂讲解:(回调应用)
HibernateTemplate还提供一种更加灵活的方式来操作数据库,通过这种方式可以完全使用Hibernate的操作方式。HibernateTemplate的灵活访问方式是通过如下两个方法完成:
Object execute(HibernateCallback action)
List execute(HibernateCallback action)
这两个方法都需要一个HibernateCallback的实例,HibernateCallback实例可在任何有效的Hibernate数据访问中使用。程序开发者通过HibernateCallback,可以完全使用Hibernate灵活的方式来访问数据库,解决Spring封装Hibernate后灵活性不足的缺陷。HibernateCallback是一个接口,该接口只有一个方法doInHibernate(org.hibernate.Session session),该方法只有一个参数Session。
通常,程序中采用实现HibernateCallback的匿名内部类来获取HibernateCallback的实例。举一个简单的例子说明下HibernateCallback的应用,其实有了这个东西的话就跟以前我们用session.CreateQuery();的这种写法一模一样了。
public List findPersonsByName(final String name) {
// 返回HibernateTemplate的execute的结果
return (List) this.getHibernateTemplate().execute(
// 创建匿名内部类
new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException {
// 使用条件查询的方法返回
List result = session.createCriteria(Users.class).add(
Restrictions.like("name", name + "%")).list();
return result;
}
});
}
(五):applicationContext.xml
这个是spring的核心配置文件,如果这里的配置很多的话,我们也可以用分层的方法,把它都分开,东西少的话能写在一个里面就行了。比如说:数据库的操作 – database.properties.然后新建一个applicationDatabase.xml 在这里面就是一些连接数据库的Bean管理了。包括hibernate的映射关系。到时候直接可以<include file = “applicationDatabase.xml”/>就行了。类似的业务层也同样的是建一个applicationResource.xml.在这个配置文件中定义的专门是业务的Bean管理了。这样层次就非常的清楚了。不用在一个文件中写的很多,耦合性很强。
<?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: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.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
(1) <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
(2) <bean id="trancationManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
(3) <bean id="impl" class="org.itfuture.www.dao.impl.LoginDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
(4)<bean id="loginAction" class="org.itfuture.www.action.LoginAction">
<property name="dao" ref="impl"></property>
</bean>
</beans>
注意:
<1>:前面的xml的<beans>必须得引正确。
<2>:Claspath:hibernate.cfg.xml 这个xml必须得放在工程的src下面,才能用classpath.
<3>:通过HibernateTransactionManager的bean我们就很容易的创建了一个sessionFactory就不用以前的传统的做法……。
<4>:从(4)中我们看到了<property name=”dao” ref=”impl”/>这里面的name 实际上就对应的是LoginAction中一个实例属性,这样做不用每次都来new了,直接通过依赖注入的模式来赋值,这样还不容易错(当然前提必须得配对了)、这叫属性注入,还有set、构造子注入以后回说。这个ref 它有两个属性 local=”impl” -- 这个表示:在本地也就是说当前的这个文件中的用local。bean=”impl” -- 这个表示:不在同一个文件中,但还想用到这个,那就用bean.
至于事务配置也很简单、以后回陆续的说。
总结:通过这三者的整合,使我们的开发效率回有很大的提过,不用写重复的代码。通过spring的引入,可以很好的把struts、Hibernate的整合,同时加上自身的优点,更加的使三者结合在一起了。SSH
(六):实际应用中CRUD(增、删、改、查)比较的常用,就以这个为例子,看看spring是如何管理hibernate的事务的。一般登陆成功后都会跳转到系统的主框架中,在这里让它跳转到一个成功的页面即:show.jsp
说明:这里面还是用到了struts2的标签:<s:url>和<s:a>.其中<s:a>与html标签的<a href=”url”>的用法一样。区别在于href=”%{bId}”,可以看到它这个应用到了<s:url>中的id,action即对应的是配置文件中的name属性。最后<s:a>翻译过来为
<a href=”/SpringOne/login/book.action”>书籍查询</a>,点击了这个后它会自动的去在配置文件中寻找其对应的一个方法。
<action name="book" class="bookAction" method="findBooks">
<result name="success">/book.jsp</result>
<result name="error">/error.jsp</result>
</action>
其中红色部分对应的是action中的一个方法,跟struts1.x中的DispatcherAction的分派一样的道理。在后台对应的Action中:
注:这里面的一个request是此action实现了ServletRequestAware中的setServletRequest方法,把改方法重写了对request进行了赋值,对此就可以用request了,request的用法和struts1.x中的用法是一样的。只不过在前台页面当中取值有所改变。
前台它用的是标签<s:iterator value=”%{#request.list}”>来取值,跟struts1.x中的<logic:iterator>区别开来。它的每一个属性的取值得注意:<s:property value=”#book.id”/>,这里面的book就是Action中对应的一个实体Bean.所看到的画面:
这个说明的是页面的展现。
(七):看新增的做法:
这个画面主要用到了struts2.0中的两个标签<s:textfield>和<s:textarea>.
<s:textfield name=”book.bookName” label=”书籍名称”/>可以对应源文件中的发现:
<tr>
<td class="tdLabel"><label for="saveBook_book_bookName" class="label">书籍名称:</label>
</td>
<td><input type="text" name="book.bookName" value="" id="saveBook_book_bookName"/></td>
</tr>
一个标签换成html代码就这么多,并且class都是自己加的。主要看的是id。saveBook是form 中的所要提交对应的名字,所以这个id。saveBook_book_bookName.下面的<s:textarea name=”book_bookDesc” label=”书籍描述”/>是一样的。
同样的道理提交的时候现经过配置文件:
Method:属性:对应Action中的其中的一个方法,大小写注意。
Action中得到的数据是通过request来得到的,这是其中的一种方法,还有就是通过实体Bean
来获得。即:book.getBookName();两者是一样的。主要看下:spring是怎么来管理hibernate
的事务的。
BookDaoImpl。这个是bookDao接口的一个实现类。
上面写出两种的实现方式:
(1):直接使用的是hibernate的事务,即:打开一个---使用---关闭一个事务。
(2):hibernate的事务直接交给了spring的Bean来管理了。Spring底层把hibernate的事务已
给封装的很好了,我们只需要继承它这个Bean类即可。--HibernateDaoSupport
这个就是HibernateDaoSupport底层类的写法,有兴趣可以看看它的源码。
Spring配置hibernate的事务共有4中配置,现说一种比较常用的。
主要看下配置文件中的配置:
说明:
用到了spring的事务代理Bean,很明显就是Hibernate的事务交给spring去代理去了。
(1):属性transactionManager,寻找transactionManger(上面所配置的事务Bean).
(2):transactionAttributes事务的属性。
Get*、Insert*、update*、表示:表示类方法名称是以get开头的方法,需要事务。
*是通配符。
PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
(3):<bean id=”implProxy” parent=”txBase”> 继承父的(上面画面上已经定义)
<property name=”target”> 继承完了就可以用这里面的事务了,目标是ref -- 寻找去。
<ref local=”bImpl”>
</property>
</bean>
上面所说的这一中事务比较常用。但是必须得配置对了,才能发挥作用,要不然错误一大片,找都不好找。
下面的修改、删除都是一个意思.
getHibernateTemplate().update(实例)。
getHibernateTemplate().delete(实例);
(八):所遇到的问题:
<1>:在做事务提交的时候,spring中的bean已经把hibernate的事务代理了。直接getHibernateTemplate().save(实例).就ok了。但是试了好多遍都不行,最后在 hibernate.cfg.xml中配置了自动事务提交为true,就好了.这个配置跟spring做配置的缓存还是有一定的关系,这个还得继续查一查。
<2>:在Action新增完毕后都是直接返回到列表页面的。可是如果单单的这么写是出不来的。
<3>:struts2.0的其它标签没用到,有的还不是很熟悉,写原始标签也是可以的。