Open Source Software Technical Articles

Want the Best of the Wazi Blogs Delivered Directly to your Inbox?

Subscribe to Wazi by Email

Your email:

Connect with Us!

Current Articles | RSS Feed RSS Feed

JSF tip: How to create bookmarkable pages

  
  
  

In a web browser, a bookmark allows users to get back to a given web page at any time. Users can share bookmarkable pages with other users by just sharing a page URL (with its required parameters). Bookmarkable pages are also friends to search engines because they can be indexed by search crawlers. Sometimes you might want to create a bookmarkable page programmatically, with Java for instance. Here's how to create bookmarkable pages in Java EE applications using the JavaServer Faces (JSF) framework.

To support bookmarkable pages, the JSF 2.0 specification introduced view parameters. JSF view parameters allow JSF pages to be RESTful, which means that such pages can be bookmarked by users in a browser. To demonstrate this, we'll create a page that will respond to parameters in the page URL.

In JSF, you create view parameters in the JSF Facelets pages using the <f:viewParam> tag under the <f:metadata> tag. The following code snippet shows how to define an <f:viewParam> tag inside a JSF page called vehicle.xhtml:

<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:ui="http://java.sun.com/jsf/facelets" 
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">

    <f:metadata>
        <f:viewParam name="model" value="#{vehicle.model}"/>
        <f:viewParam name="color" value="#{vehicle.color}"/>        
    </f:metadata>
    
    <h:head>
        <title>Vehicle Information</title>
    </h:head>
    
    <h:body>
        <p>
            Vehicle Model: #{vehicle.model} <br/>
            Vehicle Color: #{vehicle.color}
        </p>
    </h:body>
</html>

Here I've defined two view parameters, for model and color. As you can see from the <f:viewParam> tag, every view parameter has two main attributes: name, which specifies the name of the request parameter, and value, which represents a value expression that the value of the request parameter is bound to. In this code, the value of the request parameter whose name is model is bound to the #{vehicle.model} expression, and the request parameter whose name is color is bound to the #{vehicle.color} expression.

The following code listing shows the Vehicle managed bean, which defines the Vehicle attributes:

@ManagedBean
@RequestScoped
public class Vehicle {
    private String model;
    private String color;

    public String getModel() {
        return model;
    }
    public void setModel(String model) {
        this.model = model;
    }

    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
}

Once we have defined both the managed bean and the view parameters we can start testing and calling our RESTful page. So, for instance, calling the vehicle.xhtml page from the browser with the parameters

/vehicle.xhtml?model=Mercedes&color=black

produces the following content in the vehicle.xhtml page:

Vehicle Model: Mercedes
Vehicle Color: black

The <f:viewParam> tag causes a UIViewParameter instance to be attached as metadata for the current view. This is why it is put inside the <f:metadata> tag, which is used for declaring a metatag facet for the view. UIViewParameter extends UIInput, which means that any actions that one would normally take on a UIInput instance are valid for instances of this class.

This means that you can attach converters, validators, and value change listeners to the <f:viewParam> tag. Let's see how to validate the view parameters in vehicle.xhtml. First, modify the Vehicle managed bean by adding a new attribute to describe the vehicle number:

@ManagedBean
@RequestScoped
public class Vehicle {
    //...
    private Long number;

    //...
    public Long getNumber() {
        return number;
    }
    public void setNumber(Long number) {
        this.number = number;
    }
}

Next, move back to the XHTML page. To mandate that all of the Vehicle attributes are mandatory, as we do with other EditableValueHolder components (such as the inputText or selectOneMenu JSF components), we can set the required attribute to true. To validate that the Vehicle number attribute is a valid number within a specific numeric range, we can use <f:validateLongRange/> tag inside the <f:viewParam> tag. The next code snippet shows how to validate the view parameters in vehicle.xhtml:

<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:ui="http://java.sun.com/jsf/facelets" 
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">

    <f:metadata>
        <f:viewParam name="model" value="#{vehicle.model}"  
                               required="true" 
                                 requiredMessage="You need to specify vehicle model"/>

        <f:viewParam name="color" value="#{vehicle.color}" 
                                required="true" 
                                requiredMessage="You need to specify vehicle color"/>    
        
        <f:viewParam name="number" value="#{vehicle.number}" 
                                required="true" 
                                requiredMessage="You need to specify vehicle number">
            
            <f:validateLongRange minimum="1" maximum="9999999999"/>
        </f:viewParam>
    </f:metadata>
    
    <h:head>
        <title>Vehicle Information</title>
    </h:head>
    
    <h:body>
        <p>
            <h:outputText  value="Vehicle Model: #{vehicle.model}" rendered="#{vehicle.model ne null}" /> <br/>
            <h:outputText  value="Vehicle Color: #{vehicle.color}" rendered="#{vehicle.color ne null}"/> <br/>
            <h:outputText  value="Vehicle Number: #{vehicle.number}" rendered="#{vehicle.number ne null}"/>            
        </p>
        
        <h:messages  styleClass="errorMessage"/>
    </h:body>
</html>

Any validation errors that arise will be displayed in the <h:messages/> component. You would get a validation error when for example the URL does not specify model or color or number parameters, or when the number parameter represents an invalid number or an out-of-range number (the assumed number range is from 1 to 9,999,999,999).

To support browser bookmarkability and search engine crawlers, JSF 2.0 provides a <h:link> component, which renders an HTML anchor element. If you set the includeViewParams attribute of <h:link> component to true, you can generate the page view parameters as part of the generated URL of the <h:link> component. For example, suppose we added the <h:link> component to the vehicle.xhtml page in the previous code snippet as follows:

<h:link includeViewParams="true" value="Can be bookmarked"/>

This will generate a URL with the following pattern:

<a href="/contextPath/vehicle.xhtml?model=xxx&color=yyy&number=zzz">Can be bookmarked</a>

Buttons and input

JSF 2.0 added a <h:button> component. Like the <h:link> component, the <h:button> component has an includeViewParams attribute, but <h:button> generates an HTML button that depends on a JavaScript onclick action to view the target page, which means that it cannot be reached by crawlers, as they cannot execute JavaScript. If you want to allow crawlers to parse and index the target page you should instead style a <h:link> component to look like a button.

You can also use the includeViewParams parameter inside the JSF action attribute (as part of the JSF action outcome) of UICommand components. (Examples of UICommand components are the command button and the command link components.) The following code snippet shows a JSF input form in a new page, intro.xhtml, that allows a user to enter vehicle information that will be displayed on the vehicle.xhtml page.

<h:form>
            <h:panelGrid columns="3">
                <h:outputText value="Model:"></h:outputText>
                <h:inputText id="model" 
                             value="#{vehicle.model}" 
                             required="true"  
                             requiredMessage="You need to specify vehicle model">
                </h:inputText>
                <h:message for="model" styleClass="errorMessage"/>

                <h:outputText value="Color:"></h:outputText>
                <h:inputText id="color" 
                             value="#{vehicle.color}" 
                             required="true"  
                             requiredMessage="You need to specify vehicle color">
                </h:inputText>
                <h:message for="color" styleClass="errorMessage"/>
                
                <h:outputText value="Vehicle Number:"></h:outputText>
                <h:inputText id="number" 
                             value="#{vehicle.number}" 
                             required="true"  
                             requiredMessage="You need to specify vehicle number">
                    
                    <f:validateLongRange minimum="1" maximum="9999999999"/>
                </h:inputText>
                <h:message for="number" styleClass="errorMessage"/>                
            </h:panelGrid>
            
            <h:commandButton value="View vehicle details" 
                             action="vehicle?faces-redirect=true&amp;includeViewParams=true" />  
           
</h:form>

As you can see from this code, in order to allow the JSF command button to navigate to our RESTful page vehicle.xhtml in a RESTful way (that is, target page name and parameters appearing in the browser address bar), we need to add the following two parameters to set the outcome of the UICommand component:

  1. Setting faces-redirect to true allows the current page to be redirected to the target page.
  2. Setting includeViewParams to true inside the action outcome allows the UICommand component to include view parameters when performing navigation. Keep in mind that the included view parameters must be declared in the target JSF page, which is vehicle.xhtml in our example.

If we enter valid data in the intro.xhtml page and then click the "View vehicle details" button, the page will be redirected to vehicle.xhtml with the following parameters in the browser address bar:

contextPath/vehicle.xhtml?model=xxx&color=yyy&number=zzz

which will produce the following content in vehicle.xhtml page:

Vehicle Model: xxx
Vehicle Color: yyy
Vehicle Number: zzz

You may have noticed that in order to specify an ampersand (&) we used &amp; in the last code snippet. This is because JSF 2.x Facelets is an XML-based view technology, which means that the ampersand character is interpreted as the start of an XML entity, which means that in order to represent the actual ampersand character you have to use &amp; in the Facelets page.

With these techniques, you can create RESTful pages in JSF, validate the page view parameters, bind page view parameters with JSF managed beans using the JSF expression language, and create bookmarkable links in the pages using the JSF 2.0 <h:link> component. You can then navigate to JSF RESTful pages from other JSF pages using JSF UICommand components such as command buttons and command links.




This work is licensed under a Creative Commons Attribution 3.0 Unported License
Creative Commons License.

Comments

 
Software SEO website top 1st Google,Bing,Yahoo with Rank Builder Neo 2.0 Huge Bonus Over $1459 
Click here Download FREE NOW  
http://rankbuilder-reviews.com/rank-builder-seo-huge-bonus/
Posted @ Sunday, June 02, 2013 10:30 AM by Truong Demon
Nice description, but this has absolutely NOTHING do to with RESTful!!! In fact, from a RESTful perspective it's total nonsense! 
 
You would use a URL like vehicle.xhtml?model=Mercedes&color=black to search for a specific car in your stock and then return a list of cars that matches your search criteria. Each vehicle would then be addressed by url like this: vehicles/{id} Additional information (on a subpage) could be viewed like this: vehiclles/{id}/details 
 
Also, you would not receive an internal server error if you hit the back button or submit "illegal" parameters. If your (search) parameters would not be associated with a car, you would return 404 Not Found! 
 
Your example is 100% RPC and has absolutely nothing to do with REST! Please stop calling things RESTful if you can see a URL since this is just nonsense!
Posted @ Sunday, July 20, 2014 8:18 AM by Jason
Very nice coding and if we use this coding with the help of software then this work so easy.
Posted @ Saturday, October 04, 2014 3:51 AM by How Apple Pay Works with Passbook?
Post Comment
Name
 *
Email
 *
Website (optional)
Comment
 *

Allowed tags: <a> link, <b> bold, <i> italics