﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-爪哇一角-文章分类-框架文章</title><link>http://www.blogjava.net/ocean07000814/category/15418.html</link><description>共同探讨STRUTS#HIBERNATE#SPRING#EJB等技术</description><language>zh-cn</language><lastBuildDate>Sat, 12 Jun 2010 09:14:46 GMT</lastBuildDate><pubDate>Sat, 12 Jun 2010 09:14:46 GMT</pubDate><ttl>60</ttl><item><title>Struts1和Struts2的区别</title><link>http://www.blogjava.net/ocean07000814/articles/323242.html</link><dc:creator>非洲小白脸</dc:creator><author>非洲小白脸</author><pubDate>Thu, 10 Jun 2010 07:42:00 GMT</pubDate><guid>http://www.blogjava.net/ocean07000814/articles/323242.html</guid><wfw:comment>http://www.blogjava.net/ocean07000814/comments/323242.html</wfw:comment><comments>http://www.blogjava.net/ocean07000814/articles/323242.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ocean07000814/comments/commentRss/323242.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ocean07000814/services/trackbacks/323242.html</trackback:ping><description><![CDATA[<pre>Struts1和Struts2的区别和对比 (转) <br />
&#8226; Struts1要求Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口。 <br />
&#8226; Struts 2 Action类可以实现一个Action接口，也可实现其他接口，使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类去 实现 常用的接口。Action接口不是必须的，任何有execute标识的POJO对象都可以用作Struts2的Action对象。 <br />
线程模式: <br />
&#8226; Struts1 Action是单例模式并且必须是线程安全的，因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事，并且要在开发时特别小心。Action资源必须是线程安全的或同步的。 <br />
&#8226; Struts2 Action对象为每一个请求产生一个实例，因此没有线程安全问题。（实际上，servlet容器给每个请求产生许多可丢弃的对象，并且不会导致性能和垃圾回收问题） <br />
<br />
Servlet 依赖: <br />
&#8226; Struts1 Action 依赖于Servlet API ,因为当一个Action被调用时HttpServletRequest 和 HttpServletResponse 被传递给execute方法。 <br />
&#8226; Struts 2 Action不依赖于容器，允许Action脱离容器单独被测试。如果需要，Struts2 Action仍然可以访问初始的request和response。但是，其他的元素减少或者消除了直接访问HttpServetRequest 和 HttpServletResponse的必要性。 <br />
<br />
可测性: <br />
&#8226; 测试Struts1 Action的一个主要问题是execute方法暴露了servlet API（这使得测试要依赖于容器）。一个第三方扩展－－Struts TestCase－－提供了一套Struts1的模拟对象（来进行测试）。 <br />
&#8226; Struts 2 Action可以通过初始化、设置属性、调用方法来测试，&#8220;依赖注入&#8221;支持也使测试更容易。 <br />
<br />
捕获输入: <br />
&#8226; Struts1 使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm，开发者经 常创建多余的类捕获输入。动态Bean（DynaBeans）可以作为创建传统ActionForm的选择，但是，开发者可能是在重新描述(创建)已经存 在的JavaBean（仍然会导致有冗余的javabean）。 <br />
&#8226; Struts 2直接使用Action属性作为输入属性，消除了对第二个输入对象的需求。输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过 web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型，包括业务对象，能够用作输入/输出对象。这种 ModelDriven 特性简化了taglib对POJO输入对象的引用。 <br />
<br />
表达式语言： <br />
&#8226; Struts1 整合了JSTL，因此使用JSTL EL。这种EL有基本对象图遍历，但是对集合和索引属性的支持很弱。 <br />
&#8226; Struts2可以使用JSTL，但是也支持一个更强大和灵活的表达式语言－－"Object Graph Notation Language" (OGNL). <br />
<br />
绑定值到页面（view）: <br />
&#8226; Struts 1使用标准JSP机制把对象绑定到页面中来访问。 <br />
&#8226; Struts 2 使用 "ValueStack"技术，使taglib能够访问值而不需要把你的页面（view）和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重用页面（view）。 <br />
<br />
类型转换： <br />
&#8226; Struts 1 ActionForm 属性通常都是String类型。Struts1使用Commons-Beanutils进行类型转换。每个类一个转换器，对每一个实例来说是不可配置的。 <br />
&#8226; Struts2 使用OGNL进行类型转换。提供基本和常用对象的转换器。 <br />
<br />
校验： <br />
&#8226; Struts 1支持在ActionForm的validate方法中手动校验，或者通过Commons Validator的扩展来校验。同一个类可以有不同的校验内容，但不能校验子对象。 <br />
&#8226; Struts2支持通过validate方法和XWork校验框架来进行校验。XWork校验框架使用为属性类类型定义的校验和内容校验，来支持chain校验子属性 <br />
<br />
Action执行的控制： <br />
&#8226; Struts1支持每一个模块有单独的Request Processors（生命周期），但是模块中的所有Action必须共享相同的生命周期。 <br />
&#8226; Struts2支持通过拦截器堆栈（Interceptor Stacks）为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用。</pre>
<img src ="http://www.blogjava.net/ocean07000814/aggbug/323242.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ocean07000814/" target="_blank">非洲小白脸</a> 2010-06-10 15:42 <a href="http://www.blogjava.net/ocean07000814/articles/323242.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts,JSF,MVC等实现原理</title><link>http://www.blogjava.net/ocean07000814/articles/323241.html</link><dc:creator>非洲小白脸</dc:creator><author>非洲小白脸</author><pubDate>Thu, 10 Jun 2010 07:37:00 GMT</pubDate><guid>http://www.blogjava.net/ocean07000814/articles/323241.html</guid><wfw:comment>http://www.blogjava.net/ocean07000814/comments/323241.html</wfw:comment><comments>http://www.blogjava.net/ocean07000814/articles/323241.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ocean07000814/comments/commentRss/323241.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ocean07000814/services/trackbacks/323241.html</trackback:ping><description><![CDATA[JSF六个底层原理：
<br />
--重建组件树：jsf应用里的jsp页面被表示成一个组件树。在这个阶段里，通过重建这棵树开始LifeCycle处理过程。每个组件树都有一个在整个应用程序范围里唯一的标识符，此标识符是所请求URI的路径信息部分
<br />
--应用请求值：在这个阶段，使用请求里的当前值来更新每个组件的本地值，这些值可能来自请求参数，请求的包头及cookie。在这个阶段的处理中，组件可以往事件队列里加入某些事件，这些事件可在随后的处理阶段处理
<br />
--处理验证：当每个组件的本地值被更新后，在此阶段中LifeCycle对象会验证这些值的合法性。要求验证的组件必须提供验证逻辑的实现。作
为选择，开发人员可以为一个组件注册0个或者多个验证器。如果发现外部验证器，那么还会应用这些外部验证器里的验证逻辑来验证本地值。
<br />
--更新模型值：只有当组件树中所有的组件的本地值都通过验证后，才有可能到达该阶段。在这个阶段中，LifeCycle更新呢应用的模型数据。组件在这个节点也可以排列事件。
<br />
--调用应用：在这个阶段，JSF实现处理所有应用层次的时间。
<br />
--呈现响应：在这个阶段，JSF实现将相应发挥客户端。
<br />
<br />
JSF的生命周期：
<br />
恢复视图--应用请求值--处理验证--呈现响应--调用应用程序--更新模型值
<br />
<br />
JSF的工作方式：
<br />
JSF应用是通过处理由页面中组件处罚的事件来工作的。这些事件是由用户的动作引起的。（JSF是事件驱动的）
<br />
--创建FacesContext
<br />
--把控制权交给LifeCycle
<br />
--分六个阶段处理FacesContext
<br />
<br />
ajax原理：
<br />
-----一个异步无刷新的技术，主要是通过在客户端浏览器内置的XMLHttpRequest对象，发送和接收请求。
<br />
XMLHttpRequest对象先把请求发送给浏览器中内置的ajax引擎，通过引擎转发给对应的服务器，并且引擎还要负责接收服务器的返回，
和服务器进行交互，即时获取服务器的状态。还要负责把服务器的返回发送给客户端。客户端通过XMLHttpRequest对象对返回结果进行解析
<br />
<br />
<br />
Http原理：
<br />
----最常见的网络传输协议。速度快，无状态。
<br />
----不管客户端用什么频率去请求服务器的资源，服务器只会去响应，而不会去保存客户端的任何状态
<br />
<br />
<br />
Struts原理：
<br />
----web服务器启动的时候读取web.xml文档，创建ActionServlet对象。
<br />
----当客户端请求发起是，ActionServlet拦截请求，截取特定的请求，获取请求的名称。
<br />
----然后读取Struts读取配置文件,根据请求的名称读取相关信息，保存在moduleConfig对象中
<br />
----找到其中的ActionMapping和path属性，来进行请求是否匹配的判断
<br />
----如果发现有对应的path，则将请求转到对应的Action，并且创建ActionForm对象，获取从请求中传递来的参数，将参数保存在ActionForm中，调用Action的execute方法
<br />
----ActionServlet接收Action处理完业务逻辑返回的结果---ActionForward对象
<br />
----然后在配置文件找到对应的forward路径，将显示转发或者重定向到找到的路径。
<br />
<br />
Servlet MVC原理：
<br />
----服务器启动的时候读取web.xml，创建servlet对象。
<br />
----当客户端发起请求的时候，servlet负责拦截指定的请求，根据请求的方式是get还是post调用对象的doGet或者doPost方法。
<br />
----doGet，doPost中通过request或者response控制页面的转发或者重定向
<img src ="http://www.blogjava.net/ocean07000814/aggbug/323241.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ocean07000814/" target="_blank">非洲小白脸</a> 2010-06-10 15:37 <a href="http://www.blogjava.net/ocean07000814/articles/323241.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts+Spring+Hibernate的练习(完整)(转) </title><link>http://www.blogjava.net/ocean07000814/articles/70581.html</link><dc:creator>非洲小白脸</dc:creator><author>非洲小白脸</author><pubDate>Tue, 19 Sep 2006 09:23:00 GMT</pubDate><guid>http://www.blogjava.net/ocean07000814/articles/70581.html</guid><wfw:comment>http://www.blogjava.net/ocean07000814/comments/70581.html</wfw:comment><comments>http://www.blogjava.net/ocean07000814/articles/70581.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ocean07000814/comments/commentRss/70581.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ocean07000814/services/trackbacks/70581.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Struts+Spring+Hibernate练习(完整)																																						工具：								    Eclipse3.1、MyEclipse4.03、Tomcat5.5.9、Properties Editor插件、MySql4.1.13								 								新建工程：名称为 lo...&nbsp;&nbsp;<a href='http://www.blogjava.net/ocean07000814/articles/70581.html'>阅读全文</a><img src ="http://www.blogjava.net/ocean07000814/aggbug/70581.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ocean07000814/" target="_blank">非洲小白脸</a> 2006-09-19 17:23 <a href="http://www.blogjava.net/ocean07000814/articles/70581.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>spring + hibernate 数据化持久层 [转] </title><link>http://www.blogjava.net/ocean07000814/articles/70580.html</link><dc:creator>非洲小白脸</dc:creator><author>非洲小白脸</author><pubDate>Tue, 19 Sep 2006 09:22:00 GMT</pubDate><guid>http://www.blogjava.net/ocean07000814/articles/70580.html</guid><wfw:comment>http://www.blogjava.net/ocean07000814/comments/70580.html</wfw:comment><comments>http://www.blogjava.net/ocean07000814/articles/70580.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ocean07000814/comments/commentRss/70580.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ocean07000814/services/trackbacks/70580.html</trackback:ping><description><![CDATA[
		<div class="postTitle">
				<a class="postTitle2" id="viewpost1_TitleUrl" href="/ocean07000814/archive/2006/09/19/70556.html">
						<font color="#56b6e9">
						</font>
				</a> </div>
		<div class="diary_datetitle">
				<font color="#56b6e9">
				</font> </div>
		<table class="diary_bg1" cellspacing="3" cellpadding="3" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<a class="diary_title" href="http://www.blogcn.com/u/40/61/zzxanadu/blog/41223442.html">
												<font color="#56b6e9">
														<font class="diary_title">spring + hibernate 数据话持久层 [转]</font>
												</font>
										</a>
										<a name="41223442">
										</a>
										<span id="oImg4" style="FLOAT: left; HEIGHT: 49px" vspace="10" hspace="10">
												<font color="#56b6e9">
												</font>
										</span>
										<table style="WIDTH: 96px; HEIGHT: 9px" cellspacing="2" cellpadding="6" width="96">
												<tbody>
														<tr>
																<td>
																		<font style="FONT-WEIGHT: normal; FONT-SIZE: 8pt; LINE-HEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal" color="#56b6e9">
																				<center> </center>
																		</font>
																</td>
														</tr>
												</tbody>
										</table>
										<script language="JavaScript"><![CDATA[nChangeFloat('left','oImg4');]]&gt;</script>
										<br />spring + hibernate 数据话持久层（转） <br /> <br />张利海 发表<br />   <br />对于J2EE 应用程序而言，事务的处理一般有两种模式：<br />1． 依赖特定事务资源的事务处理<br />这是应用开发中最常见的模式，即通过特定资源提供的事务机制进行事务管理。<br />        如通过JDBC、JTA 的rollback、commit方法；Hibernate Transaction 的rollback、commit方法等。这种方法大家已经相当熟悉。<br />2． 依赖容器的参数化事务管理<br />通过容器提供的集约式参数化事务机制，实现事务的外部管理，如EJB 中的事务管理模式。<br />        如，下面的EJB事务定义中，将SessionBean MySession的doService方<br />法定义为Required。也就是说，当MySession.doServer 方法被某个线程调用时，容器将此线程纳入事务管理容器，方法调用过程中如果发生异常，当前事务将被容器自动回滚，如果方法正常结束，则容器将自动提交当前事务。<br />&lt;container-transaction &gt;<br />&lt;method &gt;<br />&lt;ejb-name&gt;MySession&lt;/ejb-name&gt;<br />&lt;method-intf&gt;Remote&lt;/method-intf&gt;<br />&lt;method-name&gt;doService&lt;/method-name&gt;<br />&lt;method-params&gt;<br />&lt;method-param&gt;java.lang.String&lt;/method-param&gt;<br />&lt;/method-params&gt;<br />&lt;/method&gt;<br />&lt;trans-attribute&gt;Required&lt;/trans-attribute&gt;<br />&lt;/container-transaction&gt;<br />容器管理的参数化事务为程序开发提供了相当的灵活性，同时因为将事务委托给容器进行管理，应用逻辑中无需再编写事务代码，大大节省了代码量（特别是针对需要同时操作多个事务资源的应用），从而提高了生产率。然而，使用EJB 事务管理的代价相当高昂，撇开EJB 容器不菲的价格，EJB的学习成本，部署、迁移、维护难度，以及容器本身带来的性能开销（这往往意味着需要更高的硬件配置）都给我们带来了相当的困惑。此时事务管理所带来的优势往往还不能抵消上面这些负面影响。<br /><br />Spring事务管理能给我们带来什么?<br /><br />下面这段xml配置片断展示了Spring中的事务设定方式：<br />&lt;beans&gt;<br />&lt;bean id="dataSource"<br />class="org.apache.commons.dbcp.BasicDataSource"<br />destroy-method="close"&gt;<br />&lt;property name="driverClassName"&gt;<br />&lt;value&gt;org.gjt.mm.mysql.Driver&lt;/value&gt;<br />&lt;/property&gt;<br />&lt;property name="url"&gt;<br />&lt;value&gt;jdbc:mysql://localhost/sample&lt;/value&gt;<br />&lt;/property&gt;<br />&lt;property name="username"&gt;<br />&lt;value&gt;user&lt;/value&gt;<br />&lt;/property&gt;<br />&lt;property name="password"&gt;<br />&lt;value&gt;mypass&lt;/value&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;bean id="transactionManager"<br />class="org.springframework.jdbc.datasource.DataSourceTr<br />ansactionManager"&gt;<br />&lt;property name="dataSource"&gt;<br />&lt;ref local="dataSource" /&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;bean id="userDAO" class="net.xiaxin.dao.UserDAO"&gt;<br />&lt;property name="dataSource"&gt;<br />&lt;ref local="dataSource" /&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;<br />SpringFrameWork Developer’s Guide Version 0.6<br />October 8, 2004 So many open source projects. Why not Open your Documents?<br />&lt;bean id="userDAOProxy"<br />class="org.springframework.transaction.interceptor.Tran<br />sactionProxyFactoryBean"&gt;<br />&lt;property name="transactionManager"&gt;<br />&lt;ref bean="transactionManager" /&gt;<br />&lt;/property&gt;<br />&lt;property name="target"&gt;<br />&lt;ref local="userDAO" /&gt;<br />&lt;/property&gt;<br />&lt;property name="transactionAttributes"&gt;<br />&lt;props&gt;<br />&lt;prop key="insert*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="get*"&gt;<br />PROPAGATION_REQUIRED,readOnly<br />&lt;/prop&gt;<br />&lt;/props&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;/beans&gt;<br />配置中包含了dataSource，transactionManager 等资源定义。这些资源都为一个名为userDAOProxy 的TransactionProxyFactoryBean 服务， 而userDAOProxy 则对包含实际数据逻辑的userDAO进行了事务性封装。<br />可以看到，在userDAOProxy 的"transactionAttributes"属性中，我们定义了针对userDAO 的事务策略，即将所有名称以insert 开始的方法（如UserDAO.insertUser方法）纳入事务管理范围。如果此方法中抛出异常，则Spring<br />将当前事务回滚，如果方法正常结束，则提交事务。而对所有名称以get 开始的方法（如UserDAO.getUser 方法）则以只读的事务处理机制进行处理。（设为只读型事务，可以使持久层尝试对数据操作进行优化，如对<br />于只读事务Hibernate将不执行flush操作，而某些数据库连接池和JDBC 驱动也对只读型操作进行了特别化。）<br />        结合上面这段申明带来的感性认知，看看Spring 的事务管理机制与EJB 中事务管理有何不同，或者有何优势。这里自然有许多方面可以比较，不过，笔者认为其中最为关键的两点是：<br />1． Spring可以将任意Java Class 纳入事务管理<br />这里的UserDAO只是我们编写的一个普通Java Class，其中包含了一些基本的数据应用逻辑。通过Spring，我们即可简单的实现事务的可配置化。也就是说，我们可以随意为某个类的某个方法指定事务管理机制。与之对比，如果使用EJB容器提供的事务管理功能，我们不得不按照EJB规范编将UserDAO 进行改造，将其转换为一个标准的EJB。<br />2． Spring事务管理并不依赖特定的事务资源。<br />EJB 容器必须依赖于JTA 提供事务支持。而Spring 的事务管理则支持JDBC、JTA 等多种事务资源。这为我们提供了更多的选择，从而也使得我们的系统部署更加灵活。<br />        对Spring事务管理机制进行简单分析之后，我们将结合持久层封装的具体事务应用机制，对Spring中的事务管理进行更具实效的探讨。<br />                                                                      持久层封装<br />                                                                           JDBC<br />Spring对JDBC进行了良好的封装，通过提供相应的模板和辅助类，在相当程度上降低了JDBC操作的复杂性。并且得益于Spring良好的隔离设计，JDBC封装类库可以脱离Spring Context独立使用，也就是说，即使系统并没有采用Spring作为结构性框架，我们也可以单独使用Spring的JDBC部分（spring-dao.jar）来改善我们的代码。作为对比，首先让我们来看一段传统的JDBC代码：<br />Connection conn =null;<br />Statement stmt = null;<br />try {<br />conn = dataSource.getConnection();<br />stmt = con.createStatement();<br />stmt.executeUpdate("UPDATE user SET age = 18 WHERE id = 'erica'"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />} finally {<br />if (stmt != null) {<br />try {<br />stmt.close();<br />} catch (SQLException ex) {<br />logger.warn("Exception in closing JDBC Statement", ex);<br />}<br />}<br />if (conn != null) {<br />try {<br />conn.close();<br />} catch (SQLException ex) {<br />logger.warn("Exception in closing JDBC Connection", ex);<br />}<br />}<br />}<br />类似上面的代码非常常见。为了执行一个SQL语句，我们必须编写22行代码，而其中21行与应用逻辑并无关联，并且，这样的代码还会在系统其他地方（也许是每个需要数据库访问的地方）重复出现。<br />于是，大家开始寻找一些设计模式以改进如此的设计，Template模式的应用是其中一种典型的改进方案。Spring的JDBC封装，很大一部分就是借助Template模式实现，它提供了一个优秀的JDBC模板库，借助这个工具，我们可以简单有效的对传统的JDBC编码方式加以改进。下面是借助Spring JDBC Template修改过的代码，这段代码完成了与上面代码相同的功能。<br /><br />JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);<br />jdbcTemplate.update("UPDATE user SET age = 10 WHERE id = 'erica'"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br /><br />可以看到，两行代码完成了上面需要19行代码实现的功能。所有冗余的代码都通过合理的抽象汇集到了JdbcTemplate中。无需感叹，借助Template模式，我们大致也能实现这样一个模板，不过，Spring的设计<br />者已经提前完成了这一步骤。org.springframework.jdbc.core.JdbcTemplate中包含了这个模板实现的代码，经过Spring设计小组精心设计，这个实现可以算的上是模板应用的典范。特别是回调（CallBack）的使用，使得整个模板结构清晰高效。值得一读。<br /><br />Tips:实际开发中，可以将代码中硬编码的SQL语句作为Bean的一个String类型属性，借助DI机制在配置文件中定义，从而实现SQL的参数化配置。<br /><br />再对上面的例子进行一些改进，通过PrepareStatement执行update操作以避免SQL<br />Injection 漏洞 9：<br />JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);<br />jdbcTemplate<br />.update(<br />"UPDATE user SET age = ? WHERE id = ?",<br />new PreparedStatementSetter() {<br />public void setValues(PreparedStatementSetter ps)<br />throws SQLException {<br />ps.setInt(1, 18);<br />ps.setString(2, "erica"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />}<br />}<br />);<br />可以看到，上面引用了update方法的另一个版本，传入的参数有两个，第一个用于创建<br />PreparedStatement的SQL。第二个参数是为PreparedStatement设定参数的PreparedStatementSetter。<br />第二个参数的使用方法比较独到，我们动态新建了一个PreparedStatementSetter类，并实现了这个抽象类的setValues方法。之后将这个类的引用作为参数传递给update。update接受参数之后，即可调用第二个参数提供的方法完成PreparedStatement的初始化。<br />Spring JDBC Template中大量使用了这样的Callback机制，这带来了极强的灵活性和扩展性。<br />上面演示了update方法的使用（同样的操作适用于update、insert、delete）。下面是一个查询的示例。<br />final List userList = new ArrayList();<br />JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);<br />jdbcTemplate<br />.query(<br />"SELECT name, sex, address FROM user WHERE age &gt; 18",<br />9 SQL Injection： SQL语句中直接引入参数值而导致的系统漏洞，具体请参见以下论文：<br /><img alt="::URL::" hspace="2" src="http://www.blogcn.com/images/aurl.gif" align="absBottom" border="0" /><a href="http://www.governmentsecurity.org/articles/SQLInjectionModesofAttackDefenceandWhyItMatters.php" target="_blank"><font color="#56b6e9">http://www.governmentsecurity.org/articles/SQLInjectionModesofAttackDefenceandWhyItMatters.php</font></a><br />SpringFrameWork Developer’s Guide Version 0.6<br />October 8, 2004 So many open source projects. Why not Open your Documents?<br />new RowCallbackHandler() {<br />public void processRow(ResultSet rs) throws SQLException {<br />User user = new User();<br />user.setId(rs.getString("name"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>);<br />user.setSex(rs.getString("sex"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>);<br />user.setAddress(rs.getString("address"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>);<br />userList.add(product);<br />}<br />}<br />);<br />这里传入query方法的有两个参数，第一个是Select查询语句，第二个是一个RowCallbackHandler实例，我们通过RowCallbackHandler对Select语句得到的每行记录进行解析，并为其创建一个User数据对象。实现了手动的OR映射。此外，我们还可以通过JdbcTemplate.call方法调用存储过程。query、update方法还有其他很多不同参数版本的实现，具体调用方法请参见SpringJavaDoc。<br />                                                                 <br />                                                              JdbcTemplate与事务<br /><br />上例中的JdbcTemplate操作采用的是JDBC默认的AutoCommit模式，也就是说我们还无法保证数据操作的原子性（要么全部生效，要么全部无效），如：<br />JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);<br />jdbcTemplate.update("UPDATE user SET age = 10 WHERE id = 'erica'"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />jdbcTemplate.update("UPDATE user SET age = age+1 WHERE id = 'erica'"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />由于采用了AutoCommit模式，第一个update操作完成之后被自动提交，数据库中”erica”对应的记录已经被更新，如果第二个操作失败，我们无法使得整个事务回滚到最初状态。对于这个例子也许无关紧要，但是对于一个金融帐务系统而言，这样的问题将导致致命错误。<br />为了实现数据操作的原子性，我们需要在程序中引入事务逻辑，在JdbcTemplate中引入事务机制，在Spring中有两种方式：<br />1． 代码控制的事务管理<br />2． 参数化配置的事务管理<br />下面就这两种方式进行介绍。<br />u 代码控制的事务管理<br />首先，进行以下配置，假设配置文件为（Application-Context.xml）：<br />&lt;beans&gt;<br />&lt;bean id="dataSource"<br />SpringFrameWork Developer’s Guide Version 0.6<br />October 8, 2004 So many open source projects. Why not Open your Documents?<br />class="org.apache.commons.dbcp.BasicDataSource"<br />destroy-method="close"&gt;<br />&lt;property name="driverClassName"&gt;<br />&lt;value&gt;net.sourceforge.jtds.jdbc.Driver&lt;/value&gt;<br />&lt;/property&gt;<br />&lt;property name="url"&gt;<br />&lt;value&gt;jdbc:jtds:sqlserver://127.0.0.1:1433/Sample&lt;/value&gt;<br />&lt;/property&gt;<br />&lt;property name="username"&gt;<br />&lt;value&gt;test&lt;/value&gt;<br />&lt;/property&gt;<br />&lt;property name="password"&gt;<br />&lt;value&gt;changeit&lt;/value&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;bean id="transactionManager"<br />class="org.springframework.jdbc.datasource.DataSourceTransac<br />tionManager"&gt;<br />&lt;property name="dataSource"&gt;<br />&lt;ref local="dataSource" /&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;bean id="userDAO" class="net.xiaxin.dao.UserDAO"&gt;<br />&lt;property name="dataSource"&gt;<br />&lt;ref local="dataSource" /&gt;<br />&lt;/property&gt;<br />&lt;property name="transactionManager"&gt;<br />&lt;ref local="transactionManager" /&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;/beans&gt;<br />配置中包含了三个节点:<br />&amp;Oslash; dataSource<br />这里我们采用了apache dhcp组件提供的DataSource实现，并为其配置了JDBC驱动、数据库URL、用户名和密码等参数。<br />&amp;Oslash; transactionManager<br />针对JDBC DataSource类型的数据源，我们选用了DataSourceTransactionManager作为事务管理组件。<br />如果需要使用基于容器的数据源（JNDI），我们可以采用如下配置：<br />SpringFrameWork Developer’s Guide Version 0.6<br />October 8, 2004 So many open source projects. Why not Open your Documents?<br />&lt;bean id="dataSource"<br />class="org.springframework.jndi.JndiObjectFactoryBean"&gt;<br />&lt;property name="jndiName"&gt;<br />&lt;value&gt;jdbc/sample&lt;/value&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;bean id="transactionManager"<br />class="org.springframework.transaction.jta.JtaTrans<br />actionManager"<br />/&gt;<br />&amp;Oslash; userDAO<br />申明了一个UserDAO Bean，并为其指定了dataSource和transactionManger资源。<br />UserDAO对应的代码如下：<br />public class UserDAO {<br />private DataSource dataSource;<br />SpringFrameWork Developer’s Guide Version 0.6<br />October 8, 2004 So many open source projects. Why not Open your Documents?<br />private PlatformTransactionManager transactionManager;<br />public PlatformTransactionManager getTransactionManager() {<br />return transactionManager;<br />}<br />public void setTransactionManager(PlatformTransactionManager<br />transactionManager) {<br />this.transactionManager = transactionManager;<br />}<br />public DataSource executeTestSource() {<br />return dataSource;<br />}<br />public void setDataSource(DataSource dataSource) {<br />this.dataSource = dataSource;<br />}<br />public void insertUser() {<br />TransactionTemplate tt =<br />new TransactionTemplate(getTransactionManager());<br />tt.execute(new TransactionCallback() {<br />public Object doInTransaction(TransactionStatus status) {<br />JdbcTemplate jt = new JdbcTemplate(executeTestSource());<br />jt.update(<br />"insert into users (username) values ('xiaxin');"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />jt.update(<br />"insert into users (id,username) values(2,<br />'erica');"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />return null;<br />}<br />});<br />}<br />}<br />可以看到，在insertUser方法中，我们引入了一个新的模板类：<br />org.springframework.transaction.support.TransactionTemplate。<br />TransactionTemplate封装了事务管理的功能，包括异常时的事务回滚，以及操作成功后的事务提交。和JdbcTemplate一样，它使得我们无需在琐碎的try/catch/finally代码中徘徊。<br />在doInTransaction中进行的操作，如果抛出未捕获异常将被自动回滚，如果成功执行， 则将被自动提交。<br />这里我们故意制造了一些异常来观察数据库操作是否回滚（通过在第二条语句中更新自增ID字段故意触发一个异常）：<br />编写一个简单的TestCase来观察实际效果：<br />InputStream is = new FileInputStream("Application-Context.xml"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />XmlBeanFactory factory = new XmlBeanFactory(is);<br />UserDAO userDAO = (UserDAO) factory.getBean("userDAO"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />userDAO.insertUser();<br />相信大家多少觉得上面的代码有点凌乱，Callback类的编写似乎也有悖于日常的编程习惯（虽然笔者觉得这一方法比较有趣，因为它巧妙的解决了笔者在早期自行开发数据访问模板中曾经遇到的问题）。如何进一步避免上面这些问题？Spring 的容器事务管理机制在这里即体现出其强大的能量。u 参数化配置的事务管理在上面的Application-Context.xml增加一个事务代理（UserDAOProxy）配置，同时，由于事务由容器管理，UserDAO不再需要TransactionManager设定，将其移除：<br />&lt;bean id="UserDAOProxy"<br />class="org.springframework.transaction.interceptor.Transac<br />tionProxyFactoryBean"&gt;<br />&lt;property name="transactionManager"&gt;<br />&lt;ref bean="transactionManager" /&gt;<br />&lt;/property&gt;<br />&lt;property name="target"&gt;<br />&lt;ref local="userDAO" /&gt;<br />&lt;/property&gt;<br />&lt;property name="transactionAttributes"&gt;<br />&lt;props&gt;<br />&lt;prop key="insert*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br />&lt;/props&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;bean id="userDAO" class="net.xiaxin.dao.UserDAO"&gt;<br />&lt;property name="dataSource"&gt;<br />&lt;ref local="dataSource" /&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;<br />SpringFrameWork Developer’s Guide Version 0.6<br />October 8, 2004 So many open source projects. Why not Open your Documents?<br />上面的配置中，UserDAOProxy节点配置了一个针对userDAO bean的事务代理（由target属性指定）。通过transactionAttributes属性，我们指定了事务的管理策略，即对所有以insert开头的方法进行事务管理，如果被管理方法抛出异常，则自动回滚方法中的事务，如果成功执行，则在方法完成之后进行事务提交。另一方面对于其他方法（通过通配符*表示），则进行只读事务管理，以获得更好的性能。与之对应UserDAO.insertUser的代码修改如下：<br />public void insertUser(RegisterInfo regInfo) {<br />JdbcTemplate jt = new JdbcTemplate(executeTestSource());<br />jt.update("insert into users (username) values ('xiaxin');"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />jt.update("insert into users (id,username) values (2,'erica');"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />}<br />测试代码修改如下：<br />InputStream is = new FileInputStream("Application-Context.xml"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />XmlBeanFactory factory = new XmlBeanFactory(is);<br />//注意这里须通过代理Bean"userDAOProxy"获得引用，而不是直接getBean(“userDAO”)<br />//此外这里还存在一个有关强制转型的潜在问题，请参见Hibernate in Spring一节后<br />//关于强制转型的补充描述。<br />UserDAO userDAO = (UserDAO) factory.getBean("userDAOProxy"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />userDAO.insertUser();<br />可以看到，insertUser变得非常简洁。数据逻辑清晰可见，对比前面代码控制的事务管理，以及传统的JDBC操作，相信大家会有一些霍然开朗的感觉。细心的读者会说，这只不过将代码转移到了配置文件，并没有减少太多的工作量。这点区别也许并不重要，从应用维护的角度而言，配置化的事务管理显然更具优势。何况，实际开发中，如果前期设计细致，方法的事务特性确定之后一般不会发生大的变动，之后频繁的维护过程中，我们只需面对代码中的数据逻辑即可。上面我们结合JdbcTemplate介绍了Spring中的模板操作以及事务理机制。Spring作为一个开放式的应用开发平台。同时也针对其他组件提供了良好的支持。在持久层，Spring提供面向了Hibernate、ibatis和JDO的模板实现，同样，这些实现也为我们的开发提供了强有力的支持。<br />下面我们就hibernate、ibatis这两种主流持久层框架在Spring中的使用进行介绍。至于JDO，由于实际开发中使用并不广泛（实际上笔者觉得JDO前景堪忧），这里也就不重点介绍，有兴趣的读者可参见Spring-Reference中的相关章节。<br />SpringFrameWork Developer’s Guide Version 0.6<br />October 8, 2004 So many open source projects. Why not Open your Documents?<br />Hibernate in Spring<br />Hibernate在开源的持久层框架中无疑是近期最为鲜亮的角色，其作者甚至被邀请加入<br />新版EJB设计工作之中，足见Hibernate设计的精彩贴切。关于Hibernate的使用，在笔者<br />的另外一篇文档中进行了探讨：<br />《Hibernate开发指南》 <img alt="::URL::" hspace="2" src="http://www.blogcn.com/images/aurl.gif" align="absBottom" border="0" /><a href="http://www.xiaxin.net/Hibernate_DEV_GUIDE.rar。" target="_blank"><font color="#56b6e9">http://www.xiaxin.net/Hibernate_DEV_GUIDE.rar。</font></a><br />下面主要就Hibernate在Spring中的应用加以介绍，关于Hibernate本身就不多加描<br />述。<br />另外考虑到Spring对容器事务的良好支持，笔者建议在基于Spring Framework的应<br />用开发中，尽量使用容器管理事务，以获得数据逻辑代码的最佳可读性。下面的介绍中，将<br />略过代码控制的事务管理部分，而将重点放在参数化的容器事务管理应用。代码级事务管理<br />实现原理与上面JdbcTemplate中基本一致，感兴趣的读者可以参见Spring-Reference中<br />的相关内容。<br />出于简洁，我们还是沿用上面的示例。首先，针对Hibernate，我们需要进行如下配置：<br />Hibernate-Context.xml:<br />&lt;beans&gt;<br />&lt;bean id="dataSource"<br />class="org.apache.commons.dbcp.BasicDataSource"<br />destroy-method="close"&gt;<br />&lt;property name="driverClassName"&gt;<br />&lt;value&gt;net.sourceforge.jtds.jdbc.Driver&lt;/value&gt;<br />&lt;/property&gt;<br />&lt;property name="url"&gt;<br />&lt;value&gt;jdbc:jtds:sqlserver://127.0.0.1:1433/Sample&lt;/value&gt;<br />&lt;/property&gt;<br />&lt;property name="username"&gt;<br />&lt;value&gt;test&lt;/value&gt;<br />&lt;/property&gt;<br />&lt;property name="password"&gt;<br />&lt;value&gt;changeit&lt;/value&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;bean id="sessionFactory"<br />class="org.springframework.orm.hibernate.LocalSessionFactoryBean"<br />&gt;<br />&lt;property name="dataSource"&gt;<br />&lt;ref local="dataSource" /&gt;<br />&lt;/property&gt;<br />&lt;property name="mappingResources"&gt;<br />&lt;list&gt;<br />&lt;value&gt;net/xiaxin/dao/entity/User.hbm.xml&lt;/value&gt;<br />&lt;/list&gt;<br />SpringFrameWork Developer’s Guide Version 0.6<br />October 8, 2004 So many open source projects. Why not Open your Documents?<br />&lt;/property&gt;<br />&lt;property name="hibernateProperties"&gt;<br />&lt;props&gt;<br />&lt;prop key="hibernate.dialect"&gt;<br />net.sf.hibernate.dialect.SQLServerDialect<br />&lt;/prop&gt;<br />&lt;prop key="hibernate.show_sql"&gt;<br />true<br />&lt;/prop&gt;<br />&lt;/props&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;bean id="transactionManager"<br />class="org.springframework.orm.hibernate.HibernateTransactionMana<br />ger"&gt;<br />&lt;property name="sessionFactory"&gt;<br />&lt;ref local="sessionFactory" /&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;bean id="userDAO" class="net.xiaxin.dao.UserDAO"&gt;<br />&lt;property name="sessionFactory"&gt;<br />&lt;ref local="sessionFactory" /&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;bean id="userDAOProxy"<br />class="org.springframework.transaction.interceptor.TransactionPro<br />xyFactoryBean"&gt;<br />&lt;property name="transactionManager"&gt;<br />&lt;ref bean="transactionManager" /&gt;<br />&lt;/property&gt;<br />&lt;property name="target"&gt;<br />&lt;ref local="userDAO" /&gt;<br />&lt;/property&gt;<br />&lt;property name="transactionAttributes"&gt;<br />&lt;props&gt;<br />&lt;prop key="insert*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />&lt;prop key="get*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br />&lt;/props&gt;<br />SpringFrameWork Developer’s Guide Version 0.6<br />October 8, 2004 So many open source projects. Why not Open your Documents?<br />&lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;/beans&gt;<br />与上面JDBC中的配置相对比，区别主要在于：<br />1． SessionFactory的引入<br />Hibernate中通过SessionFactory创建和维护Session。Spring对SessionFactory的配置也进行了整合，无需再通过Hibernate.cfg.xml对SessionFactory进行设定。<br />SessionFactory节点的mappingResources属性包含了映射文件的路径，list节点下可配置多个映射文件。<br />hibernateProperties节点则容纳了所有的属性配置。<br />可以对应传统的Hibernate.cfg.xml文件结构对这里的SessionFactory配置进行解读。<br />2． 采用面向Hibernate的TransactionManager实现：<br />org.springframework.orm.hibernate.HibernateTransactionManag<br />er<br />可以看到，对于事务管理配置，基本与上一章节中相同。对应刚才的Users表，建立如下映射类：<br />User.java:<br />/**<br />* @hibernate.class table="users"<br />*/<br />public class User {<br />public Integer id;<br />public String username;<br />public String password;<br />/**<br />* @hibernate.id<br />* column="id"<br />* type="java.lang.Integer"<br />* generator-class="native"<br />*/<br />public Integer getId() {<br />return id;<br />SpringFrameWork Developer’s Guide Version 0.6<br />October 8, 2004 So many open source projects. Why not Open your Documents?<br />}<br />public void setId(Integer id) {<br />this.id = id;<br />}<br />/**<br />* @hibernate.property column="password" length="50"<br />*/<br />public String getPassword() {<br />return password;<br />}<br />public void setPassword(String password) {<br />this.password = password;<br />}<br />/**<br />* @hibernate.property column="username" length="50"<br />*/<br />public String getUsername() {<br />return username;<br />}<br />public void setUsername(String username) {<br />this.username = username;<br />}<br />}<br />上面的代码中，通过xdoclet指定了类/表；属性/字段的映射关系，通过xdoclet anttask 我们可以根据代码生成对应的user.hbm.xml文件。具体细节请参见《hibernate开发指南》一文。<br />下面是生成的user.hbm.xml：<br />&lt;hibernate-mapping&gt;<br />&lt;class<br />name="net.xiaxin.dao.entity.User"<br />table="users"<br />dynamic-update="false"<br />dynamic-insert="false"<br />&gt;<br />&lt;id<br />name="id"<br />column="id"<br />SpringFrameWork Developer’s Guide Version 0.6<br />October 8, 2004 So many open source projects. Why not Open your Documents?<br />type="java.lang.Integer"<br />&gt;<br />&lt;generator class="native"&gt;<br />&lt;/generator&gt;<br />&lt;/id&gt;<br />&lt;property<br />name="password"<br />type="java.lang.String"<br />update="true"<br />insert="true"<br />access="property"<br />column="password"<br />length="50"<br />/&gt;<br />&lt;property<br />name="username"<br />type="java.lang.String"<br />update="true"<br />insert="true"<br />access="property"<br />column="username"<br />length="50"<br />/&gt;<br />&lt;/class&gt;<br />&lt;/hibernate-mapping&gt;<br />UserDAO.java:<br />public class UserDAO extends HibernateDaoSupport implements IUserDAO<br />{<br />public void insertUser(User user) {<br />getHibernateTemplate().saveOrUpdate(user);<br />}<br />}<br />看到这段代码想必会有点诧异，似乎太简单了一点……，不过这已经足够。短短一行代码我们已经实现了与上一章中示例相同的功能，这也正体现了Spring+Hibernate的威力所在。<br />上面的UserDAO实现了自定义的IUserDAO接口（这里的IUserDAO接口仅包含insertUser方法的定义，不过除此之外，它还有另一层含义，见下面的代码测试部分），<br />并扩展了抽象类：<br />HibernateDaoSupport<br />HibernateSupport实现了HibernateTemplate和SessionFactory实例的关联。与JdbcTemplate类似，HibernateTemplate对Hibernate Session操作进行了封装，而HibernateTemplate.execute方法则是一封装机制的核心，感兴趣的读者可以<br />研究一下其实现机制。借助HibernateTemplate我们可以脱离每次数据操作必须首先获得Session实例、启动事务、提交/回滚事务以及烦杂的try/catch/finally的繁琐操作。从而获得以上代码中精干集中的逻辑呈现效果。<br />对比下面这段实现了同样功能的Hibernate原生代码，想必更有体会：<br />Session session<br />try {<br />Configuration config = new Configuration().configure();<br />SessionFactory sessionFactory =<br />config.buildSessionFactory();<br />session = sessionFactory.openSession();<br />Transaction tx = session.beginTransaction();<br />User user = new User();<br />user.setName("erica"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />user.setPassword("mypass"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />session.save(user);<br />tx.commit();<br />} catch (HibernateException e) {<br />e.printStackTrace();<br />tx.rollback();<br />}finally{<br />session.close();<br />}<br />测试代码：<br />InputStream is = new FileInputStream("Hibernate-Context.xml"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />XmlBeanFactory factory = new XmlBeanFactory(is);<br />IUserDAO userDAO = (IUserDAO)factory.getBean("userDAOProxy"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />SpringFrameWork Developer’s Guide Version 0.6<br />October 8, 2004 So many open source projects. Why not Open your Documents?<br />User user = new User();<br />user.setUsername("erica"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />user.setPassword("mypass"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />userDAO.insertUser(user);<br />这段代码似乎并没有什么特殊，但有一个细微之处：<br />IUserDAO userDAO = (IUserDAO)factory.getBean("userDAOProxy"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />这里并没有直接用UserDAO对获得的Bean实例进行强制转型。这与上面JdbcTemplate的测试代码不同。并非完全出自设计上的考虑，这里情况有些特殊，我们可以尝试一下用UserDAO类对bean实例进行强制转型，不过将得到一个ClassCastException，程序异常中止。<br />为什么会出现这样的问题？是不是只有在使用Hibernate才会出现这样的问题？事实并非如此，如果对上面基于JdbcTempate的UserDAO进行改造，使之实现IUserDAO接口，同样的问题也将会出现。IUserDAO接口本身非常简单（仅包含一个insertUser方法的定义），显然也不是导致异常的原因所在。原因在于Spring的AOP实现机制，前面曾经提及，Spring中的事务管理实际上是基于动态AOP机制实现，为了实现动态AOP，Spring在默认情况下会使用Java DynamicProxy，但是，Dynamic Proxy要求其代理的对象必须实现一个接口，该接口定义了准备进行代理的方法。而对于没有实现任何接口的Java Class，需要采用其他方式，Spring通过CGLib10实现这一功能。<br />当UserDAO没有实现任何接口时（如JdbcTemplate示例中）。Spring通过CGLib对UserDAO进行代理，此时getBean返回的是一个继承自UserDAO类的子类实例，可以通过UserDAO对其强制转型。而当UserDAO实现了IUserDAO接口之后，Spring将通过JavaDynamic Proxy机制实现代理功能，此时返回的Bean，是通过java.lang.reflect.Proxy.newProxyInstance方法创建的IUserDAO接口的一个代理实现，这个实例实现了IUserDAO接口，但与UserDAO类已经没有继承关系，因此无法通过UserDAO强制转型。由于此问题牵涉到较为底层的代理机制实现原理，下面的AOP章节中我们再进行详细探讨。<br />实际开发中，应该面向接口编程，通过接口来调用Bean提供的服务。<br />10 CGLib可以在运行期对Class行为进行修改。由于其功能强大，性能出众，常常被作为Java Dynamic Proxy<br />之外的动态Proxy模式的实现基础。在Spring、Hibernate中都用到了CGLib类库。</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/ocean07000814/aggbug/70580.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ocean07000814/" target="_blank">非洲小白脸</a> 2006-09-19 17:22 <a href="http://www.blogjava.net/ocean07000814/articles/70580.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于在spring中hibernate的分页问题</title><link>http://www.blogjava.net/ocean07000814/articles/70575.html</link><dc:creator>非洲小白脸</dc:creator><author>非洲小白脸</author><pubDate>Tue, 19 Sep 2006 09:19:00 GMT</pubDate><guid>http://www.blogjava.net/ocean07000814/articles/70575.html</guid><wfw:comment>http://www.blogjava.net/ocean07000814/comments/70575.html</wfw:comment><comments>http://www.blogjava.net/ocean07000814/articles/70575.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ocean07000814/comments/commentRss/70575.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ocean07000814/services/trackbacks/70575.html</trackback:ping><description><![CDATA[
		<p>
				<font color="#ff0000" size="6">环境:  hibernate+spring</font>
				<br />
				<br />
				<br />1.如果sql语句写在映射文件里,如下:<br />&lt;?xml version="1.0"?&gt;<br />&lt;!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"<br />"<a href="http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd</a>"&gt;<br />&lt;!-- <br /> Mapping file autogenerated by MyEclipse - Hibernate Tools<br />--&gt;<br />&lt;hibernate-mapping&gt;<br /> &lt;class name="com.jgcgov.model.Contract" table="CONTRACT" schema="JGCUSER"&gt;<br />  &lt;id name="contractNo" type="string"&gt;<br />   &lt;column name="CONTRACT_NO" length="11" /&gt;<br />   &lt;generator class="assigned" /&gt;<br />  &lt;/id&gt;<br />  ............</p>
		<p>  &lt;set name="TbTaxpayment2104Add" table="TB_TAXPAYMENT_2104_ADD" cascade="all"&gt;<br />   &lt;key column="CONTRACT_NO"&gt;&lt;/key&gt;<br />   &lt;one-to-many class="com.jgcgov.model.TbTaxpayment2104Add" /&gt;<br />  &lt;/set&gt;<br />  <br /> &lt;/class&gt; <br /> &lt;!-- 查询合同的计税金额百分比--&gt;<br /> &lt;sql-query name="contractPrealarm"&gt;<br />  &lt;![CDATA[<br />    <br />         select con.CONTRACT_NO as contractNo,con.REGISTER_DATE as registerDate,<br />             con.CONSTRUCT_UINT as constructUint,trunc(con.WORKLOAD*10000,2) as workload,<br />             trunc(con1.TaxNum,2) as taxnum,trunc(con1.conPercent,1) as conPercent,<br />             null as attribute7,null as attribute8,null as attribute9,null as attribute10<br />       from CONTRACT con,(<br />             select con.CONTRACT_NO as contractNo,sum(nvl(tb2104.TAX_BASE,0)/(con.WORKLOAD*100)) as conPercent,<br />                sum(nvl(tb2104.TAX_BASE,0)) as TaxNum <br />             from CONTRACT con ,Jgctax.TB_TAXPAYMENT_2104_ADD tb2104<br />                where con.REGISTER_DATE &gt;= :conBeg<br />                and con.REGISTER_DATE &lt;= :conEnd<br />                and con.CONTRACT_NO = tb2104.contract_No(+) <br />                and nvl(tb2104.OP_DATE,to_date('1900-01-01','yyyy-MM-dd')) &lt;= :taxDate<br />                and nvl(con.WORKLOAD,0)&lt;&gt;0 <br />                group by con.CONTRACT_NO<br />                having sum(nvl(tb2104.TAX_BASE,0)/(con.WORKLOAD*100)) &gt;= :percent) con1<br />         where con.CONTRACT_NO=con1.contractNo<br />     ]]&gt;<br />  &lt;return alias="con" class="com.jgcgov.model.HibernateSqlResult"&gt;<br />   &lt;return-property name="attribute1" column="contractNo" /&gt;<br />   &lt;return-property name="attribute2" column="registerDate" /&gt;<br />   &lt;return-property name="attribute3" column="constructUint" /&gt;<br />   &lt;return-property name="attribute4" column="workload" /&gt;<br />   &lt;return-property name="attribute5" column="taxnum" /&gt;<br />   &lt;return-property name="attribute6" column="conPercent" /&gt;<br />   &lt;return-property name="attribute7" column="attribute7" /&gt;<br />   &lt;return-property name="attribute8" column="attribute8" /&gt;<br />   &lt;return-property name="attribute9" column="attribute9" /&gt;<br />   &lt;return-property name="attribute10" column="attribute10" /&gt;</p>
		<p>  &lt;/return&gt;<br /> &lt;/sql-query&gt;<br />&lt;/hibernate-mapping&gt;<br /><br />可以这样分页:<br />/***************************************************************************<br />  * * 函数名: getPrealarm * 输 入: conBeg,conEnd,taxDate,operatorStr,percent *<br />  * conBeg---合同起始时间 * conEnd---合同结束时间 * taxDate---计税截止时间 * operatorStr---运算符 *<br />  * percent---计税占合同额百分比 * 输 出: List * 功能描述: 得到计税占合同额百分比 * 全局变量: * 调用模块: * 作者:<br />  * <br />  **************************************************************************/<br /> }<br /> /**分页操作<br />     * 使用hql 语句进行操作<br />     * @param offset<br />     * @param length<br />     * @return List<br />     */<br />    public List getListForPage(int offset,int length,Date conBeg, Date conEnd, Date taxDate,<br />   Float percent) {</p>
		<p>    final int offset3 = offset;<br />    final int length3 = length;<br />    final Date conBeg3 = conBeg;<br />    final Date conEnd3 = conEnd;<br />    final Date taxDate3 = taxDate;<br />    final Float percent3 = percent;<br />    <br />     List list = getHibernateTemplate().executeFind(new HibernateCallback() {<br />      public Object doInHibernate(Session session)<br />        throws HibernateException, SQLException {<br />          Query query = session.getNamedQuery("contractPrealarm").setFirstResult(offset3).setMaxResults(length3);<br />          query.setDate(0,conBeg3);<br />          query.setDate(1,conEnd3);<br />          query.setDate(2,taxDate3);<br />          query.setFloat(4,percent3.floatValue());<br />          <br />          List list = query.list();<br />       return list;<br />      }<br />     });<br />     return list;<br />    }</p>
		<p>    /**<br />     * 获得记录的总个数<br />     */<br />    public int getCountForPage(){<br />     <br />     List list = getHibernateTemplate().find(hql3);<br />  int count = ((Integer)list.get(0)).intValue();<br />     return count;<br />    }<br />    /**<br />     * 获得分页类的对象<br />     * SimplePager(显示内容,记录总个数,页面最大个数,当前页)<br />     */<br />    public Pageable getPageable(int offset,int length,Date conBeg, Date conEnd, Date taxDate,<br />   Float percent,int currentPage){<br />     final int offset1 = offset;<br />     final int length1 = length;<br />     final int currentPage1 = currentPage;<br />     final int count = getCountForPage();<br />     List list = getListForPage(int offset,int length,Date conBeg, Date conEnd, Date taxDate,<br />   Float percent);<br />     Pageable pageable = new SimplePager(list,count,length1,currentPage1);<br />     return pageable;<br />    }<br /><br /><br />2.直接写在java类中,则可以用session的creatQuery()进行分页,具体如下:<br /><br /><br />private static String hql3 = "select count(*) from Jgcuser as user order by user.id ";<br /> <br /> private static String hql4 = "select u from Jgcuser as u order by u.id ";<br /> <br /><br /><br /><br />/**分页操作<br />     * 使用hql 语句进行操作<br />     * @param offset<br />     * @param length<br />     * @return List<br />     */<br />    public List getListForPage(int offset,int length) {</p>
		<p>    final int offset3 = offset;<br />    final int length3 = length;<br />     List list = getHibernateTemplate().executeFind(new HibernateCallback() {<br />      public Object doInHibernate(Session session)<br />        throws HibernateException, SQLException {<br />       List list = session.createQuery(hql4).setFirstResult(offset3).setMaxResults(length3).list();<br />       return list;<br />      }<br />     });<br />     return list;<br />    }</p>
		<p>    /**<br />     * 获得记录的总个数<br />     */<br />    public int getCountForPage(){<br />     <br />     List list = getHibernateTemplate().find(hql3);<br />  int count = ((Integer)list.get(0)).intValue();<br />     return count;<br />    }<br />    /**<br />     * 获得分页类的对象<br />     * SimplePager(显示内容,记录总个数,页面最大个数,当前页)<br />     */<br />    public Pageable getPageable(int offset,int length,int currentPage){<br />     final int offset1 = offset;<br />     final int length1 = length;<br />     final int currentPage1 = currentPage;<br />     final int count = getCountForPage();<br />     List list = getListForPage(offset1,length1);<br />     Pageable pageable = new SimplePager(list,count,length1,currentPage1);<br />     return pageable;<br />    }<br /></p>
<img src ="http://www.blogjava.net/ocean07000814/aggbug/70575.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ocean07000814/" target="_blank">非洲小白脸</a> 2006-09-19 17:19 <a href="http://www.blogjava.net/ocean07000814/articles/70575.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>