假如这个世界上只剩下你一个人,当你正坐在屋子里的时候,这时突然响起了敲门声...

【原创】Struts 2杂谈(1):ValueStack对象的传送带机制

上一篇 / 下一篇  2009-02-14 22:58:01 / 个人分类:struts2

本文为原创,如需转载,请注明作者和出处,谢谢!ITPUB个人空间 s~8[s e,hwA S
ITPUB个人空间su:J5l5d2O%O5i b
    众所周知,Strut 2的Action类通过属性可以获得所有相关的值,如请求参数、Action配置参数、向其他Action传递属性值(通过chain结果)等等。要获得 这些参数值,我们要做的唯一一件事就是在Action类中声明与参数同名的属性,在Struts 2调用Action类的Action方法(默认是execute方法)之前,就会为相应的Action属性赋值。ITPUB个人空间0Y5lN{Lr%Jw,u
    要完成这个功能,有很大程度上,Struts 2要依赖于ValueStack对象。这个对象贯穿整个Action的生命周期(每个Action类的对象实例会拥有一个ValueStack对象)。当 Struts 2接收到一个.action的请求后,会先建立Action类的对象实例,并且将Action类的对象实例压入ValueStack对象中(实际 上,ValueStack对于相当一个栈),而ValueStack类的setValue和findValue方法可以设置和获得Action对象的属性 值。Struts 2中的某些拦截器正是通过ValueStack类的setValue方法来修改Action类的属性值的。如params拦截器用于将请求参数值映射到相 应成Action类的属性值。在params拦截器中在获得请求参数值后,会使用setValue方法设置相应的Action类的属性。
*J[:mXVC'xy[L0    从这一点可以看出,ValueStack对象就象一个传送带,当客户端请求.action时,Struts 2在创建相应用Action对象后就将Action对象放到了ValueStack传送带上,然后ValueStack传送带会带着Action对象经过 若干拦截器,在每一拦截器中都可以通过ValueStack对象设置和获得Action对象中的属性值。实际上,这些拦截器就相当于流水线作业。如果要对 Action对象进行某项加工,再加一个拦截器即可,当不需要进行这项工作时,直接将该拦截器去掉即可。
/L8Tk rJv0    下面我们使用一个例子来演示这个过程。在这个例子中实现了一个拦截器,该拦截器的功能是将一个属性文件中的key-value对映射成相应的属性的值。如下面是一个属性文件的内容:ITPUB个人空间t u%c!Bzd7zE8x^s

Y:?p4W;m fgky0    name = 超人ITPUB个人空间@u8`*T9xS
    price = 10000
A"qwEYQb0ITPUB个人空间]v [o2lXQl#{
    我们可以在Action类中定义name和price属性,在Action中引用这个拦截器后,就会自动为属性赋值。
;^7[l1A2n p {j0    在使用该拦截器有如下规则:
a~c*CMvk0    1.  拦截器读取的属性文件路径由path参数指定。
!{+v0B|km x$cVl/t0    2.  属性文件的编码格式由encoding参数指定,默认值是UTF-8。ITPUB个人空间9w uf!IL|/fsT_
    3.  如果某个key中包含有“.”(该符号不能出现在标识符中),则有如下处理方法:
@:[8r? DHJl0    (1)将Action类的属性名定义为去掉“.”的key。例如,key为person.name,而属性名可定义为personname。ITPUB个人空间u*L!O x^?;p,Jo+mG
    (2)将Action类的属性名定义为将“.”替换成其他字符的表示符号。例如,key为person.name,而属性名可定义为person_name,其中“_”由separator参数指定。
"Fq8X1c6h0    4.  如果key太长,也可以直接使用Action参数进行映射,例如,key为country.person.name,可做如下映射:ITPUB个人空间F6S'v r]Y"eZ+[
      <param name="countrypersonname">name</param>
Ch"Va"|0      要注意的是,name属性值不能包含“.”,因此,应将key值中的“.”去掉。现在就可以直接在Action类中定义名为name的属性的,name属性的值会与key值相同。ITPUB个人空间W*pf}/scZ
    5.  上面所有的规则可以同时使用。
^JkT;s'M-TBsd1Y0
o:[K3sO:m5p0拦截器的源代码ITPUB个人空间8r:\(o!@)J|E[

;Ruxf1YV0
package interceptors;ITPUB个人空间bE,EbT4Oc1~;l1r L
ITPUB个人空间6r`%y[Rtm
import java.util.Enumeration;
4B-IB6E x5\y_0
import java.util.Map;
Q5mHh\Ok0
import java.util.Properties;ITPUB个人空间$rGJ\(b j#L kf
import java.io.InputStream;
"FY5W.\8E QS0
import java.io.FileInputStream;
/k e#[D#?6d[/b0
import com.opensymphony.xwork2.ActionContext;
&I%S8H&_l!Xy0
import com.opensymphony.xwork2.ActionInvocation;ITPUB个人空间e?$XO#{U"AQma
import com.opensymphony.xwork2.config.entities.ActionConfig;ITPUB个人空间b2q'?!P:Jgx
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
n-D7h3?T0
import com.opensymphony.xwork2.util.ValueStack;
{ y6^VP0
9V&WODn5x1IT2uL0
public class PropertyInterceptor extends AbstractInterceptorITPUB个人空间 C8O$Ad W)e'_ Dy7P-PQ#[
{ITPUB个人空间Sv \SF1a8qo
    
private static final String DEFAULT_PATH_KEY = "path";ITPUB个人空间 d3kk.Z;i.\*`5p'q
    
private static final String DEFAULT_ENCODING_KEY = "encoding";
BC&|^{?"F.N9b"g Br0    
private static final String DEFAULT_SEPARATOR_KEY = "separator";ITPUB个人空间'|{2n q#~ D3J(|'W

S-_?|9rN0    
protected String pathKey = DEFAULT_PATH_KEY;
-k3?1qx#yF0    
protected String encodingKey = DEFAULT_ENCODING_KEY;ITPUB个人空间PIS7rP@
    
protected String separatorKey = DEFAULT_SEPARATOR_KEY;ITPUB个人空间2j i5S"m U
ITPUB个人空间t7v8^\zV%u
    
public void setPathKey(String pathKey) 
?!l(m3o3L5~7P0    {ITPUB个人空间It g [kkd
        
this.pathKey = pathKey;ITPUB个人空间#sFm7jD(re8j
    }
^{p'XX]0ITPUB个人空间 @mk!V+z J+Z B$O'`
    
public void setEncodingKey(String encodingKey)ITPUB个人空间 qS|9] k+v4vGC1cb
    {
^uOp|J^0        
this.encodingKey = encodingKey;ITPUB个人空间saU Vum3\a
    }
]%f:jh^J0
p9S;U&T f)?]Az0    
public void setSeparatorKey(String separatorKey)ITPUB个人空间Z)V9y+a2WRsC
    {
2XS |#T;|x'vq.o n0        
this.separatorKey = separatorKey;
,ah}fLN7q/Z0    }ITPUB个人空间 w(_5n aE VO(i%M
ITPUB个人空间i$s3lg-r U%_+J
    @Override
ZjV dB!u)Y7ue]"O0    
public String intercept(ActionInvocation invocation) throws ExceptionITPUB个人空间gtdU3L#Z
    {
Q9yj~ K7b7q6_0        ActionConfig config 
= invocation.getProxy().getConfig();
@o/}fSEz0
E3_#TnkY2MH0        Map
<String, String> parameters = config.getParams();ITPUB个人空间\G+i'm$i(D7o1A kb2y R
        
if (parameters.containsKey(pathKey))ITPUB个人空间y(a;mL7J b&z J
        {
q)y.HV4_.B%qp0            String path 
= parameters.get(pathKey);
;Biu8t2{y0            String encoding 
= parameters.get(encodingKey);ITPUB个人空间K {&`![!\
            String separator 
= parameters.get(separatorKey);
nL oLs qS0            
if (encoding == null)
\/f0L"E!M*J@H0                encoding 
= "UTF-8";
`uT? d"? m\0            
if (separator == null)ITPUB个人空间%^fi@4Ta]2o:H4l@
                separator 
= "";
E/Jv'\.}ai0            path 
= invocation.getAction().getClass().getResource(path)ITPUB个人空间kw.`Vf p4]2HO
                    .getPath();
X0yRS:\-x?0            Properties properties 
= new Properties();
"p:^ lIs8~8nQ0            InputStream is 
= new FileInputStream(path);ITPUB个人空间V Jn#j+l
            java.io.Reader reader 
= new java.io.InputStreamReader(is, encoding);
j/e,mM+fh2pup0            
KrP{O'l3N5c~e0            properties.load(reader);
8On3YZ0O;JUmk0            ActionContext ac 
= invocation.getInvocationContext();
Pog+T(_,D9I8Z0            ValueStack stack 
= ac.getValueStack();
+`+uQ)\6kx"iy-O0            System.out.println(stack.hashCode());
(v0yK3M4G Uh0            Enumeration names 
= properties.propertyNames();ITPUB个人空间x;J8jHh%@cRm
            
while (names.hasMoreElements())ITPUB个人空间4d%\&BTV YS
            {
T3Q;DH m6Nkq]0                
//  下面会使用setValue方法修改ValueStack对象中的相应属性值
b zZ y4CrDXi0
                String name = names.nextElement().toString();
s-J5BMk c A0                
if (!name.contains("."))ITPUB个人空间W wNx*A5x8l4]
                    stack.setValue(name, properties.get(name)); ITPUB个人空间!S+C(F5i2\.Yl |2^i+b

9T$ys ej+s'{B$K0                String newName 
= null;ITPUB个人空间V"e:g-~K*^7?I2q
                newName 
= parameters.get(name.replaceAll("\\."""));
&h"S3qk{wQt0                
if (newName != null)
a u:R s Q&hae0                    stack.setValue(newName, properties.get(name));ITPUB个人空间9fa"oW7L)H c

KNA9r G!U'g6M!w0                
if (!separator.equals(""))ITPUB个人空间 l-r'@-dkQBzYS
                {
} aY3Ayoa%~+?/`q0                    newName 
= name.replaceAll("\\.""");
8E5m z9]9l)s0                    stack.setValue(newName, properties.get(name));
qLm&K"t(d0                }               
(bKXtF0                newName 
= name.replaceAll("\\.", separator);
6b.}(mu U&[0                stack.setValue(newName, properties.get(name));
Gf;NwXD0            } ITPUB个人空间vZ!^j7Oz"L
        }ITPUB个人空间,SP(k2tm!dWY
        
return invocation.invoke();
p$u1g4[rSO0    }ITPUB个人空间7n/`-q7?#r7\-x2i+Ya
}ITPUB个人空间OhQ9C;G$~ wK

N{6{v?L0用于测试的Action类的源代码:ITPUB个人空间:D0K8\)Q&Y3X{
ITPUB个人空间a_Bo8fs1cP(v
package actions;ITPUB个人空间a6vIi7U x'm

$MI8Q de{+_I F#p0
public class MyAction
Q V&YP8K9j:ox%G0{ITPUB个人空间 ?*ZpBa"x
    
private String name;
.lrC#^hZ0    
private Integer price;
C"T\/CkzG ]fc0    
private String log4jappenderstdout;ITPUB个人空间"bhkY2C
    
private String log4j_rootLogger;
|x}.st$}:FS0    
private String conversionPattern;ITPUB个人空间d8m2Sn~|
ITPUB个人空间2utbdH4YI%J
    
public String getName()
Q5~.Egmn d0    {ITPUB个人空间3i Q,MN7f g-C
        
return name;
iy p#~,e(V0Mk0    }ITPUB个人空间&@ [ x r y'vP(W |c

;zd'j:vON }Z0    
public void setName(String name)
W5XM(QN)@[0    {
2U9a6k1K(O;K*o%^k0        
this.name = name;
+j1q!Pe]W V0    }
.e)DS;cpGW0
K @,I*][ey#Z ~0    
public Integer getPrice()ITPUB个人空间)@'gQ#Ok;D
    {
*Ol4PoC0        
return price;
qY+xTWY?y/^0    }ITPUB个人空间.g@4o1C0z.b@&F

[4IU7\nn@&RI0    
public void setPrice(Integer price)ITPUB个人空间h?Fu$}? F%Z7_l
    {ITPUB个人空间5g-w c1a"z*Io @{/G
        
this.price = price;ITPUB个人空间R D%l0SV
    }
W v0o*GM ?4`U9}g v0
4W H FW u [:JI(B}9S0    
public String getLog4jappenderstdout()ITPUB个人空间,`U;S?$N6Y4H^Rk
    {ITPUB个人空间6` {0Fi#V}!U;~jL
        
return log4jappenderstdout;
q:MD#s EO Z(h.zl0    }ITPUB个人空间1|&` T]S s

,gCD5s"vR rDy0    
public void setLog4jappenderstdout(String log4jappenderstdout)ITPUB个人空间+~NO(T.noX/[ _
    {ITPUB个人空间O3w `'R&kBtZ
        
this.log4jappenderstdout = log4jappenderstdout;ITPUB个人空间Y%?:f&x*?-]z$f8u
    }
x&yQt:MV\0ITPUB个人空间h J#kv7|tu
    
public String getLog4j_rootLogger()
g7o`6AYX0    {
6B0R;p;zNv!^0        
return log4j_rootLogger;
0e/kW!t!Q+Dmz0    }ITPUB个人空间[W [+g'd)s;h#yu v

B U,d;`@~U(V5E0    
public void setLog4j_rootLogger(String log4j_rootLogger)
v(G)|rb0    {ITPUB个人空间;Pp#tZ%^@PLR
        
this.log4j_rootLogger = log4j_rootLogger;ITPUB个人空间U0O!o#g0Bp1l
    }ITPUB个人空间 @?b'n0[1c oy

(S3qv3iNq#C#IE0    
public String getConversionPattern()
L!uD TI0    {ITPUB个人空间 X|:Op"M)]
        
return conversionPattern;
vM%F-Lx3wcf$DI0    }
.^{{d[ FQ0ITPUB个人空间$O/Q"Y8E4ACG~
    
public void setConversionPattern(String conversionPattern)
+rLa*ujMk0    {
g3h3W-gB!Py0        
this.conversionPattern = conversionPattern;
I)c9\Z#Z&[0    }ITPUB个人空间pY*K$d8P{'t H{
ITPUB个人空间Ba^*D'a)o7E
    
public String execute()ITPUB个人空间]1qEvzD:l[
    {
#UM X w:o0        System.out.println(
"name:" + name);ITPUB个人空间YjQ"?g(e b8Q*X)y
        System.out.println(
"price:" + price);ITPUB个人空间9F&X8\BT6{;o
        System.out.println(
"log4jappenderstdout:" + log4jappenderstdout);ITPUB个人空间0Gk7W(latX
        System.out.println(
"log4j_rootLogger:" + log4j_rootLogger);
FP}fP+M!r0M J0        System.out.println(
"conversionPattern:" + conversionPattern);
@-p3N#aHJg#WuZ0        
return null;ITPUB个人空间t R0z5_1d-u+~ Bs
    }
)Znsk)bt2N0}
4Zs7M/j}0
ITPUB个人空间q:TOp/|a0OIF
Action类的配置代码如:
5mH@gI ?w0ITPUB个人空间,S5EG6Ga
<?xml version="1.0" encoding="UTF-8" ?>
X2Z {.LR'ct9rj,h0
<!DOCTYPE struts PUBLICITPUB个人空间Y+WJB)O.hA
    "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
[} w,Ic0    "http://struts.apache.org/dtds/struts-2.1.dtd"
>
6q;a ie mb0
<struts>ITPUB个人空间;@'l#[WW+C$D3[D J
    
<package name="struts" extends="struts-default">
:^DOOK0ITPUB个人空间X'Y6kz"\mW
        
<interceptors>
:c;j)U1X8I&f/X)[0            
<interceptor name="property"
tp@d:C!z/j0                class
="interceptors.PropertyInterceptor" />ITPUB个人空间%?R}M(T,c1mz r+j
            
<interceptor-stack name="myStack">ITPUB个人空间j_ QI$R%f%B`B'I
                
<interceptor-ref name="defaultStack" />ITPUB个人空间 O;P/\0WBs4q}G
                
<interceptor-ref name="property" />
7{/RC9DQ6Q"lWM+X7o y0            
</interceptor-stack>ITPUB个人空间#LkY&`.C^%j G7P4U6Oe \
        
</interceptors>ITPUB个人空间\@.v2| i IBU
        
<action name="test" class="actions.MyAction">ITPUB个人空间 l(_+DYN/eQ5c8Ts
            
<interceptor-ref name="myStack" />ITPUB个人空间|g;d#H/l^!y"o.k&M1d
            
<param name="path">/log4j.properties</param>
j _XLAU$|0            
<param name="encoding">UTF-8</param>ITPUB个人空间Q7]2W!w?
            
<param name="separator">_</param>
SVqE%qf0            
<param name="log4jappenderstdoutlayoutConversionPattern">ITPUB个人空间~Pt{nZod\u
                conversionPatternITPUB个人空间hz5yn+oe
            
</param>ITPUB个人空间&x|\ Z i*aU6F D

A[ i tL(NJ;@0        
</action>
7A,z![| IL}F k|0    
</package>
.N nIL)[f0
</struts>ITPUB个人空间v w2l,F{:T B8M
ITPUB个人空间(R&b} KL_!c
  请将log4j.properties文件复制到WEB-INF\classes目录,并在该文件中加入name和price属性。ITPUB个人空间b?)g IR \-f N6k~1p

Rz9]3Gm)F8x2^:p7b0测试结果:ITPUB个人空间2V;EbF#[b'u ^ P

h C u?CeQ'g6O0
name:中国
a {;C }(y0price:
34
)~)D1P)I"i%i0log4jappenderstdout:org.apache.log4j.ConsoleAppenderITPUB个人空间}%Lz5R;h@)k/kN0F
log4j_rootLogger:error
, stdout
)F{f}XW0c9G0conversionPattern:%d{ABSOLUTE} %5p %c{
1}:%L - %m%n
ITPUB个人空间1dG[ zV]S.U
    由于property拦截器在defaultStack后引用,因此,在该拦截器中设置的属性值是最终结果,如果将property拦截器放在 defaultStack前面(将两个<interceptor-ref>元素掉换一下),就可以通过同名胜Action配置参数或请求参数 来干预最终究输出结果了。
-~7i-[E!Si'I-g6G0

TAG:

引用 删除 Guest   /   2012-03-07 14:39:51
5
引用 删除 Guest   /   2012-03-02 11:16:37
5
引用 删除 Guest   /   2011-12-13 20:57:20
5
引用 删除 Guest   /   2011-07-22 14:53:12
5
引用 删除 Guest   /   2010-09-25 11:39:54
5
引用 删除 Guest   /   2010-07-03 18:00:47
5
引用 删除 Guest   /   2010-05-28 20:09:25
1
引用 删除 IT进行时   /   2010-02-22 11:02:28
拜读了
 

评分:0

我来说两句

显示全部

:loveliness: :handshake :victory: :funk: :time: :kiss: :call: :hug: :lol :'( :Q :L ;P :$ :P :o :@ :D :( :)

日历

« 2012-05-22  
  12345
6789101112
13141516171819
20212223242526
2728293031  

数据统计

  • 访问量: 84292
  • 日志数: 209
  • 建立时间: 2008-02-08
  • 更新时间: 2010-04-14

RSS订阅

Open Toolbar