Spring Web Flows
實(shí)踐指南
原文:Spring Web Flows - A Practical Guide
Author: Erwin Vervaet (Mail To)
translator: Dorian Shi (Mail To)
這篇文章介紹了 Spring Web Flows。用實(shí)例來(lái)說(shuō)明基于 Web Flow 的原理。文章也提供了一個(gè)使用 Web Flow 和 Spring 框架來(lái)構(gòu)建 Web 應(yīng)用的實(shí)踐指南.
假定讀者已經(jīng)了解一些 J2EE Web 應(yīng)用、XML、Spirng 框架,當(dāng)然還有 Spring 的 Web MVC 框架。你可以查看資源來(lái)了解這些信息。
介 紹
在一個(gè) Web 應(yīng)用程序中傳統(tǒng)的定義一個(gè)頁(yè)面流程是一個(gè)一點(diǎn)也不直觀的過(guò)程。像 Struts 和 Spring 這樣的框架促使你把頁(yè)面流程放進(jìn)單獨(dú)的控制器和視圖中。舉個(gè)例子:Struts 會(huì)把請(qǐng)求映射到一個(gè) Action。這個(gè) Action 會(huì)選擇一個(gè)視圖并轉(zhuǎn)發(fā)到這個(gè)視圖。雖然這是一個(gè)簡(jiǎn)單并且實(shí)用的方法,但它有一個(gè)主要的缺點(diǎn):到 Action 的定義文件 struts-config.xml 中看看,Web 應(yīng)用程序的所有頁(yè)面流程一點(diǎn)也不清晰。因?yàn)?Action 不能簡(jiǎn)單的被重用,靈活性同樣也會(huì)遭到損害。
Spring Web MVC 框架提供了一個(gè)細(xì)微的高級(jí)功能:表單控制器執(zhí)行一個(gè)預(yù)先定義好的工作流。有兩種控制器提供了這一特性:SimpleFormController 和 AbstractWizardFormController。然而,這些仍舊是一種一般化的硬編碼的工作流概念。
到這里就要引入 Spring 的 Web Flow 了。它允許你用清晰簡(jiǎn)單的方式展現(xiàn) Web 應(yīng)用的頁(yè)面流程。就像我們要看到的一樣,他有許多有點(diǎn):
- 一個(gè) Web 應(yīng)用的頁(yè)面流程通過(guò) Web Flow 定義文件(一個(gè) XML 文件)清楚的展現(xiàn)出來(lái)。
- Web Flow 可以被設(shè)計(jì)成自包含的(slef contained)。這意味著允許你在很多情形中把你應(yīng)用程序的一部分看成一個(gè)組件并且使之重用。
- Web Flow 可以在一個(gè) Web 應(yīng)用中總是使用一樣的手法來(lái)定義任何合理的頁(yè)面流程。你無(wú)需在非常特殊的情況下被迫使用專門的控制器。
現(xiàn)在 Web Flow 有足夠的能力表示由一系列 State 組成的一個(gè) Web 流程。State 是事件發(fā)生的流程點(diǎn):舉例來(lái)說(shuō)就是顯示一個(gè)視圖或者執(zhí)行一個(gè) Action。每個(gè) State 有一個(gè)或多個(gè) transitions ,他們習(xí)慣于從一個(gè) State 轉(zhuǎn)到另一個(gè) State 。一個(gè) transitions 被一個(gè) Event 所觸發(fā)。 為了讓你對(duì) Web 流程有一個(gè)大概的印象,下面這段 XML 定義了一個(gè) Web 流程,大致等效于實(shí)現(xiàn)一個(gè) SimpleFormController 的工作流 。對(duì)于這個(gè) Web 流程的原理將在本文的稍后詳細(xì)說(shuō)明。
熟悉業(yè)務(wù)過(guò)程管理(BPM) 的讀者將認(rèn)識(shí)到 Web 流程是普通工作流的一個(gè)特例,所以他們?cè)诶碚撋峡梢允褂孟?JBMP(請(qǐng)查看資源) 來(lái)實(shí)現(xiàn)一般化的 BMP 系統(tǒng)。既然簡(jiǎn)單是 Spring Web Flow 的重要設(shè)計(jì)目的,所以它不會(huì)去使用這種一般化的工作流引擎。在我們 Web 應(yīng)用中,我們會(huì)用一個(gè)簡(jiǎn)單的 Web 流程來(lái)描述一個(gè)頁(yè)面的流程。
本文的剩余部分會(huì)用一個(gè)實(shí)例來(lái)說(shuō)明這方面內(nèi)容,可以使用這個(gè)連接來(lái)下載源代碼:PhoneBook.war.zip ?,F(xiàn)在下載并解壓縮這個(gè)文件可能是個(gè)好注意,它能夠在你閱讀文章的時(shí)候幫助你學(xué)習(xí)。
實(shí) 例
實(shí)例是一個(gè)使用 Spring Web Flow 的電話簿應(yīng)用程序,我們將使用圖解的方式來(lái)說(shuō)明他的功能意圖。這是一個(gè)典型的公司內(nèi)網(wǎng)的應(yīng)用程序,你會(huì)發(fā)現(xiàn)大部分功能可能你已經(jīng)熟悉他的概念了。他主要允許你使用一些標(biāo)準(zhǔn)來(lái)查找公司的某位職員。一旦當(dāng)你發(fā)現(xiàn)了某個(gè)適當(dāng)?shù)厝?,你就可以更進(jìn)一步的查看他的信息,像電話號(hào)碼、辦公桌位置、他的經(jīng)理是誰(shuí)、他的同事有那些等等。圖1的草圖描繪了這個(gè)電話簿應(yīng)用程序的基本需求和頁(yè)面流程。
圖 1. 實(shí)例概覽
就像草圖描述的那樣,應(yīng)用程序?qū)嶋H有兩個(gè)模塊組成: Search 模塊允許我們查找一個(gè)我們要的人,而 Detail 模塊則顯示查找到這個(gè)人的詳細(xì)信息。Search 模塊將會(huì)使用 Detail 模塊來(lái)顯示查詢結(jié)果中某人的詳細(xì)信息。草圖同樣顯示了我們可以在明細(xì)頁(yè)直接訪問(wèn)被查人同事的明細(xì)。這意味著 Detail 模塊可以遞歸使用 Detail 模塊來(lái)顯示同事的明細(xì)。
文章稍后,將看到我們可以在一個(gè)單獨(dú)的 Web 流程中定義各個(gè)模塊。這意味著我們會(huì)有兩個(gè)流程:一個(gè) Search 流程和一個(gè) Detail 流程。
因?yàn)楸疚牡慕裹c(diǎn)是實(shí)現(xiàn)應(yīng)用程序的 Web 接口,所以我們將會(huì)提供包含了硬編碼啞數(shù)據(jù)的基本業(yè)務(wù)層。領(lǐng)域?qū)ο蟊话赾om.ervacon.springframework.samples.phonebook.domain 包中。我們有 4 個(gè)業(yè)務(wù)類:
- Person — 一個(gè)簡(jiǎn)單的 JavaBean 包含人員的信息 (名, 姓, 電話號(hào)碼 ...)。Person 對(duì)象使用 User Id 來(lái)唯一識(shí)別,是 UserId 類的一個(gè)實(shí)例。一個(gè) Person 類同樣也維護(hù)他同事們的引用,同樣都是 Person 類的實(shí)例。
- UserId — 這是一個(gè)主要對(duì)象用來(lái)識(shí)別一個(gè) Person。
- PhoneBookQuery — 一個(gè)查詢對(duì)象,在電話簿中描述一個(gè)查詢。我們可以是使用姓,名或者姓名來(lái)查詢。
- PhoneBook — 我們的主要業(yè)務(wù)門面(Business Facade)。這個(gè)類僅僅定義了一些啞數(shù)據(jù)和兩個(gè)業(yè)務(wù)方法:
- public List query(PhoneBookQuery query)
- public Person getPerson(UserId userId)
確定好業(yè)務(wù)功能性后,我們準(zhǔn)備使用 Spring Web Flow 來(lái)為電話簿應(yīng)用程序開發(fā) Web 接口。
設(shè)置 Spring MVC
在我們開始使用 Web Flow 之前,我們需要配置一個(gè)基本的 Spring Web 應(yīng)用程序。要做的第一件事是我們必須確定在 /WEB-INF/lib 目錄下有我們所要的 jar 文件。一個(gè) Spring Web Flow 的應(yīng)用程序需要4個(gè)jar在類路進(jìn)下: 包含 Spring 框架自身的 Spring.jar;包含 Web Flow 控制器實(shí)現(xiàn)的 webflow.jar; 記錄日志所需的 commons-logging.jar 和用來(lái)讀取和分析 Web Flow XML 文件的 jdom.jar;
由于這將是一個(gè)標(biāo)準(zhǔn)的 J2EE Web 應(yīng)用程序,所以需要在 /WEB-INF 目錄下有一個(gè) web.xml 部署文件。下面是此部署描述文件的代碼,它描述了如下事物:
- contextLoader servlet,當(dāng) Servlet 引擎(如 Tomcat )在加載我們的 Web 應(yīng)用程序的時(shí)候進(jìn)行初始化。
- 一個(gè)名為 phoneBook 的 Spring Dispatcher Servlet。這個(gè) Servlet 配置了處理所有相匹配的請(qǐng)求 (如 /phoneBook/*)。
- index.jsp 將會(huì)成為應(yīng)用程序的歡迎頁(yè)面。
- 實(shí)例的 JSP 頁(yè)面使用到了 Spring 的 標(biāo)簽庫(kù),所以我們需要聲明它。實(shí)際的 TLD 文件存儲(chǔ)在 /WEB-INF/tld 目錄下。

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

在 Spring MVC 應(yīng)用程序中,我們需要一個(gè) Spring 應(yīng)用程序上下文。它是你在應(yīng)用程序上下文中定義業(yè)務(wù)對(duì)象最好的地方。這樣你就能夠干凈的區(qū)分你的業(yè)務(wù)對(duì)象和任何 Web 應(yīng)用工件(artifacts)。讓我們跟隨這個(gè)練習(xí)創(chuàng)建一個(gè) /WEB-INF/applicationContext.xml 文件來(lái)定義我們的業(yè)務(wù)門面:phoneBook Bean。

2

3

4

5

6

7

我們需要在 web.xml 中適當(dāng)?shù)亩x Dispatcher Servlet。 這個(gè) Servlet 將會(huì)以默認(rèn)得方式讀取 /WEB-INF/ServletName-servlet.xml 配置文件。在我們的例子中將會(huì)是 /WEB-INF/phoneBook.xml。我們唯一需要配置的事是一個(gè) View Resolver。這個(gè) View Resolver 負(fù)責(zé)將視圖名(如:"criteria")解析成真實(shí)的視圖路進(jìn)(如:/WEB-INF/JSP/criteria.jsp)。下面這段使用的是 InternalResourceViewResolver。 所以在我們的實(shí)例中,所有頁(yè)面的位置將會(huì)在 /WEB-INF/jsp 目錄中。
我們假設(shè)所有其他的 Dispatcher Servlet 配置為默認(rèn)值。這意味著我們將使用一個(gè)簡(jiǎn)單的 BeanNameUrlHandlerMapping 來(lái)定位將要處理請(qǐng)求的控制器。對(duì)于如何配置 Dispatcher Servlet 的詳細(xì)信息請(qǐng)參考 Spring 的參考文檔(查看資源)。

2

3

4

5

6

7

8

9

待續(xù)……
參考資源:
- 下載本指南地實(shí)例應(yīng)用和源代碼: PhoneBook.war.zip
此應(yīng)用需要的 Jar 文件到下列地址可以找到:- spring.jar: Spring framework 首頁(yè)
- commons-logging.jar: Jakarta commons logging 首頁(yè)
- jdom.jar: JDOM 首頁(yè)
- webflow.jar: Spring web flow 首頁(yè)
- Java Servlet 技術(shù)和 JSP: http://java.sun.com/products/servlet/index.jsp
- Spring Web MVC 應(yīng)用程序一步步開發(fā)可以讀此教程: http://www.springframework.org/docs/MVC-step-by-step/Spring-MVC-step-by-step.html
- 要了解更多關(guān)于 Spring 的信息可以到 Spring Framework 的主頁(yè): http://www.springframework.org
- Spring 參考文檔: http://www.springframework.org/docs/reference/index.html
- 如果你想找一個(gè)通用的 Java 業(yè)務(wù)處理管理系統(tǒng), 查看 JBPM: http://www.jbpm.org