JavaServer Faces (JSF) Tutorial

JSF GuessNumber: Demonstrating Standard Validation and Backing Bean Methods

In this tutorial, we will create the familiar Guess Number application. The scenario is as follows. A user is asked to guess a number between 0 and 100. If the guess is correct, a success page is displayed with a link to play again. If the guess is incorrect, a message is printed notifying the user that a smaller or a larger number should be entered and the game continues.

For this application, we will try to use as many aspects of JSF as possible. We will use the standard validation available in JSF and also show how to use backing bean methods to help with navigation.

Of course, we think you should build this application from the beginning. However, if you would like to run a finished application instead, you can download the file, jsf-guessnumber.jar. Then follow the steps at the end of this tutorial to build and deploy.

Actually, if this is your first experience with JSF, we recommend you try our JSF KickStart tutorial first. Another good resource and starting place for JSF is our JSF Tags Reference Guide.

What Are We Going to Build?

The following screen shots show you how the application will look.


Figure 1: A user is asked to enter a number between 0 and 100.


Figure 2: User input is validated and an error message is displayed if invalid input was entered.


Figure 3: After the user enters a guess, the application tells the user if a smaller or a larger number should be tried.


Figure 4: A user guesses correctly.

Let's start working on our application!

Preparing for the Application

We first need to create a JSF project directory structure. We are going to provide you with a JSF project skeleton directory structure which will be the starting point of our application. Download and unzip this file, jsf-blank.zip.

You should now have JSF project directory structure with a topmost folder called jsfProject. Rename that folder to jsfGuessNumber to make a more appropriate name for our application.

Creating the JSP Pages

Our application has two pages. The first page is inputnumber.jsp. It prompts the user to enter a number. If the guess is incorrect, the same page will be redisplayed with a message indicating whether a smaller or a larger number should be tried. The second page is success.jsp. This page will be shown after the user guesses the number correctly. From this page you also have the option to play the game again.

Page Flow

The page flow in this example will look like the image below. The blue-colored page with a transition leading to the inputnumber.jsp page represents that the playagain outcome from any page whatsoever will lead to the inputnumber.jsp page. We will explain this more later.

inputnumber.jsp

Let's start with our first page, inputnumber.jsp. Create the file in the WebContent/pages directory. Then paste in the following code for the file.

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<f:loadBundle basename="game.messages" var="msg"/>

<html>
 <head>
    <title>inputnumber.jsp</title>
 </head>
 <body>
     <f:view>
      <h:form id="inputNumbers">
       <p>
         <h:outputText value="#{msg.how_to_play}"/>
       </p>
       <p>
         <h:messages style="color: blue"/>
       </p>
       <p>
         <h:inputText value="#{numberBean.userNumber}" required="true">
           <f:validateLongRange minimum="0" maximum="100"/>
         </h:inputText>
         <h:commandButton value="#{msg.makeguess_button}" action="#{numberBean.checkGuess}"/>
       </p>
      </h:form>
    </f:view>
 </body>
</html>

The first line is a directive that tells where to find JSF tags that define HTML elements and the second is a directive that tells where to find JSF tags that define core JSF elements. The third line loads a resource bundle that holds messages that we want to display in our JSP page. We will create the bundle file a little bit later.

Most of the tagging on the page is is contained in the <f:view> element. All JSF components must go inside this element and there can be only one <f:view> element on a page.

The <h:form> simply creates a form. The form values will be submitted to the server. The id attribute is any unique id that identifies this form.

The <h:outputText> tag simply looks up the value of msg.how_to_play in a properties file and prints it on the page. In our case it will print the game instructions. Also the messages tag will display any error messages during the execution of the application (for example, if the user enters an invalid number).

Next we create input field and also add validation. The first line creates an input text field for the user to enter a number. Look closely at the value property. It is associated with a property in a JavaBean class which we will create later. When we submit this page, the value of the userNumber property will be set to the entered number.

Next we see JSF standard validation. First, note the attribute/value pair, required="true". This means the user must enter something or an error message will be shown. Next, note the f:validateLongRange tag. This will ensure that the user enters a number and that number is between 0 and 100 or an error will be shown.

Next we create a submit button. The button's label will be taken from our resource file defined as msg from the value of makeguess_button. The action value references a method in a backing bean. This method will perform our application logic, checking if the entered number is equal to the application generated random number. It will return a value that will determine the path of our navigation. If the "success" string is returned, then we will transition to the success.jsp page. If a null is returned, we will redisplay the same page.

Why Do We Use null?

We just want the same page to redisplay if a user did not guess the number. So, we take advantage of the JSF feature that if a null value is received by the navigation, it simply means to redisplay the same page.

success.jsp

Create the success.jsp file in the WebContent/pages directory with this code.

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<f:loadBundle basename="game.messages" var="msg"/>

<html>
 <f:view>
   <h:form id="result">
     <p>
       <h:outputFormat value="#{msg.success_text}">
         <f:param value="#{numberBean.userNumber}"/>
       </h:outputFormat>
     </p>
     <p>
       <h:commandButton value="#{msg.tryagain_button}"
       			action="#{numberBean.playagain}"/>
     </p>
   </h:form>
 </f:view>
</html>

This page, success.jsp, is shown if the user correctly guessed the number. The <h:outputFormat> tag will get the value of success_text from the properties file. The {0} in success_text will be substituted for by the value of the value attribute within the <f:param> tag during runtime.

At the end, we have a button which allows us to replay the game. The action value references a backing bean method. In this case, the method only terminates the current session so that when we are shown the first page, the input text box is clear and a new random number is generated.

index.jsp

Create the index.jsp file one level up in the WebContent folder with this code.

<html>
 <body>
  <jsp:forward page="/pages/inputnumber.jsf" />
 </body>
</html>

This code is very simple. We are just starting our application by forwarding from a non-JSF resource (this file) to a JSF resource. index.jsp doesn't have any JSF components, just a standard JSP forward.

Creating a Resource Bundle

We will use a properties file to hold some of the text strings used in the application.

messages.properties

Create the messages.properties file in JavaSource/game/ (after creating the folder, game) with this code.

how_to_play=Please pick a number between 0 and 100. 
makeguess_button=Make Guess
tryagain_button=Play Again?
success_text=How cool... You have guessed the number. {0} is correct! 
tryagain_smaller=Oops... incorrect guess. Please try a smaller number.
tryagain_bigger=Oops... incorrect guess. Please try a bigger number.

This properties file is also very simple. It contains keys and values which are used in our example.

Creating a Bean Class

We will use a bean class to hold the "business" logic and to store and retrieve values.

NumberBean.java

Create the NumberBean.java file in the JavaSource/game folder with the code below. The code in NumberBean.java is explained by the comments inserted in the file.

package game;

import javax.faces.context.FacesContext;
import javax.servlet.http.HttpSession;
import javax.faces.application.FacesMessage;
import java.util.ResourceBundle;

public class NumberBean {

  Integer userNumber; // user entered number 
  int randomNumber ; // random number generated by application

  // constructor, generates random number
  public NumberBean () {
    randomNumber = (int)(Math.random()*100);
    System.out.println ( "Random number: "+randomNumber);
  }
  // setter for inputNumber
  public void setUserNumber (Integer value){
     this.userNumber = value;
  }
  // getter for inputNumber
  public Integer getUserNumber () {
    return this.userNumber;
  } 
  // this method simply invalidates the current session
  public String playagain () {
    FacesContext context = FacesContext.getCurrentInstance();
    HttpSession session = (HttpSession) context.getExternalContext().getSession(false);
    session.invalidate();
    return "playagain"; 
  }
  // check if user guessed the number
  public String checkGuess () {
     
    // if guessed, return 'success' for navigation
    if ( userNumber.intValue() == randomNumber ) {
      return "success";
    }
    // incorrect guess
    else {

      // get a reference to properties file to retrieve messages
      FacesContext context = FacesContext.getCurrentInstance();
      ResourceBundle bundle =
                ResourceBundle.getBundle("game.messages",
                    		context.getViewRoot().getLocale());
      String msg = "";
      // if number bigger, get appropriate message
      if ( userNumber.intValue() > randomNumber ) 
         msg = bundle.getString("tryagain_smaller");
      else // if number smaller, get appropriate message
         msg = bundle.getString("tryagain_bigger");
      
      // add message to be displayed on the page via <h:messages> tag
      context.addMessage (null, new FacesMessage(msg)); 

      // return null for navigation to display the same page
      return null;
    }
  }
}

Editing faces-config.xml, the JSF Configuration File

The last file we need to work on is the faces-config.xml file. Find this file in the WebContent/WEB_INF folder.

This file will hold our two navigation rules and defines the backing bean used. You will need to insert the code colored red into the file.

<?xml version="1.0"?>
<!DOCTYPE faces-config PUBLIC
  "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
  "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">

<faces-config>
  
  <navigation-rule>
    <from-view-id>/pages/inputnumber.jsp</from-view-id>
    <navigation-case>
      <from-outcome>success</from-outcome> 
      <to-view-id>/pages/success.jsp</to-view-id>
    </navigation-case>
  </navigation-rule>
  
  <navigation-rule>
    <from-view-id>*</from-view-id>
    <navigation-case>
      <from-outcome>playagain</from-outcome> 
      <to-view-id>/pages/inputnumber.jsp</to-view-id>
    </navigation-case>
  </navigation-rule>

  <managed-bean>
    <managed-bean-name>numberBean</managed-bean-name>
    <managed-bean-class>game.NumberBean</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
  </managed-bean>
                 
</faces-config>

The first navigation rules states that if you are at the page, /pages/inputnumber.jsp, and the outcome is success, then navigate to the /pages/success.jsp page.

The second navigation rules states that from any page, (* stands for any page) an outcome of playagain will take you to /pages/inputnumber.jsp. Outcome values are returned from backing bean methods in this example.

If you look closely at the navigation rules, you'll see there is no rule to redisplay the inputnumber.jsp page when a user enters an invalid number generating a null result. That's done on purpose in this example to demonstrate a feature of JSF. When JSF navigation receives a null value as the outcome, it will redisplay the same page.

Finally, the managed bean section simply defines our backing bean.

Compiling

The project skeleton that you downloaded comes with an Ant script to compile your application, but, first, we need to modify it to tell Ant where to find the servlet API. The servlet file is usually kept inside the servlet container. In our example, we use Tomcat, so we will point to the jar that comes with Tomcat.

Open the ant/build.xml file and add the following line to the compile.classpath section where TomcatHome is the root folder of the Tomcat server you are going to use.

<pathelement path ="{TomcatHome}/common/lib/servlet-api.jar"/>

To compile the application, type the following inside the ant folder in the project skeleton:

ant build.xml

Deploying

Before you can run this application within the servlet container, we need to deploy it. We will use null (link) deployment to deploy the application in-place. To do this we need to register a context in Tomcat's {TomcatHome}\conf\server.xml file.

To do this, insert this code:

<Context debug="0"
docBase="Path_to_WebContent"
path="/jsfGuessNumber" reloadable="true"/> 
near the end of the server.xml file within the Host element just before the closing </Host> tag. Of course, Path_to_WebContent needs to be replaced with the exact path on your system to the WebContent folder inside the jsfGuessNumber folder (for example, C:/examples/jsfGuessNumber/WebContent).

Running

Next, start your Tomcat server. When Tomcat is done loading, launch a web browser and enter: http://localhost:8080/jsfGuessNumber. ( Port 8080 is the default port in Tomcat, but your setup might be different.)


Tutorials
Training