【问题标题】:Java servlet and JSP accessing the same session beanJava servlet 和 JSP 访问同一个会话 bean
【发布时间】:2011-02-09 10:08:31
【问题描述】:

假设我有一个简单的登录 servlet,它检查传递的 name 并创建 User 对象并将其存储在会话中。

User user = new User();
user.setId(name);

request.getSession().setAttribute("user", user);
response.sendRedirect("index.jsp");

index.jsp页面我通过jsp:useBean访问用户对象

<jsp:useBean id="user" scope="session"
             class="package.name.User"/>

<div class="panel">
    Welcome ${user.id}
</div>

到目前为止有效。

来自 jsp beans 文档

要定位或实例化 Bean, 采取以下措施 步骤,按以下顺序:

  1. 尝试使用您指定的范围和名称来定位 Bean。
  2. 使用您指定的名称定义对象引用变量。
  3. 如果找到 Bean,则在变量中存储对它的引用。如果 你指定类型,给出 Bean 那种类型。
  4. 如果它没有找到 Bean,则从你的类中实例化它 指定,存储对它的引用 新变量。如果类名 表示一个序列化的模板, Bean被实例化 java.beans.Beans.instantiate。
  5. 如果已经实例化(而不是定位)了 Bean,并且如果 它有身体标签或元素(之间 和 ), 执行body标签。

问题:

尝试使用您指定的范围和名称来定位 Bean

它没有指定“定位”过程。这是否意味着它会检查HttpServletRequest.getSession() 或者只是检查其他页面是否已经创建了这个bean?

如果它没有找到 Bean,则从您指定的类中对其进行实例化,并将对它的 > 引用存储在新变量中。

这实际上意味着 Jsp 可以使用 jsp_internal_name_user 将新创建的 bean 与会话相关联。 没有关于 Jsp 如何在会话中存储和查找 bean 的消息。

有一个选项可以使用${sessionScope.user} 访问会话对象,这将保证从 Java 会话对象中获取“用户”。和我自己装的一样。

Java EE 5 示例“书店”使用${sessionScope.name} 方法访问会话对象。

仅使用 ${user} 即可。而这正是我担心的。我想在规范中看到关于locate 进程以及${user} 是否必须工作或者它是否取决于JSP 和/或JSTL 参考实现的具体句子。

【问题讨论】:

    标签: java jsp servlets


    【解决方案1】:

    来自文档:

    &lt;jsp:useBean&gt; 元素定位或实例化 JavaBeans 组件。 &lt;jsp:useBean&gt; 首先尝试定位 Bean 的实例。 如果 Bean 不存在,&lt;jsp:useBean&gt; 从类中实例化它或序列化 模板。

    既然“定位” bean 完全没问题,那么我们可以假设 bean 可以通过&lt;jsp:useBean&gt; 实例化以外的方式提供。例如,通过在 servlet 中创建它。

    【讨论】:

      【解决方案2】:

      对于负责模型的控制器(servlet),jsp:useBean 仅在默认实例(使用无参数构造函数构造)公开与不存在实例不同的行为/状态时才有用。例如。如果您想拥有一个默认用户名“未知用户”,您可以:

      public User {
          this.id = "Unknown User";
      }
      

      否则,最终用户可能会面临“欢迎”而不是“欢迎未知用户”的显示。在您的特定情况下,您可以安全地删除它。这是多余的。

      但是,我也看到了它对纯文档很有用的论点。您可以在 JSP 页面顶部声明“无用”jsp:useBean 实例,以便您大致了解在特定 JSP 页面中使用了哪些模型。虽然我觉得它很聪明,但我自己从来没有需要这种在 JSP 中记录模型的方式。根据 cmets,另一个论点确实是这样的 IDE 像 IDEA 和 Eclipse 能够在 EL 中自动完成 bean 属性。

      更新:关于定位,它使用PageContext#findAttribute(),然后使用反射/javabean自省来调用它的getter方法。例如

      ${user.name}
      

      大致解析为

      out.print(pageContext.findAttribute("user").getName())
      

      另请参阅 JSP specificationJSP EL specification

      更新 2&lt;jsp:useBean&gt; 当然 不使用内部名称或会话属性前缀。自己循环所有会话属性以查看实际的键和值:

      <c:forEach items="${sessionScope}" var="entry">
          ${entry.key} = ${entry.value}<br>
      </c:forEach>
      

      或在 servlet 中

      for (String name : Collections.list(session.getAttributeNames())) {
         System.out.println(name + " = " + session.getAttribute(name));
      }
      

      【讨论】:

      • 是否有一些文档明确描述了jsp页面中变量解析的过程?
      • Intellij IDEA 仅在显式声明的情况下完成变量字段。
      • 1) 你说的是EL?检查JSP EL specification。简而言之,它通过PageContext#findAttribute() 来定位任何范围内的属性。 2)这确实也是我以前见过的另一个论点。
      • 感谢您指出问题。我指的是 JSP 规范,但没有发现任何有用的东西。查看 EL 规范。
      • 能否请您指出您发现“大致解析为...”的部分?
      【解决方案3】:

      引用 JSP 规范 JSP.5.1

      基本语义尝试使用 id 和 范围。如果找不到对象,它将尝试使用其他对象创建对象 属性。

      换句话说,

      <jsp:useBean id="user" scope="session" class="package.name.User"/>
      

      大概会翻译成java:

      package.name.User user = (package.name.User)session.getAttribute("user");
      if (user == null){
        user = new package.name.User();
        session.setAttribute("user", user);
      }
      

      【讨论】:

      • 嘿,很高兴在这里见到你 :) 你的答案确实适合特定的 jsp:usebean 行,你只是忘记了 if 块中的 session.setAttribute("user", user); ;)
      • 我想看看“查找现有”过程的描述。事实上 jsp 可以使用“user_jsp_internal”名称存储对象。
      • 不,它没有。该对象与id 中指定的属性键一起存储。否则你怎么能通过${user} 等在纯 EL 中访问它?
      • 因为当前的实现。那么为什么我们可以使用 ${scopeSession.user} 显式表达式。请指出您在哪里发现它会使用 id 将其存储在会话中?我认为这是 JSR 实施人员可以自己决定的。
      • 参考 JSP.5.1。一切都是黑白的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-24
      • 1970-01-01
      • 2016-11-24
      • 1970-01-01
      • 1970-01-01
      • 2011-01-02
      相关资源
      最近更新 更多