﻿<?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-俺们那嘎达-文章分类-webwork</title><link>http://www.blogjava.net/livery/category/23347.html</link><description>找到属于自己的一片天空</description><language>zh-cn</language><lastBuildDate>Wed, 27 Jun 2007 16:59:01 GMT</lastBuildDate><pubDate>Wed, 27 Jun 2007 16:59:01 GMT</pubDate><ttl>60</ttl><item><title>WebWork中的spring(2)</title><link>http://www.blogjava.net/livery/articles/125560.html</link><dc:creator>心情经纬</dc:creator><author>心情经纬</author><pubDate>Thu, 21 Jun 2007 06:19:00 GMT</pubDate><guid>http://www.blogjava.net/livery/articles/125560.html</guid><wfw:comment>http://www.blogjava.net/livery/comments/125560.html</wfw:comment><comments>http://www.blogjava.net/livery/articles/125560.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/livery/comments/commentRss/125560.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/livery/services/trackbacks/125560.html</trackback:ping><description><![CDATA[<h1><a name=SpringSessionComponentsWorkarounds-%E5%8A%A8%E6%9C%BA></a>动机</h1>
<p>Spring现在不支持session会话范围的bean和component.你可以在singleton或者prototype生命周期之间选择,但是你不能让你的bean绑定到web应用程序的session生命周期上去.在Spring 2.0版本中已经计划集成这样一个特性.我们试着指出一些可能的解决方案来工作在基于WebWork的应用程序中.首先我们会考查在Spring社区中发现的通用解决方案,来处理HTTPSession和诸如此类的事情.然后我们会讨论在XWork/WebWork里发现的特殊情况和需求,以及这些会如何影响可能的解决方案.我们会展示一些XWork/WebWork对给定问题的特定解决方案.</p>
<table class=infoMacro cellSpacing=8 cellPadding=5 width="85%" align=center border=0>
    <colgroup>
    <col width=24>
    <col></colgroup>
    <tbody>
        <tr>
            <td vAlign=top><img height=16 alt="" src="http://wiki.javascud.org/images/icons/emoticons/information.gif" width=16 align=absMiddle border=0></td>
            <td>
            <p>Spring 2.0(前一个版本是1.3)的第一个里程碑版本将会在2005十二月的第二个星期发布.已经证实它会包含一个Session会话范围的组件,使用了Proxy(CGLIB或者JDK)方法.</p>
            </td>
        </tr>
    </tbody>
</table>
<h1><a name=SpringSessionComponentsWorkarounds-%E5%AF%B9%E4%BA%8Eweb%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E7%9A%84%E9%80%9A%E7%94%A8%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88></a>对于web应用程序的通用解决方案</h1>
<h2><a name=SpringSessionComponentsWorkarounds-Spring2.0%E7%9A%84%E6%96%B9%E6%B3%95></a>Spring 2.0 的方法</h2>
<p>Interface21(译注:Spring作者的公司)在Spring 2.0中添加了session(和request)会话范围的bean的支持.这个方法通过org.springframework.aop.target.scope.ScopedProxyFactoryBean 创建了一个session会话范围的bean的CGLIB或者JDK动态代理,并设置scopeMap为org.springframework.web.context.scope.SessionScopeMap.</p>
<p>因为jar是向后兼容的,因为只需要简单地构建Spring并替换WebWork带来的jar.(当你读到这里的时候Spring 2.0 M1可能已经发布了).</p>
<p>有两种方法来设置这个,也就是使用或者不使用简化的XML.第一个方法是使用传统的bean定义,这对于理解内部发生了什么是很有用的.</p>
<p>一个shopping cart例子里经过改良的applicationContext.xml,使用了传统的XML DTD的例子显示在下面.</p>
<div class=code>
<div class=codeContent>
<pre class=code-xml><span class=code-tag>&lt;?xml version=<span class=code-quote>"1.0"</span> encoding=<span class=code-quote>"UTF-8"</span>?&gt;</span>
<span class=code-tag>&lt;!DOCTYPE beans PUBLIC <span class=code-quote>"-//SPRING//DTD BEAN//EN"</span> <span class=code-quote>"http://www.springframework.org/dtd/spring-beans.dtd"</span>&gt;</span>
<span class=code-tag>&lt;beans&gt;</span>
&lt;bean id=<span class=code-quote>"shoppingCart"</span> class=<span class=code-quote>"org.springframework.aop.target.scope.ScopedProxyFactoryBean"</span>
singleton=<span class=code-quote>"false"</span>&gt;
<span class=code-tag>&lt;property name=<span class=code-quote>"scopeKey"</span> value=<span class=code-quote>"shoppingCart"</span>/&gt;</span>
<span class=code-tag>&lt;property name=<span class=code-quote>"targetBeanName"</span> value=<span class=code-quote>"__shoppingCart"</span>/&gt;</span>
<span class=code-tag>&lt;property name=<span class=code-quote>"scopeMap"</span>&gt;</span>
<span class=code-tag>&lt;bean class=<span class=code-quote>"org.springframework.web.context.scope.SessionScopeMap"</span>/&gt;</span>
<span class=code-tag>&lt;/property&gt;</span>
<span class=code-tag>&lt;/bean&gt;</span>
&lt;bean id=<span class=code-quote>"__shoppingCart"</span> class=<span class=code-quote>"com.opensymphony.webwork.example.ajax.cart.DefaultCart"</span>
singleton=<span class=code-quote>"false"</span>/&gt;
<span class=code-tag>&lt;/beans&gt;</span></pre>
</div>
</div>
<p>一个使用简化XML方式的shopping cart例子的改良applicationContext.xml显示在下面.</p>
<div class=code>
<div class=codeContent>
<pre class=code-xml><span class=code-tag>&lt;?xml version=<span class=code-quote>"1.0"</span> encoding=<span class=code-quote>"UTF-8"</span>?&gt;</span>
&lt;beans xmlns=<span class=code-quote>"http://www.springframework.org/schema/beans"</span>
<span class=code-keyword>xmlns:xsi</span>=<span class=code-quote>"http://www.w3.org/2001/XMLSchema-instance"</span>
<span class=code-keyword>xmlns:aop</span>=<span class=code-quote>"http://www.springframework.org/schema/aop"</span>
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"&gt;
&lt;bean id=<span class=code-quote>"catalog"</span> class=<span class=code-quote>"com.opensymphony.webwork.example.ajax.catalog.TestCatalog"</span>
singleton=<span class=code-quote>"true"</span>/&gt;
&lt;bean id=<span class=code-quote>"shoppingCart"</span> class=<span class=code-quote>"com.opensymphony.webwork.example.ajax.cart.DefaultCart"</span>
singleton=<span class=code-quote>"true"</span>&gt;
<span class=code-tag>&lt;aop:scope type=<span class=code-quote>"session"</span>/&gt;</span>
<span class=code-tag>&lt;/bean&gt;</span>
<span class=code-tag>&lt;/beans&gt;</span></pre>
</div>
</div>
<p>你还要修改web.xml来包含下面的filter.</p>
<div class=code>
<div class=codeContent>
<pre class=code-xml><span class=code-tag>&lt;filter&gt;</span>
<span class=code-tag>&lt;filter-name&gt;</span>springFilter<span class=code-tag>&lt;/filter-name&gt;</span>
<span class=code-tag>&lt;filter-class&gt;</span>org.springframework.web.filter.RequestContextFilter<span class=code-tag>&lt;/filter-class&gt;</span>
<span class=code-tag>&lt;/filter&gt;</span>
<span class=code-tag>&lt;filter-mapping&gt;</span>
<span class=code-tag>&lt;filter-name&gt;</span>springFilter<span class=code-tag>&lt;/filter-name&gt;</span>
<span class=code-tag>&lt;url-pattern&gt;</span>/*<span class=code-tag>&lt;/url-pattern&gt;</span>
<span class=code-tag>&lt;/filter-mapping&gt;</span></pre>
</div>
</div>
<h2><a name=SpringSessionComponentsWorkarounds-%E4%BD%BF%E7%94%A8%E4%B8%80%E4%B8%AAServletFilter%E6%9D%A5%E5%AE%9A%E5%88%B6TargetSource></a>使用一个ServletFilter来定制 TargetSource</h2>
<p>一个很"clean"的一般是为web应用程序提出的解决方案可以在 <span class=nobr><a href="http://ja-sig.org/" rel=nofollow><u><font color=#0000ff>JA-SIG<sup><img class=rendericon height=7 alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width=7 align=absMiddle border=0></sup></font></u></a></span> 发现. 这个解决方案有很好的文档,可以在 <span class=nobr><a href="https://clearinghouse.ja-sig.org/wiki/display/UPC/Session+Scoped+Beans" rel=nofollow><u><font color=#0000ff>这里<sup><img class=rendericon height=7 alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width=7 align=absMiddle border=0></sup></font></u></a></span> 发现. 在后面你可以找到一个采用它的方法.</p>
<h1><a name=SpringSessionComponentsWorkarounds-XWork%2FWebWork%E7%89%B9%E6%AE%8A%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88></a>XWork/WebWork 特殊的解决方案</h1>
<h2><a name=SpringSessionComponentsWorkarounds-%E5%89%8D%E8%A8%80></a>前言</h2>
<p>WebWork是基于XWork的,而XWork不是绑定到web层的.因此当处理session会话范围的对象时,WW用户可能会使用XWork的session抽象特性来保持他们的应用程序独立于web环境.这也就是我们为什么要讨论一些下面列出的XW/WW特定的解决方案.</p>
<h2><a name=SpringSessionComponentsWorkarounds-%E5%AE%9A%E5%88%B6TargetSource%2CWebWork%E7%9A%84%E6%96%B9%E6%B3%95></a>定制 TargetSource, WebWork 的方法</h2>
<p>这是一个上面指出的TargetSource解决方案的一个改良版本,它和已有的WebWork session相结合,不需要一个额外的filter或者listener.使用方法是几乎相似的,为你的对象创建一个接口,并确保你使用的总是接口而不是具体的实现,否则自动装配会失败.你可以研究 <a title="WebWorkTargetSource Shopping Cart Example" href="http://wiki.javascud.org/display/ww2cndoc/WebWorkTargetSource+Shopping+Cart+Example"><u><font color=#0000ff>WebWorkTargetSource Shopping Cart Example</font></u></a> 以找到更多的关于这个如何工作的信息.</p>
<div class=code style="BORDER-TOP-STYLE: solid; BORDER-RIGHT-STYLE: solid; BORDER-LEFT-STYLE: solid; BORDER-BOTTOM-STYLE: solid">
<div class=codeHeader style="BORDER-BOTTOM-STYLE: solid"><strong>WebWorkTargetSource.java</strong></div>
<div class=codeContent>
<pre class=code-java><span class=code-keyword>package</span> org.tuxbot.webwork.spring;
/* Portions Copyright 2005 The JA-SIG Collaborative.  All rights reserved.
*  See license distributed with <span class=code-keyword>this</span> file and
*  available online at http:<span class=code-comment>//www.uportal.org/license.html
</span> */
<span class=code-keyword>import</span> org.apache.commons.logging.Log;
<span class=code-keyword>import</span> org.apache.commons.logging.LogFactory;
<span class=code-keyword>import</span> org.springframework.aop.target.AbstractPrototypeBasedTargetSource;
<span class=code-keyword>import</span> org.springframework.beans.factory.DisposableBean;
<span class=code-keyword>import</span> com.opensymphony.xwork.ActionContext;
<span class=code-keyword>import</span> java.util.Map;
/**
* This target source is to be used in collaberation with WebWork.
* The target source binds the target bean to the Session retrieved from
* WebWork. By <span class=code-keyword>default</span> the bean is bound to the session
* using the name of the target bean as part of the key. This can be overridden by setting
* the &lt;code&gt;sessionKey&lt;/code&gt; property to a not <span class=code-keyword>null</span> value.
*
* @author Eric Dalquist &lt;a href=<span class=code-quote>"mailto:edalquist@unicon.net"</span>&gt;edalquist@unicon.net&lt;/a&gt;
* @author Eric Molitor &lt;a href=<span class=code-quote>"mailto:eric@tuxbot.com"</span>&gt;eric@tuxbot.com&lt;/a&gt;
* @version 1.0
*/
<span class=code-keyword>public</span> class WebWorkTargetSource <span class=code-keyword>extends</span> AbstractPrototypeBasedTargetSource <span class=code-keyword>implements</span> DisposableBean {
<span class=code-keyword>private</span> <span class=code-keyword>final</span> <span class=code-keyword>static</span> Log LOG = LogFactory.getLog(WebWorkTargetSource.class);
<span class=code-keyword>private</span> <span class=code-keyword>transient</span> <span class=code-object>Object</span> noSessionInstance = <span class=code-keyword>null</span>;
<span class=code-keyword>private</span> <span class=code-object>String</span> sessionKey = <span class=code-keyword>null</span>;
<span class=code-keyword>private</span> <span class=code-object>String</span> compiledSessionKey = <span class=code-keyword>null</span>;
<span class=code-keyword>public</span> WebWorkTargetSource() {
<span class=code-keyword>this</span>.updateBeanKey();
}
/**
* @<span class=code-keyword>return</span> Returns the sessionKey.
*/
<span class=code-keyword>public</span> <span class=code-object>String</span> getSessionKey() {
<span class=code-keyword>return</span> <span class=code-keyword>this</span>.sessionKey;
}
/**
* @param sessionKey The sessionKey to set.
*/
<span class=code-keyword>public</span> void setSessionKey(<span class=code-object>String</span> sessionKey) {
<span class=code-keyword>this</span>.sessionKey = sessionKey;
<span class=code-keyword>this</span>.updateBeanKey();
}
/**
* @see org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource#setTargetBeanName(java.lang.<span class=code-object>String</span>)
*/
<span class=code-keyword>public</span> void setTargetBeanName(<span class=code-object>String</span> targetBeanName) {
<span class=code-keyword>super</span>.setTargetBeanName(targetBeanName);
<span class=code-keyword>this</span>.updateBeanKey();
}
/**
* @see org.springframework.aop.TargetSource#getTarget()
*/
<span class=code-keyword>public</span> <span class=code-object>Object</span> getTarget() <span class=code-keyword>throws</span> Exception {
<span class=code-keyword>final</span> Map session = ActionContext.getContext().getSession();
<span class=code-keyword>if</span> (session == <span class=code-keyword>null</span>) {
LOG.warn(<span class=code-quote>"No Session found <span class=code-keyword>for</span> thread '"</span> + <span class=code-object>Thread</span>.currentThread().getName() + <span class=code-quote>"'"</span>);
<span class=code-keyword>if</span> (<span class=code-keyword>this</span>.noSessionInstance == <span class=code-keyword>null</span>) {
<span class=code-keyword>this</span>.noSessionInstance = <span class=code-keyword>this</span>.newPrototypeInstance();
<span class=code-keyword>if</span> (LOG.isDebugEnabled()) {
LOG.debug(<span class=code-quote>"Created instance of '"</span> + <span class=code-keyword>this</span>.getTargetBeanName() + <span class=code-quote>"', not bound to any webWorkSession."</span>);
}
}
<span class=code-keyword>else</span> {
<span class=code-keyword>if</span> (LOG.isDebugEnabled()) {
LOG.debug(<span class=code-quote>"Found instance of '"</span> + <span class=code-keyword>this</span>.getTargetBeanName() + <span class=code-quote>"', not bound to any webWorkSession."</span>);
}
}
<span class=code-keyword>return</span> <span class=code-keyword>this</span>.noSessionInstance;
}
<span class=code-keyword>else</span> {
<span class=code-object>String</span> beanKey = <span class=code-keyword>this</span>.compiledSessionKey;
<span class=code-object>Object</span> instance = session.get(beanKey);
<span class=code-keyword>if</span> (instance == <span class=code-keyword>null</span>) {
instance = <span class=code-keyword>this</span>.newPrototypeInstance();
session.put(beanKey, instance);
<span class=code-keyword>if</span> (LOG.isDebugEnabled()) {
LOG.debug(<span class=code-quote>"Created instance of '"</span> + <span class=code-keyword>this</span>.getTargetBeanName() + <span class=code-quote>"', bound to webWorkSession <span class=code-keyword>for</span> '"</span>
+ <span class=code-object>Thread</span>.currentThread().getName() + <span class=code-quote>"' using key '"</span> + beanKey + <span class=code-quote>"'."</span>);
}
}
<span class=code-keyword>else</span> <span class=code-keyword>if</span> (LOG.isDebugEnabled()) {
LOG.debug(<span class=code-quote>"Found instance of '"</span> + <span class=code-keyword>this</span>.getTargetBeanName() + <span class=code-quote>"', bound to webWorkSession <span class=code-keyword>for</span> '"</span>
+ <span class=code-object>Thread</span>.currentThread().getName() + <span class=code-quote>"' using key '"</span> + beanKey + <span class=code-quote>"'."</span>);
}
<span class=code-keyword>return</span> instance;
}
}
/**
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
<span class=code-keyword>public</span> void destroy() <span class=code-keyword>throws</span> Exception {
<span class=code-keyword>if</span> (<span class=code-keyword>this</span>.noSessionInstance != <span class=code-keyword>null</span> &amp;&amp; <span class=code-keyword>this</span>.noSessionInstance <span class=code-keyword>instanceof</span> DisposableBean) {
<span class=code-keyword>if</span> (LOG.isDebugEnabled()) {
LOG.debug(<span class=code-quote>"Destroying sessionless bean instance '"</span> + <span class=code-keyword>this</span>.noSessionInstance + <span class=code-quote>"'"</span>);
}
((DisposableBean)<span class=code-keyword>this</span>.noSessionInstance).destroy();
}
}
/**
* Generates the key to store the bean in the session with.
*/
<span class=code-keyword>private</span> void updateBeanKey() {
<span class=code-keyword>if</span> (<span class=code-keyword>this</span>.sessionKey == <span class=code-keyword>null</span>) {
<span class=code-keyword>final</span> <span class=code-object>StringBuffer</span> buff = <span class=code-keyword>new</span> <span class=code-object>StringBuffer</span>();
buff.append(<span class=code-keyword>this</span>.getClass().getName());
buff.append(<span class=code-quote>"_"</span>);
buff.append(<span class=code-keyword>this</span>.getTargetBeanName());
<span class=code-keyword>this</span>.compiledSessionKey = buff.toString();
}
<span class=code-keyword>else</span> {
<span class=code-keyword>this</span>.compiledSessionKey = <span class=code-keyword>this</span>.sessionKey;
}
}
}</pre>
</div>
</div>
<h2><a name=SpringSessionComponentsWorkarounds-%E8%87%AA%E5%AE%9A%E4%B9%89ApplicationContext%E5%AE%9E%E7%8E%B0></a>自定义 ApplicationContext 实现</h2>
<p><strong>TODO: Document</strong></p>
<h2><a name=SpringSessionComponentsWorkarounds-%E8%87%AA%E5%AE%9A%E4%B9%89WW%2FXWObjectFactory></a>自定义 WW/XW ObjectFactory</h2>
<p><strong>TODO: Document</strong></p>
<h2><a name=SpringSessionComponentsWorkarounds-Session%E6%94%AF%E6%8C%81%E7%9A%84BeanFactory></a>Session 支持的 Bean Factory</h2>
<p>这个想法就是简单地创建一个 获取/创建(session) 的bean factory:</p>
<div class=code style="BORDER-TOP-STYLE: solid; BORDER-RIGHT-STYLE: solid; BORDER-LEFT-STYLE: solid; BORDER-BOTTOM-STYLE: solid">
<div class=codeHeader style="BORDER-BOTTOM-STYLE: solid"><strong>SessionBackedBeanFactory.java</strong></div>
<div class=codeContent>
<pre class=code-java><span class=code-keyword>package</span> net.itneering.core.spring.session;
<span class=code-keyword>import</span> org.springframework.beans.BeansException;
<span class=code-keyword>import</span> org.springframework.beans.factory.BeanFactory;
<span class=code-keyword>import</span> org.springframework.beans.factory.BeanFactoryAware;
<span class=code-keyword>import</span> com.opensymphony.xwork.ActionContext;
<span class=code-keyword>import</span> java.util.Map;
<span class=code-keyword>import</span> java.io.Serializable;
/**
* SessionBackedBeanFactory tries to lookup beans by name in XWork session. If not found,
* it tries to instantiate <span class=code-keyword>new</span> bean and attaches it to said session.
*
* @author &lt;a href=<span class=code-quote>"mailto:gielen@it-neering.net"</span>&gt;Rene Gielen&lt;/a&gt;
*/
<span class=code-keyword>public</span> class SessionBackedBeanFactory <span class=code-keyword>implements</span> Serializable, BeanFactoryAware {
BeanFactory beanFactory = <span class=code-keyword>null</span>;
/**
* Find a component by name in session scoped storage implementation. If not found, <span class=code-keyword>try</span> to instantiate <span class=code-keyword>new</span> one by
* {@link org.springframework.beans.factory.BeanFactory#getBean(<span class=code-object>String</span>)}. Then found component will be attached
* to session store implementation.
*
* @param componentName
* @<span class=code-keyword>return</span> The requested component, <span class=code-keyword>if</span> found.
*/
<span class=code-keyword>public</span> <span class=code-object>Object</span> getSessionComponent( <span class=code-object>String</span> componentName ) {
<span class=code-object>Object</span> result = getSession().get(componentName);
<span class=code-keyword>if</span> ( result == <span class=code-keyword>null</span> ) {
result = beanFactory.getBean(componentName);
storeComponent(componentName, result);
}
<span class=code-keyword>return</span> result;
}
<span class=code-keyword>public</span> void storeComponent(<span class=code-object>String</span> componentName, <span class=code-object>Object</span> component ) {
getSession().put(componentName, component);
}
/**
* Actual implementation of the session scoped storage Map.
* Lookup {@link com.opensymphony.xwork.ActionContext#getSession()}.
*
* @<span class=code-keyword>return</span> The Map <span class=code-keyword>for</span> keeping session objects.
*/
<span class=code-keyword>public</span> Map getSession() {
<span class=code-keyword>return</span> ActionContext.getContext().getSession();
}
/**
* Callback that supplies the owning factory to a bean instance.
* &lt;p&gt;Invoked after population of normal bean properties but before an init
* callback like InitializingBean's afterPropertiesSet or a custom init-method.
*
* @param beanFactory owning BeanFactory (may not be <span class=code-keyword>null</span>).
*                    The bean can immediately call methods on the factory.
*
* @<span class=code-keyword>throws</span> org.springframework.beans.BeansException
*          in <span class=code-keyword>case</span> of initialization errors
* @see org.springframework.beans.factory.BeanInitializationException
*/
<span class=code-keyword>public</span> void setBeanFactory( BeanFactory beanFactory ) <span class=code-keyword>throws</span> BeansException {
<span class=code-keyword>this</span>.beanFactory = beanFactory;
}
}</pre>
</div>
</div>
<p>示例的applicationContext 设置(注意session会话范围的bean设置为singleton="false"):</p>
<div class=code style="BORDER-TOP-STYLE: solid; BORDER-RIGHT-STYLE: solid; BORDER-LEFT-STYLE: solid; BORDER-BOTTOM-STYLE: solid">
<div class=codeHeader style="BORDER-BOTTOM-STYLE: solid"><strong>applicationContext.xml</strong></div>
<div class=codeContent>
<pre class=code-xml><span class=code-tag>&lt;?xml version=<span class=code-quote>"1.0"</span> encoding=<span class=code-quote>"UTF-8"</span>?&gt;</span>
<span class=code-tag>&lt;!DOCTYPE beans PUBLIC <span class=code-quote>"-//SPRING//DTD BEAN//EN"</span> <span class=code-quote>"http://www.springframework.org/dtd/spring-beans.dtd"</span>&gt;</span>
<span class=code-tag>&lt;beans default-autowire=<span class=code-quote>"byName"</span>&gt;</span>
<span class=code-tag>&lt;bean id=<span class=code-quote>"sessionBeanProxy"</span> class=<span class=code-quote>"net.itneering.core.spring.session.SessionBackedBeanFactory"</span> singleton=<span class=code-quote>"true"</span>/&gt;</span>
<span class=code-tag>&lt;bean id=<span class=code-quote>"securityContextComponent"</span> class=<span class=code-quote>"net.itneering.security.component.DefaultSecurityContextComponent"</span> singleton=<span class=code-quote>"false"</span> /&gt;</span>
<span class=code-tag>&lt;/beans&gt;</span></pre>
</div>
</div>
<p>使用它的例子action:</p>
<div class=code style="BORDER-TOP-STYLE: solid; BORDER-RIGHT-STYLE: solid; BORDER-LEFT-STYLE: solid; BORDER-BOTTOM-STYLE: solid">
<div class=codeHeader style="BORDER-BOTTOM-STYLE: solid"><strong>SecurityAwareAction.java</strong></div>
<div class=codeContent>
<pre class=code-java><span class=code-keyword>package</span> net.itneering.xwork.action;
<span class=code-keyword>import</span> com.opensymphony.xwork.ActionSupport;
<span class=code-keyword>import</span> net.itneering.core.spring.session.SessionBackedBeanFactory;
<span class=code-keyword>import</span> net.itneering.security.component.DefaultSecurityContextComponent;
/**
* Simple sessionBeanProxy aware action.
*
* @author &lt;a href=<span class=code-quote>"mailto:gielen@it-neering.net"</span>&gt;Rene Gielen&lt;/a&gt;
* @version $Revision: 1.1 $
*/
<span class=code-keyword>public</span> class SecurityAwareAction <span class=code-keyword>extends</span> ActionSupport <span class=code-keyword>implements</span> PrincipalAware {
<span class=code-keyword>private</span> <span class=code-keyword>static</span> <span class=code-keyword>final</span> Logger log = Logger.getLogger(SecurityAwareAction.class);
<span class=code-keyword>protected</span> SessionBackedBeanFactory sessionBeanProxy;
/**
* For Spring wiring usage.
*
* @param sessionBeanProxy The sessionBeanProxyto use.
*/
<span class=code-keyword>public</span> void setSessionBeanProxy( SessionBackedBeanFactory sessionBeanProxy ) {
<span class=code-keyword>this</span>.sessionBeanProxy = sessionBeanProxy;
}
/**
* Getter <span class=code-keyword>for</span> actions security context.
*
* @<span class=code-keyword>return</span> The securityContextComponent set by IoC.
*/
<span class=code-keyword>public</span> SecurityContextComponent getSecurityContextComponent() {
<span class=code-keyword>return</span> sessionBeanProxy!= <span class=code-keyword>null</span> ? sessionBeanProxy.getSessionComponent(<span class=code-quote>"securityContextComponent"</span>) : <span class=code-keyword>null</span>;
}
/**
* Get the current User Principal <span class=code-keyword>for</span> <span class=code-keyword>this</span> session.
*
* @<span class=code-keyword>return</span> The User Principal.
*/
<span class=code-keyword>public</span> UserEntity getPrincipal() {
<span class=code-keyword>try</span> {
<span class=code-keyword>return</span> getSecurityContextComponent().getPrincipal();
} <span class=code-keyword>catch</span> ( NullPointerException e ) {
<span class=code-keyword>return</span> <span class=code-keyword>null</span>;
}
}
...
}</pre>
</div>
</div>
<p>对于使用广泛的session会话范围组件,你可能为了方便而集成SessionBackedBeanFactory:</p>
<div class=code style="BORDER-TOP-STYLE: solid; BORDER-RIGHT-STYLE: solid; BORDER-LEFT-STYLE: solid; BORDER-BOTTOM-STYLE: solid">
<div class=codeHeader style="BORDER-BOTTOM-STYLE: solid"><strong>SecurityAwareSessionBeanProxy.java</strong></div>
<div class=codeContent>
<pre class=code-java><span class=code-keyword>package</span> net.itneering.security.component;
<span class=code-keyword>import</span> net.itneering.core.spring.session.SessionBackedBeanFactory;
/**
* SecurityAwareSessionBeanProxy.
*
* @author &lt;a href=<span class=code-quote>"mailto:gielen@it-neering.net"</span>&gt;Rene Gielen&lt;/a&gt;
*/
<span class=code-keyword>public</span> class SecurityAwareSessionBeanProxy <span class=code-keyword>extends</span> SessionBackedBeanFactory {
<span class=code-object>String</span> securityContextComponentName = <span class=code-quote>"securityContextComponent"</span>;
/**
* Make component name configurable by spring setup
*/
<span class=code-keyword>public</span> void setSecurityContextComponentName( <span class=code-object>String</span> securityContextComponentName ) {
<span class=code-keyword>this</span>.securityContextComponentName = securityContextComponentName;
}
<span class=code-keyword>public</span> SecurityContextComponent getSecurityContextComponent() {
<span class=code-keyword>return</span> (SecurityContextComponent) getSessionComponent(securityContextComponentName);
}
}</pre>
</div>
</div>
<p>同样示例的 applicationContext 配置:</p>
<div class=code style="BORDER-TOP-STYLE: solid; BORDER-RIGHT-STYLE: solid; BORDER-LEFT-STYLE: solid; BORDER-BOTTOM-STYLE: solid">
<div class=codeHeader style="BORDER-BOTTOM-STYLE: solid"><strong>applicationContext2.xml</strong></div>
<div class=codeContent>
<pre class=code-xml><span class=code-tag>&lt;?xml version=<span class=code-quote>"1.0"</span> encoding=<span class=code-quote>"UTF-8"</span>?&gt;</span>
<span class=code-tag>&lt;!DOCTYPE beans PUBLIC <span class=code-quote>"-//SPRING//DTD BEAN//EN"</span> <span class=code-quote>"http://www.springframework.org/dtd/spring-beans.dtd"</span>&gt;</span>
<span class=code-tag>&lt;beans default-autowire=<span class=code-quote>"byName"</span>&gt;</span>
<span class=code-tag>&lt;bean id=<span class=code-quote>"mySecurityContextComponent"</span> class=<span class=code-quote>"net.itneering.security.component.DefaultSecurityContextComponent"</span> singleton=<span class=code-quote>"false"</span> /&gt;</span>
<span class=code-tag>&lt;bean id=<span class=code-quote>"sessionBeanProxy"</span> class=<span class=code-quote>"net.itneering.security.component.SecurityAwareSessionBeanProxy"</span> singleton=<span class=code-quote>"true"</span>&gt;</span>
<span class=code-tag>&lt;property name=<span class=code-quote>"securityContextComponentName"</span> value=<span class=code-quote>"mySecurityContextComponent"</span> /&gt;</span>
<span class=code-tag>&lt;/bean&gt;</span>
<span class=code-tag>&lt;/beans&gt;</span></pre>
</div>
</div>
<p>使用的action示例:</p>
<div class=code style="BORDER-TOP-STYLE: solid; BORDER-RIGHT-STYLE: solid; BORDER-LEFT-STYLE: solid; BORDER-BOTTOM-STYLE: solid">
<div class=codeHeader style="BORDER-BOTTOM-STYLE: solid"><strong>SecurityAwareAction2.java</strong></div>
<div class=codeContent>
<pre class=code-java><span class=code-keyword>package</span> net.itneering.xwork.action;
<span class=code-keyword>import</span> com.opensymphony.xwork.ActionSupport;
<span class=code-keyword>import</span> net.itneering.security.component.SecurityAwareSessionBeanProxy;
<span class=code-keyword>import</span> net.itneering.security.component.DefaultSecurityContextComponent;
/**
* Simple sessionBeanProxy aware action.
*
* @author &lt;a href=<span class=code-quote>"mailto:gielen@it-neering.net"</span>&gt;Rene Gielen&lt;/a&gt;
* @version $Revision: 1.1 $
*/
<span class=code-keyword>public</span> class SecurityAwareAction <span class=code-keyword>extends</span> ActionSupport <span class=code-keyword>implements</span> PrincipalAware {
<span class=code-keyword>private</span> <span class=code-keyword>static</span> <span class=code-keyword>final</span> Logger log = Logger.getLogger(SecurityAwareAction.class);
<span class=code-keyword>protected</span> SecurityAwareSessionBeanProxy sessionBeanProxy;
/**
* For Spring wiring usage.
*
* @param sessionBeanProxy The sessionBeanProxy to use.
*/
<span class=code-keyword>public</span> void setSessionBeanProxy( SecurityAwareSessionBeanProxy sessionBeanProxy ) {
<span class=code-keyword>this</span>.sessionBeanProxy = sessionBeanProxy;
}
/**
* Get the current User Principal <span class=code-keyword>for</span> <span class=code-keyword>this</span> session.
*
* @<span class=code-keyword>return</span> The User Principal.
*/
<span class=code-keyword>public</span> UserEntity getPrincipal() {
<span class=code-keyword>try</span> {
<span class=code-keyword>return</span> sessionBeanProxy.getSecurityContextComponent().getPrincipal();
} <span class=code-keyword>catch</span> ( NullPointerException e ) {
<span class=code-keyword>return</span> <span class=code-keyword>null</span>;
}
}
...
}</pre>
</div>
</div>
<p>就像前面所说,这个解决方案是非常简单的.你不需要绑定到web层,配置也实在简单,也没有必要在applicationContext.xml里面定义proxy.</p>
<p><font color=red>主要的缺点就是你不能直接装配session会话范围的bean到你的action,你必须间接使用session支持的bean factory.而且,当你处理XWork session抽象层的时候,你经常必须关心来设置一个action context.</font></p>
<h2><a name=SpringSessionComponentsWorkarounds-%E8%87%AA%E5%8A%A8%E4%BB%A3%E7%90%86session%E6%94%AF%E6%8C%81%E7%9A%84%E7%BB%84%E4%BB%B6Factory></a>自动代理session支持的组件Factory</h2>
<p>有人有这样一个实现吗? (Eric Molitor)</p>
<p>这个意图有一点不同,因此我试图澄清标题.好主意,虽然... (Rene Gielen).</p>
<p><font color=red>译注:下面这段就不翻译了 </font></p>
<p>The theory here is to create a custom Pointcut class that utilizes the ComponentConfiguration retrieved from the DefaultComponentManager (which loads the Component list from components.xml). The getClassFilter() matches anything that implements one of the Components in the ComponentConfiguration. The Pointcut is then registered as an advisor for all beans (AutoProxy via Springs DefaultAdvisorAutoProxyCreator). The Advice implementation looks at which Component is implmented and fetches the apporiate value out of the Session and calls the Components setter method. </p>
<p><strong>TODO: Document, create example</strong></p>
<img src ="http://www.blogjava.net/livery/aggbug/125560.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/livery/" target="_blank">心情经纬</a> 2007-06-21 14:19 <a href="http://www.blogjava.net/livery/articles/125560.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WebWork中的spring(1)</title><link>http://www.blogjava.net/livery/articles/125558.html</link><dc:creator>心情经纬</dc:creator><author>心情经纬</author><pubDate>Thu, 21 Jun 2007 06:17:00 GMT</pubDate><guid>http://www.blogjava.net/livery/articles/125558.html</guid><wfw:comment>http://www.blogjava.net/livery/comments/125558.html</wfw:comment><comments>http://www.blogjava.net/livery/articles/125558.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/livery/comments/commentRss/125558.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/livery/services/trackbacks/125558.html</trackback:ping><description><![CDATA[<font color=#ff0000>随着其他东西,Spring同时也是一个控制反转框架.(原文:Spring is, among other things, an Inversion of Control framework.)</font> 它在WebWork 2.2中是推荐的IoC容器.你可以在<span class=nobr><a href="http://www.springframework.org/" rel=nofollow><u><font color=#0000ff>http://www.springframework.org<sup><img class=rendericon height=7 alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width=7 align=absMiddle border=0></sup></font></u></a></span>找到更多关于Spring的信息.
<table class=noteMacro cellSpacing=8 cellPadding=5 width="85%" align=center border=0>
    <colgroup>
    <col width=24>
    <col></colgroup>
    <tbody>
        <tr>
            <td vAlign=top><img height=16 alt="" src="http://wiki.javascud.org/images/icons/emoticons/warning.gif" width=16 align=absMiddle border=0></td>
            <td>此部分仅包括 <em>支持</em> Spring集成的技术.当然,还有很多其他的方法把Spring和WebWork绑定在一起.请查看<a title="Other Spring Integration" href="http://wiki.javascud.org/display/ww2cndoc/Other+Spring+Integration"><u><font color=#800080>其他集成Spring的方法</font></u></a>了解更多信息.<font color=red> 注意其他方法的任何一个都不被支持,而且可能随时发生变化!(原文:Note that <em>none</em> of the other methods are currently supported and could change at any time!) </font></td>
        </tr>
    </tbody>
</table>
<h1><a name=Spring-%E5%BC%80%E5%90%AFSpring%E9%9B%86%E6%88%90></a>开启Spring集成</h1>
<p>在WebWork中开启Spring支持是一件简单的事情,只需要安装最新的Spring的jar文件到你的classpath,然后添加下面的行到<a title=webwork.properties href="http://wiki.javascud.org/display/ww2cndoc/webwork.properties"><u><font color=#0000ff>webwork.properties</font></u></a>文件:</p>
<div class=code>
<div class=codeContent>
<pre class=code-java>webwork.objectFactory = spring</pre>
</div>
</div>
<p>如果你想要改变缺省的自动装配模式,也就是自动按照name装配(例如,使用你的bean属性相同的名字去查找在Spring里定义的bean),你也需要在你的<a title=webwork.properties href="http://wiki.javascud.org/display/ww2cndoc/webwork.properties"><u><font color=#0000ff>webwork.properties</font></u></a>中进行一下设置:</p>
<div class=code>
<div class=codeContent>
<pre class=code-java>webwork.objectFactory.spring.autoWire = type</pre>
</div>
</div>
<p>这个设置的选项包括:</p>
<table class=confluenceTable>
    <tbody>
        <tr>
            <td class=confluenceTd>name </td>
            <td class=confluenceTd>按照你的action的属性的名字和Spring里的bean的名字,如果匹配就自动装配. <strong>这是缺省的</strong> </td>
        </tr>
        <tr>
            <td class=confluenceTd>type </td>
            <td class=confluenceTd>按照你的action的属性的类型,在Spring注册的bean中查找,如果相同就自动装配.这需要你在Spring中仅注册了一个此类型的bean </td>
        </tr>
        <tr>
            <td class=confluenceTd>auto </td>
            <td class=confluenceTd>Spring会试图自动监测来找到最好的方法自动装配你的action </td>
        </tr>
        <tr>
            <td class=confluenceTd>constructor </td>
            <td class=confluenceTd>Spring会自动装配bean的构造函数的参数 </td>
        </tr>
    </tbody>
</table>
<p>在这种情况下,所有的对象都至少会试图使用Spring来创建.如果它们不能被Spring创建,然后WebWork会自己创建对象.接下来,你需要在web.xml打开Spring的Listener:</p>
<div class=code>
<div class=codeContent>
<pre class=code-xml><span class=code-tag>&lt;listener&gt;</span>
<span class=code-tag>&lt;listener-class&gt;</span>org.springframework.web.context.ContextLoaderListener<span class=code-tag>&lt;/listener-class&gt;</span>
<span class=code-tag>&lt;/listener&gt;</span></pre>
</div>
</div>
<table class=tipMacro cellSpacing=8 cellPadding=5 width="85%" align=center border=0>
    <colgroup>
    <col width=24>
    <col></colgroup>
    <tbody>
        <tr>
            <td vAlign=top><img height=16 alt="" src="http://wiki.javascud.org/images/icons/emoticons/check.gif" width=16 align=absMiddle border=0></td>
            <td><strong class=strong>需要更多的 ApplicationContext 配置文件?</strong><br>
            <p>既然使用一个标准的Listener来集成Spring,它可以被配置来支持除了applicationContext.xml之外的配置文件.把下面的几行添加到你的web.xml会让Spring的ApplicationContext从所有匹配给定的规则的文件中初始化:</p>
            <div class=code>
            <div class=codeContent>
            <pre class=code-xml><span class=code-tag><span class=code-comment>&lt;!-- Context Configuration locations for Spring XML files --&gt;</span></span>
            <span class=code-tag>&lt;context-param&gt;</span>
            <span class=code-tag>&lt;param-name&gt;</span>contextConfigLocation<span class=code-tag>&lt;/param-name&gt;</span>
            <span class=code-tag>&lt;param-value&gt;</span>/WEB-INF/applicationContext-*.xml,classpath*:applicationContext-*.xml<span class=code-tag>&lt;/param-value&gt;</span>
            <span class=code-tag>&lt;/context-param&gt;</span></pre>
            </div>
            </div>
            <p>浏览Spring的文件查看这个参数的详细描述.</p>
            </td>
        </tr>
    </tbody>
</table>
<h1><a name=Spring-Spring%E9%85%8D%E7%BD%AE%E4%B8%BE%E4%BE%8B></a>Spring配置举例</h1>
<p>在这里,你可以添加标准的Spring配置文件 <strong>WEB-INF/applicationContext.xml</strong> .这个配置文件的一个例子如下:</p>
<div class=code>
<div class=codeContent>
<pre class=code-xml><span class=code-tag>&lt;?xml version=<span class=code-quote>"1.0"</span> encoding=<span class=code-quote>"UTF-8"</span>?&gt;</span>
<span class=code-tag>&lt;!DOCTYPE beans PUBLIC <span class=code-quote>"-//SPRING//DTD BEAN//EN"</span> <span class=code-quote>"http://www.springframework.org/dtd/spring-beans.dtd"</span>&gt;</span>
<span class=code-tag>&lt;beans default-autowire=<span class=code-quote>"autodetect"</span>&gt;</span>
<span class=code-tag>&lt;bean id=<span class=code-quote>"personManager"</span> class=<span class=code-quote>"com.acme.PersonManager"</span>/&gt;</span>
...
<span class=code-tag>&lt;/beans&gt;</span></pre>
</div>
</div>
<h1><a name=Spring-%E4%BB%8E%E5%86%85%E7%BD%AE%E7%9A%84IoC%E5%88%87%E6%8D%A2%E5%88%B0Spring></a>从内置的IoC切换到Spring</h1>
<p>切换是非常简单的.Spring的设置就像上面描述的已经完成.为了完成迁移,你还需要<br>Switching is quite easy. Spring setup is done as described above. To complete migration, you will have to</p>
<ol>
    <li>适当地转换你配置的组件,从 components.xml 到 applicationContext.xml. 然后你可以安全地删除 components.xml.
    <li>在<a title=xwork.xml href="http://wiki.javascud.org/display/ww2cndoc/xwork.xml"><u><font color=#0000ff>xwork.xml</font></u></a>中,从你的拦截器stack里移除 <a title="Component Interceptor" href="http://wiki.javascud.org/display/ww2cndoc/Component+Interceptor"><u><font color=#0000ff>组件拦截器</font></u></a>. 虽然保留它在那里不会带来任何影响,但是从现在开始它只不过是多余的了. </li>
</ol>
<table class=noteMacro cellSpacing=8 cellPadding=5 width="85%" align=center border=0>
    <colgroup>
    <col width=24>
    <col></colgroup>
    <tbody>
        <tr>
            <td vAlign=top><img height=16 alt="" src="http://wiki.javascud.org/images/icons/emoticons/warning.gif" width=16 align=absMiddle border=0></td>
            <td><strong class=strong>Session 会话范围和Spring</strong><br>
            <p>Spring &lt;= 1.3 不支持 session 会话范围的组件. Spring 2.0 版本会增加这个支持, 并且在对Spring 2.0M3 (beta) 的测试中被报告可以工作的很好. 请查阅 <a title="Spring Session Components Workarounds" href="http://wiki.javascud.org/display/ww2cndoc/Spring+Session+Components+Workarounds"><u><font color=#800080>和Spring的Session组件一起工作</font></u></a> 来了解这个话题的更详细信息.</p>
            </td>
        </tr>
    </tbody>
</table>
<h1><a name=Spring-%E4%BB%8ESpring%E4%B8%AD%E5%88%9D%E5%A7%8B%E5%8C%96Action></a>从Spring中初始化 Action</h1>
<p>正常情况下,在xwork.xml里你可以为每个action指定类.当你使用SpringObjectFactory(就像上面配置的)时WebWork会请求Spring来创建action并按照缺省指定的自动装配行为来装配依赖的组件.SpringObjectFactory 也会设置所有的bean的后置处理程序(post processors)来完成类似对你的Action进行事务,安全等等方面的代理的事情.Spring可以不依赖外在的配置来自动确定.对于大多数的使用,这就是你所全部需要的了,用来配置你的action,设置它们获取服务和依赖组件.</p>
<table class=tipMacro cellSpacing=8 cellPadding=5 width="85%" align=center border=0>
    <colgroup>
    <col width=24>
    <col></colgroup>
    <tbody>
        <tr>
            <td vAlign=top><img height=16 alt="" src="http://wiki.javascud.org/images/icons/emoticons/check.gif" width=16 align=absMiddle border=0></td>
            <td>我们 <strong>强烈</strong> 推荐你找到一种声明式的方法来让Spring知道为你的action提供什么.这包括让你的bean能够自动装配,无论是把你的Action里的依赖的属性命名为和Spring应该提供的Bean的名字一致(这允许基于名字的自动装配),或者使用by type方式的自动装配,也就是在注册到Spring的Bean中需要的类型仅拥有一个.也可以包括使用JDK5的标准来声明事务和安全需求,而不是必须在你的Spring配置里明确设置代理.如果你能找到方法让Spring在没有任何明确的配置(在_applicationContext.xml_中)的情况下知道需要为你的action做什么,那么你就不需要在两个地方维护这个配置了. </td>
        </tr>
    </tbody>
</table>
<p>However, sometimes you might want the bean to be completely managed by Spring. This is useful, for example, if you wish to apply more complex AOP or Spring-enabled technologies, such as Acegi, to your beans. To do this, all you have to do is configure the bean in your Spring <strong>applicationContext.xml</strong> and then <em>change</em> the class attribute from your WebWork action in the <em>xwork.xml</em> to use the bean name defined in Spring instead of the class name. </p>
<p>当然,有时候你可能想要Spring完全来管理bean.这是有实际意义的,例如,如果你想要为你的bean设置更复杂的AOP或者Spring相关的技术,例如Acegi.为了达到这个目的,你所有必须要做的事情就是在Spring的 <strong>applicationContext.xml</strong> 里配置你的bean,然后在 <em>xwork.xml</em> 里改变你的WebWork action的类属性来使用在Spring里面定义的bean的名字,而不再使用类名.</p>
<p>你的xwork.xml文件也会改变action类的属性,最后留下的就像这样:</p>
<div class=code>
<div class=codeContent>
<pre class=code-xml><span class=code-tag>&lt;!DOCTYPE xwork PUBLIC <span class=code-quote>"-//OpenSymphony Group//XWork 1.0//EN"</span> <span class=code-quote>"http://www.opensymphony.com/xwork/xwork-1.1.dtd"</span>&gt;</span>
<span class=code-tag>&lt;xwork&gt;</span>
<span class=code-tag>&lt;include file=<span class=code-quote>"webwork-default.xml"</span>/&gt;</span>
<span class=code-tag>&lt;package name=<span class=code-quote>"default"</span> extends=<span class=code-quote>"webwork-default"</span>&gt;</span>
<span class=code-tag>&lt;action name=<span class=code-quote>"foo"</span> class=<span class=code-quote>"com.acme.Foo"</span>&gt;</span>
<span class=code-tag>&lt;result&gt;</span>foo.ftl<span class=code-tag>&lt;/result&gt;</span>
<span class=code-tag>&lt;/action&gt;</span>
<span class=code-tag>&lt;/package&gt;</span>
<span class=code-tag>&lt;package name=<span class=code-quote>"secure"</span> namespace=<span class=code-quote>"/secure"</span> extends=<span class=code-quote>"default"</span>&gt;</span>
<span class=code-tag>&lt;action name=<span class=code-quote>"bar"</span> class=<span class=code-quote>"bar"</span>&gt;</span>
<span class=code-tag>&lt;result&gt;</span>bar.ftl<span class=code-tag>&lt;/result&gt;</span>
<span class=code-tag>&lt;/action&gt;</span>
<span class=code-tag>&lt;/package&gt;</span>
<span class=code-tag>&lt;/xwork&gt;</span></pre>
</div>
</div>
<p>在你的 <strong>applicationContext.xml</strong> 里定义了一个名字为 "bar"的Spring的bean.注意 <em>com.acme.Foo</em> 不需要改变,因为它可能是自动装配的.</p>
<p>一个典型的spring的bar的配置可能看起来像下面列出的一样.</p>
<div class=code>
<div class=codeContent>
<pre class=code-xml><span class=code-tag>&lt;?xml version=<span class=code-quote>"1.0"</span> encoding=<span class=code-quote>"UTF-8"</span>?&gt;</span>
<span class=code-tag>&lt;!DOCTYPE beans PUBLIC <span class=code-quote>"-//SPRING//DTD BEAN//EN"</span> <span class=code-quote>"http://www.springframework.org/dtd/spring-beans.dtd"</span>&gt;</span>
<span class=code-tag>&lt;beans default-autowire=<span class=code-quote>"autodetect"</span>&gt;</span>
<span class=code-tag>&lt;bean id=<span class=code-quote>"bar"</span> class=<span class=code-quote>"com.my.BarClass"</span> singleton=<span class=code-quote>"false"</span>/&gt;</span>
...
<span class=code-tag>&lt;/beans&gt;</span></pre>
</div>
</div>
<table class=noteMacro cellSpacing=8 cellPadding=5 width="85%" align=center border=0>
    <colgroup>
    <col width=24>
    <col></colgroup>
    <tbody>
        <tr>
            <td vAlign=top><img height=16 alt="" src="http://wiki.javascud.org/images/icons/emoticons/warning.gif" width=16 align=absMiddle border=0></td>
            <td>
            <p>注意spring配置里面的id属性对应xwork配置里面的class属性. 还要注意在spring配置中,singleton(单态) 属性被设置为false. 这通常是因为WebWork希望基于每个request来创建一个新的action.因此当用到Spring集成时,这会是期望的行为.让Spring的singleton 属性为false就可以做到这一点.</p>
            </td>
        </tr>
    </tbody>
</table>
<p>记住: <strong>这不是必须的</strong>. 仅仅当你希望覆盖在WebWork中创建一个action时的缺省行为,而要用Spring的拦截器,以及Spring不能自动确定IoC策略时,这才是必要的. 要记住一点,WebWork的Spring集成会进行标准的IoC,使用你指定的任何自动装配策略,即使你没有明确第在Spring中映射每个Action.所以通常你不需要做这个,但是知道怎么做当你需要的时候对你是有好处的.</p>
<img src ="http://www.blogjava.net/livery/aggbug/125558.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/livery/" target="_blank">心情经纬</a> 2007-06-21 14:17 <a href="http://www.blogjava.net/livery/articles/125558.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WebWork中的Junit</title><link>http://www.blogjava.net/livery/articles/125557.html</link><dc:creator>心情经纬</dc:creator><author>心情经纬</author><pubDate>Thu, 21 Jun 2007 06:16:00 GMT</pubDate><guid>http://www.blogjava.net/livery/articles/125557.html</guid><wfw:comment>http://www.blogjava.net/livery/comments/125557.html</wfw:comment><comments>http://www.blogjava.net/livery/articles/125557.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/livery/comments/commentRss/125557.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/livery/services/trackbacks/125557.html</trackback:ping><description><![CDATA[<p>你有很多方法可以对WebWork的action进行单元测试.</p>
<h2><a name=JUnit-%E6%9C%80%E7%AE%80%E5%8D%95%E7%9A%84%E5%B0%B1%E6%98%AF%E5%AE%9E%E4%BE%8B%E5%8C%96%E4%BD%A0%E7%9A%84action%2C%E8%B0%83%E7%94%A8setter%E5%B9%B6%E8%B0%83%E7%94%A8execute%28%29.%E8%BF%99%E5%85%81%E8%AE%B8%E4%BD%A0%E7%BB%95%E8%BF%87%E6%89%80%E6%9C%89%E5%A4%8D%E6%9D%82%E7%9A%84%E5%AE%B9%E5%99%A8%E8%AE%BE%E7%BD%AE.></a>最简单的就是实例化你的action,调用setter并调用execute(). 这允许你绕过所有复杂的容器设置.</h2>
<p>从 Petsoar 里拿的:</p>
<div class=code>
<div class=codeContent>
<pre class=code-java><span class=code-keyword>package</span> org.petsoar.actions.inventory;
<span class=code-keyword>import</span> com.mockobjects.constraint.IsEqual;
<span class=code-keyword>import</span> com.mockobjects.dynamic.C;
<span class=code-keyword>import</span> com.mockobjects.dynamic.Mock;
<span class=code-keyword>import</span> com.opensymphony.xwork.Action;
<span class=code-keyword>import</span> junit.framework.TestCase;
<span class=code-keyword>import</span> org.petsoar.pets.Pet;
<span class=code-keyword>import</span> org.petsoar.pets.PetStore;
<span class=code-keyword>public</span> class TestViewPet <span class=code-keyword>extends</span> TestCase {
<span class=code-keyword>private</span> Mock mockPetStore;
<span class=code-keyword>private</span> ViewPet action;
<span class=code-keyword>protected</span> void setUp() <span class=code-keyword>throws</span> Exception {
mockPetStore = <span class=code-keyword>new</span> Mock(PetStore.class);
PetStore petStore = (PetStore) mockPetStore.proxy();
action = <span class=code-keyword>new</span> ViewPet();
action.setPetStore(petStore);
}
<span class=code-keyword>public</span> void testViewPet() <span class=code-keyword>throws</span> Exception {
Pet existingPet = <span class=code-keyword>new</span> Pet();
existingPet.setName(<span class=code-quote>"harry"</span>);
existingPet.setId(1);
Pet expectedPet = <span class=code-keyword>new</span> Pet();
expectedPet.setName(<span class=code-quote>"harry"</span>);
expectedPet.setId(1);
mockPetStore.expectAndReturn(<span class=code-quote>"getPet"</span>, C.args(<span class=code-keyword>new</span> IsEqual(<span class=code-keyword>new</span> <span class=code-object>Long</span>(1))), existingPet);
action.setId(1);
<span class=code-object>String</span> result = action.execute();
assertEquals(Action.SUCCESS, result);
assertEquals(expectedPet, existingPet);
mockPetStore.verify();
}
<span class=code-keyword>public</span> void testViewPetNoId() <span class=code-keyword>throws</span> Exception {
mockPetStore.expectAndReturn(<span class=code-quote>"getPet"</span>, C.ANY_ARGS, <span class=code-keyword>null</span>);
<span class=code-object>String</span> result = action.execute();
assertEquals(Action.ERROR, result);
assertEquals(1, action.getActionErrors().size());
assertEquals(<span class=code-quote>"Invalid pet selected."</span>, action.getActionErrors().iterator().next());
assertNull(action.getPet());
mockPetStore.verify();
}
<span class=code-keyword>public</span> void testViewPetInvalidId() <span class=code-keyword>throws</span> Exception {
action.setId(-1);
testViewPetNoId();
}
}</pre>
</div>
</div>
<h2><a name=JUnit-%E6%B5%8B%E8%AF%95%E6%8B%A6%E6%88%AA%E5%99%A8%E6%88%96%2F%E5%92%8Cresult%E7%B1%BB%E5%9E%8B></a>测试拦截器 或/和 result类型</h2>
<p>检查XWork/WebWork的测试套件.它们是非常全面并且提供了一个好的开端.例如,这是 <strong>ParametersInterceptor</strong> 测试的例子:</p>
<div class=code>
<div class=codeContent>
<pre class=code-java><span class=code-keyword>public</span> void testDoesNotAllowMethodInvocations() {
Map params = <span class=code-keyword>new</span> HashMap();
params.put(<span class=code-quote>"@java.lang.<span class=code-object>System</span>@exit(1).dummy"</span>, <span class=code-quote>"dumb value"</span>);
HashMap extraContext = <span class=code-keyword>new</span> HashMap();
extraContext.put(ActionContext.PARAMETERS, params);
<span class=code-keyword>try</span> {
ActionProxy proxy = ActionProxyFactory.getFactory().
createActionProxy("", MockConfigurationProvider.MODEL_DRIVEN_PARAM_TEST, extraContext);
assertEquals(Action.SUCCESS, proxy.execute());
ModelDrivenAction action = (ModelDrivenAction) proxy.getAction();
TestBean model = (TestBean) action.getModel();
<span class=code-object>String</span> property = <span class=code-object>System</span>.getProperty(<span class=code-quote>"webwork.security.test"</span>);
assertNull(property);
} <span class=code-keyword>catch</span> (Exception e) {
e.printStackTrace();
fail();
}
}</pre>
</div>
</div>
<p>注意:这不是你唯一的途径.</p>
<!--
<rdf:rdf xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
<rdf:description
rdf:about="http://wiki.javascud.org/display/ww2cndoc/JUnit"
dc:identifier="http://wiki.javascud.org/display/ww2cndoc/JUnit"
dc:title="JUnit"
trackback:ping="http://wiki.javascud.org/rpc/trackback/2150"/>
</rdf:rdf>
--><!--
Root decorator: all decisions about how a page is to be decorated via the
inline decoration begins here.
--><!--
Switch based upon the context. However, for now, just delegate to a decorator
identified directly by the context.
-->
<img src ="http://www.blogjava.net/livery/aggbug/125557.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/livery/" target="_blank">心情经纬</a> 2007-06-21 14:16 <a href="http://www.blogjava.net/livery/articles/125557.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>