我做过tutorial about Facelets templating。
现在我尝试创建一个与模板不在同一目录中的页面。我有页面样式的问题,因为样式用相对路径引用,如下所示:
<link rel="stylesheet" href="style_resource_path.css" />
我可以从/
开始使用绝对引用:
<link rel="stylesheet" href="/project_root_path/style_resource_path.css" />
但是,当我将应用程序移动到不同的环境时,这将给我带来麻烦。
所以我想知道在Facelets中引用CSS(以及JS和图像)资源的最佳方法是什么?
正确的JSF 2.x方式是使用<h:outputStylesheet>
,<h:outputScript>
和<h:graphicImage>
和name
引用相对于webapp的/resources
文件夹的路径。这样您就不必像在JSF 1.x中那样担心上下文路径。另见How to include CSS relative to context path in JSF 1.x?
将CSS / JS /图像文件放在公共webcontent的/resources
文件夹中,如下所示(如果不存在,则创建一个与/WEB-INF
和/META-INF
相同的级别)。
WebContent
|-- resources
| |-- css
| | |-- other.css
| | `-- style.css
| |-- js
| | `-- script.js
| `-- images
| |-- background.png
| |-- favicon.ico
| `-- logo.png
|-- META-INF
| `-- MANIFEST.MF
|-- WEB-INF
| |-- faces-config.xml
| `-- web.xml
|-- page.xhtml
:
在Maven的情况下,它应该在/main/webapp/resources
中,因此不是/main/resources
(那些用于Java资源(properties / xml / text / config文件),它们必须最终在运行时类路径中,而不是在webcontent中)。另见Maven and JSF webapp structure, where exactly to put JSF resources。
最终,这些资源可以在任何地方获得,无需摆弄相对路径:
<h:head>
...
<h:outputStylesheet name="css/style.css" />
<h:outputScript name="js/script.js" />
</h:head>
<h:body>
...
<h:graphicImage name="images/logo.png" />
...
</h:body>
name
属性必须表示相对于/resources
文件夹的完整路径。它不需要从/
开始。只要您没有开发像PrimeFaces这样的组件库或由多个webapp共享的公共模块JAR文件,就不需要library
属性。
您可以在任何地方引用<h:outputStylesheet>
,也可以在模板客户端的<ui:define>
中引用,而无需额外的<h:head>
。它将通过主模板的<h:head>
组件自动结束生成的<head>
。
<ui:define name="...">
<h:outputStylesheet name="css/style.css" />
...
</ui:define>
您也可以在任何地方引用<h:outputScript>
,但默认情况下它会在您声明它的地方的HTML中结束。如果你希望它通过<head>
结束在<h:head>
,那么添加target="head"
属性。
<ui:define name="...">
<h:outputScript name="js/script.js" target="head" />
...
</ui:define>
或者,如果你希望它最终在<body>
的末尾(在</body>
之前,所以例如window.onload
和$(document).ready()
等没有必要)通过<h:body>
,然后添加target="body"
属性。
<ui:define name="...">
<h:outputScript name="js/script.js" target="body" />
...
</ui:define>
HeadRenderer
如果你正在使用PrimeFaces,它的HeadRenderer
将如上所述弄乱默认的<h:head>
脚本排序。您基本上被迫通过PrimeFaces特定的<f:facet name="first|middle|last">
强制执行订单,这可能会导致混乱和“无法模板”的代码。你可能想要关闭它,如this answer中所述。
您甚至可以将资源打包到JAR文件中。另见Structure for multiple JSF projects with shared code。
您可以在EL中使用#{resource}
映射让JSF基本上打印像/context/javax.faces.resource/folder/file.ext.xhtml?ln=library
这样的资源URL,以便您可以将其用作例如CSS背景图片或favicon。唯一的要求是CSS文件本身也应该作为JSF资源提供,否则EL表达式将不会被评估。另见How to reference JSF image resource as CSS background image url。
.some {
background-image: url("#{resource['images/background.png']}");
}
这是@import
的例子。
@import url("#{resource['css/other.css']}");
这是favicon的例子。另见Add favicon to JSF project and reference it in <link>。
<link rel="shortcut icon" href="#{resource['images/favicon.ico']}" />
如果您使用的是SCSS编译器(例如Sass Compiler Plugin for Maven),请记住SCSS处理器可能会将#
解释为特殊字符。在这种情况下,您需要使用\
来逃避它。
.some {
background-image: url("\#{resource['images/background.png']}");
}
通过<h:outputStylesheet>
加载的第三方CSS文件反过来引用字体和/或图像可能需要更改为使用#{resource}
表达式,如上一节所述,否则需要安装UnmappedResourceHandler
才能为使用JSF的人提供服务。另见a.o. Bootsfaces page shows up in browser without any styling和How to use Font Awesome 4.x CSS file with JSF? Browser can't find font files。
如果您打算通过将整个/resources
文件夹移动到/WEB-INF
来隐藏公共访问资源,那么您可以从JSF 2.2中选择性地通过新的web.xml
上下文参数更改webcontent-relative路径,如下所示:
<context-param>
<param-name>javax.faces.WEBAPP_RESOURCES_DIRECTORY</param-name>
<param-value>/WEB-INF/resources</param-value>
</context-param>
在较旧的JSF版本中,这是不可能的。
假设您正在运行Web应用程序的子目录中。你可以尝试这样:
<link href="${facesContext.externalContext.requestContextPath}/css/style.css" rel="stylesheet" type="text/css"/>
'${facesContext.externalContext.requestContextPath}/'
链接将帮助您立即返回上下文的根。
在相对URL中,前导斜杠/指向域根。因此,如果JSF页面例如由http://example.com/context/page.jsf请求,则CSS URL将绝对指向http://example.com/styles/decoration.css。要知道有效的相对URL,您需要知道JSF页面和CSS文件的绝对URL,并从另一个中提取一个。
假设您的CSS文件实际位于http://example.com/context/styles/decoration.css,那么您需要删除前导斜杠,使其相对于当前上下文(page.jsp之一):
<link rel="stylesheet" type="text/css" href="styles/decoration.css" />
这些答案帮助我解决了同样的问题。虽然我使用SASS和GULP后问题更加复杂。
我不得不改变(请注意#前面的“\”。吞咽的可能副作用:
<h:outputStylesheet library="my_theme" name="css/default.css"/>
background: $blue url("\#{resource['my_theme/images/background-homepage-h1.png']}");
resourcehandlers.UnmappedResourceHandler有助于在/javax.faces.resource/*的URL模式上映射JSF资源。
对我来说,faces-config.xml中的这两个xml配置:org.omnifaces.resourcehandler.UnmappedResourceHandler
并在web.xml中:
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>/javax.faces.resource/*</url-pattern>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
帮助css和图像。