防止在页面加载时向资源添加后缀 [英] Prevent suffix from being added to resources when page loads
问题描述
我有一个 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 背景图像上重新应用映射.因为我对加载资源没有问题.该网站有效,我们只是很难将网页与资源区分开来(因为我们只关注扩展名).
- 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).
Why this questions is different from others
当然你可能会问我为什么需要这个.好吧,我们正在将我们的应用程序转移到 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
,又名 className
是 null
因为我得到的错误是 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
/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屋!