5.7. Other Action execution examples

on-start

The following example shows an action that creates a new Booking object by invoking a method on a service:

<flow xmlns="http://www.springframework.org/schema/webflow"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/webflow
                          http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">

    <input name="hotelId" />

    <on-start>
        <evaluate expression="bookingService.createBooking(hotelId, currentUser.name)" 
                  result="flowScope.booking" />
    </on-start>

</flow>
			

on-entry

The following example shows a state entry action that sets the special fragments variable that causes the view-state to render a partial fragment of its view:

<view-state id="changeSearchCriteria" view="enterSearchCriteria.xhtml" popup="true">
    <on-entry>
        <render fragments="hotelSearchForm" />
    </on-entry>
</view-state>
			

on-exit

The following example shows a state exit action that releases a lock on a record being edited:

<view-state id="editOrder">
    <on-entry>
        <evaluate expression="orderService.selectForUpdate(orderId, currentUser)"
                  result="viewScope.order" />
    </on-entry>
    <transition on="save" to="finish">
        <evaluate expression="orderService.update(order, currentUser)" />
    </transition>
    <on-exit>
        <evaluate expression="orderService.releaseLock(order, currentUser)" />
    </on-exit>
</view-state>
			

on-end

The following example shows the equivalent object locking behavior using flow start and end actions:

<flow xmlns="http://www.springframework.org/schema/webflow"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/webflow
                          http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">

    <input name="orderId" />

    <on-start>
        <evaluate expression="orderService.selectForUpdate(orderId, currentUser)"
                  result="flowScope.order" />
    </on-start>

    <view-state id="editOrder">
        <transition on="save" to="finish">
            <evaluate expression="orderService.update(order, currentUser)" />
        </transition>
    </view-state>

    <on-end>
        <evaluate expression="orderService.releaseLock(order, currentUser)" />
    </on-end>
    
</flow>
			

on-render

The following example shows a render action that loads a list of hotels to display before the view is rendered:

<view-state id="reviewHotels">
    <on-render>
        <evaluate expression="bookingService.findHotels(searchCriteria)"
	              result="viewScope.hotels" result-type="dataModel" />
    </on-render>
    <transition on="select" to="reviewHotel">
        <set name="flowScope.hotel" value="hotels.selectedRow" />
    </transition>
</view-state>
			

on-transition

The following example shows a transition action adds a subflow outcome event attribute to a collection:

<subflow-state id="addGuest" subflow="createGuest">
    <transition on="guestCreated" to="reviewBooking">
        <evaluate expression="booking.guestList.add(currentEvent.attributes.newGuest)" />  
    </transition>
</subfow-state>
			

Named actions

The following example shows how to execute a chain of actions in an action-state. The name of each action becomes a qualifier for the action's result event.

<action-state id="doTwoThings">
    <evaluate expression="service.thingOne()">
        <attribute name="name" value="thingOne" />
    </evaluate>
    <evaluate expression="service.thingTwo()">
        <attribute name="name" value="thingTwo" />
    </evaluate>
    <transition on="thingTwo.success" to="showResults" />
</action-state>
			

In this example, the flow will transition to showResults when thingTwo completes successfully.

Streaming actions

Sometimes an Action needs to stream a custom response back to the client. An example might be a flow that renders a PDF document when handling a print event. This can be achieved by having the action stream the content then record "Response Complete" status on the ExternalContext. The responseComplete flag tells the pausing view-state not to render the response because another object has taken care of it.

<view-state id="reviewItinerary">
    <transition on="print">
        <evaluate expression="printBoardingPassAction" />
    </transition>
</view-state>
			
public class PrintBoardingPassAction extends AbstractAction {
    public Event doExecute(RequestContext context) {
        // stream PDF content here...
        // - Access HttpServletResponse by calling context.getExternalContext().getNativeResponse();
        // - Mark response complete by calling context.getExternalContext().recordResponseComplete();
        return success();
    }
}
			

In this example, when the print event is raised the flow will call the printBoardingPassAction. The action will render the PDF then mark the response as complete.

Handling File Uploads

Another common task is to use Web Flow to handle multipart file uploads in combination with Spring MVC's MultipartResolver. Once the resolver is set up correctly as described here and the submitting HTML form is configured with enctype="multipart/form-data", you can easily handle the file upload in a transition action. Given a form such as:

<form:form modelAttribute="fileUploadHandler" enctype="multipart/form-data">
	Select file: <input type="file" name="file"/>		
	<input type="submit" name="_eventId_upload" value="Upload" />			
</form:form>
			

and a backing object for handling the upload such as:

package org.springframework.webflow.samples.booking;

import org.springframework.web.multipart.MultipartFile;

public class FileUploadHandler {
    
    private transient MultipartFile file;
    
    public void processFile() {
		//Do something with the MultipartFile here
    }

    public void setFile(MultipartFile file) {
        this.file = file;
    } 
}
			

you can process the upload using a transition action as in the following example:

<view-state id="uploadFile" model="uploadFileHandler">
    <var name="fileUploadHandler" class="org.springframework.webflow.samples.booking.FileUploadHandler" />
    <transition on="upload" to="finish" >
        <evaluate expression="fileUploadHandler.processFile()"/>
    </transition>
    <transition on="cancel" to="finish" bind="false"/>
</view-state>
			

The MultipartFile will be bound to the FileUploadHandler bean as part of the normal form binding process so that it will be available to process during the execution of the transition action.