238

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

<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 输出有点不同。给定 的上下文路径/contextnameFacesServletURL 模式的映射*.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="" />

而后者在 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那么该属性到底有多大用处?

4

1 回答 1

266

实际上,网络上所有那些将“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" />

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

更容易识别

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

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

应该注意的是 RichFaces 做错了。它根本没有使用任何library资源,并且在其上自制了另一个资源处理层,因此无法以编程方式识别 RichFaces 资源。这正是OmniFaces CombinedResourceHander必须引入基于反射的 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 展示源代码

或者,当您想在多个 webapps 上共享相同的资源并基于与此答案中相同的示例创建一个“通用”项目时,该项目又作为 JAR 嵌入 webapp's/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" />

v这将使用库版本作为参数生成以下 HTML :

<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="" />

因此,如果您编辑/更新了某些资源,那么您需要做的就是将版本文件夹复制或重命名为新值。如果您有多个版本文件夹,则 JSFResourceHandler将根据数字排序规则自动从最高版本号开始提供资源。

因此,当复制/重命名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. 另请参阅如何对 jar 中的资源使用 JSF 版本控制

也可以看看:

于 2012-08-16T13:38:19.100 回答