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