序:JSP 被容器翻译为 Java 源码,然后编译为 full-fledged Java servlet class。本章讨论讨论六种不同的JSP元素,且各自有不同的语法、功能。学习如何该写进JSP什么不该写进JSP。
JSP 到底还是 Servlet
容器自动把JSP变成Servlet,装载class,实例化,初始化,为每个请求分别分配线程,调用serlet的 service() 方法。
本章回答的问题包括:
# 使用java代码块 scriptlet
<!--BasicCounter.jsp-->
<html>
<body>
The page count is:
<%
out.println(Counter.getCount());
%>
<!--The "out" object is implicitly there. Everything between <% and %> is a scriptlet, which is just plain old Java.-->
</body>
<.html>
pacakge foo;
/** Plain old java helper class
*/
public class Counter {
private static int count;
public static synchronized int getCount() {
count++;
return count;
}
}
编译部署测试后发现不行,因JSP找不到 foo 包。用 import,或者fully-qualified class name.
<%
out.println(foo.Counter.getCount());
%>
//Now, it'll work.
Use the page directive to import packages
可以用 import, 只需 directive
<!--BasicCounter.jsp-->
<%@ page import="foo.*" %>
<html>
<body>
The page count is:
<% out.println(Counter.getCount()); %>
</body>
</html>
如果有多个import,用逗号隔开即可:
<%@ page import="foo.*", java.util.*" %>
注:Java code 卸载 <% %> 中,directive 放在带 @ 标记的<@% %>中。即出现<@% %>就知道它是 directive,本书后续会进一步探讨page directive。
JSP “expression” 表达式
不必在 JSP 中使用 out.println()。用表达式。
<%@ page import="foo.*" %>
<html>
<body>
The page count is:
<% out.println(Counter.getCount()); %>
</body>
</html>
<%@ page import="foo.*" %>
<html>
<body>
The page count is:
<%= Counter.getCount() %>
</body>
</html>
JSP expression element-自动打印被tags包裹的一切。被包裹的被视为参数,故不要分号了,有分号会通不过编译。
已经看到三种不同的JSP元素类型,小结:
类型 | 标记 |
---|---|
Scriptlet | <% %> |
Directive | <%@ %> |
Expression | <%= %> |
如果不用Counter类,直接声明,会造成每次打开页面都是打印的是1。因为这样本质尚声明的是一个局部变量,如下图。
声明变量的JSP元素 declaration:
<%! int count=0; %>
,注意!
和;
。
you can declare both static and instance variables and methods.
JSP Declarations
声明变量和方法的例子如下。
![声明变量的JSP元素 declaration:<%! int count=0; %>
,注意!
和;
。
you can declare both static and instance variables and methods.
是时候看看真正生成的 servlet 了
开发时不必管容器生成的java source files,只是帮助一下学习。
步骤如下:
implicit objects
P301的练习展示了 jsp expression 的正确用法,注意哪些部分应该在一起,哪些部分应该分开。代码如下
<%@ page import="java.util.*" %>
<html>
<body>
The friends who share your hobby of
<%=reqeust.getParameter("hobby")%>
are:<br>
<% ArrayList a1 = (ArrayList) request.getAttribute("names"); %>
<%
Iterator it = a1.iterator();
while(it.hasNext()){%>
<%=it.next()%>
<br>
<% }%>
</body>
</html>
API for the generated servlet
- jspIint()
- jspDestroy()
- _jspService() 有下划线表示不能重写
Lifecycle of a JSP
对于第一次请求到来,Lifecycle 如下:
总之就是接收到请求后,被容器翻译成 Java代码,编译为二进制文件(翻译和编译只进行一次),然后像一个普通 servlet 一样被载入、初始化,分配线程,做出响应。
关于预编译:
Initialize your JSP
与普通 servlet 有区别。
Configure servlet init parameters
在DD中,用<jsp-file>
标签
Override jspInit()
可以在 jspInit()
方法中,使用 getServletConfig()
, getServletContext()
方法。如下一个例子,使用 jspInit()
方法取回 servlet init parameter(配置在DD中),并用这个值来设置一个 application-scoped 属性。
<%! <!--重写 jspInit() 用 declaration-->
public void jspInit() {
ServletConfig sConfig = getServletConfig();
String emailAddr = sConfig.getInitParameter("email"); <!--此处与普通 servlet 完全相同-->
ServletContext ctx = getServletContext();
ctx.setAttribute("mail", emailAddr); <!--Get a reference to the ServletContext and set an applicatoin-scope attribute.-->
}
%>
Attributes in a JSP
作为标准 servlet request
, session
, and application(context)
scopes的补充,JSP加入第四个作用域—— page
scope——可以从中获取 pageContext
对象。
除非开发自定义ta,否则不太会用到 pageContext
对象,故到自定义tag 的章节再讨论它。
### 使用 PageContext for attributes
use a PageContext
reference to get attributes from any scopes. 这些方法通过 init argument 来指定作用域,如 SESSION_SCOPE。
Examples using pageContext to get and set attributes
Setting a page-scoped attribute
<% Float one = new Float(42.5); %>
<% pageContext.setAttribute("foo", one); %>
Getting a page-scoped attribute
<%= pageContext.getAttribute("foo"); %>
Using the pageContext to set a session-scoped attribute
<% Float two = new Float(22.4); %>
<% pageContext.setAttribute("foo", two, PageContext.SESSION_SCOPE); %>
Using the pageContext to get a session-scoped attribute
<%= pageContext.getAttribute("foo", two, PageContext.SESSION_SCOPE); %>
<!--Which is identical to: <%= session.getAttribute("foo") %>-->
Using the pageContext to get an application-scope attribute
Email is:
<%= pageContext.getAttribute("mail", PageContext.APPLICATION_SCOPE) %>
<!-- which is identical to -->
Email is:
<%= application.getAttribute("mail") %>
Using the pageContext to find an attribute when you don’t know the scope
<%= pageContext.findAttribute("foo") %>
找法:先找 page context
,再 request scope
,再 session
, 再 application
scope.( 即 from most restricted to least restricted)
详谈三个 directive
之前有提到过 page directive(三个directive之一) 和其 import attribute(page directive 的13个attribute之一)。一些在下一章之前不详述,一些在本书中不详述(用得少)
### Attribute to the page directive
不必全部记忆,只需要对一共能感谢什么有个大致感觉。下一章会探讨 isELIgnored 和其他连与错误相关的属性。
Scriptlets considerd harmful
把所有 Java 代码放进 HTML 是糟糕的(bad practice,调试一下可以,放在生产环境中一定是不利的)。
- 前端开发人员或网站设计师并不应该被要求懂得Java代码。
- JSP中 的Java极难修改和维护
但是“以前没得选”(There didn’t used to be an alternative.)。
好在……
EL(Expression Language)是一切的答案。用简单的tags 调用 Java方法而不必把实际的 Java 代码放进页面中。
JSP 2.0 spec 以来 EL 是官方的规格的一部分。Writting the actual functionality(method code,调用自己写的方法)不是EL的目的。EL的目的是invoke Java Code——but the code itself belongs somewhere else. 则意味着一个regualr old Java class 不仅是有着方法的类,也是被称为 Tag Handler 的东西。换句话说,不必把方法代码写进 JSP,而是写在别的什么地方,再使用 EL 来调用。
Sneak peek at EL
整个下一章都是 EL 的内容,所以这里不深入细节。只是明白一下语法,知道什么东西可以写进JSP。
// This EL expression:
Please contact: ${applicationScope.mail}
// Is the same as this Java expression:
Please contact: <%= application.getAttribute("mail") %>
一个 EL 表达式看起来总是 ${something}
,即表达式被花括号(curly braces)包围,并有个美元(dollar)前缀。
EL 语法固然需要重新学习,但是这对于前后端人员是一个这种的办法,深入探究之后,就会发现这是值得的。
强制大家使用 EL expression 而非 scriptlet——在 DD中禁用之,用 <scripting-invalid>
标签。
<web-app...>
...
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<scripting-invalid>
true
</scripting-invalid>
</jsp-property-group>
</jsp-config>
...
</web-app>
在已经弃用的旧标准里会有这样的禁用办法:
<%@ page isScriptingEnabled="false" %>
但是由于被弃用,所以现在只用一个办法——在DD中使用 <scripting-invalid>
标签。
You can choose to ignore EL
有的时候需要关闭 EL,方式符号冲突,如下图。
由于 EL 默认开启,所以需要在 DD 中明确指定关闭,用
<el-ignored>
标签 或者 page directive isELIgnored
属性(注意 el-ignored 和 isELIgnored 名字的不同),如下。
<web-app...>
...
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<el-ignored>
true
</el-ignored>
</jsp-property-group>
</jsp-config>
...
</web-app>
或
<%@ page isELIgnored="true" %>
如果上述两种设置发生了冲突,页面中的directive设置会覆盖掉全局的DD中的设置。
JSP elements : actions
之前已经认识了出现在 JSP 中的五种类型的元素:scriptlets, directives, declarations, Java expression, and EL expressions. 还有一种 actions,其有两种风格:standard 和 not standard。
<!--Standard Action:-->
<jsp:include page="wickedFooter.jsp" />
<!--Other Action:-->
<c:set var="rate" value="32" />
现在只需要认得,之后会详细讨论。
对比前面五种,还是有显著区别:
类型 | 标记 |
---|---|
Scriptlet | <% %> |
Directive | <%@ %> |
Expression | <%= %> |
Declaration | <%! %> |
EL expression | ${ } |
ch7 mocktest 正确率 10/15 66.6%,较上一章有进步。
七章暂毕。