Create Mobile Websites using Java Server Faces and PrimeFaces Mobile

January 8th, 2012 by

The more smartphones and tablets are sold the bigger the need for a mobile version of a modern website. PrimeFaces Mobile helps us developers here  and allows us to quickly create mobile websites that display well on an iPhone, Android, Palm, Blackberry, Windows Mobile and others.

In the following tutorial we’re going to create a web application that is using Java Server Faces 2.1, PrimeFaces 3.1 and PrimeFaces Mobile 1.0 and runs on a simple web container like Tomcat or Jetty.

 

Prerequisites

If you want to build the following examples you’ll need at least the following development environment ..

JSF Web Project, Adding PrimeFaces

First we need a web application project ..

  • Create a new Maven project using the webapp archetype

    Creating a new Maven Web Application Project

    Creating a new Maven Web Application Project

  • Add the PrimeFaces and Java Maven repositories and dependencies for Java Server Faces, PrimeFaces and PrimeFaces Mobile to your pom.xml – my final project descriptor looks like this
    <?xml version="1.0"?>
    <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.tutorial</groupId>
    <artifactId>primefaces-mobile-tutorial</artifactId>
    <packaging>war</packaging>
    <version>0.0.1</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <jsf.version>2.1.6</jsf.version>
    </properties>
    <repositories>
        <repository>
            <id>prime-repo</id>
            <name>PrimeFaces Maven Repository</name>
            <url>http://repository.primefaces.org</url>
            <layout>default</layout>
        </repository>
        <repository>
            <id>maven2-repository.dev.java.net</id>
            <name>Java.net Repository for Maven</name>
            <url>http://download.java.net/maven/2</url>
        </repository>
    </repositories>
    <build>
        <finalName>primefaces-mobile-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>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.primefaces</groupId>
            <artifactId>primefaces</artifactId>
            <version>3.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>${jsf.version}</version>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>${jsf.version}</version>
        </dependency>
        <dependency>
            <groupId>org.primefaces</groupId>
            <artifactId>mobile</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
    </project>

    joomla visitor

  • Since we’re going to run our web application in a simple servlet container and not a Java EE application server we need to add the JSF dispatcher to our web context. Add the following web.xml in src/main/webapp/WEB-INF
    <!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 PrimeFaces Mobile Tutorial</display-name>
        <context-param>
            <param-name>javax.faces.PROJECT_STAGE</param-name>
            <param-value>Development</param-value>
        </context-param>
        <context-param>
            <param-name>com.sun.faces.allowTextChildren</param-name>
            <param-value>true</param-value>
        </context-param>
        <servlet>
            <servlet-name>Faces Servlet</servlet-name>
            <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        </servlet>
        <servlet>
            <servlet-name>Resource Servlet</servlet-name>
            <servlet-class>org.primefaces.resource.ResourceServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>Resource Servlet</servlet-name>
            <url-pattern>/primefaces_resource/*</url-pattern>
        </servlet-mapping>
        <servlet-mapping>
            <servlet-name>Faces Servlet</servlet-name>
            <url-pattern>*.xhtml</url-pattern>
        </servlet-mapping>
        <welcome-file-list>
            <welcome-file>/demo.xhtml</welcome-file>
        </welcome-file-list>
    </web-app>
  • Finally switch to the mobile theme application wide by adding the following faces-config.xml in src/main/webapp/WEB-INF
    <?xml version="1.0" encoding="UTF-8"?>
    <faces-config 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" version="2.1" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_1.xsd">
    <name>hascode-demo</name>
    <application>
        <default-render-kit-id>PRIMEFACES_MOBILE</default-render-kit-id>
    </application>
    </faces-config>
  • If you want to temporarily enable the mobile version you are free to use the request parameter javax.faces.RenderKitId=PRIMEFACES_MOBILE or write a custom view handler by overriding the calculateRenderKitId API – I haven’t tried this one yet

A simple multi view page

Our first web site is a simple page that contains multiple views ..

  • Create a new file named demo.xhtml in src/main/webapp
    <f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:pm="http://primefaces.org/mobile" contentType="text/html">
    <pm:page title="hasCode.com PrimeFaces Mobile Tutorial - Simple Navigation">
        <pm:view id="viewChapter1">
            <pm:header title="First Chapter"/>
            <pm:content>
                <h:form>
                    <p:commandButton value="Go to second chapter" action="pm:viewChapter2"/>
                </h:form>
                				This is the first chapter
                			</pm:content>
            </pm:view>
            <pm:view id="viewChapter2">
                <pm:header title="Second Chapter"/>
                <pm:content>
                    <h:form>
                        <p:commandButton value="Go to first chapter" action="pm:viewChapter1"/>
                    </h:form>
                    				This is the second chapter
                </pm:content>
            </pm:view>
        </pm:page>
    </f:view>
  • The command buttons hold references to the views and allow you to switch between the views
  • Now it’s time to run the sample, simply run the following command in your IDE our console:
    mvn tomcat:run
  • That is what the sample app looks like on my HTC Desire Android smartphone / webkit browser

    A simple multiview page on a Android smartphone

    A simple multiview page on a Android smartphone

Using AJAX

In the following example, we’re going to add some AJAX to our mobile app. A managed bean is queried for the current time when the button is clicked …

  • Create a new file in src/main/webapp named ajax.xhtml
    <f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:pm="http://primefaces.org/mobile" contentType="text/html">
    <pm:page title="hasCode.com PrimeFaces Mobile Tutorial - AJAX">
        <pm:view id="main">
            <pm:header title="AJAX Sample"/>
            <pm:content>
                <h:form>
                    <p:commandButton value="Click" update="result"/>
                    <h:outputText id="result" value="#{demoBean.output}"/>
                </h:form>
            </pm:content>
        </pm:view>
    </pm:page>
    </f:view>
  • Add a directory src/main/java if it does not exist yet and add the managed bean DemoBean
    package com.hascode.tutorial;
     
    import java.util.Date;
     
    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.RequestScoped;
     
    @ManagedBean
    @RequestScoped
    public class DemoBean {
    	public String getOutput() {
    		return "It is " + new Date().toString();
    	}
    }
  • Run the example, but this time use mvn tomcat:run-war – the result looks like this

    Using AJAX and a ManagedBean

    Using AJAX and a ManagedBean

Mobile Components

PrimeFaces Mobile not only optimizes some of the existing UI components but also adds some sexy new ones .. the following page shows some of them ..

  • Create a new file named components.xhtml in src/main/webapp
    <f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:pm="http://primefaces.org/mobile" contentType="text/html">
    <pm:page title="hasCode.com PrimeFaces Mobile Tutorial - Mobile Components">
        <pm:view id="components">
            <pm:header title="Mobile Components"/>
            <pm:content>
                <h:form>
                    <h:outputText value="Button Group"/>
                    <pm:buttonGroup>
                        <p:commandButton value="Accept"/>
                        <p:commandButton value="Deny"/>
                    </pm:buttonGroup>
                    <p:separator/>
                    <h:outputText value="Input Range"/>
                    <pm:inputRange value="23"/>
                    <p:separator/>
                    <h:outputText value="Nav Bar"/>
                    <pm:content>
                        <pm:navBar>
                            <p:button value="Home" icon="home" href="#components" styleClass="ui-btn-active"/>
                            <p:button value="Settings" icon="gear" href="#components"/>
                            <p:button value="About" icon="info" href="#components"/>
                        </pm:navBar>
                    </pm:content>
                    <p:separator/>
                    <h:outputText value="Switch"/>
                    <pm:switch value="#{true}" onLabel="Accept" offLabel="deny"/>
                </h:form>
            </pm:content>
        </pm:view>
    </pm:page>
    </f:view>
  • Run mvn tomcat:run and enjoy the result – mine looks like this one

    PrimeFaces Mobile Components in Action

    PrimeFaces Mobile Components in Action

Using a Header-Footer-Layout

PrimeFaces Mobile gives us special components to declare header and footer regions for our mobile pages.

A header supports facets to define the left and right section of the header region.

  • I have defined such a layout in a file named segments.xhtml
    <f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:pm="http://primefaces.org/mobile" contentType="text/html">
    <pm:page title="hasCode.com PrimeFaces Mobile Tutorial - Mobile Components">
        <pm:view id="segments">
            <pm:header title="The header">
                <f:facet name="left">
                    <p:button value="Back" icon="back" href="#segments"/>
                </f:facet>
                <f:facet name="right">
                    <p:button value="Config" icon="gear" href="#config"/>
                </f:facet>
            </pm:header>
            <pm:content>
                <h:outputText value="This is our content.."/>
                <p:calendar mode="inline"/>
            </pm:content>
            <pm:footer>
                <pm:buttonGroup orientation="horizontal">
                    <p:button value="Like" href="#segments"/>
                    <p:button value="Share" href="#segments"/>
                </pm:buttonGroup>
            </pm:footer>
        </pm:view>
    </pm:page>
    </f:view>
  • The layout looks like this on my mobile device

    PrimeFaces Mobile Header-Footer Layout

    PrimeFaces Mobile Header-Footer Layout

Tutorial Sources

I have put the source from this tutorial on my Bitbucket repository – download it there or check it out using Mercurial:

hg clone https://bitbucket.org/hascode/primefaces-mobile-tutorial

Troubleshooting

  • javax.el.PropertyNotFoundException: if you are testing your app with the tomcat maven plugin – try running mvn tomcat:run-war instead of mvn tomcat:run

Resources

<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.tutorial</groupId>
<artifactId>primefaces-mobile-tutorial</artifactId>
<packaging>war</packaging>
<version>0.0.1</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jsf.version>2.1.6</jsf.version>
</properties>

<repositories>
<repository>
<id>prime-repo</id>
<name>PrimeFaces Maven Repository</name>
<url>http://repository.primefaces.org</url>
<layout>default</layout>
</repository>
<repository>
<id>maven2-repository.dev.java.net</id>
<name>Java.net Repository for Maven</name>
<url>http://download.java.net/maven/2</url>
</repository>
</repositories>

<build>
<finalName>primefaces-mobile-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>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>3.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>${jsf.version}</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>${jsf.version}</version>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>mobile</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>

</project>

Tags: , , , , , , , ,

8 Responses to “Create Mobile Websites using Java Server Faces and PrimeFaces Mobile”

  1. Rose Says:

    My application has both normal and mobile pages. I’ve used following code to determine which renderkit should be used. If there is a shorter/better way, I will be pleased to be know it.

    public String calculateRenderKitId(FacesContext facesContext) {
    Map headers = facesContext.getExternalContext().getRequestHeaderMap();
    for(String key : headers.keySet()){
    if (headers.get(key).contains(“mobile”)){
    return “PRIMEFACES_MOBILE”;
    }
    }
    HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest();
    String renderKit = (String)request.getAttribute(“javax.faces.RenderKitId”);
    if(“PRIMEFACES_MOBILE”.equals(renderKit)){
    return renderKit;
    }
    return wrapped.calculateRenderKitId(facesContext);
    }

  2. sai Says:

    Hi ,

    Thanks for the wonderfull work ..

    in my app i always get javax.el.PropertyNotFoundException: i did try running as mvn tomcat:run-war still i’m getiing the error .
    Please help me

  3. micha kops Says:

    hi, could you please post the complete stack trace? and did you modify parts of the application? :)

  4. sai Says:

    This is the trace

    javax.el.PropertyNotFoundException: /forms.xhtml @18,58 value=”#{personBean.firstname}”: Target Unreachable, identifier ‘personBean’ resolved to null
    at com.sun.faces.facelets.el.TagValueExpression.getType(TagValueExpression.java:97)
    at org.primefaces.util.ComponentUtils.getValueToRender(ComponentUtils.java:75)
    at org.primefaces.mobile.renderkit.InputTextRenderer.encodeInput(InputTextRenderer.java:107)
    at org.primefaces.mobile.renderkit.InputTextRenderer.encodeMarkup(InputTextRenderer.java:93)
    at org.primefaces.mobile.renderkit.InputTextRenderer.encodeEnd(InputTextRenderer.java:52)
    at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:879)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1650)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1646)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1646)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1646)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1646)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1646)
    at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:389)
    at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:127)
    at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:117)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:97)
    at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:135)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:309)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
    at java.lang.Thread.run(Thread.java:662)

    forms.xhtml

    PersonBean.java

    package com.test.Mobile;

    import java.io.Serializable;

    import javax.faces.application.FacesMessage;
    import javax.faces.bean.ManagedBean;
    import javax.faces.context.FacesContext;
    import javax.faces.event.ActionEvent;

    @ManagedBean(name=”personBean”)
    public class PersonBean implements Serializable{

    private String firstname;

    private String surname;

    public String getFirstname() {
    return firstname;
    }
    public void setFirstname(String firstname) {
    this.firstname = firstname;
    }

    public String getSurname() {
    return surname;
    }
    public void setSurname(String surname) {
    this.surname = surname;
    }

    public void savePerson(ActionEvent actionEvent) {

    FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(“Welcome ” + getFirstname() + ” ” + getSurname() + “!”));
    }
    }

  5. sai Says:

    i want to call a different xhtml file after a button click .

    For example : when i open my url it points to demo.xhtml , which has a button …

    Now i have a demo1.xhtml different file .. now after i click the button from the demo.xhtml it should redirect to demo1.xhtm ..

    How can i do this .. ??

    Please help me on this ..

  6. Chaitali Varughese Says:

    Hmm is anyone else having problems with the images on this
    blog loading? I’m trying to determine if its a problem on my end or if it’s
    the blog. Any suggestions would be greatly appreciated.

  7. micha kops Says:

    I’ve tested it in several browsers and could not detect any problem .. is the problem still visible for you and which picture does not load? Could you please provide some information about your system environment, browser etc? tia

  8. Andre Nunes Says:

    Fantastic

Search
Categories