防止在页面加载时向资源添加后缀 [英] Prevent suffix from being added to resources when page loads

查看:20
本文介绍了防止在页面加载时向资源添加后缀的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a JSF2 application running and working no problem. The issue I am having with JSF is with the resource bundle. All resources have the .xhtml suffix appended to it. So main.css becomes main.css.xhtml when loaded in the browser. I would like to have it so the .xhtml isn't apended to the resources (don't mind about the pages themselves).

有没有办法让我们.xhtml 附加到资源中?

Is there a way where we can NOT have .xhtml appended to resources?

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

I would ideally not have to change the internal workings of the site. I have listed ideas below, but I have to say I don't really like these. Hoping for a solution somewhere?

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

I am using Majorra v.2.1.17 on Glassfish 3.1.2.2.

<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 资源?.我不希望将我的资源放在 CDN 上,而是希望将我的资源保留在我的服务器上但被推送到 CDN.
  • 更改/javax.faces.resource 前缀资源网址.我不想更改前缀.我只想更改后缀.我希望 <link type="text/css" rel="stylesheet" href="/javax.faces.resource/main03.css.xhtml?ln=styles"> 变成: WITHOUT.xhtml 扩展名.
  • 将 JSF 前缀更改为后缀映射迫使我在 CSS 背景图像上重新应用映射.因为我对加载资源没有问题.该网站有效,我们只是很难将网页与资源区分开来(因为我们只关注扩展名).
  • Why this questions is different from others

    • JSF 2 resources with CDN?. I am not looking to place my resources on a CDN, but to have my resources stay on my server but are pushed towards a CDN.
    • Change /javax.faces.resource prefix of resource URLs. I don't want to change the prefix. I want only to change the suffix. I would want <link type="text/css" rel="stylesheet" href="/javax.faces.resource/main03.css.xhtml?ln=styles"> to become : <link type="text/css" rel="stylesheet" href="/javax.faces.resource/main03.css?ln=styles"> WITHOUT the .xhtml extension.
    • Changing JSF prefix to suffix mapping forces me to reapply the mapping on CSS background images. Since I have no issue with loading the resources. The site works, we are simply having a hard time differrentiating a webpage from a resource (Since we are looking at the extention alone).
    • 当然你可能会问我为什么需要这个.好吧,我们正在将我们的应用程序转移到 Akamai CDN 上.

      Sure you might be asking me why I need this. Well, we are moving our application to be served by the Akamai CDN.

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

      The issue we are having with the integration of the site is that we are trying to cache static content on the edge servers. This is done by matching file extensions (ie: .js, .doc, .png, css, etc). We cannot match xhtml because this would be caching all pages as well as static content. Which by that would cause problems with sessions and such.

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

      In line with the answer by BalusC, I have implemented the resource handler as suggested. I will not rewrite code here, since it is in answer below.

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

      However, I am getting an error when loading composite components. I am getting an error as such :

      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) 处:

      Composite component is loaded correctly because if I "unregister" the new ResourceHandler we just created it will load. The stack trace leads me to believe that it is trying to find this component in a java class, instead of finding it in the resources. According to grepcode this would be at this last line (975) where the error happens :

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

      意味着 resourceName,又名 classNamenull 因为我得到的错误是 java.lang.NullPointerException.我似乎无法弄清楚 ResourceHandler 是如何/在何处被称为相对于复合组件的.对解决最后一个问题有帮助吗?

      Meaning that the resourceName, aka className is null since the error I am getting is java.lang.NullPointerException. I can't seem to figure out how/where the ResourceHandler is called vis-a-vis a composite component. Any help figuring out this last issue?

      推荐答案

      这可以通过自定义 ResourceHandler 返回 createResource() a Resource 反过来在 Resource#getRequestPath().你只需要在FacesServlet列表中添加默认的JSF资源前缀/javax.faces.resource/*> 映射以便无论如何都能触发它.

      This is doable with a custom ResourceHandler which returns in createResource() a Resource which in turn returns an "unmapped" URL on Resource#getRequestPath(). You only need to add the default JSF resource prefix /javax.faces.resource/* to the <url-pattern> list of the FacesServlet mapping in order to get it to be triggered anyway.

      此外,您需要覆盖 isResourceRequest() 检查 URL 是否以 JSF 资源前缀以及 handleResourceRequest() 以定位和传输正确的资源.

      Further, you need to override isResourceRequest() to check if the URL starts with the JSF resource prefix and also the handleResourceRequest() to locate and stream the proper resource.

      总而言之,这应该是:

      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>
      

      使用 ResourceHandler.RESOURCE_IDENTIFIER 扩展 FacesServlet URL 模式:

      Extend the FacesServlet URL pattern with ResourceHandler.RESOURCE_IDENTIFIER:

      <servlet-mapping>
          <servlet-name>facesServlet</servlet-name>
          <url-pattern>*.xhtml</url-pattern>
          <url-pattern>/javax.faces.resource/*</url-pattern>
      </servlet-mapping>
      

      这篇关于防止在页面加载时向资源添加后缀的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆