3

我有一个(工作的)JSF 应用程序。现在我想要使用 JSF 表达式语言扩展一个不是页面资源的文档(假设是纯文本文档)(因为我需要来自我的 bean 的状态,这看起来很“自然”)。但似乎我没有完全了解机制......

为了在 web.xml 中有“*.txt”文件

<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
</servlet-mapping> 
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.txt</url-pattern>
</servlet-mapping>

我添加了一个“plain.txt”资源

<f:view contentType="text/plain" xmlns:f="http://java.sun.com/jsf/core" >

hi #{request.contextPath}/

</f:view>

请求

http://myServer/myApp/plain.txt

使用 myfaces 2.1.10 在服务器上无限循环失败。将资源重命名为“plain.xhtml”并请求它工作正常。

更新到 myfaces 2.1.17(与 2.2.9 相同)后,提供“plain.txt”也有效!

问题是:以这种方式使用模板是“最佳实践”还是“意外副作用”(并且不应该真正起作用)?有没有更好的方法来实现这样的模板任务?

编辑

经过更多尝试,它似乎更加奇怪。提供扩展内容似乎随机失败(2.1.17 和 2.2.9)。重新启动后,我在服务器端获得了一个资源“res1.txt”的“循环”,但不是资源“res2.txt”的精确副本。还发生了“res1.txt”成功呈现。也许服务器跟踪可以给出一些提示:

首先,有一个很长的“递归”

Mär 09, 2016 5:06:20 PM org.apache.catalina.core.ApplicationDispatcher invoke
SCHWERWIEGEND: Servlet.service() for servlet Faces Servlet threw exception
java.lang.NullPointerException
    at org.apache.myfaces.shared.context.flash.FlashImpl.isKeepMessages(FlashImpl.java:388)
    at org.apache.myfaces.shared.context.flash.FlashImpl._saveMessages(FlashImpl.java:668)
    at org.apache.myfaces.shared.context.flash.FlashImpl.doPostPhaseActions(FlashImpl.java:269)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:254)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:486)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
    at org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:369)
    at org.apache.myfaces.view.jsp.JspViewDeclarationLanguage.buildView(JspViewDeclarationLanguage.java:99)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:78)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:486)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
    at org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:369)
    at org.apache.myfaces.view.jsp.JspViewDeclarationLanguage.buildView(JspViewDeclarationLanguage.java:99)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:78)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:486)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
    at org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:369)
    at org.apache.myfaces.view.jsp.JspViewDeclarationLanguage.buildView(JspViewDeclarationLanguage.java:99)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:78)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:486)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
    at org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:369)
    at org.apache.myfaces.view.jsp.JspViewDeclarationLanguage.buildView(JspViewDeclarationLanguage.java:99)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:78)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:486)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
    at org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:369)
    at org.apache.myfaces.view.jsp.JspViewDeclarationLanguage.buildView(JspViewDeclarationLanguage.java:99)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:78)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:486)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
    at org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:369)
    at org.apache.myfaces.view.jsp.JspViewDeclarationLanguage.buildView(JspViewDeclarationLanguage.java:99)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:78)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:486)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
    at org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:369)
    at org.apache.myfaces.view.jsp.JspViewDeclarationLanguage.buildView(JspViewDeclarationLanguage.java:99)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:78)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:486)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
    at org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:369)
    at org.apache.myfaces.view.jsp.JspViewDeclarationLanguage.buildView(JspViewDeclarationLanguage.java:99)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:78)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

此跟踪重复并每次变短,直到最终达到此目的:

Mär 09, 2016 5:06:20 PM org.apache.catalina.core.StandardWrapperValve invoke
SCHWERWIEGEND: Servlet.service() for servlet [Faces Servlet] in context with path [/cloudsuite-snippets] threw exception
java.lang.NullPointerException
    at org.apache.myfaces.shared.context.flash.FlashImpl.isKeepMessages(FlashImpl.java:388)
    at org.apache.myfaces.shared.context.flash.FlashImpl._saveMessages(FlashImpl.java:668)
    at org.apache.myfaces.shared.context.flash.FlashImpl.doPostPhaseActions(FlashImpl.java:269)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:254)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

浏览器页面只是白色的..

编辑二

还有另一个信息:失败并不是真正的不确定性(这会稍微损害我的信仰......)但仍然很奇怪。对于我有同名资源但结尾为“.xhtml”的所有资源,渲染成功。

服务器似乎在内部重定向到“.xhtml”版本,呈现这个内容并以“.txt”版本的名称返回它(忽略后者的内容)。这里发生了什么?

4

2 回答 2

3

问题是:以这种方式使用模板是“最佳实践”还是“意外副作用”(并且不应该真正起作用)?

它不应该真的起作用。JSF 作为基于 HTML 表单的 MVC 框架首先不支持text/plain内容,而仅支持基于 HTML 的内容,例如text/html. 在 Mojarra 而不是 MyFaces 上尝试您的用例时(重命名plain.txt为后plain.xhtml,请参见下文),我得到以下异常:

java.lang.IllegalArgumentException:无法识别的内容类型。

至于查看解析,从技术上讲,您应该将plain.txt文件命名为plain.xhtml并且仅将*.txtURL 模式添加到FacesServlet. 即在将FacesServletURL 模式中的任何文件扩展名重新映射javax.faces.DEFAULT_SUFFIX到默认为.xhtml. 当物理文件不存在时,JSF 将从 Facelets 视图回退到 JSP 视图(通过JspViewDeclarationLanguage堆栈跟踪中的存在来确认)但plain.jsp也不存在,并且 URL 仍然匹配FacesServlet映射,这反过来又在无限循环中运行无果而终地寻找和呈现物理资源。

有关 JSF 视图解析的内部工作原理的详细说明,另请参阅JSF Facelets:有时我看到 URL 是 .jsf,有时是 .xhtml。为什么?至于无限循环dispatch(),这在技术上又是 JSF 中的一个错误,因为它实际上应该返回 404。


有没有更好的方法来实现这样的模板任务?

如果唯一的目的是评估 EL 表达式,那么最好使用 JSP servlet 而不是 JSF servlet,并专门使用只读 EL 表达式${}而不是可写 EL 表达式#{},因为 JSP 不支持这一点。

最简单的方法是将 servlet 名称更改为 Tomcat 自己的 JSP servlet 之一:(jsp不需要<servlet>条目,因为 Tomcat 已经在其自己的中定义了它/conf/web.xml)。

<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.txt</url-pattern>
</servlet-mapping>

然后将其更改/plain.txt为 JSP 视图,如下所示。请注意,${request}在 JSP 中不存在,它仅作为${pageContext}. 另请参阅我们的 EL wiki 页面

<%@page contentType="text/plain" %>

hi ${pageContext.request.contextPath}/

至于解析托管bean,它只是不发现 JSF @ManagedBean,但它可以发现 CDI @Named。因此,当您在 Tomcat 上安装 CDI并将感兴趣的托管 bean 改造成 CDI 托管 bean 而不是 JSF 托管 bean 时,它们将可用。

一个不同的替代方案需要更多的工作,但保证跨 servlet 容器可移植(因为 servlet 名称jsp是 Tomcat 特定的,尽管几乎所有 servlet 容器都具有相同的“事实上”名称)使用普通的 vanilla servlet,甚至可能是 JAX- RS (RESTful) 资源,用于您想到的任务。将其映射到所需的 URL 模式/plain.txt,让它准备所需的模型,最后以通常的方式转发到“真实”JSP 文件。

@WebServlet("/plain.txt")
public class PlainTxtServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getRequestDispatcher("/WEB-INF/plain.jsp").forward(request, response);
    }

}

并且有一个/WEB-INF/plain.jsp物理文件,仍然使用上述 JSP 语法。请注意,它被放置在内部/WEB-INF,因为您不希望最终用户能够直接请求/plain.jsp而不是/plain.txt.

额外的好处是,这并不一定需要 CDI 来管理 bean,因为您可以手动管理 bean,如下所示:

Bean bean = new Bean();
request.setAttribute("bean", bean);

它将像${bean}在 EL 中一样可用。

也可以看看:

于 2016-03-12T09:55:13.853 回答
0

我不太确定那里发生了什么,但我是这样做的......

保留您已有的 web.xml 文件。

创建像plain.xhtml这样的xhtm文件......

<ui:composition
    xmlns:ui="http://java.sun.com/jsf/facelets">
    hi #{request.contextPath}/
</ui:composition>

现在转到 .../plain.txt

它应该可以正常工作

于 2016-03-12T10:15:11.107 回答