JSF Guess Number Example
Hello, in this tutorial we will be building the Guess Number in a bootstrap enabled jsf application and will demonstrate the following:
- Application presents user with a page that asks you to guess a number
- Output page that tells whether the number is guessed correctly or not
This example will show the implementation of Guess Number.
1. Introduction
JSF allows to build a Guess Number application where the application asks the user to guess a number between 0 and 10 (both inclusive), validates the input against a random number and responds with another page that informs the user whether he or she has guessed the number correctly or incorrectly. In this application, the following will be shown on the output page:
- If a number has been guessed incorrectly, the applications will display the response page (
response.xhtml
) with a proper error messageand contains a Back button. Clicking the Back button results in displaying the original greeting page (greetings.xhtml
) which asks the user to guess a number again - If a number has been guessed correctly, the application will display the response page (
response.xhtml
) with a message as “Congratulations! You got it correct!” - The application will also display a validation error message in case the entered number doesn’t fall within the minimum and maximum range
In the below tutorial, we will have the following components:
- greetings.xhtml – A jsf page application the user to input the number
- response.xhtml – Class to display the out
- UserNumberBean.java – Managed bean class to validate the user entered number with the randomly generated number and display the corresponding result to the user
- MessageFactory.java – Factory class to display the UI related messages on the response page
- faces-config.xml – Configuration file to register the managed bean and implement the navigation rules for our jsf application
- web.xml – Web application configuration file
1.1 How it can be achieved?
Programmers need to implement the below steps to this example:
- Developing the managed beans
- Creating the pages using the component tags
- Defining page navigation
- Mapping the
FacesServlet
instance - Adding managed bean declarations
Now, open up the Eclipse IDE and let’s start building the application!
2. JSF Guess Number Example
2.1 Tools Used
We are using Eclipse Kepler SR2, JDK 8 (1.8.0_131), Tomcat7 application server and MySQL database. Having said that, we have tested the code against JDK 1.7 and it works well.
2.2 Project Structure
Firstly, let’s review the final project structure, in case you are confused about where you should create the corresponding files or folder later!
2.3 Project Creation
The below example shows how to implement the event queue using a method binding technique in an application.
This section will demonstrate on how to create a Dynamic Web Java project with Eclipse. In Eclipse IDE, go to File -> New -> Dynamic web project
In the New Dynamic Project window fill in the below details and click next
- Enter the project name and project location
- Select Target runtime as Apache Tomcat v7.0 from dropdown
- Select Configuration as JavaServer Faces v.2.2 Project from dropdown (this is required to download the java server faces capabilities in your project)
Leave everything as default in this window as we will be making the required java file at a later stage. Simply click next and we will land up on the web-module window
In the Web Module window, leave the context_root
and content_directory
values as default (however, you can change the context_root
but for the first application let’s keep it as a default value). Simply, check Generate web.xml deployment descriptor checkbox and click next
In the JSF Capabilities windows, we will require downloading the dependencies (not available by default) so that our project is configured as a JSF module in Eclipse. Add the JSF capabilities to the web project by clicking on the download icon (encircled in Fig. 6) and download the JSF 2.2 Mojarra implementation
A new pop-up window will open where it will auto lists down the JSF library. Select the JSF 2.2 library and click next (the library name and download destination will be auto populated)
Check the license checkbox and click finish. Eclipse will download the JSF 2.2 library and will display them on the JSF capabilities windows (i.e. Fig. 6)
Now the JSF implementation libraries will be listed down on the capabilities page. Select the checkbox (JSF2.2 (Mojarra 2.2.0)) and leave everything else as default. Click Finish
Eclipse will create the project named JSF Guessnumber in the workspace and web.xml
will be configured for accepting the JSF requests. It will have the following code:
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>JSF Guessnumber</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <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>/faces/*</url-pattern> </servlet-mapping> <context-param> <description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description> <param-name>javax.faces.STATE_SAVING_METHOD</param-name> <param-value>client</param-value> </context-param> <context-param> <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name> <param-value>resources.application</param-value> </context-param> <listener> <listener-class>com.sun.faces.config.ConfigureListener</listener-class> </listener> </web-app>
Let’s start building the application!
3. Application Building
Below are the steps involved in developing this application:
3.1 Source File Creation
For the demo, we are using a sample login page application. Right click on project WebContent -> New -> File
Note: In JSF 2.0, it’s recommended to create a JSF page in xhtml format, a file format with .xhtml extension
A pop-up window will open. Verify the parent folder location as JSF Guessnumber/WebContent
and enter the file name as greetings.xhtml
. Click Finish
Repeat the step listed in Fig. 10. Verify the parent folder location as JSF Guessnumber/WebContent
and enter the file name as response.xhtml
and click Finish
3.1.1 Implementation of Input & Output file
The first page of the example is greetings.xhtml
which will have the form based UI components and accepts the user input for validation. The action attribute on the button will show the corresponding result based on the corresponding logic written in the managed-bean. Add the following code to it:
greetings.xhtml
<!DOCTYPE HTML> <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://xmlns.jcp.org/jsf/core"> <h:head> <meta charset="utf-8" name="viewport" content="width=device-width, initial-scale=1" http-equiv="X-UA-Conpatible" /> <h:outputStylesheet library="css" name="bootstrap.min.css" /> <title>JSF Guessnumber</title> <style type="text/css"> .errorMsg { color: red; padding-top: 20px; } </style> </h:head> <h:body> <center><h2>JSF Guess Number Example</h2></center> <div class="container"> <div class="row"> <div class="form_bg"> <h:form id="helloForm"> <div class="form-group"> Hi! I am Mr. Ocean. And I'm thinking of a number from <span id="minimumVal"><h:outputText value="#{UserNumberBean.minimum}"/></span> to <span id="maximumVal"><h:outputText value="#{UserNumberBean.maximum}"/></span>. Can you guess it? </div> <div class="form-group"> <h:graphicImage id="waveImg" library="images" name="wave.med.gif" alt="Mr. Oecan Waving Hand" /> <h:inputText id="userNo" label="User Number" value="#{UserNumberBean.userNumber}" validator="#{UserNumberBean.validate}" /> </div> <div> <h:commandButton id="submit" action="success" value="Submit" styleClass="btn btn-primary" /> </div> <div class="errorMsg"><h:message id="errors1" for="userNo" /></div> </h:form> </div> </div> </div> </h:body> </html>
We now create the second page response.xhtml
to display the output message. Add the following code to it:
response.xhtml
<!DOCTYPE HTML> <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://xmlns.jcp.org/jsf/core"> <h:head> <meta charset="utf-8" name="viewport" content="width=device-width, initial-scale=1" http-equiv="X-UA-Conpatible" /> <h:outputStylesheet library="css" name="bootstrap.min.css" /> <title>JSF Guessnumber</title> <style type="text/css"> .responseTextCSS { font-size: xx-large; padding: 18px; } </style> </h:head> <h:body> <center><h2>JSF Guess Number Example</h2></center> <div class="container"> <div class="row"> <div class="form_bg"> <h:form id="responseForm"> <div class="form-group"> <h:graphicImage id="waveImg" library="images" name="wave.med.gif" alt="Mr. Oecan Waving Hand" /> <h:outputText styleClass="responseTextCSS" id="result" value="#{UserNumberBean.response}"/> </div> <div id="successBtn"> <h:commandButton rendered="#{UserNumberBean.btnValue}" id="errBack" value="Back" action="error" styleClass="btn btn-success" /> </div> <div id="errorBtn"> <h:commandButton rendered="#{!UserNumberBean.btnValue}" id="successBack" value="Back" action="success" styleClass="btn btn-danger" /> </div> </h:form> </div> </div> </div> </h:body> </html>
3.2 Java Class Creation
Let’s create the required java files. Right click on src folder New -> Package
A new pop window will open where we will enter the package name as com.jsf.guessnumber.example
Once the package is created in the application, we will need to create the required managed bean. Right click on the newly create package New -> Class
A new pop window will open and enter the file name as UserNumberBean
. The managed bean class will be created inside the package com.jsf.guessnumber.example
Repeat the step listed in Fig. 14. Again, a new pop window will open and enter the file name as MessageFactory
. The managed bean class will be created inside the package com.jsf.guessnumber.example
3.2.1 Implementation of Managed Bean Class
The managed bean class, UserNumberBean.java
generates a random number from 0 to 10 inclusive. Add the following code to it:
UserNumberBean.java
package com.jsf.guessnumber.example; import java.util.Random; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.validator.LongRangeValidator; import javax.faces.validator.ValidatorException; public class UserNumberBean { private int maximum = 0; private int minimum = 0; private String[] status = null; private String response = null; private Integer randomInt = null; private Integer userNumber = null; private boolean btnValue = false; private boolean maximumSet = false; private boolean minimumSet = false; // Generating Random Number At Application Start-Up Which Will Be Used To Test The Application public UserNumberBean() { Random randomNum = new Random(); do { randomInt = new Integer(randomNum.nextInt(10)); } while (randomInt.intValue() == 0); System.out.println("Selected Random Number Is?: " + randomInt); } public int getMaximum() { return maximum; } public void setMaximum(int maximum) { this.maximum = maximum; this.maximumSet = true; } public int getMinimum() { return minimum; } public void setMinimum(int minimum) { this.minimum = minimum; this.minimumSet = true; } public String[] getStatus() { return status; } public void setStatus(String[] status) { this.status = status; } // Check Whether The Entered Number Is Correct Or Incorrect. public String getResponse() { if (userNumber != null && userNumber.compareTo(randomInt) == 0) { setBtnValue(true); response = "Congratulations! You got it correct!"; } else if (userNumber == null) { response = "Sorry, " + userNumber + " is incorrect. Try a larger number."; } else { int enteredNum = userNumber.intValue(); System.out.println("Number Entered By User Is?= " + enteredNum); if (enteredNum > randomInt.intValue()) { response = "Sorry, " + userNumber + " is incorrect. Try a smaller number."; } else { response = "Sorry, " + userNumber +" is incorrect. Try a larger number."; } } return response; } public Integer getUserNumber() { return userNumber; } public void setUserNumber(Integer userNumber) { this.userNumber = userNumber; } public boolean isBtnValue() { return btnValue; } public void setBtnValue(boolean btnValue) { this.btnValue = btnValue; } public boolean isMaximumSet() { return maximumSet; } public void setMaximumSet(boolean maximumSet) { this.maximumSet = maximumSet; } public boolean isMinimumSet() { return minimumSet; } public void setMinimumSet(boolean minimumSet) { this.minimumSet = minimumSet; } public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException { if ((context == null) || (component == null)) { throw new NullPointerException(); } if (value != null) { try { int converted = intValue(value); if (maximumSet && (converted > maximum)) { if (minimumSet) { throw new ValidatorException(MessageFactory.getMessage (context, LongRangeValidator.NOT_IN_RANGE_MESSAGE_ID, new Object[] { new Integer(minimum), new Integer(maximum), MessageFactory.getLabel(context, component) })); } else { throw new ValidatorException(MessageFactory.getMessage(context, LongRangeValidator.MAXIMUM_MESSAGE_ID, new Object[] { new Integer(maximum), MessageFactory.getLabel(context, component) })); } } if (minimumSet && (converted < minimum)) { if (maximumSet) { throw new ValidatorException(MessageFactory.getMessage (context, LongRangeValidator.NOT_IN_RANGE_MESSAGE_ID, new Object[] { new Double(minimum), new Double(maximum), MessageFactory.getLabel(context, component) })); } else { throw new ValidatorException(MessageFactory.getMessage (context, LongRangeValidator.MINIMUM_MESSAGE_ID, new Object[] { new Integer(minimum), MessageFactory.getLabel(context, component) })); } } } catch (NumberFormatException e) { throw new ValidatorException(MessageFactory.getMessage (context, LongRangeValidator.TYPE_MESSAGE_ID, new Object[] { MessageFactory.getLabel(context, component) })); } } } private int intValue(Object attributeValue) throws NumberFormatException { if (attributeValue instanceof Number) { return ((Number) attributeValue).intValue(); } else { return Integer.parseInt(attributeValue.toString()); } } }
3.2.2 Implementation of Message Factory Class
The message factory class displays the required validation messages on the output screen in case the criteria of the entered number is not met by the application. Add the following code to it:
MessageFactory.java
package com.jsf.guessnumber.example; import javax.el.ValueExpression; import javax.faces.FactoryFinder; import javax.faces.application.Application; import javax.faces.application.ApplicationFactory; import javax.faces.application.FacesMessage; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import java.text.MessageFormat; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; public class MessageFactory extends Object { private MessageFactory() { } public static FacesMessage getMessage(String messageId, Object params[]) { Locale locale = null; if (FacesContext.getCurrentInstance() != null && FacesContext.getCurrentInstance().getViewRoot() != null) { locale = FacesContext.getCurrentInstance().getViewRoot().getLocale(); if (locale == null) { locale = Locale.getDefault(); } } else { locale = Locale.getDefault(); } return getMessage(locale, messageId, params); } public static FacesMessage getMessage(Locale locale, String messageId, Object params[]) { String summary = null, detail = null, bundleName = null; ResourceBundle bundle = null; // Check Whether User Has Provided A Bundle Or Not if (null != (bundleName = getApplication().getMessageBundle())) { if (null != (bundle = ResourceBundle.getBundle(bundleName, locale, getCurrentLoader(bundleName)))) { try { summary = bundle.getString(messageId); detail = bundle.getString(messageId + "_detail"); } catch (MissingResourceException missingResourceExceptionObj) { } } } // Couldn't Find Summary In User Bundle if (null == summary) { bundle = ResourceBundle.getBundle(FacesMessage.FACES_MESSAGES, locale, getCurrentLoader(bundleName)); if (null == bundle) { throw new NullPointerException(); } try { summary = bundle.getString(messageId); detail = bundle.getString(messageId + "_detail"); } catch (MissingResourceException missingResourceExceptionObj) { } } // If We Couldn't Find A Summary Anywhere, Return Null if (null == summary) { return null; } if (null == summary || null == bundle) { throw new NullPointerException(" summary " + summary + " bundle " + bundle); } return (new BindingFacesMessage(locale, summary, detail, params)); } // Methods From MessageFactory Class public static FacesMessage getMessage(FacesContext context, String messageId) { return getMessage(context, messageId, null); } public static FacesMessage getMessage(FacesContext context, String messageId, Object params[]) { if (context == null || messageId == null) { throw new NullPointerException(" context " + context + " messageId " +messageId); } Locale locale = null; // ViewRoot May Not Have Been Initialized At This Point if (context != null && context.getViewRoot() != null) { locale = context.getViewRoot().getLocale(); } else { locale = Locale.getDefault(); } if (null == locale) { throw new NullPointerException(" locale " + locale); } FacesMessage message = getMessage(locale, messageId, params); if (message != null) { return message; } locale = Locale.getDefault(); return getMessage(locale, messageId, params); } public static FacesMessage getMessage(FacesContext context, String messageId, Object param0) { return getMessage(context, messageId, new Object[] {param0}); } public static FacesMessage getMessage(FacesContext context, String messageId, Object param0, Object param1) { return getMessage(context, messageId, new Object[] {param0, param1}); } public static FacesMessage getMessage(FacesContext context, String messageId, Object param0, Object param1, Object param2) { return getMessage(context, messageId, new Object[] {param0, param1, param2}); } public static FacesMessage getMessage(FacesContext context, String messageId, Object param0, Object param1, Object param2, Object param3) { return getMessage(context, messageId, new Object[] {param0, param1, param2, param3}); } // Gets The "Label" Property From The Component public static Object getLabel(FacesContext context, UIComponent component) { Object o = component.getAttributes().get("label"); if (o == null) { o = component.getValueExpression("label"); } // Use The "clientId" If There Was No Label Specified. if (o == null) { o = component.getClientId(context); } return o; } public static Application getApplication() { FacesContext context = FacesContext.getCurrentInstance(); if (context != null) { return (FacesContext.getCurrentInstance().getApplication()); } ApplicationFactory afactory = (ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY); return (afactory.getApplication()); } public static ClassLoader getCurrentLoader(Object fallbackClass) { ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (loader == null) { loader = fallbackClass.getClass().getClassLoader(); } return loader; } private static class BindingFacesMessage extends FacesMessage { private Locale locale; private Object[] parameters; private Object[] resolvedParameters; private static final long serialVersionUID = 1L; BindingFacesMessage(Locale locale, String messageFormat, String detailMessageFormat, Object[] parameters) { super(messageFormat, detailMessageFormat); this.locale = locale; this.parameters = parameters; if (parameters != null) { resolvedParameters = new Object[parameters.length]; } } public String getSummary() { String pattern = super.getSummary(); resolveBindings(); return getFormattedString(pattern, resolvedParameters); } public String getDetail() { String pattern = super.getDetail(); resolveBindings(); return getFormattedString(pattern, resolvedParameters); } private void resolveBindings() { FacesContext context = null; if (parameters != null) { for (int i = 0; i < parameters.length; i++) { Object o = parameters[i]; if (o instanceof ValueExpression) { if (context == null) { context = FacesContext.getCurrentInstance(); } o = ((ValueExpression) o).getValue(context.getELContext()); } if (o == null) { o = ""; } resolvedParameters[i] = o; } } } private String getFormattedString(String msgtext, Object[] params) { String localizedStr = null; if (params == null || msgtext == null) { return msgtext; } StringBuffer b = new StringBuffer(100); MessageFormat mf = new MessageFormat(msgtext); if (locale != null) { mf.setLocale(locale); b.append(mf.format(params)); localizedStr = b.toString(); } return localizedStr; } } }
3.3 Registering Managed Bean & Navigation Rules
To implement the navigation rules and register our managed bean with the JSF application, we need to add the following entry to application’s faces-config.xml
file:
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?> <faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd" version="2.2"> <navigation-rule> <from-view-id>/greetings.xhtml</from-view-id> <navigation-case> <from-outcome>success</from-outcome> <to-view-id>/response.xhtml</to-view-id> </navigation-case> </navigation-rule> <navigation-rule> <from-view-id>/response.xhtml</from-view-id> <navigation-case> <from-outcome>success</from-outcome> <to-view-id>/greetings.xhtml</to-view-id> </navigation-case> </navigation-rule> <navigation-rule> <from-view-id>/response.xhtml</from-view-id> <navigation-case> <from-outcome>error</from-outcome> <to-view-id>/greetings.xhtml</to-view-id> </navigation-case> </navigation-rule> <managed-bean> <managed-bean-name>UserNumberBean</managed-bean-name> <managed-bean-class>com.jsf.guessnumber.example.UserNumberBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> <managed-property> <property-name>minimum</property-name> <property-class>int</property-class> <value>1</value> </managed-property> <managed-property> <property-name>maximum</property-name> <property-class>int</property-class> <value>10</value> </managed-property> </managed-bean> <managed-bean> <managed-bean-name>requestBean</managed-bean-name> <managed-bean-class>com.jsf.guessnumber.example.UserNumberBean</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> <managed-property> <property-name>minimum</property-name> <property-class>int</property-class> <value>12</value> </managed-property> <managed-property> <property-name>maximum</property-name> <property-class>int</property-class> <value>22</value> </managed-property> </managed-bean> </faces-config>
4. Project Deploy
Once we are ready with all the changes done, let us compile and deploy the application on tomcat7 server. In order to deploy the application on tomcat7, right-click on the project and navigate to Run as -> Run on Server
Tomcat will deploy the application in its webapps folder and shall start its execution to deploy the project so that we can go ahead and test it on the browser.
Open your favorite browser and hit the following URL. The output page will be displayed.
http://localhost:8085/JSFGuessnumber/faces/greetings.xhtml
Server name (localhost) and port (8085) may vary as per your tomcat configuration
5. Project Demo
Now, we are done with the application creation and its time to test out the application. Accessing the page: greetings.xhtml
, we will see guess number input page.
Enter a value between 0 and 10 and click the Submit button. If the entered number is correct, the success message will appear or else the error page.
Enter the number as ‘8‘ and click the Submit button. The success page with the congratulations message will be displayed.
Now, let’s enter the value greater than the pre-defined values and click the Submit button. The validation message will be displayed to the user.
Hope this helped :)
6. Conclusion
Through this example, we learned about the guess number implementation in jsf. We have also deployed it using the Tomcat7 application server.
7. Download the Eclipse Project
This was a JSF Guess Number example with Eclipse and Tomcat
You can download the full source code of this example here: JSF Guessnumber