JSF 返回空白/未解析的页面,而不是呈现 HTML 输出,而是返回纯文本/原始 XHTML/XML/EL 源代码。

24
我有一些像下面这样的Facelets文件。
WebContent
 |-- index.xhtml
 |-- register.xhtml
 |-- templates
 |    |--userForm.xhtml
 |    `--banner.xhtml
 :
两个页面都使用了/templates目录下的模板。我的/index.xhtml在浏览器中可以正常打开,我得到了生成的HTML输出。我在/index.xhtml文件中有一个链接到/register.xhtml文件。
但是,我的/register.xhtml没有被解析,返回的是普通的XHTML /原始XML,而不是生成的HTML输出。所有以#{...}形式的EL表达式均按原样显示,而不是打印它们的结果。当我在浏览器中右键单击页面并执行“查看页面源代码”时,仍然会看到原始的XHTML源代码,而不是生成的HTML输出。例如,<h:body>没有变成<body>。看起来模板没有被执行。
然而,当我在浏览器的地址栏中打开/faces/register.xhtml时,它会正确显示。这是由什么引起的,我应该如何解决?
1个回答

49

有三个主要原因。

  1. FacesServlet 没有被调用。
  2. XML 命名空间 URI 缺失或错误。
  3. 加载了多个 JSF 实现。

1. 确保URL与FacesServlet映射匹配

链接的URL(在浏览器地址栏中看到的URL)必须与web.xml中定义的FacesServlet<url-pattern>匹配,以便让所有JSF工作正常运行。 FacesServlet负责解析XHTML文件,收集提交的表单值,执行转换/验证,更新模型,调用操作并生成HTML输出。如果您不通过URL调用FacesServlet,则您将获得的是原始的XHTML源代码(通过右键单击,在浏览器中查看源代码)。

例如,如果<url-pattern>*.jsf,则链接应该指向/register.jsf而不是/register.xhtml。如果它是/faces/*,就像您现在所拥有的一样,则链接应该指向/faces/register.xhtml而不是/register.xhtml。避免这种混淆的一种方法是将<url-pattern>/faces/*更改为*.xhtml。因此,以下是理想的映射:

<servlet>
    <servlet-name>facesServlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>facesServlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
</servlet-mapping>

如果由于某种原因无法更改<url-pattern>*.xhtml,则您可能还希望通过URL防止最终用户直接访问XHTML源代码文件。在这种情况下,您可以在web.xml*.xhtml<url-pattern>上添加一个空的<auth-constraint><security-constraint>来防止这种情况发生。
<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> 

JSF 2.3是于2017年4月发布的,它已经通过在Web应用程序启动期间自动注册URL模式为*.xhtmlFacesServlet来解决了上述所有问题。因此,另一种选择就是升级到最新可用的JSF版本,应该是JSF 2.3或更高版本。但理想情况下,您仍应该明确地将FacesServlet仅注册到一个URL模式*.xhtml,因为对于完全相同的资源(例如/register.xhtml/register.jsf/register.faces/faces/register.xhtml),拥有多个可能的URL对于SEO来说是不好的。

另请参阅:


2. 确保XML命名空间与JSF版本匹配

自从JSF 2.2引入以来,另一个可能的原因是XML命名空间与JSF版本不匹配。像下面这样的xmlns.jcp.org是JSF 2.2之后新增的,在旧版本的JSF中不起作用。症状与未调用FacesServlet几乎相同。

<html lang="en"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets">

如果您无法升级到JSF 2.2或更高版本,则需要使用旧的java.sun.com XML命名空间。
<html lang="en"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">

但最好始终使用最新版本(如果有的话)。

另请参阅:


3. 多个JSF实现已加载

还有一个可能的原因是你的Web应用程序已经加载了多个JSF实现,彼此冲突并损坏。例如,当你的Web应用程序的运行时类路径被多个不同版本的JSF库污染时,或者在特定的Mojarra 2.x + Tomcat 8.x组合中,当Web应用程序的web.xml中存在不必要的ConfigureListener条目导致它被加载两次。

<!-- You MUST remove this one from web.xml! -->
<!-- This is actually a workaround for buggy GlassFish3 and Jetty servers. -->
<!-- When leaving this in and you're targeting Tomcat, you'll run into trouble. -->
<listener>
    <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>

使用Maven时,请务必确保正确声明依赖关系并了解依赖范围。重要的是,在目标服务器已提供依赖项时,不要在webapp中捆绑依赖项。
另请参阅: - com.sun.faces.config.ConfigureListener的配置 - 如何通过Maven正确安装和配置JSF库?

确保以正确的方式学习JSF

对于不熟悉基本HTTP, HTMLServlets的人来说,JSF的学习曲线非常陡峭。互联网上存在着许多低质量资源。请忽略那些由业余人员维护的代码片段爬取站点,他们主要关注广告收入而非教学,例如roseindia、tutorialspoint、javabeat、baeldung等等。它们很容易通过令人不快的广告链接/横幅进行识别。此外,请忽略与史前时代JSF 1.x有关的资源。他们使用JSP文件而不是XHTML文件,因此很容易辨别。自2009年起,JSP作为视图技术已经被JSF 2.0所取代。

为了以正确的方式开始,从我们的JSF维基页面开始,并订购权威书籍

另请参阅:


谢谢BalusC。我会尝试这个并回复你。保持联系。 - Muneer
亲爱的, 现在我使用<h:link />标签添加了我的链接。链接工作正常。但我有一个问题。链接自动进入/faces/register.xhtml。有没有办法隐藏/faces/目录并且链接应该显示/register.xhtml而不带“faces”目录? - Muneer
1
啊,你正在使用前缀映射“/faces/”,不行,你不能隐藏它。使用扩展名映射,如“.jsf”、“*.faces”甚至是“*.customextension”。 - BalusC
1
FacesServleturl-pattern/faces/*替换为*.jsf - BalusC
刚刚又有一个选项。p:remoteCommand有一个更新属性,其ID错误。也许对某些人来说会起作用。 - UnknownJoe
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接