Last updated February 01, 2009 21:26, by Jason Lee
== PrettyUrlPhaseListener - A Quick and Easy Way To Make Human-friendly URLs==
One of the most common requests from JSF users is "How do I use GET requests?" or "How do I make pretty URLs?" The answer usually boiled down to [http://blogs.steeplesoft.com/2006/08/17/jsf-phaselisteners-and-get-requests-redux implementing] a custom <code>PhaseListener</code> to handle the URI-to-managed-bean data transfer, but these solutions were almost always very specific to the application. Scales, however, now has a general use <code>PrettyUrlPhaseListener</code> to handle this painlessly.
Configuring the <code>PhaseListener</code> is quite simple. First, the <code>PhaseListener</code> must be registered with JSF:
<textarea name="code" class="xml"><nowiki><lifecycle>
<phase-listener>com.sun.mojarra.scales.util.PrettyUrlPhaseListener</phase-listener>
</lifecycle>
</nowiki></textarea>
Second, the <code>PhaseListener</code> must be configured in <code>web.xml</code>:
<textarea name="code" class="xml"><nowiki><context-param>
<param-name>com.sun.mojarra.scales.urlPatterns</param-name>
<param-value>
viewOrderList.jsp=/orderList/#{testBean.customernumber}/#{testBean.pageNumber}
viewOrder.jsp=/viewOrder/#{testBean.orderNumber}
</param-value>
</context-param>
</nowiki></textarea>
The value of this <code>context-param</code> lists a key/value pair of actual template files and URL patterns. '''NOTE: the extension used in the mapping key is the extension of the physical file on disk, NOT the servlet mapping used in the browser.''' When the <code>PhaseListener</code> processes each request, it uses a regular expression created from each URL pattern to determine if the current request URL is one which it should process. If it is, the value from the request URL that corresponds to each EL expression in the pattern is extracted, URL-decoded, then set on the <code>ValueExpression</code> created from the EL. Once all the values have been processed, JSF is instructed to display the actual template file, specified by the key in the pair.
One important thing to note, which may or may not be obvious, is that any security constraints specified in web.xml will still be applied, so using this feature will not allow you to circumvent those protections. Since the web container is still doing the processing, nothing changes with regard to those constraints. Additionally, while this is, strictly speaking, outside the scope of Mojarra Scales, any resources on the disk will hide any Servlet mappings, so take care when creating mappings.
One more step must be performed, however. If your pretty URLs do not match any existing <code>servlet-mapping</code> entries, then entries must be added until all of the URLs configured are covered. This will send the request to the <code>FacesServlet</code> so that the <code>PhaseListener</code> can process the request. The <code>servlet-mapping</code>s for the URLs above might look like this:
<textarea name="code" class="xml"><nowiki><servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/orderList/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/viewOrder/*</url-pattern>
</servlet-mapping>
</nowiki></textarea>
With these config changes in place, the user can now request [http://localhost:8080/MyApp/orderList/123456/15], and the <code>PhaseListener</code> will call <code>testBean.setCustomerNumber("123456")</code> and <code>testBean.setPageNumber("15")</code>, then cause JSF to display <code>viewOrderList.jsp</code>.
'''One final note:''' This <code>PhaseListener</code> will not affect any links rendered in the page. It was not designed to do so, though there are other more general solutions that will do so. The purpose of this component is simply to give a "pretty" entry point into an application. It is certainly possible that this will be expanded in the future to modify links created by, for example, <code>h:commandLink</code> to match the rules setup, but it does not do that now.





