﻿<?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-&lt;h2&gt;&lt;font color="green"&gt;生命科学领域的专业信息解决方案！&lt;/font&gt;&lt;/h2&gt;-随笔分类-Spring</title><link>http://www.blogjava.net/rain1102/category/37657.html</link><description>&lt;br/&gt;&lt;font color="green" style="font-family: 华文行楷;font-size:16px;"&gt;化学结构搜索，化学信息学，生物信息学，实验室信息学等
。&lt;/font&gt;&lt;br/&gt;&lt;font color="#3C1435"&gt;以高科技的生物、化学信息技术实现生命科学领域中专业数据的计算和管理、提高研发能力、增强在科研和成本效率方面的国际竞争力，为生物、化学、医药和学术机构提供一流的解决方案和技术咨询。&lt;/font&gt;&lt;br/&gt;
&lt;br/&gt;&lt;font color="green" style="font-family: 华文行楷;font-size:16px;"&gt;子曰：危邦不入，乱邦不居。天下有道则见，无道则隐。&lt;/font&gt;&lt;font color="#3C1435"&gt;&lt;/font&gt;&lt;br/&gt;
</description><language>zh-cn</language><lastBuildDate>Fri, 06 May 2011 09:26:00 GMT</lastBuildDate><pubDate>Fri, 06 May 2011 09:26:00 GMT</pubDate><ttl>60</ttl><item><title>当@PathVariable遇上中文和点</title><link>http://www.blogjava.net/rain1102/archive/2011/05/05/349643.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Thu, 05 May 2011 15:03:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2011/05/05/349643.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/349643.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2011/05/05/349643.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/349643.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/349643.html</trackback:ping><description><![CDATA[<p>Spring MVC从3.0开始支持REST，而主要就是通过@PathVariable来处理请求参数和路径的映射。<br />
由于考虑到SEO的缘故，很多人喜欢把新闻的名称作为路径中的一部分去处理，这时候中文的名称就会遇到问题，没办法映射，这个是因为编码问题，只要到TOMCAT/conf下找到server.xml，添加URIEncoding="UTF-8"进行URL编码设置就可以解决中文问题。<br />
另外经常遇到路径中有点"."，而点是特殊字符，比如.html, .do等等，所以Spring MVC默认是把点后面的信息当作文件后缀，这时候我们就要修改这个默认值。</p>
&lt;bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"&gt; <br />
&nbsp;&nbsp;&lt;property name="interceptors" ref="localeChangeInterceptor"/&gt;<br />
&nbsp;&nbsp;<span style="color: red">&lt;property name="useDefaultSuffixPattern" value="false" /&gt;&nbsp;<br />
</span>&nbsp;&lt;/bean&gt; <br />
<br />
另外，这时候如果只设置这个，请求可以传递到对于的controller，但传过去的数据会有问题，只会传最后一个点前面的数据，除非你在最后加上&#8220;/&#8221;，比如/news/测试.点/&nbsp; 这样就会把&#8220;测试.点&#8221;当作整体，不然只会得到&#8220;测试&#8221;。这时候我们可以这样设置<span style="color: #000000"><span style="color: #ff0000">@RequestMapping("/news/{title:.*}")<br />
</span>这样就一切ok啦。</span><img src ="http://www.blogjava.net/rain1102/aggbug/349643.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2011-05-05 23:03 <a href="http://www.blogjava.net/rain1102/archive/2011/05/05/349643.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Flash Scope for Spring MVC(Without Spring Web Flow)</title><link>http://www.blogjava.net/rain1102/archive/2010/05/28/322112.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Fri, 28 May 2010 02:19:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2010/05/28/322112.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/322112.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2010/05/28/322112.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/322112.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/322112.html</trackback:ping><description><![CDATA[<a href="http://jira.springframework.org/browse/SPR-6464?page=com.atlassian.jira.plugin.system.issuetabpanels%3Aall-tabpanel#issue-tabs" target="_blank">http://jira.springframework.org/browse/SPR-6464?page=com.atlassian.jira.plugin.system.issuetabpanels%3Aall-tabpanel#issue-tabs</a><img src ="http://www.blogjava.net/rain1102/aggbug/322112.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2010-05-28 10:19 <a href="http://www.blogjava.net/rain1102/archive/2010/05/28/322112.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>REST in Spring 3: @MVC</title><link>http://www.blogjava.net/rain1102/archive/2009/12/24/307201.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Thu, 24 Dec 2009 11:53:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2009/12/24/307201.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/307201.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2009/12/24/307201.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/307201.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/307201.html</trackback:ping><description><![CDATA[<p>In the last couple of years, REST has emerged as a compelling alternative to SOAP/WSDL/WS-*-based distributed architectures. So when we started to plan our work on the next major release of Spring &#8211; version 3.0, it was quite clear to us that we had to focus on making the development of 'RESTful' Web services and applications easier. Now, what is and isn't 'RESTful' could be the topic of a whole new post all together; in this post I'll take a more practical approach, and focus on the features that we added to the @Controller model of Spring MVC.</p>
<h2>A Bit of Background</h2>
<p><em>Ok, I lied: there is some background first. If you really want to learn about the new features, feel free to skip to the <a href="http://blog.springsource.com/2009/03/08/rest-in-spring-3-mvc/#features">next section</a>.</em></p>
<p>For me, work on REST started about two years ago, shortly after reading the highly recommended book <a onclick="javascript:urchinTracker('/outbound/oreilly.com');" href="http://oreilly.com/catalog/9780596529260/index.html">RESTful Web Services</a> from O'Reilly, by Leonard Richardson and Sam Ruby. Initially, I was thinking about adding REST support to <a onclick="javascript:urchinTracker('/outbound/www.springsource.org');" href="http://www.springsource.org/spring-ws">Spring Web Services</a>, but after working a couple of weeks on a prototype, it became clear to me that this wasn't a very good fit. In particular, I found out that I had to copy most of the logic from the Spring-MVC <tt>DispatcherServlet</tt> over to Spring-WS. Clearly, this was not the way to go forward.</p>
<p>Around the same time we introduced the <a href="http://blog.springsource.com/2007/11/14/annotated-web-mvc-controllers-in-spring-25/">annotation-based model of Spring MVC</a>. This model was clearly an improvement to the former, inheritance-based model. Another interesting development at that time was the development of the <a onclick="javascript:urchinTracker('/outbound/jcp.org');" href="http://jcp.org/en/jsr/detail?id=311">JAX-RS</a> specification. My next attempt was to try and merge these two models: to try and combine the @MVC annotations with the JAX-RS annotations, and to be able to run JAX-RS applications within the <tt>DispatcherServlet</tt>. While I did get a working prototype out of this effort, the result was not satisfactory. There were a number of technical issues which I won't bore you with, but most importantly the approach felt 'clunky' and unnatural for a developer who was already used to Spring MVC 2.5.</p>
<p>Finally, we decided to add the RESTful functionality to features to Spring MVC itself. Obviously, that would mean that there would be some overlap with JAX-RS, but at least the programming model would be satisfactory for Spring MVC developers, both existing and new ones. Additionally, there are already three JAX-RS implementations offering Spring support (<a href="https://jersey.dev.java.net/">Jersey</a>, <a onclick="javascript:urchinTracker('/outbound/www.jboss.org');" href="http://www.jboss.org/resteasy/">RESTEasy</a>, and <a onclick="javascript:urchinTracker('/outbound/www.restlet.org');" href="http://www.restlet.org/">Restlet</a>). Adding a fourth to this list did not seem a good use of our valuable time.</p>
<h2><a name="features" modo="false">RESTful features in Spring MVC 3.0</a></h2>
<p>Now, enough of the background, let's look at the features!</p>
<h3>URI Templates</h3>
<p>A URI template is a URI-like string, containing one or more variable names. When these variables are substituted for values, the template becomes a URI. For more information, see the <a onclick="javascript:urchinTracker('/outbound/bitworking.org');" href="http://bitworking.org/projects/URI-Templates/">proposed RFC</a>.</p>
<p>In Spring 3.0 M1, we introduced the use of URI templates through the <tt>@PathVariable</tt> annotation. For instance:</p>
<div class="syntaxhighlighter " id="highlighter_205437">
<div class="toolbar">&nbsp;</div>
<div class="lines">
<div class="line alt1"><code class="number">1.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="color1">@RequestMapping</code><code class="plain">(</code><code class="string">"/hotels/{hotelId}"</code><code class="plain">) </code></span></span></div>
<div class="line alt2"><code class="number">2.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="keyword">public</code> <code class="plain">String getHotel(</code><code class="color1">@PathVariable</code> <code class="plain">String hotelId, Model model) { </code></span></span></div>
<div class="line alt1"><code class="number">3.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">List&lt;Hotel&gt; hotels = hotelService.getHotels(); </code></span></span></div>
<div class="line alt2"><code class="number">4.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">model.addAttribute(</code><code class="string">"hotels"</code><code class="plain">, hotels); </code></span></span></div>
<div class="line alt1"><code class="number">5.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="keyword">return</code> <code class="string">"hotels"</code><code class="plain">; </code></span></span></div>
<div class="line alt2"><code class="number">6.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="plain">}</code></span></span></div>
</div>
</div>
<p>When a request comes in for <tt>/hotels/1</tt>, that 1 will be bound to the <tt>hotelId</tt> parameter. You can optionally specify the variable name the parameter is bound to, but when you compile your code with debugging enabled that is not necessary: we infer the path variable name from the parameter name.</p>
<p>You can also have more than one path variable, like so:</p>
<div class="syntaxhighlighter " id="highlighter_13061">
<div class="toolbar">&nbsp;</div>
<div class="lines">
<div class="line alt1"><code class="number">1.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="color1">@RequestMapping</code><code class="plain">(value=</code><code class="string">"/hotels/{hotel}/bookings/{booking}"</code><code class="plain">, method=RequestMethod.GET) </code></span></span></div>
<div class="line alt2"><code class="number">2.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="keyword">public</code> <code class="plain">String getBooking(</code><code class="color1">@PathVariable</code><code class="plain">(</code><code class="string">"hotel"</code><code class="plain">) </code><code class="keyword">long</code> <code class="plain">hotelId, </code><code class="color1">@PathVariable</code><code class="plain">(</code><code class="string">"booking"</code><code class="plain">) </code><code class="keyword">long</code> <code class="plain">bookingId, Model model) { </code></span></span></div>
<div class="line alt1"><code class="number">3.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">Hotel hotel = hotelService.getHotel(hotelId); </code></span></span></div>
<div class="line alt2"><code class="number">4.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">Booking booking = hotel.getBooking(bookingId); </code></span></span></div>
<div class="line alt1"><code class="number">5.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">model.addAttribute(</code><code class="string">"booking"</code><code class="plain">, booking); </code></span></span></div>
<div class="line alt2"><code class="number">6.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="keyword">return</code> <code class="string">"booking"</code><code class="plain">; </code></span></span></div>
<div class="line alt1"><code class="number">7.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="plain">}</code></span></span></div>
</div>
</div>
<p>This would match requests like <tt>/hotels/1/bookings/2</tt>, for instance.</p>
<p>You can also combine the use of Ant-style paths and path variables, like so:</p>
<div class="syntaxhighlighter " id="highlighter_8191">
<div class="toolbar">&nbsp;</div>
<div class="lines">
<div class="line alt1"><code class="number">1.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="color1">@RequestMapping</code><code class="plain">(value=</code><code class="string">"/hotels/*/bookings/{booking}"</code><code class="plain">, method=RequestMethod.GET) </code></span></span></div>
<div class="line alt2"><code class="number">2.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="keyword">public</code> <code class="plain">String getBooking(</code><code class="color1">@PathVariable</code><code class="plain">(</code><code class="string">"booking"</code><code class="plain">) </code><code class="keyword">long</code> <code class="plain">bookingId, Model model) { </code></span></span></div>
<div class="line alt1"><code class="number">3.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">... </code></span></span></div>
<div class="line alt2"><code class="number">4.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="plain">}</code></span></span></div>
</div>
</div>
<p>and you can use data binding, too:</p>
<div class="syntaxhighlighter " id="highlighter_311065">
<div class="toolbar">&nbsp;</div>
<div class="lines">
<div class="line alt1"><code class="number">01.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="color1">@InitBinder</code></span></span></div>
<div class="line alt2"><code class="number">02.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="keyword">public</code> <code class="keyword">void</code> <code class="plain">initBinder(WebDataBinder binder) { </code></span></span></div>
<div class="line alt1"><code class="number">03.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">SimpleDateFormat dateFormat = </code><code class="keyword">new</code> <code class="plain">SimpleDateFormat(</code><code class="string">"yyyy-MM-dd"</code><code class="plain">); </code></span></span></div>
<div class="line alt2"><code class="number">04.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">binder.registerCustomEditor(Date.</code><code class="keyword">class</code><code class="plain">, </code><code class="keyword">new</code> <code class="plain">CustomDateEditor(dateFormat, </code><code class="keyword">false</code><code class="plain">)); </code></span></span></div>
<div class="line alt1"><code class="number">05.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="plain">} </code></span></span></div>
<div class="line alt2"><code class="number">06.</code><span class="content"><code class="spaces">&nbsp;</code><span class="block" style="margin-left: 7px! important">&nbsp;</span></span></div>
<div class="line alt1"><code class="number">07.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="color1">@RequestMapping</code><code class="plain">(</code><code class="string">"/hotels/{hotel}/dates/{date}"</code><code class="plain">) </code></span></span></div>
<div class="line alt2"><code class="number">08.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="keyword">public</code> <code class="keyword">void</code> <code class="plain">date(</code><code class="color1">@PathVariable</code><code class="plain">(</code><code class="string">"hotel"</code><code class="plain">) String hotel, </code><code class="color1">@PathVariable</code> <code class="plain">Date date) { </code></span></span></div>
<div class="line alt1"><code class="number">09.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">... </code></span></span></div>
<div class="line alt2"><code class="number">10.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="plain">}</code></span></span></div>
</div>
</div>
<p>The above would match <tt>/hotels/1/dates/2008-12-18</tt>, for instance.</p>
<h3>Content Negotiation</h3>
<p>In version 2.5, Spring-MVC lets the @Controller decide which view to render for a given request, through its <tt>View</tt>, view name, and <tt>ViewResolver</tt> abstractions. In a RESTful scenario, it is common to let the client decide the acceptable representations, via the <tt>Accept</tt> HTTP header. The server responds with the delivered representation via the <tt>Content-Type</tt> header. This process is known as <a onclick="javascript:urchinTracker('/outbound/en.wikipedia.org');" href="http://en.wikipedia.org/wiki/Content_negotiation">content negotiation</a>.</p>
<p>One issue with the <tt>Accept</tt> header is that is impossible to change it in a web browser, in HTML. For instance, in Firefox, it's fixed to</p>
<div class="codesnip-container">Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8</div>
<p>So what if you want to link to a PDF version of a particular resource? Looking at the file extension is a good workaround. For example, <tt>http://example.com/hotels.pdf</tt> retrieves the PDF view of the hotel list, as does <tt>http://example.com/hotels</tt> with an Accept header of <tt>application/pdf</tt>.</p>
<p>This is what the <tt>ContentNegotiatingViewResolver</tt> does: it wraps one or more other <tt>ViewResolver</tt>s, looks at the <tt>Accept</tt> header or file extension, and resolves a view corresponding to these. In an upcoming blog post, Alef Arendsen will show you how to use the <tt>ContentNegotiatingViewResolver</tt>.</p>
<h3>Views</h3>
<p>We also added some new Views to Spring MVC, particularly:</p>
<ul>
    <li>the <a onclick="javascript:urchinTracker('/outbound/static.springsource.org');" href="http://static.springsource.org/spring/docs/3.0.0.M1/javadoc-api/org/springframework/web/servlet/view/feed/AbstractAtomFeedView.html"><tt>AbstractAtomFeedView</tt></a> and <a onclick="javascript:urchinTracker('/outbound/static.springsource.org');" href="http://static.springsource.org/spring/docs/3.0.0.M1/javadoc-api/org/springframework/web/servlet/view/feed/AbstractRssFeedView.html"><tt>AbstractRssFeedView</tt></a>, which can be used to return an Atom and RSS feed,
    <li>the <a onclick="javascript:urchinTracker('/outbound/static.springframework.org');" href="http://static.springframework.org/spring/docs/3.0.0.M2/javadoc-api/org/springframework/web/servlet/view/xml/MarshallingView.html"><tt>MarshallingView</tt></a>, which can be used to return an XML representation. This view is based on the Object/XML Mapping module, which has been copied from the Spring Web Services project. This module wraps XML marshalling technologies such as JAXB, Castor, JiBX, and more, and makes it easier to configure these within a Spring application context,
    <li>the <tt>JacksonJsonView</tt>, for JSON representations of objects in your model. This view is actually part of the Spring JavaScript project, which we'll talk about more in a future blog post. </li>
</ul>
<p>Obviously, these work great in combination with the <tt>ContentNegotiatingViewResolver</tt>!</p>
<h3>HTTP Method Conversion</h3>
<p>Another key principle of REST is the use of the Uniform Interface. Basically, this means that all resources (URLs) can be manipulated using the same four HTTP method: GET, PUT, POST, and DELETE. For each of methods, the HTTP specification defines exact semantics. For instance, a GET should always be a safe operation, meaning that is has no side effects, and a PUT or DELETE should be idempotent, meaning that you can repeat these operations over and over again, but the end result should be the same.</p>
<p>While HTTP defines these four methods, HTML only supports two: GET and POST. Fortunately, there are two possible workarounds: you can either use JavaScript to do your PUT or DELETE, or simply do a POST with the 'real' method as an additional parameter (modeled as a hidden input field in an HTML form). This latter trick is what the <tt>HiddenHttpMethodFilter</tt> does. This filter was introduced in Spring 3.0 M1, and is a plain Servlet Filter. As such, it can be used in combination with any web framework (not just Spring MVC). Simply add this filter to your <tt>web.xml</tt>, and a POST with a hidden <tt>_method</tt> parameter will be converted into the corresponding HTTP method request.</p>
<p>As an extra bonus, we've also added support for method conversion in the Spring MVC form tags. For example, the following snippet taken from the updated Petclinic sample:</p>
<div class="syntaxhighlighter " id="highlighter_354227">
<div class="toolbar">&nbsp;</div>
<div class="lines">
<div class="line alt1"><code class="number">1.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="plain">&lt;</code><code class="keyword">form:form</code> <code class="color1">method</code><code class="plain">=</code><code class="string">"delete"</code><code class="plain">&gt; </code></span></span></div>
<div class="line alt2"><code class="number">2.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">&lt;</code><code class="keyword">p</code> <code class="color1">class</code><code class="plain">=</code><code class="string">"submit"</code><code class="plain">&gt;&lt;</code><code class="keyword">input</code> <code class="color1">type</code><code class="plain">=</code><code class="string">"submit"</code> <code class="color1">value</code><code class="plain">=</code><code class="string">"Delete Pet"</code><code class="plain">/&gt;&lt;/</code><code class="keyword">p</code><code class="plain">&gt; </code></span></span></div>
<div class="line alt1"><code class="number">3.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="plain">&lt;/</code><code class="keyword">form:form</code><code class="plain">&gt;</code></span></span></div>
</div>
</div>
<p>will actually perform an HTTP POST, with the 'real' DELETE method hidden behind a request parameter, to be picked up by the <tt>HiddenHttpMethodFilter</tt>. The corresponding @Controller method is therefore:</p>
<div class="syntaxhighlighter " id="highlighter_172114">
<div class="toolbar">&nbsp;</div>
<div class="lines">
<div class="line alt1"><code class="number">1.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="color1">@RequestMapping</code><code class="plain">(method = RequestMethod.DELETE) </code></span></span></div>
<div class="line alt2"><code class="number">2.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="keyword">public</code> <code class="plain">String deletePet(</code><code class="color1">@PathVariable</code> <code class="keyword">int</code> <code class="plain">ownerId, </code><code class="color1">@PathVariable</code> <code class="keyword">int</code> <code class="plain">petId) { </code></span></span></div>
<div class="line alt1"><code class="number">3.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="keyword">this</code><code class="plain">.clinic.deletePet(petId); </code></span></span></div>
<div class="line alt2"><code class="number">4.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="keyword">return</code> <code class="string">"redirect:/owners/"</code> <code class="plain">+ ownerId; </code></span></span></div>
<div class="line alt1"><code class="number">5.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="plain">}</code></span></span></div>
</div>
</div>
<h3>ETag support</h3>
<p>An <a onclick="javascript:urchinTracker('/outbound/en.wikipedia.org');" href="http://en.wikipedia.org/wiki/HTTP_ETag">ETag</a> (entity tag) is an HTTP response header returned by an HTTP/1.1 compliant web server used to determine change in content at a given URL. It can be considered to be the more sophisticated successor to the <tt>Last-Modified</tt> header. When a server returns a representation with an ETag header, client can use this header in subsequent GETs, in a <tt>If-None-Match</tt> header. If the content has not changed, the server will return <tt>304: Not Modified</tt>.</p>
<p>In Spring 3.0 M1, we introduced the <tt>ShallowEtagHeaderFilter</tt>. This is a plain Servlet Filter, and thus can be used in combination any web framework. As the name indicates, the filter creates so-called <em>shallow</em> ETags (as opposed to a deep ETags, more about that later). The way it works is quite simple: the filter simply caches the content of the rendered JSP (or other content), generates a MD5 hash over that, and returns that as a <tt>ETag</tt> header in the response. The next time a client sends a request for the same resource, it use that hash as the <tt>If-None-Match</tt> value. The filter notices this, renders the view again, and compares the two hashes. If they are equal, a 304 is returned. It is important to note that this filter will not save processing power, as the view is still rendered. The only thing it saves is <strong>bandwith</strong>, as the rendered response is not sent back over the wire.</p>
<p><em>Deep</em> ETags are a bit more complicated. In this case, the ETag is based on the underlying domain objects, RDMBS tables, etc. Using this approach, no content is generated unless the underlying data has changed. Unfortunately, implementing this approach in a generic way is much more difficult than shallow ETags. We might add support for deep ETags in a later version of Spring, by relying on JPA's @Version annotation, or an AspectJ aspect for instance.</p>
<h2>And more!</h2>
<p>In a following post, I will conclude my RESTful journey, and talk about the <tt>RestTemplate</tt>, which was also introduced in Spring 3.0 M2. This class gives you client-side access to RESTful resources in a fashion similar to the <tt>JdbcTemplate</tt>, <tt>JmsTemplate</tt>, etc.<br />
</p>
<h2>Similar Posts</h2>
<ul class="similar-posts">
    <li><a title="March 27, 2009" href="http://blog.springsource.com/2009/03/27/rest-in-spring-3-resttemplate/" rel="bookmark">REST in Spring 3: RestTemplate</a>
    <li><a title="March 16, 2009" href="http://blog.springsource.com/2009/03/16/adding-an-atom-view-to-an-application-using-springs-rest-support/" rel="bookmark">Adding an Atom view to an application using Spring's REST support</a>
    <li><a title="July 10, 2009" href="http://blog.springsource.com/2009/07/10/pluggable-styling-with-springsource-slices/" rel="bookmark">Pluggable styling with SpringSource Slices</a>
    <li><a title="March 29, 2007" href="http://blog.springsource.com/2007/03/29/aop-context-binding/" rel="bookmark">AOP Context Binding With Named Pointcuts</a>
    <li><a title="November 14, 2007" href="http://blog.springsource.com/2007/11/14/annotated-web-mvc-controllers-in-spring-25/" rel="bookmark">Annotated Web MVC Controllers in Spring 2.5</a> </li>
</ul>
<br />
<br />
原文地址：http://blog.springsource.com/2009/03/08/rest-in-spring-3-mvc/<img src ="http://www.blogjava.net/rain1102/aggbug/307201.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2009-12-24 19:53 <a href="http://www.blogjava.net/rain1102/archive/2009/12/24/307201.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JavaMail问题之Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream</title><link>http://www.blogjava.net/rain1102/archive/2009/11/17/302654.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Tue, 17 Nov 2009 03:05:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2009/11/17/302654.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/302654.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2009/11/17/302654.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/302654.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/302654.html</trackback:ping><description><![CDATA[<p><strong>Exception in thread "main" <a title="Java爱好者" href="http://www.blogjava.net/rain1102">Java</a>.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream</strong></p>
<p>解决方案:</p>
<p>&nbsp;&nbsp;&nbsp;JavaEE版本和JavaMail的版本不一致,请将sun公司上下载最新版本.http://java.sun.com/products/javamail/downloads/index.html<br />
&nbsp;&nbsp; 例如:javaMail 1.3以下的如果在javaEE5上就会出现上面的错误,<br />
&nbsp;&nbsp;&nbsp;如果还出现此问题，则是因为javaEE5中包含有javaMail的类但是却不全面,所以出本身的JavaMail<br />
&nbsp;&nbsp; 包冲突.用rar打开X:/Program Files/MyEclipse 6.0/myeclipse/eclipse/plugins/com.genuitec.eclipse.j2eedt.core_x.x.x.zmyeclipsexxxxxxxxx/data/libraryset/EE_5/javaee.jar<br />
,然后删除mail,一切就ok了.<br />
</p><img src ="http://www.blogjava.net/rain1102/aggbug/302654.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2009-11-17 11:05 <a href="http://www.blogjava.net/rain1102/archive/2009/11/17/302654.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate中主键增长步长为50的问题 Oracle</title><link>http://www.blogjava.net/rain1102/archive/2009/11/11/302019.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Wed, 11 Nov 2009 13:54:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2009/11/11/302019.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/302019.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2009/11/11/302019.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/302019.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/302019.html</trackback:ping><description><![CDATA[<p>原文地址：http://jhyimu2005.javaeye.com/blog/514379<br />
先声明一下我用的框架是Spring + Hibernate + SpringMVC 数据库使用的是Oracle <br />
昨天遇到了一个特诡异的问题就是我使用Oracle序列，把主键的计数交给Hibernate处理，
Entity
@Table(name = "BIO_STUDY")
public class Study implements Serializable{
private static final long serialVersionUID = -5932941248053882057L;
private int id;
private Project project;
private String name;
private String description;
private Set&lt;Experiment&gt; experiments;
@Id
@Column(name = "ID")
@SequenceGenerator(name = "BIO_STUDY_SQ",
sequenceName = "BIO_STUDY_SQ" )
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "BIO_STUDY_SQ")
public int getId() {
return id;
}

<p><br />
写完部署什么都没问题，可当我写了测试类进行测试时发现主键的初始值竟然是50，其步长亦是50，在同事的帮助下发现原来是Hibernate在做鬼，@SequenceGenerator中添加两个参数<span style="color: red">（allocationSize = 1, initialValue = 1）</span>就OK。通过查找Hibernate的资料发现原来是因为allocationSize的默认值是50.具体请参考http://www.oracle.com/technology/global/cn/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#SequenceGenerator <br />
<br />
<span style="color: red">只需要增加allocationSize = 1就可以</span></p><img src ="http://www.blogjava.net/rain1102/aggbug/302019.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2009-11-11 21:54 <a href="http://www.blogjava.net/rain1102/archive/2009/11/11/302019.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>AbstractTransactionalJUnit4SpringContextTests中的事务回滚</title><link>http://www.blogjava.net/rain1102/archive/2009/11/04/301147.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Wed, 04 Nov 2009 12:58:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2009/11/04/301147.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/301147.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2009/11/04/301147.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/301147.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/301147.html</trackback:ping><description><![CDATA[今天同事问了一个问题，关于annotation配置多对多关联映射以后，创建新的对象时候，为什么多对多的关系没有保存到关系表中。具体问题如下：<br />
当前有一个User和一个Role，它们是多对多关系，中间表为user_role存放user和role的id。部分User代码如下：<br />
<span style="color: #008000">@ManyToMany(cascade = { CascadeType.PERSIST }, fetch = FetchType.LAZY)&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; @JoinTable(name = "user_role", <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;joinColumns = @JoinColumn(name = "user_id"), <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;inverseJoinColumns = @JoinColumn(name = "role_id"))&nbsp;&nbsp;&nbsp;&nbsp;</span><br />
&nbsp;public Set&lt;Role&gt; getRoles() {<br />
&nbsp;&nbsp;return roles;<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;public void setRoles(Set&lt;Role&gt; roles) {<br />
&nbsp;&nbsp;this.roles = roles;<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;public void addRole(Role role) {<br />
&nbsp;&nbsp;if (!this.roles.contains(role)) {<br />
&nbsp;&nbsp;&nbsp;this.roles.add(role);<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;public void removeRole(Role role) {<br />
&nbsp;&nbsp;this.roles.remove(role);<br />
&nbsp;}<br />
<br />
Role中的部分代码如下：<br />
<span style="color: #008000">@ManyToMany(<br />
&nbsp;&nbsp;&nbsp;cascade = {CascadeType.PERSIST, CascadeType.MERGE},<br />
&nbsp;&nbsp;&nbsp;mappedBy = "roles",<br />
&nbsp;&nbsp;&nbsp;targetEntity = User.class<br />
&nbsp;&nbsp;&nbsp;)</span><br />
&nbsp;public Set&lt;User&gt; getUsers() {<br />
&nbsp;&nbsp;return users;<br />
&nbsp;}<br />
<br />
而测试代码继承了AbstractTransactionalJUnit4SpringContextTests，代码如下：<br />
&nbsp;@Test<br />
&nbsp;public void testManyToMany() {<br />
&nbsp;&nbsp;Role oneRole = new Role();<br />
&nbsp;&nbsp;oneRole.setDescription("manager");<br />
&nbsp;&nbsp;oneRole.setEnabled(true);<br />
&nbsp;&nbsp;oneRole.setRoleName("manger");<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;Role twoRole = new Role();<br />
&nbsp;&nbsp;twoRole.setDescription("waitress");<br />
&nbsp;&nbsp;twoRole.setEnabled(true);<br />
&nbsp;&nbsp;twoRole.setRoleName("waitress");<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;User user = new User();<br />
&nbsp;&nbsp;user.setEnabled(true);<br />
&nbsp;&nbsp;user.setPassword("jianghaiying");<br />
&nbsp;&nbsp;user.setUsername("Jiang HaiYing");<br />
&nbsp;&nbsp;user.addRole(oneRole);<br />
&nbsp;&nbsp;user.addRole(twoRole);<br />
&nbsp;&nbsp;userDAO.persist(user);<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;userDAO.getConnection().commit();<br />
&nbsp;&nbsp;} catch (SQLException e) {<br />
&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
这样执行以后，打印出的信息如下：<br />
Hibernate: insert into user (enabled, password, username) values (?, ?, ?)<br />
Hibernate: insert into role (description, enabled, name) values (?, ?, ?)<br />
Hibernate: insert into role (description, enabled, name) values (?, ?, ?)<br />
<br />
这时候问题出来了，为什么没有往关系表中插入数据？<br />
其实这并不是代码或者配置写错误了，在正式运行代码一切正常，而是AbstractTransactionalJUnit4SpringContextTests出的鬼，事实上多对多关联关系是由Hibernate去帮我们维护的，而AbstractTransactionalJUnit4SpringContextTests为了保持数据的清洁又会自动回滚。如何解决这个问题呢？<br />
方法：<br />
只需要在test方法上添加<span style="color: #008000">@Rollback(false)，</span>不让它回滚，一切正常了。这时候也可以去掉try语句了。<br />
Hibernate: insert into user (enabled, password, username) values (?, ?, ?)<br />
Hibernate: insert into role (description, enabled, name) values (?, ?, ?)<br />
Hibernate: insert into role (description, enabled, name) values (?, ?, ?)<br />
Hibernate: insert into user_role (user_id, role_id) values (?, ?)<br />
Hibernate: insert into user_role (user_id, role_id) values (?, ?)<img src ="http://www.blogjava.net/rain1102/aggbug/301147.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2009-11-04 20:58 <a href="http://www.blogjava.net/rain1102/archive/2009/11/04/301147.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring MVC集成Tiles时候的属性值国际化</title><link>http://www.blogjava.net/rain1102/archive/2009/10/24/299586.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Sat, 24 Oct 2009 13:08:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2009/10/24/299586.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/299586.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2009/10/24/299586.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/299586.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/299586.html</trackback:ping><description><![CDATA[<p>在使用Tiles时候, 一般会有类似以下配置:<br />
&lt;definition name="main.layout" template="/jsp/layout/baseLayout.jsp"&gt;<br />
&nbsp;&nbsp;&lt;put-attribute name="title" value="Tiles Test Title" /&gt;<br />
&nbsp;&nbsp;&lt;put-attribute name="header" value="/jsp/layout/header.jsp" /&gt;<br />
&nbsp;&nbsp;&lt;put-attribute name="body" value="/" /&gt;<br />
&nbsp;&nbsp;&lt;put-attribute name="footer" value="/jsp/layout/footer.jsp" /&gt;<br />
&nbsp;&lt;/definition&gt;</p>
默认情况下, 如果value值一"/"开头, 则认为是URL, 其他则任务是字符串, 而如果想让title实现国际化, 如何配置呢?<br />
以下有两种解决方案, 一种就是准备多个tiles配置文件,如tiles_def_zh_CN.xml, tile_def_en_US.xml, 这个优点麻烦了(个人觉得).<br />
第二种方法就是使用标签, 如果spring:message或者fmt等等, 具体如下:<br />
修改tiles配置文件中的title对应的值为资源文件中的key:<br />
&lt;put-attribute name="title" value="project.title" /&gt;<br />
然后修改页面需要渲染的地方:<br />
<span style="color: #008000">&lt;tiles:useAttribute id="key" name="title"/&gt;<br />
&lt;title&gt;&lt;spring:message code="${key}"/&gt;&lt;/title&gt;</span><br />
或者<br />
<span style="color: #008000">&lt;tiles:useAttribute id="key" name="title"/&gt;<br />
&lt;title&gt;&lt;fmt:message key="${key}"/&gt;title&gt;</span><img src ="http://www.blogjava.net/rain1102/aggbug/299586.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2009-10-24 21:08 <a href="http://www.blogjava.net/rain1102/archive/2009/10/24/299586.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Interceptor中onFlushDirty方法的参数previousState一直是空</title><link>http://www.blogjava.net/rain1102/archive/2009/06/05/280270.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Fri, 05 Jun 2009 12:58:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2009/06/05/280270.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/280270.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2009/06/05/280270.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/280270.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/280270.html</trackback:ping><description><![CDATA[Interceptor中onFlushDirty方法的参数previousState一直是空, 经检查发现原来在更新对象的时候使用saveOrUpdate方法的缘故, 替换使用merge问题就解决了.<br /><img src ="http://www.blogjava.net/rain1102/aggbug/280270.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2009-06-05 20:58 <a href="http://www.blogjava.net/rain1102/archive/2009/06/05/280270.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用@RequestParam绑定请求参数到方法参数</title><link>http://www.blogjava.net/rain1102/archive/2009/03/17/260273.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Tue, 17 Mar 2009 08:26:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2009/03/17/260273.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/260273.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2009/03/17/260273.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/260273.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/260273.html</trackback:ping><description><![CDATA[@RequestParam注解用于在控制器中绑定请求参数到方法参数.<br />
用法如下:<br />
@RequestMapping<br />
&nbsp;public void advancedSearch(<br />
&nbsp;<span style="color: #008000">&nbsp;&nbsp;@RequestParam("queryStr") String queryStr,<br />
&nbsp;&nbsp;&nbsp;@RequestParam("showFlag") String showFlag,<br />
&nbsp;&nbsp;&nbsp;@RequestParam("totalnumber") String totalNumber,<br />
&nbsp;&nbsp;&nbsp;@RequestParam("upType") String upType,<br />
&nbsp;&nbsp;&nbsp;@RequestParam("jmesareq") String jmesaReq,<br />
&nbsp;&nbsp;&nbsp;@RequestParam("isExportOper") String isExportOper,</span><br />
&nbsp;&nbsp;&nbsp;HttpServletResponse response, final HttpServletRequest request,<br />
&nbsp;&nbsp;&nbsp;ModelMap model) {<br />
&nbsp;&nbsp;// get query structure and query type from page<br />
&nbsp;&nbsp;List&lt;Long&gt; cd_ids = new ArrayList&lt;Long&gt;();<br />
&nbsp;&nbsp;if(StringUtils.equals("invoke", jmesaReq)){<br />
&nbsp;&nbsp;&nbsp;cd_ids = (List&lt;Long&gt;)request.getSession().getAttribute(Constants.RESULT_IDS);<br />
&nbsp;&nbsp;}<br />
&nbsp;....<br />
&nbsp;}<br />
<br />
使用这个注解参数默认是必需的, 但是可以把@RequestParam的required属性设置为false从而让这个参数可选.<br />
例如<span style="color: #008000">@RequestParam(value="name", required="false")</span><img src ="http://www.blogjava.net/rain1102/aggbug/260273.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2009-03-17 16:26 <a href="http://www.blogjava.net/rain1102/archive/2009/03/17/260273.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring Security 2 配置精讲[转载]</title><link>http://www.blogjava.net/rain1102/archive/2009/03/14/259768.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Sat, 14 Mar 2009 15:04:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2009/03/14/259768.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/259768.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2009/03/14/259768.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/259768.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/259768.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 论坛上看了不少Spring Security的相关文章。这些文章基本上都还是基于Acegi-1.X的配置方式，而主要的配置示例也来自于SpringSide的贡献。 众所周知，Spring Security针对Acegi的一个重大的改进就在于其配置方式大大简化了。所以如果配置还是基于Acegi-1.X这样比较繁琐的配置方式的话，那么我们还不如直接使用Acegi而不要去升级了。所以在这里，我将...&nbsp;&nbsp;<a href='http://www.blogjava.net/rain1102/archive/2009/03/14/259768.html'>阅读全文</a><img src ="http://www.blogjava.net/rain1102/aggbug/259768.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2009-03-14 23:04 <a href="http://www.blogjava.net/rain1102/archive/2009/03/14/259768.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring中Bean的生命中期与InitializingBean和DisposableBean接口</title><link>http://www.blogjava.net/rain1102/archive/2009/03/14/259764.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Sat, 14 Mar 2009 14:22:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2009/03/14/259764.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/259764.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2009/03/14/259764.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/259764.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/259764.html</trackback:ping><description><![CDATA[<p><span style="color: black; font-family: 'Tahoma','sans-serif'">Spring</span><span style="color: black; font-family: 宋体">提供了一些标志接口，用来改变</span><span style="color: black; font-family: 'Tahoma','sans-serif'">BeanFactory</span><span style="color: black; font-family: 宋体">中的</span><span style="color: black; font-family: 'Tahoma','sans-serif'">bean</span><span style="color: black; font-family: 宋体">的行为。</span><span style="color: black; font-family: 宋体">它们包括</span><span style="color: black; font-family: 'Tahoma','sans-serif'">InitializingBean</span><span style="color: black; font-family: 宋体">和</span><span style="color: black; font-family: 'Tahoma','sans-serif'">DisposableBean</span><span style="color: black; font-family: 宋体">。</span><span style="color: black; font-family: 宋体">实现这些接口将会导致</span><span style="color: black; font-family: 'Tahoma','sans-serif'">BeanFactory</span><span style="color: black; font-family: 宋体">调用前一个接口的</span><span style="color: black; font-family: 'Tahoma','sans-serif'">afterPropertiesSet()</span><span style="color: black; font-family: 宋体">方法，</span><span style="color: black; font-family: 宋体">调用后一个接口</span><span style="color: black; font-family: 'Tahoma','sans-serif'">destroy()</span><span style="color: black; font-family: 宋体">方法，从而使得</span><span style="color: black; font-family: 'Tahoma','sans-serif'">bean</span><span style="color: black; font-family: 宋体">可以在初始化和析构后做一些特定的动作。</span></p>
<p><span style="color: black; font-family: 宋体">在内部，</span><span style="color: black; font-family: 'Tahoma','sans-serif'">Spring</span><span style="color: black; font-family: 宋体">使用</span><span style="color: black; font-family: 'Tahoma','sans-serif'">BeanPostProcessors </span><span style="color: black; font-family: 宋体">来处理它能找到的标志接口以及调用适当的方法。</span><span style="color: black; font-family: 宋体">如果你需要自定义的特性或者其他的</span><span style="color: black; font-family: 'Tahoma','sans-serif'">Spring</span><span style="color: black; font-family: 宋体">没有提供的生命周期行为，</span><span style="color: black; font-family: 宋体">你可以实现自己的</span><span style="color: black; font-family: 'Tahoma','sans-serif'"> BeanPostProcessor</span><span style="color: black; font-family: 宋体">。关于这方面更多的内容可以看这里：</span><span style="color: black; font-family: 宋体">第</span><span style="color: black; font-family: 'Tahoma','sans-serif'"> 3.7 </span><span style="color: black; font-family: 宋体">节</span><span style="color: black; font-family: 宋体">&#8220;使用</span><span style="color: black; font-family: 'Tahoma','sans-serif'">BeanPostprocessors</span><span style="color: black; font-family: 宋体">定制</span><span style="color: black; font-family: 'Tahoma','sans-serif'">bean</span><span style="color: black; font-family: 宋体">&#8221;。</span></p>
<p><span style="color: black; font-family: 宋体">所有的生命周期的标志接口都在下面叙述。在附录的一节中，你可以找到相应的图，</span><span style="color: black; font-family: 宋体">展示了</span><span style="color: black; font-family: 'Tahoma','sans-serif'">Spring</span><span style="color: black; font-family: 宋体">如何管理</span><span style="color: black; font-family: 'Tahoma','sans-serif'">bean</span><span style="color: black; font-family: 宋体">；那些生命周期的特性如何改变你的</span><span style="color: black; font-family: 'Tahoma','sans-serif'">bean</span><span style="color: black; font-family: 宋体">的本质特征以及它们如何被管理。</span></p>
<p><span style="color: black; font-family: 'Tahoma','sans-serif'">1. InitializingBean / init-method</span></p>
<p><span style="color: black; font-family: 宋体">实现</span><span style="color: black; font-family: 'Tahoma','sans-serif'">org.springframework.beans.factory.InitializingBean </span><span style="color: black; font-family: 宋体">接口允许一个</span><span style="color: black; font-family: 'Tahoma','sans-serif'">bean</span><span style="color: black; font-family: 宋体">在它的所有必须的属性被</span><span style="color: black; font-family: 'Tahoma','sans-serif'">BeanFactory</span><span style="color: black; font-family: 宋体">设置后，</span><span style="color: black; font-family: 宋体">来执行初始化的工作。</span><span style="color: black; font-family: 'Tahoma','sans-serif'">InitializingBean</span><span style="color: black; font-family: 宋体">接口仅仅制定了一个方法：</span></p>
<p><span style="color: black; font-family: 'Tahoma','sans-serif'">&nbsp;&nbsp;&nbsp; * Invoked by a BeanFactory after it has set all bean properties supplied&nbsp;&nbsp;&nbsp; * (and satisfied BeanFactoryAware and ApplicationContextAware).&nbsp;&nbsp;&nbsp; * &lt;p&gt;This method allows the bean instance to perform initialization only&nbsp;&nbsp;&nbsp; * possible when all bean properties have been set and to throw an&nbsp;&nbsp;&nbsp; * exception in the event of misconfiguration.&nbsp;&nbsp;&nbsp; * @throws Exception in the event of misconfiguration (such&nbsp;&nbsp;&nbsp; * as failure to set an essential property) or if initialization fails.&nbsp;&nbsp;&nbsp; */&nbsp;&nbsp;&nbsp; void afterPropertiesSet() throws Exception;</span></p>
<p><span style="color: black; font-family: 宋体">注意：通常</span><span style="color: black; font-family: 'Tahoma','sans-serif'">InitializingBean</span><span style="color: black; font-family: 宋体">接口的使用是能够避免的（而且不鼓励，因为没有必要把代码同</span><span style="color: black; font-family: 'Tahoma','sans-serif'">Spring</span><span style="color: black; font-family: 宋体">耦合起来）。</span><span style="color: black; font-family: 'Tahoma','sans-serif'">Bean</span><span style="color: black; font-family: 宋体">的定义支持指定一个普通的初始化方法。在使用</span><span style="color: black; font-family: 'Tahoma','sans-serif'">XmlBeanFactory</span><span style="color: black; font-family: 宋体">的情况下，可以通过指定</span><span style="color: black; font-family: 'Tahoma','sans-serif'">init-method</span><span style="color: black; font-family: 宋体">属性来完成。</span><span style="color: black; font-family: 宋体">举例来说，下面的定义：</span></p>
<p><span style="color: black; font-family: 'Tahoma','sans-serif'">&lt;bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/&gt;public class ExampleBean {&nbsp;&nbsp;&nbsp; public void init() {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // do some initialization work&nbsp;&nbsp;&nbsp; }}</span></p>
<p><span style="color: black; font-family: 宋体">同下面的完全一样：</span></p>
<p><span style="color: black; font-family: 'Tahoma','sans-serif'">&lt;bean id="exampleInitBean" class="examples.AnotherExampleBean"/&gt;public class AnotherExampleBean implements InitializingBean {&nbsp;&nbsp;&nbsp; public void afterPropertiesSet() {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // do some initialization work&nbsp;&nbsp;&nbsp; }}</span></p>
<p><span style="color: black; font-family: 宋体">但却不把代码耦合于</span><span style="color: black; font-family: 'Tahoma','sans-serif'">Spring</span><span style="color: black; font-family: 宋体">。</span></p>
<p><span style="color: black; font-family: 'Tahoma','sans-serif'">2. DisposableBean / destroy-method</span></p>
<p><span style="color: black; font-family: 宋体">实现</span><span style="color: black; font-family: 'Tahoma','sans-serif'">org.springframework.beans.factory.DisposableBean</span><span style="color: black; font-family: 宋体">接口允许一个</span><span style="color: black; font-family: 'Tahoma','sans-serif'">bean</span><span style="color: black; font-family: 宋体">，</span><span style="color: black; font-family: 宋体">可以在包含它的</span><span style="color: black; font-family: 'Tahoma','sans-serif'">BeanFactory</span><span style="color: black; font-family: 宋体">销毁的时候得到一个回调。</span><span style="color: black; font-family: 'Tahoma','sans-serif'">DisposableBean</span><span style="color: black; font-family: 宋体">也只指定了一个方法：</span></p>
<p><span style="color: black; font-family: 'Tahoma','sans-serif'">&nbsp;&nbsp;&nbsp; /**&nbsp;&nbsp;&nbsp; * Invoked by a BeanFactory on destruction of a singleton.&nbsp;&nbsp;&nbsp; * @throws Exception in case of shutdown errors.&nbsp;&nbsp;&nbsp; * Exceptions will get logged but not rethrown to allow&nbsp;&nbsp;&nbsp; * other beans to release their resources too.&nbsp;&nbsp;&nbsp; */&nbsp;&nbsp;&nbsp; void destroy() throws Exception;</span></p>
<p><span style="color: black; font-family: 宋体">注意：通常</span><span style="color: black; font-family: 'Tahoma','sans-serif'">DisposableBean</span><span style="color: black; font-family: 宋体">接口的使用能够避免的（而且是不鼓励的，因为它不必要地将代码耦合于</span><span style="color: black; font-family: 'Tahoma','sans-serif'">Spring</span><span style="color: black; font-family: 宋体">）。</span><span style="color: black; font-family: 'Tahoma','sans-serif'"> Bean</span><span style="color: black; font-family: 宋体">的定义支持指定一个普通的析构方法。在使用</span><span style="color: black; font-family: 'Tahoma','sans-serif'">XmlBeanFactory</span><span style="color: black; font-family: 宋体">使用的情况下，它是通过</span><span style="color: black; font-family: 'Tahoma','sans-serif'"> destroy-method</span><span style="color: black; font-family: 宋体">属性完成。</span><span style="color: black; font-family: 宋体">举例来说，下面的定义：</span></p>
<p><span style="color: black; font-family: 'Tahoma','sans-serif'">&lt;bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="destroy"/&gt;public class ExampleBean {&nbsp;&nbsp;&nbsp; public void cleanup() {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // do some destruction work (like closing connection)&nbsp;&nbsp;&nbsp; }}</span></p>
<p><span style="color: black; font-family: 宋体">同下面的完全一样：</span></p>
<p><span style="color: black; font-family: 'Tahoma','sans-serif'">&lt;bean id="exampleInitBean" class="examples.AnotherExampleBean"/&gt;public class AnotherExampleBean implements DisposableBean {&nbsp;&nbsp;&nbsp; public void destroy() {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // do some destruction work&nbsp;&nbsp;&nbsp; }}</span></p>
<p><span style="color: black; font-family: 宋体">但却不把代码耦合于</span><span style="color: black; font-family: 'Tahoma','sans-serif'">Spring</span><span style="color: black; font-family: 宋体">。</span></p>
<p><span style="color: black; font-family: 宋体">重要的提示：当以</span><span style="color: black; font-family: 'Tahoma','sans-serif'">portotype</span><span style="color: black; font-family: 宋体">模式部署一个</span><span style="color: black; font-family: 'Tahoma','sans-serif'">bean</span><span style="color: black; font-family: 宋体">的时候，</span><span style="color: black; font-family: 'Tahoma','sans-serif'">bean</span><span style="color: black; font-family: 宋体">的生命周期将会有少许的变化。</span><span style="color: black; font-family: 宋体">通过定义，</span><span style="color: black; font-family: 'Tahoma','sans-serif'">Spring</span><span style="color: black; font-family: 宋体">无法管理一个</span><span style="color: black; font-family: 'Tahoma','sans-serif'">non-singleton/prototype bean</span><span style="color: black; font-family: 宋体">的整个生命周期，</span><span style="color: black; font-family: 宋体">因为当它创建之后，它被交给客户端而且容器根本不再留意它了。</span><span style="color: black; font-family: 宋体">当说起</span><span style="color: black; font-family: 'Tahoma','sans-serif'">non-singleton/prototype bean</span><span style="color: black; font-family: 宋体">的时候，你可以把</span><span style="color: black; font-family: 'Tahoma','sans-serif'">Spring</span><span style="color: black; font-family: 宋体">的角色想象成&#8220;</span><span style="color: black; font-family: 'Tahoma','sans-serif'">new</span><span style="color: black; font-family: 宋体">&#8221;操作符的替代品。</span><span style="color: black; font-family: 宋体">从那之后的任何生命周期方面的事情都由客户端来处理。</span><span style="color: black; font-family: 'Tahoma','sans-serif'">BeanFactory</span><span style="color: black; font-family: 宋体">中</span><span style="color: black; font-family: 'Tahoma','sans-serif'">bean</span><span style="color: black; font-family: 宋体">的生命周期将会在第</span><span style="color: black; font-family: 'Tahoma','sans-serif'"> 3.4.1 </span><span style="color: black; font-family: 宋体">节</span><span style="color: black; font-family: 宋体">&#8220;生命周期接口&#8221;</span><span style="color: black; font-family: 宋体">一节中有更详细的叙述</span><span style="color: black; font-family: 'Tahoma','sans-serif'"> .</span></p><img src ="http://www.blogjava.net/rain1102/aggbug/259764.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2009-03-14 22:22 <a href="http://www.blogjava.net/rain1102/archive/2009/03/14/259764.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate 与 Spring 多数据源的配置【转载】</title><link>http://www.blogjava.net/rain1102/archive/2009/03/09/258670.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Mon, 09 Mar 2009 13:06:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2009/03/09/258670.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/258670.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2009/03/09/258670.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/258670.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/258670.html</trackback:ping><description><![CDATA[<p>Spring2.0.1以后的版本已经支持配置多数据源，并且可以在运行的时候动态加载不同的数据源。通过继承AbstractRoutingDataSource就可以实现多数据源的动态转换。目前做的项目就是需要访问12个数据源，每个数据源的表结构都是相同的，所以要求数据源的变动对于编码人员来说是透明，也就是说同样SQL语句在不同的环境下操作的数据库是不一样的。具体的配置如下： <br />
一、首先需要写一个静态的键值对照类：</p>
<p>
<div>代码</div>
<div>
<div>
<div></div>
<ol>
    <li><span><span>package</span><span>&nbsp;cn.com.xinli.ccp.dynamicds; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>public</span><span>&nbsp;</span><span>class</span><span>&nbsp;DataSourceMap&nbsp;{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>public</span><span>&nbsp;</span><span>static</span><span>&nbsp;</span><span>final</span><span>&nbsp;String&nbsp;Admin=</span><span>"Admin"</span><span>; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>public</span><span>&nbsp;</span><span>static</span><span>&nbsp;</span><span>final</span><span>&nbsp;String&nbsp;Yxh&nbsp;=&nbsp;</span><span>"Yxh"</span><span>; &nbsp;&nbsp;</span>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>这个类主要在使用的时候当作获得数据源的标志使用。 <br />
二、建立一个获得和设置上下文的类： <br />
<div>代码</div>
<div>
<div>
<div></div>
<ol>
    <li><span><span>package</span><span>&nbsp;cn.com.xinli.ccp.dynamicds; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>public</span><span>&nbsp;</span><span>class</span><span>&nbsp;CustomerContextHolder&nbsp;{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>private</span><span>&nbsp;</span><span>static</span><span>&nbsp;</span><span>final</span><span>&nbsp;ThreadLocal&nbsp;contextHolder&nbsp;=&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>new</span><span>&nbsp;ThreadLocal(); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>public</span><span>&nbsp;</span><span>static</span><span>&nbsp;</span><span>void</span><span>&nbsp;setCustomerType(String&nbsp;customerType)&nbsp;{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contextHolder.set(customerType); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>public</span><span>&nbsp;</span><span>static</span><span>&nbsp;String&nbsp;getCustomerType()&nbsp;{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>return</span><span>&nbsp;(String)&nbsp;contextHolder.get(); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>public</span><span>&nbsp;</span><span>static</span><span>&nbsp;</span><span>void</span><span>&nbsp;clearCustomerType()&nbsp;{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contextHolder.remove(); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
</div>
<br />
这个主要负责设置上下文环境和获得上下文环境。 <br />
三、建立动态数据源类，这个类必须继承AbstractRoutingDataSource： <br />
<div>代码</div>
<div>
<div>
<div></div>
<ol>
    <li><span><span>package</span><span>&nbsp;cn.com.xinli.ccp.dynamicds; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>import</span><span>&nbsp;org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>public</span><span>&nbsp;</span><span>class</span><span>&nbsp;DynamicDataSource&nbsp;</span><span>extends</span><span>&nbsp;AbstractRoutingDataSource&nbsp;{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>protected</span><span>&nbsp;Object&nbsp;determineCurrentLookupKey()&nbsp;{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>//&nbsp;TODO&nbsp;Auto-generated&nbsp;method&nbsp;stub </span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>return</span><span>&nbsp;CustomerContextHolder.getCustomerType(); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
</div>
<br />
这个类实现了determineCurrentLookupKey方法，该方法返回一个Object，一般是返回字符串，也可以是枚举类型。该方法中直接使用了CustomerContextHolder.getCustomerType()方法获得上下文环境并直接返回。 <br />
四、编写spring的配置文件配置数据源 <br />
<div>代码</div>
<div>
<div>
<div></div>
<ol>
    <li><span><span>&lt;</span><span>bean</span><span>&nbsp;</span><span>id</span><span>=</span><span>"parentDataSource"</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>class</span><span>=</span><span>"org.springframework.jdbc.datasource.DriverManagerDataSource"</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>property</span><span>&nbsp;</span><span>name</span><span>=</span><span>"driverClassName"</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>value</span><span>&gt;</span><span>COM.ibm.db2.jdbc.net.DB2Driver</span><span>&lt;/</span><span>value</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>property</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>property</span><span>&nbsp;</span><span>name</span><span>=</span><span>"url"</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>value</span><span>&gt;</span><span>jdbc:db2:127.0.0.1:TEST</span><span>&lt;/</span><span>value</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>property</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>bean</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>bean</span><span>&nbsp;</span><span>id</span><span>=</span><span>"adminDataSource"</span><span>&nbsp;</span><span>parent</span><span>=</span><span>"parentDataSource"</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>property</span><span>&nbsp;</span><span>name</span><span>=</span><span>"username"</span><span>&nbsp;</span><span>value</span><span>=</span><span>"admin"</span><span>/&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>property</span><span>&nbsp;</span><span>name</span><span>=</span><span>"password"</span><span>&nbsp;</span><span>value</span><span>=</span><span>"master997mb"</span><span>/&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>bean</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>bean</span><span>&nbsp;</span><span>id</span><span>=</span><span>"yxhDataSource"</span><span>&nbsp;</span><span>parent</span><span>=</span><span>"parentDataSource"</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>property</span><span>&nbsp;</span><span>name</span><span>=</span><span>"username"</span><span>&nbsp;</span><span>value</span><span>=</span><span>"yxh"</span><span>/&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>property</span><span>&nbsp;</span><span>name</span><span>=</span><span>"password"</span><span>&nbsp;</span><span>value</span><span>=</span><span>"yxh"</span><span>/&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>bean</span><span>&gt;</span><span>&nbsp;&nbsp;</span></li>
</ol>
</div>
</div>
<br />
在这个配置中可以看到首先有个parentDataSource，这个主要配置一些数据源的公用信息，项目中都是链接DB2数据库；adminDataSource和yxhDataSource是根据不同需要配置的个性化信息，但都必须加parent属性，值为parentDataSource。这样就配置好了2个数据源信息。当然如果链接的多数据源是不同类型的两个数据库，那么parentDataSource就可以不要了，直接配置两个不同的数据源链接就可以了。 <br />
五、编写spring配置文件配置多数据源映射关系 <br />
<div>代码</div>
<div>
<div>
<div></div>
<ol>
    <li><span><span>&lt;</span><span>bean</span><span>&nbsp;</span><span>id</span><span>=</span><span>"dataSource"</span><span>&nbsp;</span><span>class</span><span>=</span><span>"cn.com.xinli.ccp.dynamicds.DynamicDataSource"</span><span>&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>property</span><span>&nbsp;</span><span>name</span><span>=</span><span>"targetDataSources"</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>map</span><span>&nbsp;</span><span>key-type</span><span>=</span><span>"<a title="Java爱好者" href="http://www.blogjava.net/rain1102" >Java</a>.lang.String"</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>entry</span><span>&nbsp;</span><span>key</span><span>=</span><span>"Yxh"</span><span>&nbsp;</span><span>value-ref</span><span>=</span><span>"yxhDataSource"</span><span>/&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>map</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>property</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>property</span><span>&nbsp;</span><span>name</span><span>=</span><span>"defaultTargetDataSource"</span><span>&nbsp;</span><span>ref</span><span>=</span><span>"adminDataSource"</span><span>/&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>bean</span><span>&gt;</span><span>&nbsp;&nbsp;</span></li>
</ol>
</div>
</div>
<br />
在这个配置中第一个property属性配置目标数据源，&lt;map key-type="<a title="Java爱好者" href="http://www.blogjava.net/rain1102" >Java</a>.lang.String"&gt;中的key-type必须要和静态键值对照类DataSourceMap中的值的类型相同；&lt;entry key="Yxh" value-ref="yxhDataSource"/&gt;中key的值必须要和静态键值对照类中的值相同，如果有多个值，可以配置多个&lt;entry&gt;标签。第二个property属性配置默认的数据源。 <br />
六、配置hibernate。 <br />
Hibernate的配置和普通的hibernate、spring结合的配置一样 <br />
<div>代码</div>
<div>
<div>
<div></div>
<ol>
    <li><span><span>&lt;</span><span>bean</span><span>&nbsp;</span><span>id</span><span>=</span><span>"sessionFactory"</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>class</span><span>=</span><span>"org.springframework.orm.hibernate3.LocalSessionFactoryBean"</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;!--&nbsp;to&nbsp;override,&nbsp;use&nbsp;the&nbsp;"SpringDatasourceConfig"&nbsp;snippet&nbsp;in&nbsp;your&nbsp;project&nbsp;--&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>property</span><span>&nbsp;</span><span>name</span><span>=</span><span>"dataSource"</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>ref</span><span>&nbsp;</span><span>local</span><span>=</span><span>"dataSource"</span><span>&nbsp;</span><span>/&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>property</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>property</span><span>&nbsp;</span><span>name</span><span>=</span><span>"mappingResources"</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>list</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>value</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cn/com/xinli/ccp/entity/User.hbm.xml &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>value</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>value</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cn/com/xinli/ccp/entity/Test.hbm.xml &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>value</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>list</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>property</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>property</span><span>&nbsp;</span><span>name</span><span>=</span><span>"hibernateProperties"</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>props</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>prop</span><span>&nbsp;</span><span>key</span><span>=</span><span>"hibernate.dialect"</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.hibernate.dialect.DB2Dialect &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>prop</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>prop</span><span>&nbsp;</span><span>key</span><span>=</span><span>"hibernate.show_sql"</span><span>&gt;</span><span>true</span><span>&lt;/</span><span>prop</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>prop</span><span>&nbsp;</span><span>key</span><span>=</span><span>"hibernate.use_outer_join"</span><span>&gt;</span><span>true</span><span>&lt;/</span><span>prop</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>prop</span><span>&nbsp;</span><span>key</span><span>=</span><span>"hibernate.jdbc.batch_size"</span><span>&gt;</span><span>50</span><span>&lt;/</span><span>prop</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>prop</span><span>&nbsp;</span><span>key</span><span>=</span><span>"hibernate.jdbc.fetch_size"</span><span>&gt;</span><span>5</span><span>&lt;/</span><span>prop</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>prop</span><span>&nbsp;</span><span>key</span><span>=</span><span>"hibernate.connection.pool_size"</span><span>&gt;</span><span>2</span><span>&lt;/</span><span>prop</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>prop</span><span>&nbsp;</span><span>key</span><span>=</span><span>"hibernate.connection.autocommit"</span><span>&gt;</span><span>false</span><span>&lt;/</span><span>prop</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>prop</span><span>&nbsp;</span><span>key</span><span>=</span><span>"hibernate.cache.use_query_cache"</span><span>&gt;</span><span>false</span><span>&lt;/</span><span>prop</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>prop</span><span>&nbsp;</span><span>key</span><span>=</span><span>"hibernate.max_fetch_depth"</span><span>&gt;</span><span>1</span><span>&lt;/</span><span>prop</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>prop</span><span>&nbsp;</span><span>key</span><span>=</span><span>"hibernate.bytecode.use_reflection_optimizer"</span><span>&gt;</span><span>true</span><span>&lt;/</span><span>prop</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>props</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>property</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>bean</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>&lt;</span><span>bean</span><span>&nbsp;</span><span>id</span><span>=</span><span>"mydao"</span><span>&nbsp;</span><span>class</span><span>=</span><span>"cn.com.xinli.ccp.dao.HibernateBaseDao"</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>property</span><span>&nbsp;</span><span>name</span><span>=</span><span>"sessionFactory"</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;</span><span>ref</span><span>&nbsp;</span><span>local</span><span>=</span><span>"sessionFactory"</span><span>&nbsp;</span><span>/&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>property</span><span>&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&lt;/</span><span>bean</span><span>&gt;</span><span>&nbsp;&nbsp;</span></li>
</ol>
</div>
</div>
<br />
关于dao的代码这里就省略了。 <br />
七、配置结束，可以使用了。 <br />
<div>代码</div>
<div>
<div>
<div></div>
<ol>
    <li><span><span>public</span><span>&nbsp;</span><span>class</span><span>&nbsp;DaoTest&nbsp;</span><span>extends</span><span>&nbsp;TestCase&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>public</span><span>&nbsp;</span><span>void</span><span>&nbsp;testSave()&nbsp;</span><span>throws</span><span>&nbsp;Exception{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CustomerContextHolder.setCustomerType(DataSourceMap.Admin);</span><span>//设置数据源 </span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>//hibernate创建实体 </span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Test&nbsp;test&nbsp;=&nbsp;</span><span>new</span><span>&nbsp;Test(); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;test.setTest(</span><span>"22222222"</span><span>); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mydao.save(test);</span><span>//使用dao保存实体 </span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CustomerContextHolder.setCustomerType(DataSourceMap.Yxh);</span><span>//设置为另一个数据源 </span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mydao.save(test);</span><span>//使用dao保存实体到另一个库中 </span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
</div>
在项目中对于编码人员对多数据源的切换可以做成透明的，操作同样的dao，就可以访问不同的数据库了。<img src ="http://www.blogjava.net/rain1102/aggbug/258670.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2009-03-09 21:06 <a href="http://www.blogjava.net/rain1102/archive/2009/03/09/258670.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring MVC I18N配置</title><link>http://www.blogjava.net/rain1102/archive/2009/03/07/258389.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Sat, 07 Mar 2009 11:11:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2009/03/07/258389.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/258389.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2009/03/07/258389.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/258389.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/258389.html</trackback:ping><description><![CDATA[1. 首先需要配置资源文件，这个做j2ee开发应该都比较清楚。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;!-- i18n configure --&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean id="messageSource"&nbsp; class="org.springframework.context.support.ResourceBundleMessageSource"&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="basename" value="com.founder.cst.i18n.messageResource"/&gt;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt;<br />
<br />
2. 配置Resolver，这里有三种，基于Request，基于Session，以及基于Cookie，但一般我们会用基于Session的。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;基于Request的class为：org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver<br />
&nbsp;&nbsp;&nbsp;&nbsp;基于Session的class为：org.springframework.web.servlet.i18n.CookieLocaleResolver<br />
<br />
3. 配置拦截器<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" /&gt;<br />
<br />
4. 设置拦截器<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"&gt;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="interceptors" ref="localeChangeInterceptor"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;如果使用BeanNameUrlHandlerMapping则为<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean id="defaultUrlMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="interceptors" ref="localeChangeInterceptor" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt;<br />
<br />
最后注意请求参数为locale，例如locale=zh_CN<br />
在controller里面获取资源文件的时候, 注意使用RequestContextUtils.getLocale(request)替代request.getLocale()获取locale信息.<br /><img src ="http://www.blogjava.net/rain1102/aggbug/258389.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2009-03-07 19:11 <a href="http://www.blogjava.net/rain1102/archive/2009/03/07/258389.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring 2.5.6新特性之packagesToScan</title><link>http://www.blogjava.net/rain1102/archive/2009/02/09/253927.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Mon, 09 Feb 2009 09:14:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2009/02/09/253927.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/253927.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2009/02/09/253927.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/253927.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/253927.html</trackback:ping><description><![CDATA[如果你使用早前版本的Spring，又恰好采用了Annotation注解方式(而非传统XML方式)配置Hibernate对象关系映射，那么在通过org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean配置sessionFactory时，你一定对annotatedClasses、annotatedPackages有一种说不出的胸闷的感觉，如此以高配置性见长的Spring，怎么在这一个小小的环节上就不能做得再灵活些呢，一定要一个个手写Class路径么？<br />
<br />
估计有不少人无奈选择了从AnnotationSessionFactoryBean继承一个自定义的子类，自己实现扫描逻辑，找出@Entity注解过的类清单配置进去。<br />
<br />
Spring 2.5.6里有个不怎么起眼的改进，那就是在AnnotationSessionFactoryBean上增加了一个新的方法：<br />
<a title="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/orm/hibernate3/annotation/AnnotationSessionFactoryBean.html#setPackagesToScan(java.lang.String[])" href="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/orm/hibernate3/annotation/AnnotationSessionFactoryBean.html#setPackagesToScan%28java.lang.String%5B%5D%29" target="_blank">setPackagesToScan(String[] packagesToScan)</a><br />
<br />
有了这个方法，我们不再需要自己动手去实现实体类的扫描了，直接在Spring配置文件中AnnotationSessionFactoryBean这个section上增加类似如下的一个property即可(假定你需要加载的实体类所在的包名match这个字符串"com.**.bo")：<br />
<div style="border-right: rgb(204,204,204) 1px solid; padding-right: 5px; border-top: rgb(204,204,204) 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: rgb(204,204,204) 1px solid; width: 98%; padding-top: 4px; border-bottom: rgb(204,204,204) 1px solid; background-color: rgb(238,238,238)"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: rgb(0,0,255)">&lt;</span><span style="color: rgb(128,0,0)">property&nbsp;</span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">="packagesToScan"</span><span style="color: rgb(255,0,0)">&nbsp;value</span><span style="color: rgb(0,0,255)">="com.**.bo"</span><span style="color: rgb(0,0,255)">/&gt;</span></div>
<br />
你也可以以清单的方式指定多于1条的匹配字串，如：<br />
<div style="border-right: rgb(204,204,204) 1px solid; padding-right: 5px; border-top: rgb(204,204,204) 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: rgb(204,204,204) 1px solid; width: 98%; padding-top: 4px; border-bottom: rgb(204,204,204) 1px solid; background-color: rgb(238,238,238)"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: rgb(0,0,255)">&lt;</span><span style="color: rgb(128,0,0)">property&nbsp;</span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">="packagesToScan"</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">&lt;</span><span style="color: rgb(128,0,0)">list</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">&lt;</span><span style="color: rgb(128,0,0)">value</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)">com.abc.core.bo</span><span style="color: rgb(0,0,255)">&lt;/</span><span style="color: rgb(128,0,0)">value</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">&lt;</span><span style="color: rgb(128,0,0)">value</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)">com.abc.auditing.bo</span><span style="color: rgb(0,0,255)">&lt;/</span><span style="color: rgb(128,0,0)">value</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">&lt;/</span><span style="color: rgb(128,0,0)">list</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)"><br />
</span><span style="color: rgb(0,0,255)">&lt;/</span><span style="color: rgb(128,0,0)">property</span><span style="color: rgb(0,0,255)">&gt;</span></div><img src ="http://www.blogjava.net/rain1102/aggbug/253927.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2009-02-09 17:14 <a href="http://www.blogjava.net/rain1102/archive/2009/02/09/253927.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Bind And Validate</title><link>http://www.blogjava.net/rain1102/archive/2009/01/09/250752.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Fri, 09 Jan 2009 15:05:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2009/01/09/250752.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/250752.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2009/01/09/250752.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/250752.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/250752.html</trackback:ping><description><![CDATA[<p>在Spring MVC体系里，已经提供了bind(request,command)函数进行Bind and Validate工作。 <br />
&nbsp; 但因为默认的bind()函数是抛出Servlet异常，而不是返回以数组形式保存错误信息的BindingResult对象供Controller处理 所以BaseController另外实现了一个bindObject函数：</p>
<p>BindException&nbsp; bindObject(ServletRequest request, Object command)<br />
1.Bind And Validate的完整使用代码：<br />
&nbsp;&nbsp;&nbsp;&nbsp; public BindingResult bindBook(HttpServletRequest request, Book book) throws Exception<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;Integer category_id = new Integer(request.getParameter("category.id"));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; book.setCategory(bookManager.getCategory(category_id));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; binder.setDisallowedFields(new String[]{"category"}); <br />
addValidator(new BookValiator());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return bindObject(request, book);<br />
}<br />
&nbsp; 其中第1-3句是绑定不能自动绑定的Category对象，（另外一个方案是实现Category的PropertityEditor,并注册，不过这太不实际了）并命令binder忽略这些已被手工绑定的field.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注意,如果不忽略,binder绑定时则很有可能出错。</p>
<p>&nbsp; 第4句增加validator。</p>
<p>&nbsp; 第5句执行Bind and Validate。</p>
<p>不过，我们一般会重载preBind()函数来完成1-3句的操作。逐一<br />
&nbsp;&nbsp;&nbsp;&nbsp; 而且springmodules+ common-validator已经提供了默认的几种Validator和在XML节点配置默认注入的框架，只有自己写了特别的validator，并且不希望使用common-validator框架来定义时才像第四步那样使用BaseController的addValidator函数加入新的validator。</p>
<p>2.Binder<br />
&nbsp;&nbsp;&nbsp;&nbsp; 一般由ServletRequestDataBinder完成Bind的工作。与其他框架自动绑定FormBean不同，Spring里需要手工调用Binder.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 但因为日期格式不固定, Binder并没有预先包含Date的Propertity Editor。 另外数字类的Editor默认不允许字符串为空，这些都需要初始化设置。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 在Multi-action体系中,有initBinder()的callBack函数：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SimpleDateFormat dateFormat = new SimpleDateFormat(DateUtil.getDatePattern());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; binder.registerCustomEditor(Integer.class, new CustomNumberEditor(Integer.class, true));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; binder.registerCustomEditor(Double.class, new CustomNumberEditor(Double.class, true));<br />
&nbsp;&nbsp; createBinder的另一个callBack函数是getCommandName()，getCommandName将用于在页面用&lt;spring:bind&gt;绑定错误信息时的标识，baseController默认定为首字母小写的类名。</p>
<p>&nbsp;</p>
<p>3.Validator<br />
&nbsp;&nbsp;&nbsp;&nbsp; Validator的客户端和服务器端方案用common validator和spring moudles里的集成 。</p>
<p>&nbsp;</p>
<p>4.Bind and Validate出错处理<br />
&nbsp;&nbsp;&nbsp; Bind and Validate出错，一般会重新跳回输入页面，在页头以如下代码显示错误信息，并重新绑定所有数据：</p>
<p>&lt;%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %&gt;</p>
<p><br />
&lt;c:iftest="${book!=null}"&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;spring:bind path="book.*"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;c:if test="${not empty status.errorMessages}"&gt;&lt;&nbsp; BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;div class="error"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;c:forEach var="error" items="${status.errorMessages}"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${error}&lt;br/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/c:forEach&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/div&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/c:if&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/spring:bind&gt;<br />
&lt;/c:if&gt;</p>
<p>&nbsp;</p><img src ="http://www.blogjava.net/rain1102/aggbug/250752.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2009-01-09 23:05 <a href="http://www.blogjava.net/rain1102/archive/2009/01/09/250752.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring中使用Springmodules的Commons Validator做验证</title><link>http://www.blogjava.net/rain1102/archive/2009/01/08/250551.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Thu, 08 Jan 2009 14:54:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2009/01/08/250551.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/250551.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2009/01/08/250551.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/250551.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/250551.html</trackback:ping><description><![CDATA[<p>使用Springmodules的Commons Validator做验证需要两个bean（<span style="font-size: 10pt; color: rgb(42,0,255)">ValidatorFactory</span><span style="font-size: 10pt; color: rgb(42,0,255)">、</span><span style="font-size: 10pt; color: rgb(42,0,255)">BeanValidator</span>）及两xml文件（<span style="font-size: 10pt; color: rgb(42,0,255)">validator-rules.xml</span><span style="font-size: 10pt; color: black">、</span><span style="font-size: 10pt; color: rgb(42,0,255)">validation.xml</span>）的支持，<span>ValidatorFactory</span>用于制造<span>BeanValidator</span>，后者则是在程序中执行校验的控制bean。v<span>alidator-rules.xml</span>中定义了各种验证的规则，如字段不为空，字段输入<span>值必须为整数等等，在这里可以自己扩展验证规则。而v</span><span>alidation.xml</span>中则定义了那些bean及bean中的哪些属性字段需要验证，使用哪些验证规则。validate 分为两级验证，客户端验证（<span>javascript</span>）和服务器端验证。以下是使用validate的步骤：</p>
<span>1.<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>在配置&lt;action&gt;-servlet.xml文件中声明<span>ValidatorFactory</span> 和 <span>BeanValidator</span>：<br />
&lt;!-- validation --&gt;<br />
&nbsp;&lt;bean id="validatorFactory" class="org.springmodules.validation.commons.DefaultValidatorFactory"&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;property name="validationConfigLocations"&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;list&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;WEB-INF/validator-rules.xml&lt;/value&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;WEB-INF/validation.xml&lt;/value&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/list&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;/property&gt; <br />
&nbsp;&lt;/bean&gt; <br />
&nbsp;<br />
&nbsp;&lt;bean id="beanValidator" class="org.springmodules.validation.commons.DefaultBeanValidator"&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="validatorFactory" ref="validatorFactory"/&gt; <br />
&nbsp;&lt;/bean&gt;<br />
①&nbsp;&nbsp;&nbsp;&nbsp; 声明validatoFactory 这里我们使用DefaultValidatorFactory<br />
②&nbsp;&nbsp;&nbsp;&nbsp; 定义其validationConfigLocations属性，将validator-rules.xml和validation.xml传入<br />
③&nbsp;&nbsp;&nbsp;&nbsp; 声明beanValidator 这里我们使用DefaultBeanValidator <br />
④&nbsp;&nbsp;&nbsp;&nbsp; 在其属性中指明要使用的validatorFactory 。这里我们使用刚刚定义的validatorFactory<br />
这里需要注意的是随着Springmodules版本的不同，DefaultValidatorFactory和DefaultBeanValidator的包路径有可能不同。<br />
<br />
<span>2.<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>在需要进行验证的controller（即要使用form表单或者command的controller）中声明validate。<br />
&lt;bean id="compoundMainController" class="com.founder.action.CompoundMainController"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;property name="formView"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;regcompound&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;property name="successView"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;regcompound&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;property name="<span style="color: #0000ff">commandClass</span>"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;com.founder.domain.ChemicalInfo&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;property name="<span style="color: #0000ff">commandName</span>"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;chemicalInfo&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;property name="compoundService"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;ref bean="compoundService"/&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;property name="validator" ref="beanValidator" /&gt; <br />
&nbsp;&lt;/bean&gt;<br />
①&nbsp;&nbsp;&nbsp;&nbsp; commandName 用于指明需要验证的 command的名字，这个名字必须和 validation.xml中&lt;form name=" xxxxx "&gt; 所写的名字保持一致。<br />
②&nbsp;&nbsp;&nbsp;&nbsp; commandClass用于指定这个command的类型。其必须与你jsp提交的form最后形成的command类型相一致。<br />
③&nbsp;&nbsp;&nbsp;&nbsp; 声明该controller使用validator，这里将我们刚刚定义的beanValidator传入进去。<br />
<br />
<span>3.<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>在<span style="font-size: 10pt; color: rgb(42,0,255)">validation.xml</span>文件中，定义你要校验的<span style="font-size: 10pt; color: rgb(42,0,255)">formbean</span>（或者说是<span style="font-size: 10pt; color: rgb(42,0,255)">command</span>） ，定义这个<span style="font-size: 10pt; color: rgb(42,0,255)">bean</span>中有哪几个<span style="font-size: 10pt; color: rgb(42,0,255)">field</span>需要验证，使用何种规则验证。（<span style="color: red">注意：这里定义的</span><span style="color: red">form name </span><span style="color: red">必须和前面</span><span style="color: red">controller</span><span style="color: red">中定义的</span><span style="color: red">commandName</span><span style="color: red">保持一致</span>）以下是几种常用的验证示例：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;form name="chemicalInfo"&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;field property="saltForm" depends="maxlength,required"&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;arg0 key="chemicalInfo.saltForm.displayName" /&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;arg1 name="maxlength" key="${var:maxlength}" resource="false" /&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;var&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;var-name&gt;maxlength&lt;/var-name&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;var-value&gt;30&lt;/var-value&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/var&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/field&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;field property="saltNumber" depends="required"&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;arg0 key="chemicalInfo.saltNumber.displayName" /&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/field&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/form&gt; <br />
而validator-rules.xml默认模板可以从下载的spring-modules-0.9.zip（当然你下的版本可能不同）里面的可以找到。<br />
<br />
<span style="font-size: 10pt; color: black">4. &nbsp;</span><span style="font-size: 10pt; color: black">在<span>jsp</span>页面中定义错误信息显示语句：</span><br />
&lt;spring:bindpath="chemicalInfo.*"&gt;&nbsp;&nbsp; -----①<br />
&nbsp;&nbsp;&nbsp; &lt;c:iftest="${not empty status.errorMessages}"&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;div class="error"&gt;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;c:forEachvar="error" items="${status.errorMessages}"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;c:outvalue="${error}"escapeXml="false"/&gt;&lt;br/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/c:forEach&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/div&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/c:if&gt;<br />
&lt;/spring:bind&gt;<br />
①&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里的path必须要与传入该 jsp的bean的名字一样。如传入该jsp的数据bean叫chemicalInfo，path就应该写为chemicalInfo.*。<br />
<br />
<span style="font-size: 10pt">5</span><span style="font-size: 10pt">．</span><span style="font-size: 10pt">使客户端产生</span><span style="font-size: 10pt">javascript</span><span style="font-size: 10pt">代码：<br />
&lt;v:javascriptformName="chemicalInfo"&nbsp;&nbsp;&nbsp; -----①<br />
staticJavascript="false" xhtml="true" cdata="false"/&gt;<br />
&lt;script type="text/javascript" src="&lt;c:urlvalue="scripts/validator.jsp"/&gt;"&gt;&lt;/script&gt;<br />
&nbsp;<br />
①&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; v:javascript标签是spring的标签，定义在spring-commons-validator.tld 。其中formName必须与validation.xml中form的name保持一致。</span><img src ="http://www.blogjava.net/rain1102/aggbug/250551.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2009-01-08 22:54 <a href="http://www.blogjava.net/rain1102/archive/2009/01/08/250551.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring MVC Annotation &amp; Convention Over Configuration</title><link>http://www.blogjava.net/rain1102/archive/2009/01/07/250410.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Wed, 07 Jan 2009 13:43:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2009/01/07/250410.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/250410.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2009/01/07/250410.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/250410.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/250410.html</trackback:ping><description><![CDATA[<p>Spring MVC在使用annotation进行配置controller时候要注意：两种urlmapping的模式不能同时使用，如果使用annotation就不能再配置urlmapping了。</p>
&lt;action&gt;-servlet.xml如下：<br />
<p><span style="color: #008000">&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />
&lt;beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />
&nbsp;&nbsp;xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"<br />
&nbsp;&nbsp;xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd<br />
&nbsp;&nbsp;&nbsp;&nbsp;http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"&gt;</span></p>
<p><span style="color: #008000">&nbsp;&lt;!--&nbsp;对com.founder.action包中的所有类进行扫描，以完成Bean创建和自动依赖注入的功能 --&gt;<br />
&nbsp;&lt;context:component-scan base-package="com.founder.action"/&gt;<br />
&nbsp;<br />
&lt;!--&nbsp;启动Spring MVC的注解功能，完成请求和注解POJO的映射 --&gt;<br />
&nbsp;&lt;bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/&gt;<br />
&nbsp;<br />
&lt;!--把请求的URL映射到Controller的name上面 --&gt;<br />
&nbsp;&lt;bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/&gt;&nbsp; <br />
&nbsp;&nbsp; <br />
&nbsp;&lt;!-- 对模型视图名称的解析，即在模型视图名称添加前后缀--&gt;<br />
&nbsp;&lt;bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt;<br />
&nbsp;&nbsp;&lt;property name="viewClass"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;value&gt;org.springframework.web.servlet.view.JstlView&lt;/value&gt;<br />
&nbsp;&nbsp;&lt;/property&gt;<br />
&nbsp;&nbsp;&lt;property name="prefix"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;/jsp/&lt;/value&gt; <br />
&nbsp;&nbsp;&lt;/property&gt;<br />
&nbsp;&nbsp;&lt;property name="suffix"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;value&gt;.jsp&lt;/value&gt;<br />
&nbsp;&nbsp;&lt;/property&gt;<br />
&nbsp;&lt;/bean&gt;<br />
<br />
&lt;/beans&gt;</span></p>
<br />
<p>package com.founder.action;</p>
<p>import org.springframework.stereotype.Controller;<br />
import org.springframework.web.bind.annotation.RequestMapping;<br />
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;<br />
</p>
<p><br />
@Controller<br />
@RequestMapping<br />
public class HelloController{<br />
&nbsp;@RequestMapping<br />
&nbsp;public String world(){<br />
&nbsp;&nbsp;String name = "Eric";<br />
&nbsp;&nbsp;System.out.println("name is = " + name);<br />
&nbsp;&nbsp;return "hello";<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;@RequestMapping<br />
&nbsp;public String test() {<br />
&nbsp;&nbsp;String name = "test";<br />
&nbsp;&nbsp;System.out.println("name is = " + name);<br />
&nbsp;&nbsp;return "test";<br />
&nbsp;}<br />
&nbsp;<br />
}<br />
</p><img src ="http://www.blogjava.net/rain1102/aggbug/250410.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2009-01-07 21:43 <a href="http://www.blogjava.net/rain1102/archive/2009/01/07/250410.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Yale CAS实现原理及其基础协议[转载]</title><link>http://www.blogjava.net/rain1102/archive/2008/09/08/227739.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Mon, 08 Sep 2008 06:56:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2008/09/08/227739.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/227739.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2008/09/08/227739.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/227739.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/227739.html</trackback:ping><description><![CDATA[CAS(Central Authentication Service) 是 Yale 大学发起的一个开源项目，据统计，大概每 10 个采用开源构建 Web SSO 的 <a title="Java爱好者" href="http://www.blogjava.net/rain1102" >Java</a> 项目，就有 8 个使用 CAS 。对这些统计，我虽然不以为然，但有一点可以肯定的是， CAS 是我认为最简单实效，而且足够安全的 SSO 选择。
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>本节主要分析 CAS 的安全性，以及为什么 CAS 被这样设计，带着少许密码学的基础知识，我希望有助于读者对 CAS 的协议有更深层次的理解。 </div>
<div></div>
<div>
<div style="text-indent: 21pt">从结构体系看， CAS 包含两部分： </div>
<div style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt"><font color="#0000ff"><span>l<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>CAS Server </font></div>
<div style="text-indent: 21pt">CAS Server 负责完成对用户的认证工作， CAS Server 需要独立部署，有不止一种 CAS Server 的实现， Yale CAS Server 和 ESUP CAS Server 都是很不错的选择。 </div>
<div style="text-indent: 21pt">CAS Server 会处理用户名 / 密码等凭证 (Credentials) ，它可能会到数据库检索一条用户帐号信息，也可能在 XML 文件中检索用户密码，对这种方式， CAS 均提供一种灵活但同一的接口 / 实现分离的方式， CAS 究竟是用何种认证方式，跟 CAS 协议是分离的，也就是，这个认证的实现细节可以自己定制和扩展。 </div>
<div style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt"><font color="#0000ff"><span>l<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>CAS Client </font></div>
<div style="text-indent: 21pt">CAS Client 负责部署在客户端（注意，我是指 Web 应用），原则上， CAS Client 的部署意味着，当有对本地 Web 应用的受保护资源的访问请求，并且需要对请求方进行身份认证， Web 应用不再接受任何的用户名密码等类似的 Credentials ，而是重定向到 CAS Server 进行认证。 </div>
<div style="text-indent: 21pt">目前， CAS Client 支持（某些在完善中）非常多的客户端，包括 <a title="Java爱好者" href="http://www.blogjava.net/rain1102" >Java</a> 、 .Net 、 ISAPI 、 Php 、 Perl 、 uPortal 、 Acegi 、 Ruby 、 VBScript 等客户端，几乎可以这样说， CAS 协议能够适合任何语言编写的客户端应用。 </div>
<div style="text-indent: 21pt"></div>
<div style="text-indent: 21pt">&nbsp;剖析协议就像剖析设计模式，有些时候，协议让人摸不着头脑。 CAS 的代理模式要相对复杂一些，它引入了一些新的概念，我希望能够在这里描述一下其原理，有助于读者在配置和调试 CAS SSO 有更清晰的思路。
<div style="text-indent: 21pt">如果没记错， CAS 协议应该是由 <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#100;&#114;&#101;&#119;&#46;&#109;&#97;&#122;&#117;&#114;&#101;&#107;&#64;&#121;&#97;&#108;&#101;&#46;&#101;&#100;&#117;">Drew Mazurek</a> 负责可开发的，从 CAS v1 到现在的 CAS v3 ，整个协议的基础思想都是基于 Kerberos 的票据方式。 </div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CAS v1</span> 非常原始，传送一个用户名居然是 &#8221;yes\ndavid.turing&#8221; 的方式， CAS v2 开始使用了 XML 规范，大大增强了可扩展性， CAS v3 开始使用 AOP 技术，让 Spring 爱好者可以轻松配置 CAS Server 到现有的应用环境中。 </div>
<div style="text-indent: 21pt">CAS 是通过 TGT(Ticket Granting Ticket) 来获取 ST(Service Ticket) ，通过 ST 来访问服务，而 CAS 也有对应 TGT ， ST 的实体，而且他们在保护 TGT 的方法上虽然有所区别，但是，最终都可以实现这样一个目的——免去多次登录的麻烦。 </div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>下面，我们看看 CAS 的基本协议框架： </div>
<div></div>
<div>基础协议
<div><span><img height="380" alt="cas_protocol-1.jpg" src="http://www.blogjava.net/images/blogjava_net/security/cas_protocol-1.jpg" width="528" border="0" /> <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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CAS</span> 基础模式 </div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>上图是一个最基础的 CAS 协议， CAS Client 以 Filter 方式保护 Web 应用的受保护资源，过滤从客户端过来的每一个 Web 请求，同时， CAS Client 会分析 HTTP 请求中是否包请求 Service Ticket( 上图中的 Ticket) ，如果没有，则说明该用户是没有经过认证的，于是， CAS Client 会重定向用户请求到 CAS Server （ Step 2 ）。 Step 3 是用户认证过程，如果用户提供了正确的 Credentials ， CAS Server 会产生一个随机的 Service Ticket ，然后，缓存该 Ticket ，并且重定向用户到 CAS Client （附带刚才产生的 Service Ticket ）， Service Ticket 是不可以伪造的，最后， Step 5 和 Step6 是 CAS Client 和 CAS Server 之间完成了一个对用户的身份核实，用 Ticket 查到 Username ，因为 Ticket 是 CAS Server 产生的，因此，所以 CAS Server 的判断是毋庸置疑的。 </div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>该协议完成了一个很简单的任务，就是 User(david.turing) 打开 IE ，直接访问 helloservice 应用，它被立即重定向到 CAS Server 进行认证， User 可能感觉到浏览器在 helloservcie 和 casserver 之间重定向，但 User 是看不到， CAS Client 和 CAS Server 相互间的 Service Ticket 核实 (Validation) 过程。当 CAS Server 告知 CAS Client 用户 Service Ticket 对应确凿身份， CAS Client 才会对当前 Request 的用户进行服务。 </div>
<div></div>
<div>CAS 如何实现 SSO
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>当我们的 Web 时代还处于初级阶段的时候， SSO 是通过共享 cookies 来实现，比如，下面三个域名要做 SSO ： </div>
<div style="text-indent: 21pt"><a href="http://www.blogjava.net/">http://www.blogjava.net</a> </div>
<div style="text-indent: 21pt"><a href="http://www.matrix.org.cn/">http://www.matrix.org.cn</a> </div>
<div style="text-indent: 21pt"><a href="http://www.csdn.net/">http://www.csdn.net</a> </div>
<div style="text-indent: 21pt">如果通过 CAS 来集成这三个应用，那么，这三个域名都要做一些域名映射， </div>
<div style="text-indent: 21pt"><a href="http://blogjava.cas.org/">http://blogjava.cas.org</a> </div>
<div style="text-indent: 21pt"><a href="http://matrix.cas.org/">http://matrix.cas.org</a> </div>
<div style="text-indent: 21pt"><a href="http://csdn.cas.org/">http://csdn.cas.org</a> </div>
<div style="text-indent: 21pt">因为是同一个域，所以每个站点都能够共享基于 cas.org 的 cookies 。这种方法原始，不灵活而且有不少安全隐患，已经被抛弃了。 </div>
<div style="text-indent: 21pt">CAS 可以很简单的实现跨域的 SSO ，因为，单点被控制在 CAS Server ，用户最有价值的 TGC-Cookie 只是跟 CAS Server 相关， CAS Server 就只有一个，因此，解决了 cookies 不能跨域的问题。 </div>
<div style="text-indent: 21pt">回到 CAS 的基础协议图，当 Step3 完成之后， CAS Server 会向 User 发送一个 Ticket granting cookie (TGC) 给 User 的浏览器，这个 Cookie 就类似 Kerberos 的 TGT ，下次当用户被 Helloservice2 重定向到 CAS Server 的时候， CAS Server 会主动 Get 到这个 TGC cookie ，然后做下面的事情： </div>
<div style="margin: 0cm 0cm 0pt 57.75pt; text-indent: -36.75pt"><span>1，<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>如果 User 的持有 TGC 且其还没失效，那么就走基础协议图的 Step4 ，达到了 SSO 的效果。 </div>
<div style="margin: 0cm 0cm 0pt 57.75pt; text-indent: -36.75pt"><span>2，<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>如果 TGC 失效，那么用户还是要重新认证 ( 走基础协议图的 Step3) 。 </div>
<div style="margin: 14pt 0cm 14.5pt"><strong>&nbsp;CAS 的代理模式 </strong></div>
<div style="margin: 14pt 0cm 14.5pt">&nbsp;模式 1 已经能够满足大部分简单的 SSO 应用，现在，我们探讨一种更复杂的情况，即用户访问 helloservice ， helloservice 又依赖于 helloservice2 来获取一些信息，如同：
<div style="text-indent: 21pt">User <span>&#224; </span>helloservice <span>&#224; </span>helloservice2 </div>
<div style="text-indent: 21pt">这种情况下，假设 helloservice2 也是需要对 User 进行身份验证才能访问，那么，为了不影响用户体验（过多的重定向导致 User 的 IE 窗口不停地 闪动 ) ， CAS 引入了一种 Proxy 认证机制，即 CAS Client 可以代理用户去访问其它 Web 应用。 </div>
<div style="text-indent: 21pt">代理的前提是需要 CAS Client 拥有用户的身份信息 ( 类似凭据 ) 。 与其说之前我们提到的 TGC 是用户持有对自己身份信息的一种凭据，则这里的 PGT 就是 CAS Client 端持有的对用户身份信息的一种凭据。凭借 TGC ， User 可以免去输入密码以获取访问其它服务的 Service Ticket ，所以，这里，凭借 PGT ， Web 应用可以代理用户去实现后端的认证，而无需前端用户的参与。 </div>
<div style="text-indent: 21pt">如下面的 CAS Proxy 图所示， CAS Client 在基础协议之上，提供了一个额外的 PGT URL 给 CAS Server, 于是， CAS Server 可以通过 PGT URL 提供一个 PGT 给 CAS Client 。 <br />
</div>
<div><span><img height="402" alt="cas_protocol-2.jpg" src="http://www.blogjava.net/images/blogjava_net/security/cas_protocol-2.jpg" width="528" border="0" /> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>初学者可能会对上图的 PGT URL 感到迷惑，或者会问，为什么要这么麻烦，要通过一个额外的 URL( 而且是 SSL 的入口 ) 去传递 PGT ？如果直接在 Step 6 返回，则连用来做对应关系的 PGTIOU 都可以省掉。 PGTIOU 设计是从安全性考虑的，非常必要， CAS 协议安全性问题我会在后面一节介绍。 </div>
<div style="text-indent: 21pt">于是， CAS Client 拿到了 PGT( <span style="font-size: 10pt; color: black">PGTIOU-85&#8230;..ti2td</span> ) ，这个 PGT 跟 TGC 同样地关键， CAS Client 可以通过 PGT 向后端 Web 应用进行认证。如下图所示， Proxy 认证与普通的认证其实差别不大， Step1, 2 与基础模式的 Step 1,2 几乎一样，唯一不同的是， Proxy 模式用的是 PGT 而不是 TGC ，是 Proxy Ticket （ PT ）而不是 Service Ticket 。 </div>
<div style="text-indent: 21pt">最终的结果是， helloservice2 明白 helloservice 所代理的客户是 David. Turing 同学，同时，根据本地策略， helloservice2 有义务为 PGTURL=http://helloservice/proxy 服务 (PGTURL 用于表示一个 Proxy 服务 ) ，于是它传递数据给 helloservice 。这样， helloservice 便完成一个代理者的角色，协助 User 返回他想要的数据。 </div>
<div style="text-indent: 21pt"><br />
<img height="378" alt="cas_protocol-3.jpg" src="http://www.blogjava.net/images/blogjava_net/security/cas_protocol-3.jpg" width="543" border="0" /> <br />
&nbsp;&nbsp;&nbsp;代理认证模式非常有用，它也是 CAS 协议 v2 的一个最大的变化，这种模式非常适合在复杂的业务领域中应用 SSO 。因为，以前我们实施 SSO 的时候，都是假定以 IE User 为 SSO 的访问者，忽视了业务系统作为 SSO 的访问者角色。</div>
</div>
</div>
</div>
</div>
</div><img src ="http://www.blogjava.net/rain1102/aggbug/227739.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2008-09-08 14:56 <a href="http://www.blogjava.net/rain1102/archive/2008/09/08/227739.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Kerberos简介 </title><link>http://www.blogjava.net/rain1102/archive/2008/09/08/227724.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Mon, 08 Sep 2008 06:23:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2008/09/08/227724.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/227724.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2008/09/08/227724.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/227724.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/227724.html</trackback:ping><description><![CDATA[<div class="postbody"><span>Kerberos</span><span>协议：</span>
<p><span>Kerberos</span><span>协议主要用于计算机网络的身份鉴别</span><span>(Authentication), </span><span>其特点是用户只需输入一次身份验证信息就可以凭借此验证获得的票据</span><span>(ticket-granting ticket)</span><span>访问多个服务，即</span><span>SSO(Single Sign On)</span><span>。由于在每个</span><span>Client</span><span>和</span><span>Service</span><span>之间建立了共享密钥，使得该协议具有相当的安全性。<br />
<br />
<strong style="font-size: 18pt">条件</strong></span></p>
<p><span>先来看看</span><span>Kerberos</span><span>协议的前提条件：</span></p>
<p><span>如下图所示，</span><span>Client</span><span>与</span><span>KDC</span><span>，</span><span> KDC</span><span>与</span><span>Service </span><span>在协议工作前已经有了各自的共享密钥，并且由于协议中的消息无法穿透防火墙，这些条件就限制了</span><span>Kerberos</span><span>协议往往用于一个组织的内部，</span> <span>使其应用场景不同于</span><span>X.509 PKI</span><span>。</span></p>
<p><img height="471" alt="" src="http://images.cnblogs.com/cnblogs_com/idior/kerberos1.jpeg" width="487" border="0" />&nbsp;</p>
<p><span><strong style="font-size: 18pt">过程</strong><br />
<br />
Kerberos</span><span>协议分为两个部分：</span></p>
<p><span>1 . Client</span><span>向</span><span>KDC</span><span>发送自己的身份信息，</span><span>KDC</span><span>从</span><span>Ticket Granting Service</span><span>得到</span><span>TGT(ticket-granting ticket)</span><span>，</span> <span>并用协议开始前</span><span>Client</span><span>与</span><span>KDC</span><span>之间的密钥将</span><span>TGT</span><span>加密回复给</span><span>Client</span><span>。</span></p>
<p><span>此时只有真正的</span><span>Client</span><span>才能利用它与</span><span>KDC</span><span>之间的密钥将加密后的</span><span>TGT</span><span>解密，从而获得</span><span>TGT</span><span>。</span></p>
<p><span>（此过程避免了</span><span>Client</span><span>直接向</span><span>KDC</span><span>发送密码，以求通过验证的不安全方式）</span></p>
<p><span>2. Client</span><span>利用之前获得的</span><span>TGT</span><span>向</span><span>KDC</span><span>请求其他</span><span>Service</span><span>的</span><span>Ticket</span><span>，从而通过其他</span><span>Service</span><span>的身份鉴别。</span></p>
<p>&nbsp;<span>Kerberos</span><span>协议的重点在于第二部分，简介如下：</span></p>
<p>&nbsp;</p>
<p><img height="391" alt="" src="http://images.cnblogs.com/cnblogs_com/idior/kerberos2.jpeg" width="547" border="0" /></p>
<p><span><span>1．<span>&nbsp;&nbsp;&nbsp; </span></span></span><span>Client</span><span>将之前获得</span><span>TGT</span><span>和要请求的服务信息</span><span>(</span><span>服务名等</span><span>)</span><span>发送给</span><span>KDC</span><span>，</span><span>KDC中的<span>Ticket Granting Service</span></span><span>将为</span><span>Client</span><span>和</span><span>Service</span><span>之间生成一个</span><span>Session Key</span><span>用于</span><span>Service</span><span>对</span><span>Client</span><span>的身份鉴别。然后</span><span>KDC</span><span>将这个</span><span>Session Key</span><span>和用户名，用户地址（</span><span>IP</span><span>），服务名，有效期</span><span>, </span><span>时间戳一起包装成一个</span><span>Ticket(</span><span>这些信息最终用于</span><span>Service</span><span>对</span><span>Client</span><span>的身份鉴别</span><span>)</span><span>发送给</span><span>Service</span><span>，</span> <span>不过</span><span>Kerberos</span><span>协议并没有直接将</span><span>Ticket</span><span>发送给</span><span>Service</span><span>，而是通过</span><span>Client</span><span>转发给</span><span>Service.</span><span>所以有了第二步。</span></p>
<p><span><span>2．<span>&nbsp;&nbsp;&nbsp; </span></span></span><span>此时</span><span>KDC</span><span>将刚才的</span><span>Ticket转发</span><span>给</span><span>Client</span><span>。由于这个</span><span>Ticket</span><span>是要给</span><span>Service</span><span>的，不能让</span><span>Client</span><span>看到，所以</span><span>KDC</span><span>用协议开始前</span><span>KDC</span><span>与</span><span>Service</span><span>之间的密钥将</span><span>Ticket</span><span>加密后再发送给</span><span>Client</span><span>。同时为了让</span><span>Client</span><span>和</span><span>Service</span><span>之间共享那个秘密</span><span>(KDC</span><span>在第一步为它们创建的</span><span>Session Key)</span><span>，</span><span> KDC</span><span>用</span><span>Client</span><span>与它之间的密钥将</span><span>Session Key</span><span>加密随加密的</span><span>Ticket</span><span>一起返回给</span><span>Client</span><span>。</span></p>
<p><span><span>3．<span>&nbsp;&nbsp;&nbsp; </span></span></span><span>为了完成</span><span>Ticket</span><span>的传递，</span><span>Client</span><span>将刚才收到的</span><span>Ticket</span><span>转发到</span><span>Service. </span><span>由于</span><span>Client</span><span>不知道</span><span>KDC</span><span>与</span><span>Service</span><span>之间的密钥，所以它无法算改Ticket中的信息。同时</span><span>Client</span><span>将收到的</span><span>Session Key</span><span>解密出来，然后将自己的用户名，用户地址（</span><span>IP</span><span>）打包成</span><span>Authenticator</span><span>用</span><span>Session Key</span><span>加密也发送给</span><span>Service</span><span>。</span></p>
<p><span><span>4．<span>&nbsp;&nbsp;&nbsp; </span></span></span><span>Service </span><span>收到</span><span>Ticket</span><span>后利用它与</span><span>KDC</span><span>之间的密钥将</span><span>Ticket</span><span>中的信息解密出来，从而获得</span><span>Session Key</span><span>和用户名，用户地址（</span><span>IP</span><span>），服务名，有效期。然后再用</span><span>Session Key</span><span>将</span><span>Authenticator</span><span>解密从而获得用户名，用户地址（</span><span>IP</span><span>）将其与之前</span><span>Ticket</span><span>中解密出来的用户名，用户地址（</span><span>IP</span><span>）做比较从而验证</span><span>Client</span><span>的身份。</span></p>
<p><span><span>5．<span>&nbsp;&nbsp;&nbsp; </span></span></span><span>如果</span><span>Service</span><span>有返回结果，将其返回给</span><span>Client</span><span>。</span></p>
<p><strong style="font-size: 18pt">总结</strong></p>
<p><span>概括起来说</span><span>Kerberos</span><span>协议主要做了两件事</span></p>
<p><span><span>1．<span>&nbsp;&nbsp;&nbsp; </span></span></span><span>Ticket</span><span>的安全传递。</span></p>
<p><span><span>2．<span>&nbsp;&nbsp;&nbsp; </span></span></span><span>Session Key</span><span>的安全发布。</span></p>
<p><span>再加上时间戳的使用就很大程度上的保证了用户鉴别的安全性。并且利用</span><span>Session Key，在通过鉴别之后</span><span>Client</span><span>和</span><span>Service</span><span>之间传递的消息也可以获得</span><span>Confidentiality(机密性), Integrity(完整性)</span><span>的保证。不过由于没有使用非对称密钥自然也就无法具有抗否认性，这也限制了它的应用。不过相对而言它比</span><span>X.509 PKI</span><span>的身份鉴别方式实施起来要简单多了。</span></p>
<p><span>推荐资料：</span></p>
<p><span><a href="http://blog.joycode.com/peon/articles/18657.aspx" target="_blank">Kerberos<span><span>的原理</span></span></a></span></p>
<p><span><a href="http://www.isi.edu/gost/publications/kerberos-neuman-tso.html" target="_blank">Kerberos: An <strong><span>Authentication</span></strong><span> </span><strong><span>Service</span></strong><span> </span><strong><span>for</span></strong><span> </span><strong><span>Computer</span></strong><span> </span><strong><span>Networks</span></strong></a><br />
<br />
<a href="http://idior.cnblogs.com/archive/2006/04/21/354066.html" target="_blank"><a href="http://idior.cnblogs.com/archive/2006/04/21/354066.html" target="_blank">Web Services Security系列文章</a>&nbsp;</a></span></p>
</div><img src ="http://www.blogjava.net/rain1102/aggbug/227724.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2008-09-08 14:23 <a href="http://www.blogjava.net/rain1102/archive/2008/09/08/227724.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Commons-Validator</title><link>http://www.blogjava.net/rain1102/archive/2008/05/07/198893.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Wed, 07 May 2008 02:50:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2008/05/07/198893.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/198893.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2008/05/07/198893.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/198893.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/198893.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Commons-Validator（一）&nbsp;&nbsp;&nbsp;&nbsp;Commons-Validator包用来把验证规则程序提取出来，以供重复使用。这个包可以使用在Struts中，也可以独立的应用在任何其它的应用中。用户可以通过Java类的方式自定义验证方法，也可以在配置文件中通过正则表达式配置验证方法。它不但支持服务器端的验证，客户端的验证也支持，具体需要使用tag把相...&nbsp;&nbsp;<a href='http://www.blogjava.net/rain1102/archive/2008/05/07/198893.html'>阅读全文</a><img src ="http://www.blogjava.net/rain1102/aggbug/198893.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2008-05-07 10:50 <a href="http://www.blogjava.net/rain1102/archive/2008/05/07/198893.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>项目中封装Spring中的测试基类</title><link>http://www.blogjava.net/rain1102/archive/2008/04/21/194490.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Mon, 21 Apr 2008 05:15:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2008/04/21/194490.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/194490.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2008/04/21/194490.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/194490.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/194490.html</trackback:ping><description><![CDATA[<p>package com.founder.common;</p>
<p>import <a title="Java爱好者" href="http://www.blogjava.net/rain1102" >Java</a>.text.SimpleDateFormat;<br />
import <a title="Java爱好者" href="http://www.blogjava.net/rain1102" >Java</a>.util.TimeZone;</p>
<p>import org.hibernate.SessionFactory;<br />
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;</p>
<p>/**<br />
&nbsp;* This class is the base class of all the tests, <br />
&nbsp;* we can use the dependency injection functionality of spring in all the tests,<br />
&nbsp;* and the default transaction mode is rollback, so we don't need to write special code to restore data after calling some methods affected database data. <br />
&nbsp;* <br />
&nbsp;* @author Rui Zhou, Copyright &#169; 2008 foundersoftware. All Rights Reserved.<br />
&nbsp;* @version 1.00, 2008-03-22 15:46<br />
&nbsp;*/<br />
public abstract class SpringTestCaseBase extends AbstractTransactionalDataSourceSpringContextTests {<br />
&nbsp;<br />
&nbsp;protected SimpleDateFormat sdf;<br />
&nbsp;<br />
&nbsp;public SpringTestCaseBase() {<br />
&nbsp;&nbsp;// query the protected variables to implement denpendency injection automatically,<br />
&nbsp;&nbsp;// so we don't need to write settor and gettor methods anymore.<br />
&nbsp;&nbsp;this.setPopulateProtectedVariables(true);<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;sdf = new SimpleDateFormat("yyyy-MM-dd");<br />
&nbsp;&nbsp;sdf.setTimeZone(TimeZone.getDefault());<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;protected String[] getConfigLocations() {<br />
&nbsp;&nbsp;return new String[] { "file:WebRoot/WEB-INF/applicationContext*.xml"};<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;<br />
&nbsp;protected void flushSession(){<br />
&nbsp;&nbsp;SessionFactory sessionFactory = (SessionFactory)applicationContext.getBean("sessionFactory");&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sessionFactory.getCurrentSession().flush();<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
</p><img src ="http://www.blogjava.net/rain1102/aggbug/194490.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2008-04-21 13:15 <a href="http://www.blogjava.net/rain1102/archive/2008/04/21/194490.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在Servlet(或者Filter，或者Listener)中使用spring的IOC容器 </title><link>http://www.blogjava.net/rain1102/archive/2008/01/15/175495.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Tue, 15 Jan 2008 08:42:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2008/01/15/175495.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/175495.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2008/01/15/175495.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/175495.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/175495.html</trackback:ping><description><![CDATA[<p>在servlet或者filter或者Listener中使用spring的IOC容器的方法是：</p>
<p>WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext());&nbsp;</p>
<p>由于spring是注入的对象放在ServletContext中的，所以可以直接在ServletContext取出WebApplicationContext 对象：</p>
<p>WebApplicationContext webApplicationContext = (WebApplicationContext) servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);</p>
<p>事实上WebApplicationContextUtils.getWebApplicationContext方法就是使用上面的代码实现的，建议使用上面上面的静态方法&nbsp;</p>
<br />
注意：在使用webApplicationContext.getBean("ServiceName")的时候，前面强制转化要使用接口，如果使用实现类会报类型转换错误。如：<br />
LUserService&nbsp;userService ＝ (LUserService) webApplicationContext.getBean("userService");<img src ="http://www.blogjava.net/rain1102/aggbug/175495.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2008-01-15 16:42 <a href="http://www.blogjava.net/rain1102/archive/2008/01/15/175495.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HibernateTemplate的常规用法</title><link>http://www.blogjava.net/rain1102/archive/2007/12/26/170633.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Wed, 26 Dec 2007 08:46:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2007/12/26/170633.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/170633.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2007/12/26/170633.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/170633.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/170633.html</trackback:ping><description><![CDATA[<p style="text-indent: 21pt; line-height: 15.7pt">HibernateTemplate<span style="font-family: 宋体">提供非常多的常用方法来完成基本的操作，比如通常的增加、删除、修改、查询等操作，</span>Spring 2.0<span style="font-family: 宋体">更增加对命名</span>SQL<span style="font-family: 宋体">查询的支持，也增加对分页的支持。大部分情况下，使用</span>Hibernate<span style="font-family: 宋体">的常规用法，就可完成大多数</span>DAO<span style="font-family: 宋体">对象的</span>CRUD<span style="font-family: 宋体">操作。下面是</span>HibernateTemplate<span style="font-family: 宋体">的常用方法简介：</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>void delete(Object entity)<span style="font-family: 宋体">：删除指定持久化实例</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>deleteAll(Collection entities)<span style="font-family: 宋体">：删除集合内全部持久化类实例</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>find(String queryString)<span style="font-family: 宋体">：根据</span>HQL<span style="font-family: 宋体">查询字符串来返回实例集合</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>findByNamedQuery(String queryName)<span style="font-family: 宋体">：根据命名查询返回实例集合</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>get(Class entityClass, Serializable id)<span style="font-family: 宋体">：根据主键加载特定持久化类的实例</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>save(Object entity)<span style="font-family: 宋体">：保存新的实例</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>saveOrUpdate(Object entity)<span style="font-family: 宋体">：根据实例状态，选择保存或者更新</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>update(Object entity)<span style="font-family: 宋体">：更新实例的状态，要求</span>entity<span style="font-family: 宋体">是持久状态</span></p>
<p><span style="font-family: Wingdings">q<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>setMaxResults(int maxResults)<span style="font-family: 宋体">：设置分页的大小</span></p><img src ="http://www.blogjava.net/rain1102/aggbug/170633.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2007-12-26 16:46 <a href="http://www.blogjava.net/rain1102/archive/2007/12/26/170633.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MyEclipse 开发 SSH 整合时 java.lang.NoSuchMethodError: org.objectweb.asm.ClassVisitor.visit 解决方案 </title><link>http://www.blogjava.net/rain1102/archive/2007/12/23/169853.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Sun, 23 Dec 2007 12:47:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2007/12/23/169853.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/169853.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2007/12/23/169853.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/169853.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/169853.html</trackback:ping><description><![CDATA[ERROR [org.hibernate.proxy.BasicLazyInitializer] - CGLIB Enhancement failed: dao.User<br />
<a title="Java爱好者" href="http://www.blogjava.net/rain1102" >Java</a>.lang.NoSuchMethodError: org.objectweb.asm.ClassVisitor.visit(IILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V<br />
&nbsp;at net.sf.cglib.core.ClassEmitter.begin_class(ClassEmitter.java:77) <br />
<span style="font-size: 10pt; color: #4b4b4b; line-height: 150%">Spring </span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%">和</span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%"> Hibernate </span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%">共用的一些</span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%"> jar </span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%">文件发生了版本冲突</span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%">, </span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%">删除</span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%"> WEB-INF/lib/asm-2.2.3.jar </span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%">然后重启</span><span style="font-size: 10pt; color: #4b4b4b; line-height: 150%"> Tomcat.</span><br />
<span style="font-size: 10pt; color: #4b4b4b; line-height: 150%">asm-2.2.3.jar<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; asm.jar<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; asm-attrs.jar<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; asm-commons-2.2.3.jar<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; asm-util-2.2.3.jar</span><img src ="http://www.blogjava.net/rain1102/aggbug/169853.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2007-12-23 20:47 <a href="http://www.blogjava.net/rain1102/archive/2007/12/23/169853.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>采用GenericManager做业务处理的时候CGLIB报错. </title><link>http://www.blogjava.net/rain1102/archive/2007/12/23/169846.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Sun, 23 Dec 2007 12:26:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2007/12/23/169846.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/169846.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2007/12/23/169846.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/169846.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/169846.html</trackback:ping><description><![CDATA[项目中我把Service这层的类改了一下.定义了两个Service的父类.一个是:<br />
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">interface</span><span>&nbsp;GenericManager&lt;T,&nbsp;PK&nbsp;</span><span class="keyword">extends</span><span>&nbsp;Serializable&gt;&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span class="keyword">public</span><span>&nbsp;List&lt;T&gt;&nbsp;getAll(); &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span class="keyword">public</span><span>&nbsp;T&nbsp;get(PK&nbsp;id); &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>.......基本的CRUD方法 &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>}&nbsp;&nbsp;</span></li>
</ol>
<br />
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;GenericManagerImpl&lt;T,&nbsp;PK&nbsp;</span><span class="keyword">extends</span><span>&nbsp;Serializable&gt;&nbsp;</span><span class="keyword">implements</span><span>&nbsp;GenericManager&lt;T,&nbsp;PK&gt;&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span class="keyword">protected</span><span>&nbsp;BaseGenericHibernateDAO&lt;T,&nbsp;PK&gt;&nbsp;baseGenericHibernateDAO; &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span class="keyword">public</span><span>&nbsp;GenericManagerImpl(BaseGenericHibernateDAO&lt;T,&nbsp;PK&gt;&nbsp;baseGenericHibernateDAO)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li class=""><span class="keyword">this</span><span>.baseGenericHibernateDAO&nbsp;=&nbsp;baseGenericHibernateDAO; &nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>} &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>对应实现上面的接口CRUD方法 &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>}&nbsp;&nbsp;</span></li>
</ol>
但是现在项目启动的时候抛出一个如下的错误:<br />
<li class="alt"><span><span>Caused&nbsp;by:&nbsp;org.springframework.aop.framework.AopConfigException:&nbsp;Couldn't&nbsp;generate&nbsp;CGLIB&nbsp;subclass&nbsp;of&nbsp;</span><span class="keyword">class</span><span>&nbsp;[</span><span class="keyword">class</span><span>&nbsp;com.xxxx.user.service.impl.UserManagerImpl]:&nbsp;Common&nbsp;causes&nbsp;of&nbsp;</span><span class="keyword">this</span><span>&nbsp;problem&nbsp;include&nbsp;using&nbsp;a&nbsp;</span><span class="keyword">final</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;or&nbsp;a&nbsp;non-visible&nbsp;</span><span class="keyword">class</span><span>;&nbsp;nested&nbsp;exception&nbsp;is&nbsp;java.lang.IllegalArgumentException:&nbsp;Superclass&nbsp;has&nbsp;no&nbsp;</span><span class="keyword">null</span><span>&nbsp;constructors&nbsp;but&nbsp;no&nbsp;arguments&nbsp;were&nbsp;given &nbsp;&nbsp;</span></span></li>
<li class=""><span>Caused&nbsp;by:&nbsp;java.lang.IllegalArgumentException:&nbsp;Superclass&nbsp;has&nbsp;no&nbsp;</span><span class="keyword">null</span><span>&nbsp;constructors&nbsp;but&nbsp;no&nbsp;arguments&nbsp;were&nbsp;given &nbsp;&nbsp;</span></span></li>
<li class="alt"><span>at&nbsp;net.sf.cglib.proxy.Enhancer.emitConstructors(Enhancer.java:</span><span class="number">718</span><span>)&nbsp;&nbsp;</span></li>
<br />
<span style="color: red">是Spring AOP的问题.主要是出现在事务这块,由于我用的是Spring2.0 AOP 来声明事务.在声明事务的时候我把taget-prent-class="true" 了,但事实上不能为true.去掉这个就OK了因为要针对接口代理.</span><br /><img src ="http://www.blogjava.net/rain1102/aggbug/169846.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2007-12-23 20:26 <a href="http://www.blogjava.net/rain1102/archive/2007/12/23/169846.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring事务、异常</title><link>http://www.blogjava.net/rain1102/archive/2007/07/16/130588.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Mon, 16 Jul 2007 07:23:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2007/07/16/130588.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/130588.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2007/07/16/130588.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/130588.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/130588.html</trackback:ping><description><![CDATA[<p><span>Spring</span><span>的事务实现采用基于</span><span>AOP</span><span>的拦截器来实现，如果没有在事务配置的时候注明回滚的</span><span>checked exception</span><span>，那么只有在发生了</span><span>unchecked exception</span><span>的时候，才会进行事务回滚。因此在</span><span>DAO</span><span>层和</span><span>service</span><span>层，最好抛出</span><span>unckecked exception</span><span>，毕竟对于数据库操作，使用</span><span>unckecked exception</span><span>更加合适，这个方面的例子</span><span>hibernate</span><span>就是一个，在</span><span>hibernate2</span><span>中，</span><span>HibernateException</span><span>还是</span><span>checked exceptions</span><span>，但是到了</span><span>hibernate3</span><span>中就成了</span><span>unchecked exceptions</span><span>，因为对于数据库操作来说，一旦出现异常，就是比较严重的错误，而且在</span><span>client</span><span>端基本上是无能为力的，所以使用</span><span>unchecked exceptions</span><span>更加合适。</span></p>
<p><span>另外，在</span><span>DAO</span><span>和</span><span>service</span><span>层的代码中，除非是为了异常的转化、重新抛出，否则不要捕捉和处理异常，否则</span><span>AOP</span><span>在拦截的时候就不能捕捉到异常，也就不能正确执行回滚。这一点通常很容易被忽视，只有在明白了</span><span>spring</span><span>的事务处理机制后，才能领会到。</span></p>
<p><span>对于</span><span>hibernate</span><span>的异常，</span><span>spring</span><span>会包装</span><span>hibernate</span><span>的</span><span>upckecked hibernateException</span><span>到</span><span>DAOAccessException</span><span>，并且抛出，在事务管理层，一旦接收到</span><span>DAOAccessException</span><span>就会触发事务的回滚，同时该异常会继续向上层抛出，供上层进一步处理，比如在</span><span>UI</span><span>层向用户反馈错误信息等。<br>在spring的事务管理环境下，使用unckecked exception可以极大地简化异常的处理，只需要在事务层声明可能抛出的异常（这里的异常可以是自定义的unckecked exception体系），在所有的中间层都只是需要简单throws即可，不需要捕捉和处理，直接到最高层，比如UI层再进行异常的捕捉和处理。<br></span></p><img src ="http://www.blogjava.net/rain1102/aggbug/130588.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2007-07-16 15:23 <a href="http://www.blogjava.net/rain1102/archive/2007/07/16/130588.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring中的所有事务策略</title><link>http://www.blogjava.net/rain1102/archive/2007/07/13/130075.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Fri, 13 Jul 2007 06:05:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2007/07/13/130075.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/130075.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2007/07/13/130075.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/130075.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/130075.html</trackback:ping><description><![CDATA[Spring中的所有<nobr>事务</nobr>策略：<br>
<ul>
    <li>PROPAGATION_REQUIRED--支持当前事务，如果当前没有事务，就新建一个事务。这是最常见的选择。
    <li>PROPAGATION_SUPPORTS--支持当前事务，如果当前没有事务，就以非事务方式执行。
    <li>PROPAGATION_MANDATORY--支持当前事务，如果当前没有事务，就抛出异常。
    <li>PROPAGATION_REQUIRES_NEW--新建事务，如果当前存在事务，把当前事务挂起。
    <li>PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作，如果当前存在事务，就把当前事务挂起。
    <li>PROPAGATION_NEVER--以非事务方式执行，如果当前存在事务，则抛出异常。
    <li>PROPAGATION_NESTED--如果当前存在事务，则在嵌套事务内执行。如果当前没有事务，则进行与PROPAGATION_REQUIRED类似的操作。 </li>
</ul><img src ="http://www.blogjava.net/rain1102/aggbug/130075.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2007-07-13 14:05 <a href="http://www.blogjava.net/rain1102/archive/2007/07/13/130075.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Open Session in Test 及自动Rollback</title><link>http://www.blogjava.net/rain1102/archive/2007/05/15/117541.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Tue, 15 May 2007 03:09:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2007/05/15/117541.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/117541.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2007/05/15/117541.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/117541.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/117541.html</trackback:ping><description><![CDATA[又是来自Spring这个神奇国度的东西， 你可以让testCase继承于AbstractTransactionalDataSourceSpringContextTests，就可以做到Open Session in Test ，解决Hibernate的lazy-load问题；而且接管原来的DAO里的事务控制定义，通过setDefaultRollback(boolean)方法控制最后回滚还是提交，如果默认为回滚，则测试产生数据变动不会影响数据库内数据。<br>&nbsp;<br>如果不能继承于这个基类，可以自己简单编写，代码是这样的：<br>&nbsp;&nbsp;<span style="COLOR: #008000"> protected PlatformTransactionManager transactionManager;<br>&nbsp;&nbsp; protected TransactionStatus transactionStatus;<br>&nbsp;&nbsp; protected boolean defaultRollback = true;<br>&nbsp;&nbsp; public void setUp()<br>&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; transactionManager = (PlatformTransactionManager) ctx.getBean("transactionManager");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());<br>&nbsp;&nbsp; }<br>&nbsp;&nbsp; public void tearDown()<br>&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (defaultRollback)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; transactionManager.rollback(this.transactionStatus);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; transactionManager.commit(this.transactionStatus);<br>&nbsp;&nbsp;&nbsp; }<br></span>(注，hibernate太奸诈了，如果全部默认回滚，只会在session里干活，一点不写数据库，达不到完全的测试效果。)<img src ="http://www.blogjava.net/rain1102/aggbug/117541.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2007-05-15 11:09 <a href="http://www.blogjava.net/rain1102/archive/2007/05/15/117541.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于Spring中的回滚问题AbstractTransactionalDataSourceSpringContextTests</title><link>http://www.blogjava.net/rain1102/archive/2007/05/15/117518.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Tue, 15 May 2007 02:06:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2007/05/15/117518.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/117518.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2007/05/15/117518.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/117518.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/117518.html</trackback:ping><description><![CDATA[AbstractTransactionalDataSourceSpringContextTests缺乏对hibernate session的处理，需要对其进行扩展，扩展基本思路是在事务开始后，结束前把测试方法包装在
<p>HibernateTemaplate.executeWithSession(...){ <br>public Object doInHibernate(Session session) { <br>runTest(); <br>session.flush();//synchornize database, errors will be reported. <br>session.clear();}...}<br>而AbstractTransactionalDataSourceSpringContextTests只要你不调用super.setDefaultRollback(false);这个基类默认就会回滚! 于是由此产生hibernate偷懒,无法发现数据库操作,然后我们建议你在测试中显示调用session.flush <br>或者参杂一些查询调用(其实也是为了触发session.flush)。</p>
<p>不过这里面也有些陷阱:如果你的测试还是会把数据写入了数据库的话,可能是由于你加载的spring配置文件里有多个事务管理器或session工厂,从而导致AbstractTransactionalDataSourceSpringContextTests没有获得正确的TransactionManager或SessionFactory,所以就没能回滚不过这种错误也不太容易犯,因为AbstractTransactionalDataSourceSpringContextTests默认按类型组装,如果她发现有多个TransactionManager类型的bean是要报错的,此时你需要调用setAutowireMode(this.AUTOWIRE_BY_NAME);使其按名称组装。<br><br>另外值得注意的是，使用MYSQL时候表的类型选择。例如</p>
<p><span style="COLOR: rgb(0,0,255)">CREATE</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(0,0,255)">TABLE</span><span style="COLOR: rgb(0,0,0)">&nbsp;`myisam`&nbsp;(<br>&nbsp;&nbsp;`id`&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: rgb(0,0,0)">int</span><span style="COLOR: rgb(0,0,0)">(</span><span style="FONT-WEIGHT: bold; COLOR: rgb(128,0,0)">11</span><span style="COLOR: rgb(0,0,0)">)&nbsp;</span><span style="COLOR: rgb(128,128,128)">NOT</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(0,0,255)">NULL</span><span style="COLOR: rgb(0,0,0)">&nbsp;auto_increment,<br>&nbsp;&nbsp;`name`&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: rgb(0,0,0)">varchar</span><span style="COLOR: rgb(0,0,0)">(</span><span style="FONT-WEIGHT: bold; COLOR: rgb(128,0,0)">100</span><span style="COLOR: rgb(0,0,0)">)&nbsp;</span><span style="COLOR: rgb(0,0,255)">default</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(0,0,255)">NULL</span><span style="COLOR: rgb(0,0,0)">,<br>&nbsp;&nbsp;`content`&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: rgb(0,0,0)">text</span><span style="COLOR: rgb(0,0,0)">,<br>&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">PRIMARY</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(0,0,255)">KEY</span><span style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;(`id`)<br>)&nbsp;ENGINE</span><span style="COLOR: rgb(128,128,128)">=</span><span style="COLOR: rgb(0,0,0)">MyISAM&nbsp;</span><span style="COLOR: rgb(0,0,255)">DEFAULT</span><span style="COLOR: rgb(0,0,0)">&nbsp;CHARSET</span><span style="COLOR: rgb(128,128,128)">=</span><span style="COLOR: rgb(0,0,0)">gbk;<br>这时候应该把类型改为InnoDB。</span></p>
<p><span style="COLOR: rgb(0,0,0)">MySQL存储引擎包括处理事务安全表的引擎和处理非事务安全表的引擎：&#183; MyISAM管理非事务表。它提供高速存储和检索，以及全文搜索能力。MyISAM在所有MySQL配置里被支持，它是默认的存储引擎，除非你配置 MySQL默认使用另外一个引擎。 &#183;MEMORY存储引擎提供&#8220;内存中&#8221;表。MERGE存储引擎允许集合将被处理同样的MyISAM表作为一个单独的表。就像MyISAM一样， MEMORY和MERGE存储引擎处理非事务表，这两个引擎也都被默认包含在MySQL中。 释：MEMORY存储引擎正式地被确定为HEAP引擎。&#183; InnoDB和BDB存储引擎提供事务安全表。BDB被包含在为支持它的操作系统发布的MySQL-Max二进制分发版里。InnoDB也默认被包括在所 有MySQL 5.1二进制分发版里，你可以按照喜好通过配置MySQL来允许或禁止任一引擎。&#183;EXAMPLE存储引擎是一个&#8220;存根&#8221;引擎，它不做什么。你可以用这个 引擎创建表，但没有数据被存储于其中或从其中检索。</span></p><img src ="http://www.blogjava.net/rain1102/aggbug/117518.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2007-05-15 10:06 <a href="http://www.blogjava.net/rain1102/archive/2007/05/15/117518.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>acegi的配置</title><link>http://www.blogjava.net/rain1102/archive/2007/03/29/107142.html</link><dc:creator>周锐</dc:creator><author>周锐</author><pubDate>Thu, 29 Mar 2007 02:32:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2007/03/29/107142.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/107142.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2007/03/29/107142.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/107142.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/107142.html</trackback:ping><description><![CDATA[<p>applicationContext-acegi-security.xml<br /><strong>1.filterChainProxy配置<br /></strong>&lt;bean id="<font style="BACKGROUND-COLOR: #ffffff" color="#800080">filterChainProxy</font>" class="org.acegisecurity.util.FilterChainProxy"&gt;<br />&#160;&#160;&lt;property name="<font style="BACKGROUND-COLOR: #ffffff" color="#006400">filterInvocationDefinitionSource</font>"&gt;<br />&#160;&#160;&#160;&lt;value&gt;<br />&#160;&#160;&#160;&#160;CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<br />&#160;&#160;&#160;&#160;PATTERN_TYPE_APACHE_ANT<br />&#160;&#160;&#160;&#160;/**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor<br />&#160;&#160;&#160;&lt;/value&gt;<br />&#160;&#160;&lt;/property&gt;<br />&#160;&lt;/bean&gt;<br /><br /><strong>2.httpSessionContextIntegrationFilter配置</strong><br />&lt;bean id="<font color="#800080">httpSessionContextIntegrationFilter</font>" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"/&gt;<br /><br />3.logoutFilter配置<br />&lt;bean id="<font color="#800080">logoutFilter</font>" class="org.acegisecurity.ui.logout.LogoutFilter"&gt;<br />&#160;&#160;&lt;constructor-arg value="/index.jsp"/&gt; &lt;!-- URL redirected to after logout --&gt;<br />&#160;&#160;&lt;constructor-arg&gt;<br />&#160;&#160;&#160;&lt;list&gt;<br />&#160;&#160;&#160;&#160;&lt;ref bean="<font color="#006400">rememberMeServices</font>"/&gt;<br />&#160;&#160;&#160;&#160;&lt;bean class="<font color="#006400">org.acegisecurity.ui.logout.SecurityContextLogoutHandler</font>"/&gt;<br />&#160;&#160;&#160;&lt;/list&gt;<br />&#160;&#160;&lt;/constructor-arg&gt;<br />&#160;&lt;/bean&gt;<br /><br /><strong>4.authenticationProcessingFilter配置<br /></strong>&lt;bean id="<font color="#800080">authenticationProcessingFilter</font>" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"&gt;<br />&#160;&#160;&lt;property name="<font color="#006400">authenticationManager</font>" ref="authenticationManager"/&gt;<br />&#160;&#160;&lt;property name="<font color="#006400">authenticationFailureUrl</font>" value="/login.jsp?login_error=1"/&gt;<br />&#160;&#160;&lt;property name="<font color="#006400">defaultTargetUrl</font>" value="/"/&gt;<br />&#160;&#160;&lt;property name="<font color="#006400">filterProcessesUrl</font>" value="/j_acegi_security_check"/&gt;<br />&#160;&#160;&lt;property name="<font color="#006400">rememberMeServices</font>" ref="rememberMeServices"/&gt;<br />&#160;&lt;/bean&gt;<br /><br /><strong>5.securityContextHolderAwareRequestFilter配置</strong><br />&lt;bean id="<font color="#800080">securityContextHolderAwareRequestFilter</font>" class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter"/&gt;<br /><br /><strong>6.rememberMeProcessingFilter配置</strong><br />&lt;bean id="<font color="#800080">rememberMeProcessingFilter</font>" class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter"&gt;<br />&#160;&#160;&lt;property name="<font color="#006400">authenticationManager</font>" ref="authenticationManager"/&gt;<br />&#160;&#160;&lt;property name="<font color="#006400">rememberMeServices</font>" ref="rememberMeServices"/&gt;<br />&#160;&lt;/bean&gt;<br /><br /><strong>7.anonymousProcessingFilter配置</strong><br />&lt;bean id="<font color="#800080">anonymousProcessingFilter</font>" class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter"&gt;<br />&#160;&#160;&lt;property name="<font color="#006400">key</font>" value="changeThis"/&gt;<br />&#160;&#160;&lt;property name="<font color="#006400">userAttribute</font>" value="anonymousUser,ROLE_ANONYMOUS"/&gt;<br />&#160;&lt;/bean&gt;<br /><br /><strong>8.exceptionTranslationFilter配置</strong><br />&lt;bean id="<font color="#800080">exceptionTranslationFilter</font>" class="org.acegisecurity.ui.ExceptionTranslationFilter"&gt;<br />&#160;&#160;&lt;property name="<font color="#006400">authenticationEntryPoint</font>"&gt;<br />&#160;&#160;&#160;&lt;bean class="<font color="#006400">org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint</font>"&gt;<br />&#160;&#160;&#160;&#160;&lt;property name="<font color="#006400">loginFormUrl</font>" value="/login.jsp"/&gt;<br />&#160;&#160;&#160;&#160;&lt;property name="<font color="#008000">forceHttps</font>" value="false"/&gt;<br />&#160;&#160;&#160;&lt;/bean&gt;<br />&#160;&#160;&lt;/property&gt;<br />&#160;&#160;&lt;property name="<font color="#006400">accessDeniedHandler</font>"&gt;<br />&#160;&#160;&#160;&lt;bean class="<font color="#006400">org.acegisecurity.ui.AccessDeniedHandlerImpl</font>"&gt;<br />&#160;&#160;&#160;&#160;&lt;property name="<font color="#006400">errorPage</font>" value="/accessDenied.jsp"/&gt;<br />&#160;&#160;&#160;&lt;/bean&gt;<br />&#160;&#160;&lt;/property&gt;<br />&#160;&lt;/bean&gt;<br /><br /><strong>9.filterInvocationInterceptor配置</strong><br />&lt;bean id="<font color="#800080">filterInvocationInterceptor</font>" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"&gt;<br />&#160;&#160;&lt;property name="<font color="#006400">authenticationManager</font>" ref="authenticationManager"/&gt;<br />&#160;&#160;&lt;property name="<font color="#006400">accessDecisionManager</font>" ref="accessDecisionManager"/&gt;<br />&#160;&#160;&lt;property name="<font color="#006400">objectDefinitionSource</font>"&gt;<br />&#160;&#160;&#160;&lt;value&gt;<br />&#160;&#160;&#160;&#160;PATTERN_TYPE_APACHE_ANT<br />&#160;&#160;&#160;&#160;/mainFrame.html=admin,user<br />&#160;&#160;&#160;&#160;/文件夹1/*.html*=admin,user<br />&#160;&#160;&#160;&#160;/文件夹2/*.html*=admin,user<br />&#160;&#160;&#160;&#160;/文件夹3/*.html*=admin<br />&#160;&#160;&#160;&#160;/accessDenied.jsp*=ROLE_ANONYMOUS<br />&#160;&#160;&#160;&lt;/value&gt;<br />&#160;&#160;&lt;/property&gt;<br />&#160;&lt;/bean&gt;<br /><br /><strong>10.</strong><font color="#000000"><strong>accessDecisionManager配置</strong><br /></font>&lt;bean id="<font color="#800080">accessDecisionManager</font>" class="org.acegisecurity.vote.AffirmativeBased"&gt;<br />&#160;&#160;&lt;property name="allowIfAllAbstainDecisions" value="false"/&gt;<br />&#160;&#160;&lt;property name="decisionVoters"&gt;<br />&#160;&#160;&#160;&lt;list&gt;<br />&#160;&#160;&#160;&#160;&lt;bean class="org.acegisecurity.vote.RoleVoter"&gt;<br />&#160;&#160;&#160;&#160;&#160;&lt;property name="rolePrefix" value=""/&gt;<br />&#160;&#160;&#160;&#160;&lt;/bean&gt;<br />&#160;&#160;&#160;&#160;&lt;bean class="org.acegisecurity.vote.AuthenticatedVoter"/&gt;<br />&#160;&#160;&#160;&lt;/list&gt;<br />&#160;&#160;&lt;/property&gt;<br />&#160;&lt;/bean&gt;<br /><br /><strong>11.rememberMeServices配置</strong></p>
		<p>&#160;&lt;bean id="<font color="#800080">rememberMeServices</font>" class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices"&gt;<br />&#160;&#160;&lt;property name="userDetailsService" ref="userDetailsService"/&gt;<br />&#160;&#160;&lt;property name="key" value="changeThis"/&gt;<br />&#160;&lt;/bean&gt;<br /><br /><strong>12.authenticationManager配置</strong></p>
		<p>&#160;&lt;bean id="<font color="#800080">authenticationManager</font>" class="org.acegisecurity.providers.ProviderManager"&gt;<br />&#160;&#160;&lt;property name="providers"&gt;<br />&#160;&#160;&#160;&lt;list&gt;<br />&#160;&#160;&#160;&#160;&lt;ref local="daoAuthenticationProvider"/&gt;<br />&#160;&#160;&#160;&#160;&lt;bean class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider"&gt;<br />&#160;&#160;&#160;&#160;&#160;&lt;property name="key" value="changeThis"/&gt;<br />&#160;&#160;&#160;&#160;&lt;/bean&gt;<br />&#160;&#160;&#160;&#160;&lt;bean class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider"&gt;<br />&#160;&#160;&#160;&#160;&#160;&lt;property name="key" value="changeThis"/&gt;<br />&#160;&#160;&#160;&#160;&lt;/bean&gt;<br />&#160;&#160;&#160;&lt;/list&gt;<br />&#160;&#160;&lt;/property&gt;<br />&#160;&lt;/bean&gt;<br /><br /><strong>13.daoAuthenticationProvider配置</strong></p>
		<p>&#160;&lt;bean id="<font color="#800080">daoAuthenticationProvider</font>" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;<br />&#160;&#160;&lt;property name="userDetailsService" ref="userDetailsService"/&gt;<br />&#160;&#160;&lt;property name="userCache"&gt;<br />&#160;&#160;&#160;&lt;bean class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache"&gt;<br />&#160;&#160;&#160;&#160;&lt;property name="cache"&gt;<br />&#160;&#160;&#160;&#160;&#160;&lt;bean class="org.springframework.cache.ehcache.EhCacheFactoryBean"&gt;<br />&#160;&#160;&#160;&#160;&#160;&#160;&lt;property name="cacheManager"&gt;<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&lt;bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"&gt;<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&lt;property name="configLocation" value="classpath:ehcache.xml"/&gt;<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&lt;/bean&gt;<br />&#160;&#160;&#160;&#160;&#160;&#160;&lt;/property&gt;<br />&#160;&#160;&#160;&#160;&#160;&#160;&lt;property name="cacheName" value="userCache"/&gt;<br />&#160;&#160;&#160;&#160;&#160;&lt;/bean&gt;<br />&#160;&#160;&#160;&#160;&lt;/property&gt;<br />&#160;&#160;&#160;&lt;/bean&gt;<br />&#160;&#160;&lt;/property&gt;<br />&#160;&lt;/bean&gt;<br /><br /><strong>14.methodSecurityInterceptor配置</strong><br />&#160;<br />&#160;&lt;bean id="<font color="#800080">methodSecurityInterceptor</font>" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"&gt;<br />&#160;&#160;&lt;property name="authenticationManager" ref="authenticationManager"/&gt;<br />&#160;&#160;&lt;property name="accessDecisionManager" ref="accessDecisionManager"/&gt;<br />&#160;&#160;&lt;property name="objectDefinitionSource"&gt;<br />&#160;&#160;&#160; &lt;value&gt;<br />&#160;&#160;&#160;&#160;&#160;com.rain.wsh.service.IUserService.get*=IS_AUTHENTICATED_ANONYMOUSLY <br />&#160;&#160;&#160;&#160;&#160; com.rain.wsh.service.IUserService.create*=IS_AUTHENTICATED_ANONYMOUSLY <br />&#160;&#160;&#160;&#160;&#160; com.rain.wsh.service.IUserService.update*=IS_AUTHENTICATED_ANONYMOUSLY <br />&#160;&#160;&#160;&#160;&#160; com.rain.wsh.service.IUserService.delete*=IS_AUTHENTICATED_ANONYMOUSLY&#160;<br />&#160;&#160;&#160;&lt;/value&gt;<br />&#160;&#160;&lt;/property&gt;<br />&#160;&lt;/bean&gt;<br /><br /><strong>15.loggerListener配置</strong></p>
		<p>&#160;&lt;!-- This bean is optional; it isn't used by any other bean as it only listens and logs --&gt;<br />&#160;&lt;bean id="<font color="#800080">loggerListener</font>" class="org.acegisecurity.event.authentication.LoggerListener"/&gt;<br /><br />注:userDetailsService定义为:<br />&lt;bean id="<font color="#800080">userDetailsService</font>" class="com.rain.wsh.service.impl.UserDetailsServiceImpl"/&gt;<br /><br />package com.rain.wsh.service.impl;</p>
		<p>import org.acegisecurity.userdetails.UserDetails;<br />import org.acegisecurity.userdetails.UserDetailsService;<br />import org.acegisecurity.userdetails.UsernameNotFoundException;<br />import org.springframework.dao.DataAccessException;</p>
		<p>import com.rain.wsh.dao.IUserDAO;</p>
		<p>public class UserDetailsServiceImpl implements <font color="#800080">UserDetailsService</font> {<br />&#160;private final Logger log = Logger.getLogger(getClass());<br />&#160;<br />&#160;private IUserDAO userDAO;<br />&#160;<br />&#160;/**<br />&#160; * @return the userDAO<br />&#160; */<br />&#160;public IUserDAO getUserDAO() {<br />&#160;&#160;return userDAO;<br />&#160;}</p>
		<p>&#160;/**<br />&#160; * @param userDAO the userDAO to set<br />&#160; */<br />&#160;public void setUserDAO(IUserDAO userDAO) {<br />&#160;&#160;this.userDAO = userDAO;<br />&#160;}<br />&#160;<br />&#160;/*<br />&#160; * (non-Javadoc)<br />&#160; * @see org.acegisecurity.userdetails.UserDetailsService#loadUserByUsername(java.lang.String)<br />&#160; */<br />&#160;public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException {<br />&#160;&#160;<br />&#160;&#160;UserDetails user = userDAO.getUserByName(userName);<br />&#160;&#160;if (user == null) {<br />&#160;&#160;&#160;log.error("The user was not found:" + userName);<br />&#160;&#160;&#160;throw new UsernameNotFoundException("The user was not found:" + userName);<br />&#160;&#160;}<br />&#160;&#160;return user;<br />&#160;}</p>
		<p>}<br /><br />注意user必须实现<font color="#006400">Serializable, UserDetails</font><br /></p><img src ="http://www.blogjava.net/rain1102/aggbug/107142.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">周锐</a> 2007-03-29 10:32 <a href="http://www.blogjava.net/rain1102/archive/2007/03/29/107142.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>