记一次导出Excel的升级过程

1、2003的Excel(HSSFWorkbook)升级为2007版本(SXSSFWorkbook)的
2、多文件生成临时文件批量暂存服务器,然后再压缩文件生成zip包下载.
3、下载后文件命名兼容火狐浏览器,解决了乱码问题

ZipFileUtil工具类

package cn.tools;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Base64Utils;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static cn.tools.DateHelper.getNowDate;

@SuppressWarnings("restriction")
public class ZipFileUtil {

    private static final Logger logger = LoggerFactory.getLogger(ZipFileUtil.class);

    /**
     * 编译下载的文件名
     * @param fileName
     * @param agent
     * @return
     * @throws IOException
     */
    public static String encodeDownloadFilename(String fileName, String agent)throws IOException {
        if (agent.contains("Firefox")) { // 火狐浏览器
            fileName = "=?UTF-8?B?" + (new String(Base64Utils.encodeToString(fileName.getBytes("UTF-8")))) + "?=";
        } else { // IE及其他浏览器
            fileName = URLEncoder.encode(fileName, "utf-8");
            fileName = fileName.replace("+"," ");
        }
        return fileName;
    }

    /**
     * 创建文件夹;
     * @param path
     */
    public static void createFile(String path) {
        File file = new File(path);
        //判断文件是否存在;
        if (!file.exists()) {
            //创建文件;
            file.mkdirs();
        }
    }

    /**
     * 生成.zip文件;
     * @param path
     * @throws IOException
     */
    public static ZipOutputStream craeteZipPath(String path) throws IOException{
        ZipOutputStream zipOutputStream = null;
        File file = new File(path+getNowDate(DateHelper.FMT_DATE_YYYY_MM_DD)+".zip");
        zipOutputStream = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
        File[] files = new File(path).listFiles();
        FileInputStream fileInputStream = null;
        byte[] buf = new byte[1024];
        int len = 0;
        if(files!=null && files.length > 0){
            for(File excelFile:files){
                String fileName = excelFile.getName();
                fileInputStream = new FileInputStream(excelFile);
                //放入压缩zip包中;
                zipOutputStream.putNextEntry(new ZipEntry(path + "/"+fileName));
                //读取文件;
                while((len=fileInputStream.read(buf)) >0){
                    zipOutputStream.write(buf, 0, len);
                }
                //关闭;
                zipOutputStream.closeEntry();
                if(fileInputStream != null){
                    fileInputStream.close();
                }
            }
        }
        return zipOutputStream;
    }


    /**
     * //压缩文件
     * @param srcfile   要压缩的文件数组
     * @param zipfile  生成的zip文件对象
     */
    public static void ZipFiles(java.io.File[] srcfile, File zipfile) throws Exception {
        byte[] buf = new byte[1024];
        FileOutputStream fos = new FileOutputStream(zipfile);
        ZipOutputStream out = new ZipOutputStream(fos);
        for (int i = 0; i < srcfile.length; i++) {
            FileInputStream in = new FileInputStream(srcfile[i]);
            out.putNextEntry(new ZipEntry(srcfile[i].getName()));
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
            out.closeEntry();
            in.close();
        }
        out.close();
        fos.flush();
        fos.close();
    }

    /**
     * 删除文件夹及文件夹下所有文件
     * @param dir
     * @return
     */
    public static boolean deleteDir(File dir) {
        if (dir == null || !dir.exists()){
            return true;
        }
        if (dir.isDirectory()) {
            String[] children = dir.list();
            //递归删除目录中的子目录下
            for (int i=0; i<children.length; i++) {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
        // 目录此时为空,可以删除
        return dir.delete();
    }

    /**
     * 生成html
     * @param msg
     * @return
     * @author zgd
     * @time 2018年6月25日11:47:07
     */
    public static String getErrorHtml(String msg) {
        StringBuffer sb = new StringBuffer();
        sb.append("<html>");
        sb.append("<head>");
        sb.append("<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>");
        sb.append("</head>");
        sb.append("<body>");
        sb.append("<div id='errorInfo'> ");
        sb.append("</div>");
        sb.append("<script>alert('"+msg+"')</script>");
        sb.append("</body>");
        sb.append("</html>");
        return sb.toString();
    }


    /**
     * 设置下载excel的响应头信息
     * @param response
     * @param request
     * @param fileName
     * @throws IOException
     * @author zgd
     * @time 2018年6月25日11:47:07
     */
    public static void setExcelHeadInfo(HttpServletResponse response, HttpServletRequest request, String fileName)  {
        try {
            // 获取客户端浏览器的类型
            String agent = request.getHeader("User-Agent");
            // 对文件名重新编码
            String encodingFileName = ZipFileUtil.encodeDownloadFilename(fileName, agent);
            // 告诉客户端允许断点续传多线程连接下载
            response.setHeader("Accept-Ranges", "bytes");
            //文件后缀
            response.setContentType("application/vnd.ms-excel;charset=UTF-8");
            response.setHeader("Content-Disposition", "attachment; filename=" + encodingFileName);
        } catch (IOException e) {
            logger.error(Thread.currentThread().getStackTrace()[1].getMethodName() +"发生的异常是: ",e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 设置下载zip的响应头信息
     * @param response
     * @param fileName 文件名
     * @param request
     * @throws IOException
     * @author zgd
     * @time 2018年6月25日11:47:07
     */
    public static void setZipDownLoadHeadInfo(HttpServletResponse response, HttpServletRequest request, String fileName) throws IOException {
        // 获取客户端浏览器的类型
        String agent = request.getHeader("User-Agent");
        response.setContentType("application/octet-stream ");
        // 表示不能用浏览器直接打开
        response.setHeader("Connection", "close");
        // 告诉客户端允许断点续传多线程连接下载
        response.setHeader("Accept-Ranges", "bytes");
        // 对文件名重新编码
        String encodingFileName = ZipFileUtil.encodeDownloadFilename(fileName, agent);
        response.setHeader("Content-Disposition", "attachment; filename=" + encodingFileName);
    }

    /**
     * 将批量文件打包下载成zip
     * @param request
     * @param response
     * @param zipName     下载的zip名
     * @param files       要打包的批量文件
     * @param zipPath     生成的zip路径
     * @throws Exception
     */
    public static void downloadZip(HttpServletRequest request, HttpServletResponse response, String zipName, List<File> files, String zipPath)throws Exception {
        File srcfile[] = new File[files.size()];
        File zip = new File(zipPath);
        for (int i = 0; i < files.size(); i++) {
            srcfile[i] = files.get(i);
        }
        //生成.zip文件;
        FileInputStream inStream = null;
        ServletOutputStream os = null;
        try {
            //设置下载zip的头信息
            ZipFileUtil.setZipDownLoadHeadInfo(response, request, zipName);
            os = response.getOutputStream();
            ZipFileUtil.ZipFiles(srcfile, zip);
            inStream = new FileInputStream(zip);
            byte[] buf = new byte[4096];
            int readLength;
            while (((readLength = inStream.read(buf)) != -1)) {
                os.write(buf, 0, readLength);
            }
        }  finally {
            if (inStream != null) {
                inStream.close();
            }
            if (os != null) {
                os.flush();
                os.close();
            }
        }
    }

    /**
     * 将数据转成多个excel文件放在项目中
     *
     * @param tempDir
     * @throws Exception
     * @author chengboying
     * @time 2020年02月25日11:47:07
     */
    public static List<File> getStoreOrderExcels(Map<String,SXSSFWorkbook> workbook, String tempDir) throws Exception {
        //excel文件个数
        ZipFileUtil.createFile(tempDir);
        List<File> files = new ArrayList<File>();  //声明一个集合,用来存放多个Excel文件路径及名称

        for (Map.Entry<String,SXSSFWorkbook> entry : workbook.entrySet()){
            SXSSFWorkbook wb = entry.getValue();
            //生成一个excel
            String path = tempDir + "-" + entry.getKey() + ".xlsx";
            generateExcelToPath(wb, path);
            //excel添加到files中
            files.add(new File(path));
        }
        return files;
    }


    /**
     * 生成excel到指定路径
     * @param wb
     * @param path
     * @throws Exception
     */
    private static void generateExcelToPath(SXSSFWorkbook wb, String path) throws Exception {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(path);
            wb.write(fos);
        } finally {
            if (fos != null) {
                fos.flush();
                fos.close();
            }
        }
    }
}

这里是controller层的方法

public void toStatisticExcel() throws Exception{
        String beginDate = getFromRequestParameter("beginDate");
        String endDate = getFromRequestParameter("endDate");
        String websiteId = getFromRequestParameter("websiteId");
        String options = getFromRequestParameter("options");
        //用Map来存储要导出的多个SXSSFWorkbook对象,String为Excel要显示的表名
        Map<String,SXSSFWorkbook> hssw = statisticExcel.statisticExcel(beginDate, endDate,websiteId,options);
        AreaBean areaBean = dataAreaDao.getAreaById(areaId);
        //单个Excel表不需要压缩、直接导出就好
        if (hssw.size() == 1){
            String keyName = getKeyOrNull(hssw);
            super.downloadFile(hssw.get(keyName), areaBean.getName()+"人民政府-智能问答统计报表-"+keyName+"-"+beginDate+"~"+endDate, "xlsx");
        }else {
            super.poizip(hssw, areaBean.getName()+"人民政府-智能问答统计报表-"+beginDate+"~"+endDate, "zip");
        }
    }

这里是单个Excel下载的调用方法

/**
     *
     * @Title: downloadFile
     * @author chengboying
     * @Description: 下载文件
     * @date 2020年1月25日 上午10:30:38
     */
    protected void downloadFile(SXSSFWorkbook hwb, String fileName,
                                String extension) throws Exception {

        // 获取客户端浏览器的类型
        String agent = request.getHeader("User-Agent");
        String downloadName = ZipFileUtil.encodeDownloadFilename(fileName,agent);
        response.reset();
        response.setContentType("application/x-msdownload");
        response.setHeader(
                "Content-Disposition",
                "attachment; filename="
                        + downloadName
                        + "." + extension);
        OutputStream out = response.getOutputStream();
        hwb.write(out);
        out.close();
    }

这里是多个Excel压缩打包下载的调用方法

public void poizip(Map<String,SXSSFWorkbook> sxssfWorkbook, String fileName, String extension) throws IOException {
        try {
                String realPath = request.getSession().getServletContext().getRealPath("WEB-INF");
                //创建临时文件夹保存excel
                String tempDir = realPath + "/tempDir/" + fileName;
                List<File> files = ZipFileUtil.getStoreOrderExcels(sxssfWorkbook,tempDir);
                fileName = fileName + ".zip";
                String zipPath = tempDir + "\\" + fileName;
                //下载zip
                ZipFileUtil.downloadZip(request, response, fileName, files, zipPath);
                //删除tempDir文件夹和其中的excel和zip文件
                boolean b = ZipFileUtil.deleteDir(new File(realPath + "\\tempDir"));
                if (!b) {
                    throw new RuntimeException("tempDir文件夹及其中的临时Excel和zip文件删除失败");
                }
        }catch (Exception e) {
            try {
                if (!response.isCommitted()) {
                    response.setContentType("text/html;charset=utf-8");
                    response.setHeader("Content-Disposition", "");
                    String html = ZipFileUtil.getErrorHtml("下载失败");
                    response.getOutputStream().write(html.getBytes("UTF-8"));
                }
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }

Excel的SXSSFWorkbook对象数据内容生成根据自己的业务规则完成

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,640评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,254评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,011评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,755评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,774评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,610评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,352评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,257评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,717评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,894评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,021评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,735评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,354评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,936评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,054评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,224评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,974评论 2 355

推荐阅读更多精彩内容

  • 转自链接 目录 1.认识NPOI 2.使用NPOI生成xls文件 2.1创建基本内容 2.1.1创建Workboo...
    腿毛裤阅读 10,570评论 1 3
  • 转自链接 3.项目实践 3.1基于.xls模板生成Excel文件 3.2生成九九乘法表 3.3生成一张工资单 3....
    腿毛裤阅读 3,452评论 0 0
  • WinRAR - 最新版本的更新 版本 5.50 1. WinRAR 和命令行 RAR 默认使用 RAR ...
    王舒璇阅读 2,395评论 0 2
  • 一、基本概念: 注:对于git的分布式概念及其优点,不重复说明,自己百度或谷歌。本文中涉及到指令前面有$的,在cm...
    大厂offer阅读 1,425评论 0 3
  • 从受精卵在子宫着床的那一刻起,母子之间血脉相连的羁绊悄悄萌芽,情感纽带逐渐根深蒂固。 那段牵肠挂肚的日子,...
    哈哈男爵阅读 240评论 0 1