Struts2+hibernate3.0+spring2.0整合
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" 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" ref="sessionFactory"></property>?
? </bean>?
(4)<bean id="loginAction"? 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" 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 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的其它标签没用到,有的还不是很熟悉,写原始标签也是可以的。?