Recently, I am working on a project, which involves file download and package compression download. Single file download is relatively simple. Multi file download involves package and compression knowledge, which I haven't done before. Write a blog to make a simple record. Less gossip, code:
The following codes are test codes, which can be used in practice:
/** * @author renxiang.fan * @version 1.0 * @date 2019/7/9 * @description File download controller **/ @RestController @RequestMapping("/file") public class FileController { private static final Logger logger = LoggerFactory.getLogger(FileController.class); @Autowired private DownLoadService downLoadService; /** * Single file download * * @param fileName Real file name */ @GetMapping("/down-one") public void downOneFile(@RequestParam(value = "filename", required = false) String fileName) { logger.info("Input parameter of single file download interface:[filename={}]", fileName); if (fileName.isEmpty()) { return; } try { downLoadService.downOneFile(fileName); } catch (Exception e) { logger.error("Single file download interface exception:{fileName={},ex={}}", fileName, e); } } /** * Bulk package download file * * @param fileName File names, multiple separated by commas */ @GetMapping("/down-together") public void downTogether(@RequestParam(value = "filename", required = false) String fileName) { logger.info("Batch packaging file download interface input:[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("Exception in downloading interface of bulk package file:{fileName={},ex={}}", fileName, e); } } }
/** * @author renxiang.fan * @version 1.0 * @date 2019/7/9 * @description File download service **/ @Service public class DownLoadServiceImpl implements DownLoadService { private static final Logger logger = LoggerFactory.getLogger(DownLoadServiceImpl.class); @Value("${file.path}") private String FILE_ROOT_PATH; /** * Single file download * * @param fileName Single file name * @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(); } } /** * File bulk packaging and downloading * * @param fileNameList Multiple file names separated by commas * @throws IOException */ @Override public void downTogetherAndZip(List<String> fileNameList) throws IOException { HttpServletResponse resp = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse(); resp.setContentType("application/x-msdownload"); //Temporarily set the name of the compressed download file to 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(); } //Set the comment content after decompressing the file zos.setComment("download success:" + rt + str); zos.flush(); zos.close(); } }
Run, test, ok~
Digression
The OSS file server of Alibaba cloud is used in our project. The used partners will find that what is returned from the OSS server is an "OSSObject" object. Through the OSSObject object, only the corresponding InputStream can be obtained. At that time, we just started to do it. The idea is to write the InputStream directly to ZipOutputStream, which has not been possible. After half a day's tossing, I decided to temporarily write the InputStream to the linux server running the service, and then read the file. When I write the file to the ZipOutputStream class, I can delete the file directly and solve my problem successfully.