POI导出时写一份到ftp服务器,一份下载给客户端

Posted 隔壁w王叔叔

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POI导出时写一份到ftp服务器,一份下载给客户端相关的知识,希望对你有一定的参考价值。

导语:

  昨天接到项目经理这么一个需求,让我在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();
       }
}

 

以上是关于POI导出时写一份到ftp服务器,一份下载给客户端的主要内容,如果未能解决你的问题,请参考以下文章

MaridDB主从复制,双主模型,半同步的配置

如何在python中用markdown语言写一份报告并输出成PDF格式

服务器日志—wp—青少年CTF

poi复杂excel的实现

如何写一份让面试官眼前一亮的简历?

Pr制作中英文双语字幕教程