如何在Facelets模板中引用CSS / JS / image资源?

我已经完成了关于Facelets模板的教程 。

现在我试着创build一个与模板不在同一个目录中的页面。 我遇到了页面样式的问题,因为样式被相对path引用,如下所示:

<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>来引用相对于webapp的/resources文件夹的path。 这样,您就不必像在JSF 1.x中那样担心上下文path。 另请参见如何在JSF 1.x中包含相对于上下文path的CSS?

文件夹结构

将CSS / JS /图像文件放在public webcontent的/resources文件夹中(如果不在/WEB-INF/META-INF的相同级别,则创build一个)。

 WebContent |-- META-INF |-- WEB-INF |-- resources | |-- css | | |-- other.css | | `-- style.css | |-- js | | `-- script.js | `-- images | |-- background.png | |-- favicon.ico | `-- logo.png |-- page.xhtml : 

在Maven的情况下,它应该在/main/webapp/resources ,因此不是 /main/resources (那些用于Java资源(properties / xml / text / config文件)的资源必须以运行时类path结束,而不是在webcontent中) 。 另请参阅Maven和JSF webapp结构,其中正是放置JSF资源的地方 。

在Facelets中引用

最终,这些资源可以在任何地方使用,无需摆弄相对path:

 <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文件夹的完整path。 它不需要以/开头。 只要不开发像PrimeFaces这样的组件库或多个Web应用程序共享的公共模块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中。 如果你想通过<h:head>结束<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> 

PrimeFaces HeadRenderer

如果你使用PrimeFaces,它的HeadRenderer会混淆默认的<h:head>脚本顺序,如上所述。 您基本上被迫通过PrimeFaces特定的<f:facet name="first|middle|last">来强制执行命令,最终可能会导致混乱和“无法模板化”的代码。 您可能需要按照此答案中的描述closures它。

在JAR中打包

您甚至可以将资源打包到JAR文件中。 另请参见具有共享代码的多个JSF项目的结构 。

在EL中引用

您可以在EL中使用#{resource}映射让JSF基本上打印一个像/context/javax.faces.resource/folder/file.ext.xhtml?ln=library这样的资源URL,以便您可以使用它作为例如CSS背景图像或图标。 唯一的要求是,CSS文件本身也应该作为一个JSF资源,否则ELexpression式不会评估。 另请参见如何将JSF图像资源引用为CSS背景图像url 。

 .some { background-image: url("#{resource['images/background.png']}"); } 

这里是@import例子。

 @import url("#{resource['css/other.css']}"); 

这里是favicon的例子。 另请参阅将图标添加到JSF项目,并在<link>中引用它 。

 <link rel="shortcut icon" href="#{resource['images/favicon.ico']}" /> 

引用第三方CSS文件

通过<h:outputStylesheet>加载第三方CSS文件,然后引用字体和/或图像可能需要改变为使用前面章节描述的#{resource}expression式,否则需要安装一个UnmappedResourceHandler以便能够为使用JSF的人提供服务。 另请参阅ao Bootsfaces页面显示在浏览器中,没有任何样式和如何使用JSF的Font Awesome 4.x CSS文件? 浏览器无法find字体文件 。

隐藏在/ WEB-INF中

如果您打算通过将整个/resources文件夹移动到/WEB-INF来隐藏公共访问/resources ,那么您可以通过JSF 2.2可选地通过新的web.xml上下文参数更改webcontent相对path,如下所示:

 <context-param> <param-name>javax.faces.WEBAPP_RESOURCES_DIRECTORY</param-name> <param-value>/WEB-INF/resources</param-value> </context-param> 

在较老的JSF版本中,这是不可能的。

也可以看看:

  • Java EE 6教程 – Facelets – 资源 (只有两章远离链接)
  • 什么是JSF资源库,以及如何使用它?
  • 如何用自定义样式覆盖默认的PrimeFaces CSS?

假设您正在运行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中; ,那么您需要删除前导斜杠,以便它与当前上下文(页面的一个)相关。 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_themehttp://img.dovov.combackground-homepage-h1.png']}");