Я понимаю, что это не ответ в версии 3.3, но если вы можете выполнить обновление до финальной версии Richfaces 4, то у них есть эта изящная маленькая функция, где вы можете добавить это в web.xml:
<context-param>
<param-name>org.richfaces.staticResourceLocation</param-name>
<param-value>#{resourceLocation}</param-value>
</context-param>
и затем в META-INF вы можете включить статический файл сопоставления ресурсов. Полный путь / имя файла:
META-INF / RichFaces / static-resource-mappings.properties
Содержимое которых:
jquery.js=https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js
richfaces.js=https://mystaticimageserver.com/img/richfaces.js
EDIT:
Еще одна вещь, которую я иногда делаю (в JSF 2), это просто подавление версии ресурса, который включает провайдер библиотеки. Затем я просто создаю статическую версию и сам включаю ее в свой шаблон Facelets или в любое другое место, где это имеет смысл в вашем проекте. Это менее элегантно, но хорошо работает, если вы объединяете ресурсы для повышения производительности или чего-то подобного.
Для этого я сначала определяю некоторые средства визуализации клиентов для скриптов и таблиц стилей, добавляя их в face-config.xml:
лица-config.xml
<render-kit>
<renderer>
<component-family>javax.faces.Output</component-family>
<renderer-type>javax.faces.resource.Script</renderer-type>
<renderer-class>com.davemaple.jsf.resource.ScriptRenderer</renderer-class>
</renderer>
<renderer>
<component-family>javax.faces.Output</component-family>
<renderer-type>javax.faces.resource.Stylesheet</renderer-type>
<renderer-class>com.davemaple.jsf.resource.StylesheetRenderer</renderer-class>
</renderer>
</render-kit>
Затем я добавляю некоторые файлы или классы, которые хочу подавить, в web.xml:
web.xml
<context-param>
<param-name>com.davemaple.jsf.resource.suppressedScriptResourceClasses</param-name>
<param-value></param-value>
</context-param>
<context-param>
<param-name>com.davemaple.jsf.resource.suppressedScripts</param-name>
<param-value>javax.faces:jsf.js :jquery.js :richfaces.js :richfaces-event.js :richfaces-base-component.js org.richfaces:message.js org.richfaces:richfaces-csv.js</param-value>
</context-param>
<context-param>
<param-name>com.davemaple.jsf.resource.suppressedStylesheetResourceClasses</param-name>
<param-value></param-value>
</context-param>
<context-param>
<param-name>com.davemaple.jsf.resource.suppressedStylesheets</param-name>
<param-value>org.richfaces:msg.ecss</param-value>
</context-param>
ScriptRenderer.java
/**
* A Customer ScriptRenderer that allows specific resources to be
* suppressed and managed manually (CDN, Static Resource Server, Combining resources)
*
*/
public class ScriptRenderer extends ScriptStyleBaseRenderer {
private static final String DELIMITER = " ";
private static final String LIBRARY_DELIMITER = ":";
private static final String SUPRESSED_CLASSES_INIT_PARAM = "com.davemaple.jsf.resource.suppressedScriptResourceClasses";
private final List<Class<?>> supressedClasses = new ArrayList<Class<?>>();
private static final String SUPRESSED_SCRIPTS_INIT_PARAM = "com.davemaple.jsf.resource.suppressedScripts";
private final List<String> suppressedScriptNames = new ArrayList<String>();
/**
* Constructor
*/
public ScriptRenderer() {
super();
String suppressedClasses =
FacesContext.getCurrentInstance().getExternalContext().getInitParameter(SUPRESSED_CLASSES_INIT_PARAM);
if (suppressedClasses != null
&& !suppressedClasses.isEmpty()) {
for (String suppressedClassString : suppressedClasses.split(DELIMITER)) {
try {
this.supressedClasses.add(Class.forName(suppressedClassString));
} catch (ClassNotFoundException ex) {
}
}
}
String suppressedScripts =
FacesContext.getCurrentInstance().getExternalContext().getInitParameter(SUPRESSED_SCRIPTS_INIT_PARAM);
if (suppressedScripts != null
&& !suppressedScripts.isEmpty()) {
for (String suppressedScript : suppressedScripts.split(DELIMITER)) {
this.suppressedScriptNames.add(suppressedScript);
}
}
}
/**
* Returns a boolean indicating if the component should
* be encoded and thus rendered
*
* @param component
* @return isSuppressed
*/
protected boolean isSuppressed(UIComponent component) {
if (this.supressedClasses.contains(component.getClass())) {
return true;
}
if (component.getAttributes().containsKey("name")
&& component.getAttributes().containsKey("library")) {
String key = component.getAttributes().get("library") + LIBRARY_DELIMITER + component.getAttributes().get("name");
if (this.suppressedScriptNames.contains(key)) {
return true;
}
}
if (component.getAttributes().containsKey("name")
&& !component.getAttributes().containsKey("library")) {
String key = LIBRARY_DELIMITER + component.getAttributes().get("name");
if (this.suppressedScriptNames.contains(key)) {
return true;
}
}
return false;
}
@Override
protected void startElement(ResponseWriter writer, UIComponent component) throws IOException {
writer.startElement("script", component);
writer.writeAttribute("type", "text/javascript", "type");
}
@Override
protected void endElement(ResponseWriter writer) throws IOException {
writer.endElement("script");
}
@Override
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
if (!this.isSuppressed(component)) {
super.encodeBegin(context, component);
}
}
@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
if (!this.isSuppressed(component)) {
Map<String, Object> attributes = component.getAttributes();
Map<Object, Object> contextMap = context.getAttributes();
String name = (String) attributes.get("name");
String library = (String) attributes.get("library");
String key = name + library;
if (null == name) {
return;
}
// Ensure this script is not rendered more than once per request
if (contextMap.containsKey(key)) {
return;
}
contextMap.put(key, Boolean.TRUE);
// Special case of scripts that have query strings
// These scripts actually use their query strings internally, not
// externally
// so we don't need the resource to know about them
int queryPos = name.indexOf("?");
String query = null;
if (queryPos > -1 && name.length() > queryPos) {
query = name.substring(queryPos + 1);
name = name.substring(0, queryPos);
}
Resource resource = context.getApplication().getResourceHandler()
.createResource(name, library);
ResponseWriter writer = context.getResponseWriter();
this.startElement(writer, component);
String resourceSrc;
if (resource == null) {
resourceSrc = "RES_NOT_FOUND";
} else {
resourceSrc = resource.getRequestPath();
if (query != null) {
resourceSrc = resourceSrc
+ ((resourceSrc.indexOf("?") > -1) ? "+" : "?") + query;
}
}
writer.writeURIAttribute("src", resourceSrc, "src");
this.endElement(writer);
super.encodeEnd(context, component);
}
}
}
ScriptRenderer.java
/**
* A Customer StylesheetRenderer that allows specific resources to be
* suppressed and managed manually (CDN, Static Resource Server, Combining resources)
*
*/
public class StylesheetRenderer extends ScriptStyleBaseRenderer {
private static final String DELIMITER = " ";
private static final String LIBRARY_DELIMITER = ":";
private static final String SUPRESSED_CLASSES_INIT_PARAM = "com.davemaple.jsf.resource.suppressedStylesheetResourceClasses";
private final List<Class<?>> supressedClasses = new ArrayList<Class<?>>();
private static final String SUPPRESSED_STYLESHEETS_INIT_PARAM = "com.davemaple.jsf.resource.suppressedStylesheets";
private final List<String> suppressedStylesheets = new ArrayList<String>();
/**
* Constructor
*/
public StylesheetRenderer() {
super();
String suppressedClasses =
FacesContext.getCurrentInstance().getExternalContext().getInitParameter(SUPRESSED_CLASSES_INIT_PARAM);
if (suppressedClasses != null
&& !suppressedClasses.isEmpty()) {
for (String suppressedClassString : suppressedClasses.split(DELIMITER)) {
try {
this.supressedClasses.add(Class.forName(suppressedClassString));
} catch (ClassNotFoundException ex) {
}
}
}
String suppressedStylesheets =
FacesContext.getCurrentInstance().getExternalContext().getInitParameter(SUPPRESSED_STYLESHEETS_INIT_PARAM);
if (suppressedStylesheets != null
&& !suppressedStylesheets.isEmpty()) {
for (String suppressedStylesheet : suppressedStylesheets.split(DELIMITER)) {
this.suppressedStylesheets.add(suppressedStylesheet);
}
}
}
/**
* Returns a boolean indicating if the component should
* be encoded and thus rendered
*
* @param component
* @return isSuppressed
*/
protected boolean isSuppressed(UIComponent component) {
if (this.supressedClasses.contains(component.getClass())) {
return true;
}
if (component.getAttributes().containsKey("name")
&& component.getAttributes().containsKey("library")) {
String key = component.getAttributes().get("library") + LIBRARY_DELIMITER + component.getAttributes().get("name");
if (this.suppressedStylesheets.contains(key)) {
return true;
}
}
if (component.getAttributes().containsKey("name")
&& !component.getAttributes().containsKey("library")) {
String key = LIBRARY_DELIMITER + component.getAttributes().get("name");
if (this.suppressedStylesheets.contains(key)) {
return true;
}
}
return false;
}
@Override
protected void startElement(ResponseWriter writer, UIComponent component)
throws IOException {
writer.startElement("style", component);
writer.writeAttribute("type", "text/css", "type");
}
@Override
protected void endElement(ResponseWriter writer) throws IOException {
writer.endElement("style");
}
@Override
protected String verifyTarget(String toVerify) {
return "head";
}
@Override
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
if (!this.isSuppressed(component)) {
super.encodeBegin(context, component);
}
}
@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
if (!this.isSuppressed(component)) {
Map<String, Object> attributes = component.getAttributes();
Map<Object, Object> contextMap = context.getAttributes();
String name = (String) attributes.get("name");
String library = (String) attributes.get("library");
String key = name + library;
if (null == name) {
return;
}
// Ensure this stylesheet is not rendered more than once per request
if (contextMap.containsKey(key)) {
return;
}
contextMap.put(key, Boolean.TRUE);
Resource resource = context.getApplication().getResourceHandler()
.createResource(name, library);
ResponseWriter writer = context.getResponseWriter();
writer.startElement("link", component);
writer.writeAttribute("type", "text/css", "type");
writer.writeAttribute("rel", "stylesheet", "rel");
writer.writeURIAttribute("href",
((resource != null) ? resource.getRequestPath()
: "RES_NOT_FOUND"), "href");
writer.endElement("link");
super.encodeEnd(context, component);
}
}
}