这里讲述的是Servlet中的response对象的使用(request对象将在下文进行介绍)。如下:
1. 使用ServletOutputStream或PrintWriter向客户端输出数据;
2. 文件的下载;
3. 输出图片验证码;
4. 控制浏览器缓存当前请求内容;
5. 通过response实现请求重定向。
getOutputStream
和getWriter
方法分别用于得到输出二进制数据、输出文本数据的ServletOutputStream
、PrintWriter
对象。getOutputStream
和getWriter
这两个方法互相排斥,调用了其中的任何一个方法后,就不能再调用另一方法。请求转发的情况下同样不能同时调用这两个方法,如请求转发前的Servlet调用了getOutputStream
方法,请求转发后的Servlet调用了getWriter
方法,这样的做法同样会使程序报错。同时调用response的getOutputStream和getWriter方法会抛出:java.lang.IllegalStateException: getOutputStream() has already been called for this response 异常。ServletOutputStream
或PrintWriter
对象中写入的数据将被Servlet引擎从response里面获取,Servlet引擎将这些数据当前响应消息的正文,然后再与响应状态行和各响应头组合后输出到客户端。getWriter
或getOutputStream
方法返回的输出流对象是否已经调用过close方法,如果没有,Servlet引擎将调用close方法关闭该输出流对象。所以在实际开发过程中,我们无需调用close方法关闭getWriter
或getOutputStream
方法返回的输出流对象。但是对于我们自己创建的流对象就需要调用close方法手动关闭。使用字节流 ServletOutputStream 向客户端输出数据,注意中文数据输出和数字输出的问题。
package com.wm103.response;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
/**
* Created by DreamBoy on 2017/4/28.
*/
/**
* 在servlet中用OutputStream输出数据的问题
*/
@WebServlet(name = "ResponseDemo1", urlPatterns = {"/ResponseDemo1"})
public class ResponseDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
test3(response);
}
/**
* 设置Content-type响应头
* @param response
* @throws IOException
*/
private void test1(HttpServletResponse response) throws IOException {
response.setHeader("Content-type", "text/html;charset=UTF-8");
String data = "中国";
OutputStream out = response.getOutputStream();
out.write(data.getBytes("UTF-8"));
}
/**
* 用html技术中meta标签模拟了一个http响应头,来控制浏览器的行为
* @param response
* @throws IOException
*/
private void test2(HttpServletResponse response) throws IOException {
String data = "中国";
OutputStream out = response.getOutputStream();
out.write("".getBytes());
out.write(data.getBytes("UTF-8"));
}
/**
* 输出数字
* @param response
* @throws IOException
*/
private void test3(HttpServletResponse response) throws IOException {
OutputStream out = response.getOutputStream();
//out.write(1); // 在浏览器中看不到1这个结果,需要以字符串形式输出数字
out.write((1 + "").getBytes());
}
}
使用字符流 PrintWriter 向客户端输出字符串数据,注意中文数据输出乱码问题。
package com.wm103.response;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* Created by DreamBoy on 2017/4/28.
*/
/**
* 通过response的write流输出数据的问题
*/
@WebServlet(name = "ResponseDemo2", urlPatterns = {"/ResponseDemo2"})
public class ResponseDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
test2(response);
}
/**
* response.getWriter()输出中文数据显示的问题
* @param response
* @throws IOException
*/
private void test1(HttpServletResponse response) throws IOException {
// 设置response使用的码表,以控制response以什么码表向浏览器写出数据。(默认用的是ISO-8859-1)
response.setCharacterEncoding("UTF-8");
// 控制浏览器以什么码表显示服务器发送的数据
response.setHeader("Content-type", "text/html;charset=utf-8");
String data = "中国";
PrintWriter out = response.getWriter();
out.println(data);
out.write(data);
}
/**
* 以下方法相当于上述方法
* @param response
* @throws IOException
*/
private void test2(HttpServletResponse response) throws IOException {
response.setCharacterEncoding("UTF-8"); // 这句话也可以不写
response.setContentType("text/html;charset=utf-8");
String data = "中国";
PrintWriter out = response.getWriter();
out.println(data);
out.write(data);
}
}
设置response的content-disposition
响应头,提示文件下载,具体实现文件下载的程序如下:(示例中供下载的图片放置在项目的web目录的download文件夹下(如果是MyEclipse的话则是WebRoot目录的download文件夹下))
注意:如果供下载的文件是以中文命名,则文件名在设置content-disposition时要经过URL编码。
package com.wm103.response;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
/**
* Created by DreamBoy on 2017/4/28.
*/
/**
* 文件下载
*/
@WebServlet(name = "ResponseDemo3", urlPatterns = {"/ResponseDemo3"})
public class ResponseDemo3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//String path = this.getServletContext().getRealPath("/download/1.jpg");
String path = this.getServletContext().getRealPath("/download/图片.jpg");
String filename = path.substring(path.lastIndexOf("\\") + 1);
// 如果下载文件是以中文命名,则文件名需要经过url编码
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(path);
int len;
byte buffer[] = new byte[1024];
out = response.getOutputStream();
while ((len = in.read(buffer)) > 0) {
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();
}
}
}
}
}
使用Java中的BufferedImage类,调用getGraphics方法,获取Graphics类的对象,进行图片的绘制。绘制成功后设置响应头返回的数据类型为图片,并控制浏览器不需要缓存当前请求。示例如下:
package com.wm103.response;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
/**
* Created by DreamBoy on 2017/4/28.
*/
/**
* 输出一张随机图片(图片验证码)
*/
@WebServlet(name = "ResponseDemo4", urlPatterns = {"/ResponseDemo4"})
public class ResponseDemo4 extends HttpServlet {
public static final int WIDTH = 120;
public static final int HEIGHT = 50;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
// 1. 设置背景色
this.setBackground(g);
// 2. 设置边框
this.setBorder(g);
// 3. 画干扰线
this.drawRandomLine(g);
// 4. 写随机数
this.drawRandomNum((Graphics2D) g);
// 5. 图片写给浏览器
response.setContentType("image/jpeg");
// 控制浏览器不要缓存图片
response.setDateHeader("expires", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
ImageIO.write(image, "jpg", response.getOutputStream());
}
private void drawVCode() {
}
private void setBackground(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
}
private void setBorder(Graphics g) {
g.setColor(Color.BLUE);
g.drawRect(1, 1, WIDTH - 2, HEIGHT - 2);
}
private void drawRandomLine(Graphics g) {
g.setColor(Color.GREEN);
for(int i = 0; i < 5; i++) {
int x1 = new Random().nextInt(WIDTH);
int y1 = new Random().nextInt(HEIGHT);
int x2 = new Random().nextInt(WIDTH);
int y2 = new Random().nextInt(HEIGHT);
g.drawLine(x1, y1, x2, y2);
}
}
private void drawRandomNum(Graphics2D g) {
int fontSize = 20;
g.setColor(Color.RED);
g.setFont(new Font("宋体", Font.BOLD, fontSize));
String base = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789";
int fontNum = 4;
int y = 32;
int x = 18; String ch;
for(int i = 0; i < fontNum; i++) {
int degree = new Random().nextInt() % 30;
double radian = degree * Math.PI / 180; // 弧度
g.rotate(radian, x, y); // 设置旋转的弧度
ch = base.charAt(new Random().nextInt(base.length())) + "";
g.drawString(ch, x, y);
g.rotate(-radian, x, y);
x += 25;
}
}
}
在页面中的使用,如下:
验证码:<img style="cursor:pointer;" src="/day06/ResponseDemo4" alt="换一张" onclick="this.src = '/day06/ResponseDemo4?' + new Date().getTime()">
response.setHeader("refresh", "3");
response.setHeader("refresh", "3;url='/index.jsp'");
<meta http-equiv="refresh" content="3;url=index.jsp">
response.setDateHeader("expires", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
String data = "This is ResponseDemo5.";
response.setDateHeader("expires", System.currentTimeMillis() + 1000 * 3600); // 缓存一个小时
response.getWriter().write(data);
重定向的特点:
1. 浏览器会向服务器发送两次请求;
2. 浏览器地址将发生变化
用户登录和显示购物车时,通常会用到重定向技术。
/*response.setStatus(302);
response.setHeader("location", "/day06/index.jsp");*/
response.sendRedirect("/day06/index.jsp");