In this short tutorial we are going to build a Java Server Faces Web-Application using JSF2.0, Facelets, Maven and Hibernate as ORM Mapper.

The goals for this first step are: Setting up the project structure using Maven, defining a frame template/decorator and a registration facelet, creating a managed bean and mapping it’s values to the facelet, adding some basic validation, displaying validation errors and finally adding a navigation structure.

In step2 of this tutorial we are going to add persistence using Hibernate, add some security, create a custom UI component and add some AJAX.

The Mojarra JSF implementation is used for this tutorial – perhaps I’m going to post more about the MyFaces implementation in another tutorial.

Creating the Application

There we go ..

  1. Create a Maven webapp project structure using the following command or using your IDE e.g. Eclipse and the Maven Plugin:

    mvn archetype:create -DgroupId=com.hascode.jsf -DartifactId=registration-demo -DarchetypeArtifactId=maven-archetype-webapp
  2. Alternatively use this command and chose maven-archetype-webapp

    mvn archetype:generate
  3. The pom.xml should look similiar to this:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.hascode.jsf</groupId>
      <artifactId>jsf2-tutorial</artifactId>
      <packaging>war</packaging>
      <version>0.1</version>
      <name>hasCode.com -Java Server Faces 2 Maven Tutorial</name>
      <url>http://maven.apache.org</url>
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
      <build>
        <finalName>jsf2-tutorial</finalName>
      </build>
    </project>
  4. Add the Sun/Oracle Maven and the JBoss repositories to the pom.xml we are going to need it for the JSF API and implementation

    <repositories>
     <repository>
      <id>maven2-repository.dev.java.net</id>
      <name>Java.net Repository for Maven</name>
      <url>http://download.java.net/maven/2</url>
     </repository>
     <repository>
      <id>JBoss repository</id>
      <url>http://repository.jboss.com/maven2/</url>
     </repository>
    </repositories>
  5. Add some dependencies to your pom.xml please note that there is a difference whether the app is deployed to a Java EE Application Server or a simple Servlet Container, so choose the corresponding dependencies for your pom.xml For a JEE AppServer:

    <dependencies>
        <dependency>
            <groupId>javax.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    For a Servlet Container:

    <dependencies>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>2.0.2</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>2.0.2</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
  6. Finally, your pom.xml could look like this:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    	<groupId>com.hascode.jsf</groupId>
    	<artifactId>jsf2-tutorial</artifactId>
    	<packaging>war</packaging>
    	<version>0.0.1-SNAPSHOT</version>
    	<name>hasCode.com -Java Server Faces 2 Maven Tutorial</name>
    	<url>http://maven.apache.org</url>
    	<repositories>
    		<repository>
    			<id>maven2-repository.dev.java.net</id>
    			<name>Java.net Repository for Maven</name>
    			<url>http://download.java.net/maven/2</url>
    		</repository>
    		<repository>
    			<id>JBoss repository</id>
    			<url>http://repository.jboss.com/maven2/</url>
    		</repository>
    	</repositories>
    	<dependencies>
    		<dependency>
    			<groupId>junit</groupId>
    			<artifactId>junit</artifactId>
    			<version>3.8.1</version>
    			<scope>test</scope>
    		</dependency>
    		<dependency>
    			<groupId>com.sun.faces</groupId>
    			<artifactId>jsf-api</artifactId>
    			<version>2.0.2</version>
    			<scope>compile</scope>
    		</dependency>
    		<dependency>
    			<groupId>com.sun.faces</groupId>
    			<artifactId>jsf-impl</artifactId>
    			<version>2.0.2</version>
    			<scope>compile</scope>
    		</dependency>
    		<dependency>
    			<groupId>jstl</groupId>
    			<artifactId>jstl</artifactId>
    			<version>1.2</version>
    		</dependency>
    	</dependencies>
    	<build>
    		<finalName>jsf2-tutorial</finalName>
    		<plugins>
    			<plugin>
    				<groupId>org.apache.maven.plugins</groupId>
    				<artifactId>maven-compiler-plugin</artifactId>
    				<version>2.0.2</version>
    				<configuration>
    					<source>1.6</source>
    					<target>1.6</target>
    				</configuration>
    			</plugin>
    		</plugins>
    	</build>
    </project>
  7. Optional: Create a project file for Eclipse IDE with WebToolkit integration using the following command

    mvn eclipse:eclipse -Dwtpversion=2.0
  8. Get your IDE running and import the project if you wish to

  9. Delete the index.jsp generated____by maven – we won’t need it..

  10. Now you need to register the FacesServlet to a defined URL pattern and set the project stage to development. The URL Pattern *.xhtml is mapped to the JSF Servlet – so everything with a .xhtml suffix goes to the FacesServlet. Create a file named web.xml in src/main/webapp/WEB-INF/ and add the following declaration:

    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    <web-app>
        <display-name>hasCode.com - Java Server Faces 2 Tutorial</display-name>
        <context-param>
            <param-name>javax.faces.PROJECT_STAGE</param-name>
            <param-value>Development</param-value>
        </context-param>
        <servlet>
            <servlet-name>Faces Servlet</servlet-name>
            <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>Faces Servlet</servlet-name>
            <url-pattern>*.xhtml</url-pattern>
        </servlet-mapping>
    </web-app>
  11. In the next step we want to define the default-page – for now the registration form will be shown per default – so add the following declaration to the <web-app> Element in the web.xml:

    <welcome-file-list>
    	<welcome-file>/registration.xhtml</welcome-file>
    </welcome-file-list>
  12. Create the directory src/main/java if it doesn’t exist – if you use the eclipse maven plugin you might want to choose Update Project Configuration after that or add the directory as a source directory

  13. Now create a new package – something like com.hascode.tutorial.jsf2_tutorial.bean

  14. We need a managed bean for the registration form so create a class named UserBean in the package com.hascode.tutorial.jsf2_tutorial.bean, add some members, getter and setter

    package com.hascode.tutorial.jsf2_tutorial.bean;
    
    import java.util.Date;
    
    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.SessionScoped;
    
    @ManagedBean
    @SessionScoped
    public class UserBean {
    	protected String	nickname;
    	protected String	email;
    	protected Date		birthday;
    
    	/**
    	 * @return the nickname
    	 */
    	public String getNickname() {
    		return nickname;
    	}
    	/**
    	 * @param nickname
    	 *            the nickname to set
    	 */
    	public void setNickname(String nickname) {
    		this.nickname = nickname;
    	}
    	/**
    	 * @return the email
    	 */
    	public String getEmail() {
    		return email;
    	}
    	/**
    	 * @param email
    	 *            the email to set
    	 */
    	public void setEmail(String email) {
    		this.email = email;
    	}
    	/**
    	 * @return the birthday
    	 */
    	public Date getBirthday() {
    		return birthday;
    	}
    	/**
    	 * @param birthday
    	 *            the birthday to set
    	 */
    	public void setBirthday(Date birthday) {
    		this.birthday = birthday;
    	}
    
    }
  15. Create a frame template called decorator.xhtml in src/main/webapps - define two sections the subtemplates may overwrite – the body and title + heading

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:ui="http://java.sun.com/jsf/facelets">
        <h:head>
            <title><ui:insert name="title">hasCode.com - Default Title</ui:insert></title>
        </h:head>
        <h:body>
        	<h1><ui:insert name="title">hasCode.com - Default Heading</ui:insert></h1>
           	<ui:insert name="body">Default Body</ui:insert>
        </h:body>
    </html>
  16. Afterwards we create a registration facelet in src/main/webapp named registration.xhtml – there are some really nice tools from the JBoss Eclipse Tools helping you edit the Facelets (Component: RichFaces) – screenshot:jboss facelet editor 150x150

  17. Afterwards we create a registration facelet in src/main/webapp named registration.xhtml – there are some really nice tools from the JBoss Eclipse Tools helping you edit the Facelets (Component: RichFaces) – screenshot:jboss facelet editor 150x150

  18. Insert markup into the registration facelet

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:ui="http://java.sun.com/jsf/facelets">
    	<ui:composition template="/decorator.xhtml">
    		<ui:define name="title">hasCode.com - Java Server Faces Tutorial - Registration</ui:define>
    		<ui:define name="body">
    			<h:form>
    	       		<div id="registration">
    	       			<label>Nickname</label>
    	       			<h:inputText label="Nickname" id="nname" value=""/>
    	       			<br/>
    	       			<label>E-Mail</label>
    	       			<h:inputText label="E-Mail" id="email" value=""/>
    	       			<br/>
    	       			<label>Birthday</label>
    	       			<h:inputText label="Birthday" id="birthday" value=""/> (yyyy-mm-dd)
    	       			<br/>
    	       			<h:commandButton action="success" value="Register" />
    	       		</div>
           		</h:form>
    		</ui:define>
    	</ui:composition>
    </html>
  19. If you run the application now – e.g. mvn package tomcat:run and open it in your browser (e.g. http://localhost:8080/jsf2-tutorial) you should see the decorated registration facelet – mine looks like this:registration facelet 300x54

  20. If you run the application now – e.g. mvn package tomcat:run and open it in your browser (e.g. http://localhost:8080/jsf2-tutorial) you should see the decorated registration facelet – mine looks like this:registration facelet 300x54

  21. Map fields to bean by referencing the field value attributes to the managed UserBean

    <h:inputText label="Nickname" id="nname" value="#{userBean.nickname}"/>
    <h:inputText label="E-Mail" id="email" value="#{userBean.email}"/>
    <h:inputText label="Birthday" id="birthday" value="#{userBean.birthday}"/> (yyyy-mm-dd)
  22. Add some basic validation – change the fields to

    <h:inputText label="Nickname" id="nname" value="#{userBean.nickname}" required="true"/>
    <h:inputText label="E-Mail" id="email" value="#{userBean.email}" required="true" validator="#{userBean.validateEmail}"/>
    <h:inputText label="Birthday" id="birthday" value="#{userBean.birthday}" required="true"/> (yyyy-mm-dd)
  23. Add the validation method to the UserBean

    public void validateEmail(FacesContext context, UIComponent validated,
            Object value) {
        // simple stupid validation
        String mail = (String) value;
        if (!mail.matches(".+\\@.+\\..+")) {
            FacesMessage msg = new FacesMessage("This is not an e-mail!");
            throw new ValidatorException(msg);
        }
    }
  24. Adjust the time format

    <h:inputText label="Birthday" id="birthday" value="#{userBean.birthday}" required="true">
    	<f:convertDateTime pattern="yyy-MM-dd"/>
    </h:inputText> (yyyy-mm-dd)
  25. Add the display of errors to the registration form, the for attribute of the message element references to the id attribute of the form element. We are going to display each error after each corresponding form element and to display a list of all errors at the end of the document

    <h:inputText label="Nickname" id="nname" value="#{userBean.nickname}" required="true"/>
    <h:message for="nname"/>
    <h:inputText label="E-Mail" id="email" value="#{userBean.email}" required="true" validator="#{userBean.validateEmail}"/>
    <h:message for="email"/>
    <h:inputText label="Birthday" id="birthday" value="#{userBean.birthday}" required="true">
    	<f:convertDateTime pattern="yyy-MM-dd"/>
    </h:inputText> (yyyy-mm-dd)
    <h:message for="birthday"/><hr/>
    <h:messages/>
  26. If you run the app now (eg. mvn package tomcat:run-war) and try to submit the empty form you’re going to see some error messages – if you try to enter an invalid date you will notice the specialized error message for this fieldvalidation fail empty fields 300x88

  27. If you run the app now (eg. mvn package tomcat:run-war) and try to submit the empty form you’re going to see some error messages – if you try to enter an invalid date you will notice the specialized error message for this fieldvalidation invalid date 300x93

  28. Now let’s add some control flow/navigation to the app – if the registration action is successful and no validation errors occurred we want to redirect the user to a new view – first we add a new facelet: registration_success.xhtml in src/main/webapp

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:ui="http://java.sun.com/jsf/facelets">
    	<ui:composition template="/decorator.xhtml">
    		<ui:define name="title">hasCode.com - Java Server Faces Tutorial - Registration Successful</ui:define>
    		<ui:define name="body">
    			Registration was successful
    		</ui:define>
    	</ui:composition>
    </html>
  29. We also add the navigation structure to the faces-config.xml in src/main/webapp/WEB-INF – create if the config does not exist yet

    <?xml version="1.0" encoding="UTF-8"?>
    <faces-config version="2.0" xmlns="http://java.sun.com/xml/ns/javaee"
     xmlns:xi="http://www.w3.org/2001/XInclude"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
     <name>app</name>
     <navigation-rule>
      <from-view-id>/registration.xhtml</from-view-id>
      <navigation-case>
       <from-outcome>success</from-outcome>
       <to-view-id>/registration_success.xhtml</to-view-id>
      </navigation-case>
     </navigation-rule>
    </faces-config>
  30. If you enter valid data to all form fields you should be redirected to the success pageregistration success 300x42

  31. Compile and deploy – run the following command and deploy the war to your application server

    mvn package
  32. Alternatively you might test your application in an embedded app server using the Maven Tomcat Plugin

    mvn package tomcat:run-war

Tutorial Sources

I have put the sources on GitHub.org – you’re able to check them out if you have Mercurial installed

git clone http://github.com/hascode/hascode-tutorials.git

Additional Tools

The JBoss Tools for Eclipse offer some nice features for your work with Java Server Faces – for more information – take a look at the installation page for the JBoss Tools. Be sure to install the RichFaces feature – it adds some improvements for the configuration of your faces-config.xml e.g. an editor for the navigation  between the views

jboss navigation editor 300x68

An alternative using Java EE 6

If you’d like to see how a JSF web app is implemented using the Java EE 6 stack and an application server, take a look at my article: “Creating a sample Java EE 6 Blog Application with JPA, EJB, CDI, JSF and Primefaces on GlassFish”

Troubleshooting

  • Java compiler level does not match the version of the installed Java project facet.” – If this error occurs in Eclipse: Go Project Properties > Project Faces > Java and select Java 6 (or 5). Sometimes if you imported the project via Import > Existing Project and then enable dependency management using the Eclipse Maven Plugin – the plugin resets the Java Compiler settings – go Project Properties > Java Compiler and set the compile settings back to Java 6 (or 5).

  • Maven tries to build with an oooold target or source JVM and complains about missing annotation support, specify the target VM in the pom.xml

    <plugins>
    	<plugin>
    		<groupId>org.apache.maven.plugins</groupId>
    		<artifactId>maven-compiler-plugin</artifactId>
    		<version>2.0.2</version>
    		<configuration>
    			<source>1.6</source>
    			<target>1.6</target>
    		</configuration>
    	</plugin>
    </plugins>
  • java.lang.ClassNotFoundException: javax.servlet.jsp.jstl.core.. You app server is missing the JSTL libs – add the dependency to your pom.xml

    <dependency>
    	<groupId>javax.servlet</groupId>
    	<artifactId>jstl</artifactId>
    	<version>1.2</version>
    	<scope>compile</scope>
    </dependency>
  • java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/core/Config – The dependency to the Standard Tag Library is missing – insert this into your pom.xml

     <dependency>
        <groupId>jstl</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
  • StackOverFlowError / Infinite Loop – make sure that you map the FacesServlet via  <url-pattern>*.xhtml</url-pattern> and also name the Facelet with *.xhtml. If found some information regarding this problem thanks to BalusC on stackoverflow.com.

  • javax.el.PropertyNotFoundException: Target Unreachable, identifier ‘userBean’ resolved to null - if you are testing your app with the tomcat maven plugin – be sure to run mvn tomcat:run-war instead of mvn tomcat:run

Article Updates

  • 2015-03-03: Table of contents added.