Beetl 模板引擎生成word以及excel总结

Beetl Java模板引擎生成word excel

之前项目中使用freemarker和POI进行word以及excel的模板导出,在使用的过程中为了解决一些小问题,意外的接触了Beetl这款模板生成导出方案,解决了一些痛点,所以这次就进行总结分享下。

maven依赖
           
            com.ibeetl
            beetl
            2.9.3
           

模板制作

创建模板 doc或者xls,设置好样式以及在需要动态加载的地方填充好一些数据(替换变量的时候方便定位),然后另存为xml格式文件;用文本编辑器打开进行模板制作。
Beetl 模板引擎生成word以及excel总结_第1张图片



根据beetl的语法,在早先设置的数据处替换为变量,然后修改文件后缀名为btl,即制作好了模板。java项目的话,则放在templates目录下。

Beetl 模板引擎生成word以及excel总结_第2张图片

beetl工具类



import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.resource.ClasspathResourceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletResponse;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;

/**
 * Created on 2018/10/16.
 * Beetl生成doc文档工具类
 */
public class BeetlUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(BeetlUtils.class);

    /** 模板路径 */
    private static final String TEMPLATE_PATH = "templates/";
    /** 模板组 */
    private static GroupTemplate gt ;

    /**
     * 获取到模板
     * @param templateName 模板名称
     * @return beetle模板
     * @throws Exception 异常
     */
    public static Template getTemplate(String templateName)throws Exception{
        if (gt==null) {
            ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader(TEMPLATE_PATH);
            Configuration cfg = Configuration.defaultConfiguration();
            gt = new GroupTemplate(resourceLoader, cfg);
        }
        return gt.getTemplate(templateName+".btl");
    }


    public static String renderToString(Map data,String templateName) throws Exception{
        Template template =getTemplate(templateName);
        template.binding(data);
        return template.render();
    }

    /**
     * 下载doc文件
     * @param dataMap 模板数据
     * @param template 模板
     * @throws Exception 异常
     */
    public static void exportWord(String fileName, Map dataMap,Template template,HttpServletResponse response) throws Exception {
        setFileDownloadHeader(response, fileName);
        template.binding(dataMap);
        template.renderTo(response.getOutputStream());
    }
    /**
     * 下载doc文件
     * @param dataMap 模板数据
     * @param template 模板
     * @throws Exception 异常
     */
    public static void exportWord(Map dataMap,Template template,OutputStream out) throws Exception {
        template.binding(dataMap);
        template.renderTo(out);
    }
    /**
     *  设置让浏览器弹出下载对话框的Header
     * @param response web响应
     * @param fileName 文件名
     */
    public static void setFileDownloadHeader(HttpServletResponse response, String fileName) {
        try {
            // 中文文件名支持 ContentType 根据下载的文件不同而不同
            String encodedFileName = URLEncoder.encode(fileName, "UTF-8");
            response.setContentType("application/x-xls");
            response.setHeader("Content-Disposition", "attachment; filename=" + encodedFileName);
        } catch (UnsupportedEncodingException e) {
            LOGGER.error(e.getLocalizedMessage(),e);
        }
    }

    /**
     * 将模板渲染到指定文件
     * @param filePath 文件全路径
     * @param dataMap 数据
     * @param templateName 模板名称
     * @throws Exception 异常
     */
    public static void renderToFile(String filePath,Map dataMap,String templateName) throws Exception{
        Template template =getTemplate(templateName);
        template.binding(dataMap);
        try ( FileOutputStream fileOutputStream = new FileOutputStream(filePath)) {

            template.renderTo(fileOutputStream);
        }


    }


}






调用生成

在controller层或者service层,将查询出的数据放进map中,传递给模板;然后写给流导出。


       Map data = new HashMap<>();
        List list = new ArrayList<>();

        data.put("listPro",list);

        data.put("count",list.size()+12);

        try {
            Template t = BeetlUtils.getTemplate("product");
            BeetlUtils.exportWord("信息统计表.xls",data,t,response);
        } catch (Exception e) {
            e.printStackTrace();
        }


无论是生成word 还是 excel,都是通过一样的思路:

  1. 先制作模板,然后保存为xml格式。制作模板的时候,可以先预填一些数据,以便在添加变量的时候好找到需要动态替换的位置,然后将预填的固定值改为变量。
  2. 编辑xml文件,通过beetl的语法,将模板内需要动态填充的地方进行变量赋值;需要循环追加元素的地方也是一样。循环的时候需要找到正确的循环节点,即xml里面的,比如word表格里面的行节点等。

注:如果只是需要动态的替换掉某些位置的值,只需要在制作模板的时候设置个好记的初始值,生成另存为xml后打开替换为相应的变量即可;如果是需要动态的填充列表或者段落,道理也是一样,唯一需要注意的是,在xml里面找到预设值的地方后,需要找到合适的xml节点(循环节点),可通过生成测试是否正确,例如 word模板里, 是段落,是行,循环的时候则需要包裹它。

  1. 将添加好变量的模板 后缀名改为btl,即Beetl识别的格式。至此模板就做好了,下一步就是动态的填充数据进去生成。
beetl 官网

http://ibeetl.com

使用文档 http://ibeetl.com/guide/#/beetl

其他使用

在项目中遇到过需要编写 各种类型的统计jsp页面,根据选择的不同类型的条件以及限定条件,展示不同的统计页面以及筛选条件项;因为页面是根据选择的统计方式而变化的,所以编写固定的jsp页面就很难实现需求。


这时候找到的解决方法就是:制作jsp生成模板,模板内根据传入的参数进行代码判断,生成不同的元素,执行不同的查询和展示;即动态的生成 ‘代码页面’。后续可以加上一些判断,如将生成的jsp页面进行有效的命名,跳转页面的时候进行判断,如果已经生成(生成路径下存在 xx.jsp),则直接返回jsp路径,否则就先调用通过模板生成页面的方法,再返回jsp路径;



<${jsp_char_start} page language="java" pageEncoding="UTF-8"${jsp_char_end}>

<${jsp_char_start} taglib prefix="ta" tagdir="/WEB-INF/tags/tatags"${jsp_char_end}>


    
    <${jsp_char_start} include file="/ta/inc.jsp"${jsp_char_end}>
    
    
    

<%
  var length = report_item.~size;
   var is_4 = length%4==0;
%>






<% if(length>0){%>

<%
for (item in report_item){
%>
    <%
       if (item.condition_type=='select' && item.condition_mb == '2'){

    %>

            
            
                
                
                
                
            
            

<%
    }
 else {

            var dataTypeStr = item.condition_type;
            var selectType = item.condition_mb;
            var dateCondition = item.condition_date;
            var taType = "text";
            var collectionValue;
            var selectCol = "sqlType";
            var dateShowType = '';
            if(dataTypeStr == "date"){
                 taType = "date";
                 if(item.condition_date!='' && item.condition_date != 'date'){

                     var words = strutil.split(dateCondition,"_");
                     if(array.contain(words,"issue")){

                        dateShowType = ' issue ="true"';
                     }else{

                        dateShowType = words[0]+'="true"' ;
                     }

                 }
            }

            if(dataTypeStr == "number"){
                 taType = "number";
            }
            if(dataTypeStr == "select" && selectType == '1'){
                taType = "selectInput";
                selectCol = "colType";
                collectionValue = ' collection="'+item.condition_code+'"' ;
            }
            if(dataTypeStr == "select" && selectType == '0'){
                taType = "selectInput";
            }
%>

         
 <%
    }
 }
%>
        
            
            
        


<%}%>
    
    
    <% if(length==0){%>
     

                
            
<%}%>
            
            
   





<${jsp_char_start} include file="/ta/incfooter.jsp"${jsp_char_end}>

注:导出生成后的word或者excel,一般常见的问题有:wps可以正常打开而office却打开报错。

一.制作excel模板生成的 xls wps可以打开,office打开报错

参考博文 https://blog.csdn.net/klchht/article/details/52218203

解决测试:

  1. ExpandedRowCount 设置的行数值小于实际行数则报错,修改成 xml文件里默认的ExpandedRowCount+追加的数据行数,但是还是office打不开
  2. 发现另存的xml里还有ActiveRow节点 跟 ExpandedRowCount一致,也修改成默认的ActiveRow数+追加的数据行数,测试office可以打开

二. 生成word数据 设置 ContentType 错误, response.setContentType;需要针对导出 word、还是xls 选择不同的ContentType,可以网上搜索

要点:

  1. 生成的模板最好使用office来进行制作,避免一些未知的错误(适当使用不是最新版本的),
  2. 语法参考Beetl的使用文档

网上关于beetl的生成模板的使用文档比较少,自己最开始使用的时候也是找了很久,踩过很多的坑,当然模板生成的解决方案有很多,freemarker以及poi都可以,综合使用后,还是觉得beetl比较方便,对于生成出的文档的格式,兼容性也不错。有时间的话可以试一试哟。

你可能感兴趣的:(疑难杂症,java)