<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>


    posts - 15,  comments - 34,  trackbacks - 27

    最近在TSS上看到了一片介紹Spring Web Flow的文章,順便就翻譯了下來(lái),SWF的正式版估計(jì)要到6月份才能看到了,目前的例子都是和Spring MVC集成的,但是換作和Struts集成也是非常方便的。



    2005年3月


    介紹
    你是否覺(jué)得當(dāng)你的Web應(yīng)用越來(lái)越復(fù)雜,理解和管理頁(yè)面流程—驅(qū)動(dòng)你應(yīng)用程序用例的樂(lè)譜—也越來(lái)越困難了呢?而被迫使用特定的方式做事情并且無(wú)法重用是不是讓你感覺(jué)很累?你是否覺(jué)得使用了太多時(shí)間開(kāi)發(fā)你自己特定的方法去解決普遍問(wèn)題就像會(huì)話狀態(tài)管理?

    進(jìn)入Spring Web Flow。

    什么是Spring Web Flow?
    Spring Web Flow (SWF) 是Spring Framework的一個(gè)脫離模塊。這個(gè)模塊是Spring Web應(yīng)用開(kāi)發(fā)模塊棧的一部分,Spring Web包含Spring MVC。

    Spring Web Flow 的目標(biāo)是成為管理Web應(yīng)用頁(yè)面流程的最佳方案。當(dāng)你的應(yīng)用需要復(fù)雜的導(dǎo)航控制,例如向?qū)В谝粋€(gè)比較大的事務(wù)過(guò)程中去指導(dǎo)用戶經(jīng)過(guò)一連串的步驟的時(shí)候,SWF將會(huì)是一個(gè)功能強(qiáng)大的控制器。

    以下是一個(gè)受控制的導(dǎo)航的例子,使用UML狀態(tài)圖描述:




    圖 1 - 一個(gè)航空訂票服務(wù)流程

    聰明的讀者會(huì)認(rèn)出這個(gè)是一個(gè)典型的航空訂票流程,就是那種每次你通過(guò)在線方式參與訂票的過(guò)程。

    為什么出現(xiàn)Spring Web Flow?
    在傳統(tǒng)的Web應(yīng)用中,頁(yè)面流程就像上面所展示的,不是很明確 — 他們不是一等公民。就拿一個(gè)使用Struts的Web應(yīng)用舉個(gè)例子,為了在Struts里面實(shí)現(xiàn)頁(yè)面流,大多數(shù)開(kāi)發(fā)人員利用了框架提供的Action和視圖。在這種情況下,一個(gè)單獨(dú)的Action就和一個(gè)指定的請(qǐng)求URL產(chǎn)生了聯(lián)系。只有當(dāng)請(qǐng)求從那個(gè)URL過(guò)來(lái)的時(shí)候,Action才會(huì)被執(zhí)行。在執(zhí)行過(guò)程中,Action運(yùn)行一些處理并且選擇一個(gè)合適的視圖顯示結(jié)果。這非常簡(jiǎn)單。

    所以要在Struts中實(shí)現(xiàn)多步控制的頁(yè)面流,你需要通過(guò)不同的視圖將獨(dú)立的Action形成鏈。用來(lái)處理不同事件,例如“后退”或“提交”的Action URL都是硬編碼在視圖中的。一些ad-hoc形式的會(huì)話存儲(chǔ)被用來(lái)管理流程狀態(tài)。提交后重定向被用來(lái)阻止重復(fù)提交,等等。

    雖然這是一個(gè)簡(jiǎn)單并且有效的方法,但是它具有一個(gè)很大的缺陷:從struts-config.xml文件的Action定義中不能清晰的看到頁(yè)面流程。你無(wú)法從幾棵樹(shù)看到一片森林,就像你無(wú)法從Action和視圖的定義看到頁(yè)面流程一樣。靈活性也因?yàn)锳ction和視圖不能被重用而大打折扣。最后,你仍然需要做很多工作,這并不見(jiàn)得容易。

    Spring MVC提供了一個(gè)輕便的高層次的功能:表單控制器實(shí)現(xiàn)了一個(gè)與定義的頁(yè)面流程。它提供了兩個(gè)這樣的控制器:SimpleFormController和AbstractWizardController。盡管如此,這些仍然是大多數(shù)頁(yè)面流程控制概念的例子。

    Tapestry和JSP在頁(yè)面的基礎(chǔ)上而不是請(qǐng)求的基礎(chǔ)上使用事件驅(qū)動(dòng)的方法,使得每個(gè)頁(yè)面和它的后退控制器邏輯保持一致。然而,仍然需要提供一個(gè)優(yōu)秀的類根據(jù)一個(gè)定義良好的能跨越多個(gè)頁(yè)面和不同路徑的生存周期去支持一個(gè)邏輯頁(yè)面流程。就如你所看到的,這個(gè)頁(yè)面流程的生存周期要比單一的請(qǐng)求長(zhǎng),但是卻比一個(gè)會(huì)話要短。

    這就是Spring Web Flow的切入點(diǎn),允許你使用一個(gè)簡(jiǎn)單清晰的方法體現(xiàn)你的頁(yè)面流程,并且隨時(shí)重用,包括像Struts、Spring MVC、Tapestry、JSP甚至Portlets這些環(huán)境下。

    優(yōu)點(diǎn)
    正如你所看到的,Spring Web Flow提供以下優(yōu)點(diǎn):

    Web應(yīng)用中的頁(yè)面流程可以通過(guò)Web流程的定義(XML文件或者Java類)清晰的展現(xiàn)出來(lái)。
    Web流程被設(shè)計(jì)成自包含的。這就允許你把你的應(yīng)用中的一部分看作是一個(gè)模塊,這樣就你可以在多種場(chǎng)合重用它。
    Web流程捕獲任何合理的頁(yè)面流程總是使用同種技術(shù)。你不必被迫在特定的場(chǎng)合使用特定的控制器。
    最后,Web流程是一等公民并且可以通過(guò)一個(gè)良好定義的契約使用。它具有一個(gè)清晰的,可觀察的生存周期為你自動(dòng)管理。通過(guò)簡(jiǎn)單配置,系統(tǒng)便會(huì)為你管理復(fù)雜的邏輯,總而言之,這非常容易使用。
    Spring Web Flow是如何工作的?
    現(xiàn)在已經(jīng)有能力說(shuō)Web流程是一組狀態(tài)(states)的集合。一個(gè)狀態(tài)是流程中發(fā)生某事的一個(gè)點(diǎn)。舉個(gè)例子,譬如顯示一個(gè)視圖或者執(zhí)行一個(gè)Action。每個(gè)狀態(tài)都有一個(gè)或更多的轉(zhuǎn)變(transitions)用來(lái)移動(dòng)到下一個(gè)狀態(tài)。

    一個(gè)轉(zhuǎn)變是由一個(gè)事件(event)觸發(fā)的。

    航空訂票Web流程示例
    為了展示一個(gè)Web流程的定義,下面的XML片段展示了上面UML狀態(tài)圖定義的航空訂票處理:

    代碼:
    <?xml version="1.0" encoding="UTF-8"?> 
    <!DOCTYPE webflow PUBLIC "-//SPRING//DTD WEBFLOW//EN" 
       "http://www.springframework.org/dtd/spring-webflow.dtd"
    > 

    <webflow id="bookflight" start-state="obtainTripInfo"> 

       
    <action-state id="obtainTripInfo"> 
          
    <action bean="bookingActions" method="bindAndValidate"/> 
          
    <transition on="success" to="suggestItineraries"/> 
          
    <transition on="error" to="tryAgain"/> 
       
    </action-state> 

       
    <action-state id="suggestItineraries"> 
          
    <action bean="bookingActions"/> 
          
    <transition on="success" to="displaySuggestedItineraries"/> 
       
    </action-state> 

       
    <view-state id="displaySuggestedItineraries" view="suggestedItenaries"> 
          
    <transition on="startOver" to="cancel"/> 
          
    <transition on="select" to="selectItinerary"/> 
       
    </view-state> 

       
    <action-state id="selectItinerary"> 
          
    <action bean="bookingActions"/> 
          
    <transition on="success" to="isPassengerInfoRequired"/> 
       
    </action-state> 

       
    <decision-state id="isPassengerInfoRequired"> 
          
    <if test="${requestScope.passenger == null}" then="enterPassengerInformation"/> 
          
    <if test="${requestScope.passenger.preferences.alwaysConfirmPassengerInfo}" 
             then
    ="enterPassengerInformation" else="displayReservationVerification"/> 
       
    </decision-state> 

       
    <subflow-state id="enterPassengerInformation" flow="passenger"> 
          
    <attribute-mapper> 
             
    <input value="${requestScope.passenger.id}" as="passengerId"/> 
          
    </attribute-mapper> 
          
    <transition on="finish" to="displayReservationVerification"/> 
       
    </subflow-state> 

       
    <view-state id="displayReservationVerification" view="reservationVerification"> 
          
    <transition on="startOver" to="cancel"/> 
          
    <transition on="assignSeats" to="chooseSeatAssignments"/> 
          
    <transition on="book" to="book"/> 
       
    </view-state> 

       
    <subflow-state id="chooseSeatAssignments" flow="seatAssignments"> 
          
    <attribute-mapper> 
             
    <input value="${requestScope.passenger.id}" as="passengerId"/> 
             
    <input name="itinerary"/> 
          
    </attribute-mapper> 
          
    <transition on="finish" to="displayReservationVerification"/> 
       
    </subflow-state> 

       
    <action-state id="book"> 
          
    <action bean="bookingActions"/> 
          
    <transition on="success" to="displayConfirmation"/> 
       
    </action-state> 

       
    <end-state id="displayConfirmation" view="reservationConfirmation"/> 

       
    <end-state id="tryAgain" view="tryAgain"/> 

       
    <end-state id="cancel" view="home"/> 

    </webflow>

    圖 2 - 基于XML的航空訂票流程定義

    就像你所看到的,僅僅是掃過(guò)XML定義,邏輯流程驅(qū)動(dòng)的訂票流程處理就已經(jīng)可以清晰地辨認(rèn)出來(lái)了,即使你都不了解Spring Web Flow實(shí)現(xiàn)細(xì)節(jié)。

    如果你看得仔細(xì)點(diǎn),你將會(huì)發(fā)現(xiàn)兩個(gè)子流程產(chǎn)生了訂票流程的子過(guò)程。第一個(gè)子流程指導(dǎo)用戶輸入乘客信息。第二個(gè)讓用戶分配他的座位。這個(gè)內(nèi)嵌的流程扮演了“迷你應(yīng)用程序模塊”的角色,這是Spring Web Flow強(qiáng)大的功能之一。

    你可以將這份定義上交給一位業(yè)務(wù)分析人員,并且她估計(jì)能看懂。更好的是你可以根據(jù)這個(gè)定義繪制一個(gè)可視化圖表將其提交給業(yè)務(wù)分析人員。做這個(gè)的工具已經(jīng)誕生了。

    航空訂票流程祥解
    這篇文章的下一部分將逐塊分解上面的航空訂票流程定義,并且提供對(duì)話框演示Spring Web Flow是如何工作的。

    流程定義

    這是第一行的XML流程定義:

    代碼:
    <webflow id="bookflight" start-state="obtainTripInfo"> 
        
    </webflow>

    webflow 元素定義了流程,指定它的id和start-date。id是一個(gè)簡(jiǎn)單的唯一的標(biāo)識(shí)符,start-state是一個(gè)轉(zhuǎn)變的初始狀態(tài),這發(fā)生在當(dāng)一個(gè)新的流程會(huì)話在運(yùn)行時(shí)被激活的時(shí)候。

    所以,在業(yè)務(wù)案例上,當(dāng)訂票會(huì)話被激活的時(shí)候,它將轉(zhuǎn)變?yōu)閛btainTripInfo狀態(tài)。

    獲得行程信息行為狀態(tài)(Action State)

    下面是obtainTripInfo狀態(tài)定義。

    代碼:
    <action-state id="obtainTripInfo"> 
       
    <action bean="bookingActions" method="bindAndValidate"/> 
       
    <transition on="success" to="suggestItineraries"/> 
       
    <transition on="error" to="tryAgain"/> 
    </action-state>

    記得當(dāng)狀態(tài)被進(jìn)入,針對(duì)該狀態(tài)的行為就發(fā)生了。正如你將看到的,不同的狀態(tài)類型有不同的執(zhí)行動(dòng)作。action state,正如obtainTripInfo,在進(jìn)入的時(shí)候執(zhí)行一個(gè)Action。該Action返回執(zhí)行的邏輯結(jié)果,并且這個(gè)結(jié)果被映射到狀態(tài)轉(zhuǎn)變上。一切就是這么簡(jiǎn)單。

    所以,在這個(gè)業(yè)務(wù)案例上,obtainTripInfo,當(dāng)進(jìn)入的時(shí)候執(zhí)行bookingActions這個(gè)Action的bindAndValidate方法。這個(gè)方法從瀏覽器綁定表單輸入到一個(gè)Trip領(lǐng)域?qū)ο蟛⑶覚z驗(yàn)它。如果處理成功,就進(jìn)入suggestItineraries狀態(tài)。如果錯(cuò)誤發(fā)生,進(jìn)入tryAgain狀態(tài)。

    訂票Action

    當(dāng)在Spring IoC中使用Spring Web Flow的時(shí)候,action元素的bean屬性涉及到Spring Application Context中定義的一個(gè)相同名稱的Action實(shí)現(xiàn)。下面是bookingActions的定義:

    web-context.xml

    代碼:
    <bean id="bookingActions" 
    class
    ="org.springframework.samples.bookflight.BookingActions"> 
        
    <property name="bookingAgent" ref="myBookingAgent"/> 
    </bean>

    這就允許我們的Action實(shí)現(xiàn)被Spring管理并且通過(guò)依賴注入進(jìn)行配置。

    建議路線行為狀態(tài)

    現(xiàn)在我們看一下下一個(gè)Action State,給定一個(gè)綁定的并且通過(guò)檢驗(yàn)的Trip對(duì)象作為輸入,返回一個(gè)建議的路線集合:

    代碼:
    <action-state id="suggestItineraries"> 
       
    <action bean="bookingActions"/> 
       
    <transition on="success" to="displaySuggestedItineraries"/> 
    </action-state>


    下面是Action實(shí)現(xiàn)代碼:

    代碼:
    public class BookingActions extends FormAction 
         
        
    public Event suggestItineraries(RequestContext context) 
            Trip trip 
    = (Trip)context.getRequestScope().getAttribute("trip"); 
            Collection
    <Itinerary> itineraries = bookingAgent.suggestItineraries(trip); 
            context.getRequestScope().setAttribute(
    "itineraries", itineraries); 
            
    return success(); 
        }
     
    }


    當(dāng)進(jìn)入suggestItineraries狀態(tài)的時(shí)候,suggestItineraries就被調(diào)用了。其他的Action State也是同樣的工作方式:進(jìn)入狀態(tài)并調(diào)用指定的方法。

    顯示建議路線視圖狀態(tài)(View State)

    一旦返回了一個(gè)建議的路線集合,下一步就是讓用戶看到它們并且讓用戶選擇他最喜歡的。這可以通過(guò)以下的狀態(tài)定義完成:

    代碼:
    <view-state id="displaySuggestedItineraries" view="suggestedItenaries"> 
       
    <transition on="startOver" to="cancel"/> 
       
    <transition on="select" to="selectItinerary"/> 
    </view-state>


    就如你所看到的,displaySuggestedItineraries是一個(gè)view state - 一個(gè)我們還未討論過(guò)的狀態(tài)類型。一個(gè)視圖狀態(tài),當(dāng)進(jìn)入的時(shí)候,導(dǎo)致執(zhí)行流程暫停,并將控制返回給客戶端同時(shí)根據(jù)配置的視圖同時(shí)返回。隨后,在用戶思考過(guò)后,客戶端發(fā)出一個(gè)事件描述用戶執(zhí)行的Action。繼續(xù)流程,事件的發(fā)生已經(jīng)映射到了一個(gè)狀態(tài)的轉(zhuǎn)變,這個(gè)轉(zhuǎn)變把用戶帶到了流程的下一步。

    所以,在這個(gè)業(yè)務(wù)案例上,當(dāng)進(jìn)入displaySuggestedItineraries的時(shí)候suggestedIteneraries視圖被渲染并且將控制返回給瀏覽器。然后用戶選擇路線之后點(diǎn)擊“選擇”按鈕。這就出發(fā)了select事件,傳遞選擇的路線id作為事件參數(shù)。

    用戶也可能選擇startOver,這時(shí)候流程轉(zhuǎn)變到了取消狀態(tài)。

    對(duì)于view屬性,Spring MVC中,F(xiàn)lowControoler使用熟悉的 ModelAndView和ViewResolver構(gòu)造,在Struts中,F(xiàn)lowAction用ActionForward。

    客戶端狀態(tài)

    在這個(gè)問(wèn)題上你可能會(huì)問(wèn):

    “...自從進(jìn)入ViewState之后,執(zhí)行流程暫停了,控制返回給了瀏覽器,那么流程如何重新拾起并且繼續(xù)運(yùn)行呢?”

    答案就是客戶端跟蹤一個(gè)唯一的id用戶標(biāo)示流程執(zhí)行點(diǎn),并且將這個(gè)id放在input標(biāo)簽內(nèi),以便引起下一個(gè)事件。典型的做法是放在一個(gè)隱藏域內(nèi)。

    舉個(gè)例子,在一個(gè)JSP文件里:

    代碼:
    <input type="hidden" value="<c:out value="${flowExecution.id}"/>">


    “是否需要乘客信息?” 決策狀態(tài)(Decision State)

    用戶選擇了她需要的路線之后,流程需要做一個(gè)上下文關(guān)系(contextual)的決策關(guān)于下一步執(zhí)行什么。

    需要特別指出的是,如果用戶沒(méi)有登錄,或者她已經(jīng)登錄但是希望確認(rèn)她的信息 - 例如她所使用的信用卡 - 流程控制需要允許她確定這些信息。另一方面,如果她已經(jīng)登錄并且希望直接進(jìn)入預(yù)定頁(yè)面,流程控制應(yīng)該跳個(gè)這個(gè)可選步驟。

    基本上需要做一個(gè)動(dòng)態(tài)的決策重新考慮她的信息和偏好的。

    決策狀態(tài)最適合這個(gè),看下面的定義:

    代碼:
    <decision-state id="isPassengerInfoRequired"> 
       
    <if test="${requestScope.passenger == null}" then="enterPassengerInformation"/> 
       
    <if test="${requestScope.passenger.preferences.alwaysConfirmPassengerInfo}" 
          then
    ="enterPassengerInformation" else="displayReservationVerification"/> 
    </decision-state>


    輸入乘客信息子流程狀態(tài)(SubFlow State)
    處理乘客信息的過(guò)程邏輯上獨(dú)立的。這是處理的一部分,但是在機(jī)票預(yù)定這個(gè)上下文環(huán)境之外它也可以獨(dú)立存在。

    子流程(Subflow)狀態(tài)機(jī)制就是針對(duì)這個(gè)實(shí)現(xiàn)的。當(dāng)進(jìn)入一個(gè)子流程狀態(tài),這個(gè)子流程就被產(chǎn)生了。父流程掛起知道子流程結(jié)束。這讓你可以把你的應(yīng)用作為一系列自包含的模塊看待,至于流程,你可以很容易的把多種情況統(tǒng)一處理。

    看一下enterPassengerInformation子流程狀態(tài):

    代碼:
    <subflow-state id="enterPassengerInformation" flow="passenger"> 
        
    <attribute-mapper> 
          
    <input value="${requestScope.passenger.id}" as="passengerId"/> 
       
    </attribute-mapper> 
       
    <transition on="finish" to="displayReservationVerification"/> 
    </subflow-state>


    flow 屬性是這個(gè)進(jìn)入這個(gè)流程的id,attribute-mapper 元素從子流程映射屬性。輸入映射將屬性向下映射到子流程。輸出映射將屬性倒退會(huì)父流程當(dāng)子流程結(jié)束的時(shí)候。你可以從這里看到表達(dá)式也是支持的。

    所以,在這個(gè)業(yè)務(wù)用例上,當(dāng)進(jìn)入enterPassengerInformation狀態(tài),乘客流程就產(chǎn)生了。passengerId屬性傳遞給這個(gè)流程作為輸入。從這里,自流程作它需要做的。對(duì)于父流程來(lái)說(shuō)這是一個(gè)黑箱。當(dāng)子流程結(jié)束,父流程繼續(xù),應(yīng)答最后結(jié)果并決定去哪執(zhí)行下一步 — 在這里,去確認(rèn)預(yù)定。

    顯示確認(rèn)結(jié)束狀態(tài)(End State)

    最有一個(gè)狀態(tài)類型在這里討論:結(jié)束狀態(tài)。當(dāng)進(jìn)入結(jié)束狀態(tài),活動(dòng)的流程會(huì)話就結(jié)束了。在結(jié)束上面,所有與之相關(guān)的資源都被自動(dòng)清理。

    displayConfirmation結(jié)束狀態(tài)在一條路線被被成功預(yù)定后顯示確認(rèn)信息:

    代碼:
    <end-state id="displayConfirmation" view="reservationConfirmation"/>


    當(dāng)進(jìn)入這個(gè)狀態(tài)的時(shí)候,訂票流程結(jié)束了并且顯示reservationConfirmation視圖。因?yàn)橛喥绷鞒淌歉鞒蹋⒎亲恿鞒蹋匀魏畏峙涞馁Y源都會(huì)被自動(dòng)清理。

    注意:結(jié)束流程如果是一個(gè)子流程,進(jìn)入這個(gè)狀態(tài)就會(huì)被認(rèn)為是一個(gè)子流程結(jié)果并繼續(xù)父流程。更特別的是,這個(gè)狀態(tài)的ID在繼續(xù)父流程的子流程的狀態(tài)上被用作一個(gè)狀態(tài)的轉(zhuǎn)變。你可以從enterPassengerInformation子流程狀態(tài)定義上看出來(lái)。注意它如何響應(yīng)子流程的“完成”結(jié)果,是通過(guò)一個(gè)“完成”結(jié)束狀態(tài)。

    流程部署
    到這里,你了解了Spring Web Flow是關(guān)于什么的,并且你也看到了一個(gè)現(xiàn)實(shí)的例子。現(xiàn)在你要看到的就是如何部署這個(gè)流程定義到特定的環(huán)境中去執(zhí)行,就行Spring MVC在一個(gè)Servlet環(huán)境下一樣:

    做這事是很容易的,這里你需要和Spring MVC一起使用:

    代碼:
    <bean name="/booking.htm" class="org.springframework.web.flow.mvc.FlowController"> 
        
    <property name="flow"> 
            
    <ref bean="bookingFlow"/> 
        
    </property> 
    </bean> 
      
    <bean id="bookingFlow" class="org.springframework.web.flow.config.XmlFlowFactoryBean"> 
       
    <property name="location" value="classpath:bookflight-flow.xml"/> 
    </bean>


    這就自動(dòng)將bookingFlow導(dǎo)出至/booking.htm這個(gè)URL在一個(gè)Servlet環(huán)境里。

    高級(jí)主題
    下面的部分介紹了一些SWF更高級(jí)的特性。

    流程執(zhí)行監(jiān)聽(tīng)器(Flow Execution Listeners)
    FlowExecutionListener 構(gòu)造了一個(gè)觀察者允許你監(jiān)聽(tīng)并且對(duì)一個(gè)執(zhí)行著的流程的生存周期作出反應(yīng)。你可以使用這個(gè)特性作任何事,從一個(gè)狀態(tài)的預(yù)處理到后期條件的檢測(cè),或則審計(jì)、安全處理。

    流程執(zhí)行存儲(chǔ)策略(Flow Execution Storage Strategies)
    一個(gè)執(zhí)行著的流程的狀態(tài)的存儲(chǔ)機(jī)制是完全可插拔的。基于HttpSession的存儲(chǔ)是默認(rèn)的,但是SWF提供兩種其他的存儲(chǔ)方式:一個(gè)是使用服務(wù)器端連續(xù)的會(huì)話儲(chǔ)存,另一種是使用完全的客戶端序列化。定義你自己的存儲(chǔ)方式,舉個(gè)例子,譬如使用數(shù)據(jù)庫(kù)存儲(chǔ),是不推薦的。

    什么時(shí)候使用Spring Web Flow才適合你?
    你應(yīng)該注意到Spring Web Flow并不是一攬子全包的解決方案。正如你所看到的,這是一個(gè)有狀態(tài)的系統(tǒng)能夠自動(dòng)管理這些由業(yè)務(wù)處理過(guò)程驅(qū)動(dòng)的頁(yè)面流程。它不能被當(dāng)作簡(jiǎn)單的、無(wú)狀態(tài)的解決方案。舉個(gè)例子,它不能被用在一些需要自由導(dǎo)航的站點(diǎn),一些可以讓用戶自由“點(diǎn)擊周圍任意鏈接”的站點(diǎn)。Spring Web Flow被設(shè)計(jì)為強(qiáng)大的受控制導(dǎo)航,可以指導(dǎo)用戶按照一個(gè)清晰的業(yè)務(wù)目的和生存周期進(jìn)行處理。

    為了使得用例更具體,這里有一些“不錯(cuò)的流程”的例子,這些流程就適合使用SWF系統(tǒng):

    航空訂票
    稅收管理
    申請(qǐng)貸款
    下面的一些例子是不適合使用SWF的:

    索引頁(yè)
    歡迎頁(yè)
    菜單
    簡(jiǎn)單表單流(一個(gè)頁(yè)面)
    Spring Web Flow打算要作為一個(gè)優(yōu)秀的傳統(tǒng)的控制器在任何Web環(huán)境下,就像Spring MVC、Struts、Tapestry、Web Work、JSP或者Portlets一樣。一個(gè)單一的站點(diǎn)可以適當(dāng)?shù)慕M合使用簡(jiǎn)單的控制器管理Web流程。

    路線圖
    Spring Web Flow 1.0 final 版本將隨著Spring 1.3正式版發(fā)布,時(shí)間定在JavaOne大會(huì)前大概六月份的時(shí)候。就現(xiàn)在而言,只能期待正式、穩(wěn)定的預(yù)覽版。這個(gè)產(chǎn)品目前已經(jīng)在特性集合和示例程序方面相當(dāng)成熟了。

    當(dāng)開(kāi)發(fā)小組給最終發(fā)布版砌上最后一塊磚時(shí),下面是一些最重要的特性我們長(zhǎng)在著手完成:

    整合
    作為獨(dú)立的庫(kù),Spring Web Flow很好與其他框架整合了。除了Spring MVC以外,已經(jīng)提供了和Struts、Portlet MVC的整合,JSP和Tapestry的整合在最終版中也會(huì)見(jiàn)到。

    流程管理
    在Spring 1.2中,在MBeanServer中輸出用于管理和監(jiān)視的bean是很容易的。一個(gè)FlowExecutionMBean管理接口已經(jīng)存在了,我們計(jì)劃擴(kuò)展以便可以從JMX控制臺(tái)集中監(jiān)控在服務(wù)器執(zhí)行的所有流程的全局統(tǒng)計(jì)數(shù)據(jù)。

    可插拔性
    系統(tǒng)中的每個(gè)結(jié)構(gòu)都可以做成可插拔的以獲得簡(jiǎn)單的擴(kuò)展或定制,甚至是從xml定義中。這包括狀態(tài)和轉(zhuǎn)變,以及其中的其他概念。

    事務(wù)補(bǔ)償
    提供的特性和例子程序展示了在執(zhí)行過(guò)程中使用事務(wù)補(bǔ)償來(lái)回滾先前提交的事務(wù),我們對(duì)這點(diǎn)很感興趣。

    總結(jié)
    Spring Web Flow 是控制業(yè)務(wù)處理流程的有效解決方案。并且用起來(lái)也很有意思,如果你還沒(méi)試過(guò),那么你還等什么呢?

    參考
    Spring Web Flow is covered in the Core Spring training course offered by Interface21 -
    http://www.springframework.com/training

    The Spring Framework,
    http://www.springframework.org/

    The Spring Web Flow Wiki,
    http://opensource.atlassian.com/confluence/spring/display/WEBFLOW/Home

    The kdonald blog,
    http://www.jroller.com/page/kdonald

    Struts,
    http://struts.apache.org/

    Java Server Faces,
    http://java.sun.com/j2ee/javaserverfaces/

    Tapestry,
    http://jakarta.apache.org/tapestry

    WebWork,
    http://www.opensymphony.com/webwork/

    JMX,
    http://java.sun.com/jmx

    JavaOne,
    http://java.sun.com/javaone/

    譯者
    Nicholas@NirvanaStudio

    2005-5-19

    原文地址:http://www.theserverside.com/articles/content/SpringWebFlow/article.html


    引用:
    http://www.nirvanastudio.org/forum/topic.aspx?topicid=15&page=65535
    _________________
    Blog:
    http://nicholasdsj.blogdriver.com
    MSN:
    http://spaces.msn.com/members/nicholasdsj
    Nicholas@NirvanaStudio
    http://www.nirvanastudio.org/jswiki/default.asp?title=Nicholas
    http://www.nirvanastudio.org/jswiki
    http://www.nirvanastudio.org/forum

    posted on 2005-09-23 15:07 jacky 閱讀(1415) 評(píng)論(1)  編輯  收藏 所屬分類: Open source

    FeedBack:
    # re: [轉(zhuǎn)]翻譯了一篇Spring Web Flow的文章
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    常用鏈接

    留言簿(10)

    隨筆檔案

    文章分類

    文章檔案

    相冊(cè)

    收藏夾

    java

    搜索

    •  

    最新評(píng)論


    主站蜘蛛池模板: 亚洲国产成人精品久久久国产成人一区二区三区综 | 亚洲精品无码MV在线观看| 国产区卡一卡二卡三乱码免费| 久久久高清免费视频| 日日麻批免费40分钟日本的| 国产成人yy免费视频| 亚洲一级毛片免费观看| 57pao一国产成永久免费| 4444www免费看| 一级女人18毛片免费| 成年在线网站免费观看无广告| AV免费网址在线观看| 四虎影院在线免费播放| 国产网站免费观看| 亚洲精品高清一二区久久| 亚洲精品WWW久久久久久| 免费一级肉体全黄毛片| 亚洲一级特黄大片在线观看| 亚洲三区在线观看无套内射| 亚洲Av无码精品色午夜| 亚洲欧洲日产国码在线观看| 国产人成亚洲第一网站在线播放| 亚洲日韩一区二区三区| 四虎国产精品成人免费久久 | 亚洲av无码专区首页| 国产成人+综合亚洲+天堂| 国产免费久久久久久无码| 国产免费一区二区三区不卡| 久久99国产乱子伦精品免费| 国产情侣激情在线视频免费看| 香蕉高清免费永久在线视频| 免费观看四虎精品国产永久| 精品国产日韩亚洲一区| 亚洲精品自产拍在线观看动漫| 精品久久亚洲中文无码| 国产综合激情在线亚洲第一页| a级毛片100部免费观看| 噼里啪啦免费观看高清动漫4| 国产精品色午夜免费视频| 亚洲日韩小电影在线观看| 亚洲成人免费在线观看|