by Ed Burns

Michael Jouravlev, in his influential August 2004 articleRedirect After Post,described a problem that many web applications present. He described the problem as follows:
All interactive programs provide two basic functions: obtaining user input and displaying the results.Web applications implement this behavior using two HTTP methods: POST and GET respectively. This simple protocol getsbroken when an application returns a web page in response to a POST request. Peculiarities of the POST method combined withidiosyncrasies of different browsers often lead to an unpleasant user experience and may produce an incorrect state ofthe server application.
To address the problem, Jouravlev described a technique that he called POST-REDIRECT-GET, or the PRG pattern for short.The rules of the pattern are as follows:
  • Never show pages in response to POST
  • Always load pages using GET
  • Navigate from POST to GET using REDIRECT
Previous versions of JavaServer Faces (JSF) technology violated the firstof these rules by using POST for every page navigation.In navigating from one page to another in a JSF-enabled application, the JSF framework forwarded a POST requestthrough the Servlet API's RequestDispatcher.forward( ) method. This caused a new Faces page to be renderedand returned to the browser in response to the postback request.

Indeed, most popular Java Servlet-based web frameworks, including Struts, use this approach for navigation. HTTP purists rightlypoint out that this approach violates the first rule in the PRG pattern. Not only did JSF violate the first rule, but untilJavaServer Faces 2.0, it was very difficult to do it any other way.Thanks to a JSF contribution from the Seam team at JBoss, it is now much easier to do PRG with JSF.

This Tech Tip shows how to implement the PRG pattern in JSF 2.0. The content of the tip is an adaptation of a sectionon PRG and JSF 2.0 in my upcoming book, with Neil Griffin,JavaServer Faces 2.0: The Complete Reference.

A Non-PRG Example

Let's start by examining a simple JSF 2.0 application that handles user registration. In this first example, the applicationdoes not implement the PRG pattern. The initial page for the application is coded in file register.xhtml, as follows:

A Simple JavaServer Faces Registration Application JSF Registration App

Registration Form

First Name: Last Name: ... additional table rows not shown.

The page presents text fields for the user to enter a first name and a last name. It also displays a Register button.When the user presses the Register button, the JSF navigation rule system looks for a page within the application whose extensionis the same as the current page and whose filename is confirm. If confirm.xhtml exists,JSF uses the navigation components in that file to navigate to the next page. Here is the confirm.xhtmlfile:

A Simple JavaServer Faces Registration Application JSF Registration App

Registration Confirmation

First Name: package com.jsfcompref.model; ... imports @ManagedBean @SessionScoped public class UserBean { ... properties and methods public String addConfirmedUser() { boolean added = true; // actual application may fail to add user FacesMessage doneMessage = null; String outcome = null; if (added) { doneMessage = new FacesMessage("Successfully added new user"); outcome = "done"; } else { doneMessage = new FacesMessage("Failed to add new user"); outcome = "register"; } FacesContext.getCurrentInstance().addMessage(null, doneMessage); return outcome; }
For this simple case, addConfirmedUser( ) causes a message stating Successfully added new userto be displayed on the page and returns "done" as the outcome.When the addConfirmedUser( ) method returns "done" as the outcome,it takes the user to the done.xhtml page.This is an example of implicit navigation, a new feature in JSF 2.0.If no matching navigation case is found after checking all available rules, the navigation handler checks to see whetherthe action outcome corresponds to a view id. If a view matching the action outcome is found, an implicit navigation tothe matching view occurs. Here the outcome is "done" and the matching view is done.xhtml,so the user is taken to the done.xhtml page. Implicit navigation saves you the effort of adding navigation rulesin the faces-config.xml file.

Here is the done.xhtml page:

A Simple JavaServer Faces Registration Application JSF Registration App

Registration Confirmation

First Name:
This example specifies that the value of the request parameter with the name "foo" is automatically assignedto the property at #{}. So for a GET request as follows:

The value of the #{} property will be set to bar when JSF starts processing the request.

View Parameters is similar in spirit to the page parameters feature found in JBoss Seam, but the JSF 2.0 incarnation of the featureis tightly integrated with the core JSF specification, making the feature easier to use and more powerful.Let?s look at another simple example.

A Simple JavaServer Faces 2.0 View First Name:<

The element has action="page02?faces-redirect=true". In the Internet standard thatdefines URLs, the presence of a ? character indicates the remainder of the URL will be an & or &-separated list ofname=value pairs that should be submitted to the server along with the request for the URL. This is known as a query string.JSF borrows the meaning of the ? character here, and the meaning is exactly the same as in the Internet standard for URLs.There are two special query strings parameters recognized by JSF when it parses the outcome on the server side.The faces-redirectquery string tells the navigation system that this implicit navigation case must be treated asif it were a real element that includes a element. The otherspecial query string parameter, includeViewParams, tells the navigation handler to include the view parameters whenperforming the navigation. But what view parameters should be included? The view parameters to be included when performing thenavigation are declared on the to-view-id page. In this case, we are using implicit navigation, so theimplicit to-view-id is page02.xhtml, shown below.