开发者

Statically serve JSF component framework Javascript and CSS

I'm using RichFaces 3.3.1 and I am trying to figure out if there is a way to host the RichFaces CSS and Javascript as static resources from another web server like Apache or Nginx.

I've tried setting the org.ajax4jsf.RESOURCE_URI_PREFIX initialization parameter in th开发者_StackOverflowe web.xml to the other web server but the URI was still relative to the web application.

I also tried extracting the two Javascript files from the RichFaces jar

  • framework.pack.js
  • ui.pack.js

added the following to the web.xml.

<context-param>
    <param-name>org.richfaces.LoadScriptStrategy</param-name>
    <param-value>NONE</param-value>
</context-param>

and then in the xhtml included the Javascript files from the other server. Unfortunately many of the RichFaces components did not work after I did this.

Any other ideas how this might be done? Has anyone had any success doing this with JSF component frameworks?


I realize this isn't the answer in version 3.3 but if you can updgrade to Richfaces 4 final then they have this nifty little feature where you can add this to web.xml:

<context-param>
    <param-name>org.richfaces.staticResourceLocation</param-name>
    <param-value>#{resourceLocation}</param-value>
</context-param>

and then in META-INF you can include a static resource mapping file. The full path/filename is:

META-INF/richfaces/static-resource-mappings.properties

The contents of which are like:

jquery.js=https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js
richfaces.js=https://mystaticimageserver.com/img/richfaces.js

EDIT:

One other thing I do sometimes (In JSF 2) is just suppress the version of a resource that a library provider includes. Then I just create a static version and include it myself in my facelets template or wherever it makes sense in your project. It's less elegant but it works well if you are combining resources for performance or the like.

To do this I first define some customer renderers for Script and Stylesheet by adding this to faces-config.xml:

faces-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>

Then I add some files or Classes I want to suppress to 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);
        }
    }

}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜