具体代码
实体类:
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@TableName("lpn_photo")
@ApiModel
public class LpnPhotoEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
@ApiModelProperty("主键ID")
@TableField("id")
private Integer id;
/**
* 仓库编码
*/
@ApiModelProperty("仓库编码")
@TableField("warehouse_code")
private String warehouseCode;
/**
* 入仓预报id
*/
@ApiModelProperty("入仓预报id")
@TableField("warehousing_notify_id")
private Integer warehousingNotifyId;
/**
* 柜号/集装箱编码
*/
@ApiModelProperty("柜号/集装箱编码")
@TableField("container_no")
private String containerNo;
/**
* LPN
*/
@ApiModelProperty("LPN")
@TableField("lpn")
private String lpn;
/**
* SKU长度照片
*/
@ApiModelProperty("SKU长度照片")
@TableField("photo1")
private String photo1;
/**
* SKU宽度照片
*/
@ApiModelProperty("SKU宽度照片")
@TableField("photo2")
private String photo2;
/**
* SKU高度照片
*/
@ApiModelProperty("SKU高度照片")
@TableField("photo3")
private String photo3;
/**
* SKU重量照片
*/
@ApiModelProperty("SKU重量照片")
@TableField("photo4")
private String photo4;
/**
* 创建时间
*/
@ApiModelProperty("创建时间")
@TableField(value = "created_datetime", fill = FieldFill.INSERT)
private LocalDateTime createdDatetime;
/**
* 更新时间
*/
@ApiModelProperty("更新时间")
@TableField(value = "updated_datetime", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updatedDatetime;
}
工具类:
import com.opene.config.exception.ResultException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@Component
@Slf4j
public class ZipUtil {
public static void zip(ZipOutputStream zipOutputStream, String fileName, byte[] bytes) {
try {
ZipEntry zipEntry = new ZipEntry(fileName);
zipOutputStream.putNextEntry(zipEntry);
zipOutputStream.write(bytes);
} catch (Exception e) {
log.info("抛出异常后跳过,继续向下执行");
}
}
public static ZipOutputStream getZipOutputStream(HttpServletResponse response, String fileName) {
try {
ZipOutputStream zipOutputStream = null;
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".zip");
zipOutputStream = new ZipOutputStream(response.getOutputStream());
return zipOutputStream;
} catch (Exception e) {
throw new ResultException("获取ZipOutputStream异常");
}
}
}
使用类案例:
Controller
@PostMapping("/downloadImages")
@ApiOperation("下载图片")
public void download(@Validated @RequestBody TallyLpnDownLoadReqVo vo, HttpServletResponse response) throws IOException {
tallyService.tallyLpnPhotoDownload(vo.getLpnPhotoIds(), response);
}
Service
void tallyLpnPhotoDownload(List<Integer> lpnPhotoIds, HttpServletResponse response);
ServiceImpl:
@Override
public void tallyLpnPhotoDownload(List<Integer> lpnPhotoIds, HttpServletResponse response) {
List<LpnPhotoEntity> list = lpnPhotoService.queryByIds(lpnPhotoIds);
if (CollectionUtils.isEmpty(list)) {
throw new ResultException("No images to download");
}
Map<String, List<LpnPhotoEntity>> collect = list.stream().collect(Collectors.groupingBy(LpnPhotoEntity::getContainerNo));
ZipOutputStream zipOutputStream = null;
try {
// 最外层的ZIP名称
String filename = URLEncoder.encode("tally_lpn", "UTF-8");
zipOutputStream = ZipUtil.getZipOutputStream(response, filename);
List<CompletableFuture<Map<String, byte[]>>> futures = new ArrayList<>();
collect.forEach((k, v) -> {
CompletableFuture<Map<String, byte[]>> overallFuture = CompletableFuture.supplyAsync(() -> {
Map<String, byte[]> map = new HashMap<>();
// ZIP包第一层的文件夹名称
String path = String.format("%s/", k);
for (LpnPhotoEntity lpnPhoto : v) {
if (StringUtils.isNotBlank(lpnPhoto.getPhoto1())) {
String photo1 = lpnPhoto.getPhoto1();
String suffix = photo1.substring(photo1.lastIndexOf("."));
// 这里设置LPN为第二层文件夹,如果第二层文件夹一致,则会自动归类
String pathName = String.format("%s%s/photo1%s", path, lpnPhoto.getLpn(), suffix);
byte[] bytes = gcloudStorageUtil.publicGetBytes(photo1, Constant.wms);
map.put(pathName, bytes);
}
if (StringUtils.isNotBlank(lpnPhoto.getPhoto2())) {
String photo2 = lpnPhoto.getPhoto2();
String suffix = photo2.substring(photo2.lastIndexOf("."));
String pathName = String.format("%s%s/photo2%s", path, lpnPhoto.getLpn(), suffix);
byte[] bytes = gcloudStorageUtil.publicGetBytes(photo2, Constant.wms);
map.put(pathName, bytes);
}
if (StringUtils.isNotBlank(lpnPhoto.getPhoto3())) {
String photo3 = lpnPhoto.getPhoto3();
String suffix = photo3.substring(photo3.lastIndexOf("."));
String pathName = String.format("%s%s/photo3%s", path, lpnPhoto.getLpn(), suffix);
byte[] bytes = gcloudStorageUtil.publicGetBytes(photo3, Constant.wms);
map.put(pathName, bytes);
}
if (StringUtils.isNotBlank(lpnPhoto.getPhoto4())) {
String photo4 = lpnPhoto.getPhoto4();
String suffix = photo4.substring(photo4.lastIndexOf("."));
String pathName = String.format("%s%s/photo4%s", path, lpnPhoto.getLpn(), suffix);
byte[] bytes = gcloudStorageUtil.publicGetBytes(photo4, Constant.wms);
map.put(pathName, bytes);
}
}
return map;
}, asyncServiceExecutor);
futures.add(overallFuture);
});
if (CollectionUtils.isEmpty(futures)) {
return;
}
for (CompletableFuture<Map<String, byte[]>> future : futures) {
Map<String, byte[]> map = future.get();
for (Map.Entry<String, byte[]> m : map.entrySet()) {
ZipUtil.zip(zipOutputStream, m.getKey(), m.getValue());
}
}
zipOutputStream.flush();
zipOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (Objects.nonNull(zipOutputStream)) {
try {
zipOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
ZIP文件层级图
zip包
第一层文件夹
第二层文件夹
第三层的文件
欢迎关注公众号:慌途L
后面会慢慢将文章迁移至公众号,也是方便在没有电脑的情况下可以进行翻阅,更新的话会两边同时更新,大家不用担心!