FTP服務器 打包 下載文件

需求:從ftp服務器打包下載文件數據庫

解決步驟:1.從ftp服務器把各個文件下載到本地服務器(通常是安裝tomcat的服務器,項目本身電腦跑的本地服務器就是本身電腦)指定目錄中瀏覽器

2.在本地服務器打包下載好的文件夾打包,返回打包好的File ziptomcat

3.zip文件用流寫入reponse,達到用戶下載效果服務器

準備文件:app

// 封裝全部須要打包下載的文件地址請求類
public class DownloadPackageReq implements Serializable {
    // 本地服務器臨時存放目錄名(儘可能惟一.eg:"menutree20200904112125")
    private String localTempDirName; // 打包下載本地服務器文件夾名字
    private List<DownloadPackageListReq> downloadPackageListReqList; // 須要下載全部文件路徑和名稱
}
// FTPClientUtils:ftp工具類
public static FTPClientUtils init() {
   FTPClientUtils ftp = new FTPClientUtils();
   ftp.setHost(host);
   ftp.setPort(port);
   ftp.setUsername(username);
   ftp.setPassword(password);
   ftp.setBinaryTransfer(true);
   ftp.setPassiveMode(false);
   ftp.setEncoding("utf-8");
   return ftp;
}
/**
 * 下載一個遠程文件到本地的指定文件
 * 
 * @param remoteAbsoluteFile
 *            遠程文件名(包括完整路徑,eg:/MTL/test/menutree_attachment/file.xlsx)
 * @param localAbsoluteFile
 *            本地文件名(包括完整路徑)
 * @param autoClose
 *            是否自動關閉當前鏈接
 * 
 * @return 成功時,返回true,失敗返回false
 * @throws Exception
 */
public boolean get(String remoteAbsoluteFile, String localAbsoluteFile, boolean autoClose) throws Exception {
   OutputStream output = null;
   try {
      output = new FileOutputStream(localAbsoluteFile);
      return get(remoteAbsoluteFile, output, autoClose);
   } catch (FileNotFoundException e) {
      throw new Exception("local file not found.", e);
   } finally {
      try {
         if (output != null) {
            output.close();
         }
      } catch (IOException e) {
         throw new Exception("Couldn't close FileOutputStream.", e);
      }
   }
}
/**
 * 下載一個遠程文件到指定的流 處理完後記得關閉流
 * 
 * @param remoteAbsoluteFile
 * @param output
 * @param autoClose
 * @return
 * @throws Exception
 */
public boolean get(String remoteAbsoluteFile, OutputStream output, boolean autoClose) throws Exception {
   try {
      FTPClient ftpClient = getFTPClient();
      // 處理傳輸
      return ftpClient.retrieveFile(remoteAbsoluteFile, output);
   } catch (IOException e) {
      throw new Exception("Couldn't get file from server.", e);
   } finally {
      if (autoClose) {
         disconnect(); // 關閉連接
      }
   }
}

第一步:工具

public File downloadMenuTreeAttachment(Integer menutreeId) throws Exception {
    // 從數據庫拿到menutreeId對應的全部文件地址
    List<ResourcesMenutreeListVo> resourcesMenutreeLists = resourcesMenutreeListMapper.selExistingAttachment(menutreeId);
    DownloadPackageReq req = new DownloadPackageReq();
    if (CollectionUtils.isNotEmpty(resourcesMenutreeLists)) {
        req.setLocalTempDirName(resourcesMenutreeLists.get(0).getMenutreeName() + DateUtils.dateTimeNow());
        List<DownloadPackageListReq> dpList = new ArrayList<>();
        for(ResourcesMenutreeListVo temp : resourcesMenutreeLists) {
            DownloadPackageListReq dpReq = new DownloadPackageListReq();
            // 文件名稱,用來下載ftp服務器文件修改文件名(由於ftp文件都是uuid名稱)
            String fileName = temp.getModuleName() + "_" + temp.getEngineerName();
            dpReq.setFileName(fileName);
            dpReq.setFileFtpUrl(temp.getMenutreeAttachment());
            dpList.add(dpReq);
        }
        req.setDownloadPackageListReqList(dpList);
    } else {
        req.setLocalTempDirName("空菜單樹" + DateUtils.dateTimeNow());
    }
    return ftpService.zipFiles(req);
}
public File zipFiles(DownloadPackageReq req) throws Exception {
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    // 本地服務器暫存路徑
    String localTempDir = request.getSession().getServletContext().getRealPath("/") + req.getLocalTempDirName() + File.separator;
    logger.info("本地服務器暫存路徑:" + localTempDir);
    File dir = new File(localTempDir);
    if ( ! dir.exists()) {
        dir.mkdir();
    }
    if (CollectionUtils.isNotEmpty(req.getDownloadPackageListReqList())) {
        List<DownloadPackageListReq> downloadList = req.getDownloadPackageListReqList();
        FTPClientUtils ftp = FTPClientUtils.init();
        for(int i=0; i<downloadList.size(); i++) {
            // 是否關閉傳輸流(最後一份文件傳輸完畢關閉)
            boolean isCloseStream = false;
            if (i == downloadList.size() - 1) {
                isCloseStream = true;
            }
            DownloadPackageListReq temp = downloadList.get(i);
            String fileFtpUrl = temp.getFileFtpUrl();
            String suffix = "";
            if (fileFtpUrl.contains(".") && !fileFtpUrl.endsWith(".")) {
                // 文件後綴名
                suffix = fileFtpUrl.substring(fileFtpUrl.lastIndexOf("."));
            }
            // 本地服務器存放完整路徑(包含文件名)
            String localUrl = localTempDir + temp.getFileName() + suffix;
            // 下載的第一個參數遠程路徑若是是FTP服務器,就採用服務器完整文件路徑(eg:/MTL/test/menutree_attachment/file.xlsx),由於初始化ftp服務器就帶了ip端口
            boolean result = ftp.get(temp.getFileFtpUrl(), localUrl, isCloseStream);
        }
    }
    // 打包下載好的文件
    File zipFile = ZipUtil.zip(localTempDir, localTempDir + req.getLocalTempDirName() + ".zip");
    return zipFile;
}

第二步:ui

public class ZipUtil {
    private static Logger logger = Logger.getLogger(ZipUtil.class);

    /**
     * 緩衝器大小
     */
    private static final int BUFFER = 512;

    /**
     * 壓縮方法 (能夠壓縮空的子目錄)
     *
     * @param srcPath     壓縮源路徑
     * @param zipFileName 目標壓縮文件
     * @return
     */
    public static File zip(String srcPath, String zipFileName) {
        ZipOutputStream zipOutputStream = null;
        InputStream inputStream = null;
        File outputZipFile = null;
        try {
            // 檢查文件是否存在,是的話先刪除
            outputZipFile = new File(zipFileName);
            if (outputZipFile.exists()) {
                outputZipFile.delete();
            }

            File srcFile = new File(srcPath);
            List<File> fileList = FileUtil.getAllFiles(srcFile);// 全部要壓縮的文件
            byte[] buffer = new byte[BUFFER];// 緩衝器
            ZipEntry zipEntry = null;
            int readLength = 0;// 每次讀出來的長度
            zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFileName));

            for (File file : fileList) {
                if (file.isFile()) {// 如果文件,則壓縮這個文件
                    zipEntry = new ZipEntry(getRelativePath(srcPath, file));
                    zipEntry.setSize(file.length());
                    zipEntry.setTime(file.lastModified());
                    zipOutputStream.putNextEntry(zipEntry);

                    inputStream = new BufferedInputStream(new FileInputStream(file));

                    while ((readLength = inputStream.read(buffer, 0, BUFFER)) != -1) {
                        zipOutputStream.write(buffer, 0, readLength);
                    }
                } else {// 如果目錄(即空目錄)則將這個目錄寫入zip條目
                    zipEntry = new ZipEntry(getRelativePath(srcPath, file) + File.separator);
                    zipOutputStream.putNextEntry(zipEntry);
                }
            } // end for
        } catch (FileNotFoundException e) {
            logger.error("zip fail!", e);
        } catch (IOException e) {
            logger.error("zip fail!", e);
        } finally {
            close(inputStream);
            close(zipOutputStream);
        }
        // 返回文件輸出流
        outputZipFile = new File(zipFileName);
        return outputZipFile;
    }

    /**
     * 關閉流
     */
    private static void close(Closeable c) {
        if (c == null)
            return;
        try {
            c.close();
        } catch (IOException e) {
            logger.error("close fail!", e);
        }
        c = null;
    }

    /**
     * 取相對路徑 依據文件名和壓縮源路徑獲得文件在壓縮源路徑下的相對路徑
     *
     * @param dirPath 壓縮源路徑
     * @param file
     * @return 相對路徑
     */
    public static String getRelativePath(String dirPath, File file) {
        File dir = new File(dirPath);
        String relativePath = file.getName();
        while (true) {
            file = file.getParentFile();
            if (file == null) {
                break;
            }
            if (file.equals(dir)) {
                break;
            } else {
                relativePath = file.getName() + "/" + relativePath;
            }
        } // end while
        return relativePath;
    }
}

第三步:Controller控制器,Result是本身封裝的返回類,能夠自定義String之類的返回編碼

public Result downloadMenuTreeAttachment(Integer menutreeId, HttpServletResponse response) {
    BufferedInputStream bis = null;
    OutputStream os = null;
    try {
        File file = resourcesMenutreeListService.downloadMenuTreeAttachment(menutreeId);
        response.reset();
        response.setCharacterEncoding("utf-8");
        response.setContentLength((int) file.length());
        // 設置content-disposition響應頭控制瀏覽器如下載的形式打開文件,中文文件名要使用URLEncoder.encode方法進行編碼,不然會出現文件名亂碼
        response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
        bis = new BufferedInputStream(new FileInputStream(file));
        os = response.getOutputStream();
        byte[] buff = new byte[1024];
        int i = 0;
        while ((i = bis.read(buff)) != -1) {
            os.write(buff, 0, i);
            os.flush();
        }
    } catch (Exception e) {
        log.error("{}",e);
        return ResultGenerator.genFailResult("下載失敗");
    } finally {
        try {
            bis.close();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return ResultGenerator.genSuccessResult();
}

最後:spa

相關文章
相關標籤/搜索