1. JSP 概述
1.1 JSP 简介
- 是 Servlet 的扩展
- 是一种基于 Java 的 服务器端技术
-
1.2 JSP 特别点
简单快捷
- 动态内容的生成和显示分离
- 组件重用
-
1.3 JSP 与 Servlet 的比较
示例:
hello-jsp.jsp<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello JSP</title>
</head>
<body>
<%
out.print("Hello JSP!");
%>
</body>
</html>
指令:<%@ directive attribute=”value” %> | 指令 | 描述 | | —- | —- | | <%page … %> | 定义页面的依赖属性,比如脚本语言、error页面、缓存需求等等 | | <%@ include … %> | 包含其他文件 | | <%@ taglib … %> | 引入标签库的定义,可以是自定义标签 |
-
1.4 执行原理
- 首次被请求
- 再次被请求
翻译后的 Java 源码和编译后的字节码文件,都在 Tomcat 目录下的 work 子目录中。
1.5 生命周期
理解 JSP 底层功能的关键就是去理解它们所遵守的生命周期。
JSP 生命周期就是从创建到销毁的整个过程,类似于 Servlet 生命周期,区别在于 JSP 生命周期还包括将 JSP 文件编译成 Servlet。
- 编译阶段:Servlet 容器编译 Servlet 源文件,生成 Servlet 类。
- 初始化阶段:加载与 JSP 对应的 Servlet 类,创建其实例,并调用它的初始化方法。
- 执行阶段:调用与 JSP 对应的 Servlet 实例的服务方法。
- 销毁阶段:调用与 JSP 对应的 Servlet 实例的销毁方法,然后销毁 Servlet 实例。
1.6 JSP 编译
当浏览器请求 JSP 页面时,JSP 引擎会首先去检查是否需要编译这个文件。如果这个文件没有被编译过,或者在上次编译后被更改过,则编译这个 JSP 文件。
编译的过程包括三个步骤:
- 解析 JSP 文件。
- 将 JSP 文件转为 Servlet。
- 编译 Servlet。
life-cycle.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSP LifeCycle</title>
</head>
<body>
<%!
int initVar = 0;
int serviceVar = 0;
int destroyVar = 0;
%>
<%!
public void jspInit(){
initVar++;
System.out.println("jspInit(): JSP被初始化了" + initVar + "次");
}
public void jspDestroy(){
destroyVar++;
System.out.println("jspDestroy(): JSP被销毁了" + destroyVar + "次");
}
%>
<%
serviceVar++;
System.out.println("_jspService(): JSP共响应了" + serviceVar + "次请求");
String content1 = "初始化次数 : " + initVar;
String content2 = "响应客户请求次数 : " + serviceVar;
String content3 = "销毁次数 : " + destroyVar;
%>
<p><%=content1 %></p>
<p><%=content2 %></p>
<p><%=content3 %></p>
</body>
</html>
问题:contentType 和 pageEncoding 都有对字符集的设置,两者有什么区别?
2. JSP 指令和动作
2.1 JSP 指令
JSP 指令用来向 JSP 引擎(Tomcat)提供编译信息。
- page 指令
- include 指令
-
2.1.1 page 指令
用于设置页面的各种属性,如导入包、指明输出内容类型、控制Session等。
- 一般位于JSP 页面的开头部分,一个 JSP 页面可包含多条 page 指令。 | 属性名 | 说明 | | —- | —- | | language | 设定JSP页面使用的脚本语言。默认为java,目前只可使用java语言 | | extends | 此JSP页面生成的Servlet的父类 | | import | 指定导入的java软件包或类名列表。如果多个类时,中间用逗号隔开 | | session | 设定JSP页面是否使用Session对象。值为“true|false”,默认为true | | buffer | 设定输出流是否有缓冲区。默认为8KB,值为“none | sizekb” | | autoFlush | 设定输出流的缓冲区是否要自动清除。值为“true | false”,默认值为true | | isThreadSafe | 设定JSP页面生成的Servlet是否实现SingleThreadModel接口。值为“true | false”,默认为true | | info | 主要表示此JSP网页的相关信息 | | errorPage | 设定JSP页面发生异常时重新指向的页面URL | | isErrorPage | 指定此JSP页面是否为处理异常错误的网页。值为“true | false”,默认为false | | contentType | 指定MIME类型和JSP页面的编码方式 | | pageEncoding | 指定JSP页面的编码方式 | | isELlgnored | 指定JSP页面是否忽略EL表达式。值为“true | false”,默认值为false |
2.1.1.1 import 属性
- import属性可以在当前JSP 页面中引入 JSP 脚本代码需要用到的其他类。
- 如果需要引入多个类或包,可以在中间使用逗号隔开或使用多个page 指令。
page-instruction.jps
<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>page 指令</title>
</head>
<body>
<p>现在时间:<%=new Date() %></p>
</body>
</html>
对日期进行格式化
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>page 指令</title>
</head>
<body>
<%
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
%>
<p>现在时间:<%=sdf.format(new Date()) %></p>
</body>
</html>
注意:import 是 page 指令中唯一一个可以在同一个 JSP 页面中多次出现的属性。
2.1.1.2 contentTyp 属性
- contentType 用于指定 JSP 输出内容的MIME 类型和字符集。MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
- MIME 类型通常由两部分组成:
- MIME类型
- MIME 子类型
- 通过设置contentType 属性,可以改变JSP 输出的 MIME 类型,从而实现一些特殊的功能。
page-excel.jsp
<%@ page language="java" contentType="application/vnd.ms-excel; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSP 生成 Excel 表格</title>
</head>
<body>
<table border="1" cellspacing="0" cellpadding="3">
<thead>
<tr>
<th>姓名</th>
<th>兵器</th>
</tr>
</thead>
<tbody>
<tr>
<td>唐僧</td>
<td>九环锡杖</td>
</tr>
<tr>
<td>孙悟空</td>
<td>金箍棒</td>
</tr>
<tr>
<td>猪八戒</td>
<td>九齿钉耙</td>
</tr>
<tr>
<td>沙僧</td>
<td>降妖宝杖</td>
</tr>
</tbody>
</table>
</body>
</html>
page-word.jsp
<%@ page language="java" contentType="application/msword; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSP 生成 Excel 表格</title>
</head>
<body>
<table border="1" cellspacing="0" cellpadding="3">
<thead>
<tr>
<th>姓名</th>
<th>兵器</th>
</tr>
</thead>
<tbody>
<tr>
<td>唐僧</td>
<td>九环锡杖</td>
</tr>
<tr>
<td>孙悟空</td>
<td>金箍棒</td>
</tr>
<tr>
<td>猪八戒</td>
<td>九齿钉耙</td>
</tr>
<tr>
<td>沙僧</td>
<td>降妖宝杖</td>
</tr>
</tbody>
</table>
</body>
</html>
2.1.2 include 指令
- include 指令用于在当前 JSP 中包含其他文件,被包含的文件可以是 JSP、HTML 或文本文件。
- 包含的过程发生在将 JSP 翻译成 Servlet 时,当前 JSP 和被包含的 JSP 会融合到一起,形成一个 Servlet,然后进行编译并运行。
include-index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>主页</title>
</head>
<body>
<%@ include file="include-header.jsp" %>
<h1>Hello JSP!</h1>
<%@ include file="include-footer.jsp" %>
</body>
</html>
include-header.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>头部</title>
</head>
<body>
<h1>Hello Header</h1>
</body>
</html>
include-footer.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>版权</title>
</head>
<body>
<h1>Hello Footer</h1>
</body>
</html>
2.2 JSP 标准动作
2.2.1 JavaBean 简介
JavaBean实际上就是一种满足特定要求的Java类:
- 是一个公有类,含有公有的无参构造方法;
- 属性私有;
-
2.2.2 JSP 动作
在 JSP 中可以使用 XML 语法格式的一些特殊标记来控制行为,称为 JSP 标准动作(Standard Action)。
JSP规范定义了一系列标准动作,常用有下列几种:
- jsp:useBean:查找或者实例化一个 JavaBean;
- jsp:setProperty:设置 JavaBean 的属性;
- jsp:getProperty:输出某个 JavaBean 的属性;
- jsp:include:在页面被请求时引入一个文件;
- jsp:forward:把请求转发到另一个页面。
2.2.2.1
useBean标准动作用来查找或者实例化一个JavaBean。<jsp:useBean id="name" class="className" scope="scope" /> <jsp:useBean id="name" type="className" scope="scope" />
id:指定该 JavaBean 实例的变量名,通过 id 可以访问这个实例。
- class:指定 JavaBean 的类名。如果需要创建一个新的实例,容器会使用 class 指定的类并调用无参构造方法来完成实例化。
scope 指定 JavaBean 的作用范围。可以使用四个值:page、request、session 和 application。
name:指定JavaBean对象名,与useBean标准动作中的id相对应;
- property:指定JavaBean中需要赋值的属性名;
- value:指定要为属性设置的值;
param:指定请求中的参数名(该参数可以来自表单、URL传参数等),并将该参数的值赋给property所指定的属性。
2.2.2.3
getProperty标准动作用于访问一个bean的属性并将其输出。访问所得到的值将转换成String类型。
<jsp:getProperty name="id" property="属性名"/>
name:指定JavaBean对象名,与useBean标准动作中的id相对应;
- property:指定JavaBean中需要访问的属性名。
User.java
package cn.cyber.entity;
public class User {
public User() {
super();
System.out.println("Constructor()...");
}
public User(String username, String password) {
super();
this.username = username;
this.password = password;
}
private String username;
private String password;
public String getUsername() {
System.out.println("getUsername()...");
return username;
}
public void setUsername(String username) {
System.out.println("setUsername()...");
this.username = username;
}
public String getPassword() {
System.out.println("getPassword()...");
return password;
}
public void setPassword(String password) {
System.out.println("setPassword()...");
this.password = password;
}
}
login.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<form action="login.jsp" method="post">
<div>
<label for="uname">Username: </label>
<input type="text" id="uname" name="user_name">
</div>
<div>
<label for="upwd">Password: </label>
<input type="password" id="upwd" name="pass_word">
</div>
<input type="submit" value="Submit">
</form>
</body>
</html>
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- 实例化一个 JavaBean(Java 类) -->
<!--
User user = new User();
-->
<jsp:useBean id="user" class="cn.cyber.entity.User" scope="request"></jsp:useBean>
<!-- 对实例化后的 JavaBean 进行初始化,即对属性进行赋值 -->
<!--
user.setUsername(request.getParamenter("user_name"));
user.setPassword(request.getParamenter("pass_word"));
-->
<jsp:setProperty name="user" property="username" param="user_name"/>
<jsp:setProperty name="user" property="password" param="pass_word"/>
<!-- 展示已经实例化的 JavaBean 的属性值 -->
<!--
user.getUsername("username");
user.getPassword("password");
-->
<p>Username: <jsp:getProperty name="user" property="username"/></p>
<p>Password: <jsp:getProperty name="user" property="password"/></p>
</body>
</html>
2.2.2.4
- include 标准动作用于在 JSP 页面动态包含其他页面。
- 该动作的功能与 JSP 的 include 指令类似,区别是 include 指令在编译时完成包含,是静态包含(一共只有一个文件);而 include 标准动作是在运行时完成包含,是动态包含(有 N 个 JSP 文件,则有 N 个 Java 文件,同时,有 N 个 class 文件)。
语法如下:
<jsp:include page="被包含文件的URL" />
如果需要额外的请求参数,则需要使用
<jsp:include page="被包含文件的URL">
<jsp:param name="参数名" value="参数值" />
</jsp:include>
对之前的 include-index.jsp 进行改造:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>主页</title>
</head>
<body>
<!--
<%@ include file="include-header.jsp" %>
-->
<jsp:include page="include-header.jsp"></jsp:include>
<h1>Hello JSP!</h1>
<jsp:include page="include-footer.jsp"></jsp:include>
<!--
<%@ include file="include-footer.jsp" %>
-->
</body>
</html>
2.2.2.5
forward 标准动作用于将用户的请求转发到另一个 HTML 文件、JSP 页面或 Servlet,语法格式如下:
<jsp:forward page="URL地址" />
如果需要额外的请求参数,则需要使用
<jsp:forward page="被包含文件的URL">
<jsp:param name="参数名" value="参数值" />
</jsp:forward>
注意:forward 动作与 RequestDispatcher 类型对象的 forward 方法类似,调用者和被调用者共享同一个 request 对象。
2.2.2.6
param 标准动作用于为其他动作标签提供附加参数值信息,该动作可以与
<jsp:param name="参数名" value="参数值" />
例如:
<jsp:include page="show.jps">
<jsp:param name="username" value="admin" />
</jsp:include>
上述代码中,在 include 标准动作中使用
测试
本题目共涉及4个文件: 1.login.html:登录页面,提交用户名和密码给 login.jsp。 2.login.jsp:实例化 JavaBean 并进行初始化,然后使用 JSP 标准动作转发到 index.jsp。 3.index.jsp:使用 JavaBean,显示用户名和密码;使用 JSP 标准动作包含 header.jsp 页面。 4.header.jsp:打印“Hello XXX”(XXX 为用户名)。
3. JSP 内置对象
3.1 内置对象概述
JSP 内置对象:由 JSP 容器(Tomcat)加载,不需要声明就可以直接在 JSP 页面中使用的对象。
JSP 九大内置对象
名称 | 说明 |
---|---|
request | 客户端的请求,包含所有从浏览器发往服务器的请求信息 |
response | 返回客户端的响应 |
session | 会话对象,表示用户的会话状态 |
application | 应用上下文对象,作用于整个应用程序 |
out | 输出流,向客户端输出数据 |
pageContext | 用于存储当前 JSP 页面的相关信息 |
config | JSP 页面的配置信息对象 |
page | 表示 JSP 页面的当前实例 |
exception | 异常对象,用于处理 JSP 页面中的错误 |
3.2 常用内置对象
3.2.1 out 对象
out 对象是一个输出流,用于将信息输出到网页中。常用得方法:
- print()
- println()
- writer()
三者都是输出信息,有区别么?
out.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>out 对象</title>
</head>
<body>
<%
out.print("Hello Print");
out.println("Hello Println");
out.write("Hello Write");
%>
</body>
</html>
- println() 虽然看似是换行,但转成网页之后,这种换行被认为是空格,所以输出的内容仍然在同一行,用空格分隔。
- print() 和 println() 是 JspWriter 类中定义的方法,write() 则是 Writer 类中定义的。
- print() 和 println() 方法可将各种类型的数据转换成字符串的形式输出,而 write() 方法只能输出字符、字符数组和字符串等与字符相关的数据。
- 如果字符串对象的值为 null,print() 和 println() 方法将输出内容为“null”的字符串,而 write() 方法则是抛出 NullPointerException 异常。
Student.java
package cn.cyber.entity;
public class Student {
private String stuNo;
private int age;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String stuNo, int age) {
super();
this.stuNo = stuNo;
this.age = age;
System.out.println("Student Constructor...");
}
public String getStuNo() {
return stuNo;
}
public void setStuNo(String stuNo) {
this.stuNo = stuNo;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [stuNo=" + stuNo + ", age=" + age + "]";
}
}
out.jsp
<%@page import="cn.cyber.entity.Student"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>out 对象</title>
</head>
<body>
<%
out.print("Hello Print");
out.println("Hello Println");
out.write("Hello Write");
Student student = new Student("111", 20);
out.print(student);
out.println(student);
// out.write(student);
String text = null;
out.print(text);
out.println(text);
try{
out.write(text);
} catch(Exception e){
e.printStackTrace();
out.print(e.getMessage());
out.print("text=null");
}
%>
</body>
</html>
除了用于输出数据的上述三种方法外,out 对象中还拥有其他常用方法:
- clear():清除缓冲区的内容,如果缓冲区已经被刷出(flush),将抛出 IOException。
- clearBuffer():清除缓冲区的当前内容,和 clear() 方法不同,即使缓冲区已经 flush,也不会发生异常。
- flush():输出缓冲区中的内容。
-
3.3.2 request 对象
request 对象是r HttpServletRequest 接口实现类的实例。包含所有从浏览器发往服务器的请求信息,例如请求的来源、Cookie 和客户端请求相关的数据。
request 对象中最常用得方法如下: String getParameter(String name):根据参数名称得到单一参数值;
- String[] getParameterValues(String name):根据参数名称得到一组参数值;
- void setAttribute(String name, Object value):以名/值的方式存储数据;
- Object getAttribute(String name):根据名称得到存储的数据。
注意:
- 对于复选框 checkbox,需要先判断其数组是否为 null,再进行遍历,因为如果用户没有选择任何选项,则 getParameterValues() 返回 null。
- 对于普通文本框 text,当没有任何输入信息时,浏览器仍然提交该表单元素信息,这时再服务器端通过 getParameter() 获取表单值时,结果为空字符串””。
- 对于单选框 radio 或复选框 checkbox,当没有任何选择时,浏览器不会提交该表单元素信息,因此再服务器端获取该表单元素信息时为 null。
- 并不是每个文本框都会生成请求参数,而是有 name 属性得文本框才生成请求参数,即每个有 name 属性得文本框对应一个请求参数。
- 如果文本框配置了 disabled=”disabled”属性,则相应表单提交数据时不会提交该文本框信息。
-
3.3.3 response 对象
response 对象是 HttpServletResponse 接口实现类的实例,负责将响应结果发送到浏览器端。
response 常用的方法如下: void setContentType(String name):设置响应内容的类型和字符编码;
void sendRedirect(String url):重定向到指定的 URL 资源。
3.3.4 session 对象
session 对象是 HttpSession 接口实现类的实例,表示用户的会话状态。
session 常用的方法如下:void setAttribute(String name, Object value):以名/值的方式存储数据;
Object getAttribute(String name):根据名称得到存储的数据。
3.3.5 application 对象
application 对象是 ServletContext 接口实现类的实例,其作用于整个应用程序,由应用程序中的所有 Servlet 和 JSP 页面共享。
application 常用的方法如下:void setAttribute(String name, Object value):以名/值的方式存储数据;
Object getAttribute(String name):根据名称得到存储的数据。
3.3.6 page 对象
page 对象表示 JSP 页面的当前实例,实际上相当于 this,可以提供对 JSP 页面上定义的所有对象的访问。实际开发中很少使用 page 对象。
3.3.7 pageContext 对象
pageContext 对象可以访问当前 JSP 页面所有的内置对象,如 request、response、session、application、out等。pageContext 对象还提供存取数据的方法,作用范围为当前 JSP 页面。
pageContext 常用方法如下:void setAttribute(String name, Object value):以名/值方式存储数据;
Object getAttribute(String name):根据名称得到存储的数据。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <% if(pageContext.getAttribute("pageCount") == null){ pageContext.setAttribute("pageCount", 0); } if(request.getAttribute("requestCount") == null){ request.setAttribute("requestCount", 0); } if(session.getAttribute("sessionCount") == null){ session.setAttribute("sessionCount", 0); } if(application.getAttribute("applicationCount") == null){ application.setAttribute("applicationCount", 0); } %> <% // page 计数 int pageCount = Integer.parseInt(pageContext.getAttribute("pageCount").toString()); pageCount++; pageContext.setAttribute("pageCount", pageCount); // request 计数 int requestCount = Integer.parseInt(request.getAttribute("requestCount").toString()); requestCount++; request.setAttribute("requestCount", requestCount); // session 计数 int sessionCount = Integer.parseInt(session.getAttribute("sessionCount").toString()); sessionCount++; session.setAttribute("sessionCount", sessionCount); // application 计数 int applicationCount = Integer.parseInt(application.getAttribute("applicationCount").toString()); applicationCount++; application.setAttribute("applicationCount", applicationCount); %> <p>page 计数:<%=pageContext.getAttribute("pageCount") %></p> <p>request 计数:<%=request.getAttribute("requestCount") %></p> <p>session 计数:<%=session.getAttribute("sessionCount") %></p> <p>application 计数:<%=application.getAttribute("applicationCount") %></p> </body> </html>
JSP 的四大作用域:pageContext、request、session、application。
这四个对象都是通过 setAttribute(String name, Object value) 方法来保存数据的,通过 getAttribute(String name) 方法获得数据的。
开发中要根据实际情况选择合适的范围,尽量使用小的范围,因为越大的范围其生命周期越长,相应的就会占用更多的服务器资源。
3.3.8 config 对象
config 对象用来存放 Servlet 的一些初始化信息,常用方法如下:
String getInitParameter(String name):返回指定名称的初始参数值。
- Enumeration getInitParameterNames():返回所有初始参数的名称集合。
- ServletContext getServletContext():返回 Servlet 上下文。
- String getServletName():返回 Servlet 的名称。
3.3.9 exception 对象
exception 对象表示 JSP 页面中的异常信息。需要注意的是,要使用 exception 对象,必须将此 JSP 中 page 指令的 isErrorPage 属性值设置为 true。