当前位置: 首页 > news >正文

04、HttpServletResponse

一、HttpServletResponse

1.1、HttpServletResponse介绍

Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象、和代表响应的response对象。

  • request:客户端请求过来的数据。
  • response:服务端发送数据给客户端。

HttpServletResponse接口代表服务器的响应。这个对象中封装了向客户端发送数据、发送响应头,发送响应状态码的方法。

1、负责向客户端发送数据的相关方法

42a772e6-e12d-40b5-8946-4350de5cbebe

2、负责向客户端发送响应头和设置状态

4d0db19b-174e-478d-ba99-87ee02ac87d2

除此之外,其中还定义一系列响应状态码常量:SC_NOT_FOUND(404)、SC_OK(200)、SC_INTERNAL_SERVER_ERROR(500)。

1.2、HttpServletResponse常用操作

1、使用OutputStream向客户端输出中文

public class ResponseDemo1 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String data = "中国";
        response.getOutputStream().write(data.getBytes("UTF-8"));
        // 指定客户端(浏览器)以UTF-8编码打开
        response.setHeader("content-type", "text/html;charset=UTF-8");      
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

460ab33b-70c3-4b3b-a6cb-1faf7e459209

2、使用PrintWriter向客户端输出中文

public class ResponseDemo1 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String data = "中国";
        response.setCharacterEncoding("UTF-8");
        // 获取打印流必须在response.setCharacterEncoding("UTF-8");之后
        PrintWriter out = response.getWriter();
        response.setHeader("content-type", "text/html;charset=UTF-8");
        
        // 还可以使用这种方式
        out.write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'/>");
        out.write(data);
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

注意:当需要向浏览器输出字符数据时,使用PrintWriter比较方便,省去了将字符转换成字节数组那一步。

3、使用PrintWriter向客户端输出数字

如果想让服务端输出什么,客户端就显示什么,需要保住传输的都是字符串。

public class ResponseDemo1 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
         response.setHeader("content-type", "text/html;charset=UTF-8");
         ServletOutputStream outputStream = response.getOutputStream();
         outputStream.write("使用OutputStream流输出数字1:".getBytes("UTF-8"));
         //outputStream.write(1); // 无法显示,因为只能输出字符串
         outputStream.write((1+ "").getBytes());
         
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

使用PrintWriter打印数字也和OutputStream一样,需要转换成字符串输出。

4、文件下载

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

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

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

2.获取要下载的文件名

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

4.获取要下载的文件输入流

5.创建数据缓冲区

6.通过response对象获取OutputStream流

7.将FileInputStream流写入到buffer缓冲区

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

public class ResponseDemo2 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        downloadFileByOutpustStream(response);
        
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
    
    private void downloadFileByOutpustStream(HttpServletResponse response) throws IOException {
        // 1.获取要下载的文件的绝对路径
        String realPath = this.getServletContext().getRealPath("/download/我的妹子.png");
        // 2.获取要下载的文件名
        String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
        // 3.设置content-disposition响应头控制浏览器以下载的形式打开文件
        //response.setHeader("content-disposition", "attachment;filename=" + fileName);
        // 3.如果是中文文件名,则需要通过URLEncoder设置UTF-8编码
        response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8"));
        // 4.获取要下载的文件输入流
        InputStream in = new FileInputStream(realPath);
        int len = 0;
        byte[] buf = new byte[1024];
        OutputStream out = response.getOutputStream();
        while((len = in.read(buf)) > 0){
            out.write(buf, 0, len);
        }
        in.close();
    }
}

注意:在编写下载文件功能时,要使用OutputStream流,避免使用PrintWriter流,因为OutputStream流是字节流,可以处理任意类型的数据,而PrintWriter流是字符流,

只能处理字符数据,如果用字符流处理字节数据,会导致数据丢失。

5、生成图片验证码

生成图片主要用到了一个BufferedImage类,

b5e4de83-7b51-47d8-bb0c-80c5e0ac3990

public class ResponseDemo3 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 设置refresh响应头控制浏览器每隔3秒钟刷新一次
        response.setHeader("refresh", "3");
        // 1.在内存中创建一张图片
        BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);
        // 得到图片
        //Graphics graphics = image.getGraphics();
        Graphics2D graphics2d = (Graphics2D) image.getGraphics();
        graphics2d.setColor(Color.WHITE);// 设置图片的背景色
        graphics2d.fillRect(0, 0, 80, 20);// 填充背景色
        // 3.向图片上写数据
        graphics2d.setColor(Color.BLUE);
        graphics2d.setFont(new Font(null, Font.BOLD, 20));
        graphics2d.drawString(makeNum(), 0, 20);
        // 4.设置响应头控制浏览器浏览器以图片的方式打开
        response.setContentType("image/jpeg");
        // 等同于response.setHeader("Content-Type", "image/jpeg");
        // 5.设置响应头控制浏览器不缓存图片数据
        response.setDateHeader("expries", -1);
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");
        // 6.将图片写给浏览器
        ImageIO.write(image, "jpg", response.getOutputStream());
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
    
    /**
     * 生成随机数字
     * */
    private String makeNum(){
        Random random = new Random();
        String num = random.nextInt(9999) + "";
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 4 - num.length(); i++) {
            sb.append("0");
        }
        num = sb.toString() + num;
        return num;
    }
}

0bd15729-37d7-4de6-98eb-4420a572df71

1.3、响应头常用操作

1、设置响应头禁止缓存当前内容

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

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

response.setHeader("refresh", "3");

3、设置响应头控制浏览器浏览器以图片的方式打开

response.setContentType("image/jpeg"); 
或
response.setHeader("Content-Type", "image/jpeg");

4、Response请求重定向

public class ResponseDemo4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        /**
         * 第一种方式实现请求重定向
         * */
        response.setHeader("Location", "/JavaResponseDemo/index.jsp");
        response.setStatus(HttpServletResponse.SC_FOUND);// 设置302状态码
        
        /**
         * 第二种方式实现请求重定向
         * 该方法内部包含:
         * response.setHeader("Location", "/JavaWeb_HttpServletResponse_Study_20140615/index.jsp");
         * response.setStatus(HttpServletResponse.SC_FOUND);//设置302状态码,等同于response.setStatus(302);
         * */
        response.sendRedirect("/JavaResponseDemo/index.jsp");
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

1.4、web工程中URL推荐写法

如果"/"是给服务器用的,则代表当前的web工程,如果"/"是给浏览器用的,则代表webapps目录。

1、"/"代表当前web工程的常见应用场景

a) ServletContext.getRealPath(String path)获取资源的绝对路径

/**
 * 1.ServletContext.getRealPath("/download/1.JPG")是用来获取服务器上的某个资源,
 * 那么这个"/"就是给服务器用的,"/"此时代表的就是web工程
 * ServletContext.getRealPath("/download/1.JPG")表示的就是读取web工程下的download文件夹中的1.JPG这个资源
 * 只要明白了"/"代表的具体含义,就可以很快写出要访问的web资源的绝对路径
 */
this.getServletContext().getRealPath("/download/1.JPG");

b) 在服务器端forward到其他页面

/**
 * forward
 * 客户端请求某个web资源,服务器跳转到另外一个web资源,这个forward也是给服务器用的,
 * 那么这个"/"就是给服务器用的,所以此时"/"代表的就是web工程
 */
this.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);

c) 使用include指令或者<jsp:include>标签引入页面

<%@include file="/jspfragments/head.jspf" %><jsp:include page="/jspfragments/demo.jsp" />

2、"/"代表webapps目录的常见应用场景

a) 使用sendRedirect实现请求重定向

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

服务器发送一个URL地址给浏览器,浏览器拿到URL再去请求服务器,所以这个"/"是给浏览器使用的,此时"/"代表的就是webapps目录。

这种写法是将项目名称写死在程序中的做法,不灵活,我们可以这样写:

response.sendRedirect(request.getContextPath() + "/index.jsp");

b) 使用超链接跳转

<a href="/JavaResponseDemo/index.jsp">跳转到首页</a>

这是客户端浏览器使用的超链接跳转,这个"/"是给浏览器使用的,此时"/"代表的就是webapps目录。

使用超链接访问web资源,绝对路径的写法推荐使用下面的写法改进:

<a href="${pageContext.request.contextPath}/index.jsp">跳转到首页</a>

c) Form表单提交

<form action="/JavaResponseDemo/servlet/CheckServlet" method="post">    
     <input type="submit" value="提交">
</form>

这是客户端浏览器将form表单提交到服务器,所以这个"/"是给浏览器使用的,此时"/"代表的就是webapps目录。

对于form表单提交中action属性绝对路径的写法,也推荐使用如下的方式改进:

<form action="${pageContext.request.contextPath}/servlet/CheckServlet" method="post">
     <input type="submit" value="提交">
</form>

d) js脚本和css样式文件的引用

<%--使用绝对路径的方式引用js脚本--%>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/index.js"></script>
<%--${pageContext.request.contextPath}与request.getContextPath()写法是得到的效果是一样的--%>
<script type="text/javascript" src="<%=request.getContextPath()%>/js/login.js"></script>
<%--使用绝对路径的方式引用css样式--%>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/index.css" type="text/css"/>

3、response细节问题

  • getOutputStream和getWriter方法分别用于得到输出二进制数据、输出文本数据的ServletOuputStream、Printwriter对象。
  • getOutputStream和getWriter这两个方法互相排斥,调用了其中的任何一个方法后,就不能再调用另一方法。

4、生成复杂图片验证码

5e9d0dfe-113a-43bc-88bc-c69c30c7140f

a) 创建一个DrawImage Servlet,用来生成验证码图片代码参看附件:DrawImageServlet.rar

b) index.jsp的代码

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>验证码</title>
  </head>  
  <body>
      <form action="#" method="post">
          <img src="${pageContext.request.contextPath}/servlet/DrawImageServlet"/>
      </form>
  </body>
</html>

运行效果如下:

879b8611-1c22-48c1-9884-4de606e109aa

转载于:https://www.cnblogs.com/pengjingya/p/5510993.html

相关文章:

  • Tomcat7.0源码分析——请求原理分析(中)
  • 小米设备怎么不ROOT激活Xposed框架的步骤
  • Mysql 复制一条数据
  • Netty源码分析(二):服务端启动
  • SNFAutoupdater通用自动升级组件V2.0
  • leetcode1018
  • 接口测试随笔
  • Promise源码解析-步步为营皆可及
  • 图像处理之USM锐化
  • 【运维趟坑回忆录 开篇】初入初创, 一脸懵
  • POJ 3384 Feng Shui
  • Android环境下hanlp汉字转拼音功能的使用介绍
  • 轻松搭建docker应用的mesos集群
  • Android Studio发布Release版本之坑--Unknown host 'd29vzk4ow07wi7.cloudfront.net'
  • Spring—Quartz定时调度CronTrigger时间配置格式说明与实例
  • __proto__ 和 prototype的关系
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • 03Go 类型总结
  • Django 博客开发教程 8 - 博客文章详情页
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • Netty 框架总结「ChannelHandler 及 EventLoop」
  • spring security oauth2 password授权模式
  • 翻译--Thinking in React
  • 前端面试之闭包
  • 在electron中实现跨域请求,无需更改服务器端设置
  • # Swust 12th acm 邀请赛# [ E ] 01 String [题解]
  • #鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行
  • (4)STL算法之比较
  • (done) NLP “bag-of-words“ 方法 (带有二元分类和多元分类两个例子)词袋模型、BoW
  • (二)linux使用docker容器运行mysql
  • (汇总)os模块以及shutil模块对文件的操作
  • (免费领源码)Python#MySQL图书馆管理系统071718-计算机毕业设计项目选题推荐
  • (亲测)设​置​m​y​e​c​l​i​p​s​e​打​开​默​认​工​作​空​间...
  • (三)docker:Dockerfile构建容器运行jar包
  • (十八)SpringBoot之发送QQ邮件
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • (原創) 物件導向與老子思想 (OO)
  • (转)h264中avc和flv数据的解析
  • .bat批处理(十):从路径字符串中截取盘符、文件名、后缀名等信息
  • .net FrameWork简介,数组,枚举
  • //解决validator验证插件多个name相同只验证第一的问题
  • /dev下添加设备节点的方法步骤(通过device_create)
  • [2023年]-hadoop面试真题(一)
  • [BUUCTF 2018]Online Tool
  • [BZOJ] 1001: [BeiJing2006]狼抓兔子
  • [BZOJ2850]巧克力王国
  • [BZOJ3211]:花神游历各国(小清新线段树)
  • [C puzzle book] types
  • [C#]winform部署PaddleOCRV3推理模型
  • [C#]winform部署yolov5-onnx模型
  • [c#基础]值类型和引用类型的Equals,==的区别
  • [C++]Leetcode17电话号码的字母组合
  • [CISCN2019 华东南赛区]Web4
  • [CSS]中子元素在父元素中居中
  • [G-CS-MR.PS02] 機巧之形2: Ruler Circle