防止页面加载时将后缀添加到资源中

2024-01-10

我有一个 JSF2 应用程序正在运行并且工作没有问题。我在 JSF 中遇到的问题与资源包有关。所有资源都有.xhtml后缀附加到它。所以main.css变成main.css.xhtml当在浏览器中加载时。我想拥有它,所以.xhtml不附加到资源(不介意页面本身)。

有什么方法可以让我们NOT have .xhtml附加到资源中?

理想情况下,我不必更改网站的内部运作方式。我在下面列出了一些想法,但我不得不说我不太喜欢这些。希望在某个地方找到解决方案?

我在 Glassfish 3.1.2.2 上使用 Majorra v.2.1.17。

当前 Faces Servlet 加载为 web.xml(已更新)

<servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/javax.faces.resource/*</url-pattern>
</servlet-mapping>

为什么这个问题与其他问题不同

  • 带 CDN 的 JSF 2 资源? https://stackoverflow.com/questions/8067904/jsf-2-resources-with-cdn?rq=1。我不想将我的资源放在 CDN 上,而是让我的资源保留在我的服务器上,但被推送到 CDN。
  • 更改资源 URL 的 /javax.faces.resource 前缀 https://stackoverflow.com/questions/7354464/change-javax-faces-resource-prefix-of-resource-urls?rq=1。我不想更改前缀。我只想更改后缀。我想要<link type="text/css" rel="stylesheet" href="/javax.faces.resource/main03.css.xhtml?ln=styles">成为 :<link type="text/css" rel="stylesheet" href="/javax.faces.resource/main03.css?ln=styles"> WITHOUT the .xhtml扩大。
  • 将 JSF 前缀更改为后缀映射迫使我在 CSS 背景图像上重新应用映射 https://stackoverflow.com/questions/6835499/changing-jsf-prefix-to-suffix-mapping-forces-me-to-reapply-the-mapping-on-css-ba。因为我加载资源没有问题。该网站工作正常,我们只是很难区分网页和资源(因为我们只查看扩展)。

推理

当然,您可能会问我为什么需要这个。好吧,我们正在将我们的应用程序移至由 Akamai CDN 提供服务。

我们在网站集成方面遇到的问题是我们试图在边缘服务器上缓存静态内容。这是通过匹配文件扩展名(即:.js、.doc、.png、css 等)来完成的。我们无法匹配xhtml因为这将缓存所有页面以及静态内容。这会导致会话等问题。

尝试的解决方案

根据 BalusC 的回答,我已经按照建议实现了资源处理程序。我不会在这里重写代码,因为它在下面的答案中。

但是,我在加载复合组件时遇到错误。我收到这样的错误:

WARNING: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception
java.lang.NullPointerException
    at com.sun.faces.application.ApplicationImpl.createComponent(ApplicationImpl.java:975)
    at com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.createComponent(CompositeComponentTagHandler.java:162)
    at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.createComponent(ComponentTagHandlerDelegateImpl.java:494)
    at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:169)
...

复合组件已正确加载,因为如果我“取消注册”新组件ResourceHandler我们刚刚创建的它将加载。堆栈跟踪使我相信它正在尝试在 java 类中查找该组件,而不是在资源中查找它。根据grepcode这将在最后一行(975)发生错误:

String packageName = componentResource.getLibraryName();
String className = componentResource.getResourceName();
className = packageName + '.' + className.substring(0, className.lastIndexOf('.'));

这意味着resourceName, aka className is null因为我收到的错误是java.lang.NullPointerException。我似乎不知道如何/在哪里ResourceHandler被称为相对于复合组件。有帮助解决最后一个问题吗?


这可以通过自定义实现ResourceHandler http://docs.oracle.com/javaee/6/api/javax/faces/application/ResourceHandler.html返回值createResource() http://docs.oracle.com/javaee/6/api/javax/faces/application/ResourceHandler.html#createResource%28java.lang.String,%20java.lang.String%29 a Resource http://docs.oracle.com/javaee/6/api/javax/faces/application/Resource.html这又返回一个“未映射”的 URLResource#getRequestPath() http://docs.oracle.com/javaee/6/api/javax/faces/application/Resource.html#getRequestPath%28%29。只需要添加默认的JSF资源前缀即可/javax.faces.resource/* to the <url-pattern>的清单FacesServlet映射以便无论如何都能触发它。

此外,您需要覆盖isResourceRequest() http://docs.oracle.com/javaee/6/api/javax/faces/application/ResourceHandler.html#isResourceRequest%28javax.faces.context.FacesContext%29检查 URL 是否以 JSF 资源前缀开头以及handleResourceRequest() http://docs.oracle.com/javaee/6/api/javax/faces/application/ResourceHandler.html#handleResourceRequest%28javax.faces.context.FacesContext%29定位并传输正确的资源。

总之,这应该做:

public class UnmappedResourceHandler extends ResourceHandlerWrapper {

    private ResourceHandler wrapped;

    public UnmappedResourceHandler(ResourceHandler wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public Resource createResource(final String resourceName, final String libraryName) {
        final Resource resource = super.createResource(resourceName, libraryName);

        if (resource == null) {
            return null;
        }

        return new ResourceWrapper() {

            @Override
            public String getRequestPath() {
                ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
                String mapping = externalContext.getRequestServletPath();

                if (externalContext.getRequestPathInfo() == null) {
                    mapping = mapping.substring(mapping.lastIndexOf('.'));
                }

                String path = super.getRequestPath();

                if (mapping.charAt(0) == '/') {
                    return path.replaceFirst(mapping, "");
                }
                else if (path.contains("?")) {
                    return path.replace(mapping + "?", "?");
                }
                else {
                    return path.substring(0, path.length() - mapping.length());
                }
            }

            @Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2).
            public String getResourceName() {
                return resource.getResourceName();
            }

            @Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2).
            public String getLibraryName() {
                return resource.getLibraryName();
            }

            @Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2).
            public String getContentType() {
                return resource.getContentType();
            }

            @Override
            public Resource getWrapped() {
                return resource;
            }
        };
    }

    @Override
    public boolean isResourceRequest(FacesContext context) {
        return ResourceHandler.RESOURCE_IDENTIFIER.equals(context.getExternalContext().getRequestServletPath());
    }

    @Override
    public void handleResourceRequest(FacesContext context) throws IOException {
        ExternalContext externalContext = context.getExternalContext();
        String resourceName = externalContext.getRequestPathInfo();
        String libraryName = externalContext.getRequestParameterMap().get("ln");
        Resource resource = context.getApplication().getResourceHandler().createResource(resourceName, libraryName);

        if (resource == null) {
            super.handleResourceRequest(context);
            return;
        }

        if (!resource.userAgentNeedsUpdate(context)) {
            externalContext.setResponseStatus(HttpServletResponse.SC_NOT_MODIFIED);
            return;
        }

        externalContext.setResponseContentType(resource.getContentType());

        for (Entry<String, String> header : resource.getResponseHeaders().entrySet()) {
            externalContext.setResponseHeader(header.getKey(), header.getValue());
        }

        ReadableByteChannel input = null;
        WritableByteChannel output = null;

        try {
            input = Channels.newChannel(resource.getInputStream());
            output = Channels.newChannel(externalContext.getResponseOutputStream());

            for (ByteBuffer buffer = ByteBuffer.allocateDirect(10240); input.read(buffer) != -1; buffer.clear()) {
                output.write((ByteBuffer) buffer.flip());
            }
        }
        finally {
            if (output != null) try { output.close(); } catch (IOException ignore) {}
            if (input != null) try { input.close(); } catch (IOException ignore) {}
        }
    }

    @Override
    public ResourceHandler getWrapped() {
        return wrapped;
    }

}

注册如下faces-config.xml:

<application>
    <resource-handler>com.example.UnmappedResourceHandler</resource-handler>
</application>

延长FacesServletURL 模式与ResourceHandler.RESOURCE_IDENTIFIER:

<servlet-mapping>
    <servlet-name>facesServlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
    <url-pattern>/javax.faces.resource/*</url-pattern>
</servlet-mapping>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

防止页面加载时将后缀添加到资源中 的相关文章

随机推荐