(jsp) scriptlets 什么时候 运行 他们的 (Java) 代码?

When do (jsp) scriptlets run their (Java) code?

我正在处理如下代码的空指针异常:

<%
SessionData session = getSessionData(request);
Webpage webPage = null;
if (session!= null) {
    webPage = session.getWebPage();
}
%>

<script type="text/javascript"> 

//NullPointer happens here, webPage is null when the session is lost
<tags:ComboBox
    comboBox="<%=webPage.getComboBox()%>" />

</script>

当我可以将 if (session!=null 的结尾移动到 javascript 之后时,我感到很惊讶,这似乎在会话为空时忽略了该代码。

<%
SessionData session = getSessionData(request);
Webpage webPage = null;
if (session!= null) {
    webPage = session.getWebPage();
//} move this to below
%>

<script type="text/javascript"> 

//NullPointer happens here, webPage is null when the session is lost
<tags:ComboBox
    comboBox="<%=webPage.getComboBox()%>" />

</script>
<% } %> //moved to here

括号内的 ComboBox 标记的 scriptlet 是否不再是 运行?我认为它仍会尝试将组合框从网页上移开,但最终仍会得到一个空指针。我是否认为 scriptlet 在代码实际 运行 之前都获得了它们的值是不正确的?

(只是想我会提到,有一个包含的脚本可以在没有会话的情况下重定向页面。我在第一段代码中得到一个 NullPointer,并在第二段代码中正确重定向节)

简而言之,您对标记库和小脚本的处理顺序不正确; JSP 编译器首先识别 JSP 指令,然后解析并呈现标记库输出,然后将不在 scriptlet 中的所有内容转换为写入页面的一堆静态字符串,然后拼接结果 Java 围绕现有的 scriptlet 代码一起归档,看起来像这样:

// start of class and _jspService method declaration omitted for brevity

    out.write("<html>\n");
    out.write("\t<head>\n");
    out.write("\t<title>Example Static HTML</title>\n");

// comment inside a scriptlet block
int x = request.getParameter("x");
pageContext.setParameter("x", x);

    out.write("\t</head>\n");

这里的问题源于标记库首先被解析,而隔离和评估它们的代码不关心 scriptlet 块或 DOM。在您的情况下,<tags:ComboBox> 标记只是认为 scriptlet 是一个常规字符串。

您应该做的是将 scriptlet 中的值暴露给标签库使用的可访问范围;例如,对于 JSTL,您需要通过 pageContext.setAttribute("varName", value).

将其添加到页面上下文中

查看 this answer 了解更多详情。

A JSP 由 servlet 容器即时编译成 servlet。

这个编译其实就是简单的一种反转:

TEXT1
<% java code %>
TEXT2
<%= java expression %>
TEXT3

即编译为:

out.print("TEXT1");
java code
out.print("TEXT2");
out.print(java expression);
out.print("TEXT3");

所以当你说:

TEXT1
<% if (true) { %>
TEXT2
<% } %>
TEXT3

你得到:

out.print("TEXT1");
if (true) {
out.print("TEXT2");
}
out.print("TEXT3");

为清楚起见,缩小了上述示例,例如忽略换行符,不包括样板 servlet 设置,并且不包括标签库执行的复杂性。