问题描述:最近公司开发一个导入excel的常见功能,本来直接调用我后端服务是没有问题的可以正常导入excel,但是经过网关gateway转发到我的服务后再导入就发现excel被破坏不能正常解析。这个问题纠结了两三天终于解决。
1.本来后端接受的参数是MultipartFile类型,但是经过网关转发后发现文件不能打开,如下图所示:
并且导入文件报错(No valid entries or contents found, this is not a valid OOXML (Office Open XML) file)搜了一下说是文件被加密,但是我这个显然不是这个问题,后边更改了poi版本依然无济于事。
因为正常情况下直接调我导入服务是没有问题的,但是经由网关转发到我的服务就导入失败。应该是网关的原因,但是由于我对之前网关代码这块不是很熟悉,所以没找到解决方法。具体网关路由到导入服务的配置如下,有大神知道啥原因的还请不吝赐教。
解决方案 最后将excel文件经由前端进行base64编码,然后将编码后的字符串传给后端再解析成MultipartFile类型,就可以成功解析excel了。下面是对MultipartFile 编码及字符串转MultipartFile 的代码。
MultipartFile base64加密
//data:image/png;base64
String prefix = "data:" + file.getContentType() + ";base64,";
BASE64Encoder encoder = new BASE64Encoder();
String baseStr = encoder.encode(file.getBytes());
baseStr = prefix + baseStr.replaceAll("\r\n", "");
base64字符串转MultipartFile
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;
import java.io.*;
/**
* base64 转 MultipartFile
*
* @author PCCW
*/
public class MultipartFileUtils {
/**
* base64转MultipartFile
* @param base64
* @return
*/
public static MultipartFile base64ToMultipart(String base64) {
try {
String[] baseStrs = base64.split(",");
BASE64Decoder decoder = new BASE64Decoder();
byte[] b;
b = decoder.decodeBuffer(baseStrs[1]);
for(int i = 0; i < b.length; ++i) {
if (b[i] < 0) {
b[i] += 256;
}
}
return new MyMultipartFile(b, baseStrs[0]);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
package com.airlook.cruise.manager.util;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
/**
* base64 转 MultipartFile
*
*/
public class MyMultipartFile implements MultipartFile {
private final byte[] imgContent;
private final String header;
public MyMultipartFile(byte[] imgContent, String header) {
this.imgContent = imgContent;
this.header = header.split(";")[0];
}
@Override
public String getName() {
return System.currentTimeMillis() + Math.random() + "." + header.split("/")[1];
}
@Override
public String getOriginalFilename() {
return System.currentTimeMillis() + (int) (Math.random() * 10000) + "." + header.split("/")[1];
}
@Override
public String getContentType() {
return header.split(":")[1];
}
@Override
public boolean isEmpty() {
return imgContent == null || imgContent.length == 0;
}
@Override
public long getSize() {
return imgContent.length;
}
@Override
public byte[] getBytes() {
return imgContent;
}
@Override
public InputStream getInputStream() {
return new ByteArrayInputStream(imgContent);
}
@Override
public void transferTo(File dest) throws IOException {
try (FileOutputStream outputStream = new FileOutputStream(dest)) {
outputStream.write(imgContent);
} catch (IOException e) {
e.printStackTrace();
}
}
}
经过排查之前的网关代码,最终找到了根本原因。原来是网关那块加了一个全局过滤器 RequestBodyFilter,修改了请求体导致上传的excel损坏。解决方式只需要将上传文件的请求排除掉即可。
参考文章:
https://blog.csdn.net/weixin_43949154/article/details/125783459
https://blog.csdn.net/qq_39815502/article/details/110141587