实现的功能:
下载照片到缓存文件,分类存放照片,压缩成zip(保留多级目录结构)通过response返回后自定义下载路径。
【用于此功能练习的代码(详细注释)可参考:https://blog.csdn.net/FFJ_Olivia/article/details/121101226】
package com.epoch.customproject.goer.bill.controller;
import com.alibaba.fastjson.JSON;
import com.epoch.bdp.imageflow.utils.ImageUtils;
import com.epoch.customproject.goer.bill.model.ImageResult;
import com.epoch.ifp.expenseclaim.model.vo.ExpenseImageResult;
import com.epoch.infrastructure.util.service.DateUtils;
import com.epoch.infrastructure.util.service.HttpClientUtils;
import com.epoch.infrastructure.util.service.JsonUtils;
import com.epoch.infrastructure.util.service.fdfs.FastDFSClientUtil;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.util.UriUtils;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
1. @author olivia
*/
public class MyController {
/**
* 根据凭证号批量下载影像
*
* @param jsonData 数据集合
*/
@PostMapping("/batchDownloadImg")
public void batchDownloadImg(@RequestBody Map<String, List<String>> jsonData, HttpServletResponse response) throws IOException {
Map<String, Object> param = new HashMap<>();
List<String> voucherCodeData = jsonData.get("voucherCodeData");
List<String> billCodeData = jsonData.get("billCodeData");
if (voucherCodeData != null) {
// 这里的一步是从数据库获取单据号
List<Map<String, Object>> billCodeDataList = billRequestMachineAccountDAO.getMainBillCodeByBillCode(voucherCodeData);
if (!billCodeDataList.isEmpty()) {
Map<String, Object> codeParam = new HashMap<>();
for (Map<String, Object> billCode : billCodeDataList) {
// key:凭证号,value:单据号
codeParam.put(billCode.get("BILL_CODE").toString(), billCode.get("MAIN_BILL_CODE").toString());
}
param.put("voucherCode", codeParam);
}
}
if (billCodeData != null) {
Map<String, Object> codeParam = new HashMap<>();
for (String billCode : billCodeData) {
// key:单据号,value:单据号
codeParam.put(billCode, billCode);
}
param.put("billCode", codeParam);
}
if (param != null) {
batchDownloadImg(param, response);
}
}
/**
* 批量下载影像
* @param paramDate key:单据类型,value:单号集合(key:单据号/凭据号,value:单据号)
*/
public void batchDownloadImg(Map<String, Object> paramData, HttpServletResponse response) throws IOException {
long time = System.currentTimeMillis();
// 影像接口地址
String url = this.serverIp + ":" + this.serverPort + "/" + this.serverName + "/rest/api/image/list";
// 请求报文参数
List<String> param = new ArrayList<>();
param.add(this.appCode);
param.add(this.docCode);
String sign = ImageUtils.getSignString(time, param, this.secretKey);
Map<String, Object> paramMap = new HashMap<>(4);
paramMap.put("sign", sign);
paramMap.put("timestamp", time);
paramMap.put("appCode", this.appCode);
Map<String, Map<String, Object>> imgsDataMap = new HashMap<>();
// 不同单据类型
for (Map.Entry<String, Object> docTypeMap : paramData.entrySet()) {
Map<String, Map<String, Object>> dataMap = new HashMap<>();
Map<String, Object> codeDataMap = JSON.parseObject(JSON.toJSONString(docTypeMap.getValue()));
// 遍历单据号
for (Map.Entry<String, Object> codeMap : codeDataMap.entrySet()) {
// 获取单据号
paramMap.put("documentCode", codeMap.getValue().toString());
// 获取单据的所有影像的信息
ExpenseImageResult allImageResult = HttpClientUtils.postForJsonNoToken(url, paramMap, ExpenseImageResult.class);
List<ImageResult> imageResultList = JsonUtils.fromJSONList(allImageResult.getObj(), ImageResult.class);
// 获取影像地址集合
if (imageResultList != null) {
dataMap.put(codeMap.getKey(), new HashMap<>());
for (ImageResult imageResult : imageResultList) {
// dataMap的key:凭证号/单据号,value:影像信息集合(key:影像名,value:影像地址)
dataMap.get(codeMap.getKey()).put(imageResult.getImageName(), imageResult.getDfsId());
}
}
}
imgsDataMap.put(docTypeMap.getKey(), new HashMap<>());
imgsDataMap.get(docTypeMap.getKey()).putAll(dataMap);
}
// 下载zip文件
batchImgsDownload(imgsDataMap, response);
}
/**
* 下载zip文件
* @param dataMap key:单据类型,value:单号信息集合[key:凭证号/单据号,value:影像信息集合(key:影像名,value:影像地址)]
*/
public void batchImgsDownload(Map<String, Map<String, Object>> dataMap, HttpServletResponse response) throws IOException {
File rootFile = new File(System.getProperty("java.io.tmpdir") + File.separator + "imgsTemp" + DateUtils.longToDateString(System.currentTimeMillis(), "yyyyMMddHHmmss"));
rootFile.mkdirs();
for (Map.Entry<String, Map<String, Object>> typeDataMap : dataMap.entrySet()) {
String secondLevelFileName;
if ("voucherCode".equals(typeDataMap.getKey())) {
secondLevelFileName = "凭证号";
} else {
secondLevelFileName = "单据号";
}
for (Map.Entry<String, Object> billCodeDataMap : typeDataMap.getValue().entrySet()) {
File imgsFile = new File(rootFile, secondLevelFileName + File.separator + billCodeDataMap.getKey());
imgsFile.mkdirs();
Map<String, Object> imgsDataMap = JSON.parseObject(JSON.toJSONString(billCodeDataMap.getValue()));
// 下载影像到文件夹
for (Map.Entry<String, Object> imgsData : imgsDataMap.entrySet()) {
try (FileOutputStream fos = new FileOutputStream(new File(imgsFile, imgsData.getKey()))) {
// 获取影像数据
byte[] data = FastDFSClientUtil.downLoadFile(imgsData.getValue().toString());
fos.write(data);
} catch (Exception e) {
e.printStackTrace();
throw new IOException(e);
}
}
}
}
try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
// 未解决问题:zip包的名称中文会乱码,zip包内的中文文件目录不会乱码
response.setHeader("Content-Disposition", "attachment;filename=" + UriUtils.encode(rootFile.getName() + ".zip", "utf-8"));
response.setContentType("application/zip");
// 压缩下载
compress(rootFile, rootFile.getName(), zos);
} catch (Exception e) {
e.printStackTrace();
throw new IOException(e);
}
}
/**
* 递归压缩法
*
* @param sourceFile 源文件
* @param fileName 源文件的文件名称
* @param zos 压缩输出流
*/
public void compress(File sourceFile, String fileName, ZipOutputStream zos) throws IOException {
byte[] bytes = new byte[10240];
if (sourceFile.isFile()) {
// 源文件是文件
try (FileInputStream fis = new FileInputStream(sourceFile)) {
zos.putNextEntry(new ZipEntry(fileName));
int len;
while ((len = fis.read(bytes, 0, bytes.length)) != -1) {
zos.write(bytes, 0, len);
}
zos.closeEntry();
zos.flush();
} catch (IOException e) {
throw new IOException(e);
}
} else {
// 源文件是目录
File[] fileList = sourceFile.listFiles();
if (fileList == null || fileList.length == 0) {
// 空目录
try {
zos.putNextEntry(new ZipEntry(fileName));
zos.closeEntry();
zos.flush();
} catch (IOException e) {
throw new IOException(e);
}
} else {
// 非空目录
for (File file : fileList) {
compress(file, fileName + File.separator + file.getName(), zos);
}
}
}
}
}
遗留的问题:
用postman调用接口下载后的zip包的包名中文会乱码,包内的文件目录中文不会乱码。
尝试方法:
- response.setHeader(“Content-Disposition”, “attachment;filename=” + UriUtils.encode(“批量下载.zip”, “UTF-8”));
- response.setHeader(“Content-Disposition”, “attachment;filename=” + UriUtils.encode(“批量下载.zip”, “GBK”));
- response.setContentType(“application/zip;charset=UTF-8”);
- ZipOutputStream.setEncoding(“GBK”);
- ZipOutputStream.setEncoding(“UTF-8”);
以上几种方法皆没效果。暂不确定其他请求方式是否会复现,因为只用postman调用过。
============
有任何疑问或者建议欢迎随时评论交流哈~~