In this recipe, we will explore an open source extension for JSF 1.0 and JSF 2.0 that enables creation of bookmarkable, pretty URLs. Its name is PrettyFaces and it includes some nice features, such as:
We developed this recipe with NetBeans 6.8, JSF 2.0, and GlassFish v3. The JSF 2.0 classes were obtained from the NetBeans JSF 2.0 bundled library. In addition, we have used PrettyFaces, which provides support for JSF 2.0. You can download this distribution from http://ocpsoft.com/prettyfaces/. The PrettyFaces libraries (including necessary dependencies) are in the book code bundle, under the /JSF_libs/PrettyFaces JSF 2.0
folder.
First copy the PrettyFaces libraries into your application /WEB-INF/lib
folder, and second, add into the web.xml
descriptor the PrettyFaces filter, as shown next:
… <filter> <filter-name>Pretty Filter</filter-name> <filter-class>com.ocpsoft.pretty.PrettyFilter</filter-class> </filter> <filter-mapping> <filter-name>Pretty Filter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>ERROR</dispatcher> </filter-mapping> …
Now, you are ready to use PrettyFaces into JSF applications.
PrettyFaces is able to work around URLs by reading a specific configuration file, named pretty-config.xml
, which is responsible for mapping URLs to Faces Views. Such a file is listed next (this file is stored in the /WEB-INF
folder):
<?xml version="1.0" encoding="UTF-8"?> <pretty-config xmlns="http://ocpsoft.com/prettyfaces-xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ocpsoft.com/prettyfaces-xsd http://ocpsoft.com/xml/ns/prettyfaces/pretty-1.0.xsd"> <url-mapping id="1"> <pattern> /say_hello_1 </pattern> <view-id>faces/hello1.xhtml</view-id> </url-mapping> <url-mapping id="2"> <pattern> /say_hello_2 </pattern> <query-param name="hello" decode="false"> #{bean.hello} </query-param> <view-id>faces/hello2.xhtml</view-id> </url-mapping> <url-mapping id="3"> <pattern> /say_hello_3 </pattern> <query-param name="hello" decode="false"> #{bean.hello} </query-param> <action>#{bean.upperHello}</action> <view-id>faces/hello2.xhtml</view-id> </url-mapping> <url-mapping id="4"> <pattern> /say_hello_4 </pattern> <view-id>#{bean.beanURL}</view-id> </url-mapping> </pretty-config>
As you can see a pretty-config.xml
file is made from a set of <url-mapping>
tags. Each tag maps a URL and is uniquely identified by the id
attribute. The body of <url-mapping>
can contain the following elements:
<pattern>/…/…/#{someBean.paramName}</pattern>
The <pattern>
tag is required and it specifies which URL will be matched. Any EL expressions #{someBean.paramName}
found within the pattern will be processed as value injection. This tag must appear only once per <url-mapping>
tag.
<query-param name="key">#{someBean.queryParamValue}</query-param>
The <query-param>
tag is optional and it defines a managed query parameter of the form http://my.site.com/url?key=somevalue
, where if the parameter exists, the value will be injected into the specified managed bean. The name
attribute is required and its value is a string representing the request value key. This tag also supports an optional attribute, named decode
, which can be true
(default) or false
and it indicates if this <query-param>
will/will not be URLDecoded
. This tag can appear zero or more times per <url-mapping>
tag.
<view-id>#{someBean.methodName}<view-id>
The <view-id>
tag specifies the JSF view ID displayed by this mapping. It can be provided by a bean method (in this case the method must return an object for which the toString
method will return the view Id) or by a String
value. This tag must appear only once per <url-mapping>
tag.
<action>#{someBean.methodName}</action>
The <action>
tag specifies an action method to be called after URL parameters have been parsed and assigned into beans. This tag also supports two attributes: the phaseId
attribute is optional and its value is a string indicating that this action should occur immediately after the specified phase (the default is after RESTORE_VIEW
phase, but it can be RESTORE_VIEW, APPLY_REQUEST_VALUES, PROCESS_VALIDATIONS, UPDATE_MODEL_VALUES, INVOKE_APPLICATION, RENDER_RESPONSE
, or ANY_PHASE
).
If the phase does not occur, neither will your action method. If ANY_PHASE
is specified, the action method will fire on EVERY phase.
The second optional attribute is onPostback
, which is a Boolean (default true
). Set it to false
if this action method should not occur on form postback.
This tag can appear zero or more times per <url-mapping>
tag.
Now, you can see all these elements in the previous pretty-config.xml
file. Next, we have developed a page to show how to call different other pages through Pretty. This page is named index.xhtml
and is listed next:
… <h:body> <!-- example 1 --> <h:outputLink value="say_hello_1"> <h:outputText value="HELLO (example_1)."/> </h:outputLink> <br/> <!-- example 2 --> <h:outputLink value="say_hello_2?hello=Adrian"> <h:outputText value="HELLO (example_2)"/> </h:outputLink> <br/> <!-- example 3 --> <h:outputLink value="say_hello_3?hello=Adrian"> <h:outputText value="HELLO (example_3)"/> </h:outputLink> <br/> <!-- example 4 --> <h:outputLink value="say_hello_4"> <h:outputText value="HELLO (example_4)"/> </h:outputLink> <br/> </h:body> …
And the bean used in this example is:
package beans; import javax.faces.bean.ManagedBean; import javax.faces.bean.SessionScoped; @ManagedBean @SessionScoped public class Bean { private String hello = ""; public Bean() { } public String getHello() { return hello; } public void setHello(String hello) { this.hello = hello; } public void upperHello() { this.hello = this.hello.toUpperCase(); } public String beanURL(){ return "/faces/hello3.xhtml"; } }
Now when you try to bookmark a URL managed by PrettyFaces you can see the "pretty" URL is used instead of the "ugly" one!
PrettyFaces makes use of its own filter to intercept URLs. Once it captures a URL it resolves it against the pretty-config.xml
file by accessing the corresponding <url-mapping>
tag. When we bookmark a page the <pattern>
body is bookmarked and the real URL is hidden.
PrettyFaces also provides other facilities such as:
The code bundled with this book contains a complete example of this recipe. The project can be opened with NetBeans 6.8 and it is named: Bookmarking_JSF_pages_with_PrettyFaces
.
More information about PrettyFaces is available at http://ocpsoft.com/prettyfaces/docs/.