JavaWeb详解(第四篇)之JSP 简介
1、JSP概述
1.1、什么是JSP
JSP 全称是 Java Servlet Pages,它是和 servlet 技术一样,都是 SUN 公司定义的一种用于动态开发 web 资源的技术。
JSP 这门技术最大的特点在于,写 JSP就像在写 html ,但:它相比 html 而言,html 只能为用户提供静态数据,而 JSP 技术允许在页面中嵌套 java 代码,为用户提供动态数据。
jsp=html+css+javascript+java代码+jsp标签(servlet)
1.2、为什么需要JSP
我们在之前的学习中,经常这样写:
相比Servlet 而言,servlet 很难对数据进行排版(需要写很多的标签、换行等),而 JSP 出了可以用 java 代码产生动态数据的同时,也很容易对数据进行排版,JSP就是替代Servlet输出HTML的。
1.3、JSP的本质
jsp页面本质上是一个Servlet程序。
如果是第一次访问该 jsp 文件,web 服务器就会把 该 jsp 文件翻译成一个同名的 Servlet 文件,然后再把 class 加载进内存,如果是第二次(或者以后)访问,就直接访问内存中的实例,因此 jsp 也是单例,所以第一次访问 jsp 网站的速度比较慢。 如果这个 jsp 文件被修改了,就相当于重新访问该 jsp 文件。
例如:新建一个a.jsp如下
<%@ page contentType="text/html;charset=GBK" language="java" isErrorPage="true"%>
<!DOCTYPE html>
<html>
<head>
<title>a.jsp</title>
</head>
<body>
<h1>我是a.jsp</h1>
<%
String s = "HelloWorld";
out.println(s);
%>
</body>
</html>
当我第一次访问时,找到我们项目的部署位置:
然后找到Catalina目录:..\work\Catalina\localhost\JspWeb\org\apache\jsp
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class a_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;
}
//JSP也是Servlet,运行时只有一个实例
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 {
//9大内置对象
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
java.lang.Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request);
//页面声明了isErrorPage="true"属性才会有
if (exception != null) {
response.setStatus(javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
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,
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("\r\n");
out.write("<!DOCTYPE html>\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("<title>a.jsp</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write(" <h1>我是a.jsp</h1>\r\n");
out.write(" ");
String s = "HelloWorld";
out.println(s);
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);
}
}
}
我们发现有个叫a_jsp.java的文件,跟踪原代码看到它它继承了HttpJspBase 类。 HttpJspBase 类又继承了 HttpServlet 类。 也就是说。 jsp 翻译出来的 java 类, 它间接了继承了 HttpServlet 类。 也就是说, 翻译出来的是一个 Servlet 程序 。细心的人可能发现,输出跟我们手写的很像,是的jsp帮我们完成了这部分复杂的工作。
JSP比Servlet更方便更简单的一个重要原因就是:内置了9个对象!内置对象有:out、session、response、request、config、page、application、pageContext、exception。
2、JSP的语法
2.1、JSP的指令
JSP指令用来声明JSP页面的相关属性,用于从 JSP 发送一个信息到容器,比如设置全局变量,文字编码,引入包等。常用的指令如下:
<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ include file=" " %>
<%@ taglib prefix=" " uri="" %>
指 令 | 说 明 |
---|---|
page | page 指令用于定义 JSP 页面的各种属性。page 是最复杂的一个指令,它的属性很多,常用的属性有 import、language、pageEncoding 等。 |
include | 静态包含指令,用于引入其它 JSP 文件。使用 include 指令引入的其它 JSP 文件,JSP 引擎将把这两个 JSP 文件翻译成一个 servlet,所以将 include 称为静态包含。 |
taglib | 用于在 JSP 页面中导入标签库(JSP 标准标签库、第三方标签库、自定义标签库)。 |
2.1.1、jsp 头部的page指令
<%@ page contentType="text/html;charset=GBK" language="java" %>
page 指令中常用属性有:
属性 | 描述 |
---|---|
language="xx" | JSP 中嵌入的代码是 xx ,暂时只支持 java |
import="包.*,包.类名" | 在该 JSP 页面引入包或者某个具体类 |
session=[true|false] | 是否在 JSP 页面中获取 session 对象 |
buffer=[none|8k|指定大小] | 给out对象使用的缓冲区是多大,默认是8k |
autoFlash=[true|false] | 当buffer 满后,是否自动刷新到浏览器 |
isThreadSafe=[true|false] | 默认 true 表示该 JSP 的线程安全是由程序员控制,false 则对应的 Servlet 将实现线程安全接口 |
errorPage=”相对 JSP 页面” | 当JSP 页面出现错误时,自动跳转到指定的 JSP 页面 |
isErrorPage=[true|false] | 指定该 JSP 页面是否专门用于作为error 页面,默认为 false,如果设为 true,则在该页面直接使用 Exception 内置对象 |
contentType="text/html; charset=GBK" | 指定页面以什么方式显示页面 |
pageEncoding="GBK" | 指定 Servlet 引擎以什么方式翻译 JSP——>Servlet ,并指定页面以什么方式显示页面 |
extends="包名.类名" | 继承其他类,可以在本jsp直接使用类中的方法 |
2.1.2、include指令
注:被引入的 JSP 页面中,不能够存在与当前页面有冲突的变量。
语法:
<%@ include file=”文件路径” %>
案例:它会把b.jsp的内容都包含进来,再一起编译。
<%@ include file=”b.jsp” %>
2.1.3、taglib指令
用来引入在JSP页面中使用到的第三方标签库。这个后面再详细介绍。
2.2、JSP常用脚本
脚本元素就是 java页面中的java代码,也叫片段的scriplet。JSP脚本有三种方式:
1)JSP声明:变量、方法和类的声明。语法: <%!声明变量、方法和类的代码%>
2)JSP中嵌入Java代码(片段)。语法:<% java代码 %>
3)JSP表达式。语法:<%=变量或可以返回值的方法或 Java 表达式%>
注:函数不能在<% %>(java片段)中定义
2.3、JSP文件的注释
三种方式:
1)<!-- 注释的内容 --> html的注释方法,可以在 JSP 中使用
2)<%-- 注释的内容 --%> jsp 专用的注释
3)//单行注释
/*多行注释*/
/**文档注释*/
java 注释
区别:
<!-- -->
会在 servlet 中生成对应的 out.write(“<!-- -->”)
,这样在返回给浏览器的静态页面中也有<!-- -->
,只是用户看不到而已;
<%-- --%>
则在 servlet 中没有任何输出,建议使用<%-- --%>
java 注释,会被翻译到java源代码中!
2.4、JSP的动作
JSP动作(JSP Actions)是一组JSP内置的标签,只书写少量的标记代码就能够使用JSP提供丰富的功能,JSP行为是对常用的JSP功能的抽象和封装。
JSP Actions是使用 xml 语法写的,是 jsp 规定的一些列标准动作,在容器处理 jsp 时,当容器遇到动作元素时,就执行相应的操作。可能看完概念还是很抽象。
常用的JSP动作有:
JSP Actions | 语法 | 描述 |
---|---|---|
include | <jsp:include page="relativeURL|<%=expressicry%>"></jsp:include > | 动态引入另一个文件 |
forward | <jsp:forward page="跳转的jsp页面"> [<jsp:param name="" value=""/>] [<jsp:param name="" value=""/>] </jsp:forward> 转发 | 在开发jsp的过程中,我们通常把jsp放入WEB-INF目录,目的是为了防止用户直接访问这些jsp文件.在WebRoot下我们有一个入口页面,它的主要转发<jsp:forword file=”/WEB-INF/xx.jsp”></jsp:forword> |
param | <jsp:param name="" value=""/> | 给一个 JSP 设置参数,常常与<jsp:include> 或者<jsp:forward> 集合使用<jsp:include page=""> <jsp:param name="" value=""/> <jsp:param name="" value=""/></jsp:include >,也可以给Bean或Applet传递参数。 |
useBean | <jsp:useBean class="" id=""> </jsp:useBean> | 创建一个 javaBean 实例 |
setProperty | <jsp:setProperty name="对象" property="属性" value="属性值" scope="作用域"/> | 给一个 javaBean 实例属性赋值 |
getProperty | <jsp:getProperty property="" name=""/> | 取得一个 javaBean 实例的成员变量 |
plugin | <jsp:plugin code="" codebase="" type="bean"></jsp:plugin > | 使用插件 |
fallback | <jsp:fallback></jsp:fallback > | 指定浏览器不支持或无法启动Bean或Applet时,在页面上打印输出信息 |
directive | <jsp:directive.include file="head.jsp"></jsp:directive.include > | 替代指令<%@%> 的语法的 |
2.4.1、include动作
前面已经提及到了,include指令是静态包含,include动作是动态包含。其实include行为就是封装了request.getRequestDispatcher(String url).include(request,response)。
动态包含也可以像静态包含一样。 把被包含的内容执行输出到包含位置。而include动作和include指令的区别:
1)属性不同
include 指令通过 file 属性来指定被包含的页面,该属性不支持任何表达式。
<jsp:include>
动作是通过 page 属性来指定被包含页面的,该属性支持 JSP 表达式。
2)处理方式不同
使用 include 指令包含文件时,被包含文件的内容会原封不动地插入到包含页中使用该指令的位置,然后 JSP 编译器再对这个合成的文件进行翻译,所以最终编译后的文件只有一个。(静态包含,被包含文件尽量不要使用<html></html>
、<body></body>
这种标记,还要避免变量冲突)
而使用<jsp:include>
动作包含文件时,只有当该标记被执行时,才会引入被包含的的页面进行编译,再将译之后的视图再引入到当前页面,然后继续执行后面的代码。所以被引入的页面即使有与当前相同的Java变量也没影响。
(如果被包含的文件改变,则静态包含的主页面需要重新编译。而动态包含只须重新编译被包含的文件即可。)
注:动态包含的原理(使用如下代码去调用被包含的 jsp 页面)
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "b.jsp", out, false);
2.4.2、forward动作
前面我们学习servlet的时候,我们使用request.getRequestDispatcher(String url).forward(request,response),进行跳转,而使用forward动作其实是对他的封装。
使用案例1:
1)新建一个b.jsp
2)在a.jsp中加入
<%@ page contentType="text/html;charset=GBK" language="java"%>
<!DOCTYPE html>
<html>
<head>
<title>a.jsp</title>
</head>
<body>
<h1>我是a.jsp</h1>
<%
String s = "HelloWorld";
out.println(s);
%>
<jsp:forward page="b.jsp"></jsp:forward>
</body>
</html>
3)案例效果
4)查看编译后的源码
if (true) {
_jspx_page_context.forward("b.jsp");
return;
}
使用案例2:
1)在a.jsp中加入
<jsp:forward page="b.jsp">
<jsp:param name="username" value="mjx"/>
<jsp:param name="password" value="123"/>
</jsp:forward>
2)在b.jsp中使用
我获取到的参数:
<%
String username = request.getParameter("username");
String password = request.getParameter("password");
%><br>
用户名:<%=username %><br>
密码:<%=password %>
3)案例效果
2.4.3、param动作
当使用<jsp:include>
或</jsp:forword>
时可以使用param动作向这个资源传递参数。上面的案例中已经使用到了,这里就不再演示了。
扩展:什么是javaBean
在学习useBean动作之前我们先了解下,什么是javaBean?
1)什么是javaBean
JavaBean是一个遵循特定写法的Java类,它通常具有如下特点:
a)这个Java类必须具有一个无参的构造函数;
b)属性必须私有化;
c)私有化的属性必须通过public类型的方法暴露给其它程序,并且方法的命名也必须遵守一定的命名规范;
2)为什么需要javaBean
Java语言欠缺属性、事件、多重继承功能。不像html的标签、js对象都有很多内置的属性。当我们在JSP页面嵌入大量的HTML 代码、JS 代码、CSS 代码、Java 代码,这就使得我们的页面结构很混乱。而且需要我们自己手写大量的胶水代码,重复的声明使用,javaBean正是编写这套胶水代码的惯用模式或约定,JavaBean 使得 JSP编程模式变得清晰,程序可读性强。JavaBean 将程序的业务逻辑封装成 Java 类,提高了程序的可维护性和代码的可重用性。
例如:
public class User {
//------------------User类封装的私有属性---------------------------------------
// 姓名 String类型
private String name;
// 性别 String类型
private String sex;
// 年龄 int类型
private int age;
//------------------User类的无参数构造方法---------------------------------------
public User() {
}
//------------------User类对外提供的用于访问私有属性的public方法-----------------------
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
在学useBean之前,我们要使用一个对象,可能会这样写:
<%@ page contentType="text/html;charset=GBK" language="java"%>
<%@ page import="com.cn.domain.User" %>
<!DOCTYPE html>
<html>
<head>
<title>a.jsp</title>
</head>
<body>
<h1>我是a.jsp</h1>
<%
User u = new User();
u.setName("mjx");
u.setAge(18);
u.setSex("男");
%>
<% String userInfo = "姓名:"+u.getName() +" 性别:"+u.getSex()+" 年龄:"+u.getAge();%>
<%=userInfo %>
</body>
</html>
案例效果:
2.4.4、useBean动作
<jsp:useBean>
用于在指定的域范围内查找指定名称的JavaBean对象。
1)如果在指定的范围已经存在该 bean 实例,那么将使用这个实例,而不会重新创建。
2)如果不存在则实例化一个新的JavaBean对象并将它以指定的名称存储到指定的域范围中。
语法一(常用):
<jsp:useBean id="实例化对象的名称" class="类的全名" scope="保存范围page|request|session|application" ></jsp:useBean>
语法二:
<jsp:useBean id="stu" class="com.Bean.StudentInfo" type="com.Bean.StudentBase(父类)" scope="session" />
使用案例:
<%@ page contentType="text/html;charset=GBK" language="java"%>
<!DOCTYPE html>
<html>
<head>
<title>a.jsp</title>
</head>
<body>
<h1>我是a.jsp</h1>
<jsp:useBean id="user" class="com.cn.domain.User" scope="page"/>
<%
user.setName("mjx");
user.setAge(18);
user.setSex("男");
%>
<% String userInfo = "姓名:"+user.getName() +" 性别:"+user.getSex()+" 年龄:"+user.getAge();%>
<%=userInfo %>
</body>
</html>
案例编译部分源码:
com.cn.domain.User user = null;
user = (com.cn.domain.User) _jspx_page_context.getAttribute("user", javax.servlet.jsp.PageContext.PAGE_SCOPE);
if (user == null){
//这里就是为什么需要一个无参构造了
user = new com.cn.domain.User();
_jspx_page_context.setAttribute("user", user, javax.servlet.jsp.PageContext.PAGE_SCOPE);
}
user.setName("mjx");
user.setAge(18);
user.setSex("男");
String userInfo = "姓名:"+user.getName() +" 性别:"+user.getSex()+" 年龄:"+user.getAge();
2.4.5、setProperty动作
<jsp:setProperty>
动作标记通常与<jsp:useBean>
动作标记一起使用,它以请求中的参数给创建的JavaBean中对应的属性赋值,通过调用 bean 中的 setXxx() 方法来完成。
使用案例1:
以前我们可能会这样写:
1)修改b.jsp为
<%@ page contentType="text/html;charset=GBK" language="java"%>
<!DOCTYPE html>
<html>
<head>
<title>b.jsp</title>
</head>
<body>
<form action="a.jsp" method="post">
用户名:<input type="text" name="name"><br>
性别:<input type="text" name="sex"><br>
年龄:<input type="text" name="age"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
2)修改a.jsp
<%@ page contentType="text/html;charset=GBK" language="java"%>
<!DOCTYPE html>
<html>
<head>
<title>a.jsp</title>
</head>
<body>
<h1>我是a.jsp</h1>
<jsp:useBean id="user" class="com.cn.domain.User" scope="page"/>
<%
String name = request.getParameter("name");
String sex = request.getParameter("sex");
int age = Integer.parseInt(request.getParameter("age"));
user.setName(name);
user.setSex(sex);
user.setAge(age);
%>
<% String userInfo = "姓名:"+user.getName() +" 性别:"+user.getSex()+" 年龄:"+user.getAge();%>
<%=userInfo %>
</body>
</html>
使用案例2:
<%@ page contentType="text/html;charset=GBK" language="java"%>
<!DOCTYPE html>
<html>
<head>
<title>a.jsp</title>
</head>
<body>
<h1>我是a.jsp</h1>
<%
request.setCharacterEncoding("GBK");
%>
<jsp:useBean id="user" class="com.cn.domain.User" scope="page"/>
<!--name:对象名称
property:属性名称,如果指定为*号则自动匹配
value:指定值
-->
<jsp:setProperty name:"user" property="name" value="自定义名字"/>
<jsp:setProperty name="user" property="age"/>
<jsp:setProperty name="user" property="sex" />
<%
String userInfo = "姓名:"+user.getName() +" 性别:"+user.getSex()+" 年龄:"+user.getAge();
%>
<%=userInfo %>
</body>
</html>
案例使用原理:
org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper(_jspx_page_context.findAttribute("user"), "name", "自定义名字", null, null, false);
out.write("\r\n");
out.write(" ");
org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper(_jspx_page_context.findAttribute("user"), "age", request.getParameter("age"), request, "age", false);
out.write("\r\n");
out.write(" ");
org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper(_jspx_page_context.findAttribute("user"), "sex", request.getParameter("sex"), request, "sex", false);
需要保持表单中的属性名和定义的javaBean属性名一致的原因就是,编译后是使用request.getParameter("sex")的值。并且,类型都会帮我们自动转换。
2.4.6、getProperty动作
<jsp:getProperty>
标记用来获得 bean中的属性,并将其转换为字符串,再在 JSP 页面中输出,该 bean 中必须具有 getXxx() 方法。
在上面的案例中,我们虽然设置好了对象的值,但是还是手动获取的。有了这个动作之后,我们就可以使用这个动作获取了。
使用案例:
<%@ page contentType="text/html;charset=GBK" language="java"%>
<!DOCTYPE html>
<html>
<head>
<title>a.jsp</title>
</head>
<body>
<h1>我是a.jsp</h1>
<%
request.setCharacterEncoding("GBK");
%>
<jsp:useBean id="user" class="com.cn.domain.User" scope="page"/>
<%--自动匹配并设置值--%>
<jsp:setProperty name="user" property="*"/>
<%--自动匹配并设置值--%>
姓名:<jsp:getProperty name="user" property="name"/> 性别:<jsp:getProperty name="user" property="sex"/> 年龄:<jsp:getProperty name="user" property="age"/>
</body>
</html>
案例效果:
3、JSP的内置对象
前面我们发现,不管是request也好、out也好,我们都能在jsp页面中直接使用。在前面我们也提到过JPS内置了9大对象:
对象名 | 类型 | 作用域 |
---|---|---|
request | 请求对象javax.servlet.ServletRequest的子类(如:HttpServletRequest) | 一次请求 |
session | 会话对象 javax.servlet.http.HttpSession | Session |
application | 应用程序对象 javax.servlet.ServletContext | application |
response | 响应对象 javax.servlet.ServletResponse的子类(如:HttpServletResponse) | Page |
pageContext | 页面上下文对象 javax.servlet.jsp.PageContext | Page |
out | 输出对象 javax.servlet.jsp.JspWriter | Page |
config | 配置对象 javax.servlet.ServletConfig | Page |
page | 页面对象java.lang.Object this | page |
exception | 异常对象 java.lang.Throwable | Page |
3.1、request对象
request对象是javax.servlet.HttpServletRequest类型的对象。该对象代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据。(包括头信息、系统信息、请求方式以及请求参数等)。request对象的作用域为一次请求。
在介绍servlet一文中,已经介绍过HttpServletRequest,用法差不多,这里就不再详细介绍了。
3.2、response对象
response对象是HttpServletResponse类型的对象,代表的是服务器对客户端的响应,主要是将JSP容器处理过的对象传回到客户端。response对象也具有作用域,它只在JSP页面内有效。
在介绍servlet一文中,已经介绍过HttpServletResponse,用法差不多,这里就不再详细介绍了。
3.3、application对象
application 对象是ServletContext类型的对象,用于保存应用程序的公用数据,服务器启动并自动创建 application 对象后,只要没有关闭服务器,application 对象就一直存在,所有用户共享 application 对象。
在介绍servlet一文中,已经介绍过ServletContext,用法差不多,这里就不再详细介绍了。
3.4、session对象
session对象是HttpSession类型的对象,作用域一次会话的所有页面之间,只要保持同一会话,把一个键值对设置到session中,无论跳转到哪个页面都可以取到session中的键值对。
在介绍servlet会话技术一文中,已经介绍过HttpSession,用法差不多,这里就不再详细介绍了。
3.5、config对象
config 对象是 javax.servlet.Servlet类的实例,表示 Servlet 的配置信息。
在介绍servlet一文中,已经介绍过ServletConfig,用法差不多,这里就不再详细介绍了。
3.6、out对象
out 对象是一个输出流,用来向客户端输出数据,可以是各种数据类型的内容,同时,它还可以管理应用服务器上的输出缓冲区,缓冲区的默认值是 8KB,可以通过页面指令 page 来改变默认大小。
out 对象是一个继承自抽象类 javax.servlet.jsp.JspWriter 的实例,在实际应用中,out 对象会通过 JSP 容器变换为 java.io.PrintWriter 类的对象。(可以简单理解:JspWriter就是带缓存的PrintWrieter)
常用API:
方法 | 说明 |
---|---|
void print(各种数据类型) | 将指定类型的数据输出到 HTTP 流,不换行 |
void println(各种数据类型) | 将指定类型的数据输出到 HTTP 流,并输出一个换行符 |
int getBufferSize() | 得到缓存大小 |
int getRemaining() | 得到未使用缓存的大小 |
void flush() | 刷新缓冲区 |
3.6.1、jsp 中 out 和 response.getwriter()的区别
使用案例:
<%@ page contentType="text/html;charset=GBK" language="java"%>
<!DOCTYPE html>
<html>
<head>
<title>c.jsp</title>
</head>
<body>
<h1>我是c.jsp</h1>
<%
// out 输出
out.write("这是 out 的第一次输出<br/>");
// out flush 之后。 会把输出的内容写入 writer 的缓冲区中
out.flush();
// 最后一次的输出, 由于没有手动 flush, 会在整个页面输出到客户端的时候, 自动写入到 writer缓冲区
out.write("这是 out 的第二次输出<br/>");
// writer 的输出
response.getWriter().write("这是 writer 的第一次输出<br/>");
response.getWriter().write("这是 writer 的第二次输出<br/>");
%>
</body>
</html>
案例效果:
只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter方法,并通过该方法返回的PrintWriter对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:
1)设置page指令的buffer属性关闭了out对象的缓存功能(或主动调用flush()方法刷新缓冲区)
2)out对象的缓冲区已满
3)整个JSP页面结束
3.7、page对象
page 对象是为了执行当前页面应答请求而设置的 Servlet类的实体,即显示 JSP页面自身,与类的 this 指针类似,使用它来调用 Servlet 类中所定义的方法,只有在本页面内才是合法的。它是 java.lang.Object 类的实例。
常用API:
方法 | 说明 |
---|---|
class getClass() | 返回当前 Object 的类 |
int hashCode | 返回 Object 的 hash 代码 |
String toString | 把 Object 对象转换成 String 类的对象 |
boolean equals(Object obj) | 比较对象和指定的对象是否相等 |
void copy (Object obj) | 把对象拷贝到指定的对象中 |
Object clone() | 复制对象(克隆对象) |
3.8、exception对象
java.lang.Throwable 的实例,该实例代表其他页面中的异常和错误。只有当页面是错误处理页面,即编译指令page 的isErrorPage 属性为true 时,该对象才可以使用。常用的方法有getMessage()和printStackTrace()等。
使用案例:
1)新建一个d.jsp
<%@ page contentType="text/html;charset=GBK" language="java" errorPage="error.jsp" %>
<html>
<head>
<title></title>
</head>
<body>
<%--模拟空指针异常的错误--%>
<%
String isnull = null;
isnull.length();
%>
</body>
</html>
2)新建一个error.jsp
<%@ page language="java" contentType="text/html; charset=GBK"
pageEncoding="GBK" isErrorPage="true"%>
<!--注意:isErrorPage="true"时才能使用exception-->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; GBK">
<title>Insert title here</title>
</head>
<body>
<%out.println("程序抛出了异常:" + exception); %>
</body>
</html>
3)案例效果
3.9、pageContext对象
pageContext对象是JSP技术中最重要的一个对象,它代表JSP页面的运行环境,这个对象不仅封装了对其它8大隐式对象的引用,它自身还是一个域对象,可以用来保存数据。并且,这个对象还封装了web开发中经常涉及到的一些常用操作,例如引入和跳转其它资源、检索其它域对象中的属性等。
官方文档上描述:
PageContext 为页面/组件作者和页面实现者提供了许多工具,其中包括:
管理各种范围名称空间的单个 API
许多便捷 API,用于访问各种公共对象
获取 JspWriter 以供输出的机制
通过页面管理会话使用的机制
向脚本环境公开页面指令属性的机制
将当前请求转发或包含到应用程序中其他活动组件的机制
处理 errorpage 异常处理的机制
pageContext对象常用API:
方法 | 说明 |
---|---|
String findAttribute(String name) | 查找各个域的属性(page—>request->session->application) |
void forward(String relativeUrlPath) | 把页面转发到另一个页面或者 Servlet组件上 |
Exception getException() | 返回当前页的 Exception 对象 |
ServletRequest getRequest() | 返回当前页的 request 对象 |
ServletResponse getResponse() | 返回当前页的 response 对象 |
ServletConfig getServletConfig() | 返回当前页的 ServletConfig 对象 |
HttpSession getSession() | 返回当前页的 session 对象 |
Object getPage() | 返回当前页的 page 对象 |
ServletContext getServletContext() | 返回当前页的 application 对象 |
public Object getAttribute(String name) | 获取属性值 |
Object getAttribute(String name,int scope) | 在指定的范围内获取属性值 |
void setAttribute(String name,Object attribute) | 设置属性及属性值 |
void setAttribute(String name,Object obj,int scope) | 在指定范围内设置属性及属性值 |
void removeAttribute(String name) | 删除某属性 |
void removeAttribute(String name,int scope) | 在指定范围内删除某属性 |
void invalidate() | 返回 servletContext 对象,全部销毁 |
使用案例:
1)新建e.jsp
<%@ page contentType="text/html;charset=GBK" language="java"%>
<!DOCTYPE html>
<html>
<head>
<title>e.jsp</title>
</head>
<body>
<h1>我是e.jsp</h1>
<%
request.setAttribute("info","value of request scope");
session.setAttribute("info","value of request scope");
application.setAttribute("info","value of application scope");
%>
pageContext 查找各个范围内的值:查找顺序page—>request->session->application <br>
输出:
<%=pageContext.findAttribute("info") %>
<hr>
pageContext 取出以下范围内的值(方法一):<br>
request 设定的值:<%=pageContext.getRequest().getAttribute("info") %> <br>
session 设定的值:<%=pageContext.getSession().getAttribute("info") %> <br>
application 设的值:<%=pageContext.getServletContext().getAttribute("info") %> <hr>
pageContext取出以下范围内各值(方法二):<br>
范围1(page)内的值:<%=pageContext.getAttribute("info",1) %> <br>
范围2(request)内的值:<%=pageContext.getAttribute("info",2) %> <br>
范围3(session)内的值:<%=pageContext.getAttribute("info",3) %> <br>
范围4(application)内的值:<%=pageContext.getAttribute("info",4) %> <hr>
pageContext 修改或删除某个范围内的值:
1)修改 request 设定的值:<br>
<% pageContext.setAttribute("info","value of request scope is modified by pageContext",2); %> <br>
修改后的值:<%=pageContext.getRequest().getAttribute("info") %> <br>
2)删除 session 设定的值:<% pageContext.removeAttribute("info"); %>
删除后的值:<%=session.getAttribute("info") %>
</body>
</html>
2)案例效果
4、JSP的四大域对象
域对象可以像Map一样存取数据对象。四个域对象的功能一样,不同的是它们对数据的存取范围。在使用上它们是有优先顺序的。
四大域对象分别是:
域对象 | 描述 | 所属域 |
---|---|---|
pageContext | 只在当前JSP页面范围内有效,跳转页面无效 | page域 |
requet | 只在一次请求中保存属性,服务器跳转有效,浏览器跳转无效 | request域 |
session | 在一个会话范围中保存属性,无论何种跳转均有效,关闭浏览器后无效 | session域 |
application | 在整个服务器中保存,所有用户都可以使用 | context域 |
优先顺序(范围从小到大):
使用案例:
1)新建scope.jsp
<%@ page contentType="text/html;charset=GBK" language="java"%>
<!DOCTYPE html>
<html>
<head>
<title>c.jsp</title>
</head>
<body>
<h1>scope.jsp</h1>
<%
// 往四个域中都分别保存了数据
pageContext.setAttribute("key", "pageContext");
request.setAttribute("key", "request");
session.setAttribute("key", "session");
application.setAttribute("key", "application");
%>
pageContext 域是否有值: <%=pageContext.getAttribute("key")%> <br>
request 域是否有值: <%=request.getAttribute("key")%> <br>
session 域是否有值: <%=session.getAttribute("key")%> <br>
application 域是否有值: <%=application.getAttribute("key")%> <br>
<%
session.setAttribute("findKey", "session");
application.setAttribute("findKey", "application");
%><br>
使用key去查找值:按作用域从小到大查<br>
key:<%=pageContext.findAttribute("key")%><br>
findKey:<%=pageContext.findAttribute("findKey")%>
</body>
</html>
2)案例效果