Friday, February 3, 2012

Learning JSF2: Using Flash scope

JSF 2 provides two new scopes on top of the standard Servlet scopes (request, session, application). One of them is the view scope. View scope was covered in Managed beans article. The other scope is Flash which I’m going to cover here. Let’s start with a very simple example.

Managed bean:

@ManagedBean(name = "bean") public class Bean {    private String text;    // getter and setter      public String nextpage (){        return "page2";    } }

As scope is not specified, the default scope is request.

JSF page (page1.xhtml):

>    > 	 value="Text:" /> 	 value="#{bean.text}" /> 	 action="#{bean.nextpage}" value="Click" />    > >


JSF page (page2.xhtml):

>#{bean.text}>

This application is very simple. The first page will render this (shown after entering text):

Once button is clicked, we navigate to the next page and text value is displayed:

One thing to note. We didn’t define a navigation rule in JSF configuratin file. We used JSF 2 implicit navigation feature:

public String nextpage (){        return "page2";  }

JSF will try to locate page called page2.xhtml and navigate to it. Navigation was was covered in this article.

Another thing to keep in mind that by default JSF does server forward when it invokes navigation. You probably noticed this this causes the URL in browser address bar always be one behind the actual page. This happens because we do a postbback (submit the page to itself) but return a different page to the browser.

One way to solve this problem is to use a redirect. A redirect can be defined in JSF configuration file or also added to our implicit navigation:

public String nextpage (){        return "page2?faces-redirect=true";  }

Running the application with above change and navigating to the second page will produce an empty page. When using a redirect, a page is submitted and once we reach the navigation step, the server sends the browser back a response telling it to send a new request to a specified URL. Now, this URL now matches the actual page we would be displaying. While we solved the URL/page matching problem, we now created another problem. As the browser sends a new request, any request-scoped objects will be recreated (or the old one gone). As our bean was in request scope, a new one was created and we lost the original text. That’s where the new Flash scope can help us.

Objects placed inside the Flash scope will be available for the subsequent request and then cleared. In other words, objects placed in Flash scope will survive a redirect. The Flash scope is very similar to temporary Seam conversation.

To place an object into Flash scope we use this:

public String nextpage (){    JSFUtils.flashScope().put("bean", this);       return "page2?faces-redirect=true";  }
public class JSFUtils {    public static Flash flashScope (){ 	return (FacesContext.getCurrentInstance().getExternalContext().getFlash());    } }

Then, to read the values from Flash scope on the result page, we update the page like this:

>#{flash.bean.text}>

this will also work:

>#{flash['bean'].text}>

View scope wouldn’t work here as it works when we are staying on the same view (page). In our case, we navigated to a different view (page).

No comments: