WEB-INF 目录中的 JSF 文件,我如何访问它们?

Posted

技术标签:

【中文标题】WEB-INF 目录中的 JSF 文件,我如何访问它们?【英文标题】:JSF files inside WEB-INF directory, how do I access them? 【发布时间】:2011-03-31 13:06:41 【问题描述】:

我想将我的 JSF 2.0 xhtml 文件放在 WEB-INF\jsf 下。那我该如何访问它们?我知道 WEB-INF 内部的任何东西都不会暴露在外部,所以我需要一个控制器来将我重定向到相应的 JSP,对吧? (这也是模型 2 模式 iirc)。

我可以通过 web.xml/faces-config.xml 中的参数来实现吗?我认为 FacesServlet 是我的 webapp 的控制器,所以它应该服务于这个目的?

还有一个关于理解 Model 2 模式的问题。是否每个操作都必须首先进入一个 servlet,然后由该 servlet 处理下一个可能的步骤?因此,在这种模式中禁止使用简单的<a href="anotherPage.html" />,因为它不会进入控制 servlet?

【问题讨论】:

【参考方案1】:

我想将我的 JSF 2.0 xhtml 文件放在 WEB-INF\jsf 下。那我该如何访问它们呢?

你不能。无法直接访问/WEB-INF 文件夹中的文件。

有两种方法可以解决 JSF 源文件可公开访问的问题。

    FacesServlet 映射到*.xhtml 而不是*.jsf

    或者,通过web.xml 中的<security-constraint> 限制对*.xhtml 的直接访问。

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

另见:

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?

关于理解 Model 2 模式的另一个问题。是否每个操作都必须首先进入一个 servlet,然后由该 servlet 处理下一个可能的步骤?

FacesServlet 已经这样做了。是控制器。使用 JSF,您已经得到了一个简单的 javabean 作为模型和 JSP/Facelets 文件作为视图。 FacesServlet 作为控制器,已经从您手中承担了请求参数收集、验证、转换、模型更新和导航的所有令人讨厌的工作。

另见:

What components are MVC in JSF MVC framework? JSF Controller, Service and DAO

所以在这种模式中禁止使用简单的&lt;a href="anotherPage.html" /&gt;,因为它不会进入控制 servlet?

不,完全没问题。控制器将在需要时启动。如果资源不需要控制器(即静态资源),那么您也不需要让它通过某个控制器。


以后,请在不同的 Stack Overflow 问题中提出多个问题。

【讨论】:

感谢您的回复。我已经只映射了 *.xhtml 文件(选项 1)。我已经读过,在某些框架(Struts、Spring Webflow、..)中,将 jsp 文件(=动态内容)放在 WEB-INF 下是可能的/首选方式,控制器在那里访问它们并将它们显示给用户。我只是想问一下 JSF 是否也可以这样做。但是如果我没看错的话,没有人可以通过浏览器查看 xhtml 文件的源代码,因为它们总是通过控制器呈现,对吧?【参考方案2】:

要访问WEB-INF/jsf 文件夹中的xhtml 页面,您可以执行以下操作:

    xhtml pages 文件夹从webapp root 移动到WEB-INF 在项目中引入“Dispatcher View”模式 根据应用程序的页面将“Front Controller”servlet 映射到urlFaces Servlet映射到“.xhtml” 在“Dispatcher”内部将请求转发到来自“WEB-INF/jsf/&lt;name&gt;.xhtml”的页面 覆盖 jsf ViewHandler getActionUrl 以从生成的 action urlform, link, button)中排除“WEB-INF

例如,xhtml 页面位于 webapp 根文件夹“jsf”中。页面之间的所有url 类似于jsf/&lt;pageName&gt;.xhtml。所以我们下一步:

    &lt;webapp root&gt;/jsf移动到&lt;webapp root&gt;/WEB-INF/jsf

    创建 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);
        

    基于页面将 web.xml 中的 Front Controller servlet 映射到 url
<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>
    web.xml中的Faces Servlet映射到.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>
    创建Dispatcher,将request 转发到更正xhtml 页面:

``

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);        
       


因此,如果页面的 url 是 /myapp/jsf/home.xhtml,那么 Dispatcher 会将其转发到 myapp/WEB-INF/jsf/home.xhtml。 Faces Servlet 将处理“.xhtml”请求。但是,如果在页面上使用jsf 组件,如h:form, h:link, h:button 等生成actionurl,那么url 将真正包括“/WEB-INF”。所以要排除它,我们需要下一步。

    jsf 生成的url 中排除“/WEB-INF”(用于jsf 表单、链接、按钮)。 为此:

    6.1 创建jsf ViewHandler 的子类并覆盖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 配置jsf 使用指定的ViewHandler。在faces-config.xml 中添加下一个:

   <application>
    ...
        <view-handler>
            controllers.HiddenPageViewHandler
        </view-handler>
   </application>

【讨论】:

不好的建议。这引入了一个安全漏洞:将所有 WEB-INF 内容直接公开。 为了简单起见,调度程序只是在请求的 url 之前添加 WEB-INF。当然,调度员可能会根据需要完成复杂的工作。如何实现它只是一个想法。 编辑了 Dispatcher 示例,使其仅从 WEB-INF/jsf 转发到页面,并增加了页面查找逻辑,包括安全检查或转发到错误页面 在使用非 XHTML 映射的情况下隐藏公共页面的 JSF 源代码文件的具体问题仍然是一个相当笨拙的解决方案。当前的最佳答案显示了如何以更简单的方式解决它。 当然,以上答案提供了更简单的方法。但我的解决方案只是展示使用 JSF 的 Dispatcher View 的好处。它的一个好处是可以从 WEB-INF 访问 jsf 文件。 Dispatcher View 模式也允许对 JSF 页面使用逻辑映射策略。在 Dispatcher 中,可以分析像 /myapp/jsf/home 这样的 url 并将其转发到 /WEB-INF/jsf/home.xhtml(对于 Faces Servlet)。在 ViewHandler 中,可以从 jsf 生成的 url 中删除 .xhtml 扩展名: if (actionUrl != null && actionUrl.contains(".xhtml")) actionUrl = actionUrl.replace(".xhtml", "");

以上是关于WEB-INF 目录中的 JSF 文件,我如何访问它们?的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式访问 JSF 应用程序中的属性文件

如何从 JSF 的 /WEB-INF 文件夹中获取属性文件?

警告:有人试图访问安全资源:/WEB-INF/login.xhtml

JSF 面对 WEB-INF 之外的配置文件?

关于JAVA EE项目在WEB-INF目录下的jsp页面如何访问WebRoot中的CSS和JS文件

普通java类文件如何访问WEB-INF目录下的文件,不是Servlet、JSP类文件