JBoss Development is brought to you in partnership with:

Max Katz heads Developer Relations for Appery.io, a cloud-based mobile app platform. He loves trying out new and cool REST APIs in mobile apps. Max is the author of two books “Practical RichFaces” (Apress 2008, 2011), and is a frequent speaker at developer conferences. You can find out what Max is up to on his blog: mkblog.exadel.com and Twitter: @maxkatz. Max is a DZone MVB and is not an employee of DZone and has posted 74 posts at DZone. You can read more from them at their website. View Full User Profile

JBoss RichFaces with Spring

02.16.2009
| 185175 views |
  • submit to reddit

Creating Views
Let's start with the main view which has a button to launch the wizard as well as display all current orders.
start.xhtml:

<h:form>
<!-- launch wizard button -->
<rich:panel header="Welcome to RichBar">
<a4j:commandButton value="Click to start your order"
oncomplete="#{rich:component('wizard')}.show()" />
</rich:panel>
<rich:editor rendered="false" />
</h:form>

<!-- modal panel where the wizard is running -->
<rich:modalPanel id="wizard" width="550" height="300">
<f:facet name="header">Drink Order</f:facet>
<f:facet name="controls">
<a href="#" onclick="#{rich:component('wizard')}.hide()">X</a>
</f:facet>

<h:panelGroup id="wizardInclude">
<a4j:include viewId="#{wizardBean.startPage}" />
</h:panelGroup>

</rich:modalPanel>

<!-- order table -->
<a4j:outputPanel id="orders">
<rich:dataTable value="#{barBean.orders}" var="order"
rendered="#{barBean.rowCount>0}" rowKeyVar="row">
<rich:column>
<f:facet name="header">Order #</f:facet>
<h:outputText value="#{row+1}" />
</rich:column>
<rich:column>
<f:facet name="header">Name</f:facet>
<h:outputText value="#{order.name}" />
</rich:column>
<rich:column>
<f:facet name="header">Email</f:facet>
<h:outputText value="#{order.email}" />
</rich:column>
<rich:column>
<f:facet name="header">Drink</f:facet>
<h:outputText value="#{order.drink}" />
</rich:column>
<rich:column>
<f:facet name="header">Comments</f:facet>
<h:outputText value="#{order.comments}" escape="false" />
</rich:column>
</rich:dataTable>
</a4j:outputPanel>
</body>



There are three main things here.

At the very top of the page, we place a button to launch the wizard. a4j:commandButton opens the modal panel by using a built-in RichFaces JavaScript function rich:component('id') and invoking the show() method on the modal panel.

Next we have the actual modal panel. Two facets define modal panel header and a control to close the modal panel. To close the modal panel we use the hide() JavaScript function on the modal panel. Next is a4j:include tag. The tag works similar to Facelets ui:include but also allows to navigate within the included content. That's what's going to give us wizard functionality. Remember that #{wizardBean.startPage} is initialized to /page1.xhtml in Spring configuration file.

The last portion is a rich:dataTable control that displays all current orders. The table is not rendered if the list is empty. We have also defined rowKeyVar attribute which holds the current row number. We use it as order number in the display.

The next four pages are part of the wizard.

page1.xhtml



<h:form xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:rich="http://richfaces.org/rich"
xmlns:a4j="http://richfaces.org/a4j">

<a4j:keepAlive beanName="wizardBean" />
<rich:panel>
<h:panelGrid>
<h:panelGroup>
<h:outputLabel value="Email:" for="email" />
<h:outputText value=" (We will email you your receipt!)"
style="FONT-SIZE: small;" />
</h:panelGroup>
<h:panelGroup>
<h:inputText id="email" value="#{wizardBean.email}">
<rich:ajaxValidator event="onkeyup" />
</h:inputText>
<rich:message for="email" />
</h:panelGroup>
<a4j:commandButton value="Next" action="next" />
</h:panelGrid>
</rich:panel>
</h:form>



In the first page of the wizard, we are only asking for an email so we can send the customer the receipt via email (just like in Apple stores). Notice that the page uses rich:ajaxValidator to validate the email field. rich:ajaxValidator works against standard Hibernate Validation set in the bean:

@NotEmpty
@Email(message = "Invalid email format")
private String email;



This eliminates having to register a validator with the component on the page. Another benefit is that rich:ajaxValidator skips the Process Validations and Update Model phases. As we are only validating the field, we can slightly increase performance by not executing those phases. Skipping those two phases is identical to setting bypassUpdates="true" (see RichFaces developers guide for further information). 

One last thing we need to cover is a4:keepAlive tag placed at the top of the page. If you look at wizardBean registration in Spring configuration file, you will notice that the scope of this bean is request. As you know, this bean is what backing up the wizard screens. Now, as we move from wizard screen to wizard screen, the values entered on the previous screen are somehow being remembered. They are being remembered because on the last screen (summary.xhtml), we are shown all the values entered. But the bean is in request scope which means that for every request a new bean is created and if that's the case then the old value will be lost. So, how are the values saved?

That's exactly what a4j:keepAlive tag does. It stores the bean (wizardBean) with the UI component tree. On postback, the UI component tree is restored and also restores the bean placing it back into request scope. This is basically a page scope, as long as we are staying on this page, the bean and its properties will be available to us on postback.

The way a4j:keepAlive works is that it adds the bean to current UI view root. The following is important, even though we placed a4j:keepAlive in the first wizard screen (page1.xhtml), technically, the bean will be added to main.xhtml UI view root. That's also the reason we only had to place a4j:keepAlive on the first page without having it on other wizard screens. Again, by placing a4j:keepAlive in the first included page (page1.xhtml), we really added the tag to main.xhtml view.

Now, because we are always staying on the same page, the wizardBean will always be there. This is the correct behavior as we are basically getting page scope. However, we want to clear the wizardBean in order to launch it again and not have old values populated. Thus, we have to programmatically end the page scope and restart it on next wizard launch. That's exactly what the last line in save method does:

public void save() {
orderService.addOrder(name, email, drink, comments);

FacesContext.getCurrentInstance().getExternalContext().getRequestMap()
.remove("wizardBean");
}


page2.xhtml

<h:form xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:rich="http://richfaces.org/rich"
xmlns:a4j="http://richfaces.org/a4j">
<rich:panel>
<h:panelGrid>
<h:outputLabel value="Name:" for="name" />
<h:panelGroup>
<h:inputText id="name" value="#{wizardBean.name}" >
<rich:ajaxValidator event="onkeyup"/>
</h:inputText>
<rich:message for="name"/>
</h:panelGroup>
<h:panelGroup>
<a4j:commandButton value="Previous" action="prev" />
<a4j:commandButton value="Next" action="next" />
</h:panelGroup>
</h:panelGrid>
</rich:panel>
</h:form>



The second page in the wizard prompts to enter the name. We again use rich:ajaxValidator to validate the name field with Hibernate Validation. Validation is defined as follows:

@NotEmpty(message = "Name must not be empty")
@Pattern(regex = ".*[^\\s].*", message = "This string contain only spaces")
private String name;

 

AttachmentSize
richfaces-spring-wizard.zip11.15 MB
Published at DZone with permission of Max Katz, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Gene De Lisa replied on Fri, 2009/07/31 - 9:45am

What exactly are you thinking by posting an 11 MB zip file that contains nothing but library jar files? Are you getting some perverse pleasure by wasting other people's time and bandwidth? Do you know the meaning of the word courtesy? Apparently not.

If you don't want to post your code don't post a zip. It's as simple as that.

Kushan Jayathilake replied on Fri, 2009/10/30 - 7:56am

Hi Max, Great work!..

i have a problem, i have added the validation conditions in managed bean of the JSF page

ie :

@NotEmpty(message = "Country Name must not be empty.")

@Pattern(regex = ".*[^\\s].*", message = "Spaces are not allowed.")

private String countryName;

 

i have several  <a4j:commandButton> and <a4j:commandLink> in the same page, validation fires each and every time i press a commandLink or Button,   iif that field is empty("countryName" as i specified here)

how can i control the validation to fire for the particular button or a link...?  (i need validation to be fired when only i clicked the save button)

please help me on this...

Max Katz replied on Thu, 2009/11/05 - 8:10pm in response to: Kushan Jayathilake

This article should help: http://java.dzone.com/news/richfaces-region-partial-jsf

Kushan Jayathilake replied on Fri, 2009/11/06 - 6:45am

Thx Max, It helped me to solve my problem,

I have another question,

I want to generate dynamic checkboxes depends on a collection, so i have written

<h:dataTable id="functionsGrid" value="# {functionManagedBean.collecOfFunctions}"                                                            var="function"  >
                                                                                   
<h:column>
      <h:selectBooleanCheckbox id="#{function.functionName}" value="#{functionManagedBean.checked}"/>
 
    <h:outputLabel for="" value="outputLabel"></h:outputLabel>

</h:column>                            
                                                                                   
</h:dataTable>



and finally this form contains an <a4j:commandButton> , in the managedBean side i want to get the selected checkboxes....(problem is checkboxes are generating dyamically, so how can assign their values for the different properties in the managedBean..

Thank you very much in advance.. :)

Tee Siong replied on Wed, 2010/04/07 - 5:40am

I have problem where the Next button could't go to next page . I am not using Facelets .But i use jsf . I have configure my faces-config.xml file properly .What is the possible root cause ? Can you share your working example ? email to me . monsiong@yahoo.com . Thanks

Thomas Strecker replied on Thu, 2010/05/27 - 3:36am in response to: Mohsin Khan

I encountered the same problem, but only after switching to Spring Annotations and Component Scan. The reason is rather simple: the WizardBean now no longer receives the value for the startPage (which was set to "/page1.xhtml" in the spring application context before) and now the renderer ends up in a endless loop.

So if you want to use the annotation based version, manually set the parameter in the bean.

Mohammad Shariq replied on Tue, 2010/06/15 - 2:50pm

Please email me the correct file. I am not able to open or download the source code. The one file from which I downloaded contained only jars and no significant java files or any other code. PLease email me as early as possible at 2008Shariq@gmail.com

Mehdi Ben Haj Abbes replied on Mon, 2010/07/19 - 2:18am in response to: stu bilton

Hi, For the NotSerializableException, I tried to implement Serializable but didn’t work and I had a Spring Exception : my backing bean has a bean injected through spring. The solution was to look for the bean through getBean(“beanName”) rather than injecting it.

Fabio Malheiro replied on Tue, 2010/09/28 - 8:26am

This was supposed to be a good tutorial right?

I was trying to implement your example... but I'm a little bit confused. Sometimes you "talk" about a bean orderService, and Service ... but where the fuck is the Service class?

Andres Botero replied on Wed, 2010/11/17 - 12:02pm

When i inyect a dependency into a bean it's null. For Example:

<bean id="wizardBean" class="bar.view.WizardBean" scope="request">
   <property name="orderService" >
    <ref bean="service" />
   </property>
</bean>

In that case the orderService is null, colud you tell me why is that?

A S M Russel replied on Fri, 2011/09/30 - 1:10am

After Migrating from XML configuration to Annotation based configurated i am getting the following error.

at com.sun.facelets.el.VariableMapperWrapper.resolveVariable(VariableMapperWrapper.java:60)

the error trace is too long thats why i am pasting it here.

I create the spring3 template project with STS and follow your instruction.

Its working well for xml configuration.But getting error when i am going to annotation based configuration 

Scott Duke replied on Tue, 2011/10/25 - 10:46pm

I came across this example and ran across a few problems and wanted to post the solutions once the project is imported. The project is using Tomcat 6.0 but I was using Tomcat 7.0. There were about 3 places in the project preferences I had to change from Tomcat 6.0 to Tomcat 7.0. Here were 3 of the places. Just look through the preferences. 1. preferences -> Java -> Compiler 2. preferences -> Server -> Runtime Environment 3. preferences -> Java Build Path Because I was using jdk 1.7.0, I had to update the facets on the project at: preferences -> Project Facets and change the Java to 1.7

Max Katz replied on Thu, 2011/10/27 - 4:48pm in response to: Scott Duke

Thanks for posting.

Nagy Andika replied on Fri, 2011/11/04 - 5:13am

Hi! Nice article. This is what I'm looking for but in an upgraded version. I wonder if you tried it with RichFaces4 and Spring3.0. Would it be as seamless as here? Andika

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.