一、问题描述

项目中, 使用restTemplate上传文件时, 文件名中文乱码, 一串问号, 源文件名为: 测试中文乱码哦哦哦.zip, 通过restTemplate.postForObject调用接口, 发现文件名变成了: ?????????.zip, 上传失败

二、话不多说, 解决方案

1、新建MyFormHttpMessageConverter类

  1. package com.cn.pinliang.admin.Configure;
  2. import javax.mail.internet.MimeUtility;
  3. import org.springframework.http.converter.FormHttpMessageConverter;
  4. import java.io.UnsupportedEncodingException;
  5. import java.nio.charset.Charset;
  6. import java.nio.charset.StandardCharsets;
  7. public class MyFormHttpMessageConverter extends FormHttpMessageConverter {
  8. @Override
  9. protected String getFilename(Object part) {
  10. String filename = super.getFilename(part);
  11. Charset multipartCharset = StandardCharsets.UTF_8;
  12. return MimeDelegate.encode(filename, multipartCharset.name());
  13. }
  14. private static class MimeDelegate {
  15. private MimeDelegate() {
  16. }
  17. public static String encode(String value, String charset) {
  18. try {
  19. return MimeUtility.encodeText(value, charset, (String) null);
  20. } catch (UnsupportedEncodingException var3) {
  21. throw new IllegalStateException(var3);
  22. }
  23. }
  24. }
  25. }

2、新建RestTemplateConf类

  1. package com.cn.pinliang.admin.Configure;
  2. import org.springframework.http.MediaType;
  3. import org.springframework.http.converter.*;
  4. import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
  5. import org.springframework.web.client.RestTemplate;
  6. import java.nio.charset.Charset;
  7. import java.nio.charset.StandardCharsets;
  8. import java.util.ArrayList;
  9. import java.util.List;
  10. public class RestTemplateConf {
  11. public static RestTemplate restTemplate() {
  12. RestTemplate restTemplate = new RestTemplate();
  13. List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
  14. messageConverters.add(new MappingJackson2HttpMessageConverter());
  15. StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
  16. stringHttpMessageConverter.setWriteAcceptCharset(true);
  17. List<MediaType> mediaTypeList = new ArrayList<>();
  18. mediaTypeList.add(MediaType.ALL);
  19. for (int i = 0; i < messageConverters.size(); i++) {
  20. HttpMessageConverter<?> converter = messageConverters.get(i);
  21. if (converter instanceof StringHttpMessageConverter) {
  22. messageConverters.remove(i);
  23. messageConverters.add(i, stringHttpMessageConverter);
  24. }
  25. if (converter instanceof MappingJackson2HttpMessageConverter) {
  26. try {
  27. ((MappingJackson2HttpMessageConverter) converter).setSupportedMediaTypes(mediaTypeList);
  28. } catch (Exception e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. if (converter instanceof FormHttpMessageConverter) {
  33. MyFormHttpMessageConverter myConverter = new MyFormHttpMessageConverter();
  34. myConverter.setCharset(StandardCharsets.UTF_8);
  35. messageConverters.remove(i);
  36. messageConverters.add(i, myConverter);
  37. }
  38. }
  39. return restTemplate;
  40. }
  41. }

3、使用

  1. RestTemplate restTemplate = RestTemplateConf.restTemplate();
  2. restTemplate.postForObject... 巴拉巴拉

三、分析

本来之前遇到过同样的问题, 是springboot项目, spring-web版本为4.2.8, 解决方案更简单, 直接在Application启动类中注入restTemplate bean

  1. @Bean
  2. public RestTemplate restTemplate() {
  3. RestTemplate restTemplate = new RestTemplate();
  4. restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
  5. StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
  6. stringHttpMessageConverter.setWriteAcceptCharset(true);
  7. List<MediaType> mediaTypeList = new ArrayList<>();
  8. mediaTypeList.add(MediaType.ALL);
  9. for (int i = 0; i < restTemplate.getMessageConverters().size(); i++) {
  10. HttpMessageConverter<?> converter = restTemplate.getMessageConverters().get(i);
  11. if (converter instanceof StringHttpMessageConverter) {
  12. restTemplate.getMessageConverters().remove(i);
  13. restTemplate.getMessageConverters().add(i, stringHttpMessageConverter);
  14. }
  15. if(converter instanceof MappingJackson2HttpMessageConverter){
  16. try{
  17. ((MappingJackson2HttpMessageConverter) converter).setSupportedMediaTypes(mediaTypeList);
  18. }catch(Exception e){
  19. e.printStackTrace();
  20. }
  21. }
  22. if (converter instanceof FormHttpMessageConverter) {
  23. ((FormHttpMessageConverter) converter).setCharset(StandardCharsets.UTF_8);
  24. ((FormHttpMessageConverter) converter).setMultipartCharset(StandardCharsets.UTF_8);
  25. }
  26. }
  27. return restTemplate;
  28. }

重点是这一行代码

  1. ((FormHttpMessageConverter) converter).setMultipartCharset(StandardCharsets.UTF_8);

设置MultipartCharset字符集为UTF-8, 搞定

但是, 现在项目不是springboot项目, 直接copy这段代码发现报错, 没有setMultipartCharset方法, 对比发现原因是spring-web版本不同, 现在是4.0.2, 没有multipartCharset变量

那么问题来了, 怎么解决, 升级版本? 想了想升级版本成本太高, 很有可能导致其他问题, 那既然是由于没有multipartCharset变量, 那就看这个变量到底干了啥能解决中文乱码问题, 跟踪代码发现

原来是获取文件名时用到了, 如果自定义了multipartCharset字符集, 则按照字符集进行转码, 否则直接返回文件名, 再来看下4.0.2版本getFilename方法怎么写的

对, 就这么简单, 没有任何转码, OK, 既然我们无法通过构造参数指定编码从而对文件名进行转码, 那为什么不重写getFilename方法呢, 直接在方法里面指定字符集为UTF-8不就行了?

试一下, 新建MyFormHttpMessageConverter继承FormHttpMessageConverter, 重写getFilename

  1. @Override
  2. protected String getFilename(Object part) {
  3. String filename = super.getFilename(part);
  4. Charset multipartCharset = StandardCharsets.UTF_8;
  5. return MimeDelegate.encode(filename, multipartCharset.name());
  6. }

这一步搞定, 现在定义restTemplate, 最重要的是这一段代码

  1. if (converter instanceof FormHttpMessageConverter) {
  2. MyFormHttpMessageConverter myConverter = new MyFormHttpMessageConverter();
  3. myConverter.setCharset(StandardCharsets.UTF_8);
  4. messageConverters.remove(i);
  5. messageConverters.add(i, myConverter);
  6. }

将原来的FormHttpMessageConverter替换为上面新建的MyFormHttpMessageConverter, 搞定, 测试如下

四、总结

解决bug是一个不断摸索的过程, 尤其是碰到版本类似的问题, 很麻烦, 需要静下心来定位问题, 分析问题, 找出解决方案, 然后不断测试, 最后搞定, 本文没有对RestTemplate的HttpMessageConverter里面的各种转换器进行分析(我也不会, 哈哈), 更多的是一种解决问题的思路, 希望对小伙伴有一点帮助

restTemplate.postForObject上传文件中文乱码(???.xls)的更多相关文章

  1. drupal7 上传文件中文乱码

    drupal7自带有file模块,可以上传文件. 但是存在问题:如果上传的文件名称是中文,存储在文件下面的文件名称是乱码的,解决办法如下:参考出处 includes/file.inc中,修改两处代码, ...

  2. Spring MVC—拦截器,文件上传,中文乱码处理,Rest风格,异常处理机制

    拦截器 文件上传 -中文乱码解决 rest风格 异常处理机制 拦截器 Spring MVC可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器必须实现HandlerI ...

  3. php上传文件中文文件名乱码的解决方法

    文件上传是我们在处理表单提交时候最常用的功能之一,今天写了一个小小的demo,如下: 先看结构: html为表单提交的页面,php为处理表单的文件,upload为上传文件所放的位置 html: < ...

  4. 关于commons-fileupload组件上传文件中文名乱码问题

    java web开发,常用到的文件上传功能,常用的commons-fileupload和commons-io两个jar包.关于如何使用这两个jar来完成文件上传的功能,这里不做详解.使用commons ...

  5. Linux学习23-Xftp上传文件显示乱码问题

    前言 当我们在windows新建一个文件,里面有中文时,使用Xftp上传到linux服务器上,会出现乱码问题. Windows的默认编码为GBK Linux的默认编码为UTF-8 Xftp上传文件乱码 ...

  6. 关于TomCat上传文件中文名乱码的问题

    最近在学习TomCat文件上传这一部分,由于文件上传必须要三个条件: 1.表单提交方式必须为Post 2.表单中需要有<input type="file">元素,还需要 ...

  7. C# 使用 fckeditor 上传文件中文名乱码的问题---转

    提到中文乱码,首先肯定是由于编码问题引起的所以就从编码转换入手,尝试了将UTF-8转换为GB2312,但发现无论如何没有办法转成功 看到很多文章说修改配置文件 <globalization re ...

  8. 中文乱码问题(使用Servlet3.0新特性实现文件上传——上传文件名中文乱码问题)

    问题描述:就是文件传送过来的文件名等是乱码 解决方法:将传送的JSP页面(即含有表单的页面)的页面编码方式改为: <%@ page contentType="text/html; ch ...

  9. 上传文件中文文件名乱码的解决方法以及iconv函数的使用

    http://www.jb51.net/article/14530.htm 一般客户端是什么格式就展示什么格式,比如浏览器的UTF-8,windows的GBK

随机推荐

  1. Mysql Navicat连接

    mysql -u root ip; 1.use mysql; 2.alter user 'root'@'localhost' identified with mysql_native_password ...

  2. 死锁问题------------------------INSERT ... ON DUPLICATE KEY UPDATE*(转)

    前言    我们在实际业务场景中,经常会有一个这样的需求,插入某条记录,如果已经存在了则更新它如果更新日期或者某些列上的累加操作等,我们肯定会想到使用INSERT ... ON DUPLICATE K ...

  3. free mybtis plugin

    dao接口与mapper.xml的互相跳转

  4. windows安装zookeeper

    ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提供的功 ...

  5. spring扩展点总结

    NamespaceHandler 通过自定义的NamespaceHandler,配合BeanDefinitionParser,可以完成自定义Bean的组装操作,对于BeanDefinition的数据结 ...

  6. 海龟绘图turtle库之二级基础编程题

    一.画一个太极图 import turtle as t t.pensize(2)#设置笔画宽度 t.circle(100)#以100为半径的圆 t.circle(50, 180) t.circle(- ...

  7. 把dotx模板的样式应用到当前文档中(不应用dotx的其他东西)

    Word.Document doc = this.Application.ActiveDocument; //模板样式添加到当前文档 doc.CopyStylesFromTemplate(@" ...

  8. ubuntu设置ssh登录

    1.为ubuntu添加root用户(其实Ubuntu中的root帐号默认是被禁用了的,所以登陆的时候没有这个账号),打开初始账号,输入命令:sudo passwd root,设置root的密码 2.切 ...

  9. Asp.net Security框架(2)

    Asp.net 的Security框架除了提供Cookies,OAuth,ActiveDirectory等多个用户认证实现,基本上已经满足业务项目的开发需要了. 当需要实现OAuth2.0服务器端实现 ...

  10. Java并发编程:Synchronized底层优化(偏向锁、轻量级锁)

    Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...