JSF files inside WEB-INF directory, how do I access them?
Asked Answered
B

2

12

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 pattern 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?

Bawbee answered 18/8, 2010 at 12:50 Comment(0)
B
21

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.

  1. Map the FacesServlet on *.xhtml instead of *.jsf.

  2. Or, restrict direct access on *.xhtml by a <security-constraint> in web.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:


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:


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.

Burley answered 18/8, 2010 at 13:20 Comment(1)
Thanks for the reply. I already mapped only *.xhtml files (option 1). I've read that in some frameworks (Struts, Spring Webflow,..) it's possible/the preferred way to put the jsp files (=dynamic content) under WEB-INF and the controller accesses them there and displays them to the user. I just wanted to ask if the same is possible with JSF. But if I see it correctly no one can view the source of the xhtml files through the browswer since they are always rendered through the controller, right?Bawbee
K
1

To access xhtml pages inside WEB-INF/jsf folder you may do next:

  1. Move xhtml pages folder from webapp root to WEB-INF
  2. Introduce "Dispatcher View" pattern to the project
  3. Map "Front Controller" servlet to url based to pages from application
  4. Map Faces Servlet to ".xhtml"
  5. Inside "Dispatcher" forward request to page from "WEB-INF/jsf/<name>.xhtml"
  6. 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:

  1. move <webapp root>/jsf to <webapp root>/WEB-INF/jsf

  2. 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);
        }
}
  1. 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>
  1. 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>
  1. 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.

  1. 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>
Kunkel answered 6/5, 2015 at 12:38 Comment(5)
Bad advice. This introduces a security hole: exposing all WEB-INF content directly into public.Burley
it was for simplicity in dispatcher just to add WEB-INF before requested url. For sure dispatcher maybe done as complicated as required. It is just an idea how to implement it.Kunkel
edited the Dispatcher sample to forward only to page from WEB-INF/jsf with additional logic of page finding including security check or forwarding to error pageKunkel
Still a rather clumsy solution to the concrete problem of hiding JSF source code files of public pages in case non-XHTML mapping was used. The current top answer shows how so solve it in much simpler ways.Burley
sure, above answers give easier ways. But my solution is just to show benefits of usage Dispatcher View with JSF. And one benefit of it is a possibility to access jsf files from WEB-INF. Also Dispatcher View pattern allows to use logical mapping strategy for JSF page. In Dispatcher it is possible to analyze url like /myapp/jsf/home and forward it to /WEB-INF/jsf/home.xhtml (for Faces Servlet). In ViewHandler is possible to remove .xhtml extension from jsf generated url: if (actionUrl != null && actionUrl.contains(".xhtml")) { actionUrl = actionUrl.replace(".xhtml", ""); }Kunkel

© 2022 - 2024 — McMap. All rights reserved.