1. 程式人生 > >POI匯出時寫一份到ftp伺服器,一份下載給客戶端 ftp伺服器搭建(離線安裝vsftpd),配置 poi實現百萬級資料匯出 oi實現百萬級資料匯出

POI匯出時寫一份到ftp伺服器,一份下載給客戶端 ftp伺服器搭建(離線安裝vsftpd),配置 poi實現百萬級資料匯出 oi實現百萬級資料匯出

導語:

  昨天接到專案經理這麼一個需求,讓我在POI匯出Excel的時候寫一份到我之前搭建的ftp伺服器上。所以就有了這篇部落格首先我們來分析下之前的業務邏輯:我們建立並構造了一個workbook,然後構建了一個OutputStream輸出流,然後我們把資料寫入輸出流中就可以被客戶端下載。

  現在我們要在此基礎上寫一份到ftp伺服器

  那麼我們就需要兩個流,首先一個輸入流把檔案寫到ftp伺服器,然後需要一個輸出流把檔案輸出到客戶端。千萬不要用workbook.write(out)一份到客戶端,然後又workbook.write(in)一份到ftp,會報錯的。Stream is closed,(為啥報錯,我也解釋不清希望大神解惑一下)

  正確思路應該是先寫一份到ftp伺服器,然後再讀取這個檔案,然後再把這個檔案輸出給客戶端

參考:

ftp伺服器搭建(離線安裝vsftpd),配置

poi實現百萬級資料匯出

來看程式碼吧:

1. 我們只需要對 oi實現百萬級資料匯出 中的 CommentController  稍作修改,然後配合一些工具類就可以實現

/**
     * excel匯出功能
     * @param commentSearch
     * @param response
     * @param request
     * @return
     * @throws Exception
     
*/ @RequestMapping("/exportCommentInfo") @ResponseBody @NoRepeatRequest public BaseDTO exportCommentInfo(CommentSearch commentSearch, HttpServletResponse response, HttpServletRequest request) throws Exception{ LOGGER.info("CommentController.exportCommentInfo start"); long
startTime = System.currentTimeMillis(); LOGGER.info("開始下載........................................."); List<ErrorInfo> errors = null; int result = 0; String fileName = FileNameUtils.getExportCommontExcelFileName(); OutputStream fileOut = null; SXSSFWorkbook workbook = null; try { LOGGER.debug("classpath: " + fileName); workbook = new SXSSFWorkbook(10000); commentService.exportCommentInfo(request,workbook, commentSearch); // 定義excel檔名 response.setCharacterEncoding("UTF-8"); response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(fileName, "UTF-8") + "\""); // 定義輸出流 fileOut = response.getOutputStream(); // 呼叫匯出方法 //workbook.write(fileOut); //寫一份到ftp伺服器 ByteArrayOutputStream os = new ByteArrayOutputStream(); workbook.write(os); byte[] b = os.toByteArray(); ByteArrayInputStream in = new ByteArrayInputStream(b);
FtpUtil.uploadFileToFtp(fileName,in,fileOut);
       workbook.dispose(); }
catch (Exception e) { LOGGER.error("InterfaceInfoController.exportInterfaceInfo Exception: ", e); ErrorInfo errorInfo = new ErrorInfo("system.error", "系統異常!"); errors = Arrays.asList(errorInfo); request.getSession().setAttribute("exportStatus","error"); }finally { fileOut.close(); workbook.close(); } LOGGER.info("下載完成....|||||.......用時:" + (System.currentTimeMillis() - startTime)); return tranferBaseDTO(errors, result); }

1.首先把workbook寫到 ByteArrayOutputStream 輸出流中,然後轉換成 位元組陣列 byte[] b 在轉換成 ByteArrayInputStream 輸入流用來寫入ftp

       ByteArrayOutputStream os = new ByteArrayOutputStream();
            workbook.write(os);
            byte[] b = os.toByteArray();
            ByteArrayInputStream in = new ByteArrayInputStream(b);
            FtpUtil.uploadFileToFtp(fileName,in,fileOut);

2.然後轉換成 位元組陣列  在轉換成輸入流用來寫入ftp ,主要看這幾個方法

/**
     * 上傳過載 二進位制流
     * @param filename
     * @param input
     * @return
     */
    public static boolean uploadFileToFtp(String filename, ByteArrayInputStream input, OutputStream fileOut) {
        getPropertity();
        return uploadFileToFtp( host,  port,  username,  password,  basePath,
                filePath,  filename,  input, fileOut);
    }

  /**
     * Description: 向FTP伺服器上傳檔案 二進位制流檔案
     * @param host FTP伺服器hostname
     * @param port FTP伺服器埠
     * @param username FTP登入賬號
     * @param password FTP登入密碼
     * @param basePath FTP伺服器基礎目錄
     * @param filePath FTP伺服器檔案存放路徑。例如分日期存放:/2015/01/01。檔案的路徑為basePath+filePath
     * @param filename 上傳到FTP伺服器上的檔名
     * @return 成功返回true,否則返回false
     */
    public static boolean uploadFileToFtp(String host, String port, String username, String password, String basePath,
                                     String filePath, String filename, ByteArrayInputStream input, OutputStream fileOut) {
        FTPClient ftp = new FTPClient();
        try {
            //開啟ftp連線
            boolean result = connectFtp(ftp, host, port, username, password, basePath, filePath);
            if(!result){
                return result;
            }
            if (FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
                // 開啟伺服器對UTF-8的支援,如果伺服器支援就用UTF-8編碼,否則就使用本地編碼(GBK).
                    if (FTPReply.isPositiveCompletion(ftp.sendCommand("OPTS UTF8", "ON"))) {
                        LOCAL_CHARSET = "UTF-8";
                    }
            }
       //防止中文亂碼 filename
= new String(filename.getBytes(LOCAL_CHARSET),SERVER_CHARSET ); //為了加大上傳檔案速度,將InputStream轉成BufferInputStream , InputStream input BufferedInputStream in = new BufferedInputStream(input); //加大快取區 ftp.setBufferSize(1024*1024); //設定上傳檔案的型別為二進位制型別 ftp.setFileType(FTP.BINARY_FILE_TYPE); //上傳檔案 if (!ftp.storeFile(filename, in)) { return false; } //寫一份給客戶端 FTPFile[] fs = ftp.listFiles(); for (FTPFile ff : fs) { if (ff.getName().equals(filename)) { ftp.retrieveFile(ff.getName(), fileOut); fileOut.close(); } } in.close(); ftp.logout(); } catch (IOException e) { e.printStackTrace(); } finally { if (ftp.isConnected()) { try { ftp.disconnect(); } catch (IOException ioe) { } } } return true; } /** * 連線ftp伺服器並切換到目的目錄 * 呼叫此方法需手動關閉ftp連線 * @param ftp * @param host * @param port * @param username * @param password * @param basePath * @param filePath * @return */ private static boolean connectFtp( FTPClient ftp,String host, String port, String username, String password, String basePath, String filePath){ boolean result = false; try { int portNum = Integer.parseInt(port); int reply; // 連線FTP伺服器 ftp.connect(host, portNum); // 如果採用預設埠,可以使用ftp.connect(host)的方式直接連線FTP伺服器 ftp.login(username, password); reply = ftp.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftp.disconnect(); return result; } //切換到上傳目錄 if (!ftp.changeWorkingDirectory(basePath+filePath)) { //如果目錄不存在建立目錄 String[] dirs = filePath.split("/"); String tempPath = basePath; for (String dir : dirs) { if (null == dir || "".equals(dir)) { continue; } tempPath += "/" + dir; if (!ftp.changeWorkingDirectory(tempPath)) { if (!ftp.makeDirectory(tempPath)) { return result; } else { ftp.changeWorkingDirectory(tempPath); } } } } result = true; } catch (IOException e) { e.printStackTrace(); } return result; } }

主要是  我們為了加快檔案上傳速度把剛才傳入的 ByteArrayInputStream 轉換成了  BufferedInputStream 

BufferedInputStream in = new BufferedInputStream(input);

然後我們把  BufferedInputStream 寫入到ftp伺服器

ftp.storeFile(filename, in)

到這裡第一步就完成了,接下來是從伺服器下載我們剛才上傳 檔案,然後通過剛才傳入的 輸出流 fileOut 輸出到客戶端

 //寫一份給客戶端
 FTPFile[] fs = ftp.listFiles();
 for (FTPFile ff : fs) {
     if (ff.getName().equals(filename)) {
             ftp.retrieveFile(ff.getName(), fileOut);
             fileOut.close();
       }
}