简介 本文是有关Faces Portlet开发的系列文章的第二部分,这里我们会关注于如何构建Portlet表单应用。 第一部分 Faces Portlet开发框架初体验
首先,我们先来回顾一下表单的基本原理及其广泛应用;接着,我们会就Faces Portlet中和表单应用相关的话题分别加以介绍;然后,我们选取了一个典型的表单应用――注册表单,来讲述构建Portlet表单应用的基本过程;最后,部署测试这个应用。
阅读本文之前,需要您对Web应用中表单的使用有所了解,同时最好能够对JSP和TagLib技术有所了解。
表单应用 表单是动态Web应用中最基本的技术之一,应用广泛,它常常承担着数据采集的重任。
一个典型的表单主要有以下三个基本组成部分:
- 表单标签:这里面包含了处理表单数据所需要的后台程序的URL以及数据提交到服务器的方法。
- 表单域:包含了文本框、密码框、隐藏域、多行文本框、复选框、单选框、下拉选择框和文件上传框等,Web应用就是通过这些控件来采集数据的。
- 表单按钮:包括提交按钮、复位按钮等;用于将数据传送到服务器上的处理程序或者取消输入,还可以用表单按钮来控制其他的处理工作。
表单相关标签及控件 标准HTML中定义了很多和表单相关的标签;而Faces Portlet开发框架则提供了丰富的用户UI控件,它们或是对相应的HTML标签做了简单的包装,或是对这些HTML标签做了进一步的扩展,丰富了它们的属性,这些控件都被实现成TagLib的形式,便于封装和将来的重用。
因此,对于Faces Portlet开发框架下的每个Faces JSP页面,都会在文件的头部增加
<%@taglib uri="http://java./jsf/core" prefix="f"%>
<%@taglib uri="http://java./jsf/html" prefix="h"%>
<%@taglib uri="http://www.ibm.com/jsf/html_extended" prefix="hx"%>
|
这样三行声明。
下面,我们就将表单应用相关的最常用的一些标签和控件放在一起做简单比较,对于每个标签和控件具体的属性请查阅相关文档,这里不再赘述。
表单标签
- 表单标签 <form></form>
这个标签用于标记表单,定义采集数据的范围,也就是<form>和</form>里面包含的数据将被提交到服务器。 样例:
<form action="http://www./test.jsp" method="post" target="_blank">...</form>
| 表示表单将向http://www./test.jsp以post的方式提交,提交的结果在新的页面显示。 Faces Portlet中相应的控件则是:
<h:form styleClass="form" id="form1">…</h:form>
| 相应的action功能已经转移到对应的表单按钮来完成。
表单域 表单域包含了文本框、多行文本框、密码框、隐藏域、复选框、单选框和下拉选择框等,用于采集用户的输入或选择的数据,下面分别讲述这些表单域的代码格式:
- 文本框
文本框是一种让用户自己输入内容的表单对象,通常被用来填写单个字或者简短的回答,如姓名、地址等。
代码格式:<input type="text" name="..." size="..." maxlength="..." value="...">
样例1:
样例1代码:
<input type="text" name="example1" size="20" maxlength="15">
|
Faces Portlet中相应的控件则是:
<h:inputText styleClass="inputText" id="text1"></h:inputText>
|
- 多行文本框
这也是一种让访问者自己输入内容的表单对象,只不过能让访问者填写较长的内容。
代码格式:<TEXTAREA name="..." cols="..." rows="..." wrap="VIRTUAL"></TEXTAREA>
样例2:
样例2代码:
<TEXTAREA name="example2" cols="20" rows="2" wrap="PHYSICAL"></TEXTAREA>
|
Faces Portlet中相应的控件则是:
<h:inputTextarea styleClass="inputTextarea" id="textarea1"></h:inputTextarea>
|
- 密码框
是一种特殊的文本域,用于输入密码。当访问者输入文字时,文字会被星号或其它符号代替,而输入的文字会被隐藏。
代码格式:<input type="password" name="..." size="..." maxlength="...">
样例3:
样例3代码:
<input type="password" name="example3" size="20" maxlength="15">
|
Faces Portlet中相应的控件则是:
<h:inputSecret styleClass="inputSecret" id="secret1"></h:inputSecret>
|
- 复选框
复选框允许在待选项中选中一项以上的选项。每个复选框都是一个独立的元素,都必须有一个唯一的名称。
代码格式:<INPUT type="checkbox" name="..." value="...">
样例4: yahoo.com google.com
样例4代码:
<input type="checkbox" name="yahoo" value="01">yahoo.com
<input type="checkbox" name="google" value="02">google.com
|
Faces Portlet中相应的控件则扩展成了单选框和多选框两种,分别是:
<h:selectBooleanCheckbox styleClass="selectBooleanCheckbox"
id="checkbox1" value="Google.com">
</h:selectBooleanCheckbox>
<h:selectManyCheckbox styleClass="selectManyCheckbox" id="checkbox2">
<f:selectItem itemLabel="Google.com" itemValue="Google.com" />
<f:selectItem itemLabel="Yahoo.com" itemValue="itemValue2" />
</h:selectManyCheckbox>
|
- 单选框
当需要访问者在待选项中选择唯一的答案时,就需要用到单选框了。
代码格式:<input type="radio" name="..." value="...">
样例5: yahoo.com google.com
样例5代码:
<input type="radio" name="myFavor" value="1">yahoo.com
<input type="radio" name="myFavor" value="2">google.com
|
Faces Portlet中相应的控件则是:
<h:selectOneRadio styleClass="selectOneRadio" id="radio1">
<f:selectItem itemLabel="Yahoo.com" itemValue="Yahoo.com" />
<f:selectItem itemLabel="Google.com" itemValue="itemValue2" />
</h:selectOneRadio>
|
- 文件上传框
有时候,需要用户上传自己的文件,文件上传框看上去和其它文本域差不多,只是它还包含了一个浏览按钮。访问者可以通过输入需要上传的文件的路径或者点击浏览按钮选择需要上传的文件。
注意:在使用文件域以前,请先确定你的服务器是否允许匿名上传文件。表单标签中必须设置ENCTYPE="multipart/form-data"来确保文件被正确编码;另外,表单的传送方式必须设置成POST。
代码格式:<input type="file" name="..." size="15" maxlength="100">
样例6:
样例6代码: <input type="file" name="myfile" size="15" maxlength="100">
Faces Portlet中相应的控件则是:
<hx:fileupload styleClass="fileupload" id="fileupload1">
<hx:fileProp name="fileName" />
<hx:fileProp name="contentType" />
</hx:fileupload>
|
- 下拉选择框
下拉选择框允许你在一个有限的空间设置多种选项。
代码格式:
<select name="..." size="..." multiple>
<option value="..." selected>...</option>
...
</select>
|
样例7:
样例7代码:
<select name="mySel" size="1">
<option value="1" selected>yahoo.com</option>
<option value="2">google.com</option>
</select>
|
Faces Portlet中相应的控件则是:
<h:selectOneMenu styleClass="selectOneMenu" id="menu1">
<f:selectItem itemLabel="yahoo.com" itemValue="Yahoo.com" />
<f:selectItem itemLabel="google.com" itemValue="Google.com" />
</h:selectOneMenu>
|
- 列表框
样例8: 按Ctrl可以多选
样例8代码:
<select name="mySelt" size="3" multiple>
<option value="1" selected>yahoo.com</option>
<option value="2">google.com</option>
<option value="3">infoseek.com</option>
</select>
|
这里,Faces Portlet同样相应地将这个HTML标签扩展成为单选列表框和多选列表框两个控件:
单选列表框:
<h:selectOneListbox styleClass="selectOneListbox" id="listbox1">
<f:selectItem itemLabel="yahoo.com" itemValue="itemValue1" />
<f:selectItem itemLabel="google.com" itemValue="itemValue2" />
<f:selectItem itemLabel="infoseek.com" itemValue="itemValue3" />
</h:selectOneListbox>
|
多选列表框:
<h:selectManyListbox styleClass="selectManyListbox" id="listbox2"> <f:selectItem itemLabel="yahoo.com" itemValue="itemValue1" /> <f:selectItem itemLabel="google.com" itemValue="itemValue2" /> <f:selectItem itemLabel="infoseek.com" itemValue="itemValue3" /> </h:selectManyListbox>
表单按钮 表单按钮控制表单的动作。
可以看出来,一般标准HTML中的标签都可以在Faces Portlet中找到对应的控件,而且它们有了更加丰富的属性。
关心的问题 这里列出了表单应用中通常会碰到的一些问题,以及这些问题在Faces Portlet中的解决办法。
- 数据传输
在实际应用中,表单通常担负着数据采集的任务,因此页面之间传递数据就成了最基本的要求。 在Faces Portlet中,所有与页面相关的数据都集中在针对每个页面的Page Data中统一管理。最常用的主要是下面几类:
1. requestScope:这里你可以定义所有在request范围内传递的变量。
2. applicationScope:这里则可以定义所有在application范围内传递的变量。
3. requestParam:这里我们可以来定义所有在request范围内传递的控件参数。还有一类特殊的数据,我们可以在页面之间传递一个对象,即一个数据Bean的实例。
4. javaBean:我们需要先准备一个数据Bean,然后在需要的JSP页面中注册它,具体的过程后面的范例中会进一步讲述。实际开发中,我们推荐采用这种方式来传递数据。
对于每个这样的数据Bean,在 faces-config.xml中会有专门的定义:
<managed-bean>
<description>
UserInfo Data Bean</description>
<managed-bean-name>userInfo</managed-bean-name>
<managed-bean-class>pagecode.UserInfo</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
|
- 页面导航
Faces Portlet中的页面导航通常是通过对某个事件处理函数的返回值进行字符串匹配来实现页面的跳转的。WSAD提供了工具的支持,这在后面范例中会进一步讲到,配置好应用中的导航规则后, faces-config.xml中会有相应的描述:
<navigation-rule>
<from-view-id>/RegUser.jsp</from-view-id>
<navigation-case>
<from-action>#{pc_RegUser.doButton1Action}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/RegPreview.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{pc_RegUser.doButton1Action}</from-action>
<from-outcome>failure</from-outcome>
<to-view-id>/RegError.jsp</to-view-id>
</navigation-case>
</navigation-rule>
|
上面这段导航规则描述的是从RegUser.jsp这个页面开始跳转,如果doButton1Action这个事件处理函数返回success,则跳转倒RegPreview.jsp;如果返回failure,则跳转倒RegError.jsp。我们还可以在后面继续添加其它跳转的情形。
- 输入验证
Faces Portlet开发框架提供了验证器的机制,尽管它默认的验证器并不算强大,但是开发人员可以进一步开发属于自己的验证器。
如果我们的验证规则并不复杂,那么可以直接对输入控件进行一些简单设定即可。
下面是最常见的输入控件的例子,在JSP文件中
<h:inputText styleClass="inputText" id="text1" required="true">
<f:validateLength minimum="1" maximum="6">
</f:validateLength><hx:validateConstraint regex="AlphabetOnly" />
</h:inputText>
|
这个输入控件要求它的输入不能为空,长度界于1个字符到6个字符之间以及只接受字母输入等诸多限制。
- 事件处理
Faces Portlet开发框架提供了一个健壮的事件处理机制,它主要关注于两类事件:Action事件和ValueChange事件。
- Action事件:这类事件通常是由用户点击某个按钮或是超链接时触发。
- ValueChange事件:这类事件则通常是某个输入控件的值被创建或是通过验证后触发。
对于每个控件来说,在后台对应的Java类中会有一个相应的事件处理函数来负责实现复杂的业务逻辑。
比如在sample.jsp中有个id为button1的按钮,我们需要处理点击它所触发的事件。在后台对应的sample.java中则有函数doButton1Action来负责处理这个事件。
这种事件处理机制和传统的basic portlet中通过actionPerformed函数集中管理事件处理,对各个事件的处理函数进行分派的情形相比较,Faces Portlet中的控制器相对分散,也更易于将来的维护。
范例 我们选取了一个典型的表单应用――注册用户。通常每个动态Web应用都会包含注册用户这个模块,这里用户需要填写一些个人信息诸如用户名,密码,确认密码,邮件地址等。对于各种不同的信息,需要有相应的验证规则,当输入通过了所有的验证之后,会跳转到另外一个预览页面,详细地列举出之前所填的个人信息;提交表单,得到提交结果。
这当中涉及到这样一些设计要素:选取合适的用户UI控件,设计数据Bean以传递数据,设置合适的验证规则,设置页面的跳转,以及处理必要的控件事件。
创建项目 新建一个Portlet Project,这里的名称是FormApp。(如图1)
图1
记得选取portlet的类型是Faces portlet。(如图2)
图2
然后,根据我们这个范例的需要,在Web Content目录下添加几个Faces JSP File,选择模型时请选择Portlet。这里增加了这样几个页面:(如图3)
- RegUser.jsp: 用户在这里输入相关的个人信息,完成输入验证。
- RegPreview.jsp: 列出所有的输入信息。
- RegResult.jsp: 显示注册提交结果。
图3
提交页面 RegUser.jsp 所见即所得,从右面的控件面板上选择你所需要的控件拖放至JSP页面,这里我们只是先加了一行标题:Register New User:
接下来,准备页面之间需要传递的数据。由于我们这里需要传递的字段比较多,如果都分别设置成requestScope中的变量比较繁琐,这里我们将这些字段组织成数据Bean。
先在项目的Java Resources的包中新建一个Java Class,就叫UserInfo吧。(如图4)
图4
这是一个典型的数据Bean,定义了各种各样的字段,然后添加了它们的Get/Set方法,有WSAD的帮助,这一切都非常简单。
下面列出了这个类的代码片断,你可以在 附件1中找到它完整的代码。
package pagecode;
public class UserInfo {
public String pid = null;
public String password = null;
public String confirmpwd = null;
public String name = null;
public String gender = null;
public String birthday = null;
public String country = null;
public String phoneno = null;
public String email = null;
public UserInfo() {
this.pid = "G000000";
this.password = "";
this.confirmpwd = "";
this.name = "XYZ";
this.gender = "Male";
this.birthday = "2004-01-01";
this.country = "China Shanghai";
this.phoneno = "86-21-63262288";
this.email = "XYZ@cn.ibm.com";
}
public String getName() {
return name;
}
public void setName(String string) {
name = string;
}
|
完成了数据Bean的代码之后,在这个JSP页面对应的Page Data框中单击右键,选择JavaBean,现在我们要把刚才编写好的类导入页面。(如图5)
图5
由于是第一次导入,需要选择 增加新的JavaBean,在类中选择刚才编写的Java类:pagecode.UserInfo,同时标明它是能够被 重用的。在它的使用范围中选择request,这个选项对服务器资源的消耗是最少的,当然数据可共享的范围也只限于request范围。(如图6)
图6
如果点击Initialize Properties这个按钮进去,我们还可以为这个数据Bean设置一些初始值。
如果这一切都完成了,点击Finish,你会发现Page Data框中会出现这个数据Bean中所有字段的列表。(如图7)
图7
这时,需要为各个字段准备输入控件了,当然我们可以手工的添加这些控件,然后设置控件和每个字段的绑定关系,但是WSAD为我们提供了自动生成控件的工具。
在Page Data中选中userInfo,单击右键,选择Insert New Controls for "userInfo"。(如图8)
图8
这里我们可以来配置哪些字段需要有相应的控件显示出来,针对每个字段选取控件的类型以及控件的相对位置等等。(如图9)
图9
注意:这里WSAD工具的支持有不足的地方,所支持的控件的种类比较少,如果不能满足需要的话,只能创建完成后在JSP页面里手工的修改控件标签了,这里我把涉及输入密码的两个控件都修改成inputSecret类型了。
完成这一切,单击Finish,下面就是创建好的注册页面外观。(如图10)
图10
接下来,还有两个事情,为控件设置验证规则和为按钮添加相应的事件处理代码。
Faces Portlet为输入控件提供了最常用的验证规则,如果不能满足您的要求,可以在客户端添加Java Script验证函数或是在服务器段的事件处理代码中实现复杂的验证逻辑。(如图11)
图11
最后,为这个表单的按钮添加事件处理代码。(如图12)
图12
这里给出了一个简单的事件处理函数,它判断密码和确认密码两个文本输入框的用户输入是否一致。
事件处理函数:
public String doButton1Action() {
// Type Java code to handle command event here
// Note, this code must return an object of type String (or null)
HtmlInputSecret src1 = this.getSecret1();
HtmlInputSecret src2 = this.getSecret2();
if(null != src1 && null != src2)
{
if(src1.getValue().equals(src2.getValue()))
{
System.out.println("success\n");
return "success";
}else
{
System.out.println("failure\n");
return "failure";
}
}else
{
System.out.println("src1 or src2 is null\n");
return "failure";
}
}
|
好,这样我们完成了最重要的注册页面。
预览页面 RegPreview.jsp 将RegPreview.jsp在编辑模式中打开,按照上个页面类似的过程,在Page Data中添加一个Java Bean,这次我们选用已经注册过的userInfo。(如图13)
图13
然后记得在选项框中选择Display fields (Read only),调整相应的控件顺序,单击Finish。
下面就是这个页面的外观。(如图14)
图14
然后,再在这个portlet的初始页面FormAppView.jsp以及RegResult.jsp里面添加一些简单的文字信息即可。
页面准备好后,我们需要来完成页面间的跳转。
编辑RegUser.jsp中按钮的属性,选择Navigation页,添加一个新的导航规则(如图15),进行相应的设置,这同时会在faces-config.xml中增加相应的导航规则。
图15
其它页面添加相应的跳转,或是通过表单按钮,或是直接采用 超链接控件来完成跳转。
最后,在Portal测试环境中运行这个portlet:
相应的两个页面如下:(如图16,图17)
图16
图17
小结:抛开华丽的美工设计和后台的业务逻辑,动态Web应用中一个最基本的功能就是收集用户输入,验证输入,传递数据。表单能够帮助你完成这一切,而在Faces Portlet中,你更是只需要拖放一些控件,设置它们的属性,添加很简单的一点代码就能够完成这一切。
|