excel文件上传下载问题总结

最近做项目跟excel打交道比较多,很多业务需求涉及到excel文件的上传、解析和下载,在这个过程中,我们难免会遇到一些棘手的问题。下面我将对这些问题做一个描述,提供出我的解决方案以及思考和总结。

一、斜线的问题

考虑到要用poi来开发如下带有斜线的表格,我之前也没遇过这样的需求,在网上也苦苦找寻了许久,一直没答案。后来突然来了灵感,为何不用读取模板的方式呢,我们可以直接在模板上把这个斜线给画好。一般情况下,斜线上下的文本也很少变动,于是我们也可以把“城市”和“手机品牌”一起画在模板上。
在这里插入图片描述

二、RestTemplate上传文件中文名乱码问题

一般情况下,我们用RestTemplate上传中文名的文件,用以下代码不会有文件名乱码问题。但是如果你有了spring-web5.0以下的jar包,你就会很郁闷,不管我们怎么设置编码格式,接收端收到的文件名都会乱码。

	@Test
    public void restTemplateTransferFile(){
        final String filePath = "F:";
        final String fileName = "我的文件.txt";
        final String url = "http://localhost:8080/file/upload";

        RestTemplate restTemplate = new RestTemplate();

        //设置请求头
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("multipart/form-data");
        headers.setContentType(type);

        //设置请求体,注意是LinkedMultiValueMap
        FileSystemResource fileSystemResource = new FileSystemResource(filePath+"/"+fileName);
        MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
        form.add("file", fileSystemResource);
        form.add("filename",fileName);

        //用HttpEntity封装整个请求报文
        HttpEntity<MultiValueMap<String, Object>> files = new HttpEntity<>(form, headers);

        String s = restTemplate.postForObject(url, files, String.class);
        System.out.println(s);
    }

这个问题阻碍了我很长时间,开始网上也找了几个解决方案,有些一看篇幅很长,我就觉得不就是编码格式问题嘛,干嘛要长篇大论一番,直接找到编码的位置设置下就好了。但是但是,这次还真不行了,在哪个地方设置编码,设置任何编码都不行。后来我也是debug进去找到了http表单的转换类,看到了以下代码。注意红色框框这里,编码竟然写死是ASCII码,我的妈呀,问题就在这里。学过编码的同学都知道,ASCII码就只有128个基本字符,根本编不了中文。
在这里插入图片描述

定位到问题后,我们就好办了。结合网上的搜索,得出两种解决方案。
第一是升级spring-web到5.0以上(我也是服了,spring竟然要到5.0以上才解决)。5.0以上我们看到没有硬编码

	 private byte[] getBytes(String name) {
         return name.getBytes(this.charset);
     }

第二是自定义一个表单的转换类,把spring-web默认的给替换了。由于我们项目是有统一的架构版本,不能私自升级spring-web包,所以最终只能用第二种方案。具体的方法如下:

  1. 复制FormHttpMessageConverter类下的所有代码,新建UploadFileFormHttpMessageConverter类
public class UploadFileUploadFileFormHttpMessageConverter implements HttpMessageConverter<MultiValueMap<String, ?>> {
	// 省略
}
  1. 修改getAsciiBytes方法,编码改为UTF-8
		private byte[] getAsciiBytes(String name) {
            try {
                return name.getBytes(StandardCharsets.UTF_8.name());
            } catch (UnsupportedEncodingException var3) {
                throw new IllegalStateException(var3);
            }
        }

3.新建UploadRestTemplateUtil,替换新的converter

public class UploadRestTemplateUtil {
 
	/**
	 * 获取上传文件的restTemplate
	 * @return
	 */
	public static RestTemplate getRestTemplate() {
		RestTemplate restTemplate = new RestTemplate();
		List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
		messageConverters.add(new MappingJackson2HttpMessageConverter());
 
		StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
		stringHttpMessageConverter.setWriteAcceptCharset(true);
 
		List<MediaType> mediaTypeList = new ArrayList<>();
		mediaTypeList.add(MediaType.ALL);
 
		for (int i = 0; i < messageConverters.size(); i++) {
			HttpMessageConverter<?> converter = messageConverters.get(i);
			if (converter instanceof StringHttpMessageConverter) {
				messageConverters.remove(i);
				messageConverters.add(i, stringHttpMessageConverter);
			}
			if (converter instanceof MappingJackson2HttpMessageConverter) {
				try {
					((MappingJackson2HttpMessageConverter) converter).setSupportedMediaTypes(mediaTypeList);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			if (converter instanceof FormHttpMessageConverter) {
				// 针对文件上传文件名乱码情况使用自定义的converter
				UploadFileFormHttpMessageConverter myConverter = new UploadFileFormHttpMessageConverter();
				myConverter.setCharset(StandardCharsets.UTF_8);
 
				messageConverters.remove(i);
				messageConverters.add(i, myConverter);
			}
		}
		return restTemplate;
	}
}

三、导出文件OOM问题

POI生成文件占用大内存的问题,相信很多开发同学都知道,如果在高并发场景下,容易遇到OOM问题。当时我们在开发环境压测下载excel的时候发现,服务很快就抛出了OOM,我们很快定位到是poi占用内存太大了。这个地方是我们代码疏忽了,漏加并发线程控制。当初我们设计文件下载的时候就有用@Async 注解做文件异步的处理。

后来我们也做了避免OOM这方面的讨论,得出结论是有两个方案,就看并发程度如何。

第一,文件下载并发低,我们直接做成异步调用,用@Async做并发控制,前端轮询文件生成结果。

第二,文件下载并发高,我们引进阿里的EasyExcel工具。这个工具是一行一行读取excel,特别省内存,我们在后面的开发中首先都是考虑采用这个工具生成excel。

关于EasyExcel的使用方法,可以查看官网。对于简单规整的excel,我们首先考虑使用这个工具。还有它的填充功能,我觉得还是特别赞的。但是对于一些单元格格式比较复杂的excel,我看EasyExcel没有很好的兼容支持,后面再持续关注这工具的发展。

四、输入输出流的实现

开发中有很多这样的需求:字节数组生成文件流,文件流生成文件,字符串写到文件等等。这都是输入输出流api的事情,好久没有接触过这方面的开发了,感觉都忘了大部分,后面专门写一篇文章来温习温习。

参考:RestTemplate上传文件中文名乱码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值