准备数据
构建测试实体
@Data
@Builder
public class ZipDownEntity {
private String time;
private String name;
private File file;
}
构建出数据
private List<ZipDownEntity> buildData() {
List<ZipDownEntity> list = new ArrayList<>();
try {
ZipDownEntity no1_1 = ZipDownEntity.builder().time("20240801").name("文件一").file(File.createTempFile("1-1.txt",null)).build();
ZipDownEntity no1_2 = ZipDownEntity.builder().time("20240801").name("文件一").file(File.createTempFile("1-2.txt",null)).build();
ZipDownEntity no1_3 = ZipDownEntity.builder().time("20240801").name("文件二").file(File.createTempFile("2-1.txt",null)).build();
ZipDownEntity no2_1 = ZipDownEntity.builder().time("20240802").name("文件一").file(File.createTempFile("1-1.txt",null)).build();
ZipDownEntity no2_2 = ZipDownEntity.builder().time("20240802").name("文件一").file(File.createTempFile("1-2.txt",null)).build();
ZipDownEntity no2_3 = ZipDownEntity.builder().time("20240802").name("文件二").file(File.createTempFile("2-1.txt",null)).build();
ZipDownEntity no3_1 = ZipDownEntity.builder().time("20240803").name("文件一").file(File.createTempFile("1-1.txt",null)).build();
ZipDownEntity no3_2 = ZipDownEntity.builder().time("20240803").name("文件一").file(File.createTempFile("1-2.txt",null)).build();
ZipDownEntity no3_3 = ZipDownEntity.builder().time("20240803").name("文件二").file(File.createTempFile("2-1.txt",null)).build();
list.add(no1_1);
list.add(no1_2);
list.add(no1_3);
list.add(no2_1);
list.add(no2_2);
list.add(no2_3);
list.add(no3_1);
list.add(no3_2);
list.add(no3_3);
}catch (Exception e){
throw new RuntimeException(e);
}
return list;
}
}
获取HttpServletResponse
private HttpServletResponse buildHttpServletResponse() {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes attributes1 = (ServletRequestAttributes) attributes;
return attributes1.getResponse();
}
下载
private void downFile(HttpServletResponse response, File file) {
try ( BufferedInputStream fis =new BufferedInputStream(Files.newInputStream(file.toPath()));
OutputStream toClient = new BufferedOutputStream(response.getOutputStream());){
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
// 清空response
response.reset();
response.setCharacterEncoding("UTF-8");
response.setContentType("application/octet-stream");
// 对文件名进行 URL 编码
response.setCharacterEncoding(String.valueOf(StandardCharsets.UTF_8));
String fileName = URLEncoder.encode(file.getName(), String.valueOf(StandardCharsets.UTF_8));
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName);
toClient.write(buffer);
toClient.flush();
} catch (Exception e) {
log.error("下载zip压缩包过程发生异常:", e);
}
第一种方式:使用ZipOutputStream
@Service
@Slf4j
public class ZipDownServiceImpl implements ZipDownService {
@Override
public void down() {
//数据构建
List<ZipDownEntity> zipDownEntitieList = this.buildData();
//按照日期分包--日期后在按照名称
if (CollectionUtils.isEmpty(zipDownEntitieList)){
return;
}
Map<String,Map<String,List<ZipDownEntity>>> map = new HashMap<>();
Map<String, List<ZipDownEntity>> timeMap = zipDownEntitieList.stream().collect(Collectors.groupingBy(ZipDownEntity::getTime));
timeMap.forEach((key, value)->{
Map<String, List<ZipDownEntity>> nameMapValue = value.stream().collect(Collectors.groupingBy(ZipDownEntity::getName));
map.put(key,nameMapValue);
});
this.doDownload(map);
}
private void doDownload(Map<String, Map<String, List<ZipDownEntity>>> map) {
//构建HttpServletResponse
HttpServletResponse response = this.buildHttpServletResponse();
File file = FileUtil.newFile("下载.zip");;
try (FileOutputStream fos = new FileOutputStream(file);
//CheckedOutputStream csum = new CheckedOutputStream(fos, new Adler32());
ZipOutputStream zos = new ZipOutputStream(fos);){
//获取文件和文件存储路径
Set<Map.Entry<String, Map<String, List<ZipDownEntity>>>> entries = map.entrySet();
for (Map.Entry<String, Map<String, List<ZipDownEntity>>> entry : entries) {
//名称路径
for (Map.Entry<String, List<ZipDownEntity>> nameEntity : entry.getValue().entrySet()) {
for (ZipDownEntity data : nameEntity.getValue()) {
//在压缩包中全路径
String folder = entry.getKey() + File.separator //日期
+ nameEntity.getKey() + File.separator //名称
+ data.getFile().getName(); //文件名
zos.write(FileUtil.readBytes(data.getFile()));
zos.putNextEntry(new ZipEntry(folder));
zos.closeEntry();
}
}
}
//下载压缩包
this.downFile(response,file);
} catch (IOException e){
throw new RuntimeException(e);
}finally {
file.delete();
}
}
第二种方式:使用Hutool得ZIP
@Service
@Slf4j
public class ZipDownServiceImpl implements ZipDownService {
@Override
public void down() {
//数据构建
List<ZipDownEntity> zipDownEntitieList = this.buildData();
//按照日期分包--日期后在按照名称
if (CollectionUtils.isEmpty(zipDownEntitieList)){
return;
}
Map<String,Map<String,List<ZipDownEntity>>> map = new HashMap<>();
Map<String, List<ZipDownEntity>> timeMap = zipDownEntitieList.stream().collect(Collectors.groupingBy(ZipDownEntity::getTime));
timeMap.forEach((key, value)->{
Map<String, List<ZipDownEntity>> nameMapValue = value.stream().collect(Collectors.groupingBy(ZipDownEntity::getName));
map.put(key,nameMapValue);
});
this.doDownload(map);
}
private void doDownload(Map<String, Map<String, List<ZipDownEntity>>> map) {
//构建HttpServletResponse
HttpServletResponse response = this.buildHttpServletResponse();
File file = FileUtil.newFile("下载.zip");;
String dir = System.getProperty("user.dir") + File.separator + "myFolder.zip";
//FileUtil.mkdir(dir);
String currentFolder = System.getProperty("user.dir")+File.separator+"myFolder";
List<File> fileList = new ArrayList<>();
try {
//获取文件和文件存储路径
Set<Map.Entry<String, Map<String, List<ZipDownEntity>>>> entries = map.entrySet();
for (Map.Entry<String, Map<String, List<ZipDownEntity>>> entry : entries) {
//名称路径
for (Map.Entry<String, List<ZipDownEntity>> nameEntity : entry.getValue().entrySet()) {
for (ZipDownEntity data : nameEntity.getValue()) {
//在压缩包中全路径
String folder = currentFolder + File.separator
+ entry.getKey() + File.separator //日期
+ nameEntity.getKey() + File.separator + data.getFile().getName();//文件名
//复制到目录
FileUtil.copy(data.getFile(), new File(folder), true);
}
}
}
ZipUtil.zip(currentFolder,dir);
this.downFile(response,new File(dir));
} catch (Exception e){
throw new RuntimeException(e);
}finally {
//删除临时目录
FileUtil.del(currentFolder);
FileUtil.del(dir);
}
}