Latest Entries »

Monday, March 12, 2012

JavaServer Faces website navigation map with Primefaces


Introduction


Hello. In this article I will show you how to create a simple website navigation map like those in asp.net (web.sitemap) which contains reference to your pages. Composite Component of navigation path will be localized on many languages and will be build on PrimeFaces BreadCrumb component. Final result will look like this:

Using PrimeFaces

Configuring PrimeFaces is as easy as riding a bike so I ommit this topic.
I'll create JSF 2.0 Composite Component with BreadCrumb inside and point it's dynamic model to ManagedBean which will use our newly created CC component.

<?xml version='1.0' encoding='UTF-8' ?>
<!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:cc="http://java.sun.com/jsf/composite"
      xmlns:p="http://primefaces.org/ui">

  <!-- INTERFACE -->
  <cc:interface>
      <cc:attribute name="model" required="true" />
      <cc:attribute name="styleClass" required="false" />
      <cc:attribute name="style" required="false" />
  </cc:interface>

  <!-- IMPLEMENTATION -->
  <cc:implementation>
      <p:breadCrumb styleClass="#{cc.attrs.styleClass}" style="#{cc.attrs.style}" model="#{cc.attrs.model}">
        </p:breadCrumb>
  </cc:implementation>
</html>

Implementing code for receive pages in project


Now it's time for ManagedBean holding all data. Most significant piece of code from class below is localized in public getWebsites(). Firstly I load localized messages and load filenames from root path "/". Next step is checking whether filename exists in localized messages:

package com.blogspot.rpiesnikowski.root;

import java.io.File;
import java.lang.String;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Locale;
import java.util.ResourceBundle;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;
import javax.faces.component.UIForm;
import javax.faces.component.UIViewRoot;
import javax.faces.component.html.HtmlOutputText;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.io.FileUtils;
import org.primefaces.component.menuitem.MenuItem;
import org.primefaces.model.DefaultMenuModel;
import org.primefaces.model.MenuModel;

/**
 *
 * @author rpiesnikowski
 */
@Named(value = "template")
@RequestScoped
public class TemplateBean {
    private MenuModel websites;

    /**
     * Method for dynamically create navigation for all pages inside
     * root directory.
     * @return
     */
    public MenuModel getWebsites() {
  // Receiving i18n bundle messages 
        String bundleName = "locales.messages";
        String Name = "";
        Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
        ResourceBundle bundle = ResourceBundle.getBundle(bundleName, locale);
        websites = new DefaultMenuModel();
        HttpServletRequest req =  (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
        // Getting all files for path and then using Apache Commons 
  String rootPath = req.getServletContext().getRealPath("/");
        Collection<File> files = FileUtils.listFiles(new File(rootPath),new String[]{"xhtml"}, false);
        websites.addMenuItem(createMenuItem("#", "#"));
        for (File f: files){
            Name = f.getName().replace(".xhtml", "");
   // Checking if localized messages has key 
            if(bundle.containsKey(Name))
                websites.addMenuItem(createMenuItem(bundle.getString(Name), f.getName().replace(".xhtml", ".jsf")));
        }
        return websites;
    }

    public void setWebsites(MenuModel websites) {
        this.websites = websites;
    }

    protected MenuItem createMenuItem(String Name, String Url) {
        MenuItem item = new MenuItem();
        item.setValue(Name);
        item.setUrl(Url);
        return item;
    }
 
    public TemplateBean() {
    }
}

Now it's time to use component somewhere in Facelets Template:

<sc:NavigationPath model="${template.websites}" style="width: 99%;" />

Localizing NavigationPath Last but not least thing is to add localization files and modify your faces-config.xml. Put this between application node:

<application>
 <locale-config>
  <default-locale>en-US</default-locale>
  <supported-locale>pl</supported-locale>
  <supported-locale>fr</supported-locale>
  <supported-locale>es</supported-locale>
 </locale-config>
 <resource-bundle>
  <base-name>locales.messages</base-name>
  <var>msgs</var>
 </resource-bundle>
</application>

And it's time for localized message:

Calendar=Calendard a'la France
AjaxEngine=AjaxEngine a'la France
index=Index a'la France
DummyPage=DummyPage a'la France
BreadCrumb=BreadCrumb a'a France
asdf=asdf a'la France
ClientIdExample=ClientId a'la France

Additional tip

I've found really nice trick when I put my all empty localized messages into project. Try right click over messages.properties and choose Open. You this nice GUI form for filling localized strings.

0 comments:

Post a Comment