Servlet中的response对象

目录

  • 目录
  • 前言
  • 简介
  • 向客户端输出数据
    • response对象的getOutputStream方法
    • response对象的getWriter方法
  • 实现文件下载
  • 生成图片验证码
  • 实现浏览器定时刷新
  • 控制浏览器缓存
  • 实现请求重定向

前言

  这里讲述的是Servlet中的response对象的使用(request对象将在下文进行介绍)。如下:
1. 使用ServletOutputStream或PrintWriter向客户端输出数据;
2. 文件的下载;
3. 输出图片验证码;
4. 控制浏览器缓存当前请求内容;
5. 通过response实现请求重定向。

简介

  • Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象和代表响应的response对象。
  • request和response对象既然代表请求和响应,那我们要获取客户机提交过来的数据,只需要找request对象就行了。要向客户机输出数据,只需要找response对象就行了。
  • HttpServletResponse对象代表服务器的响应。这个对象中封装了向客户端发送数据、发送响应头,发送响应状态码的方法。

向客户端输出数据

  • getOutputStreamgetWriter方法分别用于得到输出二进制数据、输出文本数据的ServletOutputStreamPrintWriter对象。
  • getOutputStreamgetWriter这两个方法互相排斥,调用了其中的任何一个方法后,就不能再调用另一方法。请求转发的情况下同样不能同时调用这两个方法,如请求转发前的Servlet调用了getOutputStream方法,请求转发后的Servlet调用了getWriter方法,这样的做法同样会使程序报错。同时调用response的getOutputStream和getWriter方法会抛出:java.lang.IllegalStateException: getOutputStream() has already been called for this response 异常。
  • Servlet程序向ServletOutputStreamPrintWriter对象中写入的数据将被Servlet引擎从response里面获取,Servlet引擎将这些数据当前响应消息的正文,然后再与响应状态行和各响应头组合后输出到客户端。
  • Servlet的service方法结束后,Servlet引擎将检查getWritergetOutputStream方法返回的输出流对象是否已经调用过close方法,如果没有,Servlet引擎将调用close方法关闭该输出流对象。所以在实际开发过程中,我们无需调用close方法关闭getWritergetOutputStream方法返回的输出流对象。但是对于我们自己创建的流对象就需要调用close方法手动关闭。

response对象的getOutputStream方法

  使用字节流 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());
    }
}

response对象的getWriter方法

  使用字符流 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()">

实现浏览器定时刷新

  • 每隔3秒刷新当前页面
response.setHeader("refresh", "3");
  • 3秒后跳转某一页面
response.setHeader("refresh", "3;url='/index.jsp'");
  • 通过HTML实现定时跳转
<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");

你可能感兴趣的:(JavaEE)