TA的每日心情 | 衰 2021-2-2 11:21 |
---|
签到天数: 36 天 [LV.5]常住居民I
|
9#
发表于 2015-06-02 12:45:13
|只看该作者
三、 Struts2
7 G2 {; C+ w1 e" S; ~" w3 }5 O1. Action名称的搜索顺序( n' m6 A7 A; f+ K
(1).获取请求路径的URL,例如URL是:http://server/struts2/path1/path2/path3/test.action
D" o" `1 H( ]: M
) c$ D5 I5 y+ J& X8 `4 W( n(2).首先寻找namespace为/path1/path2/path3的package,如果不存在这个package则执行步棸3,如果存在这个package,则在这个package中寻找名字为test的action,当在该package下寻找不到action时就会直接跑到默认namespace的package里面中寻找action(默认的命名空间为空字符串),如果在默认namespace的package里面还寻找不到该action,页面提示找不到action8 h/ _. E8 j7 {3 J, ]( {
4 A T; g0 E9 M(3).寻找namespace为/path1/path2的package,如果不存在这个package,则转至步棸4,如果存在这个package,则在这个package中寻找名字为test的action,当在该package中寻找不到action时就会直接跑到默认namespace的package里面去找名字为test的action,在默认的namespace的package里面还寻找不到该action,页面提示找不到action
$ w F, ]* Q, e - f0 `" |; d( n: L+ _
(4).寻找namespace为/path1的package,如果不存在这个package则执行步棸5,如果存在这个package,则在这个package中寻找名字为test的action,当在该package中寻找不到action时就会直接跑到默认namespace的package里面去找名字为test的action,在默认namespace的package里面还寻找不到该action,页面提示找不到action% u, ^3 S* \. f. ]; N, c, t
3 E% T0 E% w! Q0 T. `(5).寻找namespace为"/"的package,如果存在这个package,则在这个package中寻找名字为test的action,当在package中寻找不到action或者不存在这个package时,都会去默认namespace的package里面寻找action,如果还是找不到,页面提示找不到action
: i- [( d2 [3 P6 d$ p / w. u8 t' F9 O5 Z/ e: \
(6).在struts2中默认的处理后缀是.action,不加后缀也可以
( L1 @; z+ P$ n+ ~4 s4 Q5 H3 v X. _
9 Y0 d: d3 W* m" q! U2. Action配置的各项默认值5 w4 {; K' L/ r) Q- H" b# ^4 i H
(1).struts1中:<actionpath="/control/employee/addUI"forward="/WEB-INF/page/employeeAdd.jsp"/>实现请求转发,action将请求转发给视图jsp
4 f8 l9 x% Q' S# q, Q* a2 u , @9 R4 m3 n- L) \! H! {
(2).在struts2中,<actionname="addUI"><result>/WEB-INF/page/employeeAdd.jsp</result></action>,不需要设置addUI的类路径class属性了
% g' G( Q5 t" P6 W i. w
; }1 Y( ]: ~/ n: h8 W3 K(3).Action配置中的各项默认值:! s& `) F7 e Y8 g+ z
<package name="itcastnamespace="/test" extends="struts-default">
* g! A6 V1 F0 C+ O<action name="hellowrold"class="cn.itcast.action.HelloWorldAction"method="execute">* H" F5 H9 S6 e0 l0 ~
<result name="success">/WEB-INF/page/hello.jsp</result>1 O7 ]+ Y l) C
</action>' T& E7 O% E L! m' D+ M
</package>% P+ B$ F6 ~6 c7 u; W+ @* a
如果没有为action指定class,默认是ActionSupport,可以查看ActionSupport的源代码,首先交给ActionSupport类处理., v+ w. \: i" T0 N4 ~# v3 y
如果没有为action指定method,默认执行action中的execute()方法,这个方法的返回值为"success";" I- U1 v F% L7 i: R
) n- ^+ ^: i, }# ?+ b2 `! ^
(4).如果没有指定result的name属性,默认值为success,正好和execute方法的返回值相同,所以可以实现视图的转发
5 n0 t* l, f# a! |. t: R
/ p+ ^# @9 ]8 N P1 ^3.OGNL表达式
* n# R6 J: N5 j6 U4 Y/ c+ b u; [& k(1).OGNL表达式:OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目,struts2框架使用OGNL作为默认的表达式语言
0 G$ f1 p6 A* X2 I( {第一:相对EL表达式,它提供了平时我们需要的一些功能,如:+ }! X+ `9 H- D% w' n
支持对象方法的调用,如:xxx.sayHello();
8 l8 ~$ u1 d" l- y5 m7 v, y第二:支持类静态方法调用和值访问,表达式的格式为@[类全名 (包括包路径) ]@[方法名|值名],例如:@java.lang.String@format('foo %s,'bar')或@cn.itcast.Constant@APP_NAME# [- R6 M+ z0 G6 X6 k7 }; X
第三:操作集合对象
, z; w3 M& j. E& e - X! q ?6 Z9 D: N
(2).OGNL有一个上下文(Context)概念,说白了上下文就是一个MAP结构,他实现了java.utils.Map接口,在struts2中上下文(context)的实现为ActionContext1 Y" f( u& \' H6 m
' i/ ?9 B+ k' _/ _) @/ ](3).struts2中的OGNLContext是实现者为ActionContext,它的结构为:OGNL Context:ValueStack(值栈,他是根对象),parameters,request,session,application,attr,当struts2接受一个请求时,会迅速创建ActionContext,ValueStack,action,然后把action存放进ValueStack,所以action的实例变量可以被OGNL访问
/ P% B8 l& ?, M9 z- n
8 U$ N: ]/ Z+ o8 b( g2 s9 i) c(4).当要访问某个对象只需在其前面加上一个'#',例如:#request,当然有一个特殊的例子,就是根对象,会省略'#',OGNL会设定一个根对象(root对象),在struts2中根对象就是ValueStack(值栈),如果要访问根对象(即ValueStack)中的对象的属性,则可以省略#命名空间,直接访问该对象的属性即可.
6 O' e$ `! `9 o% A: v: ?
$ J" C9 g) R1 s0 L; a+ r7 f$ C U(5).在struts2中,根对象ValueStack的实现类为OgnlValueStack,该对象不是我们想象的只存放单个值,而是存放一组对象,在OgnlValueStack类里有一个List类型的root变量,就是使用它存在一组对象,在root变量中处于第一位的对象叫栈定对象(存放action),通常我们在OGNL表达式里直接写上属性的名称即可访问root变量对象的属性,搜索顺序是从栈定对象开始寻找,如果栈定对象不存在该属性,就会从第二个对象寻找,如果没有找到就从第三个对象寻找,依次往下访问,直到找到为止。大家注意:struts2中,OGNL表达式需要配合struts标签才可以使用,如:<s:property value="name"/>,value属性接受的是OGNL表达式,搜索是否含有name属性: E: m$ P4 k, z' ^
d# V- [4 s' _8 h+ q, \
(6).由于ValueStack(值栈)是struts2中OGNL的根对象,如果用户需要访问值栈中的对象,在JSP页面可以直接通过下面的EL表达式访问ValueStack(值栈)中对象的属性:! e0 I3 c# S N- f0 U
${foo}获得值栈中某个对象的foo属性- f' l" {- p7 ~( R* z5 Z2 X2 N
如果访问其他Context中的对象,由于他们不是根对象,所以在访问时,需要添加#前缀1 I6 V2 T2 }5 N! Q. J" X
第一:application对象:用于访问ServletContext,例如#application.userName或者#application['userName'],相当于调用ServletContext的getAttribute("username");, V& f4 e3 |* d3 R# n- l
第二:session对象:用来访问HttpSession,例如#session.userName或者#session['userName'],相当于调用session.getAttribute("userName");. s2 l7 m5 J0 |, l% t8 ?# K# h
第三:request对象:用来访问HttpServletRequest属性(attribute)的Map,例如#request.userName或者#request['userName'],相当于调用request.getAttribut("userName");, ]7 x: H' N. b7 r' Q( m* y
第四:parameters对象:用于访问HTTP的请求参数,例如#parameters.userName或者#parameters['userName'],相当于调用request.getParameter("username");/ V* B$ r- p, a% @: f: W( n6 I
第五:attr对象:用于按page->request->session->application顺序访问其属性.4 f8 {( p% ]% {
2 h/ O6 J! e+ s4 r/ P9 x" @
(7).为何使用EL表达式能够访问valueStack中对象的属性:原因是struts2对HttpServletRequest做了进一步的封装,简单代码如下8 N9 G& t8 ^( X z# m6 N5 r3 ?
public class StrutsRequestWrapper extends HttpServletRequestWrapper{7 Z& R4 f. h& w9 Q# f# {% L$ h
publicStrutsRequestWrapper(HttpServletRequest req){
. z' P/ |! w. g3 zsuper(req); k* ?& y* m3 T* v, x r" B- |
}6 I) v: m1 `2 r; Y- ]- Z: r
public Object getAttribut(String s){4 |7 F& v5 f( @7 v1 N. k* s
ActionContext ctx = ActionContext.getContext();1 i* i8 J9 c j5 V" i2 L
Object attribute = super.getAttribute(s)//先从request范围获取属性值
) k+ `4 o5 F& u6 {# ]if(ctx !=null){
Z/ O% z% D1 K. ]. D if(attribute==null){
5 ?2 P5 [2 \4 S7 V. d....
: J: Z1 s; B5 W0 \ ^ValueStack stack =ctx.getValueStack();3 t& ]: E {+ _+ E1 {
attribute=stack.findValue(s);//寻找规则就是前面的寻找规则* `# ~1 P) d/ o$ ?( p& N+ Q/ k% O
.... x Q. K: K5 ^) ?' A: N0 @! p* ]
}
4 a1 t5 B1 [* Y/ ]! t# c# I}
. z. }0 f: u) K9 }0 C/ l, y1 c% treturn attribute
6 r8 J$ e+ ?2 J* S}
' R- R1 ]- M7 \0 i. V. K% x3 Z7 p}
( X7 d! a1 u' k9 {" @& BEL表达式只能访问ValueStack对象中的内容* P X5 `/ x h5 `, z, c
2 w! B; h0 }+ ?- c# v2 `(8).采用OGNL表达式创建List/Map集合对象,如果需要一个集合元素的时候(例如List对象或者Map对象),可以使用OGNL中同集合相关的表达式,使用如下代码直接生成一个List对象:
7 w J5 z: B& L4 h/ C<s:set name="list"value="{'zhangming','xiaoi','liming'}"/>把当前迭代的对象放在值栈的栈顶
$ C: D# w# \$ y) v. V$ s5 H: X$ o7 w<s:iterator value="#list">7 E$ n, m. }, k: m% I5 s8 p, |. D
<s:property/><br>: e3 G, f4 k$ V8 ~7 u7 {, Z S
</s:iterator>
9 x' g% }' b5 u& ]; W; E. ESet标签用于将某个值放入指定范围
# e6 S' ]4 f. T3 Y+ r& xscope:指定变量被放置的范围,该属性可以接受application,session,request,page或action.如果没有设置该属性,则默认放置在OGNL Context中. B" S, w5 K t; a3 ~
value:赋给变量的值,如果没有设置该属性,则将ValueStack栈顶的值赋给变量5 `$ u5 L3 o4 p; M
生成一个Map对象:
1 L }8 l( q: y& U c3 _* a* n6 {8 E<s:set name="foobar"value="#{'foo1':'bar1','foo2':'bar2'}"/>
0 ^) F) p; I. e<s:iteratorvalue="#foobar">//迭代标签,把当前迭代的对象放在值栈的栈顶(entry对象),foobar是Map对象和request等对象是同等地位,访问时需要使用'#'
3 K9 r$ v$ g( k0 p! d9 ]$ d<s:property value="key"/>=<s:propertyvalue="value"/><br>5 Y7 c/ u1 u. N& d! O5 @
</s:iterator>% H6 D( ]. `( b9 V/ c
数字不用任何符号,字符串使用单引号('),对于Map采用的是maps.entrySet()这个方式进行迭代的.( v1 b7 f8 p0 E& b
8 l2 n( Z9 T' i+ D- k; c% F3 W(9).property标签用于输出指定值:7 ~+ i; l$ r! U& x F
<s:set name="name"value="kk"/>8 ~$ P. V- ]' O6 _3 L0 g
<s:property value="#name"/>% ~: C* H1 o( S3 s7 M
default:可选属性,如果需要输出的属性值为null,则显示该属性指定的值
0 y* N8 K5 [ ?: fescape:可选属性,指定是否格式化HTML代码
, e5 K" N: X2 c( a Svalue:可选属性,指定需要输出的属性值,如果没有指定该属性,则默认输出ValueStack栈顶的值
/ ~# P- K6 s7 x$ m+ Bid:可选属性,指定该元素的标识
" m/ v. k% k4 e+ t C 5 d! Q2 L0 V' x
(1)0.对于集合类型,OGNL表达式可以使用in和not in两个元素符号,其中in表达式用来判断某个元素是否在指定的集合对象中,not in判断某个元素是否不在指定集合对象中,如下所示:
5 K4 d! g1 D( w4 d# C8 q3 e* iin表达式:- |" _. N. i+ q3 r+ P. e
<s:if test="'foo' in {'foo','bar'}">
f4 C/ c& @) m y# [' U在3 S- s. G9 D& p6 R* P
</s:if>
# f5 M: z2 _0 e6 ^( Y/ |<s:else>, V0 q# g b/ m l# z% U- _
不在
6 _0 K! v0 e) b8 H, x5 V) n</s:else>
" O9 j- \- u( b$ f; o Fno in 表达式 L5 B/ R& U1 i9 e: C
<s:if test="'foo' not in {'foo','bar'}">
1 Y' Q$ q* ~' g$ u3 c' i7 d不在% [% U R% Y& s( `" C
</s:if>
) |- `- c" l' Z9 [6 g0 U/ Q7 T, r<s:else>* G; N6 |+ _. h# o
在
- |- i9 ?$ J$ p% l) x# k. B</s:else>
" c3 y0 e+ d7 r& y/ G
4 K6 D$ S3 f5 o/ A- E, }9 ~+ r(11).OGNL表达式的投影功能,除了in和not in之外,OGNL还允许使用某个规则获得集合对象的子集,常用的有以下3个相关操作符:# O- S8 b+ `/ V
第一:?:获得所有符号逻辑的元素
# }8 ]' C8 S3 N: j. v1 s第二:^:获得符合逻辑的第一个元素' t* T" d8 Y- M( J* x4 ]
第三:$:获得符合逻辑的最后一个元素1 w% ^3 T4 b7 ~3 n2 }2 l! p& B! `
例如代码:
* P) Q f9 N3 Q. c4 H<s:iterator value="books.{?#this.price>35}">; S3 ~. ^+ H+ U. J% B& z
<s:propertyvalue="title"/>-$<s:propertyvalue="price"/><br>
+ d/ d+ j1 `3 ?2 ~% W</s:iterator>
' _, p% {7 D2 r& w" m0 S8 i在上面代码中,直接在集合后紧跟{}运算符表明用于取出该集合的子集,{}内的表达式用于获取符合条件的元素,this指的是为了从大集合books筛选数据到小集合,需要对大集合books进行迭代,this代表当前迭代的元素,本例的表达式用于获取集合中价格大于35的书集合.
$ X, Q( g* W3 ~7 n b$ Vpublic class BookAction extends ActionSupport{
/ f4 C' z8 |8 R ~$ o9 c% z8 eprivate List<Book> books;: e' |- P$ y* }) M; w$ K- V
+ q2 {; h' r0 N0 |
@Override' z& o/ d- A$ n. A3 k, p
public String execute(){
2 y5 S3 V& T4 P% a1 k4 Q% }8 L+ Z/ fbooks = new LinkedList<Book>();
! x" R7 Z8 a6 E" Sbooks.add(new Book("aadfsd","spring",23));* `# Y5 c: m, y0 N# g
books.add(newBook("basdfd","ejb3.0",15));( j$ H$ T/ Q& k" v
}
2 j7 V) k% J1 U}
4 \1 V9 D' F! C! J1 B% m
2 r8 C' c0 V4 b! e) G2 b' U4.result配置的各种视图转发类型% e! Y* y' |) i/ u9 I8 \- T2 G7 K. o
(1).在struts1中有两种视图转发类型:容器内转发,容器外转发(重定向);& s2 e+ i! e- [% K9 Q7 ~
<actionpath="/control/employee/manage".../>
# ?" A0 }& u f* V" N+ Z<forwardname="add">/index.jsp</forward>; y6 _, q, [2 O h5 D! \8 Z
<forward name="add"redirect=""/index.jsp</forward>' r7 ?) n, i8 D% N! I0 z
</action>
9 s9 u. i: e/ f5 U* A5 b. z
# o1 h" s. R# f: `# |(2).struts2中的视图转发类型:result配置类似于struts1中的froward,但是struts2中提供了多种结果类型,常用的类型有:dispatcher(默认值)、rdierect、redirectAction、plainText;dispatcher对应于struts1中的容器内部请求转发,redirect对应于struts1中的容器外部转发(重定向)
P; \- U0 @, W9 B2 {7 a/ g) A
0 H2 F N' A; n(3).<actionname="helloworld"class="cn.itcast.action.HelloWorldAction">
3 k% Y, s2 {- s& S<resultname="success">/WEB-INF/page/hello.jsp</result>
$ Q9 A8 H8 f- N% d" J</action>: Q* ?' F1 h5 R7 q9 \* {
在result中还可以使用${属性名}表达式访问action中的属性,表达式里的属性名对应的action中的属性,如下:<resulttype="redirect">/View.jsp?id=${id}</result>,使用重定向可能需要将Action中的数据属性代入视图页面,这种方式太重要了,很实用.这种表达式叫做ognl表达式,struts1中是没有的,只能将属性值在代码中写死了,不像struts2中的这个表达式,很灵活.当传递的属性是中文时,需要进行URLEncoder.encode("传智播客","UTF-8")编码.
- ]+ a1 w; g% G$ k8 v# i
* S# _3 u( e" \. P, n(4).下面是redirectAction结果类型的例子,如果重定向的action中同一个包下:! p; f( X; c( q
<resulttype="redircetAction">helloworld</result>
2 i) ?6 ]. Z' Y3 h如果重定向的action在别的命名空间下:# M1 T- [( g0 A6 t
<resulttype="redirectAction">
) w% i* m2 Y4 Z4 ?8 y* ?: Q<paramname="actionName">helloworld</param>
: }8 f& g' y* O* a' P# i' e- o<paramname="namespace">/test</param>; P# G4 {1 ^9 Q: g% ~
</result>
' N9 o1 U% B& I, m' b0 y当添加用户完后,可以回到一个用户列表,此时可以重定向到action
+ R1 @ i9 e* C, X# V) i
* X d9 b8 M: B6 D. @7 v(5).plaintext显示原始文件内容,例如:当我们需要原样显示JSP文件源代码的时候,我们可以使用此类型
/ L+ G& [9 e& q# \<result name="source"type="plainText"># M6 M1 H4 W. k0 e+ ?9 R
<paramname="location">/xxx.jsp</param>0 z+ z# b. H4 x! X0 u
<paramname="charSet">UTF-8</param><!--指定读取文件的编码-->
7 E5 w4 W& X! k% A</result># L0 P) a3 C3 ] t, r9 s
在Eclipse中jsp是用UTF-8编码存放的,当读取jsp的内容时,是用本地字符编码的,可能出现乱码,所以要设置读取文件的编码集. Y! H) v a2 k6 ~6 c' P
# n6 P/ e2 Z' w: o(6).浏览器重定向的JSP不能放在web-inf目录中,而请求转发的JSP可以放在web-inf目录中2 P% l$ m$ E) e) l- j
% u0 m p8 Q' s9 V8 o2 ^(7).struts2中的全局视图:3 `+ c6 K9 p# Z4 `; F# y
<global-results>( w1 o, s' e( G
<resultname="index.jsp"></result>
; [# c; J& ], A* r: @<global-results>
. P/ z5 \7 W" U3 W* w1 n8 k和struts1中的全局视图是很相似的9 D( N+ `0 m' y; S- {" I& s% s
我们可以定义一个包,然后将全局视图的配置放到这个包中: r4 d. @1 q0 c* n# o
j6 F% N) |" ~$ [6 C
5.struts2常用标签
% } d# @' b+ I2 C0 e8 f, u- f- E6 S(1).property标签用于输出指定值:
# e- l* b3 A% \. O5 M% ]<s:setname="name" value="kk"/>. y5 \ d4 c; v2 @: x7 k+ E
<s:propertyvalue ="#name"/>: r% X" G3 G4 I- e
default:可选属性,如果需要输出的属性值为null,则显示该属性指定的值1 o. B! L9 l, x, c
escape:可选属性,指定是否格式化HTML代码8 }0 @+ [. e4 o D: b: P4 {
value:可选属性,指定需要输出的属性值,如果没有指定该属性,则默认输出ValueStack栈顶的值
9 v/ t) j/ N8 B7 m; fid:可选属性,指定该元素的标识; o+ G" }0 U" |# R: P3 x# q- q
, b! l" h- T" I; g(2).iterator标签用于对集合进行迭代,这里的集合包含List、Set和数组8 |; O5 S& V6 h9 ~( c% n8 q! }
<s:set name="list"value="{'aa','bb','cc'}"/>
Q( {; b3 Z: b5 P2 S8 x<s:iterator value="#list"status="st">
, P( e* a0 J N% y<font color=<s:iftest="#st.odd">red</s:if><s:else>blue</s:else>>9 D+ R+ l$ x( p7 E
<s:property/></font><br>; a: w3 _; N8 |+ s8 t
</s:iterator>
+ i L5 \9 F& m5 t7 [. Mvalue:可选属性,指定被迭代的集合,如果没有设置该属性,则使用ValueStack栈顶的集合,
) z; a# S3 @! U0 q( n; Hid:可选属性,指定集合里元素的id(已被标注为过时)9 D" y+ g8 s/ r
status:可选属性,该属性指定迭代时的iteratorStatus实例,该实例包含如下几个方法:+ |5 H: h" i/ _" g$ H, ^; @+ B
int getCount(),返回当前迭代了几个元素
8 G% U a& A+ l: p' N7 V# Uint getIndex(),返回当前迭代元素的索引
1 {1 |' d: n1 M8 dboolean isEven(),返回当前被迭代元素的索引是否为偶数% B' @( l r5 b7 y2 F- u9 \7 ]3 e% n
boolean isOdd(),返回当前被迭代元素的索引是否是奇数* ]8 }& H9 _& s2 z2 w+ B
boolean isFirst(),返回当前被迭代元素是否是第一个元素0 M( g9 o8 C, D
boolean isLast(),返回当前被迭代元素是否是最后一个元素
1 e& X/ } M5 G; ?5 q; G( u
4 f. o6 O0 _) h% J' m& b7 j(3).<s:setname="age" value="21" scope="request"/>) V+ \; b; \3 ?
<s:iftest="#request.age==23">/ Y1 N' f$ U1 m3 T# s \1 y
23
, K! m5 y9 B: C7 [</s:if>
0 Q5 D7 C9 i9 `( [<s:elseif test ="#age==21">1 o H! s+ j* {
21
# u* ~1 z5 e, u& s</s:elseif>3 I, d0 x' O7 T: ^' c8 |, ?
<s:else>/ D( F6 {7 I6 c f& J3 N6 F
都不等
+ C* F. l' J" T E$ J# Q</s:else>( S7 g" ` h: k }
1 f; l& I, u6 E3 e: Q, f' m4 Y/ g& u+ ~
(4).url标签:
* H# D8 z! P% K9 i<s:url action="helloworld_add"namespace="/test">. ?0 [0 h! I3 |& g# Q& _) ^; P' M( k+ @$ o
<s:param name="personid"value="3"/>
) R6 P7 S+ O, T8 p8 g/ Y" N4 C</s:url>5 Q; E4 x) A) T, C" X
生成类似如下路径:6 B, C$ B4 ?. {. f/ J: U
/struts/test/helloworld_add.action?persionid=3
0 {6 x1 P1 L. j) c7 T4 p y/ I ' F7 H* g% D- `) q1 V9 ], ?
当标签的属性值作为字符串类型处理时,"%"符号的用途是计算OGNL表达式的值
% y9 ~2 _' O, N, ?, P7 b<s:set name="myurl"value='"http://www.foshanshop.net"'/>& O- N# y8 u/ l# {% R2 j, f0 a
<s:url value="#myurl"/>7 v1 {& D; T* a0 `# @: g
<s:url value="%{#myurl}"/>0 c3 P9 R8 E4 V1 ` G# Y% g! F
输出结果:
6 d, { q% ^1 e, [#myurl
$ g8 Q$ X- d, k8 K) G& Ahttp://www.foshanshop.net
1 @0 v7 v- m2 C6 G1 a" v
/ b* y2 \+ N! d(5).表单标签checkboxlist复选框
0 Z( l: q6 q I1 N% r# d如果集合为list
& k' j) D1 |9 \" P. o<s:checkboxlist name="list"list={'Java','Net','RoR','PHP'}" value="{'Java','Net'}"/>% Y7 `8 Y+ s$ y% x3 M9 A) H
<input type="checkbox"name="list" value="Java"checked="checked"/><label>Java</label>: ^; B& b- u* y: E4 c/ L% c
<input type="checkbox"name="list" value="Net" checked="checked"/><label>Net</label>* g$ k# A& a1 Z' \3 f) d$ T) g h
<input type="checkbox"name="list" value="RoR" ><label>Java</label>. N7 T0 H v9 O# y
<input type="checkbox"name="list" value="Java"/><label>Java</label>
! n7 q/ d$ e& M3 c如果集合为MAP
4 h+ A" n) ?# J% k- N+ h, I6 X2 j<s:checkboxlist name="map"list="#{1:'aa',2:'bb'}" listKey="key"listValue="value" value="{1}"/>; D! Y0 D/ A) P( g, u' n4 [
生成如下html代码: R3 d* c5 X4 f$ R* ?
<input type="checkbox"name="map" value="1"checked="checked"/><label>aa</label>4 M" y* ]* ] F0 z) m) f7 m3 Y
<input type="checkbox"name="map" value="2" /><label>bb</label>
. J* o- `- T; w/ e+ i当然集合里面存放的也可以是对象类型
+ X6 V7 G; A( a2 s% C* e / {- k9 C* K3 n x2 x |3 B
(6).单选框
. Q0 c+ j- n; y3 j<s:radio name="beans"list="#request_person" listKey="personid"listValue="name"/>* M0 y) b* Z1 ^# j. Q5 }, N
, Z! Q5 s$ o! X6.struts2的处理流程与Action的管理方式
# q3 x/ [: f \ C# Q* b8 F9 z9 `(1).用户请求->(查看web.xml文件)StrutsPrepareAndExecuteFilter->Interceptor(struts2内置的一些拦截器或用户自定义拦截器)->Action(用户编写的Action类,类似Struts1中的action,针对每一次请求,都创建一个Action)->Result(类似struts1中的forward)->Jsp/html(响应)
) `7 {4 n: N' }
) J* g Y- c6 I( \7 c3 H2 u(2).StrutsPrepareAndExecuteFilter是struts2框架的核心控制器,它负责拦截由<url-pattern>/"</url-pattern>指定的所有用户请求,当用户请求到达时,该fileter会过滤用户的请求,默认情况下,如果用户请求的路径不带后缀或者后缀以.action结尾,这时请求将被转入到struts2框架处理,否则struts2框架将略过该请求的处理,当请求转入struts2框架处理时会先经过一系列的拦截器,然后再到Action,与struts1不同,struts2对用户的每一次请求都会创建一个Action,所以struts2中的action是线程安全的.2 L; ]2 `6 w3 w I1 N7 j
8 [, h. ?* k* p! U
7.XML配置方式实现对action的所有方法进行校验' d+ E- s( n, o ^) S* l1 |/ [
(1).基于XML配置方式实现对action的所有方法进行输入校验:
! @% f( E9 w$ p7 ?1 e% C3 B! D( M. J使用基于XML配置方式实现输入校验时,Action也需要继承ActionSupport,并且提供校验文件,校验文件和action类放在同一个包下,文件的取名格式为:ActionClassName-validation.xml,其中,ActionClassName为action的简单类名,-validation为固定写法,如果Action类为cn.itcast.UserAction,那么该文件的取名应为:UserAction-validation.xml,下面是校验文件的模板:: G* y0 c2 d4 m( t6 h6 G7 B
<validators>
" S# s- p/ p0 Q+ _ T/ S<field name="username">
+ U5 `; e& L7 l% i<field-validatortype="requiredstring">: N' H: q& C+ g! C6 Z( t7 y
<paramname="trim">true</param>' ^3 h/ d; \+ d
<message>用户名不能为空</message>
2 ]5 y2 h6 s# w: r</field-validator>
7 q5 w6 n5 Q2 ]* O</field>$ R8 w+ g- U: z( z q E6 V
</validators>
! I) _0 @" K5 g' o<field>指定action中要校验的属性,<field-validator>指定校验器,上面指定的校验器requirestring是由系统提供的,系统提供了能满足大部分验证需求的校验器,这些校验器的定义可以在xwork-2.x.jar中的com.opensymphony.xwork2.validator.validators下的default.xml中找到,<message>为校验失败后的提示信息,如果需要国际化,可以为message指定key属性,key的值为资源文件中的key,在这个校验文件中,对action中字符串类型的username属性进行验证,首先要求调用trim()方法去掉空格,然后判断用户名是否为空.
H2 x* _& Z# n9 y+ x/ I8 E E ! e5 i/ ^# k5 a- V4 A, G2 E
(2).struts2提供的校验器列表:4 t8 G. f# w) {$ \! ^8 Y/ L% U
required(必填校验器,要求field的值不能为Null)( e* q, H1 N$ Y1 J. }0 J
requiredstring(必填字符串校验器,要求field的值不能为null,并且长度大于0,默认情况下会对字符串取钱后空格)
% j( c( |9 @' u* I; M: ^9 ~, v& n2 R! `stringlength(字符串长度校验器,要求field的值必须在指定的范围内,否则校验失败,minLength参数指定最小长度,maxLength参数指定最大长度,trim参数指定校验field之前是否去除字符串前后的空格), z7 v3 x' U, i% M7 C
regex(正则表达式校验器,检查被校验的field是否匹配一个正则表达式,expression参数指定正则表达式,caseSensitive参数指定进行正则表达式匹配时,是否区分大小写,默认值为true)
- | l+ t; f* g# vint(整数校验器,要求field的整数值必须在指定范围内,min指定最小值,max指定最大值)% M4 `9 Z: _, B2 h; `
double(双精度浮点数校验器,要求field的双精度浮点数必须在指定范围内,min指定最小值,max指定最大值)
! n" z+ ~1 B( H; N( i+ Ffieldexpression(字段OGNL表达式校验器,要求field满足一个OGNL表达式,expression参数指定OGNL表达式,该逻辑表达式基于ValueStack进行求值,返回true时校验通过,否则不通过)
J/ O# m: O! P2 C3 g. I2 \5 c6 uemail(邮件地址校验器,要求如果field的值非空,则必须是合法的邮件地址)
- d- z$ {; s, {0 y. Y% lURL(网址校验器,要求如果field的值非空,则必须是合法的URL地址)
4 p$ D2 x8 F( b2 ~# w" X3 Tdate(日期校验器,要求field的日期值必须在指定范围内,min指定最小值,max指定最大值)- t n" J( Y% B9 F1 R$ E3 L% `& j" P, e$ f
conversion(转换校验器,指定在类型转换失败时,提示的错误信息)
0 ]$ l' T+ H4 U e1 p2 dvisitor(用于校验action中的符合属性,它指定一个校验文件用于校验符合属性中的属性)" X O& c! L9 C$ p c
expression(OGNL表达式校验器,expression参数指定ognl表达式,该逻辑表达式基于ValueStack进行求值,返回true时校验通过,否则不通过,该校验器不可用在字段校验器风格的配置中). Y# `- `2 i7 C
6 B) U" f, n! M4 `. \
(3).![CDATA[文本内容]]:文本内容不会被解析,只会原封不动的当做文本处理% Y! i. ?2 }; u, F7 i3 ^ U
% ]9 \% x5 D: \$ q
(4).编写校验文件时,不能出现帮助信息:! {0 x. p) z' n. c# ~
在编写ActionClassName-validation.xml校验文件时,如果出现不了帮助信息,可以按照下面方式解决:
* b) m. w$ x' {3 G, lwindows->preferences->myeclipse->filesand editors->xml->xmlcatalog:点击add,在出现的窗口中的location中选"file system"然后再xwork-2.1.2戒烟目录的src\java目录中选择xwork-validator-1.0.3.dtd,回到设置窗口的时候,不要急着关闭窗口,应把窗口中的Key Type改为URI,Key改为http://www.opensymphoney.com/xwork/xwork-validaor-1.0.3.dtd
0 h; o6 w4 R; {1 d: i( R
1 e8 w% O1 A) [8.XML配置方式实现对action的指定方法校验$ J* J U0 L0 K' L' x$ a- y$ C
(1).基于XML配置方式对指定action方法实现输入校验:
e( [& g, g& p# f0 ]9 b当校验文件的取名为ActionClassName-validation.xml时,会对action中的所有处理方法实施输入校验,如果你只需要对action中的某个action方法实施校验,那么校验文件的取名应为:ActionClassName-ActionName-validation.xml,其中ActionName为struts.xml中的action的名称,例如:在实际应用中,常有以下配置:
7 s) e- f! v& o% R7 z: f& e1 ]( a<action name="user_*"class="cn.itcast.action.UserAction" method="{1}">
6 e9 u3 @6 D; `3 {& I9 u<resultname="success">/WEB-INF/page/message.jsp</result>
0 M7 o3 L3 u9 g2 s<resultname="input">/WEB-INF/page/addUser.jsp</result> x) f+ \+ g- w0 a3 e* Q! k' N
</action>5 Z; u# ]; ~3 H* o, }! o
UserAction中有以下两个处理方法:
; O% b2 H/ c! {7 d0 kpublic String add() throws Exception{8 r i4 b6 p8 c( |9 y$ L
6 o) \$ H. z6 [% ^; a4 K8 B) V}" U2 S0 }) Q8 {+ A$ c2 \4 v0 Y
public String update() throws Exception{9 i$ }0 {: h3 C) H; j, F9 d" n6 O/ ]
8 h& p' J; M' a+ _7 W; w
}
! M: y1 c- a+ s8 h4 H要对add()方法实施验证,校验文件的取名为:UserAction-user_add-validation.xml* g, |8 K; e# e
要对update()方法实施验证,校验文件的取名为:UserAction-user_update-validation.xml
. F, ~# u/ f5 Y% P( u' X# C) N * {! Q& I4 R" f/ M0 j, @5 E- q$ Z
(2).基于XML校验的一些特点:8 N( l- C9 |* q
当为某个action提供了ActionClassName-validation.xml和ActionClassName-ActionName-validation.xml两种规则的校验文件时,系统按下面顺序寻找校验文件:
. s6 p' Q0 C5 ], [( SActionClassName-validation.xml. K1 K$ A4 }. p+ ]& g! z
ActionClassName-ActionName-validation.xml
: v( b* ~1 B/ S- ~- S% r系统寻找到第一个校验文件时还会继续搜索后面的校验文件,当搜索到所有校验文件时,会把校验文件里的所有校验规则汇总,然后全部应用于action方法的校验,如果两个校验文件中指定的校验规则冲突,则只使用后面文件中的规则。" c J9 {4 q% m$ t: ]4 Z6 W
当action继承了另一个action,父类action的校验文件会先被搜索到$ D/ z4 F, E0 J
假设UserAction继承BaseAction2 v& B* a. O, C" l# k2 l
<actionname="user" class="cn.itcast.action.UserAction"method="{1}">
* W, J" d2 g' B _! k z</action>
, d: b) b7 t4 ]# A! n; n. D" g4 \4 a访问上面的action,系统先搜索父类的校验文件:BaseAction-validation.xml,BaseAction-user-validation.xml,接着搜索子类的校验文件:UserAction-validation.xml,UserAction-user-validation.xml,应用于上面action的校验规则为这四个文件的总和+ P) u, q3 L9 O' O9 y4 M
q7 @5 \! M. o& X* o0 P" T9.动态方法调用和使用通配符定义action
2 h: s' n) Y$ L0 b(1).在struts1中实现方法的动态调用:7 \5 X+ T$ q7 x } o* X
<actionpath="/control/employee/manage" type="....DispatchAction"parameter="method"/>
6 z$ a" k. P+ @</action>& A# M8 Q- L2 v, s8 ^# V1 c
/control/employee/manage?method=addUI
& t7 o: @2 Q1 \4 T但是Action必须继承DispatchAction4 |! N4 y5 W$ K
; _& X& ~6 t5 i) K8 w; X7 |(2).在struts2中有两种方式:# U; I* C1 [/ ]/ L/ e& a: C; p
第一种:(struts2.1版本后就不建议使用了)是动态方法调用:如果Action中存在多个方法时,我们可以使用!+方法名调用指定方法,如下:
( V5 S! ^& F- }8 n1 M3 Upublic class HelloWorldAction{
# O( s( p; ?$ a0 O1 r; I% h- @private String message;% z5 E7 o6 W6 V. X; n& V
....! O8 z6 o J1 }! q
public String execute()throws Exception{/ r4 \0 `3 K1 A6 \/ N! V- Q; g" n( ^
this.message="我的第一个struts2应用";9 r) z8 k7 Y8 s/ O! X
}- J, x6 {1 p2 b! b4 w* s
public String other() throws Exception{
2 D) M* h, J% l; Nthis.message="第二个方法";9 k2 N8 n% k7 ~7 c1 U
return "success";# y0 c. ^. i: G! _* S: D$ {7 j4 J
}" a8 a3 H3 v m/ k& _% G
}% x* q% c: d T& y2 m% V5 l! a: u
假设访问上面的action的URL路径为:/struts/test/helloworld.action,要访问action的other方法,我们就可以这样调用:/struts/test/helloworld!other.action,如果不想使用动态方法调用,我们可以通过常量struts.enable.DynamicMethodInvocation关闭动态方法调用:
% @) A7 g8 a% W% X0 G' k& P$ z1 }5 F<constantname="struts.enable.DynamicMethodInvocation"value="false"/>$ H X9 Y6 X( w3 b4 K# x- H: S3 |2 J
第二种:使用通配符定义action(推荐使用的)* K u: c" b' p" l5 Y
<package name="itcast"namespace="/test" extends="struts-default">4 _$ Z2 t7 c: d! ~+ x% y. h
<action name="helloworld_*"class="cn.itcast.action.HelloWorldAction" method="{1}> q7 a1 f& o8 \7 d) L& S
<resultname="success">/WEB-INF/page/hello.jsp</result>
! K9 A' G. `; e% _4 y</action>
; d0 g* J4 }9 d3 f</package>+ B( Z8 n* u q, x
public class HelloWorldAction{
) t: F0 Y |# o1 d3 T* k; ]- O9 yprivate String message;
* `% P. n% n6 }. @$ a....) Q0 i. Q$ }; y% S3 E/ n' ]
public String execute()throws Exception{
: r1 W7 p; j0 Y6 `2 Z this.message="我的第一个struts2应用";
/ A% O- I5 g" y' ?}, \( m: m# {" R' w
public String other() throws Exception{
( C2 F/ D# U9 F, i; L, ythis.message="第二个方法";$ _1 S# y# X2 G8 h# j
return "success";
0 A7 e& M; _! m7 c) G! A' \# m- _1 j}( s7 n: q: z* D) k4 u* e4 G
}! m1 m+ Q v' O6 ?& V
要访问other()方法,可以通过这样的URL访问:/test/helloworld_other.action
{4 f. T0 k: Wname="helloworld_*"后可根据多个*,method={1},'1'表示匹配*的位置* U( a% \' C$ d& m4 ^! C0 F
name="helloworld_*_*",method={2}:要访问other()方法,可以通过这样的URL访问:/test/helloworld_xxx_other.action
! j' W5 e8 k) [0 G
' J4 Y2 l4 k, z/ X2 O10.对action指定的方法进行校验
* S$ h4 e2 K; e$ ?* B/ M手工编写代码实现对action指定方法输入校验:( z) Q5 C, h" e1 @
通过validateXxx()方法实现,validateXxx()只会校验action中方法名为Xxx的方法,其中Xxx的第一个字母要大写,当某个数据校验失败时,我们应该调用addFieldError()方法往系统的fieldErrors添加校验失败信息,(为了使用addFieldError()方法,action可以继承ActionSupport(),如果系统的fieldErrors包含失败信息,struts2会将请求转发到名为input的result,在input视图中可以通过<s:fielderror/>显示失败信息.' D4 _0 @4 h0 ^. A+ a
validateXxx()方法使用例子:/ o; R" `' A8 G9 @" x
public Stringadd() throws Exception{return "success";}* m4 F+ j2 }9 c/ Y7 G: }
public voidvalidateAdd() {
& I$ i7 I. W3 Pif(username==null&&"".equals(username.trim()))this.addFieldError("username","用户名不能为空");
. y$ t1 K* |$ i0 X! Q- z}
2 E. x: g! i. W7 T9 P2 d$ c4 V- S验证失败后,请求转发至input视图:<resultname="input">/WEB-INF/page/addUser.jsp</result>' l3 _7 K! J) t$ P% b: B9 R
在addUser.jsp页面中使用<s:fielderror/>显示失败信息" G- w9 K4 s3 }$ C U
3 j! ~4 X' R( c11.对Action中所有方法进行输入校验
3 f2 \* p& d7 J" \. d5 {, B(1).在struts2中,我们可以实现对action的所有方法进行校验或者对action的指定方法进行校验2 { r1 c' k+ _5 T$ j6 Q* q* k! K$ u
% R1 G) @6 s3 o6 j- n
(2).对于输入校验struts2提供了两种实现方法:一种是采用手工编写代码实现,另一种是基于XML配置方式实现+ @3 q1 E$ V; G: Y+ w7 O7 B
" i$ [$ y0 h. W8 q+ i; \) W8 X; b+ S
(3).手工编写代码实现对action中所有方法输入校验:通过重写validate()方法实现,validate()方法会校验action中所有与execute方法签名相同的方法,当某个数据校验失败时,我们应该调用addFieldError()方法往系统的fieldErrors添加校验失败信息(为了使用addFieldError()方法,action可以继承ActionSupport(),如果系统的fieldErrors包含失败信息,struts2会将请求转发到名为input的result,在input视图中可以通过<s:fielderror/>显示失败信息.) X5 P5 j& v# B& l9 E
validate()使用例子:
- e% B# p$ D5 ?9 Ppublic voidvalidate(){( I# D8 q% x! c/ O' y ]4 k9 c! _: O
if(this.mobile==null||"".equals(this.mobile.trim())){this.addFieldError("username","手机号不能为空")}else{if(Pattern.compile("^1[358]\\d{9}").matcher(this.mobile.trim()).matchers()){this.addFieldError("mobile","手机号的格式不正确");}}
J L _" N& p}
" U) W% b! \% L4 z% D" k验证失败后,请求转发至input视图:4 U! ^& _* [* Y( ?9 l, _, i
<resultname="input">/WEB-INF/page/addUser.jsp</result>) l. U# A1 f3 k0 |* |. {
在addUser.jsp页面中使用<s:fielderror/>显示失败信息
. Q. x* D5 N9 o2 m- m; M0 o
+ `3 ^% t* `: [- A4 a$ z% R12.多文件上传' R8 ^5 I/ T+ c' h$ o/ n3 P3 U
(1).多文件上传,就是在一个文件上传的基础上,将属性File变成数组类型File[]类型即可,同时该字段的名称必须要和上传页面中属性name的名称一样. X# K4 o' ]# b" P6 J
然后进行一次迭代,就可以得到所有的文件( h7 m' P0 {) }& `
7 u g8 L* h' M& ~, I
13.防止表单重复提交+ O6 r0 V# u8 E0 T* c3 m% D+ u/ Q
<s:token>标签防止表单重复提交
2 P7 G1 P _: q8 G8 _# W第一步:在表单中加入<s:token/>8 E7 N7 A5 d- M+ X- ~ {9 x
<s:form action="helloworld_other"method="post" namespace="/test">8 `4 F0 e1 C+ H. \( u
<s:textfieldname="person.name"/><s:token/><s:submit/>
. g+ c3 Z* @6 w" {3 o, E; l</s:form>6 ~9 H. v, ~, F0 ?
第二步:<action name="helloworld_*"class="cn.itcast.action.HelloWorldAction" method="{1}">3 J1 r) I8 x! f. `0 E7 r
<interceptor-refname="defaultStack"/>
" ?4 k+ X4 Q0 l; e' H C# o<interceptor-refname="token"/>8 V9 w! e8 X# S: e3 C
<resultname="invalid.token">/WEB-INF/page/message.jsp</result>
* i3 z: }, t* W( U9 t1 W<result>/WEB-INF/page/result.jsp</result>
6 `- ?1 K4 `% C& |</action>* M/ Q$ A5 K$ F; M
以上配置加入了"token"拦截器和"invalid.token"结果,因为"token"拦截器在会话的tlent与请求的token不一致时,将会直接返回"invalid.token"结果$ \; w) N* e: q5 D2 `% n- W
在debug状态,控制台出现下面信息,是因为Action中并没有struts.token和struts.token.name属性,我们不用关心这个错误" O$ O2 H; b H' e3 e/ p
使用了<s:form/>标签可以不指定action的上下文标签路径,可以通过命名空间实现.和前面的原理是一样的,在路径后面添加上sessionid号,只是这步操作不需要我们自己得到sessionid号,struts帮我们操作.1 x* }7 J& \3 I+ \. @+ A
在值栈中的对象,访问无需添加'#'
: C- G& J9 `- ~. \2 y5 s
: k- w* y7 p' Y14.访问或添加几个属性
2 x1 u; n$ P0 z o* j) G2 y/ r(1).访问或添加request/session/application属性,在struts2中的Action中的execute方法中没有Servlet api(没有响应的参数);
- x2 @* G5 w8 j" x* m. Jpublic String scope() throws Exception{; t6 m1 I. ~2 d* t; ]- b, Y6 g( g
ActionContextctx=ActionContext.getContext();
" A' F( e) W: ]7 e: fctx.getApplication().put("app","应用范围");
; i/ y- H' F0 c" Zctx.getSession().put("ses","session范围");: h1 `% V1 c4 ]" ~( d
ctx.put("request","request范围");& `4 a3 ]! [# c4 r( g+ d6 y
return "scope";0 ^' \+ {/ t- ]
}
7 o, X( V# ]6 R$ t1 z5 B0 N, P% l " g- F) S2 o0 E
<body> \# h8 X$ G- Z- t8 C
${applicationScope.app}$ b7 f3 ~, k3 g% F0 a) z. G6 W
${sessionScope.ses}
; g1 Z3 @& d. s$ n) q${requestScope.req}
h8 H0 R9 q1 b8 d% B</body>
- X7 Z: A/ q$ x( M 8 K3 ^$ {/ a! S1 B' _# u
(2).获取HttpServletRequest/HttpSession/ServletContext/HttpServletResponse对象:
% j/ W: D* `# @方法一:通过ServletActionContext类直接获取
+ K$ X) U6 Y, D9 n7 m, v# j0 l9 cpublic String rsa() throws Exception{; q3 ], W9 W& H( S- P' z' m
HttpServletRequest request =ServletActionContext.getRequest();
: y% z+ V$ I' v# wServletContextservletContext=ServletContext.getServletContext();
! Y8 A/ E" J+ m) Grequest.getSession();
4 }. Q$ f3 J. N: l- RHttpServletResponseresponse=ServletActionContext.getResponse();
v, \* R/ |( ^' X0 ^return "scope";
+ Q8 {8 L7 Q: {( `+ H) P}
3 Q5 ? X, b* P. @0 q方法二:实现指定接口,由struts框架运行时注入:
! n+ E. p8 |6 z, q5 @& ?% ]public class HelloWorldAction implementsServletRequestAware,ServletResponseAware,ServletContextAware{
3 r- H9 s9 v) g; c3 s( o$ xprivate HttpServletRequest request;- w. R9 C2 `$ p- M5 T- n
private ServletContext servletContext;
8 s) k) B6 W. J# nprivate HttpServletResponse response;+ @) {) Y0 l* E+ g" R
public voidsetServletRequest(HttpServletRequest req){
* B: q% C7 @: V0 Tthis.request.req;4 U2 B/ f1 h5 z- w
}- j, Q V0 E/ S+ Y/ k% w; C# n
public voidsetServletResponse(HttpServletResponse res){4 `" [2 Z% j; W5 a6 O$ D
this.response=res;' Z3 N7 x0 A6 h8 U
}% \" Y$ K& K/ x+ r" Y
public voidsetServletContext(ServletContext ser){1 \* T! [$ L t# i0 Y {
this.servletContext=ser;
# \3 Q( n% c. x' @, N1 V}6 F$ K0 _. ?/ ~* H
注意1和2的不同,一个不需要得到对象,一个需要得到对象,所以要区分两个的应用场景* X% t4 o. x* \" ^/ P
}
6 J- s8 }; b# P8 g! i4 q# I + }8 j$ c: ^7 f, f- s- e
15.解决struts配置文件无提示问题9 [; g( C2 c0 ?7 x3 m- b. L
找到struts2.0.dtd文件即可,windows->preferences->MyEclipse->XML->XMLCatalog,点击添加strut2.dtd
. B: Z' r/ \2 b. [ # A& A8 y" W4 L, W1 Z5 A
16.介绍struts2及struts2开发环境的搭建
$ H; u0 K' I- Z/ X0 j: _6 q1 @(1).struts2是在webwork2基础发展而来的,和struts一样,struts2也属于MVC框架,不过有一点大家需要注意的是:尽管struts2和struts1在名字上的差别不是很大,但是struts2和struts1在代码编写分割上几乎是不一样的,那么既然有了struts1,为何还要推出struts2,主要是因为有一下有点:
* S/ ^+ R3 ]: \4 b第一:在软件设计上struts2没有像struts1那样跟Servlet api和struts api有着紧密的耦合,struts2的应用可以不依赖于servlet api 和struts api,struts2的这种设计属于无侵入式的设计,而struts1却属于侵入式设计,因为其的8 @; i3 k3 N, p( U5 v
execute()方法中的参数为ActionMapping,ActionForm,HttpServletRequest,HttpServletResponse
5 A. `" h2 U8 `7 z9 ^$ `* s, f第二:struts2提供了拦截器,利用拦截器可以进行AOP编程,实现如权限拦截等功能9 S# l, {! G- e5 }. v) u3 T" d
第三:struts2提供了类型转换器,我们可以把特殊的请求参数转换成需要的类型,在struts1中,如果我们要实现同样的功能,就必须向struts1的底层实现BeanUtils注册类型转换器才行' j/ B" F% |7 b
第四:struts2提供支持多种表现层技术,如:JSP,freeMarker,Velocity等
5 v7 a2 b! k! V# w0 g2 c( m第五:struts2的输入校验可以对指定方法进行校验,解决了struts1长久之痛,struts1中的validate方法对所有的方法进行校验
3 F% W0 T" o7 J9 p" n Y第六:提供了全局范围、包范围、和Action范围的国际化资源文件管理实现.
9 [6 N4 o. t' a7 Q0 y - x: X* ^4 f+ X+ N# K9 ^( C$ T
(2).搭建struts2的环境和struts1是相同的,第一步导入相关包,第二步建立struts2的配置文件,第三步在web.xml中注册struts2框架的配置6 D. Q, K* f+ U3 C n
. j& L8 _7 D, J
(3).所需的包:struts2-core-2.x.x.jar,xwork-2.x.x.jar(webwork的核心架包),ognl-2.6.x.jar X5 b4 E' E0 _5 \/ h$ J
% o/ L4 t& e: |1 ?, G(4).struts2默认的配置文件为struts.xml,该文件需要放在/web-inf/classes目录下( c% E5 m& u* n. }
1 u/ m6 }2 h+ K5 S4 e; p. n(5).在struts1中,struts框架是通过servlet启动的,在struts2中,struts框架是通过Filter启动的,它在web.xml中的配置如下所示:可以参照struts文件夹下的例子中拷贝,在strutsperpareExecuteFilter的init()方法中将会读取类路径下默认的配置文件struts.xml完成初始化操作,注意:struts2读取到struts.xml的内容后,以javabean形式存放在内存中,以后struts2对用户的每次请求处理将使用内存中的数据,而不是每次都读取struts.xml文件# e- s. z9 S3 k6 J; C
# S/ u. }/ N# l6 W) ` C(6).自从struts2.1.3以后,下面的FilterDispatcher已经标注为过时了,struts2.1.3后期版本为StrutsPrepareAndExecuteFilter类 @: v$ s0 q& a2 |7 N
% y# b0 `; }0 e" d' G+ z. C
17.开发第一个应用& m) j" L1 G) M. Q
(1).在struts.xml中的配置:$ K' P1 y/ Z. V
<package name="itcast"namespace="/test" extends="struts-default">
* J0 ]3 D- q* l R! q$ L, e <actionname="helloworld" class="cn.itcast.action.HelloWorldAction"method="execute">
( s8 m0 H2 E' k# o! U$ y9 | <resultname="success">/WEB-INF/page/hello.jsp</result>
# A5 B. n/ i! T) T4 f; ?</action># [* O6 L7 u# Z; B" T' u
</package>
- P% j; N% i7 g. L y, ^5 |在struts2框架中使用包来管理Action,包的作用和Java中的类包是非常类似的,它主要用于管理一组业务功能相关的action,在实际应用中,我们应该吧一组业务功能相关的Action放在同一个包下
& s5 V) b! l4 a1 C% I配置包时必须指定name属性,该name属性可以任意取名,但必须唯一,它不对应java的类包,如果其他包要继承该包,必须通过该属性进行引用,包的namespace属性用于定义该报的命名空间,命名空间作为访问该包下Action的路径的一部分,如访问上面例子的Action,访问路径为:/test/helloworld.action,namespace属性可以不配置,对本例而言,如果不指定该属性,默认的命名空间为" "(空字符串).当然配置可以减少重复的代码,struts1中的重复代码就可以使用命名空间来解决
: p: D3 G6 I2 \7 C- `通常每个包都应该继承struts-default包,因为struts2很多核心的功能都是拦截器来实现的,如:从请求中把请求参数封装转到action、文件上传和数据验证等都是通过拦截器实现的,struts-defaul定义了这些拦截器和Result类型,可以这么说:当包继承了struts-default才能使用struts2提供的核心功能,struts-default包是在struts2-core-2.x.x.jar文件中的struts-default.xml中定义,struts-default.xml也是struts2默认配置文件,struts2每次都会自动加载struts-default.xml文件,包还可以通过abstract="true"定义为抽象包,抽象包中不能包含action,可以查看struts-default.xml文件中,就可以看到定义了很多拦截器
, E$ p' W( I4 m6 D. k3 u# {1 M<result></result>和struts1中的forward很相似,定义视图. X# A+ Q( l4 k0 u& A2 Z' y
+ {3 G1 H9 {* v
(2).public Stringexecute(){return 视图的名称;}注意到这个方法和struts1不同,没有参数,返回类型也不同,这就降低了耦合性,非侵入式的编程了.: g( E% w6 c' ^. G; X
& ]3 [+ U2 O: w5 K0 U
(3).在jsp中使用el表达式即可${message},message是Action中的一个方法getMessage()方法,而不是根据Action中的成员变量message
: @9 ]1 ^. q% K4 w& h) ? 3 O! s9 g; a$ P5 F9 T
18.配置Action范围国际化资源文件! F9 D' h) Y$ O- C+ l
(1).我们也可以为某个action单独制定资源文件,方法如下:在Action类所在的路径,放置ActionClassName_language_country.properties资源文件,ActionClassName为Action类的简单名称当查找指定key的消息时,系统会先从ActionClassName_language_country.properties资源文件查找,如果没有找到对应的key,然后沿着当前包往上查找基本名为package的资源文件,一直找到最顶层包,乳沟还没有找到对应的key,最后会从常量struts.custom.i18n.resources指定的资源文件中查找
. u. T* I4 P/ v9 U) L+ ~- A3 ? + @5 ]* E: T1 m3 C- h
(2).JSP中直接访问某个资源文件
6 E2 m. ~7 |! T$ ^struts2为我们提供了<s:i18n>标签,使用<s:i18n>标签我们可以在类路径下直接从某个资源文件中获取国际化数据,而无需任何配置:
; G$ ?( H$ }6 m( b- j/ \/ `$ i. y2 h<s:i18n name="itcast">% h& H7 I% i7 g& ]
<s:text name="welcome"/>* w7 x; M+ j2 D2 E/ H8 b- }
</s:i18n>$ V, r. q$ L5 c/ X3 S& X& }
itcast为类路径下资源文件的基本名
& Y# V$ M" S1 p如果要访问的资源文件在类路径的某个包下,可以这样访问:
1 H8 Z! C, O Z* I0 s<s:i18nname="cn/itcast/action/package">
0 ]" H# v" [& s7 h* q8 e) r1 _, k<s:text name="welcome">" {* M7 `7 c! c6 u% k& ?3 a. S, Z
<s:param>小张</s:param>
0 L/ u) y& X% U. d8 h& f</s:text>
6 W: Q0 G. N2 y0 s</s:i18n>1 w1 T" \( k# f& X7 @; W
上面访问cn.itcast.action包下基本名为package的资源文件
! l. Q5 v" l( k8 L5 W) g
8 {2 I% P, r3 x$ \- `1 M* \19.配置包范围的国际化资源文件, _: }4 O6 |# l8 n9 g0 z
(1).在一个大型应用中,整个应用有大量的内容需要实现国际化,如果我们把国际化的内容都放置在全局资源属性文件中,显然会导致资源文件变得过于庞大、臃肿,不便于维护,这个时候我们可以针对不同模块,使用包范围来组织国际化文件
! O1 ]) b5 D: k7 J! y) h5 y" g1 A" q方法如下:在java的包下放置package_language_country.properties资源文件,package为固定写法,处于该包及子包下的action都可以访问该资源,当查找指定key的消息时,系统会先从package资源文件中查找,当找不到对应的key时,才会从常量struts.custom.i18n.resources指定的资源文件中寻找.
7 X6 `4 ^& @: a" A) Z1 q 7 ^( V) n1 Z% }) b2 a5 `# _. X# P0 k
20.配置国际化全局资源文件、输出国际化信息. k9 t, A' Z" R' U/ M( U
(1).准备资源文件,资源文件的命名格式如下:
6 _# `6 l, q, Z7 QbaseName_language_country.properties
6 U( ^. B9 N1 ebaseName_language.properties
- M, {: j" j, ?0 Y, f3 m) JbaseName.properties
1 d+ j) o9 A! F其中baseName是资源文件的基本名,我们可以自定义,但是language和country必须是java支持的语言和国家。如:" l9 x4 o; i' g; {( ~7 S: j. S+ f
中国大陆:baseName_zh_CN.properties, v" ]4 M$ J. N+ D0 f
美国:baseName_en_US.properties/ o# K( h: _" @; A7 m
6 i# O* F5 S/ u2 N Z/ p( }
(2).现在为应用添加两个资源文件:
; ]/ f8 }2 X3 |) N) R" ?第一个存放中文:itcast_zh_CN.properties% R) ?3 L8 q) l8 o/ E1 d
内容为:welcom=欢迎来到传智播客1 v- k- T+ d$ C
第二个存放英语(美国):itcast_en_US.properties7 l n+ P; m8 l* K
内容为:welcome=welcom to itcast8 m, s0 u* z# e. G0 S3 r/ ^
* j4 v; T- r, ~( p% o' l(3).对于中文的属性文件,我们编写好后,应该使用JDK提供的native2ascii命令把文件转换为unicode编码的文件,命令的使用方式如下:9 l& s- x) F# q4 R% T
native2ascii 源文件.properties 目标文件.properties,在MyEclipse6.6版本以及后面的版本会自动转换.
- v. ~+ k1 ?% j# k$ K1 S6 x
/ j" i) t( s5 d$ y) W X5 }( }: L(4).struts2有:全局范围,包范围,action范围的资源文件9 Q0 j6 e: R' T/ k+ k' V: t
/ I1 V0 o d9 u5 {/ ] B( P# k(5).配置全局资源与输出国际化信息: u1 y2 H3 m4 ?+ y+ e7 t
当准备号资源文件之后,我们可以在struts.xml中通过:struts.custom.i18n.resources常量把资源文件定义为全局资源文件,如下:
- A; e1 Y |3 b! U/ L3 P# L<constantname="struts.custom.i18n.resources" vlaue="itcast"/>
6 ?, \- W8 ?1 Q( l! Q, @itcast为资源文件的基本名
0 h& u' g/ h8 i; i* ]1 j8 W后面我们就可以在页面或在action中访问国际化信息:; H& k9 {" b, O7 y
在JSP页面中使用<s:text name=""/>标签输出国际化信息:
2 }, @0 a6 E* G u" ?<s:textname="user"/>,name为资源文件中的key
9 g% T3 u, d& n' n2 u; g( `在Action类中,可以继承ActionSupport,使用getText()方法得到国际化信息,该该方法的第一个参数用于指定资源文件中的key,
, X* r& H7 R. S) m# g6 l( e$ a在表单标签中,通过key属性指定资源文件中的key,如:
! u- \- v4 X+ h' F0 E4 w7 }/ |<s:textfieldname="realname" key="user"/>( E" j) f* {/ _
) d! ~1 A9 V4 a% G- U
21.请求参数接受
5 K* b" N: K" Y5 n( d6 Y(1).struts1中是使用ActionForm接受用户的请求参数$ p: D2 c$ d4 v* o1 m2 M
1 k9 W0 F4 E3 f. g% w(2).采用基本类型接受请求参数(get/post):
1 r1 O1 P% A8 W$ v: A* O' v1 j在Action类中定义与请求参数同名的属性,struts2便能自动接受请求参数并赋予给同名属性:请求路径:http://localhost:8080/test/view.action?id=783 _2 f/ Z1 U) _
public classProductAction{: H6 y; P6 t" l" m9 M& b/ H6 _
private Integerid;
* Q# ?& M4 e% \' r" w* lpublic voidsetId(Integer id){//struts2通过反射技术调用与请求参数同名的属性的setter方法获取请求参数值* N- C: Y- z* O$ x' w2 x
this.id=id;0 _2 ^& K' Z9 w- ?0 R
}. b) j. M9 e; Z) H' q/ q: W
public IntegergetId(){return id;}8 c# L" k1 X! h. n3 a7 f3 p
}' |& k' {1 w2 f# C# t$ h6 I
3 l7 d9 [* X% c, A2 a3 i- N(3).采用复合类型接受请求参数
: G: l* m3 `+ K& l i* L% Y/ C# I请求路径:http://localhost:8080/test/view.action?product_id=78
4 g5 M3 t# @, xpublic class ProductAction{
! \/ v) @+ e _private Product product;6 g$ t% G/ m6 |- g& I! l# b
public void setProduct(Product product){htis.product=product;}4 {0 W; `: p3 ^
public Product getProduct(){returnproduct;}
; Q+ G& K. q+ I8 I0 `$ x}4 C, K; L$ K& L3 A6 ?
struts2首先通过反射技术调用Product的默认构造器创建product对象,然后再通过反射技术调用product中与请求参数同名的属性的setter方法来获取请求参数值
+ y' }* }- X6 {; e6 d . T6 {) M0 `( s' \0 i* I) y
(4).关于struts2.1.6版本中存在一个Bug,及接受到的中文请求参数为乱码(以post方式提交),原因是struts2.1.6在获取并使用了请求参数后才调用HttpServletRequest的setCharacterEncoding()方法进行编码设置,导致应用使用的就是乱码请求参数,这个Bug在struts2.1.8中已经解决,如果你使用的是struts2.1.6,要解决这个问题,你可以这样做:新建一个Filter,把这个Filter放置在Struts2的Filter之前,然后再doFilter()方法中添加以下代码:
; W2 z7 j5 P. h, d! d4 a0 n3 hpublic void doFilter(..){$ t# O0 l! P5 p. x$ {
HttpServletRequest req=(HttpServletRequest)request;1 N; _$ x* z4 U. v5 K
req.setCharacterEncoding("UTF-8");
. [ P! m7 C6 H' Q6 n6 bfilterchain.doFilter(request,response);
, v0 F( V& P; d7 v) e}1 o$ w# g: `: k
' E7 [- v" h. D8 ? X! s! ~22.全局类型转换器) F, ~' H4 o' e7 w6 ~
自定义全局类型转换器:将上面的类型转换器注册为全局类型转换器:在WEB-INF/classes下放置xword-conversion.properties文件,在properties文件中的内容为:待转换的类型=类型转换器的全类名
+ T% \! l4 s" M6 W4 E2 T* z5 z" s对于本例而言,xwork-conversion.properties文件中的内容为:
! d9 _9 ]2 I, Y) A. Z* hjava.util.Date=cn.itcast.conversion.DateConverter
6 ~1 k3 @) P; d 1 j! Y5 L/ M" J9 r! K$ V
23.输出带有占位符的国际化信息* ]( K; w% \$ ?
(1).资源文件中的内容如下:
: D2 S4 Z% A. `* Z: e. cwelcom={0}欢迎来到传智播客{1}$ L, _8 p( H/ O: @ t
在jsp页面中输出带占位符的国际化信息
" S9 `2 O5 B; C9 x; F p5 r<s:text name="welcom">
# g$ b, m& y1 g5 V% |! b<s:param><s:propertyvalue="realname"/></s:param>
& ?+ S% S% t w<s:param>学习</s:param>! G) h: U; D4 f3 Y
</s:text> {/ S6 ]$ A; d7 `" I& K0 T
在Action类中获取带占位符的国际化信息,可以使用getText(String key,String[] args)或getText(StringaTextName,List args)方法.
% s# m Q! p. O( ]/ l5 E/ w 7 @/ F; U+ m, y
(2).占位符就当是一个变量参数,可以传递给定的参数值.
8 b! D5 w! J5 X1 ~, h4 K, J7 p& n 7 x$ n3 x$ I- M) R3 j
24.为Action属性注入值7 {" v6 q. q3 z8 w2 C- V3 Q
struts2为Action中的属性提供了依赖注入功能,在struts2的配置文件中,我们可以很方便的为Action中的属性注入值,注意:属性必须提供setter方法,
0 P0 f* E) ]9 Upublic class HelloWorldAction{
9 ]( d( Y9 l9 `2 Q4 r q+ q( ` private String savePah;3 m9 z! Z4 X, l) p, W) @0 A4 x
public String getSavePath(){
' B9 E# z4 }1 ]/ ~% a) i- j return savePath;
" Q( Y2 A1 L: H% x! F }. z2 p+ S# M7 I' m" ]. \
public void setSavePath(String savePath){
# N. M# j/ l# _, Z* @" x this.savePath=savePath;: X' v0 h& Z2 K
}! f) ^ T1 V$ ?! x9 o
}5 S& o6 J3 ~% }& O( ?
<package name="itcast"namespace="/test" extends="struts-default">) u6 M; H( W6 X8 c1 P6 d4 \/ a
<action name="helloworld"class="cn.itcast.action.helloWorldAction">% Z- E2 t: N- a! E: U
<paramname="savePath">/images</param>
, S# v+ E' n4 [/ x h R" N o/ H<resultname="success">/WEB-INF/page/hello.jsp</result>4 [* [: K: {, m" `% H
</action>7 N: d4 t9 K `. V6 n) F
</package>8 b8 S* A0 ^8 d
上面通过<param>节点为action的savePath属性注入"/images";Action的变量的值,不能写死,经常变换,需要通过配置来设置参数
$ S% A3 h: W$ u2 j% h9 k7 f/ U1 R ) }9 y1 v3 m* ^- {
25.为应用指定多个配置文件; M8 h# G0 c4 \+ @8 \3 f& W" I* j
(1).在大部分应用中,随着应用规模的增加,系统中的Action的数量也会大量增加,导致struts.xml配置文件变得非常臃肿,为了避免struts.xml文件过于庞大、臃肿,提高struts.xml文件的可读性,我们可以讲一个struts.xml配置文件分解成多个配置文件,然后再struts.xml文件中包含其他配置文件,下面的struts.xml通过<include>元素指定多个配置文件:* ?7 _+ `* I( G" q
<struts>
; a9 w6 e' b, P/ R7 s<includefile="struts-user.xml"/>
9 w+ O, s7 b# a" @ } N/ [/ H7 r<includefile="struts-order.xml"/>( J& s' i- e4 @0 R r
</struts> j& Y8 I% T; O, q' B: Z
通过这种方式,我们就可以将struts2的Action按模块添加在多个配置文件中' ^7 k3 J( C0 S7 }5 h9 k! T! l' P
0 M! F9 B) K/ m' | _& a26.文件上传& x' U+ l, A4 f( i9 f. c9 I/ P
第一步:在WEB-INF/lib下加入commons-fileupload-1.2.1.jar、commons-io-1.3.2.jar,这两个文件可以从http://commons.apache.org下载,在struts2.1以前的版本需要添加,以后的版本就不需要添加
& q) D+ `/ `8 H+ X+ B
4 T; E6 m' Z9 g, g2 a第二步:把form表的enctype设置为:"multipart/form.data",如下:! I1 O: }; P+ [+ z0 F6 n( k
<form
# F x/ k( _$ {1 U# r6 V& N" Z" zenctype="multipart/form-data"action="${pageContext.request.contextPath}/xxx.action"method="post">% @6 g9 L$ x2 w( {
<inputtype="file" name="uploadImage">这个属性的name必须要和类中File名称一样
+ p- y" }. V+ `' c</form>3 r! f0 t$ K! `" r& }; ~
第三步:在Action类中添加以下属性
l; A) T, S6 C1 {, h6 hpublic class HelloWorldAction{5 X" Q- ^9 B; t0 |
private File uploadImage;//得到上传文件;: r7 @2 K3 ~; W
private String uploadImageContentType;//得到文件的类型
( Q( W Z0 m4 C" q5 J& w9 `' G( u1 Gprivate String uploadImageFileName;//得到文件的名称; o2 j: Y! Z+ o; \/ a
//这里省略了属性的get/set方法(但是要注意get/set方法是必须的)( _3 Q4 l1 p. c: \3 Z
public String upload() throws Exception{: T) s. W' N+ W, v& p/ S
String realpath =ServletActionContext.getServletContext().getRealPath("/images");' S. m+ e; ~) x4 M
File file=new File(realpath);+ l d4 }! X5 m. C D" u3 |
if(file.getParentFile().exists())file.getParentFile().mkdirs();//目录是否存在,不存在就创建, z# ^( ~9 ~8 Z/ h4 {' m- _" s
FileUtils.copyFile(uploadImage,newFile(file,uploadImageFileName));
" m9 a6 @+ s/ P5 Zreturn "success";( k# F! A4 ^4 o \: o
}6 ?- w1 ~& ]2 I1 U: b# b7 p& V+ R4 }
}+ i$ Z" ~( A9 A0 {& b+ t! ?
9 g7 P" O. h( l
(1).如果文件不保存,struts2会把文件保存到自己的目录中,但是当这个Action执行完后,该文件就会被删除,所以我们要将上传的文件保存到硬盘上' r: A$ t7 q6 q9 Y
8 N6 D, R: }7 k5 @ B(2).最好还要判断以下,文件uploadImage是否为空
" z! ]) ]* Q- B8 w6 t $ O. j3 z: {8 v
(3).如果上传大的文件,web都会失败,像一些门户网站上传视频,都是通过一个插件,可以把这个插件看成一个程序,只是这个程序是通过Socket变成的,针对一个端口进行传输数据
* X3 Z7 d: M1 u% N ; B' l4 Y0 L* Q* m
27.指定struts2处理的请求后缀) E4 Q4 n. d/ v l8 B) D4 d S
(1).前面我们都是默认使用.action后缀访问Action,其实默认后缀是可以通过常量"struts.action.extension"进行修改的,例如:我们可以配置struts2只处理以.do为后缀的请求路径4 ?- E3 H1 h4 U; E2 {* s
<struts>/ E: H {5 ?- f+ E
<constantname="struts.action.extendsion" value="do"/>
, F( b1 x( S" N& X</struts>
( s3 G" c0 N( N( r8 g" e0 i. i如果用户需要制定多个请求后缀,则多个后缀之间以英文逗号","隔开,如:6 H& w) X6 d# I2 M8 F4 D) ]
<constantname="struts.action.extendsion" value="do,go"/>3 W& h, h2 Y1 R* M6 N& e
a% y4 A6 X# J6 W(2).常量可以在struts.xml或struts.properties中配置,建议在struts.xml中配置,两种配置方式如下:2 l t0 z) u4 b
在struts.xml文件中配置常量:
: ]1 F/ F$ ?. b* m1 g! ~0 P<struts>
- H7 c" l2 x4 v" ?+ A9 T<constantname="struts.action.extendsion" value="do"/>8 @' @4 E* ?/ ?# r
</struts>
0 v) _: R3 Y( b6 s在struts.properties中配置常量:
# y* C. r+ E* o' t q' z% G estruts.action.extension=do
7 ~& }$ H U2 R. }2 V因为常量可以在下面多个配置文件中进行定义,所以我们需要了解struts2加载常量的搜索顺序:
0 G. t5 P, T/ }: mstruts-default.xml& V B. a6 a/ y8 [
struts-plugin.xml1 H6 _$ {( W$ H9 y
struts.xml) h+ e2 g, Z/ w. R
struts.properties
+ b. M, y! U7 W+ V+ i/ c( b5 J/ Rweb.xml6 p+ y! C7 ^. a" h$ e: w0 P
如果在多个文件中配置了同一个常量,则后一个文件中配置的常量值会覆盖前面文件中配置的常量值& E1 B- x. v3 h) |4 ?# s
0 Z5 _6 U6 ]/ a2 O- [
(3).
* N! F4 s+ a, d A, q! k第一:默认编码集,作用于HttpServletRequest的setCharacterEncoding方法和freemarker、velocity的输出:# c1 Z( |" `! H' F6 `: Z% `$ p5 W
<constantname="struts.i18n.encoding" value="UTF-8"/>4 o9 |' P" t# W9 A1 q" W
第二:该属性指定需要struts2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由struts2处理,如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开
9 h% C a# N9 }/ p& y9 E9 ?<constant name="strtus.action.extension" value=do"/>* C V7 k. {; z4 V0 r1 j
第三:设置浏览器是否缓存静态内容默认值为true(生产环境下使用)开发阶段最好关闭,不然看不到修改后的数据7 J- N% t6 M2 \2 U3 ^
<constantname="struts.serve.static.browserCache" value="false"/>
{4 O; B% t& x4 L- B" d# K$ ?5 _第四:当struts的配置文件修改后系统是否自动重新加载该文件默认值为false(生产环境下使用),开发阶段最好打开
* @: v1 [9 X4 M1 _7 D3 R e: Q<constantname="struts.configuration.xml.reload" value="true"/>
7 s1 p* W1 a- k# l2 }( t, L第五:开发模式下使用,这样可以打印出更详细的错误信息
9 W1 F- r" ]1 t, G+ O& x I: l# t/ w<constant name="struts.devMode"value="true"/>
! _! \, J4 r0 _9 H6 Q* O) S第六:默认的视图主题- H7 R+ ^% a% W
<constantname="struts.ui.theme" value="simple"/>; V, Q0 Q( c) N7 ~; r
第七:与spring集成时,指定由spring负责action对象的创建
$ ?6 K% z/ o9 ]$ r<constantname="struts.objectFactory" value="spring"/>
, T8 ?' r' K; c2 w第七:该属性设置struts2是否支持动态方法调用,该属性的默认值是true,如果需要关闭动态方法调用,则可设置该属性为false+ w& _4 f5 E' t' a' E% @
<constantname="struts.enable.DynamicMethodInvocation"value="false"/>
3 L8 A! ?: p; Z* g, m8 e) u; m' U9 D第八:上传所有文件的总大小限制' Y% [5 T( J2 K& h5 z' j
constantname="struts.mulitipart.maxSize" value="10701096"/>
a8 s" X* A3 ~8 s1 t; ] 8 H1 |1 a' ^$ w6 w
28.自定义拦截器' H6 L1 J7 @) {1 N7 G$ |$ g, U
(1).如果用户登录后可以访问action中的所有方法,如果用户没有登录不允许访问action中的方法,并且提示"你没有权限执行该操作"
! u2 [0 r- z! j" s3 x0 K 1 i9 M Z/ J+ v Q4 N
(2)." c' c g+ w" y& R& Z9 H& U' `
<interceptors>' D- |8 u1 O5 {2 K, r7 J
<interceptorname="permission"class="cn.itcast.interceptor.PermissionInterceptor"/>% @" P* e1 R' }" q
</interceptors># J! O. l. U" b- n
<actionname="list_*" class="cn.itcast.action.HelloWorldAction"method="{1}">3 a1 G% x8 o @9 p
<interceptor-refname="permission"/>6 B* Z2 F% g- V% g
如果为某一个Action定义一个拦截器,struts2中对Action的默认的很多拦截器都失去功能,所以要想做到两全其美,需要定义一个拦截器栈:. \: U5 e; j8 | r+ U
<interceptors>
' E+ ~/ {0 o& \: u1 |/ _3 v+ H<interceptorname="permission"class="cn.itcast.interceptor.PermissionInterceptor"/>
* ~+ w1 {- b, h& A3 U& R+ L<interceptor-stackname="permissionStack">( ^2 ?8 r0 h. v, e. Z# h6 X/ `( i
<interceptor-refname="defaultStack"/>
6 U0 m; _4 a+ _! N1 e6 ^<interceptor-refname="permission"/># }5 f# `3 Y" E* X/ x# L" f, e
</interceptor-stack>
8 U- L/ k: d$ _- D$ H</interceptors>3 L" [8 E6 g( e7 }$ b2 r: i9 U) b
因为struts2中如文件上传,数据验证,封装请求参数到action等功能都是由系统默认的defaultStack中的拦截器实现的,所以我们定义的拦截器需要引用系统默认的defaultStack,这样应用才可以使用struts2框架提供的众多功能,如果希望包下的所有action都使用自定义的拦截器,可以通过<default-interceptor-refname="permissionStack"/>把拦截器定义为默认拦截器,注意:每个包只能指定一个默认拦截器,另外,一旦我们为该包中的某个action显示指定了某个拦截器,则默认拦截器不会起作用.
4 w. N$ T- g- ?$ i(3).系统默认的拦截器可以到struts-default.xml中查看,很多功能.系统拦截器放在最前面,自定义的拦截器放在后面.8 U# x7 P/ h/ b+ h! J
7 V& ]4 f. w! U+ ?1 G+ i4 h4 y
29.自定义类型转换器: b3 G1 z# v( Y+ S- V8 D0 L3 p1 j
(1).struts2中提供了两种类型转换器:局部类型转换器(只对某一个action起作用),全局类型转换器(所有的action起作用)& P) t. Y/ k4 O, L
! A8 a# Z, h$ |
(2).类型转换器必须继承DefaultTypeConverter最好用xwork2.jar中的,重写converValue(Map<String,Object>context,Objectvalue,Class toType){
4 y0 W5 K( Y! V# } q0 F2 Qreturnsuper.convertValue(context,value,toType);
& X/ q2 Z9 F2 w! a8 X- @0 k4 \}0 B$ ~, b9 L' E0 c; k/ a
其中第一个参数和ognl表达式,第二个参数是需要转换类型的内容(是String数组,因为可能有多个值),第三个参数是需要转换成什么类型,要实现双向转换; e0 x H; o& S* i1 U
! K1 E2 x6 u! u( |! m9 I(3).将上面的类型转换器注册为局部类型转换器:( R% C9 C c- s- w* m/ N7 W. N
在Action类所在的包下放置ActionClassName-conversion.properties文件,ActionClassName是Action的类名,后面的-conversion.properties是固定写法,对于本例而言,文件的名称应为HelloWorldAction-conversion.properties.在properties文件中的内容为:
$ R% u, v& t% c需要转换的属性名称=类型转换器的全类名. U6 |" f+ a$ c1 O7 P$ `% m
对于本例而言,HelloWorldAction-conversion.properties文件中的内容为:
3 ^: x& ~% a$ L) kcreatetime=cn.itcast.conversion.DateConverter |
|