我花了一些时间阅读BalusC的answer on this question,但我似乎无法将这些知识运用到我的情况中。我也得到了 ViewExpiredException ,但仅限于某些情况。
我的页面由 @ViewScoped bean支持,并使用两个 p:layoutUnits 来显示ap:tree(west),其中包含中心窗格中文件夹的内容。选择树中的文件夹会触发AJAX事件,以使用所选文件夹的内容更新中心窗格。 JSF的骨架如下:
<p:layout id="workLayout">
<p:layoutUnit id="paneTree"
position="west"
size="200">
<h:form id="treeForm">
<p:tree value="#{workspace.listTree}"
var="node"
dynamic="true"
selectionMode="single"
>
<p:ajax event="select"
listener="#{workspace.onNodeSelect}"
update="panelData"
/>
<p:treeNode>
<h:outputText value="#{node.name}" />
</p:treeNode>
</p:tree>
</h:form>
</p:layoutUnit>
<p:layoutUnit id="paneData"
position="center"
resizable="true">
<h:panelGroup id="panelData" >
<h:form id="formData" rendered="#{workspace.selected ne null}">
<h2>#{workspace.selected.name}: #{workspace.selected.title}</h2>
<p>
<div id="divImages"
style="width: 49%; height: 99%; float: right">
<p:panel rendered="#{empty workspace.listImages}">
<p>No Images In This List.</p>
</p:panel>
<ui:repeat value="#{workspace.listImages}"
var="img"
>
<p>
#{img.name}: #{img.title}
</p>
<img src="#{workspace.getUrl(img)}"
style="max-width: 250px"
/>
<hr/>
</ui:repeat>
</div>
<div id="divDocs"
style="width: 49%; height: 99%; float: left">
<p:dataTable id="tableFiles"
value="#{workspace.listDocuments}"
>
<p:column ...
<p:column ...
<p:column ...
</p:dataTable>
</div>
</p>
</h:form>
</h:panelGroup>
</p:layoutUnit>
当您选择包含少量图像的文件夹时,会出现问题。只需10个或更少的图像就足以产生问题。这会导致 ui:repeat 元素呈现 img 标记的数量,每个标记都带有一个加载图像的网址。
URL触发应用程序中与同一CDI域相同的Servlet,以便它可以注入与托管bean相同的资源。 Servlet只响应具有MIME类型和数据的响应头。但是,每个 img 访问都会创建一个新的@SessionScoped bean - 与JSF页面使用的相同。它没有获得与JSF页面相同的实例,并且各种 img 访问也不共享它们之间的会话bean。每次访问都会生成一个新访问权限。
Servlet看起来像这样:
@WebServlet(name = "Obj", urlPatterns = {"/obj/*"})
public class Obj extends HttpServlet {
@Inject ProtoObjectControl poc;
@Inject UserSession us;
UserSession 是 @SessionScoped 对象,其中包含登录信息(由于它始终生成新的登录信息而未登录)以及各种实用程序(如日志功能)。 ProtoObjectControl 是一个DAO对象,用于获取要显示的图像。
最终结果是执行显示的页面最终因ViewExpiredException而崩溃。我认为这是因为会话爆炸正在消耗正在挖掘的资源。如果我取出 img 标记并运行该页面, ViewExpiredException 永远不会出现,并且该页面的工作方式与Mac Finder或Windows文件资源管理器一样可靠。
那么有什么方法可以解释为什么会发生这种情况并围绕它进行设计?我希望对显示屏中可能出现的图像数量没有限制。理想情况下,我希望让Servlet访问与JSF页面相同的 UserSession bean - 它毕竟是从同一个客户端访问的 - 但也许这是不可能的。还有其他方法吗?
答案 0 :(得分:0)
基于BalusC上面的输入,我认为这个问题已经解决了。错误在我的代码中如下:
public String getBaseUrl() {
if (baseURL != null) return baseURL;
FacesContext fc = FacesContext.getCurrentInstance();
if (fc == null) return "";
ExternalContext ec = fc.getExternalContext();
baseURL = String.format("http://%s:%d/%s/",
ec.getRequestServerName(),
ec.getRequestServerPort(),
ec.getRequestContextPath());
return baseURL;
}
使用此方法可生成以下格式的URL:
http://localhost:8080//MyApp/obj?id=nnn
问题当然是应用程序上下文路径之前的双斜杠。更正此结果不会创建新会话,因为容器正确地将GET请求与作为同一会话的一部分的servlet相关联。
虽然该程序现在有效,但有两个未解决的问题:
在所有无关会话中,每个会话都获得了一个具有不同值的JSESSIONID cookie。但是使用Firebug我找不到来自服务器的任何相应的set-cookie。那些价值来自哪里?
看起来这种性质的JSF应用程序 - 您使用Servlet来提供填充页面的对象 - 要求Servlet在与主应用程序相同的会话上下文中执行。无法解释(至少对我来说)问题是为什么Faclets页面崩溃只是因为 src 标记中的URL格式错误并且生成了无关的会话?如果URL正在寻址不同的服务器(例如图像存储服务),我不指望它。我也希望Glassfish可以毫无问题地处理数千个会话。
希望有一天这篇文章可以帮助人们摆脱这个特殊的陷阱。