likes
comments
collection
share

spring RestTemplate中文乱码小记

作者站长头像
站长
· 阅读数 19

问题简述

近日在开发新功能的时候,遇到一个问题。用RestTemplate请求一个接口返回字符串时乱码了。因为是一个使用了很久的接口了。出现乱码大概率应该是我这边出现了问题。

问题解决的坑

乱码问题解决起来应该还是很简单的。

RestTemplate添加字符串的转换器,并设置编码集。

正好项目里有个简单的工具类:

public class RestTemplateUtil {
    public static RestTemplate getInstance(){
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
        return restTemplate;
    }
}

好了,接着调试吧。

😳

还是乱码!!!!咋回事啊!!!!

在一顿挣扎后,看到了RestTemplate的源码。 原来上面的代码根本就没起作用。 RestTemplate构造方法源码:


private final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();

public RestTemplate() {
    this.messageConverters.add(new ByteArrayHttpMessageConverter());
    this.messageConverters.add(new StringHttpMessageConverter());
    this.messageConverters.add(new ResourceHttpMessageConverter(false));
    try {
       this.messageConverters.add(new SourceHttpMessageConverter<>());
    }
    catch (Error err) {
       // Ignore when no TransformerFactory implementation is available
    }
    this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());

    if (romePresent) {
       this.messageConverters.add(new AtomFeedHttpMessageConverter());
       this.messageConverters.add(new RssChannelHttpMessageConverter());
    }

    if (jackson2XmlPresent) {
       this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
    }
    else if (jaxb2Present) {
       this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
    }

    if (jackson2Present) {
       this.messageConverters.add(new MappingJackson2HttpMessageConverter());
    }
    else if (gsonPresent) {
       this.messageConverters.add(new GsonHttpMessageConverter());
    }
    else if (jsonbPresent) {
       this.messageConverters.add(new JsonbHttpMessageConverter());
    }

    if (jackson2SmilePresent) {
       this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());
    }
    if (jackson2CborPresent) {
       this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());
    }

    this.uriTemplateHandler = initUriTemplateHandler();
}

构造方法里设置的第二个转换器就是StringHttpMessageConverter。并且在处理返回结果匹配转换器的时候是按顺序匹配的。


public static final Charset DEFAULT_CHARSET = StandardCharsets.ISO_8859_1;

public StringHttpMessageConverter() {
    this(DEFAULT_CHARSET);
}

StringHttpMessageConverter默认的编码集是ISO_8859_1。所以,之前使用restTemplate.getMessageConverters().add(new StringHttpMessageConverter(StandardCharsets.UTF_8));设置字符的转换器,根本就不生效,匹配到的都是默认的转换器。

解决方案

找到不生效的原因了,那解决起来就简单了。把默认设置的给替换掉就好了。

RestTemplate对属性messageConverters提供了get/set方法。我们拿出来给他替换掉就可以了。

public class RestTemplateUtil {
    public static RestTemplate getInstance(){
        RestTemplate restTemplate = new RestTemplate();
        List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();

        for (int i = 0; i < messageConverters.size(); i++) {
            if(messageConverters.get(i) instanceof StringHttpMessageConverter){
                messageConverters.set(i, new StringHttpMessageConverter(StandardCharsets.UTF_8));
                break;
            }
        }
        return restTemplate;
    }
}

这个工具类之前也没使用过,为啥没有问题啊?我查了查,别人用的时候都定义了相应的返回类,没有使用StringHttpMessageConverter。也不知道他们是掉完坑改的还是本来写的就规范。终究是我low了。 赶紧把工具类改了,可别再坑人了。

转载自:https://juejin.cn/post/7370906781386096674
评论
请登录