记一次Springboot 二进制文件转发遇到的坑
- 业务描述
- 坑
- 两个坑
- 代码
- 解码处理
- 文件上传
- 服务器C的接收文件
- 接收文件
- 文件存入
业务描述
1、订单数据传输到后台 A,数据包含二进制类型的文件(因为都是小文件,和数据同时上传)。
2、传到后台后,使用restTemplate传到专门处理订单的服务 B
3、B 服务器中将文件部分拆分,传到文件服务器 C
坑
两个坑
1、二进制文件在 A->B 的时候,json会自动将byte[]转换为Base64编码,在B服务器中需要用Base64解码转回byte[]。
2、B->C时,需要将byte[]转为 ByteArrayInputStream,在此时,需要重写 getFilename() 和 contentLength()方法。
代码
解码处理
Json会自动把byte[]转为Base64
附上编码方法: ().encode()
在这里要解码,JAVA8的方法:().decode()
private void enclosureUpload(JSONObject jsonObject) throws Exception {
List listBody = (List) jsonObject.get("listName");
for(Map map:listBody){
try {
//Json会以Base64自动将二进制编码,这里需要解码
byte[] fileSource = Base64.getDecoder().decode(map.get(colId).toString());
String filePath = fileService.fileUploadByByteArray(fileSource, enclosureName);
} catch (Exception ex) {
throw new Exception("数据上传异常");
}
}
}
文件上传
使用restTemplate上传到服务器,将byte[]转为输入流后,存入InputStreamResource中。
在此时要重写getFilename()和contentLength()方法
不写是要报错的
@Resource
private RestTemplate restTemplate;
public static final String FILESERVICE_URL = "http://localhost:9002";
public String fileUploadByByteArray(byte[] fileBin, String fileName) {
//设置请求头
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType("multipart/form-data");
headers.setContentType(type);
InputStream inputStream = new ByteArrayInputStream(fileBin);
//设置请求体,注意是LinkedMultiValueMap
org.springframework.core.io.Resource resource = new InputStreamResource(inputStream) {
@Override
public String getFilename() {
return fileName;
}
@Override
public long contentLength() {
int estimate = fileBin.length;
return estimate == 0 ? 1 : estimate;
}
};
MultiValueMap<String, Object> bodyParams = new LinkedMultiValueMap<>();
bodyParams.add("file", resource);
//用HttpEntity封装整个请求报文
HttpEntity<MultiValueMap<String, Object>> files = new HttpEntity<>(bodyParams, headers);
String url = FILESERVICE_URL + "/xxx/files/uploadOne";
ResponseEntity<String> response = restTemplate.postForEntity(url, files, String.class);
return response.getBody();
}
服务器C的接收文件
接收文件
MultipartFile接收文件
传入处理方法中
@PostMapping(value = "/uploadOne")
ResultInfo FileUpload(@RequestParam("file") MultipartFile file) {
Map resultMap = fileDownloadService.uploadFile(file);
//other deal
}
文件存入
文件保存处理方法
public Map<String, String> uploadFile(MultipartFile partFile) throws IOException {
Map<String, String> map = new HashMap<String, String>();
byte[] inputBytes = toByteArray(partFile.getInputStream());
try {
File path = new File(uploadPath);
if (!path.exists()) {
path.mkdirs();
path.setReadable(true);//设置可读权限
path.setWritable(true);//设置可写权限
}
//获取文件名
String fileName = partFile.getOriginalFilename();
//日期
String dateString = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
//uuid
String uuid = UUID.randomUUID().toString();
//获取相对路径
String relativePath = Paths.get(dateString, uuid).toString();
//获取绝对路径
String absolutePath = Paths.get(uploadPath, relativePath).toString();
//初始化文件、路径
File upload = new File(absolutePath);
//如果不存在就新建
if (!upload.exists()) {
upload.mkdirs();
}
//指定上传路径
String filePath = Paths.get(upload.getAbsolutePath()).toString();
File targetFile = new File(filePath);
if (!targetFile.exists()) {
targetFile.mkdirs();
targetFile.setReadable(true);
targetFile.setWritable(true);
}
//文件存在就先删除
String URI = Paths.get(filePath, fileName).toString();
File file = new File(URI);
if (file.exists()) {
delFile(URI);
}
//文件保存
partFile.transferTo(file);
map.put("URI", Paths.get(relativePath, fileName).toString());
map.put("result", "success");
} catch (Exception e) {
//失败的话返回到集合
map.put("result", "faild");
}
return map;
}
就这,再见。