http://dev2dev.bea.com.cn/techdoc/wlworkshop/2005041803.html 頁(yè)面流是Java Page Flow的中文表示,作者在本文中簡(jiǎn)單分析了頁(yè)面流框架的運(yùn)行機(jī)制,還通過具體的例子簡(jiǎn)單的演示了頁(yè)面流框架下如何應(yīng)用標(biāo)簽開發(fā)用戶界面、實(shí)現(xiàn)頁(yè)面導(dǎo)航、處理表單提交等基本功能。
關(guān)鍵詞: 頁(yè)面流 標(biāo)簽 頁(yè)面導(dǎo)航 表單處理
1 頁(yè)面流的運(yùn)行機(jī)制
1.1 頁(yè)面流組成
頁(yè)面流是一個(gè)MVC框架,一個(gè)Web應(yīng)用中可以有多個(gè)頁(yè)面流,一個(gè)頁(yè)面流由一個(gè)java文件(文件后綴名為.jpf,后面的文章中將用”JPF文件”特指這個(gè)文件)和一組JSP文件組成:
1. JSP文件負(fù)責(zé)生成用戶瀏覽的界面(UI)
JSP文件使用頁(yè)面流框架提供的標(biāo)簽庫(kù)完成內(nèi)容顯示和jpf文件中的對(duì)象之間的調(diào)用,用戶輸入表單處理與JPF文件中的方法之間的關(guān)聯(lián)也通過標(biāo)簽庫(kù)來實(shí)現(xiàn)。
2. JPF文件負(fù)責(zé)用戶訪問的流程控制和頁(yè)面信息傳遞,主要包括:
a) 獲取用戶輸入,調(diào)用商業(yè)流程處理用戶輸入
b) 訪問企業(yè)資源
c) 在頁(yè)面間保持狀態(tài)
d) 控制頁(yè)面顯示的次序
頁(yè)面流框架下,不允許用戶直接訪問Web應(yīng)用中的JSP頁(yè)面,而且用戶訪問的流程控制都在一個(gè)Java文件里面實(shí)現(xiàn),所以可以輕松的實(shí)現(xiàn)一些通常Web開發(fā)中難于處理的需求,比如:在各頁(yè)面之間保持一些復(fù)雜類型的狀態(tài)信息,實(shí)行一組JSP文件的統(tǒng)一授權(quán)訪問等。
[注] 頁(yè)面流中的jpf文件和JSP文件必須在同一個(gè)目錄下。
1.2 頁(yè)面流運(yùn)行機(jī)制
下面這個(gè)圖說明了頁(yè)面流的整個(gè)處理流程:

圖一:頁(yè)面流處理流程圖
我們可以看一看struts的處理流程圖:

圖二:Struts處理流程圖
從這兩張圖看,JPF對(duì)于Struts的改進(jìn)非常有限,只是增加了一些Filter,實(shí)現(xiàn)了不能直接訪問JSP文件的功能,但這些只是表面現(xiàn)象,JPF最大的亮點(diǎn)應(yīng)該是圖一中紅色標(biāo)識(shí)的部分—JPF文件,頁(yè)面流中的配置工作都在JPF中完成,因此我們不再需要單獨(dú)的配置文件:
1. 使用JPF中的Java批注實(shí)現(xiàn)如下配置功能
A) JSP文件和Action之間的映射
B) JSP頁(yè)面之間數(shù)據(jù)傳遞的定義
2. FormBean不再需要配置,通過JPF文件中方法的參數(shù)類型直接判斷
2 使用頁(yè)面流框架開發(fā)Web應(yīng)用
作者將用一個(gè)例子來演示如何使用頁(yè)面流來開發(fā)Web應(yīng)用,這個(gè)例子非常簡(jiǎn)單,就是一個(gè)通常的用戶注冊(cè)頁(yè)面,用戶需要提供三個(gè)字段:用戶名、密碼和常用E_Mail,服務(wù)器端獲取用戶輸入的內(nèi)容,并且用另一個(gè)JSP頁(yè)面顯示出來,演示的內(nèi)容將涉及頁(yè)面流中關(guān)鍵的幾個(gè)部分:
1. 國(guó)際化
2. 界面開發(fā)
3. 頁(yè)面導(dǎo)航
4. 用戶輸入的處理
5. 數(shù)據(jù)在頁(yè)面間的傳遞
作者的例子將從Beehive提供的例子netui-blank應(yīng)用開始,Web容器采用Tomcat,操作系統(tǒng)采用Windows2000。
本文中作者默認(rèn)你的netui-blank應(yīng)用已經(jīng)在Tomcat上配置完成上下文路徑是pageflow,并且能夠正確運(yùn)行。如果你的pageflow應(yīng)用還沒有能夠運(yùn)行起來,請(qǐng)參考作者的另一篇文章《Beehive入門》。
2.1 國(guó)際化
和大多數(shù)的MVC框架一樣,頁(yè)面流中也使用資源文件的形式來解決應(yīng)用的國(guó)際化顯示。頁(yè)面流中實(shí)現(xiàn)資源國(guó)際化的步驟如下:
1. 準(zhǔn)備資源文件
在%tomcat_home%webappspageflowWEB-INFsrcglobal目錄下建立資源文件resource_cn.properties,文件的內(nèi)容如下:
label=你好!歡迎您了解頁(yè)面流!
2. 將資源文件轉(zhuǎn)化為unicode碼
打開一個(gè)Dos窗口,進(jìn)入%tomcat_home%webappspageflowWEB-INFsrcglobal目錄下,執(zhí)行命令:
native2ascii –encoding gb2312 resoure_cn.properties resource.properties
命令執(zhí)行完后將在global目錄下生成一個(gè)名為resource.properties的文件,文件內(nèi)的中文都已經(jīng)變成了unicode表示,上面的那個(gè)文件轉(zhuǎn)化后內(nèi)容應(yīng)該如下所示:
label=4f60\u597dFf016b228fce60a84e8689e3987597626d41Ff01
3. 在JSP文件中使用標(biāo)簽訪問資源
現(xiàn)在我們需要修改JSP,以便在JSP中引用創(chuàng)建的國(guó)際化內(nèi)容,這個(gè)步驟比較簡(jiǎn)單,主要兩個(gè)步驟,這里以pageflow應(yīng)用中的index.jsp為例來演示這個(gè)過程:
A) 增加對(duì)資源的綁定
在index.jsp文件的頭部增加這么一句:
<netui-data:declareBundle bundlePath="global.resource" name="ui"/>
其中的buildlePath屬性表示了資源文件在classpath中的全路徑,name屬性制定頁(yè)面中訪問時(shí)的標(biāo)識(shí)。
[注] 很容易的我們應(yīng)該知道,在頁(yè)面流中,一個(gè)JSP文件,可以綁定到多個(gè)資源文件上。
B) 顯示資源內(nèi)容
JSP文件中用這樣的聲明表示在當(dāng)前位置顯示資源內(nèi)容,其中的ui就是步驟A)中聲明的name屬性對(duì)應(yīng)的字符串,label表示顯示該資源文件中l(wèi)abel關(guān)鍵字對(duì)應(yīng)的資源。
我們修改index.jsp,將源代碼變成如下內(nèi)容:
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="http://beehive.apache.org/netui/tags-databinding-1.0" prefix="netui-data"%>
<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%>
<%@ taglib uri="http://beehive.apache.org/netui/tags-template-1.0" prefix="netui-template"%>
<netui-data:declareBundle bundlePath="global.resource" name="ui"/>
<netui:html>
<head>
<title></title>
<netui:base/>
</head>
<netui:body>
<p>
</p>
</netui:body>
</netui:html>
4. 重新編譯應(yīng)用
重新編譯的步驟請(qǐng)參考《Beehive入門》中的內(nèi)容,主要是將資源文件拷貝到WEB-INF ass下對(duì)應(yīng)的目錄下。
5. 測(cè)試一下
現(xiàn)在你啟動(dòng)Tomcat,訪問http://localhost:8080/pageflow/,瀏覽器中出現(xiàn)的界面應(yīng)該出現(xiàn)中文。
2.2 界面開發(fā)
頁(yè)面流中提供了一組以<netui:xxx>命名的標(biāo)簽庫(kù)來實(shí)現(xiàn)界面上的可視化控件,在這里例子中需要兩個(gè)JSP頁(yè)面,一個(gè)JSP頁(yè)面用于接受用戶輸入,一個(gè)JSP頁(yè)面顯示用戶的輸入信息。
我們首先建立輸入文件,在pageflow應(yīng)用的根目錄下創(chuàng)建接受用戶輸入的JSP文件—input.jsp,該文件源代碼如下:
<%@ page language="java" contentType="text/html;charset=gb2312"%>
<%@ taglib uri="http://beehive.apache.org/netui/tags-databinding-1.0" prefix="netui-data"%>
<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%>
<%@ taglib uri="http://beehive.apache.org/netui/tags-template-1.0" prefix="netui-template"%>
<netui-data:declareBundle bundlePath="global.resource" name="ui"/>
<netui:html>
<head>
<title></title>
<netui:base/>
</head>
<netui:body>
<center> <br/>
<!—form的action屬性的內(nèi)容必須是JPF中的某一個(gè)方法的名字,這里的register方法的詳細(xì)內(nèi)容請(qǐng)參考2.5用戶輸入處理中的相關(guān)內(nèi)容–〉
<netui:form action="register">
:<netui:textBox dataSource="actionForm.name"/><br/>
:<netui:textBox password="true" dataSource="actionForm.password"/><br/>
E_mail:<netui:textBox dataSource="actionForm.email"/><br/>
<netui:button type="submit"></netui:button>
</netui:form>
</center>
</netui:body>
</netui:html>
- JSP文件中使用了netui:html、netui:body、netui:form、netui:textbox、netui:button等標(biāo)簽來完成html內(nèi)容的顯示,每個(gè)標(biāo)簽的命名基本和html中的標(biāo)簽的名字對(duì)應(yīng),應(yīng)該比較好理解,更多的標(biāo)簽和詳細(xì)的標(biāo)簽用法作者將在后續(xù)的文章中專門講解。
- netui標(biāo)簽的dataSource="actionForm.name"表示這個(gè)標(biāo)簽和傳輸form的哪個(gè)字段相對(duì)應(yīng)。
- 這個(gè)JSP文件中引用了比較多的文字資源,如何準(zhǔn)備這些國(guó)際化資源,請(qǐng)大家參考
2.1國(guó)際化中的步驟來完成。
另一個(gè)顯示用戶輸入信息的頁(yè)面命名為regiester.jsp,文件內(nèi)容暫時(shí)輸入如下內(nèi)容:
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="http://beehive.apache.org/netui/tags-databinding-1.0" prefix="netui-data"%>
<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%>
<%@ taglib uri="http://beehive.apache.org/netui/tags-template-1.0" prefix="netui-template"%>
<netui:html>
<head>
<title>用戶輸入</title>
<netui:base/>
</head>
<netui:body>
<p>
用戶信息輸入成功!
</p>
</netui:body>
</netui:html>
2.3 準(zhǔn)備FormBean
要獲取用戶輸入,需要一個(gè)能夠和用戶輸入一致的FormBean,作者的FormBean命名為UserForm,文件的內(nèi)容如下:
package org.vivianj.samples.jpf.form;
//UserForm必須實(shí)現(xiàn)java.io.Serializable接口,否則編譯的時(shí)候會(huì)出錯(cuò)
public class UserForm implements java.io.Serializable
{
//用戶輸入三個(gè)字段,F(xiàn)ormBean提供三個(gè)屬性和他們一一對(duì)應(yīng)
//并且分別提供getter,setter方法
private String name;
private String password;
private String email;
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return this.name;
}
public void setPassword(String pwd)
{
this.password = pwd;
}
public String getPassword()
{
return this.password;
}
public void setEmail(String mail)
{
this.email = mail;
}
public String getEmail()
{
return this.email;
}
}
2.4 頁(yè)面導(dǎo)航
現(xiàn)在我們開始準(zhǔn)備開始要訪問2.2中創(chuàng)建的那個(gè)JSP文件,我們希望在index.jsp中有個(gè)鏈接指向這個(gè)文件,通過單擊該鏈接訪問這個(gè)JSP文件,下面是詳細(xì)的步驟:
1. 在JPF文件中增加Action指向改JSP文件
因?yàn)轫?yè)面流框架中不能直接訪問JSP文件,所以必須將JSP文件映射為Action。
修改Controller.jpf,增加Action指向改JSP文件,下面是Controller.jpf修改后的部分代碼,用斜/粗體表示標(biāo)識(shí)的代碼是需要增加的代碼:
.Controller(
simpleActions={
.SimpleAction(name="reg", path="input.jsp")
}
)
public class Controller
extends PageFlowController
2. 修改index.jsp
在index.jsp中增加一個(gè)鏈接,用標(biāo)簽來表示的鏈接如下:
<netui:anchor action="reg.do">用戶注冊(cè)</netui:anchor>
[注] action的屬性reg.do中reg對(duì)應(yīng)Controller.jpf中simpleActions的name屬性,而.do是必須的后綴。
2.5 用戶輸入處理
在2.2界面開發(fā)中,我們定義表單的action是register,在頁(yè)面流中,這個(gè)register應(yīng)該是JPF的一個(gè)方法名,所以如果需要處理用戶輸入,我們還需要在JPF文件中增加一個(gè)register方法,修改后的Controller.jpf文件的部分代碼,用斜/粗體表示標(biāo)識(shí)的代碼是需要增加的代碼:
import javax.servlet.http.HttpSession;
import org.apache.beehive.netui.pageflow.Forward;
import org.apache.beehive.netui.pageflow.PageFlowController;
import org.apache.beehive.netui.pageflow.annotations.Jpf;
//引入formbean類
import org.vivianj.samples.jpf.form.UserForm;
.Controller(
simpleActions={
.SimpleAction(name="reg", path="input.jsp")
} )
public class Controller
extends PageFlowController {
public User user = new User();
.Action(
forwards={
.Forward(name="success", path="index.jsp")
}
)
protected Forward begin()
{
return new Forward("success");
}
.Action(
forwards={
.Forward(name="register", path="register.jsp")
}
)
//register方法處理用戶輸入
//UserForm對(duì)象中保存了用戶輸入的信息
//用戶輸入處理完成后導(dǎo)航到注冊(cè)信息顯示頁(yè)面
protected Forward register(UserForm form)
{
System.out.println("form.getName()=" + form.getName());
Forward forward = new Forward("register");
forward.addActionOutput("user", user);
return forward;
}
/**
* Callback that is invoked when this controller instance is created.
*/
protected void onCreate()
{
}
/**
* Callback that is invoked when this controller instance is destroyed.
*/
protected void onDestroy(HttpSession session)
{
}
}
現(xiàn)在重新編譯整個(gè)Web應(yīng)用,重新發(fā)布到Tomcat服務(wù)器上,你應(yīng)該可以完成如下流程:
1、 進(jìn)入導(dǎo)航頁(yè),上面有一個(gè)鏈接指向用戶信息輸入界面
2、 在用戶信息輸入界面輸入信息,提交信息
3、 服務(wù)器上應(yīng)該打印你輸入的name字段的內(nèi)容,瀏覽器顯示“用戶信息輸入成功!”字樣。
2.6 數(shù)據(jù)在頁(yè)面之間的傳遞
按照我們例子的要求,用戶輸入的信息應(yīng)該在瀏覽器中輸出來,所以需要數(shù)據(jù)在頁(yè)面之間傳遞,這部分工作在頁(yè)面流中實(shí)現(xiàn)比上面的功能稍微復(fù)雜一點(diǎn),下面將詳細(xì)的演示這個(gè)過程。
緊接著上面的例子,用戶的信息如果需要在regiester.jsp上顯示出來,需要修改Controller.jpf和register.jsp。
A) 修改Controller.jpf,確定被傳遞的數(shù)據(jù)的類型、標(biāo)識(shí)
Controller.jpf經(jīng)過修改后內(nèi)容如下,其中的斜/粗線部分是增加的內(nèi)容:
import javax.servlet.http.HttpSession;
import org.apache.beehive.netui.pageflow.Forward;
import org.apache.beehive.netui.pageflow.PageFlowController;
import org.apache.beehive.netui.pageflow.annotations.Jpf;
import org.vivianj.samples.jpf.form.UserForm;
.Controller(
simpleActions={
.SimpleAction(name="reg", path="input.jsp")
}
)
public class Controller
extends PageFlowController
{
public User user = new User();
.Action(
forwards={
.Forward(name="success", path="index.jsp")
}
)
protected Forward begin()
{
return new Forward("success");
}
//修改Action的注釋,增加actionOutputs批注
//說明該方法執(zhí)行完跳轉(zhuǎn)到下一個(gè)頁(yè)面時(shí)會(huì)有共享信息傳遞
//name=”user”規(guī)定頁(yè)面之間傳遞的對(duì)象名為”user”
//type=xxx.class規(guī)定了傳遞對(duì)象的內(nèi)容
.Action(
forwards={
.Forward(name="register", path="register.jsp",
actionOutputs = {
.ActionOutput(name = "user",
type = org.vivianj.samples.jpf.form.User.class,
required = true)
})
}
)
protected Forward register(UserForm form)
{
Forward forward = new Forward("register");
//給跳轉(zhuǎn)增加傳遞對(duì)象 //對(duì)象名稱和actionOutputs批注中的name屬性保持一致
forward.addActionOutput("user", form);
return forward;
}
/**
* Callback that is invoked when this controller instance is created.
*/
protected void onCreate()
{
}
/**
* Callback that is invoked when this controller instance is destroyed.
*/
protected void onDestroy(HttpSession session)
{
}
B) 修改regiester.jsp文件,顯示傳遞過來的數(shù)據(jù)
修改后的regiester.jsp文件如下,其中斜/粗體的內(nèi)容是新增加的內(nèi)容:
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="http://beehive.apache.org/netui/tags-databinding-1.0" prefix="netui-data"%>
<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%>
<%@ taglib uri="http://beehive.apache.org/netui/tags-template-1.0" prefix="netui-template"%>
//用頁(yè)面流的netui-data標(biāo)簽將頁(yè)面的JavaBean綁定到傳遞過來到的對(duì)象
//name屬性和Controller.jpf文件中規(guī)定的傳遞對(duì)象的名字保持一致
//type屬性和Controller.jpf文件中規(guī)定的傳遞對(duì)象類型保持一致
<netui-data:declarePageInput name="user" type="org.vivianj.samples.jpf.form.User"/>
<netui-data:declareBundle bundlePath="global.resource" name="ui"/>
<netui:html>
<head>
<title></title>
<netui:base/>
</head>
<netui:body>
<center> <br/><br/><br/>
<br/>
<br/>
email<br/>
</center>
</netui:body>
</netui:html>
頁(yè)面流中用的形式可以獲取頁(yè)面之間跳轉(zhuǎn)數(shù)據(jù)的屬性,其中的user對(duì)應(yīng)netui-data標(biāo)簽的name屬性,name是被訪問對(duì)象的屬性。
現(xiàn)在你重新編譯、發(fā)布該Web應(yīng)用,重新啟動(dòng)Tomcat后,在用戶信息輸入界面輸入信息、提交給服務(wù)器后,瀏覽器應(yīng)該顯示你所輸入的信息,類似這樣的情況:
3 總結(jié)
通過一個(gè)用戶信息輸入、回顯的例子,詳細(xì)地演示了Web開發(fā)應(yīng)用中最常見的幾個(gè)動(dòng)作:國(guó)際化的處理、界面開發(fā)、頁(yè)面導(dǎo)航、用戶輸入處理、數(shù)據(jù)在頁(yè)面間傳遞。
縱觀整個(gè)演示流程,應(yīng)該說使用頁(yè)面流是非常簡(jiǎn)單的,通常我們只需要做一些聲明性的工作,整個(gè)過程中只有FormBean的準(zhǔn)備部分和JPF文件中用戶輸入處理要求對(duì)Java非常熟悉。

作者簡(jiǎn)介:
姓名:肖菁
E_mail:guilaida.com
軟件工程師,buildfiledesign項(xiàng)目設(shè)計(jì)師(buildfiledesign.sourceforge.net),Vivianj技術(shù)交流站站長(zhǎng)(guilaida.go.nease.net),致力于研究J2EE編程技術(shù)、Web Service技術(shù)以及他們?cè)?WebSphere、WebLogic、 Apache平臺(tái)上的實(shí)現(xiàn)。