转:SpringMVC 返回 json 字符串中文乱码

2023-11-15

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/wenteryan/article/details/79803691
原因
最近在写一些小的Demo案例,但是被AJAX的 json 返回乱码折磨了好久。最后通过研究StringHttpMessageConverter源代码发现,开发者很坑的使用了”ISO-8859-1”作为默认编码。经过代码测试,下面给出四种方法解决SpringMVC 返回 json 字符串中文乱码。(本文spring版本4.3.11.RELEASE)

public class StringHttpMessageConverter extends AbstractHttpMessageConverter<String> {
    public static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");
    private volatile List<Charset> availableCharsets;
    private boolean writeAcceptCharset;
    // 后面省略
1
2
3
4
5


方法一:自己编写一个工具类
学过servlet我们可以知道,可以通过HttpServletResponse设置返回编码。

工具类

public class ResponseTool {

    public static void write(HttpServletResponse response,Object o)throws Exception{
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out=response.getWriter();
        out.println(o.toString());
        out.flush();
        out.close();
    }
}
1
2
3
4
5
6
7
8
9
10
测试方法

@RequestMapping(value = "/toolToJson")
public void toolToJson(HttpServletResponse response) throws Exception {
    Map map = new HashMap();
    map.put("code", "200");
    map.put("msg", "这是一句话,测试返回json是否乱码。");
    ResponseTool.write(response,new Gson().toJson(map));
}
1
2
3
4
5
6
7


方法二:使用produces属性
在RequestMapping使用(produces = “text/html; charset=utf-8”)produces 作用根据请求头中的Accept进行匹配,如请求头“Accept:text/html”时即可匹配。

如果类型是:application/json ,设置为:produces = “application/json; charset=utf-8” 
测试方法

@RequestMapping(value = "/producesToJson", method = RequestMethod.GET, produces="text/html;charset=UTF-8")
@ResponseBody
public String producesToJson() {
    Map map = new HashMap();
    map.put("code", "200");
    map.put("msg", "这是一句话,测试返回json是否乱码。");
    return new Gson().toJson(map);
}
1
2
3
4
5
6
7
8


方法三:通过配置spring-mvc.xml
在spring-mvc.xml添加配置

<mvc:annotation-driven>
    <mvc:message-converters register-defaults="true">
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="supportedMediaTypes">
                <list>
                    <value>text/html;charset=UTF-8</value>
                    <value>application/json;charset=UTF-8</value>
                    <value>text/plain;charset=UTF-8</value>
                    <value>application/xml;charset=UTF-8</value>
                </list>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
测试方法

@RequestMapping(value = "/json")
@ResponseBody
public String json() {
    Map map = new HashMap();
    map.put("code", "200");
    map.put("msg", "这是一句话,测试返回json是否乱码。");
    return new Gson().toJson(map);
}
1
2
3
4
5
6
7
8


方法四:完成自己的AbstractHttpMessageConverter
分析源码可以看出StringHttpMessageConverter继承与AbstractHttpMessageConverter,分析该抽象类得,相关的操作字符编码的方法可以重写,于是我们可以自定义一个类继承StringHttpMessageConverter,然后重写相关的方法。这里我们只需要把ISO-8859-1改成UTF-8,并修改构造方法。

UTF8StringHttpMessageConverter 类

package com.javazhan.controller;

import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.StreamUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: yandq
 * @Description:
 * @Date: Create in 11:50 2018/4/3
 * @Modified By:
 */
public class UTF8StringHttpMessageConverter extends AbstractHttpMessageConverter<String> {
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    private volatile List<Charset> availableCharsets;
    private boolean writeAcceptCharset;

    public UTF8StringHttpMessageConverter() {
        this(DEFAULT_CHARSET);
    }

    public UTF8StringHttpMessageConverter(Charset defaultCharset) {
        super(defaultCharset, new MediaType[]{MediaType.TEXT_PLAIN, MediaType.ALL});
        this.writeAcceptCharset = true;
    }

    public void setWriteAcceptCharset(boolean writeAcceptCharset) {
        this.writeAcceptCharset = writeAcceptCharset;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return String.class == clazz;
    }

    @Override
    protected String readInternal(Class<? extends String> clazz, HttpInputMessage inputMessage) throws IOException {
        Charset charset = this.getContentTypeCharset(inputMessage.getHeaders().getContentType());
        return StreamUtils.copyToString(inputMessage.getBody(), charset);
    }

    @Override
    protected Long getContentLength(String str, MediaType contentType) {
        Charset charset = this.getContentTypeCharset(contentType);

        try {
            return (long)str.getBytes(charset.name()).length;
        } catch (UnsupportedEncodingException var5) {
            throw new IllegalStateException(var5);
        }
    }

    @Override
    protected void writeInternal(String str, HttpOutputMessage outputMessage) throws IOException {
        if (this.writeAcceptCharset) {
            outputMessage.getHeaders().setAcceptCharset(this.getAcceptedCharsets());
        }

        Charset charset = this.getContentTypeCharset(outputMessage.getHeaders().getContentType());
        StreamUtils.copy(str, charset, outputMessage.getBody());
    }

    protected List<Charset> getAcceptedCharsets() {
        if (this.availableCharsets == null) {
            this.availableCharsets = new ArrayList(Charset.availableCharsets().values());
        }

        return this.availableCharsets;
    }

    private Charset getContentTypeCharset(MediaType contentType) {
        return contentType != null && contentType.getCharset() != null ? contentType.getCharset() : this.getDefaultCharset();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
定义好上面的类后,只需要将该类注册到Spring的annotaion 处理序列中即可,当加上@ResponseBody时,Spring将会调用上面自定义类中复写的方法,从而返回UTF-8的编码:

<mvc:annotation-driven>
      <mvc:message-converters register-defaults="true">
            <bean class="com.javazhan.controller.UTF8StringHttpMessageConverter"/>
      </mvc:message-converters>
</mvc:annotation-driven>
1
2
3
4
5
测试方法

@RequestMapping(value = "/json")
@ResponseBody
public String json() {
    Map map = new HashMap();
    map.put("code", "200");
    map.put("msg", "这是一句话,测试返回json是否乱码。");
    return new Gson().toJson(map);
}
1
2
3
4
5
6
7
8


版权声明:本文为博主原创文章,未经博主允许不得转载。转载请注明出处:http://blog.csdn.net/wenteryan
————————————————
版权声明:本文为CSDN博主「wenteryan」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wenteryan/article/details/79803691

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

转:SpringMVC 返回 json 字符串中文乱码 的相关文章

随机推荐

  • 第三章-Python中的数据类型

    欢迎来到python的世界 博客主页 卿云阁 欢迎关注 点赞 收藏 留言 本文由卿云阁原创 本阶段属于练气阶段 希望各位仙友顺利完成突破 首发时间 2021年3月14日 希望可以和大家一起完成进阶之路 作者水平很有限 如果发现错误 请留言轰
  • ubuntu下编译问题集锦

    1 DSO missing from command line 一般是库链接顺序不对 将依赖于其他库的lib放在前面 库放在后面就行 2 fatal error ceres ceres h No such file or directory
  • CTF中那些脑洞大开的编码和加密

    0x00 前言 正文开始之前先闲扯几句吧 玩CTF的小伙伴也许会遇到类似这样的问题 表哥 你知道这是什么加密吗 其实CTF中脑洞密码题 非现代加密方式 一般都是各种古典密码的变形 一般出题者会对密文进行一些处理 但是会给留一些线索 所以写此
  • vant使用时覆盖默认样式

    在我们使用vant的时候 有时候一些组件的默认样式并不能满足我们项目的需求 这个时候我们可以使用下面的办法 覆盖掉默认样式 亲测有效 vant覆盖默认样式的写法 v deep van cell not last child after le
  • transform的scale属性实现对大屏的适配

    最近公司做的大屏用到了transform的scale属性来对大屏网页 进行缩放 缺点 需要给项目大屏 设定固定的宽高 当使用的屏幕分辨率和项目不一致时 会出现左右或者上下的留白 如果设计稿是1920 1080的尺寸 项目中用px来写宽高的话
  • QT 自学内容 day06 文件的打开,读取,写入,输出内容的时候编码方式的修改,文件的创建日期,和最后的修改时间

    1 打开文件 头文件 include
  • 在图像间进行特征匹配

    特征匹配 目标 我们将要学习在图像间进行特征匹配 使用 OpenCV 中的蛮力 Brute Force 匹配和 FLANN 匹配 Brute Force 匹配的基础 蛮力匹配器是很简单的 首先在第一幅图像中选取一个关键点然后依次与第二幅图像
  • python自(2)切片 字典 遍历删除添加修改查询定义函数函数返回值作用域序列化异常报错urllib使用一个类型六个方法下载 视频音频图片

    切片 切片 s hello word 下标索引为0的 print s 0 h 左闭右开 左是下标开始的 右是几个索引值 例如从0开始算 4个索引值 print s 0 4 hell 更改起始值的开始位置 print s 1 ello wor
  • 产品经理的思考-概括

    思考 断断续续从技术转产品已经两年时间 从2021年的按部就班 到2022年的兵荒马乱 从技术到产品会有优势 但也有自身的枷锁 如何发挥优势 跳出枷锁 是一个不断思考和突破的过程 比较转岗会有蜜月期 但是漫长的痛苦才是现实 从技术到产品是需
  • 再谈Qt实现Rasdial拨号问题(说说项目中遇到的问题和解决方案)

    上一篇 Qt实现Rasdial宽带拨号 讲解了下最简单的宽带拨号方式 但是在实际项目开发中 发现 这种做法是不好的 效率低 有时拨号失败 而且上一回 我们是采用异步拨号来实现 这个做法是不行的 我们需要实现同步拨号 那么我们应该借助api函
  • unity3d读取Excel小白教程

    1 课前准备准备三个文件 Excel dll ICSharpCode SharpZipLib dll System Data dll 如图 下载地址 链接 https pan baidu com s 1B2Sue9iw4qWzwjb1uJ6
  • vue3中使用vueQuill富文本编辑器详细教程,图片上传-图片压缩

    vueQuill是支持vue3的富文本编辑器组件 使用简单方便 官方网址 https vueup github io vue quill 效果图 1 安装 在官网有详细的安装教程 npm或者yran下载 npm install vueup
  • OSPF学习总结

    对于OSPF的学习重点总结 一个DR 三个表 五种包 七种状态 路径寻优 实时更新 OSPF介绍 一种链路状态和内部网关协议 所谓链路状态就是指 链路上的路由器与哪些路由器相邻以及它们之间的距离 度量值 是多少 来确定一条最短路径 内部网关
  • 汇编语言+IDA安装问题解决汇总

    利用汇编语言计算机和人类链接更为便捷如下图所示 寄存器 简单讲就是CPU可以存储数据的器件 一个CPU可以有多个寄存器 AX BX是两个不同的寄存器 16位处理器有14个寄存器 AX BX CX DX SI DI SP BP IP CS S
  • linux 文件十六进制阅读_Linux引导101

    对于Ubuntu 18 04 gt Photo by Adi Goldstein on Unsplash 让我们从Wikipedia如何描述引导程序开始 通常 自举通常是指自启动过程 应该在没有外部输入的情况下进行 在计算机技术中 该术语
  • jquery中ajax处理跨域的三大方式

    由于JS同源策略的影响 因此js只能访问同域名下的文档 因此要实现跨域 一般有以下几个方法 一 处理跨域的方式 1 代理 2 XHR2 HTML5中提供的XMLHTTPREQUEST Level2 及XHR2 已经实现了跨域访问 但ie10
  • Oracle 11g数据库安装之后没有OracleOraDb11g_home1TNSListener服务

    1 在安装目录下F Oracle Server product 11 2 0 dbhome 1 BIN netca deinst bat 以管理员身份运行 会出现命令窗口 执行完会自己退出 2 再以管理员身份启动netca bat 重新配置
  • 快速乘和改造快速幂

    快速乘和改造快速幂 文章目录 快速乘和改造快速幂 快速乘 快速幂改造 典型例题 参考材料 快速乘 因为我们知道乘法有时候会溢出 即使是long也可能因为结果过大而溢出 当模数也是long类型时 所以我们需要寻找一种能高效完成乘法操作并且不会
  • AntDB数据库参加ACDU中国行杭州站,分享数据库运维实践与经验

    关于ACDU 和中国行 ACDU是由墨天轮社区举办的中国数据库联盟的品牌活动之一 在线下汇集数据库领域的行业知名人士 共同探讨数据库前沿技术及其应用 促进行业发展和创新的平台 也为开发者们提供友好交流的机会 AntDB作为具有技术前瞻性的国
  • 转:SpringMVC 返回 json 字符串中文乱码

    版权声明 本文为博主原创文章 遵循 CC 4 0 BY SA 版权协议 转载请附上原文出处链接和本声明 本文链接 https blog csdn net wenteryan article details 79803691 原因 最近在写一