前面的文章已经覆盖了Servlet核心知识,由于JSP与Servlet在很大程度上是相通的,因此关于JSP只需要介绍语法以及一些独特的性质。
同样可以参考菜鸟笔记。
介绍JSP
首先,为什么要有JSP?
要回答这个问题,实际上只需要比较HTML、Servlet、JSP的优劣:
HTML文件是静态的,无法返回动态结果。
Servlet可以动态生成HTML页面,但是在代码里写HTML标记实在是不爽。
于是反过来,在传统的HTML文件中加入Java程序片段和JSP标记,就构成了JSP文件。
JSP是怎么工作的?
当容器接收到客户端对JSP文件的请求时,会解析对应的JSP文件,把它翻译成Servlet源文件,接着把Servlet源文件编译成Servlet类,然后再初始化并运行Servlet。
当然,一旦JSP文件已经被编译过,下次运行时只需要找对应的Servlet类就行了。
可见JSP和Servlet其实是一回事,JSP只是一层外衣。其内容中不论是HTML标记还是Java代码,都大部分被编译到了Servlet类的service()方法中。于是接下来就顺便解释了JSP的生命周期:
JSP的生命周期
编译阶段:Servlet容器编译servlet源文件,生成servlet类
初始化阶段:加载与JSP对应的servlet类,创建其实例,并调用它的初始化方法
执行阶段:调用与JSP对应的servlet实例的服务方法
销毁阶段:调用与JSP对应的servlet实例的销毁方法,然后销毁servlet实例
下图给出了后面三个阶段的示意:
其中:编译出来的Servlet类继承自javax.servlet.jsp.HttpJspPage接口,该接口继承了javax.servlet.Servlet接口。jspInit()就对应Servlet的init(), jspDestroy()就对应Servlet的destroy(), _jspService()自不必说。
下面给出一个JSP文件和编译出来的代码,就一目了然了。
<!-- Hello.jsp -->
<html>
<head>
<title>helloapp</title>
</head>
<body>
<b>Hello,<%= request.getParameter("username") %></b>
</body>
</html>
编译出的Servlet文件:
public final class hello_jsp extends org.apache.jasper.runtime.HttpJspBase {
...
public void _jspInit() {
}
public void _jspDestroy() {
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
return;
}
// 可以看出JSP的隐含对象是这么来的。
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write(" <title>helloapp</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write(" <b>Hello,");
out.print( request.getParameter("username") );
out.write("</b>\r\n");
out.write("</body>\r\n");
out.write("</html>\r\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
JSP的语法
概括地说,JSP文件中除了可以直接包含HTML文本,还可以包含以下内容:
-
JSP指令(Directive)
用来设置和整个JSP页面相关的属性。语法形式为<%@ 指令 属性1="值1" 属性2="值2" %>
。包括三种指令:Page: 可以指定language、content_type、errorPage、session等,还可以用import属性引入包。
Include: 包含其他文件。
Taglib: 指定自定义标签。
-
JSP声明
声明一个或多个变量、方法,供后面的Java代码使用。声明中的变量会被编译成Servlet的(私有)成员变量。示例:
<%! int i = 0; %> <%! int a, b, c; %> <%! Circle a = new Circle(2.0); %>
Java程序片段
任何在"<%"和"%>"标记之间的Java代码。默认会被编译到Servlet类的service()方法中(如果用Page指定了method属性,则会编到你指定的方法中)。如果你想复写jspInit()和jspDestroy()方法,应该在前面的JSP声明中写。Java表达式
语法形式为<%= JAVA表达式 %>
。相当于被编译成out.print(JAVA表达式)
。-
JSP隐含对象
JSP隐含对象是JSP容器为每个页面提供的Java对象,开发者可以直接使用它们而不用显式声明。JSP隐含对象也被称为预定义变量。
JSP所支持的九大隐含对象:对象 描述 request HttpServletRequest类的实例 response HttpServletResponse类的实例 out PrintWriter类的实例,用于把结果输出至网页上 session HttpSession类的实例 application ServletContext类的实例,与应用上下文有关 config ServletConfig类的实例 pageContext PageContext类的实例,提供对JSP页面所有对象以及命名空间的访问 page 类似于Java类中的this关键字 Exception Exception类的对象,代表发生错误的JSP页面中对应的异常对象 看起来很犀利,但实际上从前面真实的Servlet代码可以看到,它们不过是在service()方法的最前面预先定义好的局部变量。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。