spring RestTemplate中文乱码小记
问题简述
近日在开发新功能的时候,遇到一个问题。用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