JavaWeb从入门到精通(视频实战版)
上QQ阅读APP看书,第一时间看更新

6.3 使用HTML标签

与通用标签不同,HTML标签不过多提供控制结构或逻辑。而是着重于如何使用action类、value stack或者Data Tags中的数据,并且在HTML中呈现出来。如果说普通标签只是简单地做些输出结果(如果有内容),HTML标签的输出则是因模板(template)而异,它们常常组合在一起作为一个主题(theme),做实际的渲染输出HTML的工作。关于模板和主题将在以后的章节详细介绍。

Struts2竭力支持开发者所偏爱的技术,这也是Struts2没有绑定于某一种特定的模板语言的原因。Struts2支持几乎所有应用广泛的模板语言甚至还为新语言提供了接口。默认情况下,几乎每一个标签都支持JSP、Velocity和FreeMarker。

注意

Struts2中默认的模板语言是FreeMarker,而不像其前身WebWork中默认的是Velocity。关于两者的优劣有很多评论,一般的说法是FreeMarker提供的错误信息更多,更加容易调试。

6.3.1 模板和主题

Struts提供的html标签的核心是主题(theme)和模板(template)。首先明确一下3个概念:

1)tag(标签):小段代码,在JSP、FreeMarker或者Velocity里执行。

2)template(模板):一个文件,通常使用JSP或者FreeMarker编写,能被特定的标签(HTML tags)输出。

3)theme(主题):一系列templates打包在一起,提供通用的功能。

Struts2提供了4种主题可以选择:

1)simple主题:一个最小的主题,包含了最少的辅助功能。使用simple主题的缺点就是它不支持其他主题那么多的属性。例如label属性在simple主题里没有任何用处。类似地,simple主题提供的功能也远远少于xhtml和ajax主题,自动显示错误信息就不被支持。

2)xhtml主题:使用了通用的HTML实践的默认主题。

3)css_xhtml主题:使用严格的CSS布局对xhtml主题重新实现。

4)ajax主题:一个基于xhtml主题的主题,提供了高级AJAX特性。

关于主题有两项配置,它们定义在struts.properties文件中,如表6.18所示。

表6.18 主题的配置

注意

使用simple主题的缺点就是它不支持其他主题那么多的属性。例如,label属性在simple主题里没有任何用处。类似地,simple主题提供的功能也远远少于xhtml和ajax主题提供的:自动显示错误信息就不被支持。

6.3.2 通用属性

每个UI标签都有一些共有的通用属性。除了那些处理label的属性,其他属性都可以在simple和xhtml主题上使用。表6.19列出了UI标签所有的通用属性。

表6.19 UI标签所有的通用属性

如果没有设定ID属性,那么Struts2表单标签会自动设置一个ID。form标签的ID就是其action的名字,如“updatePerson”。对于Form内的表单元素ID被设定为所在form的ID+"_"+元素的name属性,如“updatePerson_username”。

除了表6.19中的通用属性之外,所有的UI标签也支持通常设置的JavaScript事件。这允许简单的JavaScript集成并让表单更具有交互性,见表6.20。

表6.20 UI标签支持的JavaScript事件

所有的UI标签还有一项特性很有趣,也很有用,那就是“name-value联动”。通常在构建一个表单时输入数据的字段也是从它获取数据的字段,并会把它显示在表单中(通过value属性赋值)。常见的就是在修改属性的表单中,如下代码:

<s:form action="updateUser">
<s:textfield name="user.firstName" value="%{user.firstName}"/>
</s:form>

Struts2提供一个简单的方式,可以自动设置value的值,无须以显式的方式给value赋值了。如下代码所示:

<s:form action="updateUser">
<s:textfield name="user.firstName“/>
</s:form>

当然,有时不需要默认的值在表单中作为这个字段的值,可以给value属性赋其他值。

6.3.3 表单标签介绍

在HTML中的表单元素在Struts2中都提供了对应的标签来支持,见表6.21所示。

表6.21 表单标签成员列表

表单标签成员众多,但使用方法都比较类似。本书只介绍几种典型的标签。

1. form标签

form标签是所有UI标签中独一无二的,因为它担当了容器的角色。它有一个起点(<s:form>)和一个终点(</s:form>)。在simple主题里,它只输出html的form元素,而在xhtml主题中,它除了form元素之外还输出周围的表格。form标签的属性如表6.22所示。

表6.22 form标签属性表

要注意最重要的两个属性是action和namespace。它们组合起来,用来把form链接到一个特殊的action。例如,如下代码会被提交到/secure/updateProfile.action:

<s:form action="updateProfile" namespace="/secure">

2. textfield标签

textfield标签是最常用的一个UI标签,输出一个text类型的HTML input元素,在前面的章节中已经多次使用。textfield标签的属性如表6.23所示。

表6.23 textfield标签属性表

3. textarea标签

textarea标签用来填写比textfield标签更大数量的文本(包括换行符),不像textfield和password标签那样输出HTML<input>标记,这个标签输出HTML<textarea>标记。textarea标签的参数如表6.24所示。

表6.24 textarea标签参数表

4. checkbox标签

不像其他标签,checkbox标签不把字段的value当成字符串类型。也就是说,复选框必须有一个字段为布尔量来求值或者能被转化为布尔类型。

<s:checkbox label=" BOX" name=user.address.poBox fieldValue="true'>

注意

复选框和其他的标签有点不同。HTML的规范方式要求只有当复选框被选中的时候才会提交对应的值。如果复选框没有被选中,那么提交的参数中就根本不包含这个项目。因此接受参数的model设计时,应该将默认值定为false,很可能是model此字段没有被赋值。这样做可以保证表单提交时不论复选框状态为何,都会得到期望的值。

5. select标签

创建一个HTML Select列表组件。select标签的参数如表6.25所示。

表6.25 select标签参数表

最重要的属性是list,它告诉标签要选择的选项从哪里来。在最简单的表单里,列表呈现给用户,选择的值会被提交到表单并被映射到指定的字段,也是与名字对应的属性。如果一个值被预先设置,那么列表里这个字段具有相同值的选项就会自动被选中。

<s:select label="State" name="user.address.state" list="{'江西','湖北'}">

在这个例子中,表达式user.address.state的值会被设置为江西或者湖北。如果填入的值是这两个值中的一个,select标签就会设置表单。输出的HTML可能是

<select>
<option>'江西'<option>
<option>'湖北'<option>
</select>

很多时候可能会希望option的显示值和实际值是不同的。比如:

<select>
<option value=1>'江西'<option>
<option value=2>'湖北'<option>
</select>

这需要给select标签设置listKey和listValue属性就可以。listKey和listValue特性是通过迭代这个列表并在循环中把对象放到stack顶部的方式进行的。这也是iterator标签使用的相同的方式。如果使用的是一个map作为select标签进行迭代的列表,对象会通过Map.Entry进行迭代,就像iterator标签一样。因为Map.Entry提供了getKey()和getValue()方法,这些通常被用来作为listKey和listValue的值。使用基于Map的方法来重新编写state下拉框:

<s:select label="State" name="user.address.state" list="#{1:'江西', 2:'湖北'}">

6.3.4 非表单标签

非表单标签与表单标签相反,是为输出一些表单以外的HTML元素设计的,主要用于显示而非提交参数。它们也会带来很多方便,如table自动排序等。非表单标签成员如表6.26所示。

表6.26 非表单标签成员列表

需要解释一下的是component标签,使用特定的模板输出一个自定义的UI widget(组件)。附加的对象可以通过param标签传递给模板,设置的对象可以在模板里面通过 $parameters.paramname获取。如在component(组件)内部,它们可以通过$parameters.get('key1') 和 $parameters.get('key2') 的方式被访问,也允许通过$parameters.key1和$parameters.key2来引用它们。

component标签提供了一种建立自定义UI标签的方式。例如,假设想要一个包含3项的复选框来表示on/off/none,可以使用HTML来编写一个,用JavaScript和一些定制的图像来代表3个状态。

6.3.5 标签实例

首先看一下需要表现的页面,是一个用户信息修改提交页面,如图6.11所示。

图6.11 标签举例界面图

如果用普通JSP表现,如实例6-14所示,在firstname字段后面有关于错误信息的处理,如果有错误信息,就在这个字段后面打印错误日志。

【实例6-14】标签实例:updateProfile.jsp

01    <%@ page
02    import="org.hibernate.auction.model.User,org.hibernate.auction.model.Address,
      java.util.Map,java.util.Collections"%>
03    <%
04      User user = (User) request.getAttribute("user");
05      Map fieldErrors = (Map) request.getAttribute("fieldErrors");
06      if (fieldErrors == null) {
07         fieldErrors = Collections.EMPTY_MAP;
08      }
09    %>
10 <html>
11        <head>
12             <title><s:text name="title" />UpdateProfile</title>
13        </head>
14        <body>
15             <form action="updateProfile.action" method="post">
16                  <table>
17                        <% if (fieldErrors.containsKey("user.firstname")) {%>
18                        <tr>
19                             <td align="center" valign="top" colspan="2">
2 0                                  <span class="errorMessage"> <%= fieldErrors.get("user.firstname")%>
21                                  </span>
22                             </td>
23                        </tr>
24                        <% }%>
25                        <tr>
26                             <td align="right">
27                                  <label>
28                                      First name£o
29                                  </label>
30                             </td>
31                             <td>
32                                  <input type="text" name="user.firstname"
33                                        value="<%= user.getFirstname() %>" />
34                             </td>
35                        </tr>
36                        <tr>
37                             <td align="right">
38                                  <label>
39                                      Last name£o
40                                  </label>
41                             </td>
42                             <td>
43                                  <input type="text" name="user.lastname"
44                                        value="<%= user.getLastname() %>" />
45                             </td>
46                        </tr>
47                        <tr>
48                             <td align="right">
49                                  <label>
50                                      Email£o
51                                  </label>
52                             </td>
53                             <td>
54                                  <input type="text" name="user.email"
55                                        value="<%= user.getEmail() %>" />
56                             </td>
57                        </tr>
58                        <tr>
59                             <td align="right">
60                                  <label>
61                                      Gender£o
62                                  </label>
63                             </td>
64                             <td>
6 5                                  <input type="radio" name="user.gender" value="0" id="user.gender0"
6 6                                        <% if (user.getGender() == 0) { %> checked="checked" <% } %> />
67                                  <label for="user.gender0">
68                                        Male
69                                  </label>
7 0                                  <input type="radio" name="user.gender" value="1" id="user.gender1"
7 1                                        <% if (user.getGender() == 1) { %> checked="checked" <% } %> />
72                                  <label for="user.gender1">
73                                        Female
74                                  </label>
75                             </td>
76                        </tr>
77                        <%
78     Address address = user.getAddress();
79     boolean nullAddress = address == null;
80 %>
81                        <tr>
82                             <td align="right">
83                                  <label>
84                                        Street Address:
85                                  </label>
86                             </td>
87                             <td>
88                                  <input type="text" name="user.address.street"
89                                      value="<%= !nullAddress ? address.getStreet() £o ""%>" />
90                             </td>
91                        </tr>
92                        <tr>
93                             <td align="right">
94                                  <label>
95                                      Zip Code£o
96                                  </label>
97                             </td>
98                             <td>
99                                  <input type="text" name="user.address.zipcode"
100                                     value="<%= !nullAddress ?address.getZipcode() £o ""%>" />
101                            </td>
102                      </tr>
103                      <tr>
104                            <td align="right">
105                                 <label>
106                                     City£o
107                                 </label>
108                            </td>
109                            <td>
110                                 <input type="text" name="user.address.city"
111                                     value="<%= !nullAddress ?address.getCity() £o ""%>" />
112                            </td>
113                      </tr>
114                      <tr>
115                            <td align="right">
116                                 <label>
117                                     State£o
118                                 </label>
119                            </td>
120                            <td>
121                                 <select name="user.address.state">
122                                      <option value="Californa"
123                                            <% if (!nullAddress &&
124                        "California".equals(address.getState())) { %>
125                                            selected="selected" <% } %>>
126                                            Californa
127                                      </option>
128                                      <option value="Oregon"
129                                            <% if (!nullAddress &&
130                        "Oregon".equals(address.getState())) { %>
131                                            selected="selected" <% } %>>
132                                            Oregon
133                                      </option>
134                                 </select>
135                            </td>
136                      </tr>
137                      <tr>
138                            <td align="right">
139                                 <label>
140                                     Country£o
141                                 </label>
142                            </td>
143                            <td>
144                                 <select name="user.address.country">
145                                      <option value="USA"
146                                            <% if (!nullAddress && "USA".equals(address.getCountry())) { %>
147                                            selected="selected" <% } %>>
148                                            USA
149                                      </option>
150                                      <option value="Canada"
151                                            <% if (!nullAddress &&"Canada".equals(address.getCountry())) { %>
152                                            selected="selected" <% } %>>
153                                            Canada
154                                      </option>
155                                      <option value="Mexico"
156                                            <% if (!nullAddress &&"Mexico".equals(address.getCountry())) { %>
157                                            selected="selected" <% } %>>
158                                            Mexico
159                                      </option>
160                                      <option value="Other"
161                                            <% if (!nullAddress &&"Other".equals(address.getCountry())) { %>
162                                            selected="selected" <% } %>>
163                                            Other
164                                      </option>
165                                 </select>
166                            </td>
167                      </tr>
168                      <tr>
169                            <td colspan="2">
170                                 <table>
171                                      <tr>
172                                            <td valign="middle">
173                                                 <input type="checkbox" name="user.address.poBox" value="true"
174                                                      <% if (!nullAddress && address.isPoBox()) { %>
175                                                      checked="checked" <% } %> />
176                                            </td>
177                                            <td valign="middle" style="width:100%">
178                                                 <label class="checkboxLabel">
179                                                      P.O. Box
180                                                 </label>
181                                            </td>
182                                      </tr>
183                                 </table>
184                            </td>
185                      </tr>
186                      <tr>
187                            <td colspan="2">
188                                 <div align="'right'">
189                                      <input value="Update Profile" type="submit" />
190                                 </div>
191                            </td>
192                      </tr>
193                 </table>
194            </form>
195      </body>
196 </html>

【代码剖析】在上述代码中,如果改为由Struts2的标签实现,那么该代码里190多行的代码只剩下30行就可以完成,Strus2的标签威力可见一斑。

通过使用Struts2标签不仅输入与Java值对象的关系是自动完成的,而且控件的布局(在xhtml主题中对form及其中的控件都使用table做了自动布局等渲染工作,在sample主题中不包含自动布局功能。请参考6.5.3节中的介绍)、错误信息的处理都是由标签完成,用户无须再干预,具体内容如实例6-15所示。

【实例6-15】标签实例:updateProfile1.jsp

01     <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
02     <%@ page import="java.util.Map,java.util.Collections"%>
03     <%@ taglib prefix="s" uri="/struts-tags"%>
04     <html>
05          <head>
06                <title>UpdateProfile</title>
07                <s:head />
08          </head>
09          <body>
10               <!--使用标签实现JSP-->
11                <s:form action="updateProfile" method="post">
12                     <s:textfield label="First name" name="user.firstname"
13                          cssStyle="float:left; color:red" />
14                     <s:textfield label="Last name" name="user.lastname" />
15                     <s:textfield label="Email" name="user.email" />
16                     <s:radio label="Gender" name="user.gender"
17                          list="#{0 : 'Male', 1 : 'Female'}" />
18                     <s:textfield label="Street" name="user.address.street" />
19                     <s:textfield label="Zip Code" name="user.address.zipcode" />
20                     <s:textfield label="City" name="user.address.city" />
21                     <s:select label="State" name="user.address.state"
22                          list="{'Californa', 'Oregon'}" />
23                     <s:select label="Country" name="user.address.country"
24                          list="{'USA', 'Canada', 'Mexico', 'Other'}" />
25                     <s:checkbox label="P.O. Box" name="user.address.poBox"
26                          fieldValue="true" />
27                     <s:submit value="Update Profile" />
28                </s:form>
29                <s:set name="user" value="user" scope="request" />
30                <s:set name="fieldErrors" value="fieldErrors" scope="request" />
31          </body>
32     </html>

【代码剖析】由于Struts2会自动增加控件的样式所有,如果想自己定义空间的样式不能再使用class属性,要使用Struts2单独提供的cssClass、cssStyle属性。这两个属性在通用属性中已经有过介绍,是所有控件都具有的属性。

图6.12 OGNL对象范围