本栏博客目录

​Serlvet笔记一(Servlet基础)​​​​Servlet笔记二(请求和响应)​​​​Servlet笔记三(会话及其会话技术)​​ Servlet笔记四(JSP技术)
​Servlet笔记五(EL表达式和JSTL)​​​​Servlet笔记六(Servlet 高级)​​​​Servlet笔记七(JDBC)​​​​Servlet笔记八(数据库连接池与DBUtils工具)​​​​Servlet笔记九(JSP 开发模型)​​​​Servlet笔记十(文件上传和下载)​


文章目录



JSP 概述

什么是 JSP

JSP 全名是 Java Server Pages,它是建立在 Servlet 规范之上的动态网页开发技术。在 JSP 文件中,HTML 代码与 Java 代码共同存在,其中,HTML 代码用来实现网页中静态内容的显示,Java 代码用来实现网页中动态内容的显示。为了与传统 HTML 有所区别,JSP 文件的扩展名为 .jsp。

JSP 技术所开发的 Web 应用程序是基于 Java 的,它可以用一种简捷而快速的方法从 Java 程序生成 Web 页面,其使用上具有如下几点特征:

  • 跨平台:由于 JSP 是基于 Java 语言的,它可以使用 Java API,所以它也是跨平台的,可以应用于不同的系统中,如 Windows、Linux 等。当从一个平台移植到另一个平台时,JSP 和 JavaBean 的代码并不需要重新编译,这是因为 Java 的字节码是与平台无关的,这也应验了 Java 语言 “一次编译,到处运行” 的特点。
  • 业务代码相分离:在使用 JSP 技术开发 Web 应用时,可以将界面的开发与应用程序的开发分离开。开发人员使用 HTML 来设计界面,使用 JSP 标签和脚本程序来动态生成页面上的内容。在服务器端,JSP 引擎(或容器,如:Tomcat)负责解析 JSP 标签和脚本程序,生成请求的内容,并将执行结果以 HTML 页面的形式返回到浏览器。
  • 组件重用:JSP 中可以使用 JavaBean 编写业务组件,也就是使用一个 JavaBean 类封装业务处理代码或者作为一个数据存储模型,在 JSP 页面中,甚至在整个项目中,都可以重复使用这个 JavaBean。同时,JavaBean 也可以应用到其他 Java 应用程序中。
  • 预编译:预编译就是在用户第 1 次通过浏览器访问 JSP 页面时,服务器将对 JSP 页面代码进行编译,并且仅执行一次编译。编译好的代码将被保存,在用户下一次访问时,会直接执行编译好的代码。这样不仅节约了服务器的 CPU 资源,还大大地提升了客户端的访问速度。

JSP 运行原理

JSP 的工作模式是请求/响应模式,客户端首先发出 HTTP 请求,JSP 程序收到请求后进行处理并返回处理结果。在一个 JSP 文件第 1 次被请求时,JSP 引擎(容器)把该 JSP 文件转换成为一个 Servlet,而这个引擎本身也是一个 Servlet。JSP 的运行过程如下:
Servlet笔记四(JSP技术)_java

JSP 的运行过程具体如下:

  1. 客户端发出请求,请求访问 JSP 文件。
  2. JSP 容器先将 JSP 文件转换成一个 Java 源文件(Java Servlet 源程序),在转换过程中,如果发现 JSP 文件中存在任何语法错误,则中断转换过程,并向服务器端和客户端返回出错误信息。
  3. 如果转换成功,则 JSP 容器将生成的 Java 源文件编译成相应的字节码文件 *.class。该 class 文件就是一个 Servlet,Servlet 容器会像处理其他 Servlet 一样来处理它。
  4. 由 Servlet 容器加载转换后的 Servlet 类 (.class 文件)创建一个该 Servlet (JSP 页面的转换结果)实例,并执行 Servlet 的 jspInit() 方法。jspInit() 方法在 Servlet 的整个生命周期中只会执行一次。
  5. 执行 jspService() 方法来处理客户端的请求。对于每一个请求,JSP 容器都会创建一个新的线程来处理它。如果多个客户端同时请求该 JSP 文件,则 JSP 容器也会创建多个线程,使得每一个客户端请求都对应一个线程。JSP 运行过程中采用的这种多线程的执行方式可以极大地降低对系统资源的需求,提高系统的并发量并缩短响应时间。需要注意的是,由于第 (4)步生成的 Servlet 是常驻内存的,所以响应速度非常快。
  6. 如果 JSP 文件被修改了,则服务器将根据设置决定是否对该文件重新编译。如果需要重新编译,则使用重新编译后的结果取代内存中常驻的 Servlet,并继续上述处理过程。
  7. 虽然 JSP 执行效率很高,但在第 1 次调用的时候往往由于需要转换和编译,所以会产生一些轻微的延迟。此外,由于系统资源不足等原因,JSP 容器可能会以某种不确定的方式将 Servlet 从内存中移除,发生这种情况时首先会调用 jspDestroy() 方法,然后 Servlet 实例会被加入 “垃圾收集” 处理。
  8. 当请求完成后,响应对象由 JSP 容器接收,并将 HTML 格式的响应信息发送回客户端。

JSP 转换文件

IDEA 下 JSP 转换后的文件存储位置:

Servlet笔记四(JSP技术)_jsp_02

Servlet笔记四(JSP技术)_java_03

可以看出 Hello.jsp 文件已经被转换成源文件和 .class 文件。打开 Hello_jsp.java 文件,可查看转换后的源代码。

Servlet笔记四(JSP技术)_servlet_04

可以看出转换后的源文件 Hello_jsp 类没有实现 Servlet 接口,但继承了 org.apache.jasper.runtime.HttpJspBase 类。

HttpJspBase 类是 HttpServlet 的一个子类,所以,Hello_jsp 类就是一个Servlet。

HttpJspBase 类中的 init()、destory()、service() 方法用 final 修饰(子类不能重写)
但是也定义了 _jspInit()、_jsp_Destory()、_jspService() 方法,供子类重新、注意:_jspService() 方法是抽象方法,子类必须实现。

init() 方法调用了 _jspInit() 方法,destory() 方法调用了 _jspDestory() 方法,service() 方法调用 _jspService() 方法。

在用户访问 JSP 文件时,会调用 _jspService() 方法响应用户的请求。(由 service()方法 调用 _jspService() 方法)

JSP 基本语法

JSP 脚本元素

JSP 脚本元素是指嵌套在 <% 和 %> 之中的一条或多条 Java 程序代码。通过 JSP 脚本元素可以将 Java 代码嵌入到 HTML 页面中,所有可执行的 Java 代码,都可以通过 JSP 脚本来执行。

JSP 脚本元素主要包含以下3类:

  • JSP Scriptlets
  • JSP 声明语句
  • JSP 表达式

1. JSP Scriptlets

JSP Scriptlets 是一段代码段。当需要使用 Java 实现一些复杂操作或控制时,可以使用它。

JSP Scriptlets语法格式如下:

<% java代码(变量、方法、表达式等)%>

在 JSP Scriptlets 中声明的变量是 JSP 页面的局部变量,调用 JSP Scriptlets 时,会为局部变量分配内存空间,调用结束后,释放局部变量占有的内存空间。(编译为 Servlet 时,被放在 _jspService() 方法里面)

2. JSP声明语句

JSP 的声明语句用于声明变量和方法

<%!
定义的变量或方法
%>

在上述语法格式中,被声明的 Java 代码将被编译到 Servlet 的 _jspService() 方法之 ,记在 JSP 声明语句中定义的都是成员方法、成员变量、静态方法、静态代码块等。

在一个 JSP 页面中可以有多个 JSP 声明语句,单个声明中的Java 语句可以是不完整的,但是多个声明组合后的结果必须是完整的 Java 语句。

3. JSP 表达式

JSP 表达式(expression) 用于将程序数据输出到客户端,它将要输出的变量或表达式直接封装在以 “<%=” 开头和以 “%>” 结尾的标记中,其基本语法格式如下:

<%= expression %>

例:

<%= a+b %>
<%= print() %>

在上述语法格式中,JSP 表达式中的变量或表达式的计算结果将被转换成一个字符串,然后插入到 JSP 页面输出结果的相应位置处。

例子:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>JSP页面</title>
</head>
<%!
int a = 1, b = 2;
%>
<body>
<%!
public String print(){
String str = "Hello World";
return str;
}
%>
</body>
<%
out.println(a + b);
%>
<br />
<%
out.println(print());
%>
<br />
<%= a + b %>
<br />
<%= print() %>
</html>

Servlet笔记四(JSP技术)_servlet_05

JSP 注释

<%-- 注释信息 --%>

注意:JSP 页面被编译成 Servlet 程序时,会忽略 JSP 页面中被注释的内容,不会将注释信息发送到客户端。

JSP 指令

JSP 指令:为了设置 JSP 页面中的一些信息

page 指令

在 JSP 页面中,经常需要对页面的某些特性进行描述,例如,页面的编码方式、JSP 页面采用的语言等,这时,可以通过 page 指令来实现。page 指令的具体语法格式如下所示。

<%@ page 属性名1="属性值1" 属性名2="属性2" ... %>

page 用于声明指令名称,属性用来指定 JSP 页面的某些特性。page 指令提供了一系列与 JSP 页面相关的属性。(可放在整个页面的任何位置,但一般将其放在JSP页面最前面)

page 指令的常用属性

属性名称

取值范围

描述

language

    java    

指明解释该JSP文件时采用的语言,默认为Java

import

任何包名、类名

指定在JSP页面翻译成的Servlet源文件中导入的包或类。import是唯一可以声明多次的page指令属性。一个import属性可以引用多个类,中间用英文逗号隔开

session

true、false

指明该JSP内是否内置Session对象,如果为true,则说明内置Session对象,可以直接使用,否则没有内置Session对象。默认情况下,session属性的值为true。

注意:JSP引擎自动导入以下4个包:

java.lang.*

javax.servlet.*

javax.servlet.jsp.*

javax.servlet.http.*

isErrorPage

true、false

指定该页面是否为错误处理页面,如果为true,则该JSP内置有一个Exception对象的exception,可直接使用。默认情况下为false

errorPage

某个JSP页面的相对路径

指定一个错误页面,如果该JSP程序抛出一个未捕捉的异常,则转到errorPage指定的页面。errorPage指定的页面的isErrorPage属性为true,且内置的exception对象为未捕捉的异常

contentType

有效的文档类型

客户端浏览器根据该属性判断文档类型,例如:

HTML格式为text/html

纯文本格式为text/plain

JPG图像为image/jpeg

GIF图像为image/gif

Word文档为application/msword

pageEnCoding

当前页面

指定页面编码格式

include 指令

可以在JSP页面静态包含一个文件,例如HTML文件、文本文件等。

<%@ include file="被包含的文件地址" %>

include 指令只有一个 file 属性,该属性用来指定插入到 JSP 页面目标位置的文件资源。需要注意的是,插入文件的路径一般不以 " / " 开头,而是使用相对路径。被引入的文件与当前 JSP 文件需要共同合并才能翻译成一个 Servlet 源文件。

  1. 被引入的文件必须遵循 JSP 语法,其中的内容可以包含静态 HTML、JSP 脚本元素和 JSP 指令等普通 JSP 页面所具有的一切内容。
  2. 除了指令元素外,被引入的文件中的其他元素都被转换成相应的 Java 源代码,然后插入当前 JSP 页面所翻译成的 Servlet 源文件中,插入位置与 include 指令在当前 JSP 页面中的位置保持一致。
  3. file 属性的设置值必须使用相对路径,如果以 " / " 开头,表示相对于当前 Web 应用程序的根目录(注意不是站点根目录),否则,表示相对于当前文件。需要注意的是,这里的 file 属性指定的相对路径是相对于文件(file),而不是相对于页面(page)。

JSP 隐式对象

在 JSP 页面中,有一些对象需要频繁使用,如果每次都重新创建这些对象则会非常麻烦。为了简化 Web 应用程序的开发, JSP2.0 规范中提供了 9 个隐式(内置)对象,它们是 JSP 默认创建的,可以直接在 JSP 页面中使用。这 9 个隐式对象的名称、类型和描述如表:

名称

类型

描述

out

javax.servlet.jsp.JspWriter

用于页面输出

request

javax.servlet.http.HttpServletRequest

得到用户请求信息

response

javax.servlet.http.HttpServletResponse

服务器向客户端的回应信息

config

javax.servlet.ServletConfig

服务器配置,可以取得初始化参数

session

javax.servlet.http.HttpSession

用来保存用户的信息

application

javax.servlet.ServletConfig

所有用户的共享信息

page

java.lang.Object

指当前页面转换后的Servlet类的实例

pageContext

javax.servlet.jsp.PageContext

JSP的页面容器

exception

java.lang.Throwable

表示JSP页面所发生的异常,在错误页中才起作用

out 对象

在 JSP 页面中,经常需要向客户端发送文本内容,这时,可以使用 out 对象来实现。out 对象是 javax.servlet.jsp.JspWriter 类的实例对象,它的作用与 ServletResponse.getWriter() 方法返回的 PrintWriter 对象非常相似,都是用来向客户端发送文本形式的实体内容。不同的是,out 对象的类型为 JspWriter,它相当于一种带缓存功能的 PrintWriter。

Servlet笔记四(JSP技术)_html_06

通过 out 隐式对象写入数据相当于将数据插入到 JspWriter 对象的缓冲区中,只有调用了 ServletResponse.getWriter() 方法,缓冲区中的数据才能真正写入到 Servlet 引擎所提供的缓冲区中。

如果希望设置 out 对象可以直接将数据写入 Servlet 引擎提供的缓冲区,则可以通过 page 指令中操作缓冲区的 buffer 属性来实现。

<%@ page .....  buffer="0kb" %>

pageContext 对象

在 JSP 页面中,使用 pageContext 对象可以获取 JSP 的其他 8 个隐式对象。pageContext 对象是 javax.servlet.jsp.PageContext 类的实例对象,它代表当前 JSP 页面的运行环境,并提供了一系列用于获取其他隐式对象的方法。

pageContext 获取隐式对象的方法

方法名

功能描述

JspWriter getOut()

用于获取 out 隐式对象

Object getPage()

用于获取 page 隐式对象

ServletRequest getRequest()

用于获取 request 隐式对象

ServletResponse getResponse()

用于获取 response 隐式对象

HttpSession getSession()

用于获取 session 隐式对象

Exception getException()

用于获取 exception 隐式对象

ServletConfig getServletConfig()

用于获取 config 隐式对象

ServletContext getServletContext()

用于获取 application 隐式对象

pageContext 对象不仅提供了获取隐式对象的方法,还提供了存储数据的功能。pageContext 对象存储数据是通过操作属性来实现的。

pageContext 操作属性的相关方法

方法名称

功能描述

void setAttribute(String name, Object value, int scope)

用于设置 pageContext 对象的属性

Object getAttribute(String name, int scope)

用于获取 pageContext 对象的属性

void removeAttribute(String name, int scope)

删除指定范围内名称为 name 的属性

void removeAttribute(String name)

删除所有范围内名称为 name 的属性

Object findAttribute(String name)

从 4 个域对象中查找名称为 name 的属性

参数 name 指定的是属性名称,参数 scope 指定的是属性的作用范围。pageContext 对象的作用范围有 4 个值:

  • pageContext.PAGE_SCOPE:表示页面范围
  • pageContext.REQUEST_SCOPE:表示请求范围
  • pageContext.SESSION_SCOPE:表示会话范围
  • pageContext.APPLICATION_SCOPE:表示 Web 应用程序范围

需要注意的是,当使用 findAttribute() 方法查找名称为 name 的属性时,会按照 page、request、session 和 application 的顺序依次进行查找,如果找到,则返回属性的名称,否则返回 null。

exception 对象

在 JSP 页面中,经常需要处理一些异常信息,这时,可以通过 exception 对象来实现。exception 对象是 java.lang.Exception 类的实例对象,它用于封装 JSP 中抛出的异常信息。需要注意的是,exception 对象只有在错误处理页面才可以使用,即 page 指令中指定了属性 ​​<%@page isErrorPage="true" %>​​ 的页面才可以使用。

​实例​

​exception.jsp​

<%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="error.jsp" %>
<html>
<head>
<title>exception</title>
</head>
<body>
<%
int a = 3;
int b = 0;
%>
输出结果:<%= a / b %>
</body>
</html>

​error.jsp​

<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<html>
<head>
<title>error page</title>
</head>
<body>
<%= exception.getMessage() %><br />
</body>
</html>

可能引发错误的页面需要设置出错后要自动跳转的页面(errorPage属性),并把 exception 对象传递给另一个页面,而显示错误的页面需要设置属性 isErrorPage=“true”;

JSP 动作元素

JSP 动作元素用来控制 JSP 的行为,执行一些常用的 JSP 页面动作。通过动作元素可以实现使用多行 Java 代码能够实现的效果,如包含页面文件、请求转发等。

<jsp:include> 动作元素

在 JSP 页面中,为了把其他资源的输出内容插入到当前 JSP 页面的输出内容中,JSP 技术提供了 <jsp:include> 动作元素。

<jsp:include page="relativeURL" flush="true/false" />

page 属性用于指定被引入资源的相对路径;flush 属性用于指定是否将当前页面的输出内容刷新到客户端,默认情况下,flush 属性的值为 false。

<jsp:include> 包含的原理是将被包含的页面编译处理后,将结果包含在页面中。当浏览器第 1 次请求一个使用 <jsp:include> 包含其他页面时,Web 容器首先会编译被包含的页面,然后将编译处理后的返回结果包含在页面中,之后编译包含页面,最后将两个页面组合的结果回应给浏览器。

​dynamicInclude.jsp​

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>dynamicInclude page</title>
</head>
<body>
dynamicInclude.jsp 内的内容
<br />
<jsp:include page="included.jsp" flush="true" />
</body>
</html>

​included.jsp​

<%--
Created by IntelliJ IDEA.
User: sweetheart
Date: 2021/10/22
Time: 下午8:39
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>include</title>
</head>
<body>
<%Thread.sleep(5000);%>
included.jsp 内的文本<br />
</body>
</html>

<jsp:include>元素的 flush设置为 true 时,会先将当前页面内容输出内容刷新到客户端,然后再编译执行被包含的页面内容。而为 false 时,会将当前页面内容和被包含页面合在一起编译后一起运行输出。

Servlet笔记四(JSP技术)_jsp_07
5 秒后:
Servlet笔记四(JSP技术)_jsp_08

<jsp:include> 和 include 指令的区别

  • <jsp:include> 标签中要引入的资源和当前 JSP 页面是两个彼此独立的执行实体,即被动态引入的资源必须能够被 Web 容器独立执行。而 include 指令只能引入遵循 JSP 格式的文件,被引入文件与当前 JSP 文件需要共同合并才能翻译成一个 Servlet 源文件。
  • <jsp:include> 标签中引入的资源是在运行时才包含的,而且只包含运行结果。而 include 指令引入的资源是在编译时期包含的,包含的是源代码。
  • <jsp:include> 标签运行原理与 RequestDispatcher.include() 方法类似,即被包含的页面不能改变响应状态码或者设置响应头(即不能改变父页面的响应状态?),而 include 指令没有这方面的限制。

<jsp:forward> 动作元素

<jsp:forward> 动作元素将当前请求转发到其他 Web 资源(HTML 页面、JSP 页面和 Servlet 等),在执行请求转发后的当前页面将不再执行,而是执行该元素指定的目标页面。

<jsp:forward page="relativeURL" />

在上述语法格式中,page 属性用于指定请求转发到的资源的相对路径,该路径是相对于当前 JSP 页面的 URL。

​jspforward.jsp​

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>forward page</title>
</head>
<body>
<jsp:forward page="welcome.jsp" />
</body>
</html>

​welcome.jsp​

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>welcome page</title>
</head>
<body>
你好,欢迎进入首页,当前访问时间是:
<%
out.println(new java.util.Date());
%>
</body>
</html>

Servlet笔记四(JSP技术)_html_09

可以看出,虽然浏览器访问的是 jspforward.jsp,但浏览器显示出了 welcome.jsp 页面的输出内容。由于请求转发是服务器端的操作,浏览器并不知道请求的页面,所以浏览器的地址栏不会发生改变。