2.3.4 JSP小脚本

以前JSP小脚本的应用非常广泛,因此JSP小脚本里可以包含任何可执行的的Java代码。通常来说,所有可执行性Java代码都可通过JSP小脚本嵌入HTML页面。

scriptlet.jsp

看下面使用JSP小脚本的示例程序。

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
<%@ 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>
<table bgcolor="#9999dd" border="1" width="300px">
<!-- JSP小脚本,这些脚本会对HTML的标签产生作用 -->
<%
for(int i = 0 ; i < 10 ; i++)
{
%>
<!-- 上面的循环将控制<tr>标签循环 -->
<tr>
<td>循环值:</td>
<td><%=i%></td>
</tr>
<%
}
%>
<table>
</body>
</html>

上面的页面中粗体字代码就是使用JSP小脚本的代码,这些代码可以控制页面中静态内容。上面例子程序将<tr>标签循环10次,即生成一个10行的表格,并在表格中输出表达式值。

生成的Servlet代码

接下来打开Tomcat生成的java文件,将看到如下代码片段:

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
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> 小脚本测试 </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("<table bgcolor=\"#9999dd\" border=\"1\" width=\"300px\">\r\n");
out.write("<!-- JSP小脚本,这些脚本会对HTML的标签产生作用 -->\r\n");

for (int i = 0; i < 10; i++) {

out.write("\r\n");
out.write("\t<!-- 上面的循环将控制<tr>标签循环 -->\r\n");
out.write("\t<tr>\r\n");
out.write("\t\t<td>循环值:</td>\r\n");
out.write("\t\t<td>");
out.print(i);
out.write("</td>\r\n");
out.write("\t</tr>\r\n");

}

out.write("\r\n");
out.write("<table>\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);
}
}

上面的代码片段中的代码:

1
2
3
4
5
6
7
8
9
10
for (int i = 0; i < 10; i++) {
out.write("\r\n");
out.write("\t<!-- 上面的循环将控制<tr>标签循环 -->\r\n");
out.write("\t<tr>\r\n");
out.write("\t\t<td>循环值:</td>\r\n");
out.write("\t\t<td>");
out.print(i);
out.write("</td>\r\n");
out.write("\t</tr>\r\n");
}

JSP小脚本对应Servlet的_jspService方法的可执行性代码

完全对应于scriptlet.jsp页面中的小脚本部分。由上面代码片段可以看出,JSP小脚本将转换成Servlet_jspService方法的可执行性代码

JSP小脚本部分可以声明局部变量

这意味着,JSP小脚本部分也可以声明变量,但在JSP小脚本部分声明的变量是局部变量,但不能使用privatepublic等访问控制符修饰,也不可使用static修饰

JSP中所有的静态内容都由_jspService方法输出

实际上不仅JSP小脚本部分会转换成_jspService方法里的可执行性代码,JSP页面里的所有静态内容都将由_jspService方法里输出语句来输出,这就是JSP小脚本可以控制JSP页面中静态内容的原因。

JSP小脚本中可以定义局部变量 不能定义方法

由于JSP小脚本将转换成_jspService方法里的可执行性代码,而Java语法不允许在方法里定义方法,所以的JSP小脚本里不能定义方法JSP小脚本中定义的变量是局部变量

JSP小脚本中操作数据库

因为JSP小脚本中可以放置任何可执行性语句,所以可以充分利用Java语言的功能,例如连接数据库和执行数据库操作。看下面的JSP页面执行数据库查询

connDb.jsp

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
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@ page import="java.sql.*" %>
<!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>
<%
// 注册数据库驱动
Class.forName("com.mysql.jdbc.Driver");
// 获取数据库连接
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/javaee","root","32147");
// 创建Statement
Statement stmt = conn.createStatement();
// 执行查询
ResultSet rs = stmt.executeQuery("select * from news_inf");
%>
<table bgcolor="#9999dd" border="1" width="300">
<%
// 遍历结果集
while(rs.next())
{%>
<tr>
<!-- 输出结果集 -->
<td><%=rs.getString(1)%></td>
<td><%=rs.getString(2)%></td>
</tr>
<%}%>
<table>
</body>
</html>

上面程序中的粗体字脚本执行了连接数据库,执行SQL查询,并使用输出表达式语法来输出查询结果。在浏览器中浏览该页面,将看到如图2.6所示的效果。

上面的页面执行SQL查询需要使用MySQL驱动程序,所以读者应该将MySQL驱动的JAR文件放在Tomcatlb路径下(所有web应用都可使用MySQL驱动),或者将MySQL驱动复制到该Web应用的WEB-INF/ib路径下(只有该Web应用可使用MySQL驱动)。除此之外,由于本JSP需要查询javaee数据库下的news_inf数据表,所以不要忘记了将codes\01路径下的data.sql导入数据库。

data.sql

1
2
3
4
5
6
7
8
9
10
11
12
13
DROP DATABASE IF EXISTS javaee;
CREATE DATABASE javaee;
USE javaee;
CREATE TABLE news_inf
(
news_id INT AUTO_INCREMENT PRIMARY KEY,
news_title VARCHAR(255)
);

INSERT INTO news_inf
VALUES
(NULL, '疯狂Java联盟'),
(NULL, 'crazyit.org');

2.3.3 JSP输出表达式

JSP提供了一种输出表达式值的简单方法,输出表达式值的语法格式如下:

1
<%= 表达式 %>

注意 输出表达式语法后不能有分号。

outputEx.jsp

看下面的JSP页面,该页面使用输出表达式的方式输出变量和方法返回值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<%@ 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>
<%!
public int count;

public String info()
{
return "hello";
}
%>
<body>
<!-- 使用表达式输出变量值 -->
<%=count++%>
<br/>
<!-- 使用表达式输出方法返回值 -->
<%=info()%>
</body>
</html>

上面的页面中粗体字代码使用输出表达式的语法代替了原来的out.println()输出语句,该页面的执行效果与前一个页面的执行效果没有区别。由此可见,输出表达式将转换成Servlet里的输出语句

2.3.2 JSP声明

JSP声明用于声明变量和方法。在JSP声明中声明方法看起来很特别,似乎不需要定义类就可直接定义方法,方法似乎可以脱离类独立存在。实际上,JSP声明将会转换成对应Servlet的成员变量或成员方法,因此JSP声明依然符合Java语法。

JSP声明语法格式

JSP声明的语法格式如下:

1
<%! 声明部分 %>

declare.jsp

看下面使用JSP声明的示例页面。

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
<%@ 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>
<!-- 下面是JSP声明部分 -->
<%!
//声明一个整形变量
public int count;
//声明一个方法
public String info()
{
return "hello";
}
%>
<body>
<%
//将count的值输出后再加1
out.println(count++);
%>
<br/>
<%
//输出info()方法的返回值
out.println(info());
%>
</body>
</html>

测试

在浏览器中测试该页面时,可以看到正常输出了count值,每刷新一次,count值将加1,同时也可以看到正常输出了info()方法的返回值。
上面的代码:

1
2
3
4
5
6
7
8
9
<%!
//声明一个整形变量
public int count;
//声明一个方法
public String info()
{
return "hello";
}
%>

声明了一个整型变量和一个普通方法,表面上看起来这个变量和方法不属于任何类,似乎可以独立存在,但这只是一个假象。打开Tomcat生成的的declare_jsp.java文件(E:\apache-tomcat-8.5.35\work\Catalina\localhost\basicSyntax\org\apache\jsp\declare_jsp.java),看到如下代码片段:

public final class declare_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 org.apache.jasper.runtime.JspSourceImports {
//声明一个整形变量
public int count;
//声明一个方法
public String info()
{
    return "hello";
}
......

上面的粗体字代码与JSP页面的声明部分完全对应,这表明**JSP页面的声明部分将转换成对应Servlet的成员变量或成员方法**。

JSP声明可以使用的修饰符

由于JSP声明语法定义的变量和方法对应于Servlet类的成员变量和方法,所以JSP声明部分定义的变量和方法可以使用privatepublic等访问控制符修饰,也可使用static修饰,将其变成类属性和类方法。

不过,不能使用abstract修饰声明部分的方法,因为抽象方法将导致JSP对应Servlet变成抽象类,从而导致无法实例化。

打开多个浏览器,甚至可以在不同的机器上打开浏览器来刷新该页面,将发现所有客户端访问的count值是连续的,即所有客户端共享了同一个count变量。这是因为:JSP页面会编译成一个Servlet类,每个Servlet在容器中只有一个实例;在JSP中声明的变量是成员变量,成员变量只在创建实例时初始化,该变量的值将一直保存,直到实例销毁。
值得注意的是,info()的值也可正常输出。因为JSP声明的方法其实是在JSP编译中生成的Servlet的实例方法—Java里的方法是不能独立存在的,即使在JSP页面中也不行。
总结:JSP声明中独立存在的方法,只是一种假象。

2.3 JSP的4种基本语法

前面已经讲过,编写JSP页面非常简单:在静态HTML页面中“镶嵌”动态Java脚本即可。现在开始学习的内容是:JSP页面的4种基本语法——也就是JSP允许在静态HTML页面中“镶嵌”的成分。

开发JSP页面步骤

掌握这4种语法之后,读者即可按如下步骤开发JSP页面

  • 编写一个静态HTML页面。
  • 用合适的语法向静态HTML页面中“镶嵌”4种基本语法的一种或多种,这样即可为静态HTML页面增加动态内容。

如果读者对第1步“编写静态HTML页面”还不会,请至少先阅读疯狂Java体系的《疯狂HTML5/CSS3/JavaScript讲义》前3章

2.3.1 JSP注释

JSP注释用于标注在程序开发过程中的开发提示,它不会输出到客户端。

JSP注释

JSP注释的格式如下:

1
<%-- 注释内容 --%>

HTML注释

JSP注释形成对比的是HTML注释,HTML注释的格式是

1
<!--注释内容-->

代码示例

JSP页面

看下面的JSP页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%@ 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>
注释示例
<!-- 增加JSP注释 -->
<%-- JSP注释部分 --%>
<!-- 增加HTML注释 -->
<!-- HTML注释部分 -->
</body>
</html>

生成的HTML源码

在浏览器中浏览该页面,并查看页面源代码,页面的源代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!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>
注释示例
<!-- 增加JSP注释 -->

<!-- 增加HTML注释 -->
<!-- HTML注释部分 -->
</body>
</html>

在上面的源代码中可看到,HTML的注释可以通过源代码查看到,但JSP的注释是无法通过网页源代码査看到的。这表明**JSP注释不会被发送到客户端**。这表明JSP注释在JSP编译成Servlet的阶段已经被“丢弃”了。

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动态网站开发者的广泛支持。

2.1.2 配置描述符web.xml

上一节介绍的位于每个web应用的WEB-INF路径下的web.xml文件被称为配置描述符,这个web.xml文件对于Java Web应用十分重要,在Servlet2.5规范之前,每个JavaWeb应用都必须包含一个web.xml文件,且必须放在WEB-NF路径下。
Servlet3开始,WEB-INF路径下的web.xml文件不再是必需的,但通常还是建议保该配置文件.

WEB-INF

对于Java Web应用而言,WEB-INF是一个特殊的文件夹,Web容器会包含该文件夹下的内容,客户端浏览器无法访问WEB-INF路径下的任何内容.

Servlet2.5规范之前,JavaWeb应用的绝大部分组件都通过web.xml文件来配置管理,从Servlet3开始,也可通过注解来配置管理Web组件,因此web.xml文件可以变得更加简洁,这也是Servlet3的重要简化。接下来讲解的内容会同时介绍两种配置管理方式。

  • 配置JSP
  • 配置和管理Servlet
  • 配置和管理Listener
  • 配置和管理Filter
  • 配置标签库
  • 配置JSP属性。

除此之外,web.xml还负责配置、管理如下常用内容:

  • 配置和管理JAAS授权认证。
  • 配置和管理资源引用。
  • Web应用首页。

web.xml文件根元素

web.xml文件的根元素是<web-app>元素,在Servlet3规范中,该元素新增了如下属性:

  • metadata-complete:该属性接受truefalse两个属性值。metadata-complete属性值为true时,该Web应用将不会加载注解配置的web组件(如ServletFilterListener等)。

配置首页

web.xml文件中配置首页使用welcome-file-list元素,该元素能包含多个welcome-file子元素,其中每个welcome-file子元素配置一个首页。例如,如下配置片段:

上面的配置信息指定该Web应用的首页依次是index.htmlindex.htmindex.jsp,意思是说:

  • web应用中包含index.html页面时,如果浏览者直接访问该web应用,系统将会把该页面呈现给浏览者;
  • index.html页面不存在时,则由index.htm页面充当首页,依此类推。

Web容器提供的web.xml文件

每个web容器都会提供一个系统的web.xml文件,用于描述所有web应用共同的配置属性。例如:

  • Tomcat的系统web.xml放在Tomcatconf路径下,
  • Jetty的系统web.xm文件放在Jettyetc路径下,文件名为webdefault.xml

2.1 Web应用和web.xml文件

JSPServletListenerFilter等都必须运行在Web应用中,所以先来学习如何构建一个Web应用。

2.1.1 构建Web应用

下面将“徒手”建立一个Web应用,请按如下步骤进行:

创建主目录 WEB-INF目录 复制web.xml文件

  1. 在任意目录下新建一个文件夹,此处将以webDemo文件夹建立一个Web应用。
  2. 在第1步所建的文件夹内建一个WEB-INF文件夹(注意大小写,这里区分大小写)。
  3. 进入Tomcat或任何其他Web容器内,找到任何一个Web应用,将Web应用的WEB-INF下的web.Xml文件复制到第2步所建的WEB-INF文件夹下。(对于Tomcat而言,其webapp路径下有大量的示例web应用。)
  4. 修改复制后的web.xml文件,将该文件修改成只有一个根元素的XML文件。修改后的web.Xml文件代码如下。
1
2
3
4
5
6
7
<?xml version="1.0" encoding="GBK"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
</web-app>

WEB-INF目录下创建classes和lib目录

在第2步所建的WEB-INF路径下,新建两个文件夹:classeslib,这两个文件夹的作用完全相同:都是用于保存Web应用所需要的Java类文件,区别是:

  • classes保存单个*.class文件;
  • lib保存打包后的JAR文件。

部署 复制到Tomcatwebapps路径下

经过以上步骤,已经建立了一个空Web应用。将该Web应用复制到Tomcatwebapps路径下,该Web应用将可以自动部署在Tomcat中。

通常只需将JSP放在Web应用的根路径下(对本例而言,就是放在webDemo目录下),然后就可以通过浏览器来访问这些页面了。

Web应用目录结构

根据上面介绍,不难发现Web应用应该有如下文件结构:

G:\Desktop\Vscode测试\webDemo
├─a.jsp
└─WEB-INF\
  ├─classes\
  ├─lib\
  └─web.xml

上面的webDemoWeb应用所对应文件夹的名字,可以更改;a.jsp是该Web应用下JSP页面的名字,也可以修改(还可以增加更多的JSP页面)。其他文件夹、配置文件都不可以修改。
a.jsp页面的内容如下。

1
2
3
4
5
6
7
8
9
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<html>
<head>
<title>欢迎</title>
</head>
<body>
欢迎学习Java Web知识
</body>
</html>

上面的页面实际上是一个静态HTML页面,在浏器中浏览该页面将看到如图2.1所示的界面。
将上面的webDemo应用复制到Tomcatwebapp目录下(部署完成),然后启动Tomcat服务器,再使用浏览器访问htrp://Localhost:8080/WebDemo/a.jsp,即可看到如图2.1所示的页面,即表示Web应用构建成功,并已经将其成功地部署到Tomcat中了.

第2章 JSP Servlet及相关技术详解 概述

本章要点

  • Web应用的基本结构和web.xml文件
  • JSP的基本原理
  • JSP声明
  • JSP注释和HTML注释
  • JSP输出表达式
  • JsP脚本
  • JSP的3个编译指令
  • JSP的7个动作指令
  • JSP脚本中的9个内置对象
  • Servlet的开发步骤
  • XMLServlet3Annotation配置Servlet
  • Servlet运行的生命周期
  • MVC基础
  • 开发JSP2自定义标签库
  • 使用有属性的标签
  • 使用带标签体的标签
  • 开发、配置Filter以及Filter的功能
  • 开发、配置Listener以及Listener的功能
  • 配置JSP属性
  • JSP2的表达式语言
  • JSP2TagFile标签库
  • Servlet3.1web模块部署描述符
  • Servlet3.1提供的异步支持
  • Servlet3.1增强的ServletAPI
  • Servlet3.1提供的非阻塞IO
  • Tomcat8.5WebSocket支持

概述

JSP( Java Server Page)ServletJavaEE规范的两个基本成员,它们是Java Web开发的重点知识,也是JavaEE开发的基础知识。JSPServlet的本质是一样的,因为JSP最终必须编译成Servlet才能运行,或者JSP只是生成Servlet的“草稿”文件
JSP比较简单,它的特点是在HTML页面中嵌入Java代码片段,或使用各种JSP标签,包括使用用户自定义标签,从而可以动态地提供页面内容。早期JSP页面的使用非常广泛,一个Web应用可以全部由JSP页面组成,只辅以少量的JavaBean即可。自JavaEE标准出现以后,人们逐渐认识到使用JSP充当过多的角色是不合适的。因此,JSP慢慢发展成单一的表现层技术,不再承担业务逻辑组件及持久层组件的责任。
随着Java EE技术的发展,又出现了FreeMarkerVelocityTapestry等表现层技术,虽然这些技术基本可以取代JSP技术,但实际上JSP依然是应用最广泛的表现层技术。本书介绍的JSP技术是基于JSP2.3Servlet3.1规范的,因此请使用支持JavaEE7规范的应用服务器或支持Servlet3.0Web服务器(比如Tomcat8.5.X)。
除了介绍JSP技术之外,本章也会讲解JSP的各种相关技术:ServletListenerFilter以及自定义标签库等技术。

概述

SVN必须联网

SVN是一个广泛使用的版本控制系统,其主要弱点在于:它必须时刻连着服务器,一旦断开网络,SVN就无法正常工作.

Git创造历史

由于Linus(Linux系统的创始人)对SVN非常“不感冒”(因为SVN必须联网才能使用),因此Linus在2005年着手开发了一个新的分布式版本控制系统:Git。不久,很多人就感受到了Git的魅力,纷纷转投Git门下。
2008年,GitHub网站上线了,它为开源项目免费提供Git存储,无数开源项目开始迁移至Github,包括jQueryMyBatis等。

SVN和Git的区别

SVNGit相比,二者的本质区别在于:

  • SVN是集中式的版本控制系统;
  • Git是分布式的版本控制系统。

集中式版本控制系统

先简单回顾一下集中式版本控制系统,以SVN为例。SWN的版本库是集中存放在中央服务器上的,每个开发者要干活时,都必须先从中央服务器同步最新的代码(下载最新的版本),然后开始修改,修改完了再提交给服务器。

分布式版本控制系统

再介绍一下分布式版本控制系统,以Git为例。对于Git而言,每个开发者的本地磁盘上都存放着一份完整的版本库,因此开发者工作时无须联网,直接使用本地版本库即可。只有在需要多人相互协作时,才通过“中央服务器”进行管理

简单来说,与SVN相比,Git的改变相当于让每个开发者都在本地“缓存”了一份完整的资源库,因此开发者对自己开发的项目文件执行添加、删除、返回之前版本时不需要通过服务器来完成。

1.8.1 下载和安装Git、 TortoiseGit

GitLinus开发的,因此起初Git自然是运行在Linux平台上的。后来Git也为WindowsMacOsX等平台提供了相应的版本。本书以Windows7为例来介绍Git的安装和使用。

下载和安装Git步骤

下载和安装Git请按如下步骤进行。
登录Git官网下载站点htps:/Git-scm.Com/download/win,下载Git的最新版本。本书成书之时Git的最新稳定版是2.15.0。
下载Git2.5.0,下载完成后得到一个Git2.15.0-64-bit.Exe文件(这是64位的安装文件。如果读者使用的是32位的操作系统,请下载32位的安装文件)

TortoiseGit

如果用户非常喜欢命令行工具,则可以直接在命令行窗口使用git命令来进行软件配置管理。但是,对于大部分读者而言,直接使用g命令会比较费劲,因此本书还会介绍一个非常好用的工具:TortoiseGit

1.8.2 创建本地资源库

第2章 JSP/Servlet及相关技术详解

第7章 Spring MVC的文件上传下载和拦截器机制 7.4 本章小结

本章介绍了Spring MVC的文件上传和文件下载,Spring MVC对文件上传提供了完美的封装, 使得用户能以非常简便的方式同时上传多个文件;Spring MVC专门提供了ResponseEntity类型, 用于实现文件下载。
接下来介绍了Spring MVC拦截器, 通过引用拦截器机制,Spring MVC框架可以使用可插拔方式管理各种功能。
第8章将重点介绍MyBatis持久化框架知识。