所谓的属性范围就是一个属性设置之后,可以经过多少个其他页面后仍然可以访问的保存范围。

JSP属性范围

JSP中提供了四种属性范围,四种属性范围分别指以下四种。

Java对象属性 for Java对象属性设置范围_html

属性的操作方法

既然JSP中提供了四种属性范围,则四种属性范围中都将包含以下的属性操作方法。

Java对象属性 for Java对象属性设置范围_java_02


属性的操作无外乎就是增加、取得和删除这几个操作。单词Attribute的意思是“属性”,setAttribute(String name, Object value)从单词的组合来看就可以知道的是这个方法是设置属性,设置属性的名字和属性的值,名字(name)为String类型,值(value)为Object类型,由于值为Object类型,这表示可以设置任意类型的数据作为值,因为所有的类都是从Object类型继承而来。因此设置属性值的时候可以是任意类型的数据。getAttribute(String name)方法是根据属性的名字取得属性值,removeAttribute(String name)方法是根据属性的名字删除属性。

JSP四种属性范围的具体介绍

page属性范围(pageContext)

page属性范围相对好理解一些:在一个页面设置的属性,跳转到其他页面就无法访问了。但是在使用page属性范围的时候必须注意的是,虽然习惯上将页面范围的属性称为page范围,但是实际上操作的时候是使用pageContext内置对象完成的。pageContext属性范围的操作流程图如下:

Java对象属性 for Java对象属性设置范围_Java对象属性 for_03


pageContext从字面上的定义,可以发现,是表示一个页面(page)的上下文(Context),可以表示一个页面中的所有内容。从操作流程图来看,在第一个页面设置的属性经过服务器端跳转到第二个页面以后,在第二个页面是无法取得在第一个页面中设置的属性的,就好比现在坐着的桌子上有一支笔,但一旦离开了这张桌子,坐到别的桌子上时,笔就没有了。下面通过代码来观察此范围的属性。

例,在pageContextDemo.jsp页面中设置两个属性。

<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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; charset=UTF-8">
<title>page属性范围</title>
</head>
<body>
	<%
        // 此时设置的属性只能够在本页中取得
        pageContext.setAttribute("name", "陈浩南");
        pageContext.setAttribute("date", new Date());
    %>

    <%
        // 取得设置的属性
        String refName = (String)pageContext.getAttribute("name");
        Date refDate = (Date)pageContext.getAttribute("date");
    %>
    <h1>姓名:<%=refName %></h1>
    <h1>日期:<%=refDate.toLocaleString() %></h1>
</body>
</html>

在Chrome浏览器上运行的效果如下:

Java对象属性 for Java对象属性设置范围_jsp页面_04


这说明了在本页设置的pageContext范围属性在本页确实可以取得,下面使用跳转语句,观察跳转之后是否还可以取得属性。

例,有如下两个JSP页面。

  • pageContextDemo1.jsp页面的内容如下:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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; charset=UTF-8">
<title>page属性范围</title>
</head>
<body>
	<%
        // 此时设置的属性只能够在本页中取得
        pageContext.setAttribute("name", "陈浩南");
        pageContext.setAttribute("date", new Date());
    %>

    <%-- 使用jsp:forward标签进行服务器端跳转 --%>
    <jsp:forward page="/pageContextDemo2.jsp"></jsp:forward>
</body>
</html>
  • pageContextDemo2.jsp页面的内容如下:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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; charset=UTF-8">
<title>page属性范围</title>
</head>
<body>
	<%
        // 取得设置的属性
        String refName = (String)pageContext.getAttribute("name");
        Date refDate = (Date)pageContext.getAttribute("date");
    %>
    <h1>姓名:<%=refName %></h1>
    <h1>日期:<%=refDate %></h1>
</body>
</html>

在以上案例中的pageContextDemo1.jsp只是设置了两个属性,跳转到pageContextDemo2.jsp之后再在pageContextDemo2.jsp中取出在pageContextDemo1.jsp设置的page属性。此时,运行结果如下:

Java对象属性 for Java对象属性设置范围_java_05


使用了服务器端跳转,但是发现内容并不能取得,证明page范围的属性只能在本页中取得,跳转到其他页面之中不能取得。如果现在希望跳转到其他页面之中,依然可以取得,则可以扩大属性范围,使用request属性范围即可。

关于pageContext属性范围的进一步补充

这四种属性范围,实际上都是通过pageContext属性范围设置的。打开pageContext所在的API说明文档。

Java对象属性 for Java对象属性设置范围_html_06


PageContext类继承了JspContext类,在JspContext类中定义了setAttribute方法,如下:

public abstract void setAttribute(java.lang.String name, java.lang.Object value, int scope)

此方法中存在一个scope的整型变量,此变量就表示一个属性的保存范围。

Java对象属性 for Java对象属性设置范围_Java对象属性 for_07


由于PageContext类继承了JspContext类,所以在PageContext类中实现了抽象的setAttribute方法。这个setAttribute()方法如果不写后面的int类型的scope参数,则此参数默认为PAGE_SCOPE,则此时setAttribute()方法设置的就是page属性范围,如果传递过来的int类型参数scope为REQUEST_SCOPE,则此时setAttribute()方法设置的就是request属性范围,同理,传递的scope参数为SESSION_SCOPE和APPLICATION_SCOPE时,则表示setAttribute()方法设置的就是session属性范围和application属性范围。

下面通过一个案例来观察此四种属性范围常量的作用。这里以request属性范围为例,有如下两个JSP页面。

  • pageContextDemo3.jsp页面的内容如下:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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; charset=UTF-8">
<title>page属性范围</title>
</head>
<body>
	<%
        // 设置属性,并指明属性范围
        pageContext.setAttribute("name", "陈浩南", pageContext.REQUEST_SCOPE);
        pageContext.setAttribute("date", new Date(), pageContext.REQUEST_SCOPE);
    %>

    <%-- 使用jsp:forward标签进行服务器端跳转 --%>
    <jsp:forward page="/pageContextDemo4.jsp"></jsp:forward>
</body>
</html>
  • pageContextDemo4.jsp页面的内容如下:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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; charset=UTF-8">
<title>page属性范围</title>
</head>
<body>
	<%
        // 使用request对象获取属性
        String refName = (String)request.getAttribute("name");
        Date refDate = (Date)request.getAttribute("date");

        // 也可以使用pageContext对象获取属性,只要在获取时指明对象的属性范围即可
        String refName2 = (String)pageContext.getAttribute("name", pageContext.REQUEST_SCOPE);
        Date refDate2 = (Date)pageContext.getAttribute("date", pageContext.REQUEST_SCOPE);
    %>

	使用request对象获取属性:
    <h1>姓名:<%=refName %></h1>
    <h1>日期:<%=refDate.toLocaleString() %></h1>
	使用pageContext对象获取属性:
    <h1>姓名:<%=refName2 %></h1>
    <h1>日期:<%=refDate2.toLocaleString() %></h1>
</body>
</html>

在Chrome浏览器上运行的效果如下:

Java对象属性 for Java对象属性设置范围_Java-Web基础_08


从运行结果可以看到:在pageContextDemo3.jsp使用的是pageContext对象调用setAttribute()方法设置的属性范围是request属性范围,因此在调用此方法时,把一个int类型的scope范围常量REQUEST_SCOPE传递了进来,这个REQUEST_SCOPE属性范围常量的作用就是告诉pageContext对象现在要设置的属性范围是request属性范围,所以pageContextDemo4.jsp这个页面中可以直接使用request.getAttribute()方法获取在pageContextDemo3.jsp设置的属性。

request属性范围

request属性范围表示在一次服务器跳转中有效,只要是服务器跳转,则设置的request属性可以一直传递下去。request属性范围的操作流程图如下:

Java对象属性 for Java对象属性设置范围_java_09


例,有如下两个JSP页面。

  • requestDemo1.jsp页面的内容如下:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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; charset=UTF-8">
<title>request属性范围</title>
</head>
<body>
	<%
        request.setAttribute("name", "陈浩南");
        request.setAttribute("date", new Date());
    %>

    <%-- 使用jsp:forward标签进行服务器端跳转 --%>
    <jsp:forward page="/requestDemo2.jsp"></jsp:forward>
</body>
</html>
  • requestDemo2.jsp页面的内容如下:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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; charset=UTF-8">
<title>request属性范围</title>
</head>
<body>
	<%
        // 取得requestDemo1.jsp设置的属性
        String refName = (String)request.getAttribute("name");
        Date refDate = (Date)request.getAttribute("date");
    %>
    <h1>姓名:<%=refName %></h1>
    <h1>日期:<%=refDate.toLocaleString() %></h1>
</body>
</html>

在Chrome浏览器上运行的效果如下:

Java对象属性 for Java对象属性设置范围_html_10


从运行结果来看,程序跳转了,但是与page范围相比,内容可以向下继续传递,即在第一个页面设置的属性跳转到第二个页面后在第二个页面中依然可以取得第一个页面设置的属性。如果现在有第三个页面了,则也可以继续向后传递。下面我会举例说明这一点。

  • 修改requestDemo2.jsp页面,使其内容如下:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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; charset=UTF-8">
<title>request属性范围</title>
</head>
<body>
	<%-- 使用jsp:forward标签进行服务器端跳转 --%>
    <jsp:forward page="/requestDemo3.jsp"></jsp:forward>
</body>
</html>
  • 再新建一个requestDemo3.jsp页面,内容如下:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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; charset=UTF-8">
<title>request属性范围</title>
</head>
<body>
	<%
        // 取得requestDemo1.jsp设置的属性
        String refName = (String)request.getAttribute("name");
        Date refDate = (Date)request.getAttribute("date");
    %>
    <h1>姓名:<%=refName %></h1>
    <h1>日期:<%=refDate.toLocaleString() %></h1>
</body>
</html>

在Chrome浏览器上访问requestDemo1.jsp页面的效果如下:

Java对象属性 for Java对象属性设置范围_Java-Web基础_11


以上的页面依然可以访问,但是如果,此时使用了超链接的方式传递的话,则属性是无法向下继续传递的。下面我会举例说明这一点。

  • 修改requestDemo3.jsp页面,使其内容如下:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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; charset=UTF-8">
<title>request属性范围</title>
</head>
<body>
	<%
        // 取得requestDemo1.jsp设置的属性
        String refName = (String)request.getAttribute("name");
        Date refDate = (Date)request.getAttribute("date");
    %>
    <h1>姓名:<%=refName %></h1>
    <h1>日期:<%=refDate.toLocaleString() %></h1>

    <h1>
	    <%--使用超链接的形式跳转,这是客户端跳转,URL地址会改变--%>
	    <a href="/day08/requestDemo4.jsp">跳转到requestDemo4.jsp</a>
    </h1>
</body>
</html>

此时使用了超链接跳转,一旦跳转之后,地址栏将发生改变,所以此种跳转也可以称为客户端跳转。

  • 再新建一个requestDemo4.jsp页面,内容如下:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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; charset=UTF-8">
<title>request属性范围</title>
</head>
<body>
	<%
        // 取得requestDemo1.jsp设置的属性
        String refName = (String)request.getAttribute("name");
        Date refDate = (Date)request.getAttribute("date");
    %>
    <h1>姓名:<%=refName %></h1>
    <h1>日期:<%=refDate %></h1>
</body>
</html>

在Chrome浏览器上访问requestDemo1.jsp页面的效果如下:

Java对象属性 for Java对象属性设置范围_html_12


然后点击跳转到requestDemo4.jsp超链接,运行的效果如下:

Java对象属性 for Java对象属性设置范围_java_13


requestDemo4.jsp页面显示的结果是null。这说明了在requestDemo1.jsp这个页面设置的属性经过超链接这种客户端跳转到别的页面时,别的页面是无法取得requestDemo1.jsp中设置的属性的。如果还想进一步扩大属性范围,则可以使用session范围属性。

session属性范围

session设置的属性不管如何跳转,都可以取得的。当然,session只针对一个用户。session属性范围的操作流程图如下:

Java对象属性 for Java对象属性设置范围_java_14


在第一个页面上设置的属性,跳转(服务器跳转/客户端跳转)到其他页面之后,其他的页面依然可以取得第一个页面上设置的属性。下面通过一个案例来观察session属性范围,例如,有如下三个JSP页面。

  • sessionDemo1.jsp页面的内容如下:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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; charset=UTF-8">
<title>session属性范围</title>
</head>
<body>
	<%
        // 此时设置的属性只能够在与本页相关的任何页面中取得
        session.setAttribute("name", "陈浩南");
        session.setAttribute("date", new Date());
    %>

    <%-- 使用jsp:forward标签进行服务器端跳转 --%>
    <jsp:forward page="/sessionDemo2.jsp"></jsp:forward>
</body>
</html>

这里使用的是服务器端跳转。

  • sessionDemo2.jsp页面的内容如下:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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; charset=UTF-8">
<title>session属性范围</title>
</head>
<body>
	<%
        String refName = (String)session.getAttribute("name");
        Date refDate = (Date)session.getAttribute("date");
    %>
    <h1>姓名:<%=refName %></h1>
    <h1>日期:<%=refDate.toLocaleString() %></h1>

    <%--使用超链接这种客户端跳转--%>
    <h1><a href="/day08/sessionDemo3.jsp">跳转到sessionDemo3.jsp</a></h1>
</body>
</html>

这里有使用到超链接这种客户端跳转。

  • sessionDemo3.jsp页面的内容如下:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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; charset=UTF-8">
<title>session属性范围</title>
</head>
<body>
	<%
        String refName = (String)session.getAttribute("name");
        Date refDate = (Date)session.getAttribute("date");
    %>
    <h1>姓名:<%=refName %></h1>
    <h1>日期:<%=refDate.toLocaleString() %></h1>
</body>
</html>

在Chrome浏览器上访问sessionDemo1.jsp页面的效果如下:

Java对象属性 for Java对象属性设置范围_Java-Web基础_15


点击超链接跳转到sessionDemo3.jsp,跳转到了sessionDemo3.jsp这个页面,此时程序的运行结果如下:

Java对象属性 for Java对象属性设置范围_java_16


这说明了即使是采用客户端跳转,在别的页面依然可以取得第一个页面中设置的session属性。但是,如果,此时新开了一个浏览器,则访问sessionDemo3.jsp肯定无法取得sessionDemo1.jsp中设置的session对象的属性,因为session只是保留了一个人的信息。如果一个属性想让所有的用户都可以访问,则可以使用最后一种属性范围:application范围。

application属性范围

application属性范围的操作流程图如下:

Java对象属性 for Java对象属性设置范围_Java对象属性 for_17


因为application属性范围是在服务器上设置的一个属性,所以一旦设置之后任何用户都可以浏览到此属性。下面通过一个案例来观察application属性范围,例如,有如下两个JSP页面。

  • applicationDemo1.jsp页面的内容如下:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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; charset=UTF-8">
<title>application属性范围</title>
</head>
<body>
	<%
        // 此时设置的属性任何用户都可以取得
        application.setAttribute("name", "陈浩南");
        application.setAttribute("date", new Date());
    %>

    <%--使用超链接这种客户端跳转--%>
    <h1><a href="/day08/applicationDemo2.jsp">跳转到applicationDemo2.jsp</a></h1>
</body>
</html>
  • applicationDemo2.jsp页面的内容如下:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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; charset=UTF-8">
<title>application属性范围</title>
</head>
<body>
	<%
        String refName = (String)application.getAttribute("name");
        Date refDate = (Date)application.getAttribute("date");
    %>
    <h1>姓名:<%=refName %></h1>
    <h1>日期:<%=refDate.toLocaleString() %></h1>
</body>
</html>

在Chrome浏览器上访问applicationDemo1.jsp页面的效果如下:

Java对象属性 for Java对象属性设置范围_java_18


点击超链接跳转到applicationDemo2.jsp,跳转到了applicationDemo2.jsp这个页面,此时程序的运行结果如下:

Java对象属性 for Java对象属性设置范围_Java对象属性 for_19


开启多个浏览器窗口,访问applicationDemo2.jsp页面时,都可以显示出上图所示的结果,因为属性范围设置在了服务器中,所以只要是连接到此服务器的任意用户都可以取得此属性,当然,如果服务器关闭的话,则此属性肯定消失。如把Tomcat服务器先关闭后再重新启动,打开浏览器窗口访问applicationDemo2.jsp,此时应将applicationDemo2.jsp修改为:

<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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; charset=UTF-8">
<title>application属性范围</title>
</head>
<body>
	<%
        String refName = (String)application.getAttribute("name");
        Date refDate = (Date)application.getAttribute("date");
    %>
    <h1>姓名:<%=refName %></h1>
    <h1>日期:<%=refDate %></h1>
</body>
</html>

不然会报空指针异常。得到的结果如下图所示:

Java对象属性 for Java对象属性设置范围_java_20


温馨提示:如果在服务器上设置了过多的application属性,则会影响到服务器的性能。

JSP四种属性范围的使用场合

Java对象属性 for Java对象属性设置范围_Java-Web基础_21