Java Server Faces/JSF 2 Tutorial – Step 1: Project setup, Maven and the first Facelet

June 5th, 2010 by

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.

Steps

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:
  17. 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>
  18. 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:
  19. 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)
  20. 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)
  21. 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);
    		}
    	}
  22. 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)
  23. 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/>
  24. 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 field
  25. 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>
  26. 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>
  27. If you enter valid data to all form fields you should be redirected to the success page
  28. Compile and deploy – run the following command and deploy the war to your application server
    mvn package
  29. Alternatively you might test your application in an embedded app server using the Maven Tomcat Plugin
    mvn package tomcat:run-war

Tutorial Download

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

hg clone http://bitbucket.org/hascode/hascode-tutorials

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

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


Resources

<!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>Archetype Created Web Application</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>*.jsf</url-pattern>
</servlet-mapping>

</web-app>

Tags: , , , , , , , , , , , , , , ,

6 Responses to “Java Server Faces/JSF 2 Tutorial – Step 1: Project setup, Maven and the first Facelet”

  1. Pablo Says:

    I solved the javax.el.PropertyNotFoundException with your solution, thanks

  2. shami Says:

    Please help me i ‘ve got problem in your example
    for exmple:

    labels are dont rendering only field box

  3. micha kops Says:

    it should work – how do you run the example? mvn tomcat:run-war ? oder do you package and deploy it on a web container? is there no error displayed in the console/web container logs?

  4. shami Says:

    Thanks for your example it’s help me a lot. It works

  5. Valéria Martins Says:

    Hello! Thanks for your help, but where do I find the Step 2 with Hibernate? Thanks.

  6. micha kops Says:

    Hi Valéria,

    I’m sorry to say that there is no Step 2 tutorial as I decided to write a full article with a sample blog application instead, please feel free to have a look at my article “Creating a sample Java EE 6 Blog Application with JPA, EJB, CDI, JSF and Primefaces on GlassFish“.

    Cheers,

    Micha

Leave a Reply

Please leave these two fields as-is:

Protected by Invisible Defender. Showed 403 to 81,008 bad guys.

Search
Categories