0.主要目的:将这样一个页面导出为word文档为doc格式,包含一些文本和循环遍历出来的echarts图表。

xwpftemplate word 循环 表格_sed

1. 目录结构如下:主要文件countAnalysed.xml(命名随意)为生成doc的内容模板文件

xwpftemplate word 循环 表格_word导出doc格式_02

2.先看一下前端请求方式,传过来json格式数据,请求两次服务器,第一次生成doc文件,第二次读取文件写入response输出流,实现下载。

function download_report() {
//此处遍历页面得数据,放到json中,可根据自己需要省略-----------------start
        var title= '${reportData.title}';
        var reportUnit= '${reportData.reportUnit!}';
        var reportTypeDate= '${reportData.reportTypeDate!}';
        var json;
        var jsonHead = {"title": title, "reportUnit": reportUnit,"reportTypeDate":reportTypeDate};
//此处用到了freemarker的模板遍历数据
        <#list reportData.reportModels as model>
        var modelTitle_${model ? index}= '${model.title!}';
        var modelDataSource_${model ? index}= '${model.dataSource!}';
        var modelShowContent_${model ? index}= '${model.showContent!}';
        var pic_${model ? index}=model_${model ? index}.chart.getConnectedDataURL();
        var model_pic_${model ? index}=pic_${model ? index}.substr(22,pic_${model ? index}.length);
        var jsonBody = {"model_${model ? index}":{
                "modelTitle": modelTitle_${model ? index},
                "modelDataSource": modelDataSource_${model ? index},
                "modelShowContent":modelShowContent_${model ? index},
                "model_pic":model_pic_${model ? index}
            }};
//最后的json对象
        json=$.extend(true,jsonHead,jsonBody);
        </#list>
//此处遍历页面得数据,放到json中,可根据自己需要省略-----------------end
        $.ajax({
//第一次请求生成doc临时文件
            url: '${base}/report/reportView/reportExport.do',
            method: 'POST',
            contentType: 'application/json;charset=utf-8',
            data: JSON.stringify(json),
            success: function (data) {
                if (data.status == 0) {
                    var encode_name = encodeURIComponent("大数据报告");
//第二次请求读取文件写入response输出流,实现下载。
                    window.location.href =  '${base}/report/reportView/reportExportLast.do'+ "?filepath=" + data.retinfo + "&name=" + encode_name;
                } else {
                    alert("下载word失败!");
                }
                console.log("success");
            },
            error: function (data) {
                alert('文件下载失败' + data);
            }
        })

    }

3.第一次请求生成doc临时文件:word导出为doc格式的后台controller类(此文章只能带出doc格式,不能导出docx格式,注释中代码根据自己需要修改)

/**
     * @param
     * @Description 报表导出doc
     * @Date 2019/11/13 11:53
     * @Param map 填入模板的数据
     * @Author 
     */
    @PostMapping("/reportExport")
    public void reportExport(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String,Object> map) throws IOException {
//从前端传过来的map中重新构建数据,用于填充到模板中(根据自己需要构建Map)  ------start
        Map<String, Object> report = new HashMap<>(16);
        Map<String, Object> model;
        List<Map<String, Object>> modelList = new ArrayList<>(16);
        report.put("title", map.get("title"));
        report.put("reportUnit", map.get("reportUnit"));
        report.put("reportTypeDate", map.get("reportTypeDate"));
        //模块数量
        int modelNum = map.size() - report.size();
//model_pic为存储前端传过来的echarts图片的Base64字符串
        for (int i = 0; i < modelNum; i++) {
            model = (Map<String, Object>) map.get("model_" + i);
            modelList.add(model);
        }
        report.put("modelList", modelList);
//从前端传过来的map中重新构建数据,用于填充到模板中(根据自己需要构建Map)  ------end
        File file = null;
        try {
//关键方法,传入模板名称和map数据  转为doc文件
            file = ResumeWord.createDoc(report, "countAnalysed");
            String text=file.getName();
//生成的文件名放到response中返回(此处根据自己需要可直接返回text)  ---------start
        PrintWriter out = null;
        try {
            
            response.setContentType("application/json;charset=UTF-8");
            out = response.getWriter();
            out.write(text);
        } catch (IOException var9) {
            LOGGER.error(var9.getMessage(), var9);
        } finally {
            if (out != null) {
                out.print("");
                out.close();
            }

        }
//生成的文件名放到response中返回(此处根据自己需要可直接返回text)  ---------end
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

4.生成doc的工具类createDoc方法:

import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.log4j.Logger;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author:
 * @Date: 2019/11/13 11:08
 * @description:报表导出
 */
public class ResumeWord {
    private static Logger log = Logger.getLogger(ResumeWord.class);
    private static Configuration configuration = null;
    private static Map<String, Template> allTemplate = null;

    static{
        configuration = new Configuration(Configuration.VERSION_2_3_0);
        configuration.setDefaultEncoding("UTF-8");
        configuration.setClassForTemplateLoading(ResumeWord.class, "/template");
        allTemplate = new HashMap<String, Template>(16);
        try{
//获取模板,名称为countAnalysed.xml,在项目的/resources/template目录下
allTemplate.put("countAnalysed",configuration.getTemplate("countAnalysed.xml"));
        }catch(IOException e){
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    private ResumeWord(){
    }

    public static File createDoc(Map<?,?> dataMap, String type){
//临时文件名
        String name = "temp"+(int)(Math.random()*100000)+".doc";
        File f = new File(name);
        Template t = allTemplate.get(type);
        try{
            //这个地方不能使用FileWriter因为需要指定编码类型否则生成的word文档会因为有无法识别的编码而无法打开
            Writer w = new OutputStreamWriter(new FileOutputStream(f), StandardCharsets.UTF_8);
            t.process(dataMap,w);
            w.close();
        }catch(Exception e){
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return f;
    }
}

5.第二次请求读取文件写入response输出流,实现下载。:将文件输出到response中,浏览器实现下载

/**
     * @param
     * @Description 报表导出
     * @Date 2019/11/13 11:53
     * @Author 
     */
    @RequestMapping("/reportExportLast")
    public void reportExportLast(HttpServletRequest request, HttpServletResponse response) throws IOException {
//前端传过来的文件路径
        String templateName = request.getParameter("filepath");
        if (templateName.isEmpty()) {
            templateName = "report" + System.currentTimeMillis();
        }
        File file = new File(templateName);
        try (InputStream inputStream = new FileInputStream(file);
             ServletOutputStream out = response.getOutputStream()) {
//前端传过来的用户下载后文件的文件名
            String name = new String(request.getParameter("name").getBytes("GB2312"), "ISO8859-1");
            response.setContentType("application/msword");
            response.setHeader("Content-Disposition", "attachment;filename=" + name + ".doc");
            byte[] buffer = new byte[1024];
            int bytesToRead;
//写入输出流中
            while ((bytesToRead = inputStream.read(buffer)) != -1) {
                out.write(buffer, 0, bytesToRead);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //删除临时文件
            file.delete();
        }
    }

freemarker遍历map集合,循环插入文字和图片(Base64字符串),大致看一下就好。

<w:p wsp:rsidR="00187954" wsp:rsidRPr="00EB273B" wsp:rsidRDefault="005A5D42" wsp:rsidP="00EB273B">
				<w:pPr>
					<w:pStyle w:val="a3"/>
                    <w:spacing w:before="0" w:before-autospacing="off" w:after="0" w:after-autospacing="off"
                               w:line="360" w:line-rule="auto"/>
                    <w:jc w:val="center"/>
                    <w:rPr>
						<w:rFonts w:ascii="Arial" w:h-ansi="Arial" w:cs="Arial"/>
                        <wx:font wx:val="Arial"/>
                        <w:b/>
                        <w:b-cs/>
                        <w:color w:val="333333"/>
                        <w:sz w:val="36"/>
                        <w:sz-cs w:val="36"/>
					</w:rPr>
				</w:pPr>
                <w:r wsp:rsidRPr="00EB273B">
					<w:rPr>
						<w:rFonts w:ascii="Arial" w:h-ansi="Arial" w:cs="Arial"/>
                        <w:b/>
                        <w:b-cs/>
                        <w:color w:val="333333"/>
                        <w:sz w:val="36"/>
                        <w:sz-cs w:val="36"/>
					</w:rPr>
                    <w:t>${title!}</w:t>
				</w:r>
			</w:p>
            <w:p wsp:rsidR="005A5D42" wsp:rsidRDefault="005A5D42" wsp:rsidP="00EB273B">
				<w:pPr>
					<w:widowControl/>
                    <w:jc w:val="center"/>
                    <w:rPr>
						<w:rFonts w:ascii="宋体" w:fareast="宋体" w:h-ansi="宋体" w:cs="Arial"/>
                        <wx:font wx:val="宋体"/>
                        <w:color w:val="333333"/>
                        <w:kern w:val="0"/>
                        <w:sz-cs w:val="28"/>
					</w:rPr>
				</w:pPr>
                <w:r wsp:rsidRPr="005A5D42">
					<w:rPr>
						<w:rFonts w:ascii="宋体" w:fareast="宋体" w:h-ansi="宋体" w:cs="Arial"/>
                        <wx:font wx:val="宋体"/>
                        <w:color w:val="333333"/>
                        <w:kern w:val="0"/>
                        <w:sz-cs w:val="28"/>
					</w:rPr>
                    <w:t>${reportUnit!}</w:t>
				</w:r>
			</w:p>
            <w:p wsp:rsidR="005A5D42" wsp:rsidRDefault="005A5D42" wsp:rsidP="00EB273B">
				<w:pPr>
					<w:widowControl/>
                    <w:jc w:val="center"/>
                    <w:rPr>
						<w:rFonts w:ascii="宋体" w:fareast="宋体" w:h-ansi="宋体" w:cs="Arial"/>
                        <wx:font wx:val="宋体"/>
                        <w:color w:val="333333"/>
                        <w:kern w:val="0"/>
                        <w:sz-cs w:val="21"/>
					</w:rPr>
				</w:pPr>
                <w:r wsp:rsidRPr="005A5D42">
					<w:rPr>
						<w:rFonts w:ascii="宋体" w:fareast="宋体" w:h-ansi="宋体" w:cs="Arial"/>
                        <wx:font wx:val="宋体"/>
                        <w:color w:val="333333"/>
                        <w:kern w:val="0"/>
                        <w:sz-cs w:val="21"/>
					</w:rPr>
                    <w:t>${reportTypeDate!}</w:t>
				</w:r>
			</w:p>
<!--            遍历模块List -->
            <#if  modelList ??>
            <#list modelList as mdl>
            <w:p wsp:rsidR="00EB273B" wsp:rsidRDefault="00EB273B" wsp:rsidP="00EB273B">
				<w:pPr>
					<w:widowControl/>
                    <w:jc w:val="center"/>
                    <w:rPr>
						<w:rFonts w:ascii="宋体" w:fareast="宋体" w:h-ansi="宋体" w:cs="Arial"/>
                        <wx:font wx:val="宋体"/>
                        <w:color w:val="333333"/>
                        <w:kern w:val="0"/>
                        <w:sz-cs w:val="28"/>
					</w:rPr>
				</w:pPr>
			</w:p>
            <!-- 模块标题 -->
            <w:p wsp:rsidR="005A5D42" wsp:rsidRDefault="005A5D42" wsp:rsidP="00EB273B">
				<w:pPr>
					<w:widowControl/>
                    <w:jc w:val="center"/>
                    <w:rPr>
						<w:rFonts w:ascii="宋体" w:fareast="宋体" w:h-ansi="宋体" w:cs="Arial"/>
                        <w:b/>
                        <w:b-cs/>
                        <wx:font wx:val="宋体"/>
                        <w:color w:val="333333"/>
                        <w:kern w:val="0"/>
                        <w:sz-cs w:val="28"/>
					</w:rPr>
				</w:pPr>
                <w:r wsp:rsidRPr="005A5D42">
					<w:rPr>
						<w:rFonts w:ascii="宋体" w:fareast="宋体" w:h-ansi="宋体" w:cs="Arial"/>
                        <w:b/>
                        <w:b-cs/>
                        <wx:font wx:val="宋体"/>
                        <w:color w:val="333333"/>
                        <w:kern w:val="0"/>
                        <w:sz-cs w:val="28"/>
					</w:rPr>
                    <w:t>${mdl.modelTitle!}</w:t>
				</w:r>
			</w:p>
            <!--            模块数据来源-->
            <w:p wsp:rsidR="005A5D42" wsp:rsidRDefault="005A5D42" wsp:rsidP="00EB273B">
				<w:pPr>
					<w:widowControl/>
                    <w:jc w:val="center"/>
                    <w:rPr>
						<w:rFonts w:ascii="宋体" w:fareast="宋体" w:h-ansi="宋体" w:cs="Arial"/>
                        <wx:font wx:val="宋体"/>
                        <w:color w:val="333333"/>
                        <w:kern w:val="0"/>
                        <w:sz-cs w:val="24"/>
					</w:rPr>
				</w:pPr>
                <w:r wsp:rsidRPr="005A5D42">
					<w:rPr>
						<w:rFonts w:ascii="宋体" w:fareast="宋体" w:h-ansi="宋体" w:cs="Arial"/>
                        <wx:font wx:val="宋体"/>
                        <w:color w:val="333333"/>
                        <w:kern w:val="0"/>
                        <w:sz-cs w:val="24"/>
					</w:rPr>
                    <w:t>${mdl.modelDataSource!}</w:t>
				</w:r>
			</w:p>
            <!-- 模块展示内容-->
            <w:p wsp:rsidR="005A5D42" wsp:rsidRDefault="005A5D42" wsp:rsidP="00EB273B">
				<w:pPr>
					<w:widowControl/>
                    <w:jc w:val="left"/>
                    <w:rPr>
						<w:rFonts w:ascii="宋体" w:fareast="宋体" w:h-ansi="宋体" w:cs="Arial"/>
                        <wx:font wx:val="宋体"/>
                        <w:color w:val="333333"/>
                        <w:kern w:val="0"/>
                        <w:sz-cs w:val="21"/>
					</w:rPr>
				</w:pPr>
                <w:r wsp:rsidRPr="005A5D42">
					<w:rPr>
						<w:rFonts w:ascii="宋体" w:fareast="宋体" w:h-ansi="宋体" w:cs="Arial"/>
                        <wx:font wx:val="宋体"/>
                        <w:color w:val="333333"/>
                        <w:kern w:val="0"/>
                        <w:sz-cs w:val="21"/>
					</w:rPr>
                    <w:t>${mdl.modelShowContent!}</w:t>
				</w:r>
			</w:p>
            <!-- 空行 -->
            <w:p wsp:rsidR="00EB273B" wsp:rsidRDefault="00EB273B" wsp:rsidP="00EB273B">
				<w:pPr>
					<w:widowControl/>
                    <w:jc w:val="center"/>
                    <w:rPr>
						<w:rFonts w:ascii="宋体" w:fareast="宋体" w:h-ansi="宋体" w:cs="Arial"/>
                        <wx:font wx:val="宋体"/>
                        <w:color w:val="333333"/>
                        <w:kern w:val="0"/>
                        <w:sz-cs w:val="21"/>
					</w:rPr>
				</w:pPr>
			</w:p>
            <!-- 趋势图 -->
            <w:p wsp:rsidR="00EB273B" wsp:rsidRDefault="003E3926" wsp:rsidP="00EB273B">
				<w:pPr>
					<w:widowControl/>
                    <w:jc w:val="left"/>
                    <w:rPr>
						<w:rFonts w:ascii="宋体" w:fareast="宋体" w:h-ansi="宋体" w:cs="Arial"/>
                        <wx:font wx:val="宋体"/>
                        <w:color w:val="333333"/>
                        <w:kern w:val="0"/>
                        <w:sz-cs w:val="21"/>
					</w:rPr>
				</w:pPr>
                <w:r wsp:rsidRPr="00E21A12">
					<w:rPr>
						<w:noProof/>
					</w:rPr>
                    <w:pict>
						<w:binData w:name="wordml://0200000${mdl_index+1}.png"
                                   xml:space="preserve">${mdl.model_pic!}</w:binData>
                        <v:shape id="图片 1" o:spid="_x0000_i1025"  type="#_x0000_t75"
                                 style="width:415.8pt;height:200pt;visibility:visible;mso-wrap-style:square">
                            <v:imagedata src="wordml://0200000${mdl_index+1}.png" o:title=""/>
                        </v:shape>
					</w:pict>
				</w:r>
			</w:p>
            <!-- 空行 -->
            <w:p wsp:rsidR="00EB273B" wsp:rsidRDefault="00EB273B" wsp:rsidP="00EB273B">
				<w:pPr>
					<w:widowControl/>
                    <w:jc w:val="center"/>
                    <w:rPr>
						<w:rFonts w:ascii="宋体" w:fareast="宋体" w:h-ansi="宋体" w:cs="Arial"/>
                        <wx:font wx:val="宋体"/>
                        <w:color w:val="333333"/>
                        <w:kern w:val="0"/>
                        <w:sz-cs w:val="21"/>
					</w:rPr>
				</w:pPr>
			</w:p>
<!--            List结束-->
    <!-- 空行 -->
        </#list>
        </#if>

7.导出样式为:文字内容和多张图片

xwpftemplate word 循环 表格_sed_03