什么是JSF资源库,以及如何使用它?
JSF <h:outputStylesheet>
, <h:outputScript>
和<h:graphicImage>
组件具有library
属性。 这是什么,应该如何使用? 在networking上有很多的例子,它使用如下的常见的内容/文件types的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" />
它有什么用处? 这些示例中的library
值似乎只是重复了标记名称所代表的内容。 对于<h:outputStylesheet>
它基于标记名已经很明显,它代表一个“CSS库”。 下面哪个区别也是一样的?
<h:outputStylesheet name="css/style.css" /> <h:outputScript name="js/script.js" /> <h:graphicImage name="img/logo.png" />
而且,生成的HTML输出有点不同。 给定*.xhtml
URL模式上的/contextname
和FacesServlet
映射的上下文path,前者将生成以下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的path中使用库名称生成以下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
属性到底有多有用呢?
实际上,所有这些使用常见的内容/文件types(例如“js”,“css”,“img”等)作为库名的例子都是误导性的 。
真实世界的例子
首先,我们来看看现有的像Mojarra和MyFaces这样的JSF实现以及像PrimeFaces和OmniFaces这样的JSF组件库如何使用它。 其中没有一个人以这种方式使用资源库。 他们使用它(在下面,通过@ResourceDependency
或UIViewRoot#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" />
应该清楚的是,它基本上代表了所有这些资源通常属于的共同的库/模块/主题名称 。
更容易识别
这样一来,指定和区分这些资源所属的和/或来自哪里将变得更加容易。 想象一下,你碰巧在你自己的webapp中有一个primefaces.css
资源,其中你正在重写/微调一些默认的PrimeFaces CSS; 如果PrimeFaces没有为自己的primefaces.css
使用一个库名,那么PrimeFaces自己的不会被加载,而是由webapp提供的,这会破坏look'n'feel。
另外,当你使用一个自定义的ResourceHandler
,当正确使用库时,你也可以对来自特定库的资源进行更精细的控制。 如果所有组件库都将使用所有JS文件的“js”,那么ResourceHandler
如何区分它是否来自特定的组件库? 例子是OmniFaces CombinedResourceHandler
和GraphicResourceHandler
; 检查在委托给链中的下一个资源处理器之前检查库的createResource()
方法。 这样他们知道什么时候创buildCombinedResource
或GraphicResource
的目的。
值得注意的是RichFaces做错了。 它根本没有使用任何library
,并且在它上面自带了另一个资源处理层,因此不可能通过编程来识别RichFaces资源。 这就是为什么OmniFaces CombinedResourceHander
必须引入基于reflection的黑客才能使其与RichFaces资源一起工作的原因。
你自己的web应用程序
您自己的web应用程序不一定需要资源库。 你最好只是省略它。
<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共享相同的资源,并且基于与此答案相同的示例创build了一个“common”项目,该项目又被embedded为webapp的/WEB-INF/lib
JAR,那么也可以将它作为库引用(名称可以自由select;像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" />
库版本控制
另一个主要优点是可以将资源库版本控制应用于由您自己的Web应用程序提供的资源(这对于embedded到JAR中的资源不起作用)。 您可以使用\d+(_\d+)*
模式中的名称在库文件夹中创build直接的子子文件夹,以表示资源库版本。
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&v=1_0" /> <script type="text/javascript" src="/contextname/javax.faces.resource/js/script.js.xhtml?ln=default&v=1_0"></script> <img src="/contextname/javax.faces.resource/img/logo.png.xhtml?ln=default&v=1_0" alt="" />
所以,如果你已经编辑/更新了一些资源,那么你所要做的就是将版本文件夹复制或重命名为一个新的值。 如果您有多个版本文件夹,则根据数字sorting规则,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&v=1_1" /> <script type="text/javascript" src="/contextname/javax.faces.resource/js/script.js.xhtml?ln=default&v=1_1"></script> <img src="/contextname/javax.faces.resource/img/logo.png.xhtml?ln=default&v=1_1" alt="" />
这将迫使网页浏览器直接从服务器请求资源,而不是在第一次请求带有已更改参数的URL时,从caching中显示同名的资源。 这样,当用户需要检索更新的CSS / JS资源时,不需要进行硬刷新(Ctrl + F5等)。
请注意,对于JAR文件中包含的资源,库版本控制是不可能的。 你需要一个自定义的ResourceHandler
。 另请参见如何在jar中使用JSF版本控制资源 。
也可以看看:
- JSF资源版本控制
- JSF2静态资源caching
- 具有共享代码的多个JSF项目的结构
- JSF 2.0规范 – 第2.6章资源处理