11.5. Handling Ajax Requests

Spring Javascript's client-side Ajax response handling is built upon the notion of receiving "fragments" back from the server. These fragments are just standard HTML that is meant to replace portions of the existing page. The key piece needed on the server is a way to determine which pieces of a full response need to be pulled out for partial rendering.

In order to be able to render partial fragments of a full response, the full response must be built using a templating technology that allows the use of composition for constructing the response, and for the member parts of the composition to be referenced and rendered individually. Spring Javascript provides some simple Spring MVC extensions that make use of Tiles to achieve this. The same technique could theoretically be used with any templating system supporting composition.

Spring Javascript's Ajax remoting functionality is built upon the notion that the core handling code for an Ajax request should not differ from a standard browser request, thus no special knowledge of an Ajax request is needed directly in the code and the same hanlder can be used for both styles of request.

Providing a Library-Specific AjaxHandler

The key interface for integrating various Ajax libraries with the Ajax-aware behavior of Web Flow (such as not redirecting for a partial page update) is org.springframework.js.AjaxHandler. A SpringJavascriptAjaxHandler is configured by default that is able to detect an Ajax request submitted via the Spring JS client-side API and can respond appropriately in the case where a redirect is required. In order to integrate a different Ajax library (be it a pure JavaScript library, or a higher-level abstraction such as an Ajax-capable JSF component library), a custom AjaxHandler can be injected into the FlowHandlerAdapter or FlowController.

Handling Ajax Requests with Spring MVC Controllers

In order to handle Ajax requests with Spring MVC controllers, all that is needed is the configuration of the provided Spring MVC extensions in your Spring application context for rendering the partial response (note that these extensions require the use of Tiles for templating):

<bean id="tilesViewResolver" class="org.springframework.js.ajax.AjaxUrlBasedViewResolver">
    <property name="viewClass" value="org.springframework.webflow.mvc.view.FlowAjaxTilesView"/>
</bean>
            

This configures the AjaxUrlBasedViewResolver which in turn interprets Ajax requests and creates FlowAjaxTilesView objects to handle rendering of the appropriate fragments. Note that FlowAjaxTilesView is capable of handling the rendering for both Web Flow and pure Spring MVC requests. The fragments correspond to individual attributes of a Tiles view definition. For example, take the following Tiles view definition:

<definition name="hotels/index" extends="standardLayout">
    <put-attribute name="body" value="index.body" />
</definition>

<definition name="index.body" template="/WEB-INF/hotels/index.jsp">
    <put-attribute name="hotelSearchForm" value="/WEB-INF/hotels/hotelSearchForm.jsp" />
    <put-attribute name="bookingsTable" value="/WEB-INF/hotels/bookingsTable.jsp" />
</definition>
            

An Ajax request could specify the "body", "hotelSearchForm" or "bookingsTable" to be rendered as fragments in the request.

Handling Ajax Requests with Spring MVC + Spring Web Flow

Spring Web Flow handles the optional rendering of fragments directly in the flow definition language through use of the render element. The benefit of this approach is that the selection of fragments is completely decoupled from client-side code, such that no special parameters need to be passed with the request the way they currently must be with the pure Spring MVC controller approach. For example, if you wanted to render the "hotelSearchForm" fragment from the previous example Tiles view into a rich Javascript popup:

<view-state id="changeSearchCriteria" view="enterSearchCriteria.xhtml" popup="true">
    <on-entry>
        <render fragments="hotelSearchForm" />
    </on-entry>
    <transition on="search" to="reviewHotels">
        <evaluate expression="searchCriteria.resetPage()"/>
    </transition>
</view-state>