This page last changed on Sep 16, 2004 by vitorsouza.

4.1.1: WebWork的UI标签

在WebWork中, UI标签包装了HTML控件以便与核心框架紧密集成. 这些标签设计目标是最小化代码中的逻辑部分, 并用一个模版系统代理最终的HTML绘制. UI标签试图覆盖最普遍的情景(scenario), 并提供了一个component标签以创建定制组件.UI标签还内建支持显示内嵌的错误信息.

本节解释如何利用UI标签的优点构建表单和其他图形控件, 并通过讲解模版系统的工作原理, 学习如何修改已有组件的外观以及定制新组件.

构建表单(form):

WebWork提供现成的用于构建表单的标签. 其中一些标签的名字可以和HTML标签名字直接联系起来, 通过名字你就可以领会它的用途: <ww:checkbox />, <ww:file />, <ww:form />, <ww:hidden />, <ww:label />, <ww:password />, <ww:radio />, <ww:select />, <ww:submit />, <ww:textarea /><ww:textfield />.

要使用这些标签构建表单, 只需把它们像HTML标签那样放在页面上. 唯一的区别是参数应当用双引号和单引号廓起来(key="'value'"). 这是因为非单引号的名称将使用值栈重新赋值.

然我们看看这个例子:

ex01-index.jsp:

<%@ taglib uri="webwork" prefix="ww" %>
<html>
<head>
<title>WebWork Tutorial - Lesson 4.1.1 - Example 1</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css">
	.errorMessage { color: red; }
</style>
</head>

<body>

<p>UI Form Tags Example:</p>

<ww:form action="'formProcessing.action'" method="'post'">
	<ww:checkbox name="'checkbox'" label="'A checkbox'" fieldValue="'checkbox_value'" />
	<ww:file name="'file'" label="'A file field'" />
	<ww:hidden name="'hidden'" value="'hidden_value'" />
	<ww:label label="'A label'" />
	<ww:password name="'password'" label="'A password field'" />
	<ww:radio name="'radio'" label="'Radio buttons'" list="{'One', 'Two', 'Three'}" />
	<ww:select name="'select'" label="'A select list'" list="{'One', 'Two', 'Three'}" 
		emptyOption="true" />
	<ww:textarea name="'textarea'" label="'A text area'" rows="'3'" cols="'40'" />
	<ww:textfield name="'textfield'" label="'A text field'" />
	<ww:submit value="'Send Form'" />
</ww:form>

</body>
</html>

ex01-index.jsp处理后的HTML结果如下:

<html> 
<head> 
<title>WebWork Tutorial - Lesson 4.1.1 - Example 1</title>
<style type="text/css"> 
  .errorMessage { color: red; } 
</style>   
</head> 

<body> 

<p>UI Form Tags Example:</p> 

<table> 
<form 
action="formProcessing.action" method="post" > 

   


<tr> 
<td valign="top" colspan="2"> 

<table width="100%" border="0" cellpadding="0" cellspacing="0"> 
<tr><td valign="top"> 
<input type="checkbox" 
name="checkbox" 
value="checkbox_value" 
/> 
</td> 
<td width="100%" valign="top"> 
<span class="checkboxLabel"> 
A checkbox 
</span> 
</td> 
</tr> 
</table> 
</td> 
</tr> 

   



<tr> 
<td align="right" valign="top"> 

<span class="label"> 

A file field: 
</span> 
</td> 

<td> 

<input type="file" 
name="file" 
/> 

</td> 
</tr> 

  <input 
type="hidden" 
name="hidden" value="hidden_value" /> 
   



<tr> 
<td align="right" valign="top"> 

<span class="label"> 

A label: 
</span> 
</td> 

<td> 
<label> </label> 
</td> 
</tr> 

   




<tr> 
<td align="right" valign="top"> 

<span class="label"> 

A password field: 
</span> 
</td> 

<td> 

<input type="password" 
name="password" 


/> 

</td> 
</tr> 

   



<tr> 
<td align="right" valign="top"> 

<span class="label"> 

Radio buttons: 
</span> 
</td> 

<td> 





<input 
type="radio" 
name="radio" 
id="radioOne" 
value="One" /> 
<label for="radioOne">One</label> 





<input 
type="radio" 
name="radio" 
id="radioTwo" 
value="Two" /> 
<label for="radioTwo">Two</label> 





<input 
type="radio" 
name="radio" 
id="radioThree" 
value="Three" /> 
<label for="radioThree">Three</label> 


</td> 
</tr> 

   



<tr> 
<td align="right" valign="top"> 

<span class="label"> 

A select list: 
</span> 
</td> 

<td> 

<select name="select" 
> 


<option value=""></option> 





<option value="One" 
>One</option> 





<option value="Two" 
>Two</option> 





<option value="Three" 
>Three</option> 


</select> 

</td> 
</tr> 

   



<tr> 
<td align="right" valign="top"> 

<span class="label"> 

A text area: 
</span> 
</td> 

<td> 

<textarea name="textarea" 
cols="40" 
rows="3" 
></textarea> 

</td> 
</tr> 

   



<tr> 
<td align="right" valign="top"> 

<span class="label"> 

A text field: 
</span> 
</td> 

<td> 

<input type="text" 
name="textfield" 
/> 

</td> 
</tr> 

  <tr> 
<td colspan="2"><div 
align="right" ><input 
type="submit" 
value="Send Form" /></div> 
</td> 
</tr> 

</form> 
</table> 


</body> 
</html>

xwork.xml:

<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" 
"http://www.opensymphony.com/xwork/xwork-1.0.dtd">

<xwork>
	<!-- Include webwork defaults (from WebWork JAR). -->
	<include file="webwork-default.xml" />
	
	<!-- Configuration for the default package. -->
	<package name="default" extends="webwork-default">
		<action name="formProcessing" class="lesson04_01_01.FormProcessingAction">
			<result name="input" type="dispatcher">ex01-index.jsp</result>
			<result name="success" type="dispatcher">ex01-success.jsp</result>
			<interceptor-ref name="validationWorkflowStack" />
		</action>
	</package>
</xwork>

FormProcessingAction.java:

package lesson04_01_01;

import com.opensymphony.xwork.ActionSupport;

public class FormProcessingAction extends ActionSupport {
	private String checkbox;
	private String file;
	private String hidden;
	private String password;
	private String radio;
	private String select;
	private String textarea;
	private String textfield;
	
	public String getCheckbox() { return checkbox; }
	public String getFile() { return file; }
	public String getHidden() { return hidden; }
	public String getPassword() { return password; }
	public String getRadio() { return radio; }
	public String getSelect() { return select; }
	public String getTextarea() { return textarea; }
	public String getTextfield() { return textfield; }
	
	public void setCheckbox(String checkbox) { this.checkbox = checkbox; }
	public void setFile(String file) { this.file = file; }
	public void setHidden(String hidden) { this.hidden = hidden; }
	public void setPassword(String password) { this.password = password; }
	public void setRadio(String radio) { this.radio = radio; }
	public void setSelect(String select) { this.select = select; }
	public void setTextarea(String textarea) { this.textarea = textarea; }
	public void setTextfield(String textfield) { this.textfield = textfield; }
	
	public String execute() throws Exception {
		return SUCCESS;
	}
}

FormProcessingAction-validation.xml:

<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.dtd">

<validators>
  <field name="checkbox">
    <field-validator type="requiredstring">
      <message>Please, check the checkbox.</message>
    </field-validator>
  </field>

  <field name="file">
    <field-validator type="requiredstring">
      <message>Please select a file.</message>
    </field-validator>
  </field>

  <field name="password">
    <field-validator type="requiredstring">
      <message>Please type something in the password field.</message>
    </field-validator>
  </field>

  <field name="radio">
    <field-validator type="requiredstring">
      <message>Please select a radio button.</message>
    </field-validator>
  </field>

  <field name="select">
    <field-validator type="requiredstring">
      <message>Please select an option from the list.</message>
    </field-validator>
  </field>

  <field name="textarea">
    <field-validator type="requiredstring">
      <message>Please type something in the text area.</message>
    </field-validator>
  </field>

  <field name="textfield">
    <field-validator type="requiredstring">
      <message>Please type something in the text field.</message>
    </field-validator>
  </field>
</validators>

ex01-success.jsp:

<%@ taglib uri="webwork" prefix="ww" %>
<html>
<head>
<title>WebWork Tutorial - Lesson 4.1.1 - Example 1</title>
</head>

<body>

<p>UI Form Tags Example result:</p>

<ul>
  <li>checkbox: <ww:property value="checkbox" /></li>
  <li>file: <ww:property value="file" /></li>
  <li>hidden: <ww:property value="hidden" /></li>
  <li>password: <ww:property value="password" /></li>
  <li>radio: <ww:property value="radio" /></li>
  <li>select: <ww:property value="select" /></li>
  <li>textarea: <ww:property value="textarea" /></li>
  <li>textfield: <ww:property value="textfield" /></li>
</ul>

</body>
</html>

请注意与HTML结果相比, ex01-index.jsp要清晰的多. 表单组件的缺省布局是一个文字标签在左侧, 输入字段在右侧的表格布局. 在下文解释了模版系统后, 我们可以知道图和创建自己的布局.

另外需要注意的是在活动配置中对validationWorkflowStack的引用. 它要求WebWork按照于活动类位于统一位置的配置文件校验发送到活动中的数据, 本例中是FormProcessingAction-validation.xml (参见校验). 如果某些数据不正确, 这将不执行活动并将请求转发到输入页面, 同时将错误信息附加在每一字段上(使用方法addFieldError(String fieldName, String errorMessage)).

但是我们现在不必关心校验框架如何工作. 运行该例子并试着让某些字段空着. 你会看到UI标签显示出与校验框架集成的错误信息, 而这也是我们要向你演示的. 分离关注点能够帮助程序员和设计人员更关注自己的那部分工作.
进一步阅读: UI标签

试试这个例子!

其他UI控件:

除了HTML设计人员已经熟悉的标准表单控件外, WebWork还提供了其他一些空间并且也能创建定制组件. 让我们看一看WebWork提供的这些控件:
<ww:checkboxlist /><ww:radio />标签的功能相似, 单使用复选框(checkbox)而不是单选按钮(radio button). 它从集合中获取键值和值来创建一组具有相同名字的复选框.
<ww:combobox />模仿一个组合框(combobox), 混合了一个选项列表和一个文本框. 它在一个<select />列表上放置了一个文本框, 每一次选项列表值发生变化时利用JavaScript代码填入文本框中.
<ww:tabbedpane />这部分内容需要帮助.
<ww:token />这部分内容需要帮助.

进一步阅读: UI Tags

模版系统:

WebWork使用Velocity模版系统为每个UI标签绘制最终的HTML. 所有模版的缺省实现已经包含在核心发行包中并允许用户'打破常规'使用UI标签. 模版可以分别修改或整个替换以便完全定制HTML输出结果. 另外, 每一个标签都可以选择覆盖缺省模版从而允许进行精细的控制. 缺省模版位于文件webwork-2.1.1.jar/template/xhtml目录下.

如果你解开webwork-2.1.1.jar并查看目录/template/xhtml就会发现一组velocity模版文件. 大部分与某一UI标签相对应, 名称也与标签相同. 如果你已经熟悉了Velocity, 推荐你分析这些模版文件看看你能对他们做什么. 从2.1版本开始, 还有一个目录/template/simple, 这里有一个HTML表单控件的更简单版本(仅包含控件, 没有表格和文本标签).

如果你想用不同于WebWork自带的布局显示你的UI组件, 你可以:
  • 编辑并替换/template/xhtml目录下的文件(重新打包Jar文件或在别处创建相同的目录结构并确保Web容器能够在Jar文件之前找到它);
  • 通过修改文件webwork.properties(应当位于根类路径中)中的webwork.ui.theme属性来改变模版目录;
  • 使用主题(theme)或模版属性分别为每个标签指定模版位置. 这种方法允许指定全部模版所在的目录(WebWork用与/template/xhtml目录下相同的文件名查找模版文件), 这允许你精确的指定组件所使用的模版.

进一步阅读: 模版, 主题

下面的例子中演示了第三种方式. 需要注意的是, 缺省情况下, 指定的主题目录应当位于/template目录下, 指定的模版文件应当位于/template/xhtml目录下.

ex02.jsp:

<%@ taglib uri="webwork" prefix="ww" %> 
<html> 
<head> 
<title>WebWork Tutorial - Lesson 4.1.1 - Example 2</title> 
</head> 

<body> 

<p>Template Change Example:</p> 

<p><ww:checkbox name="'checkbox'" label="'A checkbox'" fieldValue="'checkbox_value'" theme="'mytheme'" /></p> 

<p><ww:textfield name="'textfield'" label="'A text field'" template="mytextfield.vm" /></p> 

</body> 
</html>

/template/mytheme/checkbox.vm:

<div align="center"> 
	<input type="checkbox" 
		name="$!webwork.htmlEncode($parameters.name)" 
		value="$!webwork.htmlEncode($parameters.fieldValue)" 
	#if ($parameters.nameValue) checked="checked" #end 
	#if ($parameters.disabled == true) disabled="disabled" #end 
	#if ($parameters.tabindex) tabindex="$!webwork.htmlEncode($parameters.tabindex)" #end 
	#if ($parameters.onchange) onchange="$!webwork.htmlEncode($parameters.onchange)" #end 
	#if ($parameters.id) id="$!webwork.htmlEncode($parameters.id)" #end 
	/><br /> 
	$!webwork.htmlEncode($parameters.label) 
</div>

/template/xhtml/mytextfield.vm:

<div align="center"> 
	<input type="text" 
		name="$!webwork.htmlEncode($parameters.name)" 
	#if ($parameters.size) size="$!webwork.htmlEncode($parameters.size)" #end 
	#if ($parameters.maxlength) maxlength="$!webwork.htmlEncode($parameters.maxlength)" #end 
	#if ($parameters.nameValue) value="$!webwork.htmlEncode($parameters.nameValue)" #end 
	#if ($parameters.disabled == true) disabled="disabled" #end 
	#if ($parameters.readonly) readonly="readonly" #end 
	#if ($parameters.onkeyup) onkeyup="$!webwork.htmlEncode($parameters.onkeyup)" #end 
	#if ($parameters.tabindex) tabindex="$!webwork.htmlEncode($parameters.tabindex)" #end 
	#if ($parameters.onchange) onchange="$!webwork.htmlEncode($parameters.onchange)" #end 
	#if ($parameters.id) id="$!webwork.htmlEncode($parameters.id)" #end 
	/><br /> 
	$!webwork.htmlEncode($parameters.label) 
</div>

ex02.jsp处理的HTML结果:

<html> 
<head> 
<title>WebWork Tutorial - Lesson 4.1.1 - Example 2</title> 
</head> 

<body> 

<p>Template Change Example:</p> 

<p><div align="center"> 
  <input type="checkbox" 
         name="checkbox" 
         value="checkbox_value" 
            /><br /> 
  A checkbox 
</div></p> 

<p><div align="center"> 
  <input type="text" 
                                     name="textfield" 
                    /><br /> 
  A text field 
</div></p> 

</body> 
</html>

试试这个例子!

构建定制的UI组件:

有时候没有一个WebWork附带的UI组件能够满足你的要求. 这时, 推荐的方式就是创建自己的定制组件. 通过这种方式, 保持了页面了清晰且与布局和错误检查问题无关, 并促进了组件复用.

要创建一个定制组件, 只需要为它创建一个Velocity模版, 就像那些已有组件那样. 为把它用在页面上, 使用<ww:component />标签并在template参数中指定模版即可.

要传递模版所需的参数, 可以使用<ww:param />标签(参见4.1). 下面的例子演示了一个定制的日期字段的创建过程.
进一步阅读: UI标签

ex03.jsp:

<%@ taglib uri="webwork" prefix="ww" %> 
<html> 
<head> 
<title>WebWork Tutorial - Lesson 4.1.1 - Example 3</title> 
</head> 

<body> 
<p>Custom Component Example:</p> 

<p> 
<ww:component template="datefield.vm"> 
	<ww:param name="'label'" value="'Date'" /> 
	<ww:param name="'name'" value="'mydatefield'" /> 
	<ww:param name="'size'" value="3" /> 
</ww:component> 
</p> 

</body> 
</html>

/template/xhtml/datefield.vm:

#set ($name = $parameters.get('name')) 
#set ($size = $parameters.get('size')) 
#set ($yearSize = $size * 2) 

$parameters.get('label'): 
<input type="text" name="${name}.day" size="$size" /> / 
<input type="text" name="${name}.month" size="$size" /> / 
<input type="text" name="${name}.year" size="$yearSize" /> (dd/mm/yyyy)

ex03.jsp处理的HTML结果:

<html> 
<head> 
<title>WebWork Tutorial - Lesson 4.1.1 - Example 3</title> 
</head> 
<body> 
<p>Custom Component Example:</p> 

<p> 
Date: 
<input type="text" name="mydatefield.day" size="3" /> / 
<input type="text" name="mydatefield.month" size="3" /> / 
<input type="text" name="mydatefield.year" size="6" /> (dd/mm/yyyy) 
</p> 

</body> 
</html>

试试这个例子!


上一课 | 下一课
Document generated by Confluence on Dec 14, 2004 16:36