JSF files inside WEB-INF directory, how do I access them?
I want to put my JSF 2.0 xhtml files under WEB-INF\jsf. How do I access them then? I know that anything inside WEB-INF isn't exposed to the outside, so I need a controller to redirect me to the corresponding JSP, right? (This is also the model 2 pat开发者_运维百科tern iirc).
Can I achieve this with a parameter inside web.xml/faces-config.xml? I think the FacesServlet is the controller of my webapp so it should serve this purpose?
And another question for understanding the Model 2 Pattern. Does every action have to go first to a servlet which then handles the next possible step? So a simple <a href="anotherPage.html" />
is forbidden in this pattern since it doesn't go to the controlling servlet?
I want to put my JSF 2.0 xhtml files under WEB-INF\jsf. How do I access them then?
You cannot. Files in /WEB-INF
folder are not directly accessible.
There are two options to workaround the problem of JSF source files being public accessible.
Map the
FacesServlet
on*.xhtml
instead of*.jsf
.Or, restrict direct access on
*.xhtml
by a<security-constraint>
inweb.xml
.<security-constraint> <display-name>Restrict direct access to XHTML files</display-name> <web-resource-collection> <web-resource-name>XHTML files</web-resource-name> <url-pattern>*.xhtml</url-pattern> </web-resource-collection> <auth-constraint /> </security-constraint>
See also:
- Which XHTML files do I need to put in /WEB-INF and which not?
- JSF Facelets: Sometimes I see the URL is .jsf and sometimes .xhtml. Why?
And another question for understanding the Model 2 Pattern. Does every action have to go first to a servlet which then handles the next possible step?
The FacesServlet
already does that. It's the controller. With JSF you already end up with a simple javabean as model and JSP/Facelets file as view. The FacesServlet
as being the controller has already taken all the nasty work of request parameter gathering, validation, conversion, model updating and navigation from your hands.
See also:
- What components are MVC in JSF MVC framework?
- JSF Controller, Service and DAO
So a simple
<a href="anotherPage.html" />
is forbidden in this pattern since it doesn't go to the controlling servlet?
No, it's perfectly fine. The controller will kick in whenever needed. If the resource doesn't need a controller (i.e. static resource), then you also don't need to let it pass through some controller.
In the future, please ask multiple questions in separate Stack Overflow questions.
To access xhtml
pages inside WEB-INF/jsf
folder you may do next:
- Move
xhtml
pages folder fromwebapp root
toWEB-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 generatedaction
url
(ofform, 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
tourl
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 correctxhtml
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
" fromjsf
generatedurl
(for jsf form, link, button). For that:6.1 create subclass of
jsf ViewHandler
and overridegetActionUrl
:
``
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>
精彩评论