微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么我不能在没有 <jsp:useBean> 的情况下使用 <jsp:getProperty>?

如何解决为什么我不能在没有 <jsp:useBean> 的情况下使用 <jsp:getProperty>?

假设有一个带有代码的 servlet:

override func layoutSubviews() {
   let gradientLayer = CAGradientLayer()
   gradientLayer.type = .axial
   gradientLayer.colors = [UIColor.clear.cgColor,UIColor.black.cgColor]
   gradientLayer.frame = bounds
   gradientLayer.startPoint = CGPoint(x: 0,y: 0.5)
   gradientLayer.endPoint = .init(x: 0,y: 1)
   gradientLayer.zPosition = 1
   gradientLayer.opacity = 0.5
   layer.addSublayer(gradientLayer)
}

,转到 protected void doGet(HttpServletRequest req,HttpServletResponse resp) throws servletexception,IOException { foo.Person p = new foo.Person("Evan"); req.setAttribute("person",p); Requestdispatcher view = req.getRequestdispatcher("/result.jsp"); view.forward(req,resp); } 以打印给定的名称 (Evan)。这是它的外观图片(来源 Head First Servlets 和 JSP):

enter image description here

我知道 result.jsp 通过调用 <jsp:useBean> 返回相同的 Person 对象 - 因为它们在相同的请求范围。而在另一边,getAttribute()调用 <jsp:getProperty> 从字面上尝试查找值“person”的属性..并最终打印 Evan

但如果我不使用 findAttribute() 呢?这是否意味着我无法在 request 范围内访问“person”属性?我的意思是它仍然存在,即使我没有使用 <jsp:useBean> 那么为什么我必须在两个 id 中具有相同的 value("person") <jsp:useBean>.name<jsp:useBean> 中?简单地删除 <jsp:getProperty> 会破坏我的程序。

知道 <jsp:useBean> 调用 <jsp:getProperty>,如果有一个单独的属性(如 attribute-name),将用作一个属性不是更合乎逻辑吗?在 page>request>session>application 范围内查找属性的参数?为什么我必须“绑定”这两个标签findAttribute()<jsp:useBean>

解决方法

你觉得下面的代码怎么样?

public class Main {
    public static void main(String[] args) {
        System.out.println(person);
    }
}

您一定已经猜到了不会成功编译

现在,下面的代码怎么样?

public class Main {
    public static void main(String[] args) {
        Person person = new Person();// Declaring person
        System.out.println(person);
    }
}

当然会编译成功1,因为现在编译器明白person是什么了。

同样,使用

<jsp:getProperty name="person" property="name">

不将 person 声明为

<!-- Declaring person -->
<jsp:useBean id="person" class="foo.Person" scope="request" />

不会被成功编译


1 假设 Person.class 存在。

,

TL;DR:您应该记住,您需要将 <jsp:getProperty><jsp:useBean> 一起使用,因为规范是这样说的。 <jsp:useBean> 需要将 bean 引入 JSP 处理器,然后 <jsp:getProperty> 才能使用它。

更长的解释:

为什么我不能在没有 <jsp:getProperty> 的情况下使用 <jsp:useBean>

因为它们“在某种程度上”旨在协同工作。我不知道为什么会这样决定(只有 JSP 规范的设计者可以回答这个问题),但是 optional chaining 本身对 <jsp:getProperty> 有这样的说法:

由名称命名的对象必须已使用 jsp:useBean 操作或具有与此名称相关联的 VariableInfo 条目的自定义操作“引入”到 JSP 处理器。如果对象不是以这种方式引入的,则建议(但不是必需)容器实现引发翻译错误,因为页面实现违反了规范。

我说“有点”旨在协同工作,因为在某些情况下,您可以使用 <jsp:getProperty> 而无需 <jsp:useBean>,但是您必须配置 JSP 处理器以忽略 JSP.5.3 规范规则(对于允许这样做的服务器)。

这不是很清楚,所以让我们看看一些代码会发生什么。

我有以下 JSP:

-------------------------------------------------------------------
<jsp:useBean id="person" class="test.Person" scope="application" />
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
<jsp:getProperty name="person" property="name" />
-------------------------------------------------------------------

我使用了这些定界符,以便我以后可以在 JSP 生成的 servlet 中找到它们,它们会生成以下代码:

  out.write("\t\t-------------------------------------------------------------------\r\n");
  out.write("\t\t");
  test.Person person = null;
  synchronized (application) {
    person = (test.Person) _jspx_page_context.getAttribute("person",javax.servlet.jsp.PageContext.APPLICATION_SCOPE);
    if (person == null){
      person = new test.Person();
      _jspx_page_context.setAttribute("person",person,javax.servlet.jsp.PageContext.APPLICATION_SCOPE);
    }
  }
  out.write("\r\n");
  out.write("\t\t+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r\n");
  out.write("\t\t");
  out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString((((test.Person)_jspx_page_context.findAttribute("person")).getName())));
  out.write("\r\n");
  out.write("\t\t-------------------------------------------------------------------\r\n");

如果您查看 <jsp:getProperty>,您会发现它对 test.Person 进行了强制转换:

org.apache.jasper.runtime.JspRuntimeLibrary.toString((((test.Person)_jspx_page_context.findAttribute("person")).getName()))

但是这是从哪里来的?在您的 <jsp:getProperty> 中,您指定了一个 bean 名称 (person) 和一个属性名称 (name),但没有指定类。所以这些属性只会产生 findAttribute("person"),然后产生 getName()。这门课是从哪里学来的?答案是,之前对 <jsp:useBean> 的调用在 JSP 处理器中引入了这一点。

因此您必须调用 <jsp:useBean> 将 bean 引入 JSP 处理器,以便当处理器看到 <jsp:getProperty> 时,它知道它在处理什么。所以基本上,<jsp:useBean> 定义它,然后 <jsp:getProperty> 使用它。如果您不调用 <jsp:useBean><jsp:getProperty> 将尝试使用未定义的内容,JSP 处理器会抱怨,您将返回以下异常:

jsp:getProperty 用于名为“person”的 bean。以前没有按照 JSP.5.3 引入名称

但是如果您阅读规范,它会说:

[...] 建议(但不是必需)容器实现引发翻译错误 [...]

例如,如果您使用 Tomcat,则有一个 org.apache.jasper.compiler.Generator.STRICT_GET_PROPERTY 系统属性可以控制将 <jsp:getProperty> 中使用的对象预先“引入”到 JSP 处理器的要求(基本上,强制执行或不是 JSP.5.3 规则)。例如,请参阅此 the spec

因此,如果我使用以下系统变量启动 Tomcat 服务器:

-Dorg.apache.jasper.compiler.Generator.STRICT_GET_PROPERTY=false

然后我可以在没有 <jsp:getProperty> 的情况下使用 <jsp:useBean>,前提是我以其他方式在 SCOPE 中引入了 person Bean(例如从带有 request.setAttribute() 的 servlet,{{1 }} 或 session.setAttribute() 以便 application.setAttribute() 可以执行 <jsp:getProperty> 并查找名为 pageContext.findAttribute() 的 bean 并找到它。

如果您使用该系统属性,则 person 标记生成的输出会发生变化。它不再依赖于 <jsp:getProperty> 并且演员表被移除:

<jsp:useBean>

如果有人对所有这些混乱如何展开感兴趣,那么要查看的类(对于 Tomcat 服务器)是:out.write("\t\t+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r\n"); out.write("\t\t"); out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString(org.apache.jasper.runtime.JspRuntimeLibrary.handleGetProperty(_jspx_page_context.findAttribute("person"),"name"))); out.write("\r\n"); out.write("\t\t-------------------------------------------------------------------\r\n"); org.apache.jasper.compiler.Validator

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。