2.2 JSP的基本原理

2.2 JSP的基本原理

JSP本质是Servlet

JSP的本质是Servlet(一个特殊的Java类),当用户向指定Servlet发送请求时,Servlet利用输出流动态生成HTML页面,包括每一个静态的HTML标签和所有在HTML页面中出现的内容。

JSP可以精简Servlet

由于包括大量的HTML标签、大量的静态文本及格式等,导致Servlet的开发效率极为低下。所有的表现逻辑,包括布局、色彩及图像等,都必须耦合在Java代码中,这的确让人不胜其烦。
JSP的出现弥补了这种不足,JSP通过在标准的HTML页面中嵌入Java代码,其静态的部分无须Java程序控制,只有那些需要从数据库读取或需要动态生成的页面内容,才使用Java脚本控制。

JSP页面组成部分

从上面的介绍可以看出,JSP页面的内容由如下两部分组成

  1. 静态部分:标准的HTML标签、静态的页面内容,这些内容与静态HTML页面相同。
  2. 动态部分:受Java程序控制的内容,这些内容由Java脚本动态生成。

程序示例

first.jsp

下面是一个最简单的JSP页面代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>欢迎</title>
<meta name="website" content="http://www.crazyit.org" />
</head>
<body>
欢迎学习Java Web知识,现在时间是:
<%out.println(new java.util.Date());%>
</body>
</html>

上面的页面中代码:

1
<%out.println(new java.util.Date());%>

放在<%%>之间,表明这些是Java脚本,而不是静态内容,通过这种方式就可以把Java代码嵌入HTML页面中,这就变成了动态的JSP页面。在浏览器中浏览该页面,将看到如图2.2所示的页面

上面JSP页面必须放在Web应用中才有效,所以编写该JSP页面之前应该先构建一个Web应用。本章后面介绍的内容都必须运行在web应用中,所以也必须先构建Web应用。
从表面上看,JSP页面已经不再需要Java类,似乎完全脱离了Java面向对象的特征。事实上,JSP的本质依然是Servlet,每个JSP页面就是一个Servlet实例——**JSP页面由系统编译成Servlet,Servlet再负责响应用户请求。也就是说,JSP其实也是Servlet的一种简化,使用JSP时,其实还是使用Servlet**,因为Web应用中的每个JSP页面都会由Servlet容器生成对应的Servlet
对于Tomcat而言,JSP页面生成的Servlet放在work路径对应的Web应用下

test.jsp

再看如下一个简单的JSP页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title> 第二个JSP页面 </title>
<meta name="website" content="http://www.crazyit.org" />
</head>
<body>
<!-- 下面是Java脚本 -->
<%for(int i = 0 ; i < 7; i++)
{
out.println("<font size='" + i + "'>");
%>
HelloWorld!</font>
<br/>
<%}%>
</body>
</html>

JSP对应的java类的路径

当启动Tomcat之后,可以在Tomcatwork\Catalina\localhost\jspPrinciple\org\apache\jsp\目录下找JSP页面对应的java文件:

  • test_jsp.class
  • test_jsp.java

这两个文件都是Tomcat根据test.jsp这个JSP页面生成对应ServletJava文件和class文件.

test.jsp对应的Servlet: test_jsp.java

下面是test_Jsp.java文件的源代码,这是一个特殊的Java类,是一个Servlet类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/8.5.35
* Generated at: 2020-06-05 09:06:14 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public final class test_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {

private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();

private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;

private static final java.util.Set<java.lang.String> _jspx_imports_packages;

private static final java.util.Set<java.lang.String> _jspx_imports_classes;

static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}

private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;

public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}

public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}

public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}

public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}

public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}

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;
}

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; charset=GBK");
pageContext = _jspxFactory.getPageContext(this, request, response,
"", true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;

out.write("\r\n");
out.write("\r\n");
out.write("\r\n");
out.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\r\n");
out.write("\t\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\r\n");
out.write("<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n");
out.write("<head>\r\n");
out.write("\t<title> 第二个JSP页面 </title>\r\n");
out.write("\t<meta name=\"website\" content=\"http://www.crazyit.org\" />\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write("<!-- 下面是Java脚本 -->\r\n");
for(int i = 0 ; i < 7; i++)
{
out.println("<font size='" + i + "'>");

out.write("\r\n");
out.write("疯狂Java训练营(Wild Java Camp)</font>\r\n");
out.write("<br/>\r\n");
}
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>");
} 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);
}
}
}

Servlet三个主要方法

初学者看到上面的Java类可能有点难以阅读,其实这就是一个Servlet类的源代码,该Java类主要包含如下三个方法(去除方法名中的jsp前缀,再将首字母小写)

  • init():初始化JsP/Servlet的方法。
  • destroy():销毁JSP/Servlet之前的方法。
  • service():对用户请求生成响应的方法。

即使读者暂时不了解上面提供的Java代码,也依然不会影响JSP页面的编写,因为这都是由Web容器负责生成的,后面介绍了编写Servlet的知识之后再来看这个Java类将十分清晰。浏览该页面可看到如图2.3所示的页面。

从图2.3中可以看出,JSP页面里的Java代码不仅仅可以输出动态内容,还可以动态控制页面里的静态内容,例如,从图2.3中看到将“xxxxx”重复输出了7次

根据图2.3所示的执行效果,再次对比test.Jsptest_Jsp.java文件,可得到一个结论:test.jsp页面中的所有内容都由test_Jsp.Java文件的页面输出流来生成。图2.4显示了JSP页面的工作原理

总结

根据上面的JSP页面工作原理图,可以得到如下4个结论。

  • JSP文件必须在JSP服务器内运行。
  • JSP文件必须生成Servlet才能执行
  • 每个JSP页面的第一个访问者速度会有点慢,因为必须等待JSP编译成Servlet
  • JSP页面的访问者无须安装任何客户端,甚至不需要可以运行Java的运行环境,因为JSP页面输送到客户端的是标准HTML页面。

JSP技术的出现,大大提高了Java动态网站的开发效率,所以得到了Java动态网站开发者的广泛支持。