网上很多下载导出功能都需要先在本机生成文件,然后通过下载流进行下载,最后再删除临时文件。但是有些公司对文件生成有权限要求或者禁止生成临时文件,这个时候,这些代码就不能用了。这里我给大家提供一种新的方法来进行下载导出。

首先,先来造一批模拟数据,这里就不走数据库了,主要演示导出功能。

        //模拟导出数据
        List statusList = new ArrayList<>();
        for (int i=1; i<=100000; i++) {
            Status status = new Status();
            status.setId("" + i + "");
            status.setName("第" + i + "条");
            status.setValue("第" + i + "条内容");
            status.setMark("第" + i + "条备注");
            status.setCrateTime(sdf.format(new Date()));
            statusList.add(status);
        }

然后是生成要导出的zip压缩包的字节数组流。

        String[] fieldNames = new String[]{"id", "name", "value", "mark", "crateTime"};
        //筛选条件中文
        String[] fieldDescs = new String[]{"编号", "名称", "内容", "备注", "创建时间"};

        ByteArrayOutputStream output = exportService.exportData(statusList, fieldNames, fieldDescs);

在zip压缩包的流中加入csv格式excel文件的字节数组流。

    @Override
    public ByteArrayOutputStream exportData(List statusList, String[] fieldNames, String[] fieldDescs) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("生成csv byte数组数据");
        //csv文件名前缀
        String fileNameStr = "统计导出";
        //生成byte数组
        byte[] bytes = this.generateCsvFile(statusList, fieldNames, fieldDescs);
        stopWatch.stop();

        //打包zip文件;
        stopWatch.start("压缩数据到下载流");

        ByteArrayOutputStream temp = new ByteArrayOutputStream();
        ZipOutputStream zos = new ZipOutputStream(temp);
        try {
            String entryName = fileNameStr + ".csv";
            ZipEntry entry = new ZipEntry(entryName);
            zos.putNextEntry(entry);
            zos.write(bytes);
            zos.closeEntry();
            zos.close();
            stopWatch.stop();
            log.info(stopWatch.prettyPrint());
            return temp;
        } catch (Exception e) {
            log.error("zip文件生成错误。", e);
        } finally {
            try {
                if (zos != null) {
                    zos.close();
                }
                if (temp != null) {
                    temp.close();
                }
            } catch (IOException e) {
                log.error("文件流关闭错误。", e);
            }
        }
        return null;
    }

下面是csv字节数组流的生成代码。

    /**
     * 传入数据列表、目标文件、字段名和字段标题,生成csv文件
     *
     * @param dataList
     * @param fieldNames
     * @param fieldDescs
     * @return
     */
    public byte[] generateCsvFile(List dataList, String[] fieldNames, String[] fieldDescs) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("生成csv");
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
             BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream)
        ) {
            //文件头部插入excel的BOM信息,否则打开会中文乱码
            bufferedOutputStream.write(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF});

            //插入标题行
            writeRow(fieldDescs, bufferedOutputStream);

            String[] contents = new String[fieldNames.length];
            if (dataList.get(0) instanceof Map) {
                for (int i = 0; i < dataList.size(); i++) {
                    Map dataMap = (HashMap) dataList.get(i);
                    for (int j = 0; fieldNames != null && j < fieldNames.length; j++) {
                        String filedName = fieldNames[j];
                        Object obj = dataMap.get(filedName);
                        if (obj == null || "null".equals(String.valueOf(obj))) {
                            obj = "";
                        }
                        contents[j] = String.valueOf(obj);
                    }
                    writeRow(contents, bufferedOutputStream);
                }
            } else if (dataList.get(0) instanceof BaseEntity) {
                for (int i = 0; i < dataList.size(); i++) {
                    Class clazz = dataList.get(i).getClass();
                    for (int j = 0; fieldNames != null && j < fieldNames.length; j++) {
                        String filedName = toUpperCaseFirstOne(fieldNames[j]);
                        Method method = clazz.getMethod(filedName);
                        method.setAccessible(true);
                        Object obj = method.invoke(dataList.get(i));
                        if (obj == null || obj.equals("null")) {
                            obj = "";
                        }
                        contents[j] = String.valueOf(obj);
                    }
                    writeRow(contents, bufferedOutputStream);
                }
            }
            bufferedOutputStream.flush();
            return byteArrayOutputStream.toByteArray();
        } catch (UnsupportedEncodingException e) {
            log.error("UnsupportedEncodingException ", e);
        } catch (Exception e) {
            log.error("未捕获异常。", e);
        } finally {
            stopWatch.stop();
            log.info(stopWatch.prettyPrint());
        }
        return null;
    }

最后导出生成的zip压缩包的字节数组流到客户端。

        byte[] content = output.toByteArray();
        InputStream is = new ByteArrayInputStream(content);

        //下载文件
        String fileName = new Date().getTime() + ".zip";
        try {
            BufferedInputStream bis = null;
            BufferedOutputStream bos = null;
            ServletOutputStream out = response.getOutputStream();
            // 设置response参数,可以打开下载页面
            response.reset();
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename="+ new String(fileName.getBytes(), "iso-8859-1"));
            try {
                bis = new BufferedInputStream(is);
                bos = new BufferedOutputStream(out);
                byte[] buff = new byte[2048];
                int bytesRead;
                // Simple read/write loop.
                while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                    bos.write(buff, 0, bytesRead);
                }
            } catch (final IOException e) {
                throw e;
            } finally {
                if (bis != null)
                    bis.close();
                if (bos != null)
                    bos.close();
                stopWatch.stop();
                log.info(stopWatch.prettyPrint());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

大功告成。具体有不清楚的,可以去我的github看看。地址:

https://github.com/whol/exportdemo,分支为 简单查询生成单csv文件并打包下载

 

最后修改于 2019-04-01 15:30:12
如果觉得我的文章对你有用,请随意赞赏
扫一扫支付
上一篇