您的位置:首页 > 其它

response对象

2016-07-12 16:19 351 查看
Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象、和代表响应的response对象。request和response对象即然代表请求和响应,那我们要获取客户机提交过来的数据,只需要找request对象就行了。要向客户机输出数据,只需要找response对象就行了。

HttpServletResponse对象介绍



HttpServletResponse对象代表服务器的响应。这个对象中封装了向客户端发送数据、发送响应头,发送响应状态码的方法。查看HttpServletResponse的API,可以看到这些相关的方法。

负责向客户端(浏览器)发送数据的相关方法



负责向客户端(浏览器)发送响应头的相关方法





负责向客户端(浏览器)发送响应状态码的相关方法



响应状态码的常量

HttpServletResponse定义了很多状态码的常量(具体可以查看Servlet的API),当需要向客户端发送响应状态码时,可以使用这些常量,避免了直接写数字,常见的状态码对应的常量:

状态码404对应的常量:



状态码200对应的常量:



状态码500对应的常量:



response对象常见应用

使用OutputStream流向客户端浏览器输出中文数据

例,使用OutputStream流向客户端浏览器输出”中国”这两个汉字。

若代码如下:

public class ResponseDemo1 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String data = "中国";
OutputStream out = response.getOutputStream();
out.write(data.getBytes("UTF-8"));
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


此时会输出乱码:
涓浗
。输出乱码的原因用图来表示,如下:



解决办法:程序以什么码表输出了,程序就一定要控制浏览器以什么码表打开。

public class ResponseDemo1 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 程序以什么码表输出了,程序就一定要控制浏览器以什么码表打开
response.setHeader("Content-type", "text/html;charset=UTF-8");
String data = "中国";
OutputStream out = response.getOutputStream();
out.write(data.getBytes("UTF-8"));
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


客户端浏览器接收到数据后,就按照响应头上设置的字符编码来解析数据。

还可用html技术中的
<meta>
标签模拟了一个http响应头,来控制浏览器的行为。

public class ResponseDemo1 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 用html技术中<meta>标签模拟了一个http响应头,来控制浏览器的行为
String data = "中国";
OutputStream out = response.getOutputStream();

out.write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'>".getBytes());
out.write(data.getBytes("UTF-8"));
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


注意:如果响应头写错了,浏览器会提示下载。

public class ResponseDemo1 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 注意:下面写错了,浏览器会提示下载
response.setHeader("content-type", "text/html,charset=UTF-8");

String data = "中国";
OutputStream out = response.getOutputStream();
out.write(data.getBytes("UTF-8"));
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


运行效果如下:



保存到桌面就是:



打开就能看到“中国”二字。

问题:用OutputStream输出1,客户端看到的是什么?

public class ResponseDemo1 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
OutputStream out = response.getOutputStream();
out.write(1);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


运行上面代码显示的结果如下:



运行的结果和我们想象中的不一样,数字1没有输出来,下面我们修改一下上面的代码,修改后的代码如下:

public class ResponseDemo1 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
OutputStream out = response.getOutputStream();
out.write((1+"").getBytes());
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


1+""
这一步是将数字1和一个空字符串相加,这样处理之后,数字1就变成了字符串1了,然后再将字符串1转换成字节数组使用OutputStream进行输出,此时看到的结果如下:



这次可以看到输出来的1了,这说明了一个问题:在开发过程中,如果希望服务器输出什么浏览器就能看到什么,那么在服务器端都要以字符串的形式进行输出。

总结:

使用OutputStream流输出中文注意问题:在服务器端,数据是以哪个码表输出的,那么就要控制客户端浏览器以相应的码表打开,比如:
outputStream.write("中国".getBytes("UTF-8"));
使用OutputStream流向客户端浏览器输出中文,以UTF-8的编码进行输出,此时就要控制客户端浏览器以UTF-8的编码打开,否则显示的时候就会出现中文乱码,那么在服务器端如何控制客户端浏览器以UTF-8的编码显示数据呢?可以通过设置响应头控制浏览器的行为,例如:
response.setHeader("content-type", "text/html;charset=UTF-8");
通过设置响应头控制浏览器以UTF-8的编码显示数据。

使用PrintWriter流向客户端浏览器输出中文数据

例,使用PrintWriter流向客户端浏览器输出”中国”这两个汉字。

若代码如下:

public class ResponseDemo2 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String data = "中国";
PrintWriter out = response.getWriter();
out.write(data);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


此时会输出乱码:
??
。输出乱码的原因用图来表示,如下:



解决办法:设置response使用的码表,以控制response以什么码表向浏览器写出数据,并指定浏览器以什么码表打开服务器发送的数据。

public class ResponseDemo2 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置response使用的码表,以控制response以什么码表向浏览器写出数据
response.setCharacterEncoding("UTF-8");

// 指定浏览器以什么码表打开服务器发送的数据
response.setHeader("content-type", "text/html;charset=UTF-8");

String data = "中国";
PrintWriter out = response.getWriter();
out.write(data);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


以上代码还可以写为:

public class ResponseDemo2 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");

String data = "中国";
PrintWriter out = response.getWriter();
out.write(data);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


response.setContentType("text/html;charset=UTF-8");
一句话可顶两句话使。

总结:

使用PrintWriter流输出中文注意的问题:在获取PrintWriter输出流之前首先使用
response.setCharacterEncoding(charset)
设置字符以什么样的编码输出到浏览器,如:
response.setCharacterEncoding("UTF-8");
设置将字符以”UTF-8”编码输出到客户端浏览器,然后再使用
response.getWriter();
获取PrintWriter输出流,这两个步骤不能颠倒。

文件下载

文件下载功能是web开发中经常使用到的功能,使用HttpServletResponse对象就可以实现文件的下载。

文件下载功能的实现思路:

获取要下载的文件的绝对路径。

获取要下载的文件名。

设置content-disposition响应头控制浏览器以下载的形式打开文件。

获取要下载的文件输入流。

创建数据缓冲区。

通过response对象获取OutputStream流。

将FileInputStream流写入到buffer缓冲区。

使用OutputStream将缓冲区的数据输出到客户端浏览器。

例,使用Response实现文件下载。

public class ResponseDemo3 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.获取要下载的文件的绝对路径
String path = this.getServletContext().getRealPath("/download/1.jpg");
// 2.获取要下载的文件名
String filename = path.substring(path.lastIndexOf("\\")+1);
// 3.设置content-disposition响应头控制浏览器以下载的形式打开文件
response.setHeader("content-disposition", "attachment;filename="+filename);

InputStream in = null;
OutputStream out = null;
try {
// 4.获取要下载的文件输入流
in = new FileInputStream(path);
int len = 0;
// 5.创建数据缓冲区
byte[] buffer = new byte[1024];
// 6.通过response对象获取OutputStream流
out = response.getOutputStream();
// 7.将FileInputStream流写入到buffer缓冲区
while((len=in.read(buffer)) != -1) {
// 8.使用OutputStream将缓冲区的数据输出到客户端浏览器
out.write(buffer, 0, len);
}
} finally {
if(in != null) {
try {
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(out != null) {
try {
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


运行结果如下所示:



例,使用Response实现中文文件下载。

下载中文文件时,需要注意的地方就是中文文件名要使用
URLEncoder.encode
方法进行编码(
URLEncoder.encode(fileName, "字符编码")
),否则会出现文件名乱码。

public class ResponseDemo3 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.获取要下载的文件的绝对路径
String path = this.getServletContext().getRealPath("/download/坂井泉水.jpg");
// 2.获取要下载的文件名
String filename = path.substring(path.lastIndexOf("\\")+1);

// 3.设置content-disposition响应头控制浏览器以下载的形式打开文件,如果下载文件是中文文件,则文件名需要经过url编码
response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(filename, "UTF-8"));

InputStream in = null;
OutputStream out = null;
try {
// 4.获取要下载的文件输入流
in = new FileInputStream(path);
int len = 0;
// 5.创建数据缓冲区
byte[] buffer = new byte[1024];
// 6.通过response对象获取OutputStream流
out = response.getOutputStream();
// 7.将FileInputStream流写入到buffer缓冲区
while((len=in.read(buffer)) != -1) {
// 8.使用OutputStream将缓冲区的数据输出到客户端浏览器
out.write(buffer, 0, len);
}
} finally {
if(in != null) {
try {
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(out != null) {
try {
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


运行结果如下所示:



文件下载注意事项:编写文件下载功能时推荐使用OutputStream流,避免使用PrintWriter流,因为OutputStream流是字节流,可以处理任意类型的数据,而PrintWriter流是字符流,只能处理字符数据,如果用字符流处理字节数据,会导致数据丢失。

生成随机图片用作验证码

生成随机图片用作验证码可参考我的笔记通过Servlet生成验证码图片

肯定还有不完善的地方,留待以后修改。

设置响应头控制浏览器的行为

设置http响应头控制浏览器禁止缓存当前文档内容

response.setDateHeader("expries", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");


设置http响应头控制浏览器缓存当前文档内容

例,设置http响应头——expires,控制浏览器缓存当前网页内容一个小时。

// 控制浏览器缓存
public class ResponseDemo6 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setDateHeader("expires", System.currentTimeMillis()+1000*3600);

String data = "aaaaaaaaaaaaaaa";
response.getWriter().write(data);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


当用户第一次访问ResponseDemo6,向服务器发送一次请求,再次访问ResponseDemo6,都不会向服务器发送任何请求,而是向缓存拿数据。

那么怎样查看缓存的网页呢?

在火狐浏览器地址栏中输入
about:cache
,并回车。



点击
disk
(磁盘)→
List Cache Entries
(缓存条目列表)。



可发现ResponseDemo6被缓存一个小时,所以以后访问ResponseDemo6,都不会向服务器发送任何请求,而是向缓存拿数据。

设置http响应头控制浏览器定时刷新网页(refresh)

例,控制浏览器定时刷新网页。

public class ResponseDemo5 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

response.setHeader("refresh", "3"); // 设置refresh响应头控制浏览器每隔3秒钟刷新一次

String data = new Random().nextInt(1000000) + "";
response.getWriter().write(data);

}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


在实际开发中,并不会遇到向上面的那样的例子,我们更有可能的是碰到诸如类似以下的例子:

假设这是一个用于处理登录的servlet:

public class ResponseDemo5 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

// 假设程序运行到此,用户登录成功了

response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.setHeader("refresh", "3;url='/day06/index.jsp'"); // 3秒后刷新到首页(index.jsp)

response.getWriter().write("恭喜你,登录成功,本浏览器将在3秒后跳转到首页,如果没有跳,请点<a href=''>超链接</a>");

}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


虽然以上程序在3秒后自动刷新到首页(index.jsp),但是我们要知道客户机请求服务器,访问Servlet,Servlet产生数据,数据不适合在Servlet输出!这时Servlet通常会把请求转发给jsp,由jsp负责输出数据。所以,代码应该修改为:

实用的自动跳转技术:

public class ResponseDemo5 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

// 假设程序运行到此,用户登录成功了

String message = "<meta http-equiv='refresh' content='3;url=/day06/index.jsp'>恭喜你,登录成功,本浏览器将在3秒后跳转到首页,如果没有跳,请点<a href=''>超链接</a>";
this.getServletContext().setAttribute("message", message);
this.getServletContext().getRequestDispatcher("/message.jsp").forward(request, response);

}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


注意:ServletContext对象会被所有的web资源所共享,通过它来带数据,会出现数据紊乱的现象。在实际开发里面,不能通过context域,要通过request域。

message.jsp获取数据并显示:

<%@ page language="java" 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>Insert title here</title>
</head>
<body>
<%
String message = (String)application.getAttribute("message");
out.write(message);
%>
</body>
</html>


访问ResponseDemo5,达到相同的效果,即在3秒后自动刷新到首页。但是以上程序更为实用。

通过response实现请求重定向

请求重定向指:一个web资源收到客户端请求后,通知客户端去访问另外一个web资源,这称之为请求重定向。

应用场景:

用户登录,用户首先访问登录页面,登录成功后,就会跳转到某个页面,这个过程就是一个请求重定向的过程。

显示购物车,通常会用到重定向技术。

实现方式:
response.sendRedirect(String location)
,即调用response对象的sendRedirect方法实现请求重定向。

sendRedirect内部的实现原理:使用response设置302状态码和设置location响应头实现重定向。

使用response设置302状态码和设置location响应头实现请求重定向。

public class ResponseDemo7 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

response.setStatus(302);
response.setHeader("location", "/day06/index.jsp");

}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


以上代码相当于以下代码——调用sendRedirect方法实现请求重定向。

public class ResponseDemo7 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

response.sendRedirect("/day06/index.jsp");

}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


重定向的特点:

浏览器向服务器发送2次请求,意味着就有2个request\response。

用重定向技术,浏览器地址栏会发生变化。

请求重定向的运行流程

































response细节问题

getOutputStream和getWriter方法分别用于得到输出二进制数据、输出文本数据的ServletOuputStream、Printwriter对象。

getOutputStream和getWriter这两个方法互相排斥,调用了其中的任何一个方法后,就不能再调用另一方法。

例,同时调用getOutputStream()和getWriter()方法会抛:
java.lang.IllegalStateException: getOutputStream() has already been called for this response


public class ResponseDemo8 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getOutputStream();
response.getWriter();
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


虽然以上代码你不会愚蠢的写出来,但作为一名合格的JavaWeb开发者一定会碰到这个问题,你碰到的代码可能是这样的。

ResponseDemo8

public class ResponseDemo8 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getOutputStream();
// response.getWriter();
this.getServletContext().getRequestDispatcher("/ResponseDemo9").forward(request, response);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


ResponseDemo9

public class ResponseDemo9 extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter();
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


转发时用到的是同一个request请求,你可能会犯以上这样的错误。

Servlet程序向ServletOutputStream或PrintWriter对象中写入的数据将被Servlet引擎从response里面获取,Servlet引擎将这些数据当作响应消息的正文,然后再与响应状态行和各响应头组合后输出到客户端。

Serlvet的service方法结束后,Servlet引擎将检查getWriter或getOutputStream方法返回的输出流对象是否已经调用过close方法,如果没有,Servlet引擎将调用close方法关闭该输出流对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: