To access xhtml
pages inside WEB-INF/jsf
folder you may do next:
- Move
xhtml
pages folder from webapp root
to WEB-INF
- Introduce "Dispatcher View" pattern to the project
- Map "Front Controller" servlet to
url
based to pages from application
- Map Faces Servlet to "
.xhtml
"
- Inside "Dispatcher" forward request to page from "
WEB-INF/jsf/<name>.xhtml
"
- Override
jsf ViewHandler getActionUrl
to exclude "WEB-INF
" from generated action
url
(of form, link, button
)
For example, xhtml
pages are in webapp root folder "jsf
". All url
between pages are like jsf/<pageName>.xhtml
. So we do next:
move <webapp root>/jsf
to <webapp root>/WEB-INF/jsf
create FrontController servlet:
``
public class FrontController extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
process(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
process(req, resp);
}
private void process(HttpServletRequest request, HttpServletResponse response) {
Dispatcher dispatcher = Dispatcher.getInstance();
dispatcher.dispatch(request, response);
}
}
- map Front Controller servlet in
web.xml
to url
based for pages:
<servlet>
<servlet-name>Front Controller</servlet-name>
<servlet-class>controllers.FrontController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Front Controller</servlet-name>
<url-pattern>/jsf/*</url-pattern>
</servlet-mapping>
- map Faces Servlet in
web.xml
to .xhtml
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
- create Dispatcher which forwards
request
to correct xhtml
page:
``
public class Dispatcher {
public void dispatch(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pageBase = "/WEB-INF/jsf/";
String pagePath = null;
String errorPage = "/WEB-INF/jsf/error.xthml";
//here could be complicated logic to analyze if the page should be visible for security reasons, authorisation etc, business logic
//requested page could be taken from parsing requested URI
//pageName = findPageNameFromURI(request.getRequestURI());
pagePath = pageBase + pageName;
//if page should not be visible
pagePath = errorPage;
//forward to page inside WEB-INF/jsf
request.getServletContext().getRequestDispatcher(pagePath).
forward(request, response);
}
}
So if url for page was /myapp/jsf/home.xhtml
then Dispatcher will forward it to myapp/WEB-INF/jsf/home.xhtml
. And Faces Servlet will handle ".xhtml
" request. But if on a page are used jsf
components like h:form, h:link, h:button
etc which generate action
or url
then the url
will be really including "/WEB-INF
". So to exclude it we need next step.
Exclude "/WEB-INF
" from jsf
generated url
(for jsf form, link, button).
For that:
6.1 create subclass of jsf ViewHandler
and override getActionUrl
:
``
public class HiddenPageViewHandler extends ViewHandlerWrapper {
private static final String WEB_INF = "/WEB-INF";
private ViewHandler parent;
public HiddenPageViewHandler(ViewHandler parent) {
this.parent = parent;
}
@Override
public String getActionURL(FacesContext context, String viewId) {
String actionUrl = super.getActionURL(context, viewId);
if (actionUrl != null && actionUrl.contains(WEB_INF)) {
actionUrl = actionUrl.replace(WEB_INF, "");
}
return actionUrl;
}
@Override
public ViewHandler getWrapped() {
return parent;
}
}
6.2 configure jsf
to use the specified ViewHandler
. In faces-config.xml
add next:
<application>
...
<view-handler>
controllers.HiddenPageViewHandler
</view-handler>
</application>