使用JXLS生成Excel文件

背景

日常开发中会经常遇到数据需要下载/导出的情况,如果是比较简单的excel,没有指定特殊格式,借助第三方工具(如:hutool)几行代码即可完成,如果需要生成复杂格式的excel,代码处理起来就非常麻烦,此时可以采用加载模板文件渲染数据的方式实现。

功能实现

简单excel生成

引入依赖

    <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.7.4</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml</artifactId>
      <version>4.1.2</version>
    </dependency>

代码实现

直接生成文件

代码
    @Test
    public void testCreateSimpleCreate() {
        String outFilePath = "F:\\test-excel\\simple-create.xlsx";
        ExcelWriter writer = ExcelUtil.getWriter(outFilePath);
        List<Map<String, Object>> maps = this.mockSimpleExcelData();
        this.writeHeader(writer);
        writer.write(maps);
        writer.close();
    }

    /**
     * 写表头
     * @param writer
     */
    private void writeHeader(ExcelWriter writer ) {
        writer.addHeaderAlias("id", "ID");
        writer.addHeaderAlias("name", "名称");
        writer.addHeaderAlias("gender", "性别");
        writer.addHeaderAlias("age", "年龄");
        writer.addHeaderAlias("idCard", "身份证号");
    }

    /**
     * 模拟写入 简单的 5 列数据:id 姓名 性别 年龄 身份证号
     * @return
     */
    private List<Map<String, Object>> mockSimpleExcelData() {
        List<Map<String, Object>> list = new ArrayList<>();
        int dataCount = 10;
        for (int i = 0; i < dataCount; i++) {
            Map<String, Object> map = new LinkedHashMap<>();
                map.put("id", IdUtil.fastSimpleUUID());
                map.put("name", RandomUtil.randomString("赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨朱秦尤许何吕施张", 1).concat(RandomUtil.randomString("一二三四五六七八九十", RandomUtil.randomInt(1,2))));
                map.put("gender", i % 2 == 0 ? "男": "女");
                map.put("age", RandomUtil.randomInt(18, 35));
                map.put("idCard", String.valueOf(RandomUtil.randomString("1234567890", 18)));
            list.add(map);
        }
        return list;
    }
结果
image-20220224215358242

文件下载方式

以下代码为示例

    public void testDownloadFile(HttpServletResponse response) {
        // 通过工具类创建writer,默认创建xls格式
        ExcelWriter writer = ExcelUtil.getWriter(true);
        this.writeHeader(writer);
        List<Map<String, Object>> maps = this.mockSimpleExcelData();
        writer.write(maps);
        ServletOutputStream out = null;
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        try {
            // 中文需要使用encode加密
            String fileName = URLEncoder.encode("文件下载测试", CharsetUtil.UTF_8);
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
            out = response.getOutputStream();
            writer.flush(out, true);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            writer.close();
        }
        IoUtil.close(out);
    }

通过模板生成

导入依赖

    <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.7.4</version>
    </dependency> 
    <dependency>
<!-- 可以使用poi的实现也可以用jexcelapi的 -->
      <groupId>org.jxls</groupId>
      <artifactId>jxls-poi</artifactId>
      <version>1.0.15</version>
    </dependency>
    <dependency>
      <groupId>org.jxls</groupId>
      <artifactId>jxls-jexcel</artifactId>
      <version>1.0.7</version>
    </dependency>

代码实现

定义模板

image-20220224215034001

下载模板文件

直接生成文件

代码
    @Test
    public void testExcelByTemplate() throws IOException {
        String templatePath = "F:\\test-excel\\template_user.xlsx";
        String targetFilePath = "F:\\test-excel\\user.xlsx";
        Context context = new Context();
        List<Map<String, Object>> data = this.mockSimpleExcelData();
        // 这里的参数和模板中定义的参数名需要保持一致
        context.putVar("list", data);
        BufferedInputStream is = FileUtil.getInputStream(templatePath);
        BufferedOutputStream os = FileUtil.getOutputStream(targetFilePath);
        JxlsHelper jxlsHelper = JxlsHelper.getInstance();
        Transformer transformer = jxlsHelper.createTransformer(is, os);
        jxlsHelper.processTemplate(context, transformer);
        is.close();
        os.flush();
        os.close();
    }
运行结果
image-20220224215318779

文件下载方式

public void testDownloadFileByTemplate(HttpServletResponse response) throws IOException {
        String templateFilePath = "F:\\test-excel\\template_user.xlsx";
        File templateFile = new File(templateFilePath);
        // 生成临时文件
        String templateDir = FileUtil.getParent(templateFilePath, 1);
        String randomFileName = IdUtil.fastSimpleUUID();
        String outFilePath = StrUtil.concat(true, templateDir, File.separator, randomFileName, ".", FileUtil.getSuffix(templateFile));
        File outFile = new File(outFilePath);
        List<Map<String, Object>> data = this.mockSimpleExcelData();
        Map<String, Object> dataMap = new HashMap<>();
        // 这里的参数和模板中定义的参数名需要保持一致
        dataMap.put("list", data);
        this.renderExcelData(FileUtil.getInputStream(templateFile), FileUtil.getOutputStream(outFile), dataMap);
        // 中文需要使用encode加密
        String fileName = URLEncoder.encode("模板文件下载测试", CharsetUtil.UTF_8);
        // 创建输出流对象
        ServletOutputStream outputStream = response.getOutputStream();
        //以字节数组的形式读取文件
        byte[] bytes = FileUtil.readBytes(outFilePath);
        // 设置返回内容格式
        response.setContentType("application/octet-stream");
        // 设置下载弹窗的文件名和格式(文件名要包括名字和文件格式)
        response.setCharacterEncoding(CharsetUtil.UTF_8);
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        response.setHeader("FileName", fileName);
        // 返回数据到输出流对象中
        outputStream.write(bytes);
        // 关闭流对象
        IoUtil.close(outputStream);
        // 异步删除临时文件
        this.asyncDeleteTempFile(outFile);
    }

    private void renderExcelData(InputStream templateFileStream, OutputStream targetFileStream, Map<String, Object> dataMap) throws IOException {
        Context context = new Context();
        if (dataMap != null) {
            for (String key : dataMap.keySet()) {
                context.putVar(key, dataMap.get(key));
            }
        }
        JxlsHelper jxlsHelper = JxlsHelper.getInstance();
        Transformer transformer = jxlsHelper.createTransformer(templateFileStream, targetFileStream);
        jxlsHelper.processTemplate(context, transformer);
        templateFileStream.close();
        targetFileStream.flush();
        targetFileStream.close();
    }

    /**
     * 异步删除的临时文件
     * @param file 待删除的文件数组
     */
    public void asyncDeleteTempFile(File ...file) {
        final Integer targetDelayTime = 10 ;
        // 异步执行删除临时文件方法
        CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(targetDelayTime);
                // 删除临时文件
                if (ArrayUtil.isNotEmpty(file)) {
                    for (File tempFile : file) {
                        FileUtil.del(tempFile);
                    }
                }
            } catch (Exception e) {
                log.info("异步执行的删除临时文件时出错:{}", e);
            }
        });
    }

总结

工具类说明
hutools生成简单的excel文件只需要几行代码即可完成。
jxls1、生成excel文件需要定对应的模板文件,相对而言生成格式比较复杂的Excel文件难度更小。
2、文件下载时需要先生成临时文件,然后获取到临时文件流才可以下载。

jxls相关操作可查看:http://jxls.sourceforge.net/

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇