Java Web(6)—HttpServletResponse的介绍以及使用

  详细介绍了JavaWeb Servlet中的HttpServletResponse的常见用法和API,比如设置响应头、响应体、重定向等知识点。

  javax.servlet.http.HttpServletResponse继承了ServletResponse。专门为基于HTTP协议的HTTPServlet 封装、提供响应信息,是响应的抽象。
  在客户端发出每个HTTP请求时,服务器都会创建一个对应的HttpServletResponse对象,然后在调用Servlet.service()方法时传递给service()方法,随后又会传递给对应类型的服务方法(doGet、doPost 等)中,开发中是可以直接通过该对象来设置响应的信息,tomcat服务器会从该对象中获取响应的信息,响应给客户端。
  response对象的功能分为以下四种:

  1. 设置响应头信息;
  2. 设置响应状态码;
  3. 设置响应正文,发送响应。
  4. 重定向;

文章目录

1 设置响应头信息

void setHeader(String name,value)

  设置具有给定名称和值的响应标头。使用该方法设置的响应头最终会发送给客户端浏览器!如果已设置某个响应头,则新值将覆盖旧值。注意addheader()方法将不会覆盖。
  该方法模拟了html的meta标签,第一个参数相当于meta标签的http-equiv/name属性,第二个参数相当于meta标签的content属性。http-equiv顾名思义,相当于http的文件头作用,它可以向浏览器传回一些有用的信息,以帮助正确和精确地显示网页内容,与之对应的属性值为content,content中的内容其实就是各个参数的变量值。即key-value。

  上面的方法可设置所有类型的响应头,当然也可以针对不同类型使用不同方法。如下:

void setDateHeader(String name,long date)

  设置具有给定名称和日期值的响应头。日期是以时间周期以来的毫秒为单位指定的。如果已设置响应头, 则新值将覆盖上一个值。

void setIntHeader(String name,int value)

  设置具有给定名称和整数值的响应头。如果已设置头, 则新值将覆盖上一个值。

1.1 设置字符集

response.setHeader(“content-type”, “text/html;charset=utf-8”);

  设置content-type响应头,该头的作用是告诉浏览器响应内容为html类型,编码为utf-8,让浏览器以utf-8编码格式解析,而且同时会设置response响应正文的字符流编码为utf-8,即等同于多调用response.setCharaceterEncoding(“utf-8”)

response.setContentType(“text/html;charset=utf-8”);

  这等同与调用response.setHeader(“content-type”, “text/html;charset=utf-8”);

response.setCharacterEncoding(“utf-8”)

  专门用于设置HTTP 响应的编码为utf-8,但并没有通知浏览器以utf-8的编码格式解析响应正文,浏览器还是按照自己之前的编码格式处理正文,故而可能会出现乱码。

1.2 设置自动刷新和跳转

response.setHeader(“Refresh”,“5”);

  每5秒自动刷新一次

response.setHeader(“Refresh”,“5;URL=http://www.baidu.com”)

  5秒后自动跳转到百度主页。
  在登陆完网站之后,很多时候都会看见(登陆成功,3秒后自动跳转…),这样的功能就是Refresh响应头来完成的。

1.3 设置页面不缓存

  三个响应头配合。一般servlet使用,jsp不使用,因为jsp直接用meta标签设置不缓存。

response.setHeader(“expires”, “0”);

  当前页面过期时间,立刻过期。还可以设置精确的过期时间,0表示立刻过期。

response.setHeader(“pragma”, “no-cache”);

  HTTP1.0通过Pragma控制浏览器缓存。

response.setHeader(“cache-control”, “no-cache”);

  HTTP1.1通过Cache-Control控制浏览器缓存。

1.4 设置重定向

  在设置状态码response.setStatus(302);之后设置location响应头:

response.setHeader(“Location”, “http://www.baidu.com”);

2 设置状态码

void setStatus(int sc)

  设置此响应的状态代码。此方法用于在没有错误时设置返回状态代码。sc-状态码

void sendError(int sc)

  使用指定的错误状态码向客户端发送错误响应, 并清除缓冲区。sc-错误状态码

void sendError(int sc, msg)

  使用指定的错误状态码向客户端发送错误响应, 并清除缓冲区。传入的描述性信息,将覆盖默认的状态码的描述性信息。sc-错误状态码 msg-描述性信息

void setStatus(int sc,java.lang.String sm)

  该方法已被废弃。由于从2.1 版开始, 由于消息参数的含义不明确,不适合自定义描述性信息。

3 设置响应正文

  给客户端浏览器发送的内容,可以显示在浏览器窗体中。

3.1 设置响应正文

java.io.PrintWriter getWriter()

  返回可以向客户端发送字符文本的printwriter对象。如果没有在 setCharacterEncoding()方法中指定响应的字符集,或者其他方法指定字符集,那么该方法会默认字符集为iso-8859-1。
  PrintWriter的write()、print()Println()方法还可以输出html标签,将会被浏览器解析。

response.setContentType("text/html;charset=utf-8");
out.println("<form action='#' method='post'>");
out.println("用户名:");
out.println("<input type='text' name='username'><br/>");
out.println("密码:");
out.println("<input type='password' name='password'><br/>");
out.println("<input type='submit' value='login'>");
out.println("</form>");
out.flush();
out.close();

ServletOutputStream getOutputStream()

  返回适用于在响应中写入二进制数据的 servleteoutputstream。servlet 容器不对二进制数据进行编码。在 servletoutputstream 上调用flush()将刷新提交响应。
  注意:若将字符串转换为字节数组再通过字节流发送,那么可能出现乱码问题,因为getBytes()方法默认使用的gbk编码,需要为该方法和浏览器设置统一的字符集。可以是””.getBytes(“utf-8”),或者设置response.setContentType(“text/html;charset=gbk”);
  ServletOutputStream的write()、print()、Println()方法也能输出html标签。不过write()要注意字符集使用的统一,print()、Println()不可出现中文以及中文字符。

response.setContentType("text/html;charset=gbk");
ServletOutputStream out = response.getOutputStream();
out.write("<form action='#' method='post'>".getBytes("gbk"));
out.write("用户名:".getBytes("gbk"));
out.write("<input type='text' name='username'><br/>".getBytes("gbk"));
out.write("密码:".getBytes("gbk"));
out.write("<input type='password' name='password'><br/>".getBytes("gbk"));
out.write("<input type='submit' value='login'>".getBytes("gbk"));
out.write("</form>".getBytes("gbk"));
out.flush();
out.close();	

  注意:PrintWriter字节流和OutputStream字符流,只能使用其中一个。两个使用会发生冲突,抛出异常IllegalStateException。

3.2 设置字符集

void setCharacterEncoding(java.lang.String charset)

  设置发送到客户端的响应的字符编码,即设置了响应正文的编码格式是utf-8,而并没有通知浏览器以utf-8的编码格式解析响应正文,浏览器还是按照自己之前的编码格式处理正文,故而可能会出现乱码。可以重复调用此方法来更改字符编码。如果在调用getwriter之后或在提交响应后调用此方法,则此方法无效。

response.setHeader(“content-type”, “text/html;charset=utf-8”);

  设置content-type响应头,该头的作用是告诉浏览器响应内容为html类型,编码为utf-8,通知浏览器以utf-8编码格式解析。而且同时会设置response响应正文的字符流编码为utf-8,即response.setCharaceterEncoding(“utf-8”) 。只有在调用 getwriter 之前调用此方法时,才会从给定的内容类型设置响应的字符编码。

response.setContentType(“text/html;charset=utf-8”);

  等同与调用response.setHeader(“content-type”, “text/html;charset=utf-8”);

  注意:setCharacterEncoding方法设置的响应正文字符集与setHeader或者setContentType方法设置的字符集会按设置顺序相互覆盖。
  setCharacterEncoding(“utf-8”)和setContentType(“text/html”)这两个方法同时调用就等同于setContentType(“text/html; charset=UTF-8”)。

1.4 设置文件下载

  文件下载需要设置response.addHeader(“Content-Disposition”, “attachment;filename=” + filename)响应头。
  假设我们需要下载Web应用中的某张图片,那么:

@WebServlet("/PicDownload-servlet")
public class PicDownloadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取图片文件流
        ServletContext servletContext = getServletContext();
        InputStream resourceAsStream = servletContext.getResourceAsStream("WEB-INF/pic2.jpg");
        //读取流直接数据到bytes数组中
        int available = resourceAsStream.available();
        byte[] bytes = new byte[available];
        resourceAsStream.read(bytes);

        //设置Content-Disposition响应头
        resp.setHeader("Content-Disposition", "attachment;filename=" + "pic2.jpg");

        //响应流写bytes数组
        ServletOutputStream outputStream = resp.getOutputStream();
        outputStream.write(bytes);
        outputStream.close();
    }
}

  访问http://localhost:8080/servlet-01/PicDownload-servlet,浏览器即会弹出下载保存框。

5 展示图片

  上面的是下载图片,那么我们如何让浏览器直接在页面上展示图片呢,也很简单,我么你只需要设置resp.setContentType(“image/jpeg”),即设置Content-Type类型为对应的图片类型就可以了!

@WebServlet("/pic-servlet")
public class PicServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        ServletContext servletContext = getServletContext();

        //获取资源流
        InputStream resourceAsStream = servletContext.getResourceAsStream("WEB-INF/pic2.jpg");
        int available = resourceAsStream.available();
        System.out.println(available);
        byte[] bytes = new byte[available];
        resourceAsStream.read(bytes);

        resp.setContentType("image/jpeg");
        ServletOutputStream outputStream = resp.getOutputStream();
        outputStream.write(bytes);
        outputStream.close();
    }
}

5.1 随机验证码图片

  在我们登陆的时候经常要填写验证码,而某些验证码是一张图片,Java可以动态的生成图片,并且可以通过HttpServletResponse响应给浏览器。一个简单的动态图片生成代码如下:

@WebServlet("/verification-servlet")
public class VerificationServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        //在内存中⽣成⼀张图⽚,宽为80,⾼为20,类型是RGB
        BufferedImage bufferedImage = new BufferedImage(200, 100,
                BufferedImage.TYPE_INT_RGB);
        //获取到这张图⽚
        Graphics graphics = bufferedImage.getGraphics();
        //往图⽚设置颜⾊
        graphics.setColor(Color.red);
        //画一个矩形
        graphics.drawRect(30, 10, 140 , 80);
        //字体,样式,字号。
        graphics.setFont(new Font("宋体", Font.BOLD + Font.ITALIC, 25));
        //往图⽚上写数据,先写个147258,横坐标是70,纵坐标是60,这里的数据可以通过随机数生成,这样每次访问时会获得不同的数据。
        graphics.drawString("147258", 60, 60);

        //设置图片类型响应头
        resp.setContentType("image/jpeg");
        //java提供了图⽚流给我们使⽤,这是⼀个⼯具类,将图片的流数据写入响应流中
        ImageIO.write(bufferedImage, "jpg", resp.getOutputStream());
    }
}

6 发送重定向

6.1 什么是重定向

  当你访问http://www.sun.com时,你会发现浏览器地址栏中的URL会变成https://www.oracle.com/sun/,这就是重定向了。
Java Web(6)—HttpServletResponse的介绍以及使用

6.2 重定向的特点

  1. 重定向是两次请求两次响应。
  2. 地址栏发生变化。
  3. 重定向是客户端的行为。
  4. 重定向的URL不局限于当前应用的资源,可以指向其他应用的资源以及定位到站外资源。
  5. 重定向的响应码为302,并且必须要有Location响应头。

6.3 设置重定向

  响应码为200表示响应成功,而响应码为302表示重定向。所以完成重定向的第一步就是设置响应码为302。
  因为重定向是通知浏览器再发出第二个请求,所以浏览器需要知道第二个请求的URL,所以完成重定向的第二步是设置Location头,指定第二个请求的URL地址。

@WebServlet("/redirect-Servlet")
public class RedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //让redirect-Servlet的请求重定向到http://www.baidu.com
        resp.setStatus(302);
        resp.setHeader("Location", "http://www.baidu.com");
    }
}

  上面代码的作用是:当访问RedirectServlet后,会通知浏览器重定向到百度主页。客户端浏览器解析到响应码为302后,就知道服务器让它重定向,所以它会马上获取响应头Location中的URL,然后发出第二个请求。

6.4 便捷的重定向方式

  response.sendRedirect()方法会设置响应码为302,并且设置Location响应头,是一个重定向的快捷方法。
  设置了重定向之后,后面的的代码还会继续执行,并且执行完毕之后才会真正的响应给客户端,如果有Write输出响应数据,那么没有任何作用。使用sendRedirect方法后,会将响应视为已提交,如果响应已提交,则调用sendRedirect方法将引发IllegalStateException。我们不应该在提交响应之后调用其他提交响应或者不能在提交响应之后调用的方法,比如sendError、sendRedirect、setTrailerFields。

@WebServlet("/redirect-Servlet")
public class RedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //让redirect-Servlet的请求重定向到http://www.baidu.com
        //resp.setStatus(302);
        //resp.setHeader("Location", "http://www.baidu.com");


        //便捷重定向
        resp.sendRedirect("//www.baidu.com");

        //响应提交之后不能调用其他提交响应的方法
        //resp.sendRedirect("//www.baidu.com");

        //之后的代码会执行,并且执行完毕之后才会响应给客户端
        System.out.println(1111111);
        LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(3));
        System.out.println(2222222);
    }
}

  上面的案例,在请求3秒之后才会重定向到百度的首页。
  重定向的另一个方式就是通过response.setHeader(“Refresh”,“5;URL=http://www.baidu.com”)方法设置Refresh响应头,在指定时间(秒)后自动跳转到对应的页面。

6.5 重定向的URL路径

  重定向是服务器通知浏览器去访问另一个地址,即再发出另一个请求,因此重定向是客户端行为,使用的URL路径也是客户端路径。实际上超链接、表单提交、ajax、重定向的路径都是客户端路径。
  客户端路径可以分为相对路径和绝对路径,相对路径又可以分为加不加“/”的情况.

  1. 绝对路径: 通常的格式为请求协议://域名(IP):端口(可无)/资源路径,可以不带请求协议,默认是http协议,但是在开头必须要带上“//”。比如“http://www.baidu.com”,或者“//www.baidu.com”,或者“//localhost:8080/servlet-01/redirect-Servlet2”。
  2. 以“/”开头的相对路径: 相对于当前虚拟主机的路径,URL格式为“/Web应用目录/资源路径”。比如当前主机路径为http://localhost:8080,URL为“/B/c.html”,那么实际上重定向的URL绝对路径地址为:http://localhost:8080/B/c.htm
  3. 不以“/”开头的相对路径: 当对于当前路径,即相对于当前资源的路径,URL格式为“资源路径”。比如当前资源路径为http://localhost:8080/A/abc,URL为“b.html”,那么实际上重定向的URL绝对路径地址为:http://localhost:8080/A/b.html

  比如,我们的原始URL为http://localhost:8080/servlet-01/redirect-Servlet

  1. 如果我们要重定向到当前Web应用内部的/redirect-Servlet2资源,那么我们可以设置为resp.sendRedirect("redirect-Servlet2");
    1. 如果要重定向的资源路径比当前资源目录路径更短,或者这两个路径的上级目录不一致,比如当前资源路径为http://localhost:8080/servlet-01/11111/redirect-Servlet,要重定向的资源路径为http://localhost:8080/servlet-01/redirect-Servlet2,那么我们可以设置为resp.sendRedirect("../redirect-Servlet2");,即通过“../”定位到上一级资源目录。
  2. 如果我们要重定向到当前同一个虚拟主机下的另一个Web应用http://localhost:8080/servlet-02/hello-Servlet资源,那么我们可以设置为resp.sendRedirect("/servlet-02/hello-Servlet ");
  3. 如果我们要重定向到不同的服务器或者虚拟主机或者端口号下的另一个Web应用http://localhost:8081/servlet-03/hello-Servlet资源,那么我们可以设置为resp.sendRedirect("http://localhost:8081/servlet-03/ hello-Servlet"),或者resp.sendRedirect("//localhost:8081/servlet-03/ hello-Servlet")

如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!

上一篇:使用过滤器解决全栈乱码问题


下一篇:HttpServletResponse类的介绍和使用+解决响应传递给客户端数据的中文乱码问题