文章

Struts 2 标签(二)

Struts 2 标签(二)

本节将学习Struts2标签库的详细内容,包括数据标签,流程控制标签和其他标签。

1.数据标签

数据标签能从ValueStack上取得数据,或者将变量、对象放在ValueStack上。本小节将讨论property、set、push、bean和action标签,并演示这些标签的常见用例。

1.1 property标签

property标签提供了一种将属性写入呈现的HTML页面的快速、方便的方法。下面是这个标签的重要属性:

属性 是否必须 默认值 类型 描述
value 栈最顶端 Object 被显示的值
default 空(null) String 值为空时使用的默认值
escape true Boolean 是否转义HTML

实际的使用很简单,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
<h4>Property Tag</h4>
The current user is <s:property value="user.username"/>.
`</pre>

#### 1.2 set标签

在标签的上下文中,set意味着给一个属性指定一个别名。有时候一个属性需要使用一个很长的、复杂的OGNL表达式才能引用到它,通过为这个属性重新指定一个顶层的名字可以更容易、更快捷的访问它。默认情况下,这个属性会变成ActionContext中的一个命名对象,与ValueStack、会话映射齐名。所以你可以使用如#myObjec这样的OGNL表达式把它作为一个顶层的命名对象引用。当然,你也可以指定这个新引用被放置在ActionContext中的某个作用域中。下面是set标签的属性:

<table class="table table-bordered table-striped table-condensed">
  <tr>
    <td>
      属性
    </td>
    <td>
      是否必须
    </td>
    <td>
      类型
    </td>
    <td>
      描述
    </td>
  </tr>
  <tr>
    <td>
      name
    </td>
    <td>
      是
    </td>
    <td>
      String
    </td>
    <td>
      被设置在指定作用域内的变量的引用名
    </td>
  </tr>
  <tr>
    <td>
      scope
    </td>
    <td>
      否
    </td>
    <td>
      String
    </td>
    <td>
      application、session、request、page或者action,默认是action
    </td>
  </tr>
  <tr>
    <td>
      value
    </td>
    <td>
      否
    </td> 
    <td>
      Object
    </td>
    <td>
      设置值的表达式
    </td>
  </tr>
</table>

下面是实际的使用:

<pre>`&lt;s:set name=&quot;username&quot; value=&quot;user.username&quot;/&gt;
Hello, &lt;s:property value=&quot;#username&quot;/&gt;. How are you?    
`</pre>

以下代码经把新引用设置为application作用域映射内的一个实体:

<pre>`&lt;s:set name=&quot;username&quot; scope=&quot;application&quot; value=&quot;user.username&quot;/&gt;
Hello, &lt;s:property value=&quot;#application['username']&quot;/&gt;. How are you?
`</pre>

#### 1.3 push标签

set标签允许你创建指向值的新引用,而push标签允许你把属性放到ValueStack上。当你需要对一个对象进行很多操作时这个标签会很有用。将对象放在ValueStack顶端之后,它的所有属性可以通过第一级别的OGNL表达式访问。

<table class="table table-bordered table-striped table-condensed">
  <tr>
    <td>
      属性
    </td>
    <td>
      是否必须
    </td>
    <td>
      类型
    </td>
    <td>
      描述
    </td>
  </tr>
  <tr>
    <td>
      value
    </td>
    <td>
      是
    </td>
    <td>
      Object
    </td> 
    <td>
      放到ValueStack中的值
    </td>
  </tr>
</table>

以下是使用这个标签的示例:

<pre>`&lt;s:push value=&quot;user&quot;&gt;
    This is the &quot;&lt;s:property value=&quot;portfolioName&quot;/&gt;&quot; portfolio,
    created by none other than &lt;s:property value=&quot;username&quot;/&gt;
&lt;/s:push&gt;
`</pre>

push标签把user属性放到ValueStack的顶端,这是我们就可以把user的属性当作ValueStack这个虚对象上的顶级属性访问,这样OGNL表达式就变简单了。最后push的结束标签把user从ValueStack顶端删除。

#### 1.4 bean标签

bean标签像是set标签和push标签的混合标签。主要的不同是不需要使用一个已经存在的对象,bean标签会自己new这个对象,并把它放到ValueStack上或者设置为ActionContext的顶级引用。默认是将对象放在ValueStack上,并在标签存在期间一直保留在ValueStack上。以下是bean标签的属性:

<table class="table table-bordered table-striped table-condensed">
  <tr>
    <td>
      属性
    </td>
    <td>
      是否必须
    </td>
    <td>
      类型
    </td>
    <td>
      描述
    </td>
  </tr>
  <tr>
    <td>
      name
    </td>
    <td>
      是
    </td>
    <td>
      String
    </td>
    <td>
      被传入bean的包名和类名
    </td>
  </tr>
  <tr>
    <td>
      var
    </td>
    <td>
      否
    </td>
    <td>
      String
    </td>
    <td>
      在结束标签作用域外引用这个bean时使用的变量名
    </td>
  </tr>
</table>

下面示例展示了如何创建和存储一个bean作为ActionContext中的命名参数:

<pre>`&lt;s:bean name=&quot;org.apache.struts2.util.Counter&quot; var=&quot;counter&quot;&gt;
    &lt;s:param name=&quot;last&quot; value=&quot;7&quot;/&gt;
&lt;/s:bean&gt;
&lt;s:iterator value=&quot;#counter&quot;&gt;
    &lt;li&gt;&lt;s:property/&gt;&lt;/li&gt;
&lt;/s:iterator&gt;
`</pre>

默认情况下创建的对象会存储在ValueStack中,使用var后会在ActionContext中存储这个对象的引用,正是因为如此,在iterator标签中,我们使用它的方式需要用#操作符,即OGNL表达式#counter。在许多Struts2标签中,都存在可选的var属性,它的作用与此类似。

bean标签是我们研究的第一个参数化标签。现在看看如何使用bean标签将新创建的bean放在ValueStack上而不是存储在ActionContext上。而且我们我们还是用param标签演示怎样向自定义对象提供参数。

<pre>`&lt;s:bean name=&quot;manning.utils.JokeBean&quot; &gt;
    &lt;s:param name=&quot;jokeType&quot;&gt;knockknock&lt;/s:param&gt;
    &lt;s:property value=&quot;startAJoke()&quot;/&gt;
&lt;/s:bean&gt;
`</pre>

上面我们使用了OGNL方法调用语法starAJoke(),bean标签不需要完全遵守JavaBean标准,但是OGNL能够使用这个方法,我们将在OGNL详解中讲解它的机制。

最后,注意我们向JokenBean传递了一个参数,这个参数用来控制这个bean讲述的笑话的类型。只要这个对象实现了一个与这个参数同名的属性,它就能自动接收传入的参数。

#### 1.5 action标签

这个标签允许我们从当前的视图层调用其他的动作。action标签的实际使用很简单,只需指定其他需要调用的动作。

<table class="table table-bordered table-striped table-condensed">
  <tr>
    <td>
      属性
    </td>
    <td>
      是否必须
    </td>
    <td>
      类型
    </td>
    <td>
      描述
    </td>
  </tr>
  <tr>
    <td>
      name
    </td>
    <td>
      是
    </td>
    <td>
      String
    </td>
    <td>
      动作名
    </td>
  </tr>
  <tr>
    <td>
      namespace
    </td>
    <td>
      否
    </td>
    <td>
      String
    </td>
    <td>
      动作的命名空间,默认使用当前页面的命名空间
    </td>
  </tr>
  <tr>
    <td>
      var
    </td>
    <td>
      否
    </td>
    <td>
      String
    </td>
    <td>
      在页面后续代码中使用的动作对象的引用名
    </td>
  </tr>
  <tr>
    <td>
      executeResult
    </td>
    <td>
      否
    </td>
    <td>
      Boolean
    </td>
    <td>
      设置为true时排除动作的结果(默认值为false)
    </td>
  </tr>
  <tr>
    <td>
      flush
    </td>
    <td>
      否
    </td>
    <td>
      Boolean
    </td>
    <td>
      设置为true时在action标签的结尾会刷新写出缓冲(默认为true)
    </td>
  </tr>
  <tr>
    <td>
      ignoreConte xtParams
    </td>
    <td>
      否
    </td>
    <td>
      Boolean
    </td>
    <td>
      设置为true时动作被调用时不包含请求参数(默认值为false)
    </td>
  </tr>
</table>

以下是一个选择包含辅助动作结果的示例:

<pre>`&lt;h3&gt;Action Tag&lt;/h3&gt;
&lt;h4&gt;This line is from the ActionTag action's result.&lt;/h4&gt;
&lt;s:action name=&quot;TargetAction&quot; executeResult=&quot;true&quot;/&gt;
`</pre>

通常情况下,你希望辅助动作被触发,但不写结果,而是提供一个在ActionContext上某个地方存储域数据,在控制返回后,主动作可以访问这些数据,下面示例正是如此:

<pre>`&lt;h4&gt;This line is before the ActionTag invokes the secondary action.&lt;/h4&gt;
&lt;s:action name=&quot;TargetAction&quot;/&gt;
&lt;h4&gt;Secondary action has fired now.&lt;/h4&gt;
&lt;h5&gt;Request attribute set by secondary action = &lt;/h5&gt;
&lt;pre&gt; &lt;s:property value=&quot;#request.dataFromSecondAction&quot;/&gt;&lt;/pre&gt;
`</pre>

### 2.控制标签

Struts2中有一系列的标签可以容易的控制页面执行的流程,包括iterator标签和if/else标签等。

#### 2.1 iterator标签

使用iterator表亲啊可以很容易的便利集合对象。下面是这个标签的属性:

<table class="table table-bordered table-striped table-condensed">
  <tr>
    <td>
      属性
    </td>
    <td>
      是否必须
    </td>
    <td>
      类型
    </td>
    <td>
      描述
    </td>
  </tr>
  <tr>
    <td>
      value
    </td>
    <td>
      是
    </td>
    <td>
      Object
    </td>
    <td>
      被遍历的对象
    </td>
  </tr>
  <tr>
    <td>
      status
    </td>
    <td>
      否
    </td>
    <td>
      String
    </td>
    <td>
      如果被指定,IteratorStatus对象会使用这个属性指定的名字被放在ActionContext中
    </td>
  </tr>
</table>

下面是一个使用示例:

<pre>`&lt;s:iterator value=&quot;users&quot; status=&quot;itStatus&quot;&gt;
    &lt;li&gt;
    &lt;s:property value=&quot;#itStatus.count&quot; /&gt;
    &lt;s:property value=&quot;portfolioName&quot;/&gt;
    &lt;/li&gt;
&lt;/s:iterator&gt;
`</pre>

上面的代码很直观,在标签内部,每一个对象会轮流被放在ValueStack顶端,我们可以很容易的访问用户属性。注意,iterator标签通过指定status属性,也声明了IteratorStatus对象。你为status属性指定的名字会用来作为关键字从ActionContext中取得遍历状态对象。

**使用IteratorStatus**

有时候我们非常想知道当前发生的循环的状态信息。如果定义了status属性,那么会在ActionContext中提供一个IteratorStatus对象,这个对象可以提供诸如集合大小、当前索引、当前对象的索引是奇数还是偶数的简单信息。下面是IteratorStatus的共有方法:

<table class="table table-bordered table-striped table-condensed">
  <tr>
    <td>
      方法名
    </td>
    <td>
      返回值
    </td>
  </tr>
  <tr>
    <td>
      getCount
    </td>
    <td>
      int
    </td>
  </tr>
  <tr>
    <td>
      getIndex
    </td>
    <td>
      int
    </td>
  </tr>
  <tr>
    <td>
      isEven
    </td>
    <td>
      boolean
    </td>
  </tr>
  <tr>
    <td>
      isFirst
    </td>
    <td>
      boolean
    </td>
  </tr>
  <tr>
    <td>
      isLast
    </td>
    <td>
      boolean
    </td>
  </tr>
  <tr>
    <td>
      isOdd
    </td>
    <td>
      boolean
    </td>
  </tr>
  <tr>
    <td>
      modulus(int operand)
    </td>
    <td>
      boolean
    </td>
  </tr>
</table>

#### 2.2 if和else标签

很多语言都提供了熟悉的if和else控制逻辑,Struts2标签亦是如此。使用这些标签很容易,它们都只有一个属性,即布尔型test:

<table class="table table-bordered table-striped table-condensed">
  <tr>
    <td>
      属性
    </td>
    <td>
      是否必须
    </td>
    <td>
      类型
    </td>
    <td>
      描述
    </td>
  </tr>
  <tr>
    <td>
      test
    </td>
    <td>
      是
    </td>
    <td>
      Boolean
    </td>
    <td>
      被求值和测试的布尔表达式
    </td>
  </tr>
</table>

以下是如何使用这个标签的示例:

<pre>`&lt;s:if test=&quot;user.age &gt; 35&quot;&gt;This user is too old.&lt;/s:if&gt;
&lt;s:elseif test=&quot;user.age &lt; 35&quot;&gt;This user is too young&lt;/s:elseif&gt;
&lt;s:else&gt;This user is just right&lt;/s:else&gt;
`</pre>

### 3.其他标签

这一节将讨论Struts2的inclued标签、URL标签、i18n标签和text标签,最后了解下详细的param标签的使用。这些标签很有用,但是不太容易分类。

#### 3.1 inclued标签

虽然JSP有自己的包含标签&lt;jsp:include&gt;,但是Struts2提供了一个与Struts2集成的更好、有更多高级特性的include标签。简而言之,这个标签可以执行Servlet API样式的包含。下面是其唯一的属性:

<table class="table table-bordered table-striped table-condensed">
  <tr>
    <td>
      属性
    </td>
    <td>
      是否必须
    </td>
    <td>
      类型
    </td>
    <td>
      描述
    </td>
  </tr>
  <tr>
    <td>
      value
    </td>
    <td>
      是
    </td>
    <td>
      String
    </td>
    <td>
      页面、动作、Servlet以及其他可以被引用的URL的名字
    </td>
  </tr>
</table>

这个标签很简单,无须展示例子了吧。include标签的行为很想JSP的include标签,但是它与框架集成的更好并且提供了对ValueStack(使用%{...}从ValueStack取值)和可扩展参数模型的本地访问(使用&lt;s:param&gt;标签传递查询字符串参数)。

#### 3.2 URL标签

Struts2提供了URL标签来帮助管理URL,这个标签支持与URL相关的所有操作,从控制参数到Cookie缺失时自动持久化会话。下面是它的属性:

<table class="table table-bordered table-striped table-condensed">
  <tr>
    <td>
      属性
    </td>
    <td>
      是否必须
    </td>
    <td>
      类型
    </td>
    <td>
      描述
    </td>
  </tr>
  <tr>
    <td>
      value
    </td>
    <td>
      否
    </td>
    <td>
      String
    </td>
    <td>
      基础URL,默认为呈现当前页面的URL
    </td>
  </tr>
  <tr>
    <td>
      action
    </td>
    <td>
      否
    </td>
    <td>
      String
    </td>
    <td>
      生成的URL指向的动作名,使用声明性架构中配置的动作名(不带.action扩展名)
    </td>
  </tr>
  <tr>
    <td>
      var
    </td>
    <td>
      否
    </td>
    <td>
      String
    </td>
    <td>
      如果指定,这个URL不会被重写,而会存储在ActionContext留待后用
    </td>
  </tr>
  <tr>
    <td>
      includeParams
    </td>
    <td>
      否
    </td>
    <td>
      String
    </td>
    <td>
      从all、get、none中选择参数,默认值为get
    </td>
  </tr>
  <tr>
    <td>
      includeContext
    </td>
    <td>
      否
    </td> 
    <td>
      Boolean
    </td>
    <td>
      如果为true,那么生成的URL会使用应用程序的Context作为前缀,默认值为true
    </td>
  </tr>
  <tr>
    <td>
      encode
    </td>
    <td>
      否
    </td>
    <td>
      Boolean
    </td>
    <td>
      如果用户浏览器不支持Cookie,会将session ID追加到生成的URL中
    </td>
  </tr>
  <tr>
    <td>
      scheme
    </td>
    <td>
      否
    </td>
    <td>
      String
    </td>
    <td>
      指定协议,默认使用当前协议(HTTP或HTTPS)
    </td>
  </tr>
</table>

下面是两个示例:

<pre>`URL = &lt;s:url value=&quot;IteratorTag.action&quot;/&gt;
&lt;a href='&lt;s:url value=&quot;IteratorTag.action&quot; /&gt;'&gt; Click Me &lt;/a&gt;
`</pre>

URL标签只是把生成URL输出为字符串,下面是页面输出:

<pre>`URL = IteratorTag.action
&lt;a href='IteratorTag.action'&gt; Click Me &lt;/a&gt;
`</pre>

如果我们想指向一个动作,那么应该使用action属性:

<pre>`URL = &lt;s:url action=&quot;IteratorTag&quot; var=&quot;myUrl&quot;&gt;
                &lt;s:param name=&quot;id&quot; value=&quot;2&quot;/&gt;
            &lt;/s:url&gt;
&lt;a href='&lt;s:property value=&quot;#myUrl&quot; /&gt;'&gt; Click Me &lt;/a&gt;
`</pre>

这样页面输出会是这样:

<pre>`URL =
&lt;a href='/manningHelloWorld/chapterSix/IteratorTag.action?id=2'&gt;
    Click Me
&lt;/a&gt;
`</pre>

#### 3.3 i18n和text标签

这两个标签被用在国际化功能中,它们使用name属性指定关键字,通过这个关键字取得对应的文本消息。

下面是text标签支持的属性:

<table class="table table-bordered table-striped table-condensed">
  <tr>
    <td>
      属性
    </td>
    <td>
      是否必须
    </td>
    <td>
      类型
    </td>
    <td>
      描述
    </td>
  </tr>
  <tr>
    <td>
      name
    </td>
    <td>
      是
    </td>
    <td>
      String
    </td>
    <td>
      在ResourceBundle中查找用的关键字
    </td>
  </tr>
  <tr>
    <td>
      var
    </td>
    <td>
      否
    </td>
    <td>
      String
    </td>
    <td>
      如果找到,文本会使用这个名字保存在ActionContext中
    </td>
  </tr>
</table>

如果你想手动指定应该使用的ResourceBundle,可以使用i18n标签,下面是i18n的属性:

<table class="table table-bordered table-striped table-condensed">
  <tr>
    <td>
      属性
    </td>
    <td>
      是否必须
    </td>
    <td>
      类型
    </td>
    <td>
      描述
    </td>
  </tr>
  <tr>
    <td>
      name
    </td>
    <td>
      是
    </td>
    <td>
      String
    </td>
    <td>
      ResourceBundle的名字
    </td>
  </tr>
</table>

下面是一个示例,它展示了如何使用i18n标签设置ResourceBundle,以及如何使用text标签从中取出文本消息:

<pre>`&lt;s:i18n name=&quot;manning.chapterSix.myResourceBundle_tr&quot;&gt;
    In &lt;s:text name=&quot;language&quot;/&gt;,
    &lt;s:text name=&quot;girl&quot; var=&quot;foreignWord&quot;/&gt;
&lt;/s:i18n&gt;
&quot;&lt;s:property value=&quot;#foreignWord&quot;/&gt;&quot; means girl.

3.4 param标签

param标签什么也不做,但它是最重要的标签之一。它不仅在上述标签中起重要作用,而且在许多UI组件标签中也起重要作用。下面是它的属性:

属性 是否必须 类型 描述
name String 参数名
value Object 参数值

在之前的例子中已经展示了param标签的作用,包括作为一种自定义的工具对象传递参数的方法。只要有了这个整体思路,剩下的就是细读标签API看看哪个标签可以接受参数。

本文由作者按照 CC BY 4.0 进行授权