Struts 2 标签(二)

Posted by yangchw on March 14, 2013

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

1.数据标签

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

1.1 property标签

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

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

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

<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看看哪个标签可以接受参数。