Using JSF with Spring Webflow

From Foochal

Jump to: navigation, search


Contents

How To

Define a bean to be used in a flow scope

<bean name="launchInput" class="org.foochal.demo.MyClass" singleton="false"/>

Access your flow scope bean from Webflow Action class?

public Event myCustomAction(RequestContext context) {
 MyBean myBean = (MyBean) context.getFlowScope().getRequired("myBean", MyBean.class);

 ...
 ...

 return success();
}

Access your flow scope bean from JSF?

<h:form>
 <h:inputText id="myProperty" value="#{flowScope.myBean.myProperty}" required="true"/>
</h:form>

I ran into JSF rendering issues when I specified and id in the <h:form> tag

<h:form id="myId">

When I specified the id, for some reason, JSF was showing my submit button instead of the message tag. I think this is related to unique id generation per field, and JSF could not identify the field referred by the message tag.

Access your flow scope bean from FacesContext?

MyBean myBean = (MyBean) facesContext.getApplication().createValueBinding("#{flowScope.myBean}").getValue(facesContext);

Use tiles with JSF and Webflow

  • In your faces config, set your view handler as following. You will need the myfaces impl jar in your project classpath.
    <view-handler>org.apache.myfaces.application.jsp.JspTilesViewHandlerImpl</view-handler>
  • Add the following context parameter in your web.xml. This tells tiles-jsf integration layer which extension to expect when transferring view control from JSF to tiles.
 <context-param>
  <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
  <param-value>.view</param-value>
 </context-param>
  • Add the following context param in web.xml to tell JSF about tiles definition locations.
<context-param>
  <param-name>tiles-definitions</param-name>
  <param-value>/WEB-INF/defs/tiles.xml</param-value>
</context-param>
  • Map your faces servlet as follows (in addition to any other mapping that you may have). This maps .view extensions to JSF. The reason is as follows: while transferring logical views from spring webflow component to JSF, we need to map the extension to a JSF extension, which can then be mapped to a tiles view system by replacing the well known suffix (see context-param "javax.faces.DEFAULT_SUFFIX") with .tiles..
<servlet>
 <servlet-name>Faces Servlet</servlet-name>
 <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
  <servlet-name>Faces Servlet</servlet-name>
  <url-pattern>*.view</url-pattern>
</servlet-mapping>
  • Create the tiles definition files. A typical definition entry which need to be accessible through webflow xml should look like this:
<definition name="/index.tiles" page="/WEB-INF/jspf/index.jsp">
</definition>

In the above example, the .tiles extension is required (implicitly by the jsp-tiles view handler).

  • Finally, in your webflow xml file, refer to a view definition as defined in your tiles file, but use the .view extension instead. So the following <view-state> ...
<view-state id="welcome" view="index.view">

... refers to the tiles definition /index.tiles

Use Ajax4JSF framework in your JSF/Webflow application

Setting up ajax4jsf

  • Make sure that you include the ajax4j.jar and the oscache.jar files in your project classpath
  • Add the following tag lib directive in your includes.
<%@ taglib prefix="a4j" 	uri="https://ajax4jsf.dev.java.net/ajax" %>
  • Define a servlet filter for ajax calls
   <context-param>
      <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
      <param-value>server</param-value>
   </context-param>
   <filter>
      <display-name>Ajax4jsf Filter</display-name>
      <filter-name>ajax4jsf</filter-name>
      <filter-class>org.ajax4jsf.Filter</filter-class>
   </filter>
  • Bind the filter to the extension to which your jsf framework is bound to. In the examples in this page, we have used a .view extension.
   <filter-mapping>
      <filter-name>ajax4jsf</filter-name>
      <url-pattern>*.view</url-pattern>
   </filter-mapping>
  • When using ajax4jsf with myfaces, make sure that you always use an ajax region with selfRendered="true"
<a4j:region selfRendered="true">

Setting up the right flow repository

Ajax calls to the webflow engine end up changing the continuation id of the current flow. There are two options to solve this problem:

  1. Update the continuation id stored in the page with the newly generated id. However, I haven't found an easy way to do this. Even, if there was a way to do this, it is very manual and must be done on all pages with AJAX and in all AJAX calls.
  2. The second option is to use a flow repository which allows multiple continuations. This allows the old continuations to work, despite of new continuation ids generated as part of the AJAX calls.

Configure your spring beans xml as follows:

   <bean id="flowExecutionRepositoryFactory"
      class="org.springframework.webflow.execution.repository.continuation.ContinuationFlowExecutionRepositoryFactory">
      <constructor-arg ref="flowRegistry" />
   </bean>

   <bean id="flowRegistry"
      class="org.springframework.webflow.registry.XmlFlowRegistryFactoryBean">
      <property name="flowLocations"
         value="/WEB-INF/flows/*.xml" />
   </bean>

Define an ajax action

   <view-state id="welcome" view="/welcome.view">
      <transition on="ajaxAction" to="welcome">
         <action bean="myBean"
            method="ajaxMethod">
         </action>
      </transition>
   </view-state>

Personal tools