使用 freemark 实现 报表导出

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35704236/article/details/79942728

使用 freemark 实现 报表导出

1 准备 excel 模板

  • 1.1 创建 excel 并且输入一点测试数据,然后以 xml 格式另存为

  • 1.2 打开 xml 找到


前后省略 n 多东西
..... 

<Table ss:ExpandedColumnCount="2" ss:ExpandedRowCount="2" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="54" ss:DefaultRowHeight="13.5">
    <Row>
        <Cell>
            <Data ss:Type="String">标题1</Data>
        </Cell>
    </Row>
    <Row>
        <Cell>
            <Data ss:Type="String">内容1</Data>
        </Cell>
    </Row>
</Table>

..... 
  • 1.3 用 freemark 的语法改造后的样子
<Table ss:ExpandedColumnCount="2" ss:ExpandedRowCount="2" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="54" ss:DefaultRowHeight="13.5">
    <Row>
        <Cell>
            <Data ss:Type="String">标题1</Data>
        </Cell>
    </Row>
    <Row>
        <#list datas as data>
            <Cell>
                <Data ss:Type="String">${data.get("xxx")!''}</Data>
            </Cell>
        </#list>
    </Row>
</Table>

2 Controller 写法

  • 2.1 将查询的来的list 用hashMap封装一下
    List datalist = 自己的业务逻辑查出来的 list
    Map<String, Object> resultMap = new HashMap<>(1);
    resultMap.put("datas", datalist);
    String fileName = "xx表.xls";
    new ReportExportHelper().doExport(resultMap, fileName, exportReportConfig, overdueTemplateName, response);
  • 2.2 当 Controller 调用 ReportExportHelper 的 doExport 就完成报表导出了, 你没看错就这么简单。

3 相关工具类

3.0 ExportReportConfig

package cn.istarfinancial.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * 报表导出配置类
 *
 * @Author: huangwenjun
 * @Description:
 * @Date: Created in 11:25  2018/4/14
 **/
@Component
@ConfigurationProperties(prefix = "report")
public class ExportReportConfig {

    /**
     * 模板根目录
     */
    private String templateRootPath;

    /**
     * 用于存放临时文件的目录
     */
    private String tempReport;

    public String getTemplateRootPath() {
        return templateRootPath;
    }

    public void setTemplateRootPath(String templateRootPath) {
        this.templateRootPath = templateRootPath;
    }

    public String getTempReport() {
        return tempReport;
    }

    public void setTempReport(String tempReport) {
        this.tempReport = tempReport;
    }
}

3.1 ReportExportHelper

package cn.istarfinancial.utils;

import cn.istarfinancial.config.ExportReportConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.Map;

/**
 * 报表导出帮助者
 *
 * @Author: huangwenjun
 * @Description:
 * @Date: Created in 14:59  2018/4/14
 **/
public class ReportExportHelper {

    private Logger logger = LoggerFactory.getLogger(ReportExportHelper.class);

    /**
     * 执行报表导出
     *
     * 导出流程 1 查询数据,然后再服务器上生成报表
     *          2 将包表写回
     *
     * @param resultMap
     * @param fileName
     */
    public void doExport(Map<String, Object> resultMap, String fileName, ExportReportConfig exportReportConfig, String templateName, HttpServletResponse response) {
        try {
            boolean success = TemplateParseUtil.parse(exportReportConfig.getTemplateRootPath(), templateName, exportReportConfig.getTempReport() + "//" + fileName, resultMap);

            if (success) {
                // 模板生成成功
                boolean downloaded = FileTransUtil.download(response, fileName, exportReportConfig.getTempReport() + "\\" + fileName);

                if (downloaded) {
                    new File(exportReportConfig.getTempReport() + "//" + fileName).delete();
                }
            }
        } catch (Exception e) {
            logger.error("模板导出出错");
        }
    }
}

3.2 TemplateParseUtil

package cn.istarfinancial.utils;

import freemarker.template.TemplateException;

/**
 * 模板解析实体类
 */
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;

/**
 * @Author: huangwenjun
 * @Description:
 * @Date: Created in 9:30  2018/4/14
 **/
public class TemplateParseUtil {

    /**
     * 解析模板生成Excel
     *
     * @param templateDir  模板目录
     * @param templateName 模板名称
     * @param excelPath    生成的Excel文件路径
     * @param data         数据参数
     * @throws IOException
     * @throws TemplateException
     */
    public static boolean parse(String templateDir, String templateName, String excelPath, Map<String, Object> data) throws IOException, TemplateException {
        //初始化工作
        Configuration cfg = new Configuration();
        //设置默认编码格式为UTF-8
        cfg.setDefaultEncoding("UTF-8");
        //全局数字格式
        cfg.setNumberFormat("0.00");
        //设置模板文件位置
        cfg.setDirectoryForTemplateLoading(new File(templateDir));
        cfg.setObjectWrapper(new DefaultObjectWrapper());
        //加载模板
        Template template = cfg.getTemplate(templateName, "utf-8");
        try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(excelPath), "UTF-8")) {
            //填充数据至Excel
            template.process(data, writer);
            writer.flush();
        }

        return true;
    }

    public static void main(String[] args) throws IOException, TemplateException {
        List<String> str = new ArrayList<>();

        for(int i = 1 ; i <= 3;i ++){
            str.add("str:" + i);
        }

        //测试Excel文件生成
        Map<String,Object> data = new HashMap<>();
        data.put("strs", str);

        String templatePath = "E:\\idea_project\\xingrong-report\\src\\main\\resources\\templates";

        TemplateParseUtil.parse(templatePath, "overdue_template.ftl", templatePath + "/xmlTest.xls", data);
    }
}

3.3 FileTransUtil

package cn.istarfinancial.utils;

import javax.servlet.http.HttpServletResponse;
import java.io.*;

/**
 * 文件传输工具类
 *
 * @Author: huangwenjun
 * @Description:
 * @Date: Created in 10:25  2018/4/14
 **/
public class FileTransUtil {

    /**
     * 文件下载
     * @param response
     * @param fileName
     * @param filePath
     * @return 是否下载成功
     */
    public static boolean download(HttpServletResponse response, String fileName, String filePath) throws IOException {
        response.setHeader("content-type", "application/octet-stream");
        response.setContentType("application/octet-stream;charset=utf-8");
        // 解决下载中文文件名的bug
        fileName = new String(fileName.getBytes(), "ISO-8859-1");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        byte[] buff = new byte[1024];

        try (OutputStream os = response.getOutputStream();
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File(filePath)))) {
            int len = 0;
            while ((len = bis.read(buff)) > 0) {
                os.write(buff, 0, len);
            }
        } catch (IOException e) {
            throw e;
        }

        return true;
    }
}

4 坑 & 解决方案

上述解决方案在 wps 能 完美运行, 但是在低版本的 office 里面 无法正常打开, 会启动报错。

4.1 无脑快速解决方案

  • 1 打卡 xml 设置 ExpandedColumnCount=”999999” 和 ExpandedRowCount=”999999”

4.2 正儿八经的排查错误

 一般打开错误的话会 office 生成日志,而且告诉你问题所在

 楼主的错误日志路径位于:

 C:\Users\Administrator\AppData\Local\Microsoft\Windows\INetCache\Content.MSO

 有些电脑可能找不到这个路径 需要设置两个地方
 1 设置电脑 显示隐藏文件夹
 2 取消勾选 隐藏受保护的操作系统文件

 然后你就能看到各种错误日志了。。。

5 写在最后

最后还是有一个小问题无法解决, 就是低版本的 office 打卡会报一个警告。。。有解决方案的兄弟 麻烦告诉我一声

猜你喜欢

转载自blog.csdn.net/qq_35704236/article/details/79942728
今日推荐