1. Application scenarios

Document management module, list of records displayed daily file upload saved records. Each data field stores the storage address of the file on the file server

Now you need to batch download the list data, download multiple files together and put them together as a zip package to download to the browser

2. Development ideas

Because some need to be classified according to a save and download, because there may be multiple folders, all can’t go directly after each file of flow form to package it, so here with the method of first download, will network file according to the given rules to create folders on the local temporary directory, and then to read and write files into a compressed stream to download.

According to their actual business, due to the need to batch download the file together more than 300 MB, so the use of two split service, first request download interface, use multithreading download to the server temporary directory, and then intervals a period of time to request download services

2.1 Download Files in batches to temporary Directories

  1. The controller layer
    @GetMapping("step/imgs/download/{id}")
    @apiOperation (value = "Download the image of the specified inspection task to the local directory ")
    public ResponseEntity uploadToLocal(@PathVariable("id") Integer id) {
        // This step gets the download information set based on the individual's business
        Map<String,  List<PatrolTaskPointStepImgVO>> imgMap = exportService.getImgMap(id);
        exportService.imgTolocal(imgMap);
        return ResponseEntity.ok(Please visit /step/imgs/download in 5 minutes. Id =, download file");
    }

Copy the code
  1. imgMapData structure description:
  • Key: indicates the folder name
  • Value: stores the file data table

Fields are as follows

@APIModelProperty (value = "ID ") private Integer ID; @APIModelProperty (value = "Inspection Task Step table ID ") private Integer taskPointStepId; @APIModelProperty (value = "imgUrl ") private String imgUrl; @APIModelProperty (value = "thumbnail URL ") private String imgThumbnailUrl; @APIModelProperty (value = "type 0: image, 1: video ") private Integer type; private String pointName; private String stepName;Copy the code
  1. servicelayer
void imgTolocal(Map<String, List<PatrolTaskPointStepImgVO>> res);

Copy the code
  1. serviceThe implementation class
    @Override
    public void imgTolocal(Map<String, List<PatrolTaskPointStepImgVO>> res) {
        index = 0;
        if(res == null || res.isEmpty()){
            throw new BadRequestAlertException("has_not_imgList" ,this.getClass().getSimpleName(),"has_not_imgList");
        }
        // Obtain the system temporary storage address
        Path path = Paths.get(System.getProperty("java.io.tmpdir"),this.TaskName);
        File file = new File(String.valueOf(path));
        if(! file.exists()){ file.mkdirs(); }try {
            log.info("Start downloading file :{}", sdf.format(new Date()));
            res.forEach((k,v) -> {
                new Thread (() -> {
                    index++;
                    log.info("Start executing download thread {}", index);
                    File fl = new File(String.valueOf(path) + File.separator + k);
                    if(! fl.exists()) { fl.mkdirs(); }if(! CollectionUtils.isEmpty(v)) { v.stream().forEach(e -> {try {
                                log.info("Start downloading image resource ID {}", e.getImgUrl());
                                download(e.getImgUrl(), e.getStepName() + e.getId(), fl.getPath());
                            } catch(Exception e1) { e1.printStackTrace(); }}); } }).start(); }); }catch (Exception e) {
            e.printStackTrace();
        } finally {
            log.info("All files downloaded completed" ,sdf.format(newDate())); }}private void download(String urlString, String filename,String savePath) throws Exception {
        URL url = new URL(urlString);
        URLConnection con = url.openConnection();
        // Set the request timeout to 5s
        con.setConnectTimeout(5*1000);
        / / input stream
        InputStream is = con.getInputStream();
        // 1K data buffer
        byte[] bs = new byte[1024];
        // The length of the data read
        int len;
        // Output file stream
        File sf=new File(savePath);
        if(! sf.exists()){ sf.mkdirs(); } String extensionName = urlString.substring(urlString.lastIndexOf("."));
        String newFileName = filename + extensionName;
        OutputStream os = new FileOutputStream(sf.getPath()+ File.separator +newFileName);
        // Start reading
        while((len = is.read(bs)) ! = -1) {
            os.write(bs, 0, len);
        }
        os.close();
        is.close();
    }
Copy the code

2.2 Converting Files from the System Temporary Directory and downloading them from the Browser (Temporary files are automatically deleted when you create a scheduled task)

  1. controller
    @GetMapping("/step/imgs/download")
    @ApiOperation(value = "Download the specified inspection resources into a compressed package in the browser ")
    public void uploadStepImg (
        @APIParam (value = "Inspection task ID", Required = true) @RequestParam(value = "id") Integer id,
        HttpServletResponse response
    ){
        Map<String,  List<PatrolTaskPointStepImgVO>> imgMap = exportService.getImgMap(id);
        exportService.imgToZip(imgMap ,response);
    }

Copy the code
  1. service
void imgToZip(Map<String, List<PatrolTaskPointStepImgVO>> res , HttpServletResponse response);
Copy the code

3. Service realization

    @Override
    public void imgToZip(Map<String, List<PatrolTaskPointStepImgVO>> res , HttpServletResponse response) {
        // Obtain the system temporary storage address
        if(res == null || res.isEmpty()){
            throw new BadRequestAlertException("has_not_imgList" ,this.getClass().getSimpleName(),"has_not_imgList");
        }
        Path path = Paths.get(System.getProperty("java.io.tmpdir"),this.TaskName);
        File file = new File(String.valueOf(path));
        if(! file.exists()){throw new BadRequestAlertException("No relevant documents found.".this.getClass().getSimpleName(),"No relevant documents found.");
        }
        chenkFile(file ,String.valueOf(path));
        zip(String.valueOf(path) ,response);

    }
    
    public void chenkFile(File file,String path){
        try {
            if (file.exists()){
                // If the file does not exist
                if (!file.isDirectory()){
                    file.createNewFile();
                }
            }else {
                // If the directory does not exist
                // Create the specified directory file object
                File file1 = new File(path);
                file1.mkdirs();// Create directory
                file.createNewFile();// Create a file}}catch(IOException e) { log.error(e.getMessage(),e); }}public void zip(String sourceFileName, HttpServletResponse response){
        ZipOutputStream out = null;
        BufferedOutputStream bos = null;
        log.info("Start compression :{}", sdf.format(new Date()));
        File sourceFile = new File(sourceFileName);
        try {
            // Outputs the zip as a stream to the foreground
            response.setHeader("content-type"."application/octet-stream");
            response.setCharacterEncoding("utf-8");
            // Set content-disposition for the browser response header
            TestZip indicates the file name of the compressed package, and. Zip indicates the file suffix
            response.setHeader("Content-disposition"."attachment; filename=" + new String(this.TaskName.getBytes("gbk"), "iso8859-1") +".zip");
            // Create zip output stream
            out = new ZipOutputStream(response.getOutputStream());
            // Create a buffered output stream
            bos = new BufferedOutputStream(out);
            // Call compression
            compress(out, bos, sourceFile, sourceFile.getName());
            out.flush();
            log.info("Compression done :{}" ,sdf.format(new Date()));
        } catch (Exception e) {
            log.error("Abnormal ZIP compression:"+e.getMessage(),e);
        } finally {
           try {
               if(bos ! =null) {
                   bos.close();
               }
               if( out ! =null) { out.close(); }}catch (IOException e) {
               e.printStackTrace();
           }
           Timer After the Timer task is completed, the thread is not actively closed but waits for gc collection
            new Thread( () -> {
                try {
                    Thread.sleep(1000*60*30);
                    deleteFile(sourceFile);
                } catch(InterruptedException e) { e.printStackTrace(); }}); }}public static void compress(ZipOutputStream out, BufferedOutputStream bos, File sourceFile, String base){
        FileInputStream fos = null;
        BufferedInputStream bis = null;
        try {
            // If the path is a directory (folder)
            if (sourceFile.isDirectory()) {
                // Retrieve files from folders (or subfolders)
                File[] flist = sourceFile.listFiles();
                // If the folder is empty, just write a directory entry point in the destination ZIP file
                if (flist.length == 0) {
                    out.putNextEntry(new ZipEntry(base + File.separator));
                } else {
                    // If the folder is not empty, compress is recursively called and every file (or folder) in the folder is compressed
                    for (int i = 0; i < flist.length; i++) { compress(out, bos, flist[i], base + File.separator + flist[i].getName()); }}}else {
                // If it is not a directory (folder), that is, a file, the directory entry point is written first, then the file is written to the zip file
                out.putNextEntry(new ZipEntry(base));
                fos = new FileInputStream(sourceFile);
                bis = new BufferedInputStream(fos);
                byte []  buffer = new byte[1024];
                int tag;
                // Write the source file to the zip file
                while((tag = bis.read(buffer)) ! = -1) {
                    out.write(buffer, 0,tag); }}}catch (Exception e) {
            e.printStackTrace();
        } finally{}}private void deleteFile(File file) {
        if (file.exists()) {
            if (file.isFile()) {
                file.delete();
                log.info("Deleting file {}" ,file.getName());
            } else if (file.isDirectory()) {
                File[] files = file.listFiles();
                for (int i = 0; i < files.length; i++) {
                    this.deleteFile(files[i]);
                }
                file.delete();
                log.info("Deleting file {}",file.getName()); }}else {
            System.out.println("Deleted file does not exist"); }}Copy the code