JSP 脚本中的 9 个内置对象
JSP 脚本中包含了 9 个内置对象,这 9 个内置对象都是 Servlet API 接口的实例,只是 JSP 规范对它们进行了默认初始化。
这 9 个内置对象如下:
1、application:javax.servlet.ServletContext 的实例,该实例代表 JSP 所属的 Web 应用本身,可用于 JSP 页面,或者在 Servlet 之间交换信息。常用的方法有 getAttribute(String attrName)、setAttribute(String attrName, String attrValue) 和 getInitParameter(String paramName) 等。
2、config:javax.servlet.ServletConfig 的实例,该实例代表该 JSP 的配置信息。常用的方法有 getInitParameter(String paramName) 和 getInitParameternames() 方法。
3、exception:java.lang.Throwable 的实例,该实例代表其他页面中的异常和错误。只有当页面是错误页面,即编译指令 page 的 isErrorPage
属性为 true 时,该对象才可以使用。常用的方法有 getMessage() 和 printStackTrace()。
4、out:javax.servlet.jsp.JspWriter 的实例,该实例代表 JSP 页面的输出流,用于输出内容,形成 HTML 页面。
5、page:代表该页面本身,通常没有太大用处。也就是 Servlet 中的 this,其类型就是生成的 Servlet 类,能用 page 的地方就可用 this。
6、pageContext:javax.servlet.jsp.PageContext 的实例,该对象代表该 JSP 页面上下文,使用该对象可以访问页面中的共享数据。常用的方法有 getServletContext() 和 getServletConfig() 。
7、request:javax.servlet.jsp.HttpServletRequest 的实例,该对象封装了一次请求,客户端的请求参数都被封装在该对象里。这是一个常用的对象,获取客户端请求参数必须使用该对象。常用的方法有 getParameter(String paramName)、getParameterValues(String paramName)、setAttribute(String attrName, Object attrValue)、getAttribute(String attrName) 和 setCharacterEncoding(String encoding)
8、response:javax.servlet.jsp.HttpServletResponse 的实例,代表服务器对客户端的响应。通常很少直接使用该对象,而是使用 out 对象,常用的方法有 getOutputStream()、setRedirect(String location)
9、session:javax.servlet.http.HttpSession 的实例,该对象代表一次会话。常用的方法有 getAttribute(String attrName)、setAttribute(String attrName, Object attrValue)
打开 jsp 生成的 servlet 文件,我们可以看到内置对象的声明及初始化:
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=UTF-8"); 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; }
上面的声明及定义位于 jspService 方法内
application 对象
通常有如下两个作用:
1、让多个 JSP 、Servlet 共享数据
application 通过 setAttribute(String attrName, Object value) 方法讲一个值设置成 application 的 attrName 属性,该属性的值对整个 Web 应用有效,因此该 web 应用的每个 JSP 页面或 Servlet 都可以访问该属性,访问属性的方法为 getAttribute(String attrName)。
application 不仅可以用于两个 JSP 页面之间共享数据,还可以用于 Servlet 和 JSP 之间共享数据。可以把 application 理解成一个 Map 对象,任何 JSP、Servlet 都可以把某个变量放入 application 中保存,并为之指定一个变量名;而该应用里的其他 Servlet、JSP 就可以根据该属性名来得到这个变量。
2、获得 web 应用配置参数
application 还有一个重要用处,可用于获得 web 应用的配置参数。如下:参数都在 web.xml 中配置了。
如下,在 web.xml 里面设置参数配置(context-param 标签):
<?xml version="1.0" encoding="UTF-8"?> <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_4_0.xsd" version="4.0" metadata-complete="true"> <servlet> <servlet-name>get-application</servlet-name> <servlet-class>com.baiguiren.GetApplication</servlet-class> </servlet> <servlet-mapping> <servlet-name>get-application</servlet-name> <url-pattern>/get-application</url-pattern> </servlet-mapping> <!-- 配置第一个参数:driver --> <context-param> <param-name>driver</param-name> <param-value>com.mysql.jdbc.Driver</param-value> </context-param> <!-- 配置第二个参数:url --> <context-param> <param-name>url</param-name> <param-value>jdbc:mysql://localhost:3306/jsp</param-value> </context-param> <!-- 配置第三个参数:user --> <context-param> <param-name>user</param-name> <param-value>root</param-value> </context-param> <!-- 配置第四个参数:pass --> <context-param> <param-name>pass</param-name> <param-value>root</param-value> </context-param> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
在 JSP 中获取参数:
<%@ page contentType="text/html; charset=UTF-8" %> <%@ page import="java.sql.*" %> <html> <head> <title>通过application获取web.xml中的参数</title> </head> <body> <% // 从配置中获取参数 String driver = application.getInitParameter("driver"); // 从配置参数中获取数据库 url String url = application.getInitParameter("url"); // 从配置参数中获取用户名 String user = application.getInitParameter("user"); // 从配置参数中获取密码 String pass = application.getInitParameter("pass"); // 注册驱动 Class.forName(driver); // 获取数据库连接 Connection connection = DriverManager.getConnection(url, user, pass); // 创建 Statement 对象 Statement stmt = connection.createStatement(); // 执行查询 ResultSet rs = stmt.executeQuery("select * from person"); %> // 输出 <table bgcolor="#9999dd" border="1" width="480"> <% // 遍历结果集 while(rs.next()) { %> <tr> <td><%=rs.getString(1)%></td> <td><%=rs.getString(2)%></td> <td><%=rs.getString(3)%></td> </tr> <% } %> </table> </body> </html>
config 对象:
config对象代表当前 JSP 配置信息,但 JSP 通常无需配置,因此也就不存在配置信息。所以 JSP 页面比较少用该对象。
但在 Servlet 中则用处较大,因为 Servlet 需要在 web.xml 文件中进行配置,可以指定配置参数。
如:
web.xml 里面配置:
<servlet> <!-- 指定Servlet名字 --> <servlet-name>config</servlet-name> <!-- 指定将哪个 JSP 页面配置成Servlet --> <jsp-file>/config.jsp</jsp-file> <!-- 配置名为 name 的参数,值为 ruby --> <init-param> <param-name>name</param-name> <param-value>ruby</param-value> </init-param> <!-- 配置名为 age 的参数,值为 24 --> <init-param> <param-name>age</param-name> <param-value>24</param-value> </init-param> </servlet> <servlet-mapping> <!-- 指定将 config Servlet 配置到 /config 路径 --> <servlet-name>config</servlet-name> <url-pattern>/config</url-pattern> </servlet-mapping>
jsp 文件:
<%@ page contentType="text/html; charset=UTF-8" %> <html> <head> <title>config内置对象</title> </head> <body> <!-- 输出该 JSP 名为 name 的配置参数 --> name 配置参数的值为:<%=config.getInitParameter("name")%> <!-- 输出该 JSP 名为 age 的配置参数 --> age 配置参数的值为:<%=config.getInitParameter("age")%> </body> </html>
exception 对象
exception 对象是 Throwable 的实例,代表 JSP 脚本中产生的错误和异常,是 JSP 页面异常机制的一部分。
JSP 中的异常都可交给错误处理页面处理。
如:
首先需要在其他出现异常的页面的 page 指令中指定 errorPage 是下面的页面:
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="error.jsp" %>
又或者在 web.xml 中配置如下内容:
error-page> <exception-type>java.lang.Throwable</exception-type> <location>/error.jsp</location> </error-page>
error.jsp
<%@ page contentType="text/html; charset=UTF-8" isErrorPage="true" %> <html> <head> <title>error</title> <link href="assets/prism/prism.css" rel="stylesheet" /> </head> <body> 异常类型:<pre><code class="language-java"></code><%=exception.getClass()%></code></pre><br/> 异常信息:<pre><code class="language-java"><%=exception.getMessage()%></code></pre><br/> 错误堆栈:<pre><code class="language-java"></code><%=exception.getStackTrace()%></code></pre><br/> <script src="assets/prism/prism.js"></script> </body> </html>
out 对象:
out 对象代表一个页面输出流,通常用于在页面上输出变量值及常量。一般在使用输出表达式的地方,都可以用 out 对象来达到同样效果。
如:
<%@ page contentType="text/html; charset=UTF-8" %> <%@ page import="java.sql.*" %> <html> <head> <title>out 测试</title> </head> <body> <% // 注册数据库驱动 Class.forName("com.mysql.jdbc.Driver"); // 获取数据库连接 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jsp", "root", "root"); // 创建 Statement 对象 Statement stmt = conn.createStatement(); // 执行查询,获得 ResultSet 对象 ResultSet rs = stmt.executeQuery("select * from person"); %> <table border="1" width="400"> <% // 遍历结果集 while(rs.next()) { // 输出表格行 out.println("<tr>"); // 输出表格列 out.println("<td>"); // 输出结果集第一列的值 out.println(rs.getString(1)); // 关闭表格列 out.println("</td>"); // 开始表格列 out.println("<td>"); // 输出结果集第二列的值 out.println(rs.getString(2)); // 关闭表格列 out.println("</td>"); // 关闭表格行 out.println("</tr>"); } %> </table> </body> </html>
所有使用 out 的地方,都可使用输出表达式来代替,而且使用输出表达式更加简洁。
我们把上面的写法换成输出表达式:
<%@ page contentType="text/html; charset=UTF-8" %> <%@ page import="java.sql.*" %> <html> <head> <title>out 测试</title> </head> <body> <% // 注册数据库驱动 Class.forName("com.mysql.jdbc.Driver"); // 获取数据库连接 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jsp", "root", "root"); // 创建 Statement 对象 Statement stmt = conn.createStatement(); // 执行查询,获得 ResultSet 对象 ResultSet rs = stmt.executeQuery("select * from person"); %> <table border="1" width="400"> <% // 遍历结果集 while(rs.next()) { %> <tr> <td><%=rs.getString(1)%></td> <td><%=rs.getString(2)%></td> </tr> <% } %> </table> </body> </html>
我们可以明显看到,输出结果集的代码量更少了,并且结构也更加的清晰。
pageContext 对象
这个对象代表页面上下文,该对象主要用于访问 JSP 之间的共享数据。使用 pageContext 可以访问 page、request、session、application 范围的变量。
pageContext 是 PageContext 类的实例,它提供了如下两个方法来访问 page、request、session、application 范围的变量。
1、getAttribute(String name):取得 page 范围内的 name 属性。
2、getAttribute(String name, int scope):取得指定范围内的 name 属性,其中 scope 可以是如下 4 个值。
PageContext.PAGE_SCOPE:对应于 page 范围
PageContext.REQUEST_SCOPE:对应于 request 范围
PageContext.SESSION_SCOPE:对应于 session 范围
PageContext.APPLICATION_SCOPE:对应于 application 范围
与 getAttribute() 方法对应,PageContext 也提供了两个对应的 setAttribute() 方法,用于将指定变量放入 page、request、session、application 范围内。
<%@ page contentType="text/html; charset=UTF-8" %> <html> <head> <title>pageContext</title> </head> <body> <% // 使用 pageContext 设置属性,该属性默认在 page 范围内 pageContext.setAttribute("page", "hello"); // 使用 request 设置属性,该属性默认在 request 范围内 request.setAttribute("request", "hello"); // 使用 pageContext 将属性设置在 request 范围内 pageContext.setAttribute("request2", "hello", pageContext.REQUEST_SCOPE); // 使用 session 将属性设置在 session 范围内 session.setAttribute("session", "hello"); // 使用 pageContext 将属性设置在 session 范围内 pageContext.setAttribute("session2", "hello", pageContext.SESSION_SCOPE); // 使用 application 将属性设置在 application 范围内 application.setAttribute("application", "hello"); // 使用 pageContext 将属性设置在 application 范围内 pageContext.setAttribute("application2", "hello", pageContext.APPLICATION_SCOPE); %> <h3>获取各属性的值</h3> <p>page 范围的 page 属性值:<%=pageContext.getAttribute("page")%></p> <p>request 范围的 request 属性值:<%=request.getAttribute("request")%></p> <p>request 范围的 request2 属性值:<%=request.getAttribute("request2")%></p> <p>session 范围的 session 属性值:<%=session.getAttribute("session")%></p> <p>session 范围的 session2 属性值:<%=session.getAttribute("session2")%></p> <p>application 范围的 application 属性值:<%=application.getAttribute("application")%></p> <p>application 范围的 application2 属性值:<%=application.getAttribute("application2")%></p> </body> </html>
request 对象:
request 对象是 JSP 中重要的对象,每个 request 对象封装着一次用户请求,并且所有的请求参数都被封装在 request 对象中,因此 request 对象是获取请求参数的重要途径。
1、获取请求头/请求参数
String getParameter(String paramName):获取 paramName 请求参数的值。
Map getParameterMap(): 获取所有请求参数名和参数值组成的 Map 对象。
Enumeration getParameterNames():获取所有请求参数名所组成的 Enumeration 对象。
String[] getParameterValues(String name):name 请求参数的值,当该请求参数有多个值时,该方法将返回多个值所组成的数组。
HttpServletRequest 提供了如下方法来访问请求头:
String getHeader(String name):获取指定请求头的值。
java.util.Enumeration<String> getHeaderNames():获取所欲请求头的名称。
java.util.Enumeration<String> getHeaders(String name):获取指定请求头的多个值。
int getIntHeader(String name):获取指定请求头的值,并将该值转为整数值。
并不是每个表单域都会生成请求参数,而是有 name 属性的表单域才生成请求参数。关于表单域和请求参数的关系遵循如下四点:
a、每个有 name 属性的表单域对应一个请求参数。
b、如果多个表单域有相同的 name 属性,则多个表单域只生成一个请求参数,只是该参数有多个值。
c、表单域的 name 属性指定请求参数名,value 指定请求参数值。
d、如果某个表单域设置了 disabled="disabled" 属性,则该表单域不再生成请求参数。
request示例:
form.jsp
<%@ page contentType="text/html; charset=UTF-8" %> <html> <head> <title>form</title> </head> <body> <form method="POST" action="request1.jsp"> 用户名:<br /><input type="text" name="name"><hr/> 性别:<br /> 男:<input type="radio" name="gender" value="男"> 女:<input type="radio" name="gender" value="女"><hr/> 喜欢的颜色:<br /> 红:<input type="checkbox" name="color" value="红"> 蓝:<input type="checkbox" name="color" value="蓝"> 绿:<input type="checkbox" name="color" value="绿"><hr/> 来自的国家:<br /> <select name="country"> <option value="中国">中国</option> <option value="美国">美国</option> <option value="俄罗斯">俄罗斯</option> </select><hr/> <input type="submit" value="提交"> <input type="reset" value="重置"> </form> </body> </html>
request1.jsp
<%@ page contentType="text/html; charset=UTF-8" %> <%@ page import="java.util.*" %> <html> <head> <title>获取请求头/请求参数</title> </head> <body> <% // 获取所有请求头的名称 Enumeration<String> headerNames = request.getHeaderNames(); while(headerNames.hasMoreElements()) { String headerName = headerNames.nextElement(); // 获取每个请求、及其对应的值 out.println(headerName + "-->" + request.getHeader(headerName) + "<br />"); } out.println("<hr/>"); // 设置解码方式 request.setCharacterEncoding("UTF-8"); // 下面依次获取表单域的值 String name = request.getParameter("name"); String gender = request.getParameter("gender"); // 如果某个请求参数有多个值,将使用该方法获取多个值 String[] colors = request.getParameterValues("color"); String nation1 = request.getParameter("country"); %> <!-- 下面依次输出表单域的值 --> 你的名字:<%=name%><hr/> 你的性别:<%=gender%><hr/> <!-- 输出复选框获取的数组值 --> 你喜欢的颜色:<% for(String c: colors) out.println(c + " ");%><hr/> 你来自的国家:<%=nation1%><hr/> </body> </html>
获取包含非西欧字符的 GET 请求参数:
<%@ page contentType="text/html; charset=UTF-8" %> <html> <head> <title>request2</title> </head> <body> <% // 获取请求里包含的查询字符串 String rawQueryStr = request.getQueryString(); out.println("原始查询字符串为:" + rawQueryStr + "<hr/>"); // 使用 URLDecoder 解码字符串 String queryStr = java.net.URLDecoder.decode(rawQueryStr, "UTF-8"); out.println("解码后的查询字符串为:" + queryStr + "<hr/>"); // 以 & 号分解查询字符串 String[] parameterPairs = queryStr.split("&"); for(String parameterPair : parameterPairs) { out.println("每个请求参数名、值为:" + parameterPair + "<br />"); // 以 = 来分解请求参数名和值 String[] nameValue = parameterPair.split("="); out.println(nameValue[0] + "参数的值是:" + nameValue[1] + "<hr>"); } %> </body> </html>
也可以在获取请求参数之后对请求参数值重新编码,也就是先将其转换成字节数组,再将字节数组重新解码成字符串。如:
// 获取原始的请求参数值 String rawName = request.getParameter("name"); // 将请求参数值使用 ISO-8859-1 字符串分解成字节数组 byte[] rawBytes = rawName.getBytes("ISO-8859-1"); // 将字节数组重新解码成字符串 String name = new String(rawBytes, "UTF-8");
2、操作 request 范围的属性
HttpServletRequest 还包含如下两个方法,用于设置和获取 request 范围的属性。
setAttribute(String attrName, Object attrValue):将 attrValue 设置成 request 范围的属性。
Object getAttribute(String attrName):获取 request 范围属性。
当 forward 用户请求时,请求的参数和请求属性都不会丢失。
3、执行 forward 或 include
request 还有一个功能就是执行 forward 和 include,也就是代替 JSP 所提供的 forward 和 include 动作指令。前面需要 forward 时都是使用 JSP 的 forward 指令,实际上 request 对象也可以执行 forward。
HttpServletRequest 类提供了一个 getRequestDispatcher(String path) 方法,其中 path 就是希望 forward 或者 include 的目标路径,该方法返回 RequestDispatcher,该对象提供了如下两个方法:
a、forward(ServletRequest request, ServletResponse response):执行 forward。
b、include(ServletRequest request, ServletResponse response):执行 include。
如下代码可以将 a.jsp 页面 include 到本页面中:
request.getRequestDispatcher("/a.jsp").forward(request, response);
如下代码可以将请求 forward 到 a.jsp 页面:
request.getRequestDispatcher("/a,jsp").forward(request, response);
注意:使用 request 的 getRequestDispatcher(String path) 方法时,该 path 字符串必须以斜线开头。
response 对象:
response 代表服务器对客户端的响应。大部分时候,程序无须使用 response 来响应客户端请求,因为有个更简单的响应对象 -- out,它代表页面输出流,直接使用 out 生成响应更简单。
但 out 是 JspWriter 的实例,JspWriter 是 Writer 的子类,Writer 是字符流,无法输出非字符内容,假如需要在页面中动态生成一副位图、或者输出一个 PDF 文档,使用 out 作为响应对象将无法完成,此时必须使用 response 作为响应输出。
1、response 响应生成非字符响应
对于需要生成非字符响应的情况,就应该使用 response 来响应客户端请求。下面的 JSP 页面将在客户端生成一张图片。response 是 HttpServletResponse 接口的实例,该接口提供了一个 getOutputStream() 方法,该方法返回响应输出字节流。
如下,输出一张图片:
img.jsp
<!-- 通过 contentType 指定响应数据是图片 --> <%@ page contentType="image/png" %> <%@ page import="java.awt.image.*,javax.imageio.*,java.io.*,java.awt.*" %> <% // 创建 BufferedImage 对象 BufferedImage image = new BufferedImage(340, 160, BufferedImage.TYPE_INT_RGB); // 以 Image 对象获取 Graphics 对象 Graphics g = image.getGraphics(); // 使用 Graphics 画图,所画的图将会出现在 image 对象中 g.fillRect(0, 0, 400, 400); // 设置颜色:红 g.setColor(new Color(255, 0, 0)); // 画出一段弧 g.fillArc(20, 20, 100, 100, 30, 120); // 设置颜色:绿 g.setColor(new Color(0, 255, 0)); // 画出一段弧 g.fillArc(20, 20, 100, 100, 150, 120); // 设置颜色:蓝 g.setColor(new Color(0, 0, 255)); // 画出一段弧 g.fillArc(20, 20, 100, 100, 270, 120); // 设置颜色:黑 g.setColor(new Color(0, 0, 0)); g.setFont(new Font("Arial Black", Font.PLAIN, 16)); // 画出三个字符串 g.drawString("red:climb", 200, 60); g.drawString("green:swim", 200, 100); g.drawString("blue:jump", 200, 140); g.dispose(); // 将图像输出到页面响应 ImageIO.write(image, "png", response.getOutputStream()); %>
使用方法 <img src="/img.jsp">
以上页面的 contentType 指定为 image/png,这表明服务器响应是一张 PNG 图片。接着创建了一个 BufferedImage 对象(代表图像),并获取该 BufferedImage 的 Graphics 对象(代表画笔),然后通过 Graphics 向 BufferedImage 中绘制图形,最后一行代码直接将 BufferedImage 作为响应发送给客户端。
2、重定向
重定向是 response 的另外一个用处,与 forward 不同的是,重定向会丢失所有的请求参数和 request 范围属性,因为重定向将生成第二次请求,与前一次请求不在同一个 request 范围内,所以发送一次清的请求参数和 request 范围属性都会丢失。
HttpServletResponse 提供了一个 sendRedirect(String path) 方法,该方法用于重定向到 path 资源,即重新向 path 资源发送请求。
如:
redirect.jsp
<%@ page contentType="text/html; charset=UTF-8" %> <% // 生成页面响应 out.println("===="); // 重定向到 redirect-result.jsp 页面 response.sendRedirect("redirect-result.jsp"); %>
redirect-result.jsp
<%@ page contentType="text/html; charset=UTF-8" %> <html> <head> <title>redirect result</title> </head> <body> 被重定向的页面<br/> name 请求参数的值: <%=request.getParameter("name")%> </body> </html>
我们在第一个页面的链接后面加上一个get请求参数:http://localhost:8080/jsp/redirect.jsp?name=awk,然后我们在重定向的页面会发现获取到的参数却是 null。
这就说明,我们的 request 里面的参数已经丢失了。
forward 与 redirect 的三个区别:
a、执行 forward 后依然是上一次请求,执行 redirect 后生成第二次请求
b、forward 的目标页面可以访问原请求的参数,因为依然是同一次请求,所有原请求的请求参数、request 范围属性全部存在。redirect 的目标页面不能访问原请求的请求参数、request 范围属性,因为 redirect 产生了一个新的请求。
c、forward 的时候地址栏 URL 不会发生变化。redirect 的时候地址栏 URL 是 redirect 的时候 sendRedirect 参数的值。
3、增加 Cookie
response 对象提供了如下方法:
void addCookie(Cookie cookie):增加cookie
增加 cookie 请按如下步骤进行。
a、创建 Cookie 实例,Cookie 的构造器为 Cookie(String name, String value)
b、设置 Cookie 的生命期限,即该 Cookie 在多长时间内有效。
c、向客户端写 Cookie
<%@ page contentType="text/html; charset=UTF-8" %> <html> <head> <title>cookie</title> </head> <body> <% // 获取请求参数 String name = request.getParameter("name"); // 以获取到的请求参数为值,创建一个 Cookie 对象 Cookie c = new Cookie("username", name); // 设置 Cookie 对象的生存期限(这里是 24 小时) c.setMaxAge(24 * 3600); // 向客户端增加 Cookie 对象 response.addCookie(c); %> </body> </html>
访问客户端的 cookie,request 对象提供了 getCookies 方法,该方法返回客户端机器上所有 Cookie 组成的数组。
<%@ page contentType="text/html; charset=UTF-8" %> <html> <head> <title>读取 cookie</title> </head> <body> <% // 获取本站在客户端上保留的所有 cookie Cookie[] cookies = request.getCookies(); // 遍历客户端上的每个 Cookie for (Cookie c : cookies) { // 如果 Cookie 的名为 username,表明该 Cookie 是需要访问的 Cookie if (c.getName().equals("username")) { out.println(c.getValue()); } } %> </body> </html>
默认情况下,Cookie 值不允许出现中文字符,如果需要值为中文内容的 Cookie,我们可以借助于 java.net.URLEncoder 先对中文字符串进行编码,将编码后的结果设置为 Cookie 值。当程序要读取 Cookie 时,则应该先读取,然后使用 java.net.URLDecoder 对其进行解码。
<%@ page contentType="text/html; charset=UTF-8" %> <html> <head> <title>中文 Cookie</title> </head> <body> <% // 以编码后的字符串为值,创建一个 Cookie 对象 Cookie c = new Cookie("cnName", java.net.URLEncoder.encode("李白", "utf-8")); // 设置 Cookie 对象的生存期限 c.setMaxAge(24 * 3600); // 向客户端增加 Cookie 对象 response.addCookie(c); // 获取本站在客户端上保留的所有 Cookie Cookie[] cookies = request.getCookies(); // 遍历客户端上的每个 Cookie for (Cookie cookie : cookies) { // 如果 Cookie 的名为 cnName,表明该 Cookie 是需要访问的 Cookie if (cookie.getName().equals("cnName")) { // 使用 java.net.URLDecoder 对 Cookie 值进行解码 out.println(java.net.URLDecoder.decode(cookie.getValue())); } } %> </body> </html>
session 对象
session 对象代表一次用户会话。一次用户会话的含义是:从客户端浏览器连接服务器开始,到客户端浏览器与服务器断开为止,这个过程就是一次会话。
session 范围内的属性可以在多个页面的跳转之间共享。一旦关闭浏览器,即 session 结束,session 范围内的属性将全部丢失。
session 对象是 HttpSession 的实例,HttpSession 有如下两个常用的方法。
setAttribute(String attrName, Object attrValue):设置 session 范围内 attrName 属性的值为 attrValue。
getAttribute(String attrName):返回 session 范围内 attrName 属性的值。
使用 session 示例:
shop.jsp
<%@ page contentType="text/html; charset=UTF-8" %> <html> <head> <title>选择物品购买</title> </head> <body> <form method="POST" action="process-buy.jsp"> 书籍:<input type="checkbox" name="item" value="book"/><br/> 电脑:<input type="checkbox" name="item" value="computer"/><br/> 汽车:<input type="checkbox" name="item" value="car"/><br/> <input type="submit" value="购买" /> </form> </body> </html>
process-buy.jsp
<%@ page contentType="text/html; charset=UTF-8" %> <%@ page import="java.util.*" %> <% // 取出 session 范围的 itemMap 属性 Map<String, Integer> itemMap = (Map<String, Integer>)session.getAttribute("itemMap"); // 如果 Map 对象为空,则初始化 Map 对象 if (itemMap == null) { itemMap = new HashMap<String, Integer>(); itemMap.put("书籍", 0); itemMap.put("电脑", 0); itemMap.put("汽车", 0); } // 获取上一个页面的请求参数 String[] buys = request.getParameterValues("item"); // 遍历数组的各元素 for (String item : buys) { // 如果 item 为 book,表示选择购买书籍 if (item.equals("book")) { int num1 = itemMap.get("书籍").intValue(); // 将书籍 key 对应的数量加 1 itemMap.put("书籍", num1 + 1); } else if (item.equals("computer")) { int num2 = itemMap.get("电脑").intValue(); itemMap.put("电脑", num2 + 1); } else if (item.equals("car")) { int num3 = itemMap.get("汽车").intValue(); itemMap.put("汽车", num3 + 1); } } // 将 itemMap 对象放到 session 范围中 session.setAttribute("itemMap", itemMap); %> <html> <head> <title>process buy</title> </head> <body> 你购买的物品:<br/> 书籍:<%=itemMap.get("书籍")%>本<br/> 电脑:<%=itemMap.get("电脑")%>台<br/> 汽车:<%=itemMap.get("汽车")%>辆<br/> <p><a href="shop.jsp">再次购买</a></p> </body> </html>
关于 session 还有一点需要注意的,session 保存的信息需要保存到 web 服务器的硬盘上,所以要求 session 里的属性值必须是可序列化的,否则将会引发不可序列化的异常。
session 的属性值可以是任何可序列化的 Java 对象。