2.6.7 response对象

2.6.7 response对象

response代表服务器对客户端的响应。大部分时候,程序无须使用response来响应客户端请求,因为有个更简单的响应对象out,它代表页面输出流,直接使用out生成响应更简单。
outJspWriter的实例,JspWriterWriter的子类,Writer是字符流,无法输出非字符内容假如需要在JSP页面中动态生成一幅位图、或者输出一个PDF文档,使用out作为响应对象将无法完成,此时必须使用response作为响应输出。
除此之外,还可以使用response来重定向请求,以及用于向客户端增加Cookie.

1. response响应生成非字符响应

对于需要生成非字符响应的情况,就应该使用response来响应客户端请求。下面的JSP页面将在客户端生成一张图片。

getOutputStream方法

responseHttpServletResponse接口的实例,该接口提供了一个getOutputStream()方法,该方法返回响应输出字节流.

img.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<%-- 通过contentType属性指定响应数据是图片 --%>
<%@ page contentType="image/png" language="java"%>
<%@ 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());
%>

以上页面的代码:

1
<%@ page contentType="image/png" language="java"%>

先设置了服务器响应数据是image/png,这表明服务器响应是一张PNG图片。
接着创建了一个BufferedImage对象(代表图像),并获取该BufferedImageGraphics对象(代表画笔),然后通过GraphicsBufferedImage中绘制图形,最后一行代码将直接将BufferedImage作为响应发送给客户端。

测试

请直接在浏览器中请求该页面,将看到浏览器显张图片,效果如图2.29所示。

jsp页面直接作为img标签的地址

也可以在其他页面中使用img标签来显示这个图片页面,代码如下:

1
<img src="img.jsp">

图形验证码

使用这种临时生成图片的方式就可以非常容易地实现网页上的图形验证码功能。不仅如此,使用response生成非字符响应还可以直接生成PDF文件、Excel文件,这些文件可直接作为报表使用。

2. 重定向

重定向会丢失请求数据

重定向是response的另外一个用处,与forward不同的是,重定向会丢失所有的请求参数和request范围的属性,因为重定向将生成第二次请求,与前一次请求不在同一个request范围内,所以发送一次请求的请求参数和request范围的属性全部丢失。

response.sendRedirect方法

HttpServletResponse提供了一个sendRedirect(String path)方法,该方法用于重定向到path资源,即重新向path资源发送请求。

doRedirect.jsp

下面的JSP页面将使用response执行重定向。

1
2
3
4
5
6
7
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<%
// 生成页面响应
out.println("====");
// 重定向到redirect-result.jsp页面
response.sendRedirect("redirect-result.jsp");
%>

以上页面的代码:

1
response.sendRedirect("redirect-result.jsp");

用于执行重定向,向该页面发送请求时,请求会被重定向到redirect-result.jsp页面。例如,在地址栏中输入htp:/Localhost888LjspObject/doRedirectJsp?name=Crazyit.org,然后按回车键,将看到如图2.30所示的效果。

注意地址栏的改变,执行重定向动作时,地址栏的URL会变成重定向的目标URL,而且重定向丢失了请求数据。

重定向会丢失所有的请求参数,使用重定向的效果,与在地址栏里重新输入新地址再按回车键的效果完全一样,即发送了第二次请求。

forward和redirect的区别

从表面上来看,forward动作和redirect动作有些相似:它们都可将请求传递到另一个页面。但实际上forwardredirect之间存在较大的差异,forwardredirect的差异如表2.1所示

转发(forward) 重定向(redirect)
执行forward后依然是上一次请求 执行redirect后生成第二次请求
forward的目标页面可以访问原请求的请求参数,因为依然是同一次请求,所有原请求的请求参数、request范围的属性全部存在 redirect的目标页面不能访问原请求的请求参数,因为是第二次请求了,所有原请求的请求参数、request范围的属性全部丢失
地址栏里请求的URL不会改变 地址栏改为重定向的目标URL。相当于在浏览器地址栏里输入新的URL后按回车键

3. 增加Cookie

Cookie通常用于网站记录客户的某些信息,比如客户的用户名及客户的喜好等。一旦用户下次登录,网站可以获取到客户的相关信息,根据这些客户信息,网站可以对客户提供更友好的服务。

cookie和session的区别

Cookiesession的不同之处在于:session会随浏览器的关闭而失效,但Cookie会一直存放在客户端机器上,除非超出Cookie的生命期限。

客户端可禁用cookie

由于安全性的原因,使用Cookie客户端浏览器必须支持Cookie才行。客户端浏览器完全可以设置禁用Cookie
增加Cookie也是使用response内置对象完成的,response对象提供了如下方法。

response对象方法 描述
void addCookie(Cookie cookie) 增加Cookie

在增加Cookie之前,必须先创建Cookie对象。

添加Cookie的步骤

增加Cookie请按如下步骤进行:

  1. 创建Cookie实例,Cookie的构造器为Cookie(String name, String value)
  2. 设置Cookie的生命期限,即该Cookie在多长时间内有效
  3. 向客户端写Cookie

程序示例 读写cookie

addCookie.jsp

看如下JSP页面,该页面可以用于向客户端写一个usernameCookie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<!DOCTYPE html>
<html>
<head>
<title> 增加Cookie </title>
</head>
<body>
<%
// 获取请求参数
String name = request.getParameter("name");
// 以获取到的请求参数为值,创建一个Cookie对象
Cookie c = new Cookie("username" , name);
// 设置Cookie对象的生存期限
c.setMaxAge(24 * 3600);
// 向客户端增加Cookie对象
response.addCookie(c);
%>
</body>
</html>

如果浏览器没有阻止Cookie,在地址栏输入:

1
http://localhost:8080/jspObject/addCookie.jsp?name=Trump

执行该页面后,网站就会向客户端机器写入一个名为usernameCookie,该Cookie将在客户端硬盘上一直存在,直到超出该Cookie的生存期限(本Cookie设置为24小时)。

读取cookie request.getCookies方法

访问客户端Cookie使用request对象。

  1. request对象提供了getCookies()方法,该方法将返回客户端机器上所有Cookie组成的数组,
  2. 然后遍历该数组的每个元素,找到希望访问的Cookie即可。

readCookie.jsp

下面是访问CookieJSP页面的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<!DOCTYPE html>
<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>

上面的代码就是通过request读取Cookie数组,并搜寻指定Cookie的关键代码,访问该页面即可读出刚才写在客户端的Cookie

使用Cookie对象必须设置其生存期限,否则Cookie将会随浏览器的关闭而自动消失
默认情况下,Cookie值不允许出现中文字符,如果需要值为中文内容的Cookie怎么办呢?同样可以借助于java.net.URLEncoder先对中文字符串进行编码,将编码后的结果设为Cookie值。当程序要读取Cookie时,则应该先读取,然后使用java.net.URLDecoder对其进行解码。

cnCookie.jsp

如下代码片段示范了如何存入值为中文的Cookie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<!DOCTYPE html>
<html>
<head>
<title> 中文Cookie </title>
</head>
<body>
<%
// 以编码后的字符串为值,创建一个Cookie对象
Cookie c = new Cookie("cnName"
, java.net.URLEncoder.encode("孙悟空" , "gbk"));
// 设置Cookie对象的生存期限
c.setMaxAge(24 * 3600);
// 向客户端增加Cookie对象
response.addCookie(c);

// 获取本站在客户端上保留的所有Cookie
Cookie[] cookies = request.getCookies();
// 遍历客户端上的每个Cookie
for (Cookie cookie : cookies)
{
// 如果Cookie的名为username,表明该Cookie是需要访问的Cookie
if(cookie.getName().equals("cnName"))
{
//使用java.util.URLDecoder对Cookie值进行解码
out.println(java.net.URLDecoder
.decode(cookie.getValue()));
}
}
%>
</body>
</html>

上面的程序中两行粗体字代码是存入值为中文的Cookie的关键:存入之前先用java.net.URLEncoder进行编码;读取时需要对读取的Cookie值用Java.net.URLDecoder进行解码。