当前位置: 代码网 > it编程>编程语言>Java > 解决SpringBoot请求返回字符串中文乱码的问题

解决SpringBoot请求返回字符串中文乱码的问题

2024年06月12日 Java 我要评论
问题当controller的接口返回字符串,在swaggerui中测试时,发现返回都是问号,比如”?????id 100 ???????“,这是由于字符编码问题导致例如:res

问题

当controller的接口返回字符串,在swaggerui中测试时,发现返回都是问号,比如”?????id 100 ???????“,这是由于字符编码问题导致

例如:

responseentity.status(httpstatus.not_found)
  .body(string.format("未找到相应id %d 的记录", id));

网上解决方案

现有的两种解决方案:

  • 第一种,针对单独接口,在requestmapping里设置 produces = {"text/plain;charset=utf-8"}
  • 第二种,统一在mvc配置类中,通过修改stringhttpmessageconverter默认配置,部分代码(ps,该代码从别处拷贝而来):
@configuration
@enablewebmvc
public class mymvcconfig implements webmvcconfigurer {
 
    @bean
    public httpmessageconverter<string> responsebodystringconverter() {
        stringhttpmessageconverter converter = new stringhttpmessageconverter(standardcharsets.utf_8);
        return converter;
    }
 
 
    @override
    public void configuremessageconverters(list<httpmessageconverter<?>> converters){
        converters.add(responsebodystringconverter());
    }
}

是由于默认的编码是”standardcharsets.iso_8859_1“导致,是通过重写”configuremessageconverters“方法来设置utf-8编码来解决。

也就是第二种,坑了我,也许是我使用不当?

新解决方案

通过研究源码,找到了新的解决思路:

因为通过重写”configuremessageconverters“方法后,会导致一些其他问题

比如,统一处理异常的exceptionadvicehandler不工作,还导致controller接口不支持文件下载

比如:

//解决中文文件名的乱码问题
string utf8 = standardcharsets.utf_8.name();
try {
    downloadfilename = urlencoder.encode(downloadfilename, utf8);
} catch (unsupportedencodingexception e) {
    //
}
 
return responseentity.ok()
        .contenttype(mediatype.application_octet_stream)
        .header(httpheaders.content_disposition,
                "attachment; filename* = " + utf8 + "''" + downloadfilename)
        .body(new urlresource(downloadfile.touri()));

并且调用下载接口时,会报406错误和异常”no converter for [class org.springframework.core.io.urlresource]”,意思是不支持 “application/octet-stream“的转换,见鬼了,通过测试,禁用掉webmvcconfigurer的重写,下载功能就ok了,但是会重新有编码问题。

最终通过研究源码,找到了根源,这是由于设置了自己的converter导致默认的其他converters不会再被初始化添加导致,参见webmvcconfigurationsupport的代码:

    protected final list<httpmessageconverter<?>> getmessageconverters() {
        if (this.messageconverters == null) {
            this.messageconverters = new arraylist();
            this.configuremessageconverters(this.messageconverters);
            if (this.messageconverters.isempty()) {
                this.adddefaulthttpmessageconverters(this.messageconverters);
            }
 
            this.extendmessageconverters(this.messageconverters);
        }
 
        return this.messageconverters;
    }

所以基于这个代码,我们则应该重写extendmessageconverters方法来达到目的,最终的代码是:

   @bean
    public httpmessageconverter<string> responsebodystringconverter() {
        stringhttpmessageconverter converter = new stringhttpmessageconverter(standardcharsets.utf_8);
        return converter;
    }
 
    @override
    public void extendmessageconverters(list<httpmessageconverter<?>> converters) {
        list<stringhttpmessageconverter> stringhttpmessageconverters = converters.stream()
                .filter(converter -> converter.getclass().equals(stringhttpmessageconverter.class))
                .map(converter -> (stringhttpmessageconverter) converter)
                .collect(collectors.tolist());
 
        if (stringhttpmessageconverters.isempty()) {
            converters.add(responsebodystringconverter());
        } else {
            stringhttpmessageconverters.foreach(converter -> converter.setdefaultcharset(standardcharsets.utf_8));
        }
    }

json格式的编码探讨

这里仅处理接口直接返回字符串的问题,而对于处理json返回,这是因为json返回由mappingjackson2httpmessageconverter来控制:

	protected jsonencoding getjsonencoding(@nullable mediatype contenttype) {
		if (contenttype != null && contenttype.getcharset() != null) {
			charset charset = contenttype.getcharset();
			for (jsonencoding encoding : jsonencoding.values()) {
				if (charset.name().equals(encoding.getjavaname())) {
					return encoding;
				}
			}
		}
		return jsonencoding.utf8;
	}

所以对于返回json对象,无需处理,且已经提供了默认的utf-8编码,因为当默认没有设置mediatype的编码格式时,则会使用该默认的utf-8编码。

并且mediatype中针对json的编码有如下解释:

	/**
	 * a string equivalent of {@link mediatype#application_json_utf8}.
	 * @deprecated as of 5.2 in favor of {@link #application_json_value}
	 * since major browsers like chrome
	 * <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=438464" rel="external nofollow" >
	 * now comply with the specification</a> and interpret correctly utf-8 special
	 * characters without requiring a {@code charset=utf-8} parameter.
	 */
	@deprecated
	public static final string application_json_utf8_value = "application/json;charset=utf-8";

ps:org.springframework.boot:spring-boot-starter-web:jar:2.2.1.release

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com