三、Java Web中出现的一些乱码问题总结(详解)

一、response.getWriter().write()和 response.getWriter().print()的区别

response.getWriter()返回的是PrintWriter,这是一个打印输出流

response.getWriter().write()和 response.getWriter().print()是响应给客户端的东西,如果不用ajax接收将数据放在合适的位置,就会在浏览器上生成一个新的页面来显示内容。

  1. print
    response.getWriter().print(),不仅可以打印输出文本格式的(包括html标签),还可以将一个对象以默认的编码方式转换为二进制字节输出

  2. writer
    response.getWriter().writer(),只能打印输出文本格式的(包括html标签),不可以打印对象

二、常见乱码问题分析

1、中文变成看不懂的字符

如果一串中文字符变成了一串看不懂的字符如:“Ì Ô £ ¡Î Ò Ï²»¶ £ ¡”,这种情况通常是编码

字符集与解码时所用的字符集不一致所造成的。比如使用GBK编码,如果使用ISO-8859-1解码

的话结果就是这样。

2、一个汉字变成了一个问号

如果编码和解码的字符集都是一致的,那么可以确定该字符编码不支持中文,例如:ISO-8859-1

3、一个汉字变成了两个问号

中文经过多次编码且其中有一次编码或者解码使用了不支持中文的字符集

三、乱码相关知识点:

1.UTF-8国际编码,GBK中文编码。GBK包含GB2312,即如果通过GB2312编码后可以通过GBK解码,反之可能不成立;

2、web tomcat:默认是ISO8859-1,不支持中文的

3.java.nio.charset.Charset.defaultCharset() 获得平台默认字符编码;

4.getBytes() 是通过平台默认字符集进行编码;

5.码表:是一种规则,用来让我们看得懂的语言转换为电脑能够认识的语言的一种规则,有很多中码表,IS0-8859-1,GBK,UTF-8,UTF-16等一系列码表,比如GBK,UTF-8,UTF-16都可以标识一个汉字,而如果要标识英文,就可以用IS0-8859-1等别的码表。

6.编码:将我们看得懂的语言转换为电脑能够认识的语言。这个过程就是编码的作用

7.解码:将电脑认识的语言转换为我们能看得懂得语言。这个过程就是解码的作用

浏览器使用的是UTF-8码表,通过http协议传输,http协议只支持IS0-8859-1,到了服务器,默认也是使用的是IS0-8859-1的码表,看图
在这里插入图片描述
也就是三个过程,经历了两次编码,所以就需要进行两次解码,

1、浏览器将"小明"使用UTF-8码表进行编码(因为小明这个是汉字,所以使用能标识中文的码表,这也是我们可以在浏览器上可以手动设置的,如果使用了不能标识中文的码表,那么就将会出现乱码,因为码表中找不到中文对应的计算机符号,就可能会用??等其他符号表示),编码后得到的为 1234 ,将其通过http协议传输。

2、在http协议传输,只能用ISO-8859-1码表中所代表的符号,所以会将我们原先的1234再次进行一次编码,这次使用的是ISO-8859-1,得到的为 ??? ,然后传输到服务器

3、服务器获取到该数据是使用UTF-8编码的,而tomcat服务器默认使用ISO-8859-1解码,由于编码和解码所使用的字符集不一致,所以会出现乱码问题。

解决方案: 如果我们在客户端使用UTF-8编码的JSP页面发出请求,浏览器编码后的UTF-8字节会以ISO-8859-1的形式传递到服务器端。所以要得到经HTTP协议传输的原始字节,我们需要先调用getBytes(“ISO-8859-1”)得到原始的字节,但由于我们客户端的原始编码是UTF-8,如果继续按照ISO-8859-1解码,那么得到的将不是一个中文字符,而是3个乱码的字符。所以我们需要再次调用new String(bytes,“UTF-8”),将字节数组按照UTF-8的格式,每3个一组进行解码,才能还原为客户端的原始字符。
???.getBytes(“ISO-8859-1”);//第一次解码,转换为电脑能够识别的语言,
new String(1234,“UTF-8”);//第二次解码,转换为我们认识的语言
在这里插入图片描述
在这里插入图片描述

四、Servlet相关的几种乱码

1、 浏览器调用jsp,html等页面中文显示乱码
解决这类乱码需要满足两个要求:

1)文件本身是以utf-8编辑保存的(myEclipse中在properties中鼠标右键选择utf-8)

2)浏览器用utf-8解析:

(手动)==> 在浏览器中右键选择编码格式为utf-8

(智能)==> 在文件中写入如: 通过标签模拟response头,起到告诉浏览器用utf-8的编码解析

(智能)==> response.setContentType(“text/html;charset=UTF-8”);起到告诉浏览器用utf-8的编码解析

常用:

<meta name="content-type" content="text/html; charset=UTF-8">或<meta charset="utf-8">
<%@ pageEncoding="utf-8"%>
<?xml encoding="UTF-8"?>

2、通过浏览器调用servlet,页面显示乱码。
Servlet乱码分为request乱码和response乱码:

(1)response响应回浏览器出现的中文乱码:

首先介绍一下,response对象是如何向浏览器发送数据的。两种方法,一种getOutputStream,一种getWriter。
1)ServletOutputStream getOutputStream();  //获取输出字节流。提供write() 和 print() 两个输出方法

2)PrintWriter getWriter();  //获取输出字符流  提供write() 和 print()两个输出方法

print()方法底层都是使用write()方法的,相当于print()方法就是将write()方法进行了封装,使开发者更方便快捷的使用,想输出什么,就直接选择合适的print()方法,而不用考虑如何转换字节。
 1、ServeltOutputStream getOutputStream();不能直接输出中文,直接输出中文会报异常
 在这里插入图片描述
解决:
resp.getoutputStream().write(“哈哈哈,我要输出到浏览器”.getBytes(“UTF-8”));
要输出的汉字先用UTF-8进行编码,而不用让tomcat来进行编码,这样如果浏览器用的是UTF-8码表进行解码的话,那么就会正确输出,如果浏览器用的不是UTF-8,那么还是会出现乱码,所以说这个关键要看浏览器用的什么码表,这个就不太好,这里还要注意一点,就是使用的是write(byte)方法,因为print()方法没有输出byte类型的方法

注意:response.setContentType 等效于 response.setCharacterEncoding + response.setHeader

解决方法:

方法一:response.setContentType(“text/html;charset=uft-8”);

使用Servlet API 来通知tomcaat和强制浏览器使用UTF-8来进行编码解码,这个的底层代码就是 response.setCharacterEncoding + response.setHeader的代码,进行了简单的封装而已。

/*通过设置响应头,来设置浏览器也使用UTF-8字符集 目的是为了控制浏览器的行为,即控制浏览器用UTF-8进行解码response.setContentType 等效于 response.setCharacterEncoding + response.setHeader因为在setContentType方法中已经调用了setCharacterEncoding方法设置了Response容器的编码了。注意:1.response.setContentType它会通是设置服务器和客户端都使用UTF-8字符集,2.还设置了响应头3.调用response.setCharacterEncoding 和  response.setContentType方法,必须在getWriter执行之前或者response被提交之前,否则依旧会出现乱码问题*/response.setContentType("text/html;charset=UTF-8");

方法二:使用Servlet API response.setCharacterEncoding(“UTF-8”);

让tomcat将我们要响应到浏览器的中文用UTF-8进行编码,而不使用默认的ISO-8859-1了,这个还是要取决于浏览器是不是用的UTF-8的码表,跟上面的一样有缺陷,
所以需要配合response.setHeader(“Content-Type”,“text/html;charset=UTF-8”);来使用,作用为手动设置响应内容,通知tomcat和浏览器使用utf-8来进行编码和解码。

/*response.setCharacterEncoding("UTF-8"):设置服务器的响应对象所采用的字符编码类型为UTF-8,即设置服务器字符集为UTF-8目的是用于解决response.getWriter()输出的字符流的乱码问题。*/response.setCharacterEncoding("UTF-8");response.setHeader("Content-Type","text/html;charset=UTF-8");

(setHeader是HttpServletResponse的方法。如果想在拦截器Filter中设置字符编码,则无此方法,因为Filter的doFilter方法的参数类型是ServletResponse)

这里有几个小细节需要注意:

  1. response.setCharacterEncoding(“UTF-8”);需要写在PrintWriter out = response.getWriter();的前面。拿到字符流后再设置编码是没有用的。

  2. response.setContentType(“text/html;charset=UTF-8”);这句代码其实有两个作用:通知response以UTF-8输出和浏览器以UTF-8打开。即等价于response.setHeader(“content-type”, “text/html;charset=UTF-8”);和response.setCharacterEncoding(“UTF-8”);两句代码。

  3. response.setContentType(“text/html;charset=UTF-8”); 目的是为了控制浏览器的行为,即控制浏览器用UTF-8进行解码;

  4. response.setCharacterEncoding(“UTF-8”);目的是用于response.getWriter()输出的字符流的乱码问题。如果是response.getOutputStream()是不需要此种解决方案的,因为这句话的意思是为了将response对象中的数据以UTF-8解码后的字节流发向浏览器;

(2)request乱码问题

request请求分为post和get,对于不同的请求方式有不同的解决乱码的方案

第一种:POST请求

post请求方式的参数是在请求体中,相对于get请求简单很多,没有经过http协议这一步的编码过程,所以只需要在服务器端,设置服务器解码的码表跟浏览器编码的码表是一样的就行了,在这里浏览器使用的是UTF-8码表编码,那么服务器端就设置解码所用码表也为UTF-8就OK了
解决方案:
request.setCharacterEncoding(“UTF-8”);//命令Tomcat使用UTF-8码表解码,而不用默认的ISO-8859-1了。
所以在很多时候,在doPost方法的第一句,就是这句代码,防止获取请求参数时乱码。
注意:该设置只对post请求有效

第二种:GET请求(URI方式传递参数乱码),TOMCAT 8.0 以上用 GET 方式请求已经不存在乱码问题

get请求的参数是在url后面提交过来的,也就是在请求行中
在这里插入图片描述
 FormServlet是一个普通的Servlet,浏览器访问它时,使用get请求方式提交了一个name=小明的参数值,在doGet中获取该参数值,并且打印到控制台,发现出现乱码

法一:要解决这个问题,修改tomcat服务器的配置文件。
[注意] TOMCAT 8.0 以上用 GET 方式请求,传送的参数已默认为 UTF-8 编码,所以可以不需要修改配置文件

修改tomcat目录下的conf/server.xml文件的第69行:

修改前内容:

<Connector port="8080" protocol="HTTP/1.1"maxThreads="150"   connectionTimeout="200000"redirecPort="8443"/>修改后内容:<Connector port="8080" protocol="HTTP/1.1"maxThreads="150"   connectionTimeout="200000"redirecPort="8443"    URIEncoding="utf-8"/>

在这里插入图片描述

在这里插入图片描述

法二:
String username= request.getParameter(“name”);
String usernameString = new String(username.getBytes(“ISO-8859-1”),“UTF-8”);

tomcat默认全部都是用ISO-8859-1编码,不管你页面用什么显示,Tomcat最终还是会替你将所有字符转做ISO-8859-1.那么,当在另目标页面再用GBK翻译时就会将本来错的编码翻译成GBK的编码,这时的文字会乱码.
1.xxx.getBytes( )叫做编码,new String(byte[ ],encodingname)这个叫解码
2.http协议不会对请求参数进行编解码!只是传输,传输的是二进制。解码是tomcat的工作,utf8编码的字节序列被tomcat默认以iso8895-1方式解码所以有了乱码,所以要重新编码再解码。

a. 所以需要先将得到"字符"(不管是什么)都先用字节数组表示,
b. 且使用ISO-8859-1进行翻译,得到一个在ISO-8859-1编码环境下的字节数组.例如:AB表示成[64,65].
c. 然后再用GBK编码这个数组,并翻译成一个字符串.

那么我们可以得到一个编码转换的过程
假设:GBK码(“你”)->URLencode后变成->(%3F%2F)->Tomcat自动替你转一次ISO-8859-1->得到( 23 43 68 23 42 68 每一个符号表示为ISO-8859-1中的一个编码)->接收页面—>再转一次为ISO-8859-1的Byte数组[23,43,68,23,42,68]—>用GBK再转为可读的文字—>(%3F%2F"---->转为(“你”)

法三:URL转换
String username= request.getParameter(“name”);
String usernameString = new String(username.getBytes(“ISO-8859-1”),“gb2312”);

**
因为浏览器默认编码为gb2312

小结请求参数乱码问题:

get请求和post请求方式的中文乱码问题处理方式不同

1)get:请求参数在请求行中,涉及了http协议,手动解决乱码问题,知道出现乱码的根本原因,对症下药,其原理就是进行两次编码,两次解码的过程
new String(xxx.getBytes(“ISO-8859-1”),“UTF-8”);

2)post:请求参数在请求体中,使用servlet API解决乱码问题,其原理就是一次编码一次解码,命令tomcat使用特定的码表解码。
request.setCharaterEncoding(“UTF-8”);

五、总结

1)如果是post请求,加上这两句基本上可以解决所有的乱码问题

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

2)如果是get请求,TOMCAT 8.0 以上用 GET 方式请求,传送的参数已默认为 UTF-8 编码,所以不会出现get请求乱码问题,可以不需要修改配置文件

a. 修改tomcat服务器的配置文件后 再加上 response.setContentType(“text/html;charset=UTF-8”);

b. 不想修改配置文件的话,可以使用下面的方式:

response.setContentType("text/html;charset=UTF-8");
String username= request.getParameter("name");
String usernameString = new String(username.getBytes("ISO-8859-1"),"UTF-8");

请求乱码

1)get请求:

经过了两次编码,所以就要两次解码

第一次解码:xxx.getBytes(“ISO-8859-1”);得到yyy

第二次解码:new String(yyy,“utf-8”);

连续写:new String(xxx.getBytes(“ISO-8859-1”),“UTF-8”);

2)post请求:

只经过一次编码,所以也就只要一次解码,使用Servlet API request.setCharacterEncoding();

request.setCharacterEncoding("UTF-8");  
//不一定解决,取决于浏览器是用什么码表来编码,浏览器用UTF-8,那么这里就写UTF-8。

响应乱码

1)getOutputStream();
使用该字节输出流,不能直接输出中文,会出异常,要想输出中文,解决方法如下

解决:getOutputStream().write(xxx.getBytes(“UTF-8”));//手动将中文用UTF-8码表编码,变成字节传输,变成字节后,就不会报异常,并且tomcat也不会在编码,因为已经编码过了,所以到浏览器后,如果浏览器使用的是UTF-8码表解码,那么就不会出现中文乱码,反之则出现中文乱码,所以这个方法,不能完全保证中文不乱码

2)getWrite();
使用字符输出流,能直接输出中文,不会出异常,但是会出现乱码。能用三种方法解决,一直使用第二种方法

解决:通知tomcat和浏览器使用同一张码表。

response.setContentType(“text/html;charset=utf-8”);  //通知浏览器使用UTF-8解码 同时通知tomcat和浏览器使用UTF-8编码和解码。

这个方法的底层原理是这句话:response.setHeader(“contentType”,“text/html;charset=utf-8”);

注意:getOutputStream()和getWrite() 这两个方法不能够同时使用,一次只能使用一个,否则报异常

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 2325. 解密消息(map)

文章目录1. 题目2. 解题1. 题目 给你字符串 key 和 message &#xff0c;分别表示一个加密密钥和一段加密消息。 解密 message 的步骤如下&#xff1a; 使用 key 中 26 个英文小写字母第一次出现的顺序作为替换表中的字母 顺序 。将替换表与普通英文字母表对齐&#xff0c;形…

结对项目——最大子数组

求数组中最大子数组的和 一、程序要求 1、返回一个整数数组中最大子数组的和&#xff1b; 2、输入一个整数数组&#xff0c;数组中有正数也有负数&#xff1b; 3、数组中连续的一个或多个整数组成一个子数组&#xff0c;每个子数组都有一个和&#xff1b; 4、求所有子数组的和的…

python的GUI编程和tkinter学习笔记——第一个GUI程序

一、第一个GUI程序 from tkinter import * from tkinter import messagebox# 创建窗口 root Tk()btn01 Button(root) btn01["text"] "点我就送花"btn01.pack()def songhua(e): # e就是事件对象messagebox.showinfo("Message","送你一朵…

LeetCode 2331. 计算布尔二叉树的值(树的遍历)

文章目录1. 题目2. 解题1. 题目 给你一棵 完整二叉树 的根&#xff0c;这棵树有以下特征&#xff1a; 叶子节点 要么值为 0 要么值为 1 &#xff0c;其中 0 表示 False &#xff0c;1 表示 True 。非叶子节点 要么值为 2 要么值为 3 &#xff0c;其中 2 表示逻辑或 OR &#…

linux内核启动以及文件系统的加载过程

Linux 内核启动及文件系统加载过程 当u-boot 开始执行 bootcmd 命令&#xff0c;就进入 Linux 内核启动阶段。普通 Linux 内核的启动过程也可以分为两个阶段。本文以项目中使用的 linux-2.6.37 版源码为例分三个阶段来描述内核启动全过程。第一阶段为内核自解压过程&#xff0c…

LeetCode 2335. 装满杯子需要的最短总时长

文章目录1. 题目2. 解题1. 题目 现有一台饮水机&#xff0c;可以制备冷水、温水和热水。每秒钟&#xff0c;可以装满 2 杯 不同 类型的水或者 1 杯任意类型的水。 给你一个下标从 0 开始、长度为 3 的整数数组 amount &#xff0c;其中 amount[0]、amount[1] 和 amount[2] 分…

Linux实操篇——实用指令学习笔记(详解)

9.3帮助指令 9.3.1介绍 当我们对某个指令不熟悉时&#xff0c;我们可以使用Linux提供的帮助指令来了解这个指令的使用方法。 9.3.2man 获得帮助信息 基本语法 man[命令或配置文件]&#xff08;功能描述&#xff1a;获得帮助信息&#xff09;应用实例 案例&#xff1a;查看1…

LeetCode 2249. 统计圆内格点数目

文章目录1. 题目2. 解题1. 题目 给你一个二维整数数组 circles &#xff0c;其中 circles[i] [xi, yi, ri] 表示网格上圆心为 (xi, yi) 且半径为 ri 的第 i 个圆&#xff0c;返回出现在 至少一个 圆内的 格点数目 。 注意&#xff1a; 格点 是指整数坐标对应的点。 圆周上的…

Python实现自动发送邮件(详解)

Python实现自动发送邮件 1.开启SMTP服务 为了实现自动发送邮件的目的&#xff0c;我们需要在邮箱中开启SMTP服务&#xff1a; 这点很关键&#xff0c;别忘了去开启SMTP&#xff0c; 别忘了去开启SMTP&#xff0c;否则邮件是无法发送成功的 。然后你还需要点击下面生成授权…

React 组件:计时器例子

文章目录1. 将应用程序分解为组件2. 构建应用静态版本3. 哪些组件是有状态的4. 每个 state 应该在哪个组件里5. 硬编码初始化state6. 添加反向数据流7. 添加服务器通信learn from 《React全家桶&#xff1a;前端开发与实例详解》https://zh-hans.reactjs.org/tutorial/tutorial…

一、快速开始一个 MyBatis项目(详解)

1.0 概述 1.三层架构 界面层&#xff1a; 和用户打交道的&#xff0c; 接收用户的请求参数&#xff0c; 显示处理结果的。&#xff08;jsp &#xff0c;html &#xff0c;servlet&#xff09; 业务逻辑层&#xff1a; 接收了界面层传递的数据&#xff0c;计算逻辑&#xff0c;…

2013 ACM区域赛长沙 K Pocket Cube hdu 4801

题意:给了一个2*2的魔方..每步操作可以将任意一面翻转90度..现在问在N(<7)步内.最多能翻出几面相同的. 直接打表模拟每种翻转情况 1 #include<cstdio>2 #include<cstring>3 #include<algorithm>4 #include<iostream>5 using namespace std;6 7 int …

React 组件和服务器

文章目录1. 请求服务器数据2. 发送开始停止请求3. 发送创建、删除、更新请求learn from 《React全家桶&#xff1a;前端开发与实例详解》https://zh-hans.reactjs.org/tutorial/tutorial.htmlhttps://zh-hans.reactjs.org/docs/create-a-new-react-app.html#create-react-app服…

二、MyBatis常用对象分析 封装工具类

1.0 MyBatis 对象分析 &#xff08;1&#xff09; Resources 类 Resources 类&#xff0c;顾名思义就是资源&#xff0c;用于读取资源文件。其有很多方法通过加载并解析资源文件&#xff0c;返回不同类型的 IO 流对象。 &#xff08;2&#xff09; SqlSessionFactoryBuilder…

iOS图片拉伸技巧

纵观移动市场&#xff0c;一款移动app&#xff0c;要想长期在移动市场立足&#xff0c;最起码要包含以下几个要素&#xff1a;实用的功能、极强的用户体验、华丽简洁的外观。华丽外观的背后&#xff0c;少不了美工的辛苦设计&#xff0c;但如果开发人员不懂得怎么合理展示这些设…

LeetCode 2341. 数组能形成多少数对

文章目录1. 题目2. 解题1. 题目 给你一个下标从 0 开始的整数数组 nums 。在一步操作中&#xff0c;你可以执行以下步骤&#xff1a; 从 nums 选出 两个 相等的 整数从 nums 中移除这两个整数&#xff0c;形成一个 数对 请你在 nums 上多次执行此操作直到无法继续执行。 返…

三、MyBatis 使用传统 Dao 开发方式

1.0 使用 Dao 的实现类,操作数据库 1.0.1 Dao 开发 &#xff08;0&#xff09;定义接口StudentDao 及创建接口的映射文件StudentDao .xm package com.zep.dao;import com.zep.domain.Student;import java.util.List;public interface StudentDao {List<Student> selec…

LeetCode 2347. 最好的扑克手牌

文章目录1. 题目2. 解题1. 题目 给你一个整数数组 ranks 和一个字符数组 suit 。你有 5 张扑克牌&#xff0c;第 i 张牌大小为 ranks[i] &#xff0c;花色为 suits[i] 。 下述是从好到坏你可能持有的 手牌类型 &#xff1a; "Flush"&#xff1a;同花&#xff0c;五…

四、MyBatis 框架 Dao 动态代理

1.1 步骤 &#xff08;1&#xff09; 去掉 之前编写的Dao 接口实现类 &#xff08;2&#xff09; getMapper 获取代理对象 只需调用 SqlSession 的 getMapper()方法&#xff0c;即可获取指定接口的实现类对象。该方法的参数为指定 Dao接口类的 class 值。 不使用工具类&…

五、深入理解Mybatis中的参数parameterType (传递一个简单参数,传递多个参数:@Param、使用自定义对象、按位置、使用Map)

1.1 parameterType parameterType: 接口中方法参数的类型&#xff0c; 类型的完全限定名或别名。这个属性是可选的&#xff0c;因为 MyBatis可以推断出具体传入语句的参数&#xff0c;默认值为未设置&#xff08;unset&#xff09;。接口中方法的参数从 java 代码传入到mapper…