最近在寫項目接口,涉及到文件下載、打包壓縮下載,單個文件下載還是比較簡單的,多文件下載涉及到打包和壓縮知識,之前也沒做過,寫篇博客做個簡單的記錄一下。閒言少敘,上代碼:
如下代碼是精簡過後的測試代碼,親測可實際使用:
/**
* @author simons.fan
* @version 1.0
* @date 2019/7/9
* @description 文件下載controller
**/
@RestController
@RequestMapping("/file")
public class FileController {
private static final Logger logger = LoggerFactory.getLogger(FileController.class);
@Autowired
private DownLoadService downLoadService;
/**
* 單個文件下載
*
* @param fileName 真實存在的文件名
*/
@GetMapping("/down-one")
public void downOneFile(@RequestParam(value = "filename", required = false) String fileName) {
logger.info("單個文件下載接口入參:[filename={}]", fileName);
if (fileName.isEmpty()) {
return;
}
try {
downLoadService.downOneFile(fileName);
} catch (Exception e) {
logger.error("單個文件下載接口異常:{fileName={},ex={}}", fileName, e);
}
}
/**
* 批量打包下載文件
*
* @param fileName 文件名,多個用英文逗號分隔
*/
@GetMapping("/down-together")
public void downTogether(@RequestParam(value = "filename", required = false) String fileName) {
logger.info("批量打包文件下載接口入參:[filename={}]", fileName);
if (fileName.isEmpty()) return;
List<String> fileNameList = Arrays.asList(fileName.split(","));
if (CollectionUtils.isEmpty(fileNameList)) return;
try {
downLoadService.downTogetherAndZip(fileNameList);
} catch (Exception e) {
logger.error("批量打包文件下載接口異常:{fileName={},ex={}}", fileName, e);
}
}
}
/**
* @author simons.fan
* @version 1.0
* @date 2019/7/9
* @description 文件下載service
**/
@Service
public class DownLoadServiceImpl implements DownLoadService {
private static final Logger logger = LoggerFactory.getLogger(DownLoadServiceImpl.class);
@Value("${file.path}")
private String FILE_ROOT_PATH;
/**
* 單個文件下載
*
* @param fileName 單個文件名
* @throws Exception
*/
@Override
public void downOneFile(String fileName) throws Exception {
HttpServletResponse resp = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
File file = new File(FILE_ROOT_PATH + fileName);
if (file.exists()) {
resp.setContentType("application/x-msdownload");
resp.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes(), "ISO-8859-1"));
InputStream inputStream = new FileInputStream(file);
ServletOutputStream ouputStream = resp.getOutputStream();
byte b[] = new byte[1024];
int n;
while ((n = inputStream.read(b)) != -1) {
ouputStream.write(b, 0, n);
}
ouputStream.close();
inputStream.close();
}
}
/**
* 文件批量打包下載
*
* @param fileNameList 多個文件名,用英文逗號分隔開
* @throws IOException
*/
@Override
public void downTogetherAndZip(List<String> fileNameList) throws IOException {
HttpServletResponse resp = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
resp.setContentType("application/x-msdownload");
//暫時設定壓縮下載後的文件名字爲test.zip
resp.setHeader("Content-Disposition", "attachment;filename=test.zip");
String str = "";
String rt = "\r\n";
ZipOutputStream zos = new ZipOutputStream(resp.getOutputStream());
for (String filename : fileNameList) {
str += filename + rt;
File file = new File(FILE_ROOT_PATH + filename);
zos.putNextEntry(new ZipEntry(filename));
FileInputStream fis = new FileInputStream(file);
byte b[] = new byte[1024];
int n = 0;
while ((n = fis.read(b)) != -1) {
zos.write(b, 0, n);
}
zos.flush();
fis.close();
}
//設置解壓文件後的註釋內容
zos.setComment("download success:" + rt + str);
zos.flush();
zos.close();
}
}
跑起來,測試,ok~
題外話
我們項目使用的是阿里雲的OSS文件服務器,用過的小夥伴會發現,從OSS服務器返回的的是一個"OSSObject"對象,通過OSSObject對象,只能拿到對應的InputStream流,當時剛開始做,想法是直接將這個InputStream流寫入到ZipOutputStream,一直不行。折騰半天,決定將這個InputStream流臨時寫入到運行服務的linux服務器,再來讀這個file,當把這個文件寫入到壓縮對象類ZipOutputStream後,直接刪除這個file即可,順利解決我的問題。