什么是JSF资源库以及如何使用它?

Bal*_*usC 224 resources jsf jsf-2

在JSF <h:outputStylesheet>,<h:outputScript><h:graphicImage>组件具有library属性.这是什么以及如何使用它?Web上有很多示例,它们使用如下公共内容/文件类型css,js以及img(或image)作为库名称,具体取决于所使用的标记:

<h:outputStylesheet library="css" name="style.css" />
<h:outputScript library="js" name="script.js" />
<h:graphicImage library="img" name="logo.png" />
Run Code Online (Sandbox Code Playgroud)

它有用吗?library这些示例中的值似乎只是重复标记名称已经表示的内容.对于<h:outputStylesheet>它来说,基于标签名称已经很明显它代表了一个"CSS库".与以下内容有什么不同,它们的工作方式相同?

<h:outputStylesheet name="css/style.css" />
<h:outputScript name="js/script.js" />
<h:graphicImage name="img/logo.png" />
Run Code Online (Sandbox Code Playgroud)

此外,生成的HTML输出有点不同.给定URL模式的上下文路径/contextnameFacesServlet映射*.xhtml,前者生成以下HTML,其库名称为请求参数:

<link rel="stylesheet" type="text/css" href="/contextname/javax.faces.resource/style.css.xhtml?ln=css" />
<script type="text/javascript" src="/contextname/javax.faces.resource/script.js.xhtml?ln=js"></script>
<img src="/contextname/javax.faces.resource/logo.png.xhtml?ln=img" alt="" />
Run Code Online (Sandbox Code Playgroud)

而后者在URI的路径中生成以下带有库名的HTML:

<link rel="stylesheet" type="text/css" href="/contextname/javax.faces.resource/css/style.css.xhtml" />
<script type="text/javascript" src="/contextname/javax.faces.resource/js/script.js.xhtml"></script>
<img src="/contextname/javax.faces.resource/img/logo.png.xhtml" alt="" />
Run Code Online (Sandbox Code Playgroud)

后一种方法在事后看来也比前一种方法更有意义.该library属性究竟有用吗?

Bal*_*usC 252

实际上,网上的所有这些例子,其中诸如"js","css","img"等的共同内容/文件类型被用作库名称是误导性的.

现实世界的例子

首先,让我们看看现有的JSF实现如MojarraMyFaces以及PrimeFacesOmniFaces等JSF组件库如何使用它.他们中没有人以这种方式使用资源库.他们使用它(在封面下,用@ResourceDependencyUIViewRoot#addComponentResource())以下方式:

<h:outputScript library="javax.faces" name="jsf.js" />
<h:outputScript library="primefaces" name="jquery/jquery.js" />
<h:outputScript library="omnifaces" name="omnifaces.js" />
<h:outputScript library="omnifaces" name="fixviewstate.js" />
<h:outputScript library="omnifaces.combined" name="[dynamicname].js" />
<h:outputStylesheet library="primefaces" name="primefaces.css" />
<h:outputStylesheet library="primefaces-aristo" name="theme.css" />
<h:outputStylesheet library="primefaces-vader" name="theme.css" />
Run Code Online (Sandbox Code Playgroud)

应该清楚的是,它基本上代表了所有这些资源通常属于的公共库/模块/主题名称.

更容易识别

通过这种方式,可以更容易地指定和区分这些资源属于和/或来自何处.想象一下,您碰巧primefaces.css在自己的webapp中拥有一个资源,其中您正在重写/微调PrimeFaces的一些默认CSS; 如果PrimeFaces没有使用它自己的库名primefaces.css,那么PrimeFaces自己的那个不会被加载,而是webapp提供的那个,这将破坏look'n'feel.

此外,当您使用自定义时ResourceHandler,如果library以正确的方式使用,您还可以对来自特定库的资源应用更精细的控制.如果所有组件库都为其所有JS文件使用了"js",那么ResourceHandler如果它来自特定的组件库,它将如何区分?例如OmniFaces CombinedResourceHandlerGraphicResourceHandler; createResource()检查在委托给链中的下一个资源处理程序之前检查库的方法.通过这种方式,他们知道何时创建CombinedResourceGraphicResource用于此目的.

值得注意的是,RichFaces做错了.它根本没有使用任何东西library,并在其上自制了另一个资源处理层,因此无法以编程方式识别RichFaces资源.这正是为什么OmniFaces CombinedResourceHander必须引入基于反射的黑客才能让它在RichFaces资源上运行的原因.

你自己的webapp

您自己的webapp不一定需要资源库.你最好省略它.

<h:outputStylesheet name="css/style.css" />
<h:outputScript name="js/script.js" />
<h:graphicImage name="img/logo.png" />
Run Code Online (Sandbox Code Playgroud)

或者,如果你真的需要一个,你可以给它一个更明智的通用名称,如"默认"或一些公司名称.

<h:outputStylesheet library="default" name="css/style.css" />
<h:outputScript library="default" name="js/script.js" />
<h:graphicImage library="default" name="img/logo.png" />
Run Code Online (Sandbox Code Playgroud)

或者,当资源特定于某些主Facelets模板时,您还可以为其指定模板的名称,以便更容易相互关联.换句话说,它更多用于自我纪录目的.例如在/WEB-INF/templates/layout.xhtml模板文件中:

<h:outputStylesheet library="layout" name="css/style.css" />
<h:outputScript library="layout" name="js/script.js" />
Run Code Online (Sandbox Code Playgroud)

还有一个/WEB-INF/templates/admin.xhtml模板文件:

<h:outputStylesheet library="admin" name="css/style.css" />
<h:outputScript library="admin" name="js/script.js" />
Run Code Online (Sandbox Code Playgroud)

有关实际示例,请查看OmniFaces展示源代码.

或者,当您想要在多个Web应用程序上共享相同的资源并基于与此答案相同的示例为此创建"通用"项目时,该答案又在Web应用程序中作为JAR嵌入/WEB-INF/lib,那么也将其引用为库(名称可供您自由选择; OmniFaces和PrimeFaces等组件库也可以这样工作):

<h:outputStylesheet library="common" name="css/style.css" />
<h:outputScript library="common" name="js/script.js" />
<h:graphicImage library="common" name="img/logo.png" />
Run Code Online (Sandbox Code Playgroud)

库版本控制

另一个主要优点是您可以在您自己的webapp提供的资源上以正确的方式应用资源库版本控制(这不适用于嵌入在JAR中的资源).您可以在库文件夹中创建直接子子文件夹,并在\d+(_\d+)*模式中使用名称来表示资源库版本.

WebContent
 |-- resources
 |    `-- default
 |         `-- 1_0
 |              |-- css
 |              |    `-- style.css
 |              |-- img
 |              |    `-- logo.png
 |              `-- js
 |                   `-- script.js
 :
Run Code Online (Sandbox Code Playgroud)

使用此标记时:

<h:outputStylesheet library="default" name="css/style.css" />
<h:outputScript library="default" name="js/script.js" />
<h:graphicImage library="default" name="img/logo.png" />
Run Code Online (Sandbox Code Playgroud)

这将生成以下HTML,其库版本为v参数:

<link rel="stylesheet" type="text/css" href="/contextname/javax.faces.resource/css/style.css.xhtml?ln=default&amp;v=1_0" />
<script type="text/javascript" src="/contextname/javax.faces.resource/js/script.js.xhtml?ln=default&amp;v=1_0"></script>
<img src="/contextname/javax.faces.resource/img/logo.png.xhtml?ln=default&amp;v=1_0" alt="" />
Run Code Online (Sandbox Code Playgroud)

因此,如果您已编辑/更新了某些资源,那么您只需将版本文件夹复制或重命名为新值即可.如果您有多个版本文件夹,那么JSF ResourceHandler将根据数字排序规则自动从最高版本号提供资源.

因此,当复制/重命名resources/default/1_0/*文件夹时,resources/default/1_1/*如下所示:

WebContent
 |-- resources
 |    `-- default
 |         |-- 1_0
 |         |    :
 |         |
 |         `-- 1_1
 |              |-- css
 |              |    `-- style.css
 |              |-- img
 |              |    `-- logo.png
 |              `-- js
 |                   `-- script.js
 :
Run Code Online (Sandbox Code Playgroud)

然后最后一个标记示例将生成以下HTML:

<link rel="stylesheet" type="text/css" href="/contextname/javax.faces.resource/css/style.css.xhtml?ln=default&amp;v=1_1" />
<script type="text/javascript" src="/contextname/javax.faces.resource/js/script.js.xhtml?ln=default&amp;v=1_1"></script>
<img src="/contextname/javax.faces.resource/img/logo.png.xhtml?ln=default&amp;v=1_1" alt="" />
Run Code Online (Sandbox Code Playgroud)

这将强制webbrowser直接从服务器请求资源,而不是在第一次请求具有已更改参数的URL时从缓存中显示具有相同名称的资源.这样,当需要检索更新的CSS/JS资源时,最终用户不需要进行硬刷新(Ctrl + F5等).

请注意,JAR文件中包含的资源无法进行库版本控制.你需要一个自定义ResourceHandler.另请参见如何在jar中使用JSF版本控制资源.

也可以看看:

  • 是否可以使用EL作为库?因此,如果我想拥有资源/默认和资源/感觉问题今天我可以做类似library ="#{someLibraryHere}"的事情,将someLibraryHere映射到我选择的库,而不必每次都将资源目录重命名为更高版本我想改变它们. (2认同)
  • 在"mojarra 2.2.5(2.2.5-jbossorg-3,wildfly 8.0)"和"2.2.11(2.2.11-jbossorg-1)"之间,"library"或其相关内容的允许字符是否会发生变化?我似乎无法在发布说明中找到任何内容.请参见http://stackoverflow.com/questions/35719808/wildfly-10-issue-with-css-file (2认同)
  • 谢谢@BalusC.不幸的是,甚至Oracle自己的Java EE 7教程也在[8.6 Web Resources]一章中使用库名`css`给出了错误的例子(https://docs.oracle.com/javaee/7/tutorial/jsf-facelets006.htm #GIRGM)并且在[guessnumber-jsf示例应用程序](https://docs.oracle.com/javaee/7/tutorial/jsf-facelets003.htm)中对css和图像做错了. (2认同)