﻿<?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-微蓝领域-文章分类-Spring</title><link>http://www.blogjava.net/hilor/category/25039.html</link><description>我的学习档案馆</description><language>zh-cn</language><lastBuildDate>Mon, 28 Apr 2008 08:56:56 GMT</lastBuildDate><pubDate>Mon, 28 Apr 2008 08:56:56 GMT</pubDate><ttl>60</ttl><item><title>Spring 结合 C3P0配置</title><link>http://www.blogjava.net/hilor/articles/196735.html</link><dc:creator>hilor</dc:creator><author>hilor</author><pubDate>Mon, 28 Apr 2008 05:20:00 GMT</pubDate><guid>http://www.blogjava.net/hilor/articles/196735.html</guid><wfw:comment>http://www.blogjava.net/hilor/comments/196735.html</wfw:comment><comments>http://www.blogjava.net/hilor/articles/196735.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hilor/comments/commentRss/196735.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hilor/services/trackbacks/196735.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: applicationContext.xml 文件：&lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;beans xmlns="http://www.springframework.org/schema/beans"&nbsp;&nbsp;&nbsp; xmlns:xsi="http://www.w3.org/2001/XMLSche...&nbsp;&nbsp;<a href='http://www.blogjava.net/hilor/articles/196735.html'>阅读全文</a><img src ="http://www.blogjava.net/hilor/aggbug/196735.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hilor/" target="_blank">hilor</a> 2008-04-28 13:20 <a href="http://www.blogjava.net/hilor/articles/196735.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于OpenSessionInView</title><link>http://www.blogjava.net/hilor/articles/189348.html</link><dc:creator>hilor</dc:creator><author>hilor</author><pubDate>Fri, 28 Mar 2008 12:38:00 GMT</pubDate><guid>http://www.blogjava.net/hilor/articles/189348.html</guid><wfw:comment>http://www.blogjava.net/hilor/comments/189348.html</wfw:comment><comments>http://www.blogjava.net/hilor/articles/189348.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hilor/comments/commentRss/189348.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hilor/services/trackbacks/189348.html</trackback:ping><description><![CDATA[附http://www.javaeye.com/topic/14631<br />
OpenSessionInViewFilter讨论<br />
Hibernate的Lazy初始化1:n关系时，你必须保证是在同一个Session内部使用这个关系集合，不然Hiernate将抛出例外。
<p class="paragraph">另外，你不愿意你的DAO测试代码每次都打开关系Session，因此，我们一般会采用OpenSessionInView模式。
</p>
<h3 class="heading-1"><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="0"></a><strong style="color: black; background-color: #ffff66;">OpenSessionInViewFilter</strong>解决Web应用程序的问题
</h3>
如果程序是在正常的Web程序中运行，那么Spring的<strong style="color: black; background-color: #ffff66;">OpenSessionInViewFilter</strong>能够解决问题，它：
<div class="code">
<pre><span class="java-keyword">protected</span> void doFilterInternal(HttpServletRequest request, <br />
HttpServletResponse response,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;     FilterChain filterChain) <span class="java-keyword">throws</span> ServletException, IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SessionFactory sessionFactory = lookupSessionFactory();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(<span class="java-quote">"Opening Hibernate Session in <strong style="color: black; background-color: #ffff66;">OpenSessionInViewFilter</strong>"</span>);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Session session = getSession(sessionFactory);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TransactionSynchronizationManager.bindResource(sessionFactory, <br />
<span class="java-keyword">new</span> SessionHolder(session));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">try</span> {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filterChain.doFilter(request, response);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">finally</span> {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TransactionSynchronizationManager.unbindResource(sessionFactory);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(<span class="java-quote">"Closing Hibernate Session in <strong style="color: black; background-color: #ffff66;">OpenSessionInViewFilter</strong>"</span>);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;closeSession(session, sessionFactory);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</pre>
</div>
可以看到，这个Filter在request开始之前，把sessionFactory绑定到TransactionSynchronizationManager，和这个SessionHolder相关。这个意味着所有request执行过程中将使用这个session。而在请求结束后，将和这个sessionFactory对应的session解绑，并且关闭Session。
<p class="paragraph">为什么绑定以后，就可以防止每次不会新开一个Session呢？看看HibernateDaoSupport的情况： </p>
<div class="code">
<pre><span class="java-keyword">public</span> <span class="java-keyword">final</span> void setSessionFactory(SessionFactory sessionFactory) {<br />
<span class="java-keyword">this</span>.hibernateTemplate = <span class="java-keyword">new</span> HibernateTemplate(sessionFactory);<br />
}<br />
<span class="java-keyword">protected</span> <span class="java-keyword">final</span> HibernateTemplate getHibernateTemplate() {<br />
<span class="java-keyword">return</span> hibernateTemplate;<br />
}</pre>
</div>
<p class="paragraph">我们的DAO将使用这个template进行操作： </p>
<div class="code">
<pre><span class="java-keyword">public</span> <span class="java-keyword">abstract</span> class BaseHibernateObjectDao<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">extends</span> HibernateDaoSupport<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">implements</span> BaseObjectDao {<br />
<p class="paragraph"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">protected</span> BaseEntityObject getByClassId(<span class="java-keyword">final</span> <span class="java-object">long</span> id) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BaseEntityObject obj =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(BaseEntityObject) getHibernateTemplate()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.execute(<span class="java-keyword">new</span> HibernateCallback() {<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">public</span> <span class="java-object">Object</span> doInHibernate(Session session)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throws</span> HibernateException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">return</span> session.get(getPersistentClass(), <br />
<span class="java-keyword">new</span> <span class="java-object">Long</span>(id));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">return</span> obj;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</p>
<br />
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">public</span> void save(BaseEntityObject entity) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getHibernateTemplate().saveOrUpdate(entity);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">public</span> void remove(BaseEntityObject entity) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">try</span> {<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getHibernateTemplate().delete(entity);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <span class="java-keyword">catch</span> (Exception e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throw</span> <span class="java-keyword">new</span> FlexEnterpriseDataAccessException(e);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">public</span> void refresh(<span class="java-keyword">final</span> BaseEntityObject entity) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getHibernateTemplate().execute(<span class="java-keyword">new</span> HibernateCallback() {<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">public</span> <span class="java-object">Object</span> doInHibernate(Session session)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throws</span> HibernateException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.refresh(entity);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">return</span> <span class="java-keyword">null</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">public</span> void replicate(<span class="java-keyword">final</span> <span class="java-object">Object</span> entity) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getHibernateTemplate().execute(<span class="java-keyword">new</span> HibernateCallback() {<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">public</span> <span class="java-object">Object</span> doInHibernate(Session session)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throws</span> HibernateException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.replicate(entity, <br />
ReplicationMode.OVERWRITE);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">return</span> <span class="java-keyword">null</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</p>
</pre>
</div>
而HibernateTemplate试图每次在execute之前去获得Session，执行完就力争关闭Session
<div class="code">
<pre><span class="java-keyword">public</span> <span class="java-object">Object</span> execute(HibernateCallback action) <span class="java-keyword">throws</span> DataAccessException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Session session = (!<span class="java-keyword">this</span>.allowCreate ?<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SessionFactoryUtils.getSession(getSessionFactory(), <br />
<span class="java-keyword">false</span>) :<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SessionFactoryUtils.getSession(getSessionFactory(),<br />
getEntityInterceptor(),<br />
getJdbcExceptionTranslator()));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-object">boolean</span> existingTransaction =  <br />
TransactionSynchronizationManager.hasResource(getSessionFactory());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">if</span> (!existingTransaction &amp;&amp; getFlushMode() == FLUSH_NEVER) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.setFlushMode(FlushMode.NEVER);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">try</span> {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-object">Object</span> result = action.doInHibernate(session);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flushIfNecessary(session, existingTransaction);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">return</span> result;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">catch</span> (HibernateException ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throw</span> convertHibernateAccessException(ex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">catch</span> (SQLException ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throw</span> convertJdbcAccessException(ex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">catch</span> (RuntimeException ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// callback code threw application exception<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throw</span> ex;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">finally</span> {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SessionFactoryUtils.closeSessionIfNecessary(<br />
session, getSessionFactory());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</pre>
</div>
而这个SessionFactoryUtils能否得到当前的session以及closeSessionIfNecessary是否真正关闭session，端取决于这个session是否用sessionHolder和这个sessionFactory在我们最开始提到的TransactionSynchronizationManager绑定。
<div class="code">
<pre><span class="java-keyword">public</span> <span class="java-keyword">static</span> void closeSessionIfNecessary(Session session, <br />
SessionFactory sessionFactory)   <br />
<span class="java-keyword">throws</span> CleanupFailureDataAccessException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">if</span> (session == <span class="java-keyword">null</span> || <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   TransactionSynchronizationManager.hasResource(sessionFactory)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">return</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(<span class="java-quote">"Closing Hibernate session"</span>);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">try</span> {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">catch</span> (JDBCException ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// SQLException underneath<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throw</span> <span class="java-keyword">new</span> CleanupFailureDataAccessException(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-quote">"Cannot close Hibernate session"</span>, ex.getSQLException());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">catch</span> (HibernateException ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throw</span> <span class="java-keyword">new</span> CleanupFailureDataAccessException(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-quote">"Cannot close Hibernate session"</span>, ex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</pre>
</div>
<h3 class="heading-1">HibernateInterceptor和OpenSessionInViewInterceptor的问题 </h3>
<p class="paragraph">使用同样的方法，这两个Interceptor可以用来解决问题。但是关键的不同之处在于，它们的力度只能定义在DAO或业务方法上，而不是在我们的Test方法上，除非我们把它们应用到TestCase的方法上，但你不大可能为TestCase去定义一个接口，然后把Interceptor应用到这个接口的某些方法上。直接使用HibernateTransactionManager也是一样的。因此，如果我们有这样的测试：
</p>
<div class="code">
<pre>Category parentCategory  = <span class="java-keyword">new</span> Category ();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parentCategory.setName(<span class="java-quote">"parent"</span>);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dao.save(parentCategory);<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Category childCategory  = <span class="java-keyword">new</span> Category();<br />
childCategory.setName(<span class="java-quote">"child"</span>);<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parentCategory.addChild(childCategory);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dao.save(childCategory);</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Category savedParent = dao.getCategory(<span class="java-quote">"parent"</span>);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Category savedChild = (Category ) savedParent.getChildren().get(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertEquals(savedChild, childCategory);<br />
</p>
</pre>
</div>
将意味着两件事情：
<ul class="minus">
    <li>每次DAO执行都会启动一个session和关闭一个session
    </li>
    <li>如果我们定义了一个lazy的关系，那么最后的Category savedChild = (Category )
    savedParent.getChildren().get(0);将会让hibernate报错。 </li>
</ul>
<h3 class="heading-1">解决方案 </h3>
<p class="paragraph">一种方法是对TestCase应用Interceptor或者TransactionManager，但这个恐怕会造成很多麻烦。除非是使用增强方式的AOP.我前期采用这种方法(Aspectwerkz)，在Eclipse里面也跑得含好。
</p>
<p class="paragraph">另一种方法是在TestCase的setup和teardown里面实现和Filter完全一样的处理，其他的TestCase都从这个TestCase继承，这种方法是我目前所使用的。
</p>
<img src ="http://www.blogjava.net/hilor/aggbug/189348.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hilor/" target="_blank">hilor</a> 2008-03-28 20:38 <a href="http://www.blogjava.net/hilor/articles/189348.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>open session in view 的使用</title><link>http://www.blogjava.net/hilor/articles/189346.html</link><dc:creator>hilor</dc:creator><author>hilor</author><pubDate>Fri, 28 Mar 2008 12:29:00 GMT</pubDate><guid>http://www.blogjava.net/hilor/articles/189346.html</guid><wfw:comment>http://www.blogjava.net/hilor/comments/189346.html</wfw:comment><comments>http://www.blogjava.net/hilor/articles/189346.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hilor/comments/commentRss/189346.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hilor/services/trackbacks/189346.html</trackback:ping><description><![CDATA[<span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">在没有使用</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">Spring</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">提供的</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">Open Session In View</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">情况下，因需要在</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">service(or Dao)</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">层里把</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">session</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">关闭，所以</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">lazy loading </span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">为</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">true</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">的话，要在应用层内把关系集合都初始化，如</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;"> company.getEmployees()</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">，否则</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">Hibernate</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">抛</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">session already closed Exception;</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">&nbsp;&nbsp;&nbsp; Open Session In View</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">提供了一种简便的方法，较好地解决了</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">lazy loading</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">问题</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">.</span>
<p><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;"><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">&nbsp;&nbsp;&nbsp; </span>它有两种配置方式<font face="Verdana">OpenSessionInViewInterceptor</font></span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">和<span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">OpenSessionInViewFilter(具体参看<a title="SpringSide" target="_blank" href="http://www.springside.org.cn/"><strong><font color="#78a515">SpringSide</font></strong></a>)</span></span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">，功能相同，只是一个在</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">web.xml</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">配置，另一个在</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">application.xml</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">配置而已。</span></p>
<p><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">&nbsp;&nbsp;&nbsp; Open Session In View</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">在</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">request</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">把</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">session</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">绑定到当前</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">thread</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">期间一直保持</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">hibernate session</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">在</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">open</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">状态，使</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">session</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">在</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">request</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">的整个期间都可以使用，如在</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">View</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">层里</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">PO</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">也可以</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">lazy loading</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">数据，如</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;"> ${ company.employees }</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">。当</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">View </span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">层逻辑完成后，才会通过</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">Filter</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">的</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">doFilter</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">方法或</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">Interceptor</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">的</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">postHandle</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">方法自动关闭</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">session</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">。</span></p>
<br />
<span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;"><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">
<div class="head">
<pre class="java">
<div class="head">OpenSessionInViewInterceptor配置</div>
<ol>
    <li class="li1">
    <div class="de1">&lt;beans&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">  &lt;bean name=<span class="st0"><font color="#0000ff">"openSessionInViewInterceptor"</font></span> </div>
    </li>
    <li class="li1">
    <div class="de1"><span class="kw2"><strong><font color="#7f0055">class</font></strong></span>=<span class="st0"><font color="#0000ff">"org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor"</font></span>&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;property name=<span class="st0"><font color="#0000ff">"sessionFactory"</font></span>&gt;</div>
    </li>
    <li class="li1">
    <div class="de1">      &lt;ref bean=<span class="st0"><font color="#0000ff">"sessionFactory"</font></span>/&gt;</div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;/property&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">  &lt;/bean&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">  &lt;bean id=<span class="st0"><font color="#0000ff">"urlMapping"</font></span> </div>
    </li>
    <li class="li1">
    <div class="de1"><span class="kw2"><strong><font color="#7f0055">class</font></strong></span>=<span class="st0"><font color="#0000ff">"org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"</font></span>&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;property name=<span class="st0"><font color="#0000ff">"interceptors"</font></span>&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">      &lt;list&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">        &lt;ref bean=<span class="st0"><font color="#0000ff">"openSessionInViewInterceptor"</font></span>/&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">      &lt;/list&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;/property&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;property name=<span class="st0"><font color="#0000ff">"mappings"</font></span>&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    ... </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;/property&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">  &lt;/bean&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">... </div>
    </li>
    <li class="li1">
    <div class="de1">&lt;/beans&gt; </div>
    </li>
</ol>
</pre>
</div>
<div class="head">
<pre class="java">
<div class="head">OpenSessionInViewFilter配置</div>
<ol>
    <li class="li1">
    <div class="de1">&lt;web-app&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">... </div>
    </li>
    <li class="li1">
    <div class="de1">  &lt;filter&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;filter-class&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">      org.<span class="me1">springframework</span>.<span class="me1">orm</span>.<span class="me1">hibernate3</span>.<span class="me1">support</span>.<span class="me1">OpenSessionInViewFilter</span> </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;/filter-class&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;!-- singleSession默认为true,若设为false则等于没用<span class="me1">OpenSessionInView --&gt;</span></div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;init-param&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">      &lt;param-name&gt;singleSession&lt;/param-name&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">      &lt;param-value&gt;true&lt;/param-value&gt;</div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;/init-param&gt;</div>
    </li>
    <li class="li1">
    <div class="de1">  &lt;/filter&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">... </div>
    </li>
    <li class="li1">
    <div class="de1">  &lt;filter-mapping&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;url-pattern&gt;*.<span class="me1">do</span>&lt;/url-pattern&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">  &lt;/filter-mapping&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">... </div>
    </li>
    <li class="li1">
    <div class="de1">&lt;/web-app&gt; </div>
    </li>
</ol>
</pre>
<p>很多人在使用OpenSessionInView过程中提及一个错误：</p>
<pre class="java">
<ol>
    <li class="li1">
    <div class="de1">org.<span class="me1">springframework</span>.<span class="me1">dao</span>.<span class="me1">InvalidDataAccessApiUsageException</span>: Write operations </div>
    </li>
    <li class="li1">
    <div class="de1">are not allowed in read-only mode <span class="br0"><font color="#663300">(</font></span>FlushMode.<span class="me1">NEVER</span><span class="br0"><font color="#663300">)</font></span> - turn your Session into </div>
    </li>
    <li class="li1">
    <div class="de1">FlushMode.<span class="me1">AUTO</span> or remove <span class="st0"><font color="#0000ff">'readOnly'</font></span> marker from transaction definition </div>
    </li>
</ol>
</pre>
<p>看看OpenSessionInViewFilter里的几个方法</p>
<pre class="java">
<ol>
    <li class="li1">
    <div class="de1"><span class="kw2"><strong><font color="#7f0055">protected</font></strong></span> <span class="kw4"><font color="#f63333">void</font></span> doFilterInternal<span class="br0"><font color="#663300">(</font></span>HttpServletRequest request, <br />
    HttpServletResponse response,FilterChain filterChain<span class="br0"><font color="#663300">)</font></span> <br />
    <span class="kw2"><strong><font color="#7f0055">throws</font></strong></span> ServletException, <span class="kw3"><font color="#ff0000">IOException</font></span> <span class="br0"><font color="#663300">{<br />
    </font></span>　SessionFactory sessionFactory = lookupSessionFactory<font color="#663300"><span class="br0">(</span><span class="br0">)</span></font>;<br />
    logger.<span class="me1">debug</span><span class="br0"><font color="#663300">(</font></span><span class="st0"><font color="#0000ff">"Opening Hibernate Session in OpenSessionInViewFilter"</font></span><span class="br0"><font color="#663300">)</font></span>;<br />
    Session session = getSession<span class="br0"><font color="#663300">(</font></span>sessionFactory<span class="br0"><font color="#663300">)</font></span>;<br />
    TransactionSynchronizationManager.<span class="me1">bindResource</span><span class="br0"><font color="#663300">(<br />
    </font></span>　　sessionFactory, <span class="kw2"><strong><font color="#7f0055">new</font></strong></span> SessionHolder<span class="br0"><font color="#663300">(</font></span>session<font color="#663300"><span class="br0">)</span><span class="br0">)</span></font>;<br />
    <span class="kw2"><strong><font color="#7f0055">try</font></strong></span> <span class="br0"><font color="#663300">{<br />
    </font></span>　　filterChain.<span class="me1">doFilter</span><span class="br0"><font color="#663300">(</font></span>request, response<span class="br0"><font color="#663300">)</font></span>;<br />
    <span class="br0"><font color="#663300">}<br />
    </font></span><span class="kw2"><strong><font color="#7f0055">　finally</font></strong></span> <span class="br0"><font color="#663300">{<br />
    </font></span>　TransactionSynchronizationManager.<span class="me1">unbindResource</span><span class="br0"><font color="#663300">(</font></span>sessionFactory<span class="br0"><font color="#663300">)</font></span>;<br />
    logger.<span class="me1">debug</span><span class="br0"><font color="#663300">(</font></span><span class="st0"><font color="#0000ff">"Closing Hibernate Session in OpenSessionInViewFilter"</font></span><span class="br0"><font color="#663300">)</font></span>;<br />
    closeSession<span class="br0"><font color="#663300">(</font></span>session, sessionFactory<span class="br0"><font color="#663300">)</font></span>;<br />
    <font color="#663300"><span class="br0">}<br />
    </span><span class="br0">}</span></font><span class="br0"><br />
    <br />
    <br />
    <br />
    <br />
    </span>&nbsp;</div>
    </li>
    <li class="li1">
    <div class="de1"><span class="kw2"><strong><font color="#7f0055">protected</font></strong></span> Session getSession<span class="br0"><font color="#663300">(</font></span>SessionFactory sessionFactory<span class="br0"><font color="#663300">)<br />
    </font></span><span class="kw2"><strong><font color="#7f0055">throws</font></strong></span> DataAccessResourceFailureException <span class="br0"><font color="#663300">{<br />
    </font></span>　Session session = SessionFactoryUtils.<span class="me1">getSession</span><span class="br0"><font color="#663300">(</font></span>sessionFactory, <span class="kw2"><strong><font color="#7f0055">true</font></strong></span><span class="br0"><font color="#663300">)</font></span>;<br />
    session.<span class="me1">setFlushMode</span><span class="br0"><font color="#663300">(</font></span>FlushMode.<span class="me1">NEVER</span><span class="br0"><font color="#663300">)</font></span>;<br />
    <span class="kw2"><strong><font color="#7f0055">return</font></strong></span> session;<br />
    <span class="br0"><font color="#663300">}</font></span></div>
    </li>
    <li class="li1"><span class="kw2"><br />
    <strong><font color="#7f0055">protected</font></strong></span> <span class="kw4"><font color="#f63333">void</font></span> closeSession<span class="br0"><font color="#663300">(</font></span>Session session, SessionFactory sessionFactory<span class="br0"><font color="#663300">)<br />
    </font></span><span class="kw2"><strong><font color="#7f0055">throws</font></strong></span> CleanupFailureDataAccessException <span class="br0"><font color="#663300">{<br />
    </font></span>　SessionFactoryUtils.<span class="me1">closeSessionIfNecessary</span><span class="br0"><font color="#663300">(</font></span>session, sessionFactory<span class="br0"><font color="#663300">)</font></span>;<br />
    <span class="br0"><font color="#663300">}</font></span> </li>
</ol>
</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;
可以看到OpenSessionInViewFilter在getSession的时候,会把获取回来的session的flush mode
设为FlushMode.NEVER。然后把该sessionFactory绑定到
TransactionSynchronizationManager，使request的整个过程都使用同一个session，在请求过后再接除该
sessionFactory的绑定，最后<span class="me1">closeSessionIfNecessary</span>根据该
session是否已和transaction绑定来决定是否关闭session。在这个过程中，若HibernateTemplate
发现自当前session有不是readOnly的transaction，就会获取到FlushMode.AUTO
Session，使方法拥有写权限。</p>
<pre class="java">
<ol>
    <li class="li1">
    <div class="de1"><span class="kw2"><strong><font color="#7f0055">public</font></strong></span> <span class="kw2"><strong><font color="#7f0055">static</font></strong></span> <span class="kw4"><font color="#f63333">void</font></span> closeSessionIfNecessary<span class="br0"><font color="#663300">(</font></span>Session session, SessionFactory sessionFactory<span class="br0"><font color="#663300">)</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">      <span class="kw2"><strong><font color="#7f0055">throws</font></strong></span> CleanupFailureDataAccessException <span class="br0"><font color="#663300">{</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">    <span class="kw1"><font color="#b1b100">if</font></span> <span class="br0"><font color="#663300">(</font></span>session == <span class="kw2"><strong><font color="#7f0055">null</font></strong></span> || <br />
    TransactionSynchronizationManager.<span class="me1">hasResource</span><span class="br0"><font color="#663300">(</font></span>sessionFactory<font color="#663300"><span class="br0">)</span><span class="br0">)</span></font> <span class="br0"><font color="#663300">{</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">      <span class="kw2"><strong><font color="#7f0055">return</font></strong></span>;</div>
    </li>
    <li class="li1">
    <div class="de1">    <span class="br0"><font color="#663300">}</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">    logger.<span class="me1">debug</span><span class="br0"><font color="#663300">(</font></span><span class="st0"><font color="#0000ff">"Closing Hibernate session"</font></span><span class="br0"><font color="#663300">)</font></span>;</div>
    </li>
    <li class="li1">
    <div class="de1">    <span class="kw2"><strong><font color="#7f0055">try</font></strong></span> <span class="br0"><font color="#663300">{</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">      session.<span class="me1">close</span><font color="#663300"><span class="br0">(</span><span class="br0">)</span></font>;</div>
    </li>
    <li class="li1">
    <div class="de1">    <span class="br0"><font color="#663300">}</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">    <span class="kw2"><strong><font color="#7f0055">catch</font></strong></span> <span class="br0"><font color="#663300">(</font></span>JDBCException ex<span class="br0"><font color="#663300">)</font></span> <span class="br0"><font color="#663300">{</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">      <span class="co1"><font color="#3f5fbf">// SQLException underneath</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">      <span class="kw2"><strong><font color="#7f0055">throw</font></strong></span> <span class="kw2"><strong><font color="#7f0055">new</font></strong></span> CleanupFailureDataAccessException<span class="br0"><font color="#663300">(</font></span><span class="st0"><font color="#0000ff">"Could not close Hibernate session"</font></span>, ex.<span class="me1">getSQLException</span><font color="#663300"><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span></font>;</div>
    </li>
    <li class="li1">
    <div class="de1">    <span class="br0"><font color="#663300">}</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">    <span class="kw2"><strong><font color="#7f0055">catch</font></strong></span> <span class="br0"><font color="#663300">(</font></span>HibernateException ex<span class="br0"><font color="#663300">)</font></span> <span class="br0"><font color="#663300">{</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">      <span class="kw2"><strong><font color="#7f0055">throw</font></strong></span> <span class="kw2"><strong><font color="#7f0055">new</font></strong></span> CleanupFailureDataAccessException<span class="br0"><font color="#663300">(</font></span><span class="st0"><font color="#0000ff">"Could not close Hibernate session"</font></span>, ex<span class="br0"><font color="#663300">)</font></span>;</div>
    </li>
    <li class="li1">
    <div class="de1">    <span class="br0"><font color="#663300">}</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">  <span class="br0"><font color="#663300">}</font></span> </div>
    </li>
</ol>
</pre>
<p>&nbsp;&nbsp;&nbsp;
也即是，如果有不是readOnly的transaction就可以由Flush.NEVER转为Flush.AUTO,拥有insert,
update,delete操作权限，如果没有transaction，并且没有另外人为地设flush
model的话，则doFilter的整个过程都是Flush.NEVER。所以受transaction保护的方法有写权限，没受保护的则没有。</p>
<pre class="xml">
<div class="head">采用spring的事务声明,使方法受transaction控制</div>
<ol>
    <li class="li1">
    <div class="de1"><span class="sc3"><span class="re1">&nbsp; &lt;bean id="baseTransaction" <br />
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; abstract="true"&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="transactionManager" ref="transactionManager"/&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="proxyTargetClass" value="true"/&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="transactionAttributes"&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;props&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="get*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="find*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="load*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="save*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="add*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="update*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="remove*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/props&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &lt;/property&gt; <br />
    &nbsp; &nbsp; &lt;/bean&gt; </span></span><span class="sc3"><span class="re1"><br />
    </span></span></div>
    </li>
    <li class="li1">&nbsp; &nbsp; &lt;bean id="userService" parent="baseTransaction"&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="target"&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;bean class="com.phopesoft.security.service.impl.UserServiceImpl"/&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &lt;/property&gt; <br />
    &nbsp; &nbsp; &lt;/bean&gt; </li>
</ol>
</pre>
</div>
<ol>&nbsp;</ol>
    <p>对
    于上例，则以save,add,update,remove开头的方法拥有可写的事务，如果当前有某个方法，如命名为importExcel()，则因没
    有transaction而没有写权限，这时若方法内有insert,update,delete操作的话，则需要手动设置flush
    model为Flush.AUTO,如</p>
    <pre class="java">
    <ol>
        <li class="li1">
        <div class="de1"> session.<span class="me1">setFlushMode</span><span class="br0"><font color="#663300">(</font></span>FlushMode.<span class="me1">AUTO</span><span class="br0"><font color="#663300">)</font></span>; </div>
        </li>
        <li class="li1">
        <div class="de1"> session.<span class="me1">save</span><span class="br0"><font color="#663300">(</font></span>user<span class="br0"><font color="#663300">)</font></span>; </div>
        </li>
        <li class="li1">
        <div class="de1"> session.<span class="me1">flush</span><font color="#663300"><span class="br0">(</span><span class="br0">)</span></font>; </div>
        </li>
    </ol>
    </pre>
    <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    尽管Open Session In
    View看起来还不错，其实副作用不少。看回上面OpenSessionInViewFilter的doFilterInternal方法代码，这个方法
    实际上是被父类的doFilter调用的，因此，我们可以大约了解的OpenSessionInViewFilter调用流程:
    request(请求)-&gt;open
    session并开始transaction-&gt;controller-&gt;View(Jsp)-&gt;结束transaction并
    close session.</p>
    <p>&nbsp;&nbsp;&nbsp;&nbsp;
    一切看起来很正确，尤其是在本地开发测试的时候没出现问题，但试想下如果流程中的某一步被阻塞的话，那在这期间connection就一直被占用而不释
    放。最有可能被阻塞的就是在写Jsp这步，一方面可能是页面内容大，response.write的时间长，另一方面可能是网速慢，服务器与用户间传输时
    间久。当大量这样的情况出现时，就有连接池连接不足，造成页面假死现象。</p>
    <p>Open Session In View是个双刃剑，放在公网上内容多流量大的网站请慎用。</p>
    </span></span>    &nbsp;<br />
    <br />
    <p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1441664</p>
<img src ="http://www.blogjava.net/hilor/aggbug/189346.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hilor/" target="_blank">hilor</a> 2008-03-28 20:29 <a href="http://www.blogjava.net/hilor/articles/189346.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring的特殊字符转义和方法入参检测工具类</title><link>http://www.blogjava.net/hilor/articles/153774.html</link><dc:creator>hilor</dc:creator><author>hilor</author><pubDate>Thu, 18 Oct 2007 02:02:00 GMT</pubDate><guid>http://www.blogjava.net/hilor/articles/153774.html</guid><wfw:comment>http://www.blogjava.net/hilor/comments/153774.html</wfw:comment><comments>http://www.blogjava.net/hilor/articles/153774.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hilor/comments/commentRss/153774.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hilor/services/trackbacks/153774.html</trackback:ping><description><![CDATA[<blockquote>
<p>Spring 不但提供了一个功能全面的应用开发框架，本身还拥有众多可以在程序编写时直接使用的工具类，您不但可以在 Spring 应用中使用这些工具类，也可以在其它的应用中使用，这些工具类中的大部分是可以在脱离 Spring 框架时使用的。了解 Spring 中有哪些好用的工具类并在程序编写时适当使用，将有助于提高开发效率、增强代码质量。</p>
<p>在这个分为两部分的文章中，我们将从众多的 Spring 工具类中遴选出那些好用的工具类介绍给大家。<a href="http://www.ibm.com/developerworks/cn/java/j-lo-spring-utils1/">第 1 部分</a> 介绍了与文件资源操作和 Web 相关的工具类。在第 2 部分中将介绍特殊字符转义和方法入参检测工具类。</p>
</blockquote><!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--end RESERVED FOR FUTURE USE INCLUDE FILES-->
<p><a name="N10065"><span class="atitle">特殊字符转义</span></a></p>
<p>由于 Web 应用程序需要联合使用到多种语言，每种语言都包含一些特殊的字符，对于动态语言或标签式的语言而言，如果需要动态构造语言的内容时，一个我们经常会碰到的问题就是特殊字符转义的问题。下面是 Web 开发者最常面对需要转义的特殊字符类型：</p>
<ul>
    <li>HTML 特殊字符；
    <li>JavaScript 特殊字符；
    <li>SQL 特殊字符； </li>
</ul>
<p>如果不对这些特殊字符进行转义处理，则不但可能破坏文档结构，还可以引发潜在的安全问题。Spring 为 HTML 和 JavaScript 特殊字符提供了转义操作工具类，它们分别是 HtmlUtils 和 JavaScriptUtils。</p>
<p><a name="N1007D"><span class="smalltitle">HTML 特殊字符转义</span></a></p>
<p>HTML 中 &lt;，&gt;，&amp; 等字符有特殊含义，它们是 HTML 语言的保留字，因此不能直接使用。使用这些个字符时，应使用它们的转义序列：</p>
<ul>
    <li>&amp;：&amp;amp;
    <li>" ：&amp;quot;
    <li>&lt; ：&amp;lt;
    <li>&gt; ：&amp;gt; </li>
</ul>
<p>由于 HTML 网页本身就是一个文本型结构化文档，如果直接将这些包含了 HTML 特殊字符的内容输出到网页中，极有可能破坏整个 HTML 文档的结构。所以，一般情况下需要对动态数据进行转义处理，使用转义序列表示 HTML 特殊字符。下面的 JSP 网页将一些变量动态输出到 HTML 网页中：</p>
<br />
<a name="list1"><strong>清单 1. 未进行 HTML 特殊字符转义处理网页</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">
            &lt;%@ page language="java" contentType="text/html; charset=utf-8"%&gt;
            &lt;%!
            String userName = "&lt;/td&gt;&lt;tr&gt;&lt;/table&gt;";
            String address = " \" type=\"button";
            %&gt;
            &lt;table border="1"&gt;
            &lt;tr&gt;
            &lt;td&gt;姓名：&lt;/td&gt;&lt;td&gt;&lt;%=userName%&gt;&lt;/td&gt; ①
            &lt;/tr&gt;
            &lt;tr&gt;
            &lt;td&gt;年龄：&lt;/td&gt;&lt;td&gt;28&lt;/td&gt;
            &lt;/tr&gt;
            &lt;/table&gt;
            &lt;input value="&lt;%=address%&gt;"  type="text" /&gt; ②
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>在 ① 和 ② 处，我们未经任何转义处理就直接将变量输出到 HTML 网页中，由于这些变量可能包含一些特殊的 HTML 的字符，它们将可能破坏整个 HTML 文档的结构。我们可以从以上 JSP 页面的一个具体输出中了解这一问题：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;table border="1"&gt;
            &lt;tr&gt;
            &lt;td&gt;姓名：&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;tr&gt;&lt;/table&gt;&lt;/td&gt;
            ① 破坏了 &lt;table&gt; 的结构
            &lt;/tr&gt;
            &lt;tr&gt;
            &lt;td&gt;年龄：&lt;/td&gt;&lt;td&gt;28&lt;/td&gt;
            &lt;/tr&gt;
            &lt;/table&gt;
            &lt;input value=" " type="button"  type="text" /&gt;
            ② 将本来是输入框组件偷梁换柱为按钮组件
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>融合动态数据后的 HTML 网页已经面目全非，首先 ① 处的 &lt;table&gt; 结构被包含 HTML 特殊字符的 userName 变量截断了，造成其后的 &lt;table&gt; 代码变成无效的内容；其次，② 处 &lt;input&gt; 被动态数据改换为按钮类型的组件（type="button"）。为了避免这一问题，我们需要事先对可能破坏 HTML 文档结构的动态数据进行转义处理。Spring 为我们提供了一个简单适用的 HTML 特殊字符转义工具类，它就是 HtmlUtils。下面，我们通过一个简单的例子了解 HtmlUtils 的具体用法：</p>
<br />
<a name="list2"><strong>清单 2. HtmpEscapeExample</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">
            package com.baobaotao.escape;
            import org.springframework.web.util.HtmlUtils;
            public class HtmpEscapeExample {
            public static void main(String[] args) {
            String specialStr = "&lt;div id=\"testDiv\"&gt;test1;test2&lt;/div&gt;";
            String str1 = HtmlUtils.htmlEscape(specialStr); ①转换为HTML转义字符表示
            System.out.println(str1);
            String str2 = HtmlUtils.htmlEscapeDecimal(specialStr); ②转换为数据转义表示
            System.out.println(str2);
            String str3 = HtmlUtils.htmlEscapeHex(specialStr); ③转换为十六进制数据转义表示
            System.out.println(str3);
            ④下面对转义后字符串进行反向操作
            System.out.println(HtmlUtils.htmlUnescape(str1));
            System.out.println(HtmlUtils.htmlUnescape(str2));
            System.out.println(HtmlUtils.htmlUnescape(str3));
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>HTML 不但可以使用通用的转义序列表示 HTML 特殊字符，还可以使用以 # 为前缀的数字序列表示 HTML 特殊字符，它们在最终的显示效果上是一样的。HtmlUtils 提供了三个转义方法：</p>
<table class="data-table-1" cellspacing="0" cellpadding="0" width="100%" summary="" border="0">
    <tbody>
        <tr>
            <th>方法</th>
            <th>说明</th>
        </tr>
        <tr>
            <td><code>static String htmlEscape(String input)</code> </td>
            <td>将 HTML 特殊字符转义为 HTML 通用转义序列；</td>
        </tr>
        <tr>
            <td><code>static String htmlEscapeDecimal(String input)</code> </td>
            <td>将 HTML 特殊字符转义为带 # 的十进制数据转义序列；</td>
        </tr>
        <tr>
            <td><code>static String htmlEscapeHex(String input)</code> </td>
            <td>将 HTML 特殊字符转义为带 # 的十六进制数据转义序列；</td>
        </tr>
    </tbody>
</table>
<p>此外，HtmlUtils 还提供了一个能够将经过转义内容还原的方法：htmlUnescape(String input)，它可以还原以上三种转义序列的内容。运行以上代码，您将可以看到以下的输出：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">str1:&amp;lt;div id=&amp;quot;testDiv&amp;quot;&amp;gt;test1;test2&amp;lt;/div&amp;gt;
            str2:&#60;div id=&#34;testDiv&#34;&#62;test1;test2&#60;/div&#62;
            str3:&#x3c;div id=&#x22;testDiv&#x22;&#x3e;test1;test2&#x3c;/div&#x3e;
            &lt;div id="testDiv"&gt;test1;test2&lt;/div&gt;
            &lt;div id="testDiv"&gt;test1;test2&lt;/div&gt;
            &lt;div id="testDiv"&gt;test1;test2&lt;/div&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>您只要使用 HtmlUtils 对代码 <a href="http://www.ibm.com/developerworks/cn/java/j-lo-spring-utils2/#list1">清单 1</a> 的 userName 和 address 进行转义处理，最终输出的 HTML 页面就不会遭受破坏了。</p>
<p><a name="N100FD"><span class="smalltitle">JavaScript 特殊字符转义</span></a></p>
<p>JavaScript 中也有一些需要特殊处理的字符，如果直接将它们嵌入 JavaScript 代码中，JavaScript 程序结构将会遭受破坏，甚至被嵌入一些恶意的程序。下面列出了需要转义的特殊 JavaScript 字符：</p>
<ul>
    <li>' ：\'
    <li>" ：\"
    <li>\ ：\\
    <li>走纸换页： \f
    <li>换行：\n
    <li>换栏符：\t
    <li>回车：\r
    <li>回退符：\b </li>
</ul>

<p>我们通过一个具体例子演示动态变量是如何对 JavaScript 程序进行破坏的。假设我们有一个 JavaScript 数组变量，其元素值通过一个 Java List 对象提供，下面是完成这一操作的 JSP 代码片断：</p>
<br />
<a name="list3"><strong>清单 3. jsTest.jsp：未对 JavaScript 特殊字符进行处理</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">
            &lt;%@ page language="java" contentType="text/html; charset=utf-8"%&gt;
            &lt;jsp:directive.page import="java.util.*"/&gt;
            &lt;%
            List textList = new ArrayList();
            textList.add("\";alert();j=\"");
            %&gt;
            &lt;script&gt;
            var txtList = new Array();
            &lt;% for ( int i = 0 ; i &lt; textList.size() ; i++) { %&gt;
            txtList[&lt;%=i%&gt;] = "&lt;%=textList.get(i)%&gt;";
            ① 未对可能包含特殊 JavaScript 字符的变量进行处理
            &lt;% } %&gt;
            &lt;/script&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>当客户端调用这个 JSP 页面后，将得到以下的 HTML 输出页面：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;script&gt;
            var txtList = new Array();
            txtList[0] = ""<span class="boldcode">;alert();j=</span>""; ① 本来是希望接受一个字符串，结果被植入了一段JavaScript代码
            &lt;/script&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>由于包含 JavaScript 特殊字符的 Java 变量直接合并到 JavaScript 代码中，我们本来期望 ① 处所示部分是一个普通的字符串，但结果变成了一段 JavaScript 代码，网页将弹出一个 alert 窗口。想像一下如果粗体部分的字符串是&#8220;";while(true)alert();j="&#8221;时会产生什么后果呢？</p>
<p>因此，如果网页中的 JavaScript 代码需要通过拼接 Java 变量动态产生时，一般需要对变量的内容进行转义处理，可以通过 Spring 的 JavaScriptUtils 完成这件工作。下面，我们使用 JavaScriptUtils 对以上代码进行改造：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;%@ page language="java" contentType="text/html; charset=utf-8"%&gt;
            &lt;jsp:directive.page import="java.util.*"/&gt;
            &lt;jsp:directive.page import="org.springframework.web.util.JavaScriptUtils"/&gt;
            &lt;%
            List textList = new ArrayList();
            textList.add("\";alert();j=\"");
            %&gt;
            &lt;script&gt;
            var txtList = new Array();
            &lt;% for ( int i = 0 ; i &lt; textList.size() ; i++) { %&gt;
            ① 在输出动态内容前事先进行转义处理
            txtList[&lt;%=i%&gt;] = "&lt;%=JavaScriptUtils.javaScriptEscape(""+textList.get(i))%&gt;";
            &lt;% } %&gt;
            &lt;/script&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>通过转义处理后，这个 JSP 页面输出的结果网页的 JavaScript 代码就不会产生问题了：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;script&gt;
            var txtList = new Array();
            txtList[0] = "<span class="boldcode">\";alert();j=\"</span>";
            ① 粗体部分仅是一个普通的字符串，而非一段 JavaScript 的语句了
            &lt;/script&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p><a name="N1014A"><span class="smalltitle">SQL特殊字符转义</span></a></p>
<p>应该说，您即使没有处理 HTML 或 JavaScript 的特殊字符，也不会带来灾难性的后果，但是如果不在动态构造 SQL 语句时对变量中特殊字符进行处理，将可能导致程序漏洞、数据盗取、数据破坏等严重的安全问题。网络中有大量讲解 SQL 注入的文章，感兴趣的读者可以搜索相关的资料深入研究。</p>
<p>虽然 SQL 注入的后果很严重，但是只要对动态构造的 SQL 语句的变量进行特殊字符转义处理，就可以避免这一问题的发生了。来看一个存在安全漏洞的经典例子：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">SELECT COUNT(userId)
            FROM t_user
            WHERE userName='"+userName+"' AND password ='"+password+"';
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>以上 SQL 语句根据返回的结果数判断用户提供的登录信息是否正确，如果 userName 变量不经过特殊字符转义处理就直接合并到 SQL 语句中，黑客就可以通过将 userName 设置为 &#8220;1' or '1'='1&#8221;绕过用户名/密码的检查直接进入系统了。</p>
<p>所以除非必要，一般建议通过 PreparedStatement 参数绑定的方式构造动态 SQL 语句，因为这种方式可以避免 SQL 注入的潜在安全问题。但是往往很难在应用中完全避免通过拼接字符串构造动态 SQL 语句的方式。为了防止他人使用特殊 SQL 字符破坏 SQL 的语句结构或植入恶意操作，必须在变量拼接到 SQL 语句之前对其中的特殊字符进行转义处理。Spring 并没有提供相应的工具类，您可以通过 jakarta commons lang 通用类包中（spring/lib/jakarta-commons/commons-lang.jar）的 StringEscapeUtils 完成这一工作：</p>
<br />
<a name="list4"><strong>清单 4. SqlEscapeExample</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">
            package com.baobaotao.escape;
            import org.apache.commons.lang.StringEscapeUtils;
            public class SqlEscapeExample {
            public static void main(String[] args) {
            String userName = "1' or '1'='1";
            String password = "123456";
            userName = StringEscapeUtils.escapeSql(userName);
            password = StringEscapeUtils.escapeSql(password);
            String sql = "SELECT COUNT(userId) FROM t_user WHERE userName='"
            + userName + "' AND password ='" + password + "'";
            System.out.println(sql);
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>事实上，StringEscapeUtils 不但提供了 SQL 特殊字符转义处理的功能，还提供了 HTML、XML、JavaScript、Java 特殊字符的转义和还原的方法。如果您不介意引入 jakarta commons lang 类包，我们更推荐您使用 StringEscapeUtils 工具类完成特殊字符转义处理的工作。</p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-lo-spring-utils2/#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="N1016B"><span class="atitle">方法入参检测工具类</span></a></p>
<p>Web 应用在接受表单提交的数据后都需要对其进行合法性检查，如果表单数据不合法，请求将被驳回。类似的，当我们在编写类的方法时，也常常需要对方法入参进行合法性检查，如果入参不符合要求，方法将通过抛出异常的方式拒绝后续处理。举一个例子：有一个根据文件名获取输入流的方法：InputStream getData(String file)，为了使方法能够成功执行，必须保证 file 入参不能为 null 或空白字符，否则根本无须进行后继的处理。这时方法的编写者通常会在方法体的最前面编写一段对入参进行检测的代码，如下所示：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">public InputStream getData(String file) {
            if (file == null || file.length() == 0|| file.replaceAll("\\s", "").length() == 0) {
            throw new IllegalArgumentException("file入参不是有效的文件地址");
            }
            &#8230;
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>类似以上检测方法入参的代码是非常常见，但是在每个方法中都使用手工编写检测逻辑的方式并不是一个好主意。阅读 Spring 源码，您会发现 Spring 采用一个 org.springframework.util.Assert 通用类完成这一任务。</p>
<p>Assert 翻译为中文为&#8220;断言&#8221;，使用过 JUnit 的读者都熟知这个概念，它断定某一个实际的运行值和预期想一样，否则就抛出异常。Spring 对方法入参的检测借用了这个概念，其提供的 Assert 类拥有众多按规则对方法入参进行断言的方法，可以满足大部分方法入参检测的要求。这些断言方法在入参不满足要求时就会抛出 IllegalArgumentException。下面，我们来认识一下 Assert 类中的常用断言方法：</p>
<table class="data-table-1" cellspacing="0" cellpadding="0" width="100%" summary="" border="0">
    <tbody>
        <tr>
            <th>断言方法</th>
            <th>说明</th>
        </tr>
        <tr>
            <td><code>notNull(Object object)</code> </td>
            <td>当 object 不为 null 时抛出异常，notNull(Object object, String message) 方法允许您通过 message 定制异常信息。和 notNull() 方法断言规则相反的方法是 isNull(Object object)/isNull(Object object, String message)，它要求入参一定是 null；</td>
        </tr>
        <tr>
            <td><code>isTrue(boolean expression) / isTrue(boolean expression, String message)</code> </td>
            <td>当 expression 不为 true 抛出异常；</td>
        </tr>
        <tr>
            <td><code>notEmpty(Collection collection) / notEmpty(Collection collection, String message)</code> </td>
            <td>当集合未包含元素时抛出异常。notEmpty(Map map) / notEmpty(Map map, String message) 和 notEmpty(Object[] array, String message) / notEmpty(Object[] array, String message) 分别对 Map 和 Object[] 类型的入参进行判断；</td>
        </tr>
        <tr>
            <td><code>hasLength(String text) / hasLength(String text, String message)</code> </td>
            <td>当 text 为 null 或长度为 0 时抛出异常；</td>
        </tr>
        <tr>
            <td><code>hasText(String text) / hasText(String text, String message)</code> </td>
            <td>text 不能为 null 且必须至少包含一个非空格的字符，否则抛出异常；</td>
        </tr>
        <tr>
            <td><code>isInstanceOf(Class clazz, Object obj) / isInstanceOf(Class type, Object obj, String message)</code> </td>
            <td>如果 obj 不能被正确造型为 clazz 指定的类将抛出异常；</td>
        </tr>
        <tr>
            <td><code>isAssignable(Class superType, Class subType) / isAssignable(Class superType, Class subType, String message)</code> </td>
            <td>subType 必须可以按类型匹配于 superType，否则将抛出异常；</td>
        </tr>
    </tbody>
</table>
<p>使用 Assert 断言类可以简化方法入参检测的代码，如 InputStream getData(String file) 在应用 Assert 断言类后，其代码可以简化为以下的形式：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">public InputStream getData(String file){
            Assert.hasText(file,"file入参不是有效的文件地址");
            ① 使用 Spring 断言类进行方法入参检测
            &#8230;
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>可见使用 Spring 的 Assert 替代自编码实现的入参检测逻辑后，方法的简洁性得到了不少的提高。Assert 不依赖于 Spring 容器，您可以大胆地在自己的应用中使用这个工具类。</p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-lo-spring-utils2/#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="N101F5"><span class="atitle">小结</span></a></p>
<p>本文介绍了一些常用的 Spring 工具类，其中大部分 Spring 工具类不但可以在基于 Spring 的应用中使用，还可以在其它的应用中使用。</p>
<p>对于 Web 应用来说，由于有很多关联的脚本代码，如果这些代码通过拼接字符串的方式动态产生，就需要对动态内容中特殊的字符进行转义处理，否则就有可能产生意想不到的后果。Spring 为此提供了 HtmlUtils 和 JavaScriptUtils 工具类，只要将动态内容在拼接之前使用工具类进行转义处理，就可以避免类似问题的发生了。如果您不介意引入一个第三方类包，那么 jakarta commons lang 通用类包中的 StringEscapeUtils 工具类可能更加适合，因为它提供了更加全面的转义功能。</p>
<p>最后我们还介绍了 Spring 的 Assert 工具类，Assert 工具类是通用性很强的工具类，它使用面向对象的方式解决方法入参检测的问题，您可以在自己的应用中使用 Assert 对方法入参进行检查。</p>
<img src ="http://www.blogjava.net/hilor/aggbug/153774.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hilor/" target="_blank">hilor</a> 2007-10-18 10:02 <a href="http://www.blogjava.net/hilor/articles/153774.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)spring入门编程问题集锦</title><link>http://www.blogjava.net/hilor/articles/137477.html</link><dc:creator>hilor</dc:creator><author>hilor</author><pubDate>Fri, 17 Aug 2007 02:15:00 GMT</pubDate><guid>http://www.blogjava.net/hilor/articles/137477.html</guid><wfw:comment>http://www.blogjava.net/hilor/comments/137477.html</wfw:comment><comments>http://www.blogjava.net/hilor/articles/137477.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hilor/comments/commentRss/137477.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hilor/services/trackbacks/137477.html</trackback:ping><description><![CDATA[1、如何学习Spring？ <br>你可以通过下列途径学习spring： <br>(1) spring下载包中doc目录下的MVC-step-by-step和sample目录下的例子都是比较好的spring开发的例子。
<p>(2) AppFuse集成了目前最流行的几个开源轻量级框架或者工具Ant,XDoclet,Spring,Hibernate(iBATIS),JUnit,Cactus,StrutsTestCase,Canoo's WebTest,Struts Menu,Display Tag Library,OSCache,JSTL,Struts 。 <br>你可以通过AppFuse源代码来学习spring。 <br>AppFuse网站：http://raibledesigns.com/wiki/Wiki.jsp?page=AppFuse</p>
<p>(3)Spring 开发指南(夏昕)（http://www.xiaxin.net/Spring_Dev_Guide.rar） <br>一本spring的入门书籍,里面介绍了反转控制和依赖注射的概念，以及spring的bean管理，spring的MVC，spring和hibernte，iBatis的结合。</p>
<p>(4) spring学习的中文论坛 <br>SpringFramework中文论坛(http://spring.jactiongroup.net) <br>Java视线论坛(http://forum.javaeye.com)的spring栏目</p>
<p>2、利用Spring框架编程，console打印出log4j:WARN Please initialize the log4j system properly？ <br>说明你的log4j.properties没有配置。请把log4j.properties放到工程的classpath中，eclipse的classpath为bin目录，由于编译后src目录下的文件会拷贝到bin目录下，所以你可以把log4j.properties放到src目录下。 <br>这里给出一个log4j.properties的例子：</p>
<p>log4j.rootLogger=DEBUG,stdout <br>log4j.appender.stdout=org.apache.log4j.ConsoleAppender <br>log4j.appender.stdout.layout=org.apache.log4j.PatternLayout <br>log4j.appender.stdout.layout.ConversionPattern=%d %5p (%F:%L) - %m%n</p>
<p>3、出现 java.lang.NoClassDefFoundError? <br>一般情况下是由于你没有把必要的jar包放到lib中。</p>
<p>比如你要采用spring和hibernate（带事务支持的话），你除了spring.jar外还需要hibernat.jar、aopalliance.jar、cglig.jar、jakarta-commons下的几个jar包。</p>
<p>http://www.springframework.org/download.html下载spring开发包，提供两种zip包 <br>spring-framework-1.1.3-with-dependencies.zip和spring-framework-1.1.3.zip，我建议你下载spring-framework-1.1.3-with-dependencies.zip。这个zip解压缩后比后者多一个lib目录，其中有hibernate、j2ee、dom4j、aopalliance、jakarta-commons等常用包。</p>
<p>4、java.io.FileNotFoundException: Could not open class path resource [....hbm.xml],提示找不到xml文件？ <br>原因一般有两个： <br>(1)该xml文件没有在classpath中。 <br>(2)applicationContext-hibernate.xml中的xml名字没有带包名。比如： <br>&lt;bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean"&gt; <br>&lt;property name="dataSource"&gt;&lt;ref bean="dataSource"/&gt;&lt;/property&gt; <br>&lt;property name="mappingResources"&gt; <br>&lt;list&gt; <br>&lt;value&gt;User.hbm.xml&lt;/value&gt; 错，改为： &lt;value&gt;com/yz/spring/domain/User.hbm.xml&lt;/value&gt; <br>&lt;/list&gt; <br>&lt;/property&gt; <br>&lt;property name="hibernateProperties"&gt; <br>&lt;props&gt; <br>&lt;prop key="hibernate.dialect"&gt; net.sf.hibernate.dialect.MySQLDialect &lt;/prop&gt; <br>&lt;prop key="hibernate.show_sql"&gt;true&lt;/prop&gt; <br>&lt;/props&gt; <br>&lt;/property&gt; <br>&lt;/bean&gt;</p>
<p>5、org.springframework.beans.NotWritablePropertyException: Invalid property 'postDao' of bean class？ <br>出现异常的原因是在application-xxx.xml中property name的错误。 <br>&lt;property name="...."&gt; 中name的名字是与bean的set方法相关的，而且要注意大小写。 <br>比如 <br>public class PostManageImpl extends BaseManage implements PostManage { <br>private PostDAO dao = null; <br>public void setPostDAO(PostDAO postDAO){ <br>this.dao = postDAO; <br>} <br>} <br>那么xml的定义应该是： <br>&lt;bean id="postManage" parent="txProxyTemplate"&gt; <br>&lt;property name="target"&gt; <br>&lt;bean class="com.yz.spring.service.implement.PostManageImpl"&gt; <br>&lt;property name="postDAO"&gt;&lt;ref bean="postDAO"/&gt;&lt;/property&gt; 对 <br>&lt;property name="dao"&gt;&lt;ref bean="postDAO"/&gt;&lt;/property&gt; 错 <br>&lt;/bean&gt; <br>&lt;/property&gt; <br>&lt;/bean&gt;</p>
<p>6、Spring中如何实现事务管理？ <br>首先，如果使用mysql，确定mysql为InnoDB类型。 <br>事务管理的控制应该放到商业逻辑层。你可以写个处理商业逻辑的JavaBean，在该JavaBean中调用DAO，然后把该Bean的方法纳入spring的事务管理。</p>
<p>比如：xml文件定义如下： <br>&lt;bean id="txProxyTemplate" abstract="true" <br>class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"&gt; <br>&lt;property name="transactionManager"&gt;&lt;ref bean="transactionManager"/&gt;&lt;/property&gt; <br>&lt;property name="transactionAttributes"&gt; <br>&lt;props&gt; <br>&lt;prop key="save*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt; <br>&lt;prop key="remove*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt; <br>&lt;prop key="*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt; <br>&lt;/props&gt; <br>&lt;/property&gt; <br>&lt;/bean&gt;</p>
<p>&lt;bean id="userManage" parent="txProxyTemplate"&gt; <br>&lt;property name="target"&gt; <br>&lt;bean class="com.yz.spring.service.implement.UserManageImpl"&gt; <br>&lt;property name="userDAO"&gt;&lt;ref bean="userDAO"/&gt;&lt;/property&gt; <br>&lt;/bean&gt; <br>&lt;/property&gt; <br>&lt;/bean&gt;</p>
<p>com.yz.spring.service.implement.UserManageImpl就是我们的实现商业逻辑的JavaBean。我们通过parent元素声明其事务支持。</p>
<p>7、如何管理Spring框架下更多的JavaBean？ <br>JavaBean越多，spring配置文件就越大，这样不易维护。为了使配置清晰，我们可以将JavaBean分类管理，放在不同的配置文件中。 应用启动时将所有的xml同时加载。 <br>比如： <br>DAO层的JavaBean放到applicationContext-hibernate.xml中，商业逻辑层的JavaBean放到applicationContext-service.xml中。然后启动类中调用以下代码载入所有的ApplicationContext。</p>
<p>String[] paths = {"com/yz/spring/dao/hibernate/applicationContext-hibernate.xml", <br>"com/yz/spring/service/applicationContext-service.xml"}; <br>ctx = new ClassPathXmlApplicationContext(paths);</p>
<p>8、web应用中如何加载ApplicationContext？ <br>可以通过定义web.xml，由web容器自动加载。</p>
<p>&lt;servlet&gt; <br>&lt;servlet-name&gt;context&lt;/servlet-name&gt; <br>&lt;servlet-class&gt;org.springframework.web.context.ContextLoaderServlet&lt;/servlet-class&gt; <br>&lt;load-on-startup&gt;1&lt;/load-on-startup&gt; <br>&lt;/servlet&gt; <br><br>&lt;context-param&gt; <br>&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt; <br>&lt;param-value&gt;/WEB-INF/applicationContext-hibernate.xml&lt;/param-value&gt; <br>&lt;param-value&gt;/WEB-INF/applicationContext-service.xml&lt;/param-value&gt; <br>&lt;/context-param&gt;</p>
<p>9、在spring中如何配置的log4j? <br>在web.xml中加入以下代码即可。 <br>&lt;context-param&gt; <br>&lt;param-name&gt;log4jConfigLocation&lt;/param-name&gt; <br>&lt;param-value&gt;/WEB-INF/log4j.properties&lt;/param-value&gt; <br>&lt;/context-param&gt;</p>
<p>10、Spring框架入门的编程问题解决了，我该如何更深地领会Spring框架呢？ <br>这两本书你该去看看。这两本书是由Spring的作者Rod Johnson编写的。 <br>Expert One on one J2EE Design and Development <br>Expert One on one J2EE Development Without EJB <br>你也该看看martinfowler的Inversion of Control Containers and the Dependency Injection pattern。 <br><a href="http://www.martinfowler.com/articles/injection.html" target=blank><u><font color=#0000ff>http://www.martinfowler.com/articles/injection.html</font></u></a>
<p>再好好研读一下spring的文档。 <br><a href="http://www.jactiongroup.net/reference/html/index.html（中文版，未全部翻译）" target=blank><u><font color=#0000ff>http://www.jactiongroup.net/reference/html/index.html（中文版，未全部翻译）</font></u></a>
<p>还有就是多实践吧</p>
<img src ="http://www.blogjava.net/hilor/aggbug/137477.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hilor/" target="_blank">hilor</a> 2007-08-17 10:15 <a href="http://www.blogjava.net/hilor/articles/137477.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>