板块一 Servlet编程:第四节 HttpServletResponse对象全解与重定向 来自【汤米尼克的JAVAEE全套教程专栏】

板块一 Servlet编程:第四节 HttpServletResponse对象全解与重定向

  • 一、什么是HttpServletResponse
  • 二、响应数据的常用方法
  • 三、响应乱码问题
      • 字符流乱码
      • 字节流乱码
  • 四、重定向:sendRedirect
      • 请求转发和重定向的区别

在上一节中,我们系统的学习了请求响应在Servlet中service()方法的第一个形参HttpServletRequest(请求)对象,这一节中我们将学习它的兄弟,service()方法的第二个形参HttpServletResponse(响应)对象

一、什么是HttpServletResponse

在我们已然熟悉的浏览器访问Servlet的过程中。Request和Response 对象分别代表请求和响应:通过Request对象获取客户端数据;通过 Response 对象向客户端输出数据:
在这里插入图片描述
service()方法中形参接收的是HttpServletResponse接口的实例化对象,它继承自ServletResponse接口,专门用来封装HTTP响应消息,由于HTTP响应消息分为状态行响应消息头消息体三部分(详见HTTP协议理论与服务器请求响应原理小节),因此在HttpServletResponse中定义了状态行、响应消息头、消息体三部分。

  • 状态行部分
    响应消息头包含了关于响应的附加信息,例如内容类型、内容长度、缓存控制等。由setStatus(int status)方法实现,该方法用于设置HTTP响应消息的状态码,并生成相应代码;默认会生成一个状态码为200的状态行;
  • 响应消息头部分
    响应消息头包含了关于响应的附加信息,例如内容类型、内容长度、缓存控制等。可以使用setHeader(String name, String value)方法设置响应消息头的字段和值,例如setHeader("Content-Type", "text/html")设置内容类型为HTML。如果要设置相同字段的多个值,可以使用addHeader(String name, String value)方法,例如addHeader("Set-Cookie", "cookie1=value1")。此外还可以使用一些特定的方法来设置常见的响应消息头,例如setContentType(String type)setContentLength(int len)
  • 消息体部分
    消息体包含了实际的响应数据。可以通过获取ServletOutputStream或PrintWriter对象来写入响应消息体。getOutputStream()方法返回一个可以写入二进制数据的ServletOutputStream对象。
    getWriter()方法返回一个可以写入字符数据的PrintWriter对象。
    可以使用这些对象的方法将数据写入响应消息体,例如print(String s)、write(byte[] b)等。

二、响应数据的常用方法

接收到客户端请求后,可以通过HttpServletResponse对象直接进行响应,响应时需要获取输出流。
有两种形式:

  • getWriter() 获取字符流(只能响应字符串)
  • getOutputStream() 获取字节流(能响应一切数据)

响应回的数据到客户端被浏览器解析
注意:两者不能同时使用

实例
在start.java导入PrintWriter类,并在service()中写入测试代码

// 获取字符输出流
PrintWriter writer = resp.getWriter();
//输出数据
writer.write("Hello");

启动服务器,在浏览器中访问得
在这里插入图片描述
在start.java中导入ServletOutputStream类,并在service()中写入测试代码

//得到字节输出流
ServletOutputStream out = resp.getOutputStream();
// 输出数据
out.write("Hi".getBytes());

启动服务器,在浏览器中访问得
在这里插入图片描述
但当两者同时使用时
start.java

package www.caijiyuan;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
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;

@WebServlet("/start")
public class start extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取字符输出流
        PrintWriter writer = resp.getWriter();
        //输出数据
        writer.write("Hello");
        
        //得到字节输出流
        ServletOutputStream out = resp.getOutputStream();
        // 输出数据
        out.write("Hi".getBytes());
    }
}

启动服务器,在浏览器中访问,只得到了第一个的打印内容
在这里插入图片描述
这是为什么呢?查看报错信息
在这里插入图片描述原来是getWriter()已经调用过response对象了,如果再响应一次response对象就已经不存在了

三、响应乱码问题

在上一节中我们使用request.setCharacterEncoding("UTF-8");解决了请求时中文乱码的问题,同样,在响应时也存在中文乱码问题。这是因为服务器响应的数据也会经过网络传输,服务器端有一种编码方式,在客户端也存在一种编码方式,当两端使用的编码方式不同时则出现乱码。

字符流乱码

对于getWriter()获取到的字符流,响应中文必定出乱码,由于服务器端在进行编码时默认会使用ISO-8859-1格式的编码,该编码方式并不支持中文。要解决该种乱码只能在服务器端告知服务器使用一种能够支持中文的编码格式,这也是我们在解决请求时中文乱码的方法

response.setCharacterEncoding("UTF-8");

此时还只完成了一半的工作
要保证数据正确显示,还需要指定客户端的解码方式

response.setHeader("content-type", "text/html; charset=UTF-8");

两端指定编码后,乱码就解决了。一句话:保证发送端接收端编码一致

实例
我们在start.java的service()中写入测试测试代码,试图打印中文

// 获取字符输出流
PrintWriter writer = resp.getWriter();
//输出数据
writer.write("汤米尼克");

启动服务器,在浏览器中访问,发现输出中文乱码
在这里插入图片描述
设置服务器和客户端的编码格式统一

// 设置服务端的编码
resp.setCharacterEncoding("UTF-8");
// 设置客户端的响应类型及编码
resp. setHeader("content-type", "text/html; charset=UTF-8");
// 获取字符输出流
PrintWriter writer = resp.getWriter();
// 输出数据
writer.write("汤米尼克");

重启浏览器,再在浏览器中访问就解决问题了
在这里插入图片描述
理解了原理,其实我们还可以同时设置客户端和服务端的编码方式

response.setContentType( "text/html; charset=UTF-8");

这一句就可以替换上面的两句

字节流乱码

对于getOutputStream()方式获取到的字节流,响应中文时,由于本身就是传输的字节,所以此时可能出现乱码,也可能正确显示。当服务器端给的字节恰好和客户端使用的编码方式一致时则文本正确显示,否则出现乱码。无论如何我们都应该准确掌握服务器和客户端使用的是那种编码格式,以确保数据正确显示。
因此,字节流乱码的解决方式与上面字符流乱码的解决方式一样,在响应发出之前同时设置服务器和客户端的编码格式统一即可

response.setContentType( "text/html; charset=UTF-8");

四、重定向:sendRedirect

重定向是一种服务器为指导的客户端行为
怎么理解这句话呢?客户端发出一个请求,被服务器接收处理后进行响应,在响应的同时,服务器会给客户端一个新的地址(下次请求的地址),当客户端接收到响应后,会立刻、马上自动根据服务器给的新地址发起第二个请求,服务器接收请求并作出响应,重定向完成。可以看出这个过程中有两个请求存在,其中两个Servlet的Request对象并不共享、不能传值,属于客户端行为。

在Servlet中重定向的语句为

response.sendRedirect("url");

实例:从start.java重定向到after.java的过程
在start.java的service()中写入重定向前的测试代码

System.out.println("这里是start");
resp.sendRedirect("after");

在after.java的service()中写入重定向到底测试代码

System.out.println("这里是after");

启动服务器,在浏览器中输入start的地址
在这里插入图片描述
回车访问后地址立即跳转到after,说明重定向的地址栏会发生改变
在这里插入图片描述
同时控制台输出了
在这里插入图片描述
那么重定向在服务器中的响应头是如何实现的?
如下图,在开发者工具中打开响应头的内容
在这里插入图片描述
会发现start文件响应行的状态码是302,这就是重定向的状态码
并且响应头键值对中Location键的值就是要重定向到的地址:after文件
这与我们在第一节 HTTP协议理论与服务器请求响应原理中学习的响应头的知识首尾呼应起来了

请求转发和重定向的区别

上一节中我们学习了Request对象的请求转发,这一节又学习了Response对象的重定向,两兄弟让人傻傻分不清,必须好好区分区分

请求转发重定向
request.getRequestDispatcher("url").forward(request, response);response.sendRedirect("url");
服务器端行为客户端行为
一次请求,Request域中数据共享两次请求,Request域中数据不共享
地址栏不发生变化地址栏发生变化
跳转只能在当前站点内跳转任意地址

在这一节中我们学习了HttpServletResponse对象,学习了字符流字节流响应方法、重定向方法。不禁思考,Servlet作为“后端”,在Web交互中最重要的作用就是传递各种数据,但目前我们学到的传值的方法还知之甚少,在下一节中我们将学习Cookie对象、HttpSession对象、ServletContext对象,它们作为不同特点的容器在Servlet上可以实现不同范围的传值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/396434.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

react封装通用Modal弹窗组件

目录 1、【src/component/modal/hoc.js】 2、【src/component/modal/componentModal.js】 3、【src/page/projectView.js】 【说明】:后台管理的项目中会经常遇到弹窗,于是封装了一个简单的公共弹窗组件 这个公共组件不适用复杂的功能,简单的…

业务型 编辑器组件的封装(复制即可使用)

使用需要安装 wangeditor npm i --save wangeditor import React from react; import E from wangeditor; import ./index.lessclass EditorElem extends React.Component {constructor(props) {super(props);this.isChange false;this.state {}}componentDidMount() {con…

并发List、Set、ConcurrentHashMap底层原理

并发List、Set、ConcurrentHashMap底层原理 ArrayList: List特点&#xff1a;元素有放入顺序&#xff0c;元素可重复 存储结构&#xff1a;底层采用数组来实现 public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Clon…

后端开发怎么学?

后端开发怎么学&#xff1f; 后端开发可以简单地理解为与前端开发相对应的开发方向。前端开发主要负责构建用户界面、维护用户体验等方面的工作&#xff0c;而后端开发则主要负责处理数据、逻辑和算法等方面的工作。后端开发旨在为前端应用程序提供支持&#xff0c;以帮助实现可…

stm32学习笔记-STLINK使用

stm32学习笔记-STLINK使用 使用ST-LINK调试程序进度表格 使用ST-LINK调试程序 说明 组成 总结 记录使用STLINK进行项目的烧写和调试&#xff0c;旨在高效的进行代码调试学习工具包括笔记本、keil5MDK、stm32f030c8t6电表主机、STLINK V2、导线、电表代码总的来说&#xff0…

vue3项目配置按需自动引入自定义组件unplugin-vue-components

我们通常在项目中&#xff0c;需要手动引入自定义的各种组件&#xff0c;如果涉及的页面功能比较多的话&#xff0c;光是import的长度都能赶上春联了。 如果&#xff0c;能有一个插件帮我们实现自动引入&#xff0c;是不是要谢天谢地了呢&#xff1f; 接下来就进入我们的主角u…

Uniapp-开发小程序

文章目录 前言一、npm run xxx —— cross-env: Permission denied解决方法&#xff08;亲测有效&#xff09;其他解决方法&#xff1a; 二、macOS 微信开发者工具选择uniapp 用 vscode 开发 总结 前言 macOS下 uniapp 开发小程序。 一、npm run xxx —— cross-env: Permissi…

数据结构:动态内存分配+内存分区+宏+结构体

一、作业 1.定义一个学生结构体&#xff0c;包含结构体成员&#xff1a;身高&#xff0c;姓名&#xff0c;成绩&#xff1b;定义一个结构体数组有7个成员&#xff0c;要求终端输入结构体成员的值&#xff0c;根据学生成绩&#xff0c;进行冒泡排序。 #include <stdio.h>…

大数据技术之 Kafka

大数据技术之 Kafka 文章目录 大数据技术之 Kafka第 1 章 Kafka 概述1.1 定义1.2 消息队列1.2.1 传统消息队列的应用场景1.2.2 消息队列的两种模式 1.3 Kafka 基础架构 第 2 章 Kafka 快速入门2.1 安装部署2.1.1 集群规划2.1.2 集群部署2.1.3 集群启停脚本 2.2 Kafka 命令行操作…

【Go语言】Go语言中的变量和常量

Go语言中的变量和常量 1 变量 变量相当于是对一块数据存储空间的命名&#xff0c;程序可以通过定义一个变量来申请一块数据存储空间&#xff0c;之后可以通过引用变量名来使用这块存储空间。 Go 语言是强类型静态语言&#xff0c;所以变量的声明与赋值方式与 PHP/Python 等动…

基于java的眼镜店仓库管理系统

源码获取&#xff0c;加V&#xff1a;qq2056908377 摘要&#xff1a; 随着电子商务的兴起&#xff0c;越来越多的商家选择在线销售他们的产品。眼镜店作为零售业的一种&#xff0c;也不例外。随着市场需求的不断增加&#xff0c;眼镜店需要更加高效的管理他们的仓库和库存&…

代码随想录算法训练营DAY20 | 二叉树 (8)

一、LeetCode 701 二叉搜索树中的插入操作 题目链接&#xff1a; 701.二叉搜索树中的插入操作https://leetcode.cn/problems/insert-into-a-binary-search-tree/description/ 思路&#xff1a;见缝插针罢辽。 class Solution {public TreeNode insertIntoBST(TreeNode root, i…

Spring基础-IOC理解及自己创建类+第三方提供的类注入的方法

Spring全称为Spring Framework,是一款主流的JAVA EE 开原框架,主要功能有:IOC(控制反转,层间解耦)、AOP&#xff08;面向切面编程&#xff0c;公共代码抽取&#xff09;、MVC&#xff08;开发web应用程序&#xff09;、数据库事务管理、web单元测试&#xff08;与测试框架集成&…

【深入理解设计模式】单例设计模式

单例设计模式 概念&#xff1a; 单例模式&#xff08;Singleton Pattern&#xff09;是 Java 中最简单的设计模式之一。 单例设计模式是一种创建型设计模式&#xff0c;其主要目的是确保类在应用程序中的一个实例只有一个。这意味着无论在应用程序的哪个位置请求该类的实例&a…

自定义异常处理演示

​ 为了防止黑客从前台异常信息&#xff0c;对系统进行攻击。同时&#xff0c;为了提高用户体验&#xff0c;我们都会都抛出的异常进行拦截处理。 一、全局异常处理 编写一个异常拦截类&#xff0c;如下&#xff1a;ControllerAdvice&#xff0c;很多初学者可能都没有听说过…

商品图放大镜效果实现

业务拆解 鼠标经过商品小图&#xff0c;展示块会显示对应商品图片鼠标经过展示块&#xff0c;右侧会显示放大镜效果的大图大图可跟随鼠标移动而显示对应的部分 关键JS代码 // 1. 获取三个盒子// 2. 小盒子 图片切换效果const small document.querySelector(.small)// 中盒子…

极狐GitLab 如何配置多个 LDAP?

本文仅适用于极狐GitLab私有化部署场景。 场景化痛点 极狐GitLab 的多 LDAP 接入功能解决了企业在以下场景中可能遇到的痛点&#xff1a; 多个组织/部门的整合&#xff1a;在大型企业或跨国公司中&#xff0c;往往存在多个组织或部门&#xff0c;它们可能拥有独立的 LDAP 服务…

las数据转pcd数据

las数据转pcd数据 一、算法原理1.介绍las2.主要函数 二、代码三、结果展示3.1 las数据3.2 las转换为pcd 四、相关数据链接 一、算法原理 1.介绍las LAS文件按每条扫描线排列方式存放数据,包括激光点的三维坐标、多次回波信息、强度信息、扫描角度、分类信息、飞行航带信息、飞…

LeetCode算法实践——前缀和从入门到入土

前缀和算法 对于一个数组a&#xff0c;和为s数组&#xff1b;其每一个下标的前缀和为s[0]0,s[i]s[i-1]a[i]。 从上面可以推导出left到right之间的前缀和为是s[right1]-s[left]。 例如a[3,2,1,2]&#xff0c;对应的前缀和数组为s[0,3,5,6,8]。a的子数组[2,1,2]的和就可以用s[…

ubuntu22.04@laptop OpenCV Get Started: 015_deep_learning_with_opencv_dnn_module

ubuntu22.04laptop OpenCV Get Started: 015_deep_learning_with_opencv_dnn_module 1. 源由2. 应用Demo2.1 C应用Demo2.2 Python应用Demo 3. 使用 OpenCV DNN 模块进行图像分类3.1 导入模块并加载类名文本文件3.2 从磁盘加载预训练 DenseNet121 模型3.3 读取图像并准备为模型输…