【问题标题】:Why would setting an attribute in the session from a Java servlet sometimes fail?为什么从 Java servlet 在会话中设置属性有时会失败?
【发布时间】:2011-07-27 05:27:37
【问题描述】:

我正在开发一个相当简单的 Web 应用程序,它使用 JSP 和 Java servlet,在 tomcat 上运行。我已经能够在 servlet 的会话中设置属性,以便将信息传递给 JSP,然后将这些信息呈现给用户。我已经使用不同类的几个不同对象完成了此操作,并且效果很好。突然,当我设置一种特定类型的对象(包含配置信息)时,该属性根本没有出现在 JSP 中。我设置的其他属性仍然存在,但配置对象完全丢失。我打印了属性名称列表,但我使用的名称甚至不存在(尽管我设置的其他属性的其他名称存在)。

是什么原因造成的?我的配置类没有什么不同或奇怪的。我真的很感激关于什么样的事情可能导致这种行为的任何想法。我用谷歌搜索和搜索,但找不到任何东西。

ETA:如果重要的话,属性的名称是“配置”。我找不到任何关于保留字或任何内容的内容...我在 servlet 中将此属性设置为与“用户”等其他一些功能相同的功能。然后我重定向到一个试图获取用户和配置的 JSP。所以一切都在同时进行。用户很好,而配置甚至没有出现在属性名称列表中。

ETA2:以下是日志中不断发生的异常:

java.lang.Exception
    at pms.SessionListener.printStackTrace(Unknown Source)
    at pms.SessionListener.attributeAdded(Unknown Source)
    at org.apache.catalina.session.StandardSession.setAttribute(StandardSession.java:1498)
    at org.apache.catalina.session.StandardSession.setAttribute(StandardSession.java:1390)
    at org.apache.catalina.session.StandardSessionFacade.setAttribute(StandardSessionFacade.java:154)
    at PMS.getTaskInfo(Unknown Source)
    at PMS.doGet(Unknown Source)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:306)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:108)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:558)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:379)
    at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:282)
    at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:357)
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:1687)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

【问题讨论】:

  • 我昨天回答了一个类似的问题。您可能会发现它很有用。 stackoverflow.com/questions/5495361/…
  • 谢谢,但这根本不是问题。会话绝对存在,我可以同时从 JSP 中的会话中检索在 servlet 中设置的其他属性。这只是一个不会显示的特定属性。我发现会话中的很多东西都不存在,但不知道为什么一个属性在其他属性起作用时不起作用。
  • 我明白了。好吧,然后我发布了一个答案:)
  • 请实现 BalusC 或我自己推荐的监听器,并让使用者知道结果。

标签: java jsp tomcat servlets


【解决方案1】:

出现问题的可能性有很多。

  • 可能有两个不同的会话。
  • 可能有一些代码会从会话中删除您的配置对象。
  • 其他?

您可以通过以下方式进行测试,看看到底发生了什么。

您可以实现两个单独的侦听器接口来侦听特定的会话事件:javax.servlet.http.HttpSessionListenerjavax.servlet.http.HttpSessionAttributeListener

我将使用一个类来实现这两个接口,该类将记录每个事件期间发生的事情以及事件来自哪个会话。

您应该能够轻松地将您的侦听器添加到您的 web.xml 文件中,以便它们实际上会被 tomcat 设置为会话的侦听器。

编辑

这是一个可以作为会话监听器放入 web.xml 的类。 BalusC 和我自己都建议您尝试这种方法来调试问题。如果您在设置“配置”属性的方式中发现任何有趣的地方,请幽默地告诉我们?

import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class SessionListener implements HttpSessionListener, HttpSessionAttributeListener, HttpSessionBindingListener, HttpSessionActivationListener {

public void valueBound(HttpSessionBindingEvent event) {
    System.out.println("valueBound: " + event.getName() + " : " + event.getValue());
    System.out.println("  session: " + event.getSession().getId());
    this.printStackTrace();
}

public void valueUnbound(HttpSessionBindingEvent event) {
    System.out.println("valueUnbound: " + event.getName() + " : " + event.getValue());
    System.out.println("  session: " + event.getSession().getId());
    this.printStackTrace();
}

public void attributeAdded(HttpSessionBindingEvent event) {
    System.out.println("attributeAdded: " + event.getName() + " : " + event.getValue());
    System.out.println("  session: " + event.getSession().getId());
    this.printStackTrace();
}

public void attributeRemoved(HttpSessionBindingEvent event) {
    System.out.println("attributeRemoved: " + event.getName() + " : " + event.getValue());
    System.out.println("  session: " + event.getSession().getId());
    this.printStackTrace();
}

public void attributeReplaced(HttpSessionBindingEvent event) {
    System.out.println("attributeReplaced: " + event.getName() + " : " + event.getValue());
    System.out.println("  session: " + event.getSession().getId());
    this.printStackTrace();
}

public void sessionCreated(HttpSessionEvent event) {
    System.out.println("sessionCreated: " + event.getSession().getId());
    this.printStackTrace();
}

public void sessionDestroyed(HttpSessionEvent event) {
    System.out.println("sessionDestroyed: " + event.getSession().getId());
    this.printStackTrace();
}

public void sessionDidActivate(HttpSessionEvent event) {
    System.out.println("sessionDidActivate: " + event.getSession().getId());
    this.printStackTrace();
}

@Override
public void sessionWillPassivate(HttpSessionEvent event) {
    System.out.println("sessionWillPassivate: " + event.getSession().getId());
    this.printStackTrace();
}

private void printStackTrace() {
    try {
        if (true) {
            throw new Exception();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
}

请将上述类添加到您的代码中,然后将以下内容添加到您的过滤器映射和 servlet 映射之间的 web.xml 文件中:

<listener>
    <listener-class><your.package.name>SessionListener</listener-class>
</listener>

【讨论】:

  • 你能解释一下你所说的两个不同的会话是什么意思吗?我不确定在这种情况下是否可行。在 Java servlet 中,我同时在会话中设置了几个不同的属性(对 servlet 的相同调用)。然后在一个 JSP 中,我从会话中读取这些不同的属性,再次同时读取这些不同的属性,但其中一个没有设置。在这种情况下是否可能有两个不同的会话?
  • 更新了我的答案,为您提供调试正在发生的事情所需的确切代码。在您使用上述代码查看会话发生了什么之前,很可能没有人能够给您一个合理的答案。您的输出将非常冗长,但您应该能够搜索“配置”和首次添加“配置”时使用的会话 ID。
  • 感谢您提供准确的代码。我实际上打算自己实现监听器,我发誓,我只需要离开我的电脑一会儿。无论如何,我看到配置属性被删除,但我不知道如何或为什么。会话始终保持不变。日志里有一堆异常,估计不正常吧?
  • 谢谢,使用您提供的代码,我终于找到了问题所在。我确实用空值覆盖了,尽管我仍然不知道为什么有问题的对象是空的..
  • 发生这种情况(空对象是......)。拥有像这些听众这样的工具真的很棒。祝你好运。
【解决方案2】:

根据问题上的cmets:

会话绝对存在,我可以同时从 JSP 中的会话中检索在 servlet 中设置的其他属性。这只是一个不会显示的特定属性。我发现会话中的很多东西都不存在,但不知道为什么一个属性在其他属性时不起作用。

然后 something 删除或取消了该属性。

session.removeAttribute("name");

session.setAttribute("name", null);

甚至在 JSP 中

<c:set var="name" value="${null}" scope="session" />

或者是你自己设置了null而不是完全值得的对象。

为了更好地确定一个和另一个,我让属性实现 HttpSessionBindingListener 并将堆栈转储到 valueUnbound()

public class Foo implements HttpSessionBindingListener {

    @Override 
    public void valueBound(HttpSessionBindingEvent event) {
        System.out.println("Value bound"); // Logger?
    }

    @Override 
    public void valueUnbound(HttpSessionBindingEvent event) {
        System.err.println("Value unbound"); // Logger?
        Thread.dumpStack();
    }

    // ...
}

【讨论】:

  • 我绝对不会在任何地方将其设置为 null (正如我所说,这是一个非常简单的应用程序;没有足够的代码让我没有注意到这一点)。我刚刚尝试将属性设置为字符串“testing”,但它仍然没有出现在属性名称列表中。
  • 您不是将HttpSession 分配为应用程序范围的实例变量并在不同的会话上使用浏览器来测试它吗?您应该通过request.getSession().setAttribute("foo", "bar") 设置它,并且您应该通过${foo} 或更明确地通过JSP 中的${sessionScope.foo} 或只是在servlet 中的request.getSession().getAttribute("foo") 访问它。
  • 我在使用HttpSession session = request.getSession(true); session.setAttribute("configuration", "testing");,然后在稍后使用session.setAttribute("user", user),并在JSP 中使用session.getAttribute("configuration")session.getAttribute("user")
  • 只需让属性实现HttpSessionBindingListener 并将堆栈转储到valueUnbound(),正如我的回答中所建议的那样。在堆栈中,您应该能够看到负责删除该属性的那个。如果您已经熟悉 IDE 的调试器,或者只是运行 IDE 的调试器而不是这种“穷人的方式”调试。
猜你喜欢
  • 2012-10-30
  • 1970-01-01
  • 2013-03-26
  • 1970-01-01
  • 2016-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-02
相关资源
最近更新 更多