前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Springboot升级后@RequestBody封装出现乱码问题的解决

Springboot升级后@RequestBody封装出现乱码问题的解决

作者头像
马拉松程序员
发布于 2022-04-26 10:48:12
发布于 2022-04-26 10:48:12
2.8K01
代码可运行
举报
运行总次数:1
代码可运行

今天工作上遇到了一个比较奇葩的问题,这个问题有多方面的尴尬的原因产生。经过了一天的胡乱猜想,终于在公司大佬的指导下解决这个问题。由于公司的安全保密要求,不能直接用公司代码演示,我在自己的电脑上,把之前写的一个demo改造了一下,复现这个问题。废话少说,直接上代码。

问题产生:

用户突然发现系统(A),某个功能的列表中的数据中文有乱码了,之前还是好好的。然后把问题提交到开发这里,核查了一下发现,用户看到的数据是B系统推送进来的,这个功能开发后一直没动过,怎么突然不行了呢。

问题分析:

代码没有动过,但是由于近期产品方升级了一次springboot,所以问题可能产生在这里。乱码问题都是字符编码不统一造成的。A系统都是统一默认的UTF8编码,那问题出在B系统推送来的数据上。

然后让B系统的同事检查了下发送的数据,他们说用的数据编码正常,不过请求是用的GBK编码。

What?编码不一样确实会乱码,可是为什么乱码在这个时候出现。那既然这样,我们把request的请求的编码手动设置成UTF8的应该可以了。下面呢,我将分3个阶段,用代码演示一下效果。

刚开始没有问题阶段

demo是用springboot构建的,我忘了没升级前是多少版本了,就找一个比较早的1.5.5.RELEASE做为例子,编码为UTF8。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.5.RELEASE</version>
    <relativePath/> 
</parent>

代码示例1:

演示HelloController.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Controller
@RequestMapping("/hello")
public class HelloController {
    @PostMapping("/test")
    @ResponseBody
    public UserDO getUser(@RequestBody UserDO user) {
        System.out.println(user.getUserId());
        System.out.println(user.getUserName());
        return user;
    }
}

UserDO.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Data
public class UserDO {
    private Integer userId;
    private String userName;
}

POSTMAN 工具模拟请求

B系统的同事说请求使用的GBK发的,那就模拟当时的场景

在此请求头上加上gbk的编码,现在我们看结果是正常返回的。同样的代码,我们升级了下springboot到2.3.2.RELEASE。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.2.RELEASE</version>
    <relativePath/>
</parent>

同样的代码不动,发送请求看下结果:

现在是乱码了,这就是生产上出的问题。按照常规思路解决下,在我们的请求上对这个URL进行过滤,设置一下编码格式就ok,那接着加上过滤器:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter(urlPatterns = "/hello/test", filterName = "CharsetFilter")
public class CharsetFilter implements Filter {
    public void init(FilterConfig config) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("UTF-8");
        filterChain.doFilter(servletRequest, servletResponse);//交给下一个过滤器或servlet处理
    }

    public void destroy() {
        /*销毁时调用*/
    }
}

然后在run一下,发现仍然不可以,这个过滤器没有起作用。为什么springboot升级后就不可以了。问题就出在了这里,很明显,springboot升级后,会按照请求头设置的字符编码来对字节流解码,之前并没有这么做。而之前功能是正常的原因其实在B系统上,虽然他们在请求头加上了charset=gbk,但是传过来的是UTF8编码的字符,在springboot没有关注请求头的时候,是按照当前默认的字符解码,这是没问题的,两者都是相同编码。

问题找到了,那就很简单。我们把接收的字符用GBK解码后再用UTF8编码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

@Controller
@RequestMapping("/hello")
public class HelloController {

    @PostMapping("/test")
    @ResponseBody
    public UserDO getUser(@RequestBody UserDO user) throws UnsupportedEncodingException {
        //转换编码
        String name = new String(user.getUserName().getBytes("GBK"), "UTF-8");
        user.setUserName(name);
        System.out.println(user.getUserId());
        System.out.println(user.getUserName());
        return user;
    }
}

现在看结果:

功能恢复正常了。

你以为这就结束了,完美修复了一个bug,太天真。下面看看我不叫“张三”,我叫“张三丰”,会有怎么样的结果呢?

哇塞,太神奇了,这一定是在逗我。

为什么会这样呢,这是跟字符编码有关系。感兴趣的同学可以搜一下,其实乱码的本质就是:读取二进制的时候采用的编码和最初将字符转换成二进制时的编码不一致。

所以这个问题原因就是:

GBK一个字符2个字节,UTF-8一个字符3个字节,当用GBK去读(解码)UTF-8编码后的内容,当UTF-8字符是奇数个的时候,GBK解码之后会多出一位字节,那只能用'?'字节(63)来替换,所以即使再转码也会出现最后一个中文字符是?的乱码问题

所以解决这个问题很简单了,直接改用inputStream直接读byte,之后再转为utf-8。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Controller
@RequestMapping("/hello")
public class HelloController {
    @PostMapping("/test")
    @ResponseBody
    public UserDO getUser(HttpServletRequest request) throws IOException {
        //读取字节流转成字符串
        String content = charReader(request);
        //json字符串转成java对象
        UserDO user = JSON.parseObject(content, UserDO.class);
        return user;
    }
    //字符串读取
    static String charReader(HttpServletRequest request) throws IOException {
        BufferedReader br = request.getReader();
        String str, wholeStr = "";
        while ((str = br.readLine()) != null) {
            wholeStr += str;
        }
        return wholeStr;
    }
}

至此这个bug才是完全的修改好了,这个尴尬的问题是因为B系统请求头用的说用GBK编码,结果请求体确实UTF8,好比说现在考的中文听力,你给我放英语,然后我在一个字一个字用汉字把英语音洗出来,你说的library,我写的“来不弱瑞”,这怎么乱码呢?

我是马拉松程序员,可不止于代码。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 马拉松程序员 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
pandas系列5-分组_groupby
groupby 是pandas 中非常重要的一个函数, 主要用于数据聚合和分类计算. 其思想是“split-apply-combine”(拆分 - 应用 - 合并). 拆分:groupby,按照某个属性column分组,得到的是一个分组之后的对象 应用:对上面的对象使用某个函数,可以是自带的也可以是自己写的函数,通过apply(function) 合并:最终结果是个S型数据 pandas分组和聚合详解 官方文档 DataFrame.``groupby(self, by=None, axis=0,
皮大大
2021/03/02
1.9K0
总结了25个Pandas Groupby 经典案例!!
groupby是Pandas在数据分析中最常用的函数之一。它用于根据给定列中的不同值对数据点(即行)进行分组,分组后的数据可以计算生成组的聚合值。
用户6888863
2023/03/01
3.6K0
总结了25个Pandas Groupby 经典案例!!
Python实战项目——旅游数据分析(四)
由于有之前的项目,所以今天我们直接开始,不做需求分析,还不会需求分析的可以看我之前的文章。Python实战项目——用户消费行为数据分析(三)
老虎也淘气
2024/01/30
4761
Python实战项目——旅游数据分析(四)
Pandas的apply, map, transform介绍和性能测试
来源:Deephub Imba本文约8500字,建议阅读10分钟本文介绍了如何使用 scikit-learn中的网格搜索功能来调整 PyTorch 深度学习模型的超参数。 apply函数是我们经常用到的一个Pandas操作。虽然这在较小的数据集上不是问题,但在处理大量数据时,由此引起的性能问题会变得更加明显。虽然apply的灵活性使其成为一个简单的选择,但本文介绍了其他Pandas函数作为潜在的替代方案。 在这篇文章中,我们将通过一些示例讨论apply、agg、map和transform的预期用途。 我们一
数据派THU
2023/03/29
2.1K0
Pandas的apply, map, transform介绍和性能测试
25个例子学会Pandas Groupby 操作(附代码)
来源:DeepHub IMBA本文约2300字,建议阅读5分钟本文用25个示例详细介绍groupby的函数用法。 groupby是Pandas在数据分析中最常用的函数之一。它用于根据给定列中的不同值对数据点(即行)进行分组,分组后的数据可以计算生成组的聚合值。 如果我们有一个包含汽车品牌和价格信息的数据集,那么可以使用groupby功能来计算每个品牌的平均价格。 在本文中,我们将使用25个示例来详细介绍groupby函数的用法。这25个示例中还包含了一些不太常用但在各种任务中都能派上用场的操作。 这里使用
数据派THU
2022/10/09
3.3K0
25个例子学会Pandas Groupby 操作(附代码)
Python实战项目——用户消费行为数据分析(三)
今天我们要对用户消费行为进行分析,用户消费行为数据分析项目旨在利用大量用户消费数据,通过数据挖掘和分析技术,深入了解用户在产品或服务上的消费行为模式和习惯。通过对数据的挖掘和分析,该项目可以帮助企业更好地了解其用户,优化产品或服务,提高用户满意度,增加用户忠诚度,并在竞争激烈的市场中获得优势
老虎也淘气
2024/01/30
1.4K0
Python实战项目——用户消费行为数据分析(三)
数据分析 ——— pandas基础(四)
利用pandas来进行数据处理的方法太多了,在这里继续更新一下对缺失数据的处理,以及数据的分组,聚合函数的使用。
andrew_a
2019/08/16
1.2K0
Pandas高级教程之:GroupBy用法
pandas中的DF数据类型可以像数据库表格一样进行groupby操作。通常来说groupby操作可以分为三部分:分割数据,应用变换和和合并数据。
程序那些事
2021/07/12
3K0
《利用Python进行数据分析·第2版》第10章 数据聚合与分组运算10.1 GroupBy机制10.2 数据聚合10.3 apply:一般性的“拆分-应用-合并”10.4 透视表和交叉表10.5 总
对数据集进行分组并对各组应用一个函数(无论是聚合还是转换),通常是数据分析工作中的重要环节。在将数据集加载、融合、准备好之后,通常就是计算分组统计或生成透视表。pandas提供了一个灵活高效的gruopby功能,它使你能以一种自然的方式对数据集进行切片、切块、摘要等操作。 关系型数据库和SQL(Structured Query Language,结构化查询语言)能够如此流行的原因之一就是其能够方便地对数据进行连接、过滤、转换和聚合。但是,像SQL这样的查询语言所能执行的分组运算的种类很有限。在本章中你将会看
SeanCheney
2018/04/24
5.1K0
《利用Python进行数据分析·第2版》第10章 数据聚合与分组运算10.1 GroupBy机制10.2 数据聚合10.3 apply:一般性的“拆分-应用-合并”10.4 透视表和交叉表10.5 总
快速入门pandas进行数据挖掘数据分析[多维度排序、数据筛选、分组计算、透视表](一)
Python使用缩进(tab或者空格)来组织代码,而不是像其 他语言比如R、C++、Java和Perl那样用大括号。考虑使用for循 环来实现排序算法:
汀丶人工智能
2023/02/14
5450
快速入门pandas进行数据挖掘数据分析[多维度排序、数据筛选、分组计算、透视表](一)
《Pandas Cookbook》第07章 分组聚合、过滤、转换1. 定义聚合2. 用多个列和函数进行分组和聚合3. 分组后去除多级索引4. 自定义聚合函数5. 用 *args 和 **kwargs
第01章 Pandas基础 第02章 DataFrame运算 第03章 数据分析入门 第04章 选取数据子集 第05章 布尔索引 第06章 索引对齐 第07章 分组聚合、过滤、转换 第08章 数据清理 第09章 合并Pandas对象 第10章 时间序列分析 第11章 用Matplotlib、Pandas、Seaborn进行可视化
SeanCheney
2018/10/10
9.2K0
用 Pandas 进行数据处理系列 二
获取行操作df.loc[3:6]获取列操作df['rowname']取两列df[['a_name','bname']] ,里面需要是一个 list 不然会报错增加一列df['new']=list([...])对某一列除以他的最大值df['a']/df['a'].max()排序某一列df.sorted_values('a',inplace=True,ascending=True) , inplace 表示排序的时候是否生成一个新的 dataFrame , ascending=True 表示升序,默认为升序,如果存在缺失的补值( Nan ),排序的时候会将其排在末尾
zucchiniy
2019/10/30
8.4K0
Pandas 2.2 中文官方教程和指南(二十五·二)
将一个以小时为列、天为行的矩阵转换为连续的行序列,形成时间序列。如何重新排列 Python pandas DataFrame?
ApacheCN_飞龙
2024/05/24
2860
Pandas 2.2 中文官方教程和指南(二十五·二)
【数据处理包Pandas】分组及相关操作
数据集team.xlsx下载地址: 链接:https://pan.quark.cn/s/9e3b2a933510 提取码:7i2y
Francek Chen
2025/01/22
3020
【数据处理包Pandas】分组及相关操作
Python数据分析之Pandas(二)
: | ---------: | -----: | -----: | ------: | --------: | -----: | ---: | ------: | -------: | | 0 | 2018-01-01 | 3℃ | -6℃ | 晴~多云 | 东北风 | 1-2级 | 59 | 良 | 2 | | 1 | 2018-01-02 | 2℃ | -5℃ | 阴~多云 | 东北风 | 1-2级 | 49 | 优 | 1 | | 2 | 2018-01-03 | 2℃ | -5℃ | 多云 | 北风 | 1-2级 | 28 | 优 | 1 | | 3 | 2018-01-04 | 0℃ | -8℃ | 阴 | 东北风 | 1-2级 | 28 | 优 | 1 | | 4 | 2018-01-05 | 3℃ | -6℃ | 多云~晴 | 西北风 | 1-2级 | 50 | 优 | 1 |
yuanshuai
2022/08/22
1.7K0
Python数据分析之Pandas(二)
13个Pandas奇技淫巧
先按Mt列进行分组,然后对分组之后的数据框使用idxmax函数取出Count最大值所在的列,再用iloc位置索引将行取出。有重复值的情况
小白学视觉
2022/04/06
9020
Python 数据分析(四):Pandas 进阶
我们在上一篇文章初识 Pandas中已经对 Pandas 作了一些基本介绍,本文我们进一步来学习 Pandas 的一些使用。
Python小二
2020/08/18
7790
Python 数据分析(四):Pandas 进阶
Pandas常用的数据处理方法
本文的Pandas知识点包括: 1、合并数据集 2、重塑和轴向旋转 3、数据转换 4、数据聚合 1、合并数据集 Pandas中合并数据集有多种方式,这里我们来逐一介绍 1.1 数据库风格合并 数据库风格的合并指根据索引或某一列的值是否相等进行合并的方式,在pandas中,这种合并使用merge以及join函数实现。 先来看下面的例子: df1 = pd.DataFrame({'key':['b','b','a','c','a','a','b'],'data1':range(7)}) df2 = pd.Dat
石晓文
2018/04/11
8.5K0
Pandas常用的数据处理方法
Python数据分析实战(2)使用Pandas进行数据分析
Pandas的使用很灵活,最重要的两个数据类型是DataFrame和Series。
cutercorley
2020/08/26
4.2K0
Pandas非常用技巧汇总
注意:由于NaN的存在,B列初始的数据类型是float,如果要变成整数,使用astype转换即可。
致Great
2023/08/25
5870
推荐阅读
相关推荐
pandas系列5-分组_groupby
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档