ChatGPT解决这个技术问题 Extra ChatGPT

JSF 资源库有什么用途,应该如何使用?

JSF <h:outputStylesheet><h:outputScript><h:graphicImage> 组件具有 library 属性。这是什么,应该如何使用?网络上有很多示例,它们使用常见的内容/文件类型 cssjsimg(或 image)作为库名称,具体取决于所使用的标签:

<h:outputStylesheet library="css" name="style.css" />
<h:outputScript library="js" name="script.js" />
<h:graphicImage library="img" name="logo.png" />

它有什么用处?这些示例中的 library 值似乎只是重复了标记名称已经表示的任何内容。对于 <h:outputStylesheet>,它基于标签名称已经很明显,它代表一个“CSS 库”。与以下也以相同方式工作的有什么区别?

<h:outputStylesheet name="css/style.css" />
<h:outputScript name="js/script.js" />
<h:graphicImage name="img/logo.png" />

此外,生成的 HTML 输出有点不同。给定 /contextname 的上下文路径和 *.xhtml 的 URL 模式上的 FacesServlet 映射,前者生成以下 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="" />

而后者在 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="" />

事后看来,后一种方法也比前一种方法更有意义。 library 属性究竟有多大用处?


C
Community

实际上,网络上的所有这些示例,其中使用“js”、“css”、“img”等常见内容/文件类型作为库名称都是误导性的。

现实世界的例子

首先,让我们看看现有的 JSF 实现(如 MojarraMyFaces)以及 JSF 组件库(如 PrimeFacesOmniFaces)如何使用它。他们中没有人以这种方式使用资源库。他们使用它(在幕后,通过 @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" />

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

更容易识别

这样,指定和区分这些资源属于和/或来自哪里就容易多了。假设您碰巧在自己的 web 应用中有一个 primefaces.css 资源,其中您正在覆盖/微调 PrimeFaces 的一些默认 CSS;如果 PrimeFaces 没有为其自己的 primefaces.css 使用库名称,则不会加载 PrimeFaces 自己的库名称,而是加载 webapp 提供的库名称,这会破坏外观。

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

应该注意的是 RichFaces 做错了。它根本没有使用任何 library 并且在其上自制了另一个资源处理层,因此不可能以编程方式识别 RichFaces 资源。这正是 OmniFaces CombinedResourceHander 必须引入 a reflection-based hack 才能使其与 RichFaces 资源一起使用的原因。

你自己的网络应用

你自己的 webapp 不一定需要资源库。你最好忽略它。

<h:outputStylesheet name="css/style.css" />
<h:outputScript name="js/script.js" />
<h:graphicImage name="img/logo.png" />

或者,如果你真的需要一个,你可以给它一个更合理的通用名称,比如“默认”或一些公司名称。

<h:outputStylesheet library="default" name="css/style.css" />
<h:outputScript library="default" name="js/script.js" />
<h:graphicImage library="default" name="img/logo.png" />

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

<h:outputStylesheet library="layout" name="css/style.css" />
<h:outputScript library="layout" name="js/script.js" />

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

<h:outputStylesheet library="admin" name="css/style.css" />
<h:outputScript library="admin" name="js/script.js" />

对于真实世界的示例,请检查 OmniFaces showcase source code

或者,如果您想在多个 web 应用程序上共享相同的资源,并基于与 this answer 中相同的示例创建了一个“通用”项目,该项目又作为 JAR 嵌入到 web 应用程序的 /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" />

库版本控制

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

WebContent
 |-- resources
 |    `-- default
 |         `-- 1_0
 |              |-- css
 |              |    `-- style.css
 |              |-- img
 |              |    `-- logo.png
 |              `-- js
 |                   `-- script.js
 :

使用此标记时:

<h:outputStylesheet library="default" name="css/style.css" />
<h:outputScript library="default" name="js/script.js" />
<h:graphicImage library="default" name="img/logo.png" />

这将生成以下 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="" />

因此,如果您编辑/更新了某些资源,那么您需要做的就是将版本文件夹复制或重命名为新值。如果您有多个版本文件夹,则 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
 :

然后最后一个标记示例将生成以下 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="" />

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

请注意,对于包含在 JAR 文件中的资源,库版本控制是不可能的。您需要一个自定义 ResourceHandler。另见How to use JSF versioning for resources in jar

也可以看看:

JSF 资源版本控制

JSF2 静态资源缓存

具有共享代码的多个 JSF 项目的结构

JSF 2.0 规范 - 第 2.6 章资源处理


图书馆可以使用EL吗?因此,如果我想拥有一个资源/默认值和一个资源/feelingFroggyToday,我可以执行类似 library="#{someLibraryHere}" 之类的操作,将 someLibraryHere 映射到我选择的库,而不必每次都依赖于将资源目录重命名为更高版本我想改变它们。
当您说 library=admin 或 libray=layout 时,这些(admin 和 layout)文件夹是否位于资源文件夹中?
在 mojarra 2.2.5( 2.2.5-jbossorg-3, wildfly 8.0) 和 2.2.11(2.2.11-jbossorg-1) 之间允许的 library 值或与之相关的字符是否发生了变化?我似乎在发行说明中找不到任何东西。请参阅stackoverflow.com/questions/35719808/…
谢谢@BalusC。不幸的是,即使 Oracle 自己的 Java EE 7 教程在第 8.6 Web Resources 章中使用库名称 css 并在 guessnumber-jsf example application 中使用 css 和图像时也给出了错误的示例。
@Arash:不,不需要将当前语言环境复制粘贴到所有地方的库中,只需按照您找到的链接中的说明调整文件夹结构,其余的都是自动的。