Friendly paths to access dynamic JSF content
JSF 1 is HTTP POST based and, as such, makes it hard to generate friendly/RESTful URLs that are meaningful to the user. Try to serve something like a content management system (CMS) using JSF and you immediately run into problems. However if you write a custom ViewHandler, you can translate the virtual url, such as
All cases where the ViewHandler references the viewId (which is just the full filename of the page its executing/referencing), need to be mapped correctly so that JSF opens the page that exists, while the user sees the content specified by the URL that maps to a database for example.
Below is the view handler that wraps around the Facelets view handler to provide the described functionality.:
/page/about/contactUs, into a physical page (view), e.g. /dynamicContent.xhtml.All cases where the ViewHandler references the viewId (which is just the full filename of the page its executing/referencing), need to be mapped correctly so that JSF opens the page that exists, while the user sees the content specified by the URL that maps to a database for example.
Below is the view handler that wraps around the Facelets view handler to provide the described functionality.:
/**
* View Handler that wraps around first Facelets then the default handler, to translate the virtual address of the content page to the physical xhtml
* page that will serve it.
*
* @author Chris Watts
*/
public class ParameterisedPathViewHandler extends ViewHandlerWrapper
{
/** servletmapping for physical page */
private static final String PAGE_URL = "/dynamicPage.jsf";
/** physical page file name */
private static final String PAGE_FILE_NAME = "/dynamicContent.xhtml";
/** servletmapping prefix for served pages */
private static final String PAGE_PREFIX = "/page";
/** richfaces exclusion */
private static final String A4J_PREFIX = "/page/a4j/";
private ViewHandler wrappedHandler;
/**
* Constructor taking the previous view handler in the chain (called by JSF implementation).
* @param defaultHandler previous handler in the chain
*/
public ParameterisedPathViewHandler(ViewHandler defaultHandler)
{
//put facelets in the chain.
//If using richfaces the context param org.ajax4jsf.VIEW_HANDLERS
//should be set to: "com.sun.facelets.FaceletViewHandler,net.devgrok.jsf.ParameterisedPathViewHandler"
//and the below code commented out.
FaceletViewHandler faceletHandler = new FaceletViewHandler(defaultHandler);
this.wrappedHandler = faceletHandler;
// this.wrappedHandler = defaultHandler; // to use richfaces chaining
}
@Override
protected ViewHandler getWrapped()
{
return wrappedHandler;
}
@Override
public UIViewRoot createView(FacesContext context, String viewId)
{
return wrappedHandler.createView(context, resolveUrl(context, viewId));
}
private boolean isContentPage(FacesContext context, String viewId)
{
String servlet = context.getExternalContext().getRequestServletPath();
if (servlet == null || servlet.length() == 0)
return false;
if (servlet.startsWith(A4J_PREFIX))
return false;
return servlet.startsWith(PAGE_PREFIX);
}
//Determine what physical page will serve the request.
private String resolveUrl(FacesContext context, String viewId)
{
if (!isContentPage(context, viewId))
// not content page so use original viewId
return viewId;
//store pageId in request map for later retrieval
Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
String pageId;
//pageId is the document to be served
pageId = viewId.substring(1);
requestMap.put("pageId", pageId);
return PAGE_FILE_NAME;
}
//If is one of the dynamic content pages then actual url of xhtml file to handle it.
@Override
public String getActionURL(FacesContext context, String viewId)
{
if (isContentPage(context, viewId))
return getDynamicPageUrl(context, viewId);
else
return wrappedHandler.getActionURL(context, viewId);
}
private String getDynamicPageUrl(FacesContext context, String viewId)
{
return context.getExternalContext().getRequestContextPath() + PAGE_URL;
}
@Override
public UIViewRoot restoreView(FacesContext context, String viewId)
{
return wrappedHandler.restoreView(context, resolveUrl(context, viewId));
}
}
Comments
Post a Comment