前言
最近负责了一个需求:每天定时拉取第三方报表数据,生成文件,并可以查看、下载、压缩打包。
遂单独记录下springmvc中文件的上传、下载和压缩打包这三个工作常用功能。
版本信息:
<springcloud.version>Greenwich.SR2</springcloud.version>
<springboot.version>2.1.7.RELEASE</springboot.version>
(<spring.version>5.1.9.RELEASE</spring.version>)
文件上传
- 单文件上传
//单文件上传
@RequestMapping("/upload")
@ResponseBody
public BaseResult upload(@RequestParam("file") MultipartFile file) {
//文件信息获取
String fileName = file.getOriginalFilename();
long size = file.getSize()/1024; //单位 B>KB
String contentType = file.getContentType();
logger.info(">> file info to upload: {}, {}KB, {}", fileName, size, contentType);
//目录生成与新文件名
String newFileName = currDateStr.substring(8, currDateStr.length()) + "_" + fileName;
String dateDir = currDateStr.substring(0, 8); //20191220
File destDir = new File(upload_fspath_base, dateDir);// /xxx/upload/20191220
if(!destDir.exists()) {
destDir.mkdirs(); //注意不是mkdir
}
//文件写入
try {
file.transferTo(new File(destDir, newFileName));
} catch (IllegalStateException | IOException e) {
logger.error("保存上传文件出错!", e);
throw new BusinessException("保存上传文件出错!", e);
}
return BaseResult.succ();
}
- 多文件上传
//多文件上传
@RequestMapping("/uploads")
@ResponseBody
public BaseResult uploads(@RequestParam("files") MultipartFile[] files) {
int succSize = Arrays.stream(files).map(this::upload).collect(Collectors.toList()).size();
return BaseResult.succData(succSize);
}
- 注意:springboot预设的上传大小限制为10MB,对应配置项为
spring.servlet.multipart.max-file-size=200MB
spring.servlet.multipart.max-request-size=200MB
文件下载
- 方式1,使用 springmvc 的 ResponseEntity
//文件下载
@RequestMapping("/download/{code}")
public ResponseEntity<Resource> download(@PathVariable String code) { //上传下载码(唯一码)
//查找上传记录
UploadFileInfo fileInfo = uploadFileInfoRepo.findByUploadCode(code);
if(Objects.nonNull(fileInfo)) {
Resource resource = null;
String contentType = null;
try {
//load file as Resource
if(!RichardUtil.isStrEmpty(fileInfo.getFsPath())) {
resource = new FileSystemResource(new File(fileInfo.getFsPath()));
}else {
resource = new UrlResource(fileInfo.getSrcPath());
}
contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath());
} catch (IOException e) {
logger.error(code, e);
throw new BusinessException("资源读取异常!", e);
}
if(Objects.isNull(contentType)) contentType = "application/octet-stream";
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(contentType))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="" + fileInfo.getFileName() + """)
.body(resource);
}else {
throw new BusinessException("资源未找到!");
}
}
- 方式2,传统的 HttpServletResponse
见压缩示例一起
文件压缩/打包下载
- 意外发现使用传统的 response 更简洁好用,使用 springmvc 的 ResponseEntity 的话修改返回类型即可
org.springframework.core.io.Resource
很好用- 代码
/**
* 文件(压缩打包)下载,传统response版
*/
@RequestMapping("/manage-api/download/zip5s")
@ResponseBody
public void zip5s() {
List<UploadFileInfo> collect5 = uploadFileInfoRepo.findAll().stream().limit(5).collect(Collectors.toList());
String showName = RichardUtil.getCurrentDatetimeStrNoFlag() + ".zip";
//java7 资源自动关闭语法糖
try(ZipOutputStream out = new ZipOutputStream(response.getOutputStream())){
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="" + showName + """);
response.setContentType("application/octet-stream");
for(UploadFileInfo o:collect5) {
//load file resource
Resource resource = RichardUtil.isStrEmpty(o.getFsPath())?new UrlResource(o.getSrcPath()):new FileSystemResource(o.getFsPath());
//添加压缩
out.putNextEntry(new ZipEntry(o.getFileName()));
//写入(方法封装,目的流暂不关闭)
RichardUtil.dump_dest_not_close(resource.getInputStream(), out);
}
} catch (IOException e) {
logger.error(">> zip压缩打包异常", e);
throw new BusinessException(e);
}
}