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

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

圖二:Struts處理流程圖
從這兩張圖看,JPF對于Struts的改進非常有限,只是增加了一些Filter,實現了不能直接訪問JSP文件的功能,但這些只是表面現象,JPF最大的亮點應該是圖一中紅色標識的部分—JPF文件,頁面流中的配置工作都在JPF中完成,因此我們不再需要單獨的配置文件:
1. 使用JPF中的Java批注實現如下配置功能
A) JSP文件和Action之間的映射
B) JSP頁面之間數據傳遞的定義
2. FormBean不再需要配置,通過JPF文件中方法的參數類型直接判斷
2 使用頁面流框架開發Web應用
作者將用一個例子來演示如何使用頁面流來開發Web應用,這個例子非常簡單,就是一個通常的用戶注冊頁面,用戶需要提供三個字段:用戶名、密碼和常用E_Mail,服務器端獲取用戶輸入的內容,并且用另一個JSP頁面顯示出來,演示的內容將涉及頁面流中關鍵的幾個部分:
1. 國際化
2. 界面開發
3. 頁面導航
4. 用戶輸入的處理
5. 數據在頁面間的傳遞
作者的例子將從Beehive提供的例子netui-blank應用開始,Web容器采用Tomcat,操作系統采用Windows2000。
本文中作者默認你的netui-blank應用已經在Tomcat上配置完成上下文路徑是pageflow,并且能夠正確運行。如果你的pageflow應用還沒有能夠運行起來,請參考作者的另一篇文章《Beehive入門》。
2.1 國際化
和大多數的MVC框架一樣,頁面流中也使用資源文件的形式來解決應用的國際化顯示。頁面流中實現資源國際化的步驟如下:
1. 準備資源文件
在%tomcat_home%webappspageflowWEB-INFsrcglobal目錄下建立資源文件resource_cn.properties,文件的內容如下:
label=你好!歡迎您了解頁面流!
2. 將資源文件轉化為unicode碼
打開一個Dos窗口,進入%tomcat_home%webappspageflowWEB-INFsrcglobal目錄下,執行命令:
native2ascii –encoding gb2312 resoure_cn.properties resource.properties
命令執行完后將在global目錄下生成一個名為resource.properties的文件,文件內的中文都已經變成了unicode表示,上面的那個文件轉化后內容應該如下所示:
label=4f60\u597dFf016b228fce60a84e8689e3987597626d41Ff01
3. 在JSP文件中使用標簽訪問資源
現在我們需要修改JSP,以便在JSP中引用創建的國際化內容,這個步驟比較簡單,主要兩個步驟,這里以pageflow應用中的index.jsp為例來演示這個過程:
A) 增加對資源的綁定
在index.jsp文件的頭部增加這么一句:
<netui-data:declareBundle bundlePath="global.resource" name="ui"/>
其中的buildlePath屬性表示了資源文件在classpath中的全路徑,name屬性制定頁面中訪問時的標識。
[注] 很容易的我們應該知道,在頁面流中,一個JSP文件,可以綁定到多個資源文件上。
B) 顯示資源內容
JSP文件中用這樣的聲明表示在當前位置顯示資源內容,其中的ui就是步驟A)中聲明的name屬性對應的字符串,label表示顯示該資源文件中label關鍵字對應的資源。
我們修改index.jsp,將源代碼變成如下內容:
<%@ 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. 重新編譯應用
重新編譯的步驟請參考《Beehive入門》中的內容,主要是將資源文件拷貝到WEB-INF ass下對應的目錄下。
5. 測試一下
現在你啟動Tomcat,訪問http://localhost:8080/pageflow/,瀏覽器中出現的界面應該出現中文。
2.2 界面開發
頁面流中提供了一組以<netui:xxx>命名的標簽庫來實現界面上的可視化控件,在這里例子中需要兩個JSP頁面,一個JSP頁面用于接受用戶輸入,一個JSP頁面顯示用戶的輸入信息。
我們首先建立輸入文件,在pageflow應用的根目錄下創建接受用戶輸入的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屬性的內容必須是JPF中的某一個方法的名字,這里的register方法的詳細內容請參考2.5用戶輸入處理中的相關內容–〉
<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等標簽來完成html內容的顯示,每個標簽的命名基本和html中的標簽的名字對應,應該比較好理解,更多的標簽和詳細的標簽用法作者將在后續的文章中專門講解。
- netui標簽的dataSource="actionForm.name"表示這個標簽和傳輸form的哪個字段相對應。
- 這個JSP文件中引用了比較多的文字資源,如何準備這些國際化資源,請大家參考
2.1國際化中的步驟來完成。
另一個顯示用戶輸入信息的頁面命名為regiester.jsp,文件內容暫時輸入如下內容:
<%@ 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 準備FormBean
要獲取用戶輸入,需要一個能夠和用戶輸入一致的FormBean,作者的FormBean命名為UserForm,文件的內容如下:
package org.vivianj.samples.jpf.form;
//UserForm必須實現java.io.Serializable接口,否則編譯的時候會出錯
public class UserForm implements java.io.Serializable
{
//用戶輸入三個字段,FormBean提供三個屬性和他們一一對應
//并且分別提供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 頁面導航
現在我們開始準備開始要訪問2.2中創建的那個JSP文件,我們希望在index.jsp中有個鏈接指向這個文件,通過單擊該鏈接訪問這個JSP文件,下面是詳細的步驟:
1. 在JPF文件中增加Action指向改JSP文件
因為頁面流框架中不能直接訪問JSP文件,所以必須將JSP文件映射為Action。
修改Controller.jpf,增加Action指向改JSP文件,下面是Controller.jpf修改后的部分代碼,用斜/粗體表示標識的代碼是需要增加的代碼:
.Controller(
simpleActions={
.SimpleAction(name="reg", path="input.jsp")
}
)
public class Controller
extends PageFlowController
2. 修改index.jsp
在index.jsp中增加一個鏈接,用標簽來表示的鏈接如下:
<netui:anchor action="reg.do">用戶注冊</netui:anchor>
[注] action的屬性reg.do中reg對應Controller.jpf中simpleActions的name屬性,而.do是必須的后綴。
2.5 用戶輸入處理
在2.2界面開發中,我們定義表單的action是register,在頁面流中,這個register應該是JPF的一個方法名,所以如果需要處理用戶輸入,我們還需要在JPF文件中增加一個register方法,修改后的Controller.jpf文件的部分代碼,用斜/粗體表示標識的代碼是需要增加的代碼:
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對象中保存了用戶輸入的信息
//用戶輸入處理完成后導航到注冊信息顯示頁面
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)
{
}
}
現在重新編譯整個Web應用,重新發布到Tomcat服務器上,你應該可以完成如下流程:
1、 進入導航頁,上面有一個鏈接指向用戶信息輸入界面
2、 在用戶信息輸入界面輸入信息,提交信息
3、 服務器上應該打印你輸入的name字段的內容,瀏覽器顯示“用戶信息輸入成功!”字樣。
2.6 數據在頁面之間的傳遞
按照我們例子的要求,用戶輸入的信息應該在瀏覽器中輸出來,所以需要數據在頁面之間傳遞,這部分工作在頁面流中實現比上面的功能稍微復雜一點,下面將詳細的演示這個過程。
緊接著上面的例子,用戶的信息如果需要在regiester.jsp上顯示出來,需要修改Controller.jpf和register.jsp。
A) 修改Controller.jpf,確定被傳遞的數據的類型、標識
Controller.jpf經過修改后內容如下,其中的斜/粗線部分是增加的內容:
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批注
//說明該方法執行完跳轉到下一個頁面時會有共享信息傳遞
//name=”user”規定頁面之間傳遞的對象名為”user”
//type=xxx.class規定了傳遞對象的內容
.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");
//給跳轉增加傳遞對象 //對象名稱和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文件,顯示傳遞過來的數據
修改后的regiester.jsp文件如下,其中斜/粗體的內容是新增加的內容:
<%@ 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標簽將頁面的JavaBean綁定到傳遞過來到的對象
//name屬性和Controller.jpf文件中規定的傳遞對象的名字保持一致
//type屬性和Controller.jpf文件中規定的傳遞對象類型保持一致
<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>
頁面流中用的形式可以獲取頁面之間跳轉數據的屬性,其中的user對應netui-data標簽的name屬性,name是被訪問對象的屬性。
現在你重新編譯、發布該Web應用,重新啟動Tomcat后,在用戶信息輸入界面輸入信息、提交給服務器后,瀏覽器應該顯示你所輸入的信息,類似這樣的情況:
3 總結
通過一個用戶信息輸入、回顯的例子,詳細地演示了Web開發應用中最常見的幾個動作:國際化的處理、界面開發、頁面導航、用戶輸入處理、數據在頁面間傳遞。
縱觀整個演示流程,應該說使用頁面流是非常簡單的,通常我們只需要做一些聲明性的工作,整個過程中只有FormBean的準備部分和JPF文件中用戶輸入處理要求對Java非常熟悉。

作者簡介:
姓名:肖菁
E_mail:guilaida.com
軟件工程師,buildfiledesign項目設計師(buildfiledesign.sourceforge.net),Vivianj技術交流站站長(guilaida.go.nease.net),致力于研究J2EE編程技術、Web Service技術以及他們在 WebSphere、WebLogic、 Apache平臺上的實現。