由Servlet生成的会话

时间:2015-07-06 04:45:49

标签: jsf jsf-2.2

我花了一些时间阅读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 - 它毕竟是从同一个客户端访问的 - 但也许这是不可能的。还有其他方法吗?

1 个答案:

答案 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相关联。

虽然该程序现在有效,但有两个未解决的问题:

  1. 在所有无关会话中,每个会话都获得了一个具有不同值的JSESSIONID cookie。但是使用Firebug我找不到来自服务器的任何相应的set-cookie。那些价值来自哪里?

  2. 看起来这种性质的JSF应用程序 - 您使用Servlet来提供填充页面的对象 - 要求Servlet在与主应用程序相同的会话上下文中执行。无法解释(至少对我来说)问题是为什么Faclets页面崩溃只是因为 src 标记中的URL格式错误并且生成了无关的会话?如果URL正在寻址不同的服务器(例如图像存储服务),我不指望它。我也希望Glassfish可以毫无问题地处理数千个会话。

  3. 希望有一天这篇文章可以帮助人们摆脱这个特殊的陷阱。