我有一个正在运行且工作正常的JSF2应用程序。我在JSF中遇到的问题是资源束。所有资源都有.xhtml
后缀。因此main.css
成为main.css.xhtml
在浏览器中加载时。我想拥有它,这样.xhtml
就不会添加到资源中(不要在乎页面本身)。
是否有一个地方,我们可以一个方式 不 具有.xhtml
附加的资源呢?
理想情况下,我不必更改网站的内部运作方式。我在下面列出了一些想法,但我必须说我不太喜欢这些想法。希望在某处找到解决方案?
我在Glassfish 3.1.2.2上使用Majorra v.2.1.17。
<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>
当然,您可能会问我为什么需要这个。好吧,我们正在将我们的应用程序移交给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
,又名className
是null
因为我得到的错误是java.lang.NullPointerException
。我似乎无法弄清楚ResourceHandler
相对于复合组件的调用方式/位置。找出最后一个问题有帮助吗?
这是可行的具有自定义ResourceHandler
它返回createResource()
一个Resource
这反过来又返回上一个“未映射”的URL
Resource#getRequestPath()
。您仅需要将默认的JSF资源前缀添加/javax.faces.resource/*
到映射<url- pattern>
列表中FacesServlet
,以便无论如何都能触发它。
此外,您需要重写isResourceRequest()
以检查URL是否以JSF资源前缀开头,并且还handleResourceRequest()
需要定位和流传输正确的资源。
总而言之,这应该做到:
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>
通过以下方式扩展FacesServlet
URL模式ResourceHandler.RESOURCE_IDENTIFIER
:
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
<url-pattern>/javax.faces.resource/*</url-pattern>
</servlet-mapping>
问题内容: 我有一个PHP include,它需要一段时间才能加载,因为PHP必须获取很多数据。我不想放慢整个网页的加载,以等待包含此内容,那么如何使用ajax加载该包含内容呢?我不希望通过单击按钮来触发Ajax,而只是希望它在页面加载时加载包含,因此,如果您查看下面的示例,则会在显示内含代码的同时显示“更多HTML内容”。 php仍在加载中。 问题答案: 如果您使用的是jQuery,则可以使用他
问题内容: 如果不使用iframe,则可以加载以下内容: 与外部站点,例如somesitehere.com 页面何时加载?-我知道如何从文件加载内容,但是不确定如何加载整个网站吗? 非常感谢, 问题答案: 无需专门的操作就可以做到。由于标题中提到了jQuery,因此使用了jQuery。
那么,除非点击下一个或上一个按钮,否则有没有办法防止twitter引导转盘在页面加载时自动滑动? 谢谢
我在页面加载时使用了CAPTCHA,但由于某些安全原因,它被阻塞了。 我面对这个问题: 我使用了以下JavaScript和meta标记:
问题内容: 当Django启动时,如何从mysql数据库加载资源并将其放入内存(Redis)中,以供所有应用程序使用。 我已经看到了这个 [https://docs.djangoproject.com/en/dev/ref/applications/#django.apps.AppConfig.ready] 但是他们提到在ready函数中不使用db连接。我的网站启动时该怎么办? 我还可以在read
问题内容: 有没有办法用javascript / jquery防止图像加载?我正在从带有图像的html列表构建幻灯片。因此,我想收集所有src数据,然后阻止加载图像。因此,稍后当用户真正需要图像时,我便会加载它。 我在Google上找到了一些延迟加载脚本,但找不到阻止图像加载的方式。 提前致谢。 Edit1: 从答案看来,不可能使用javascript来防止图像加载。 这是一个执行延迟加载的脚本。