springboot中使用freemarker生成word循环输出图片(二维码)

 

1.先创建一个word文件(建议word2003,低版本兼容性好一点),在word中按照自己的需求做好文档。
2.另存为xml文件(建议与word一致即word2003xml),用可以查看xml文件的软件打开。如下图:

 

 

这一大段黑色文字就是图片由word转成xml生成的Base64码。这样的格式太乱了,建议使用firstObject xml编辑器可以格式化。
如下图:
将大段黑色文字替换为图片占位符${qrCodeList.imagedata}

 

 

将会变化的字段改为占位符${qrCodeList.row},${qrCodeList.col}

 

 

<w:tbl></w:tbl>表示表格
<w:tr></w:tr>表示行
<w:tc></w:tc>表示列
<#list></#list>表示需要循环的列表--例如<#list qrCodeList as qrCode></#list>
qrCodeList是后台传过来的数据名称例如
dataMap("qrCodeList",list);
list中也可以是list

qrCode是数据元素

 

编辑好后保存,保存后直接修改文件为.ftl文件例如model.ftl
3.在pom.xml文件中引入freemarker
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.23</version>
</dependency>

 

 

 

4.创建工具类ExportWord(若configuration报空异常,请在createWord方法中创建 (不建议这么做))
 
public class ExportWord {

    private static final String templateFolder = ExportWord.class.getClassLoader().getResource("../..").getPath()+"/ftl";
    private Configuration configuration = null;
   
    public ExportWord(){
        configuration = new Configuration();
        configuration.setDefaultEncoding("UTF-8");
    }
    public File createWord(Map<String, Object> dataMap, String hallName) throws Exception {
        Date date = new Date();
       
        configuration.setDirectoryForTemplateLoading(new File(templateFolder));
        configuration.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
        Template t = null;
        try {
            t = configuration.getTemplate("model.ftl"); // 文件名
        } catch (IOException e) {
            e.printStackTrace();
        }
        File outFile = new File(hallName+date.getTime() + ".doc");
        Writer w = null;
        try {
            w = new OutputStreamWriter(new FileOutputStream(outFile), "utf-8");
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        try {
            t.process(dataMap, w);
            w.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return outFile;
    }

    public void getData(Map<String, Object> dataMap,List<SeatInfo> seatInfo,MovieHallExt movieHallExt) {
        int sum = Integer.parseInt(movieHallExt.getHallCapacity());
        List<List<QRCode>> qrCodes = new ArrayList<>();
        List<QRCode> list = new ArrayList<>();
        for (int i = 0;i<sum ;i++){
               QRCode qrCode = new QRCode();
               qrCode.setImagedata(getImageStr(seatInfo.get(i).getRowId(),seatInfo.get(i).getColId()));
               qrCode.setRow(Integer.parseInt(seatInfo.get(i).getRowId()));
               qrCode.setCol(Integer.parseInt(seatInfo.get(i).getColId()));
               list.add(qrCode);
           }
        for(int c = 0;c < sum;c=c+6){
            if(c+6 < sum){
               qrCodes.add(list.subList(c,c+6));
            }else{
               qrCodes.add(list.subList(c,sum));
            }
        }
           dataMap.put("qrCodes",qrCodes);
    }

    private String getImageStr(String row,String col) {
        String content = row + "-" + col;
        BufferedImage image = null;
        ByteArrayOutputStream outputStream =null;
        try{
            image = QRCodeServiceImpl.createQRCode(content);
            outputStream = new ByteArrayOutputStream();
            ImageIO.write(image, "jpg", outputStream);
        }catch (Exception e){

        }
        String imageCodeBase64 = Base64.encodeBase64String(outputStream.toByteArray());
        return imageCodeBase64;
    }


}
5.controller调用ExportWord工具类

 

@RequestMapping("/exportReport")
    public void exportReport(String hallCode,HttpServletResponse response, HttpServletRequest request, String picBase64Info1) {
        Result result = new Result();
        List<SeatInfo> seatInfo = takeoutService.getSeatInfo(hallCode);
        MovieHallExt movieHallExt = takeoutService.getHallByCode(hallCode);
        ExportWord test = new ExportWord();
        Map<String, Object> dataMap = new HashMap<String, Object>();
        File file = null;
        try {
            test.getData(dataMap,seatInfo,movieHallExt);
            file  = test.createWord(dataMap,movieHallExt.getHallName());
            result.setResultCode("0");
        }catch (Exception e){
            result.setResultCode("1");
            System.out.println("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"+e);
        }

        InputStream fin = null;
        OutputStream out = null;
        try{
            fin = new FileInputStream(file);

            response.reset();
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/octet-stream; charset=utf-8");
//            response.setContentType("application/msword");
            response.setHeader("Content-Disposition","attachment; filename="+ Encodes.urlEncode(movieHallExt.getHallName())+".doc");
            out = response.getOutputStream();
            byte[] buffer = new byte[512];
            int b =-1;
            while ((b=fin.read(buffer))!= -1){
                out.write(buffer,0,b);
            }
            out.close();
            fin.close();
            result.setResultCode("0");
        }catch (Exception e){
            e.printStackTrace();
            System.out.println(e);
            result.setResultCode("1");
        }finally {
            try{
                if(out!=null){
                out.close();
                }
                if(fin != null){
                    fin.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }

        }
    }
 
 

 

 

6.难点解决
在网上有经典的三种读取模板的方法:

 

public void setClassForTemplateLoading(Class clazz, String pathPrefix);

public void setDirectoryForTemplateLoading(File dir) throws IOException;

public void setServletContextForTemplateLoading(Object servletContext, String path);

 

第一种:基于类路径,HttpWeb包下的framemaker.ftl文件(例如你的模板文件在包com.templete.ftl下)  configuration.setClassForTemplateLoading(this.getClass(), "/com/templete/ftl");(用这种方法一开始读成功一次,后面报null)。

 

configuration.getTemplate("framemaker.ftl"); //framemaker.ftl为要装载的模板

第二种:基于文件系统(例如模板D盘的ftl文件夹,操作正确不会报错)。

configuration.setDirectoryForTemplateLoading(new File("D:/ftl/");

configuration.getTemplate("framemaker.ftl"); //framemaker.ftl为要装载的模板

第三种:基于Servlet Context,指的是基于WebRoot下的template下的framemaker.ftl文件(不适合基于springboot的项目)

HttpServletRequest request = ServletActionContext.getRequest();

configuration.setServletContextForTemplateLoading(request.getSession().getServletContext(), "/template");

 

 

configuration.getTemplate("framemaker.ftl"); //framemaker.ftl为要装载的模板
 

 

 

在这三种方式中只有第二种基于文件系统的,可用且稳定。但是这只能基于在本机运行。
最后找到下面这个方法也是基于第二种方法的但是将模板文件放在WEB-INF下的某个文件里的(自己建个就可以)

 

 

例如在WEB-INF中的ftl文件夹中可以这样读:
private static final String templateFolder = ExportWord.class.getClassLoader().getResource("../..").getPath()+"/ftl";

 

configuration.setDirectoryForTemplateLoading(new File(templateFolder));
configuration.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
Template t = null;
try {
    t = configuration.getTemplate("model.ftl"); // 文件名
} catch (IOException e) {
    e.printStackTrace();
}
这样项目就可以部署到其他地方了。

 

 

 

效果图
 

 

 

ftl文件
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?mso-application progid="Word.Document"?>
<w:wordDocument xmlns:aml="http://schemas.microsoft.com/aml/2001/core" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml" xmlns:wx="http://schemas.microsoft.com/office/word/2003/auxHint" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wsp="http://schemas.microsoft.com/office/word/2003/wordml/sp2" xmlns:sl="http://schemas.microsoft.com/schemaLibrary/2003/core" w:macrosPresent="no" w:embeddedObjPresent="no" w:ocxPresent="no" xml:space="preserve">
<w:ignoreSubtree w:val="http://schemas.microsoft.com/office/word/2003/wordml/sp2"/>
<o:DocumentProperties>
<o:Author>Windows 用户</o:Author>
<o:LastAuthor>Windows 用户</o:LastAuthor>
<o:Revision>1</o:Revision>
<o:TotalTime>8</o:TotalTime>
<o:Created>2018-05-18T04:22:00Z</o:Created>
<o:LastSaved>2018-05-18T04:30:00Z</o:LastSaved>
<o:Pages>1</o:Pages>
<o:Words>2</o:Words>
<o:Characters>14</o:Characters>
<o:Lines>1</o:Lines>
<o:Paragraphs>1</o:Paragraphs>
<o:CharactersWithSpaces>15</o:CharactersWithSpaces>
<o:Version>14</o:Version>
</o:DocumentProperties>
<w:fonts>
<w:defaultFonts w:ascii="Calibri" w:fareast="宋体" w:h-ansi="Calibri" w:cs="Times New Roman"/>
<w:font w:name="Times New Roman">
<w:panose-1 w:val="02020603050405020304"/>
<w:charset w:val="00"/>
<w:family w:val="Roman"/>
<w:pitch w:val="variable"/>
<w:sig w:usb-0="E0002EFF" w:usb-1="C000785B" w:usb-2="00000009" w:usb-3="00000000" w:csb-0="000001FF" w:csb-1="00000000"/>
</w:font>
<w:font w:name="宋体">
<w:altName w:val="SimSun"/>
<w:panose-1 w:val="02010600030101010101"/>
<w:charset w:val="86"/>
<w:family w:val="auto"/>
<w:pitch w:val="variable"/>
<w:sig w:usb-0="00000003" w:usb-1="288F0000" w:usb-2="00000016" w:usb-3="00000000" w:csb-0="00040001" w:csb-1="00000000"/>
</w:font>
<w:font w:name="Cambria Math">
<w:panose-1 w:val="02040503050406030204"/>
<w:charset w:val="01"/>
<w:family w:val="Roman"/>
<w:notTrueType/>
<w:pitch w:val="variable"/>
</w:font>
<w:font w:name="Calibri">
<w:panose-1 w:val="020F0502020204030204"/>
<w:charset w:val="00"/>
<w:family w:val="Swiss"/>
<w:pitch w:val="variable"/>
<w:sig w:usb-0="E0002AFF" w:usb-1="C000247B" w:usb-2="00000009" w:usb-3="00000000" w:csb-0="000001FF" w:csb-1="00000000"/>
</w:font>
<w:font w:name="@宋体">
<w:panose-1 w:val="02010600030101010101"/>
<w:charset w:val="86"/>
<w:family w:val="auto"/>
<w:pitch w:val="variable"/>
<w:sig w:usb-0="00000003" w:usb-1="288F0000" w:usb-2="00000016" w:usb-3="00000000" w:csb-0="00040001" w:csb-1="00000000"/>
</w:font>
</w:fonts>
<w:styles>
<w:versionOfBuiltInStylenames w:val="7"/>
<w:latentStyles w:defLockedState="off" w:latentStyleCount="267">
<w:lsdException w:name="Normal"/>
<w:lsdException w:name="heading 1"/>
<w:lsdException w:name="heading 2"/>
<w:lsdException w:name="heading 3"/>
<w:lsdException w:name="heading 4"/>
<w:lsdException w:name="heading 5"/>
<w:lsdException w:name="heading 6"/>
<w:lsdException w:name="heading 7"/>
<w:lsdException w:name="heading 8"/>
<w:lsdException w:name="heading 9"/>
<w:lsdException w:name="toc 1"/>
<w:lsdException w:name="toc 2"/>
<w:lsdException w:name="toc 3"/>
<w:lsdException w:name="toc 4"/>
<w:lsdException w:name="toc 5"/>
<w:lsdException w:name="toc 6"/>
<w:lsdException w:name="toc 7"/>
<w:lsdException w:name="toc 8"/>
<w:lsdException w:name="toc 9"/>
<w:lsdException w:name="caption"/>
<w:lsdException w:name="Title"/>
<w:lsdException w:name="Default Paragraph Font"/>
<w:lsdException w:name="Subtitle"/>
<w:lsdException w:name="Strong"/>
<w:lsdException w:name="Emphasis"/>
<w:lsdException w:name="Table Grid"/>
<w:lsdException w:name="Placeholder Text"/>
<w:lsdException w:name="No Spacing"/>
<w:lsdException w:name="Light Shading"/>
<w:lsdException w:name="Light List"/>
<w:lsdException w:name="Light Grid"/>
<w:lsdException w:name="Medium Shading 1"/>
<w:lsdException w:name="Medium Shading 2"/>
<w:lsdException w:name="Medium List 1"/>
<w:lsdException w:name="Medium List 2"/>
<w:lsdException w:name="Medium Grid 1"/>
<w:lsdException w:name="Medium Grid 2"/>
<w:lsdException w:name="Medium Grid 3"/>
<w:lsdException w:name="Dark List"/>
<w:lsdException w:name="Colorful Shading"/>
<w:lsdException w:name="Colorful List"/>
<w:lsdException w:name="Colorful Grid"/>
<w:lsdException w:name="Light Shading Accent 1"/>
<w:lsdException w:name="Light List Accent 1"/>
<w:lsdException w:name="Light Grid Accent 1"/>
<w:lsdException w:name="Medium Shading 1 Accent 1"/>
<w:lsdException w:name="Medium Shading 2 Accent 1"/>
<w:lsdException w:name="Medium List 1 Accent 1"/>
<w:lsdException w:name="Revision"/>
<w:lsdException w:name="List Paragraph"/>
<w:lsdException w:name="Quote"/>
<w:lsdException w:name="Intense Quote"/>
<w:lsdException w:name="Medium List 2 Accent 1"/>
<w:lsdException w:name="Medium Grid 1 Accent 1"/>
<w:lsdException w:name="Medium Grid 2 Accent 1"/>
<w:lsdException w:name="Medium Grid 3 Accent 1"/>
<w:lsdException w:name="Dark List Accent 1"/>
<w:lsdException w:name="Colorful Shading Accent 1"/>
<w:lsdException w:name="Colorful List Accent 1"/>
<w:lsdException w:name="Colorful Grid Accent 1"/>
<w:lsdException w:name="Light Shading Accent 2"/>
<w:lsdException w:name="Light List Accent 2"/>
<w:lsdException w:name="Light Grid Accent 2"/>
<w:lsdException w:name="Medium Shading 1 Accent 2"/>
<w:lsdException w:name="Medium Shading 2 Accent 2"/>
<w:lsdException w:name="Medium List 1 Accent 2"/>
<w:lsdException w:name="Medium List 2 Accent 2"/>
<w:lsdException w:name="Medium Grid 1 Accent 2"/>
<w:lsdException w:name="Medium Grid 2 Accent 2"/>
<w:lsdException w:name="Medium Grid 3 Accent 2"/>
<w:lsdException w:name="Dark List Accent 2"/>
<w:lsdException w:name="Colorful Shading Accent 2"/>
<w:lsdException w:name="Colorful List Accent 2"/>
<w:lsdException w:name="Colorful Grid Accent 2"/>
<w:lsdException w:name="Light Shading Accent 3"/>
<w:lsdException w:name="Light List Accent 3"/>
<w:lsdException w:name="Light Grid Accent 3"/>
<w:lsdException w:name="Medium Shading 1 Accent 3"/>
<w:lsdException w:name="Medium Shading 2 Accent 3"/>
<w:lsdException w:name="Medium List 1 Accent 3"/>
<w:lsdException w:name="Medium List 2 Accent 3"/>
<w:lsdException w:name="Medium Grid 1 Accent 3"/>
<w:lsdException w:name="Medium Grid 2 Accent 3"/>
<w:lsdException w:name="Medium Grid 3 Accent 3"/>
<w:lsdException w:name="Dark List Accent 3"/>
<w:lsdException w:name="Colorful Shading Accent 3"/>
<w:lsdException w:name="Colorful List Accent 3"/>
<w:lsdException w:name="Colorful Grid Accent 3"/>
<w:lsdException w:name="Light Shading Accent 4"/>
<w:lsdException w:name="Light List Accent 4"/>
<w:lsdException w:name="Light Grid Accent 4"/>
<w:lsdException w:name="Medium Shading 1 Accent 4"/>
<w:lsdException w:name="Medium Shading 2 Accent 4"/>
<w:lsdException w:name="Medium List 1 Accent 4"/>
<w:lsdException w:name="Medium List 2 Accent 4"/>
<w:lsdException w:name="Medium Grid 1 Accent 4"/>
<w:lsdException w:name="Medium Grid 2 Accent 4"/>
<w:lsdException w:name="Medium Grid 3 Accent 4"/>
<w:lsdException w:name="Dark List Accent 4"/>
<w:lsdException w:name="Colorful Shading Accent 4"/>
<w:lsdException w:name="Colorful List Accent 4"/>
<w:lsdException w:name="Colorful Grid Accent 4"/>
<w:lsdException w:name="Light Shading Accent 5"/>
<w:lsdException w:name="Light List Accent 5"/>
<w:lsdException w:name="Light Grid Accent 5"/>
<w:lsdException w:name="Medium Shading 1 Accent 5"/>
<w:lsdException w:name="Medium Shading 2 Accent 5"/>
<w:lsdException w:name="Medium List 1 Accent 5"/>
<w:lsdException w:name="Medium List 2 Accent 5"/>
<w:lsdException w:name="Medium Grid 1 Accent 5"/>
<w:lsdException w:name="Medium Grid 2 Accent 5"/>
<w:lsdException w:name="Medium Grid 3 Accent 5"/>
<w:lsdException w:name="Dark List Accent 5"/>
<w:lsdException w:name="Colorful Shading Accent 5"/>
<w:lsdException w:name="Colorful List Accent 5"/>
<w:lsdException w:name="Colorful Grid Accent 5"/>
<w:lsdException w:name="Light Shading Accent 6"/>
<w:lsdException w:name="Light List Accent 6"/>
<w:lsdException w:name="Light Grid Accent 6"/>
<w:lsdException w:name="Medium Shading 1 Accent 6"/>
<w:lsdException w:name="Medium Shading 2 Accent 6"/>
<w:lsdException w:name="Medium List 1 Accent 6"/>
<w:lsdException w:name="Medium List 2 Accent 6"/>
<w:lsdException w:name="Medium Grid 1 Accent 6"/>
<w:lsdException w:name="Medium Grid 2 Accent 6"/>
<w:lsdException w:name="Medium Grid 3 Accent 6"/>
<w:lsdException w:name="Dark List Accent 6"/>
<w:lsdException w:name="Colorful Shading Accent 6"/>
<w:lsdException w:name="Colorful List Accent 6"/>
<w:lsdException w:name="Colorful Grid Accent 6"/>
<w:lsdException w:name="Subtle Emphasis"/>
<w:lsdException w:name="Intense Emphasis"/>
<w:lsdException w:name="Subtle Reference"/>
<w:lsdException w:name="Intense Reference"/>
<w:lsdException w:name="Book Title"/>
<w:lsdException w:name="Bibliography"/>
<w:lsdException w:name="TOC Heading"/>
</w:latentStyles>
<w:style w:type="paragraph" w:default="on" w:styleId="a">
<w:name w:val="Normal"/>
<wx:uiName wx:val="正文"/>
<w:pPr>
<w:widowControl w:val="off"/>
<w:jc w:val="both"/>
</w:pPr>
<w:rPr>
<wx:font wx:val="Calibri"/>
<w:kern w:val="2"/>
<w:sz w:val="21"/>
<w:sz-cs w:val="22"/>
<w:lang w:val="EN-US" w:fareast="ZH-CN" w:bidi="AR-SA"/>
</w:rPr>
</w:style>
<w:style w:type="character" w:default="on" w:styleId="a0">
<w:name w:val="Default Paragraph Font"/>
<wx:uiName wx:val="默认段落字体"/>
</w:style>
<w:style w:type="table" w:default="on" w:styleId="a1">
<w:name w:val="Normal Table"/>
<wx:uiName wx:val="普通表格"/>
<w:rPr>
<wx:font wx:val="Calibri"/>
<w:lang w:val="EN-US" w:fareast="ZH-CN" w:bidi="AR-SA"/>
</w:rPr>
<w:tblPr>
<w:tblInd w:w="0" w:type="dxa"/>
<w:tblCellMar>
<w:top w:w="0" w:type="dxa"/>
<w:left w:w="108" w:type="dxa"/>
<w:bottom w:w="0" w:type="dxa"/>
<w:right w:w="108" w:type="dxa"/>
</w:tblCellMar>
</w:tblPr>
</w:style>
<w:style w:type="list" w:default="on" w:styleId="a2">
<w:name w:val="No List"/>
<wx:uiName wx:val="无列表"/>
</w:style>
<w:style w:type="table" w:styleId="a3">
<w:name w:val="Table Grid"/>
<wx:uiName wx:val="网格型"/>
<w:basedOn w:val="a1"/>
<w:rsid w:val="00F76479"/>
<w:rPr>
<wx:font wx:val="Calibri"/>
</w:rPr>
<w:tblPr>
<w:tblInd w:w="0" w:type="dxa"/>
<w:tblBorders>
<w:top w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
<w:left w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
<w:bottom w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
<w:right w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
<w:insideH w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
<w:insideV w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
</w:tblBorders>
<w:tblCellMar>
<w:top w:w="0" w:type="dxa"/>
<w:left w:w="108" w:type="dxa"/>
<w:bottom w:w="0" w:type="dxa"/>
<w:right w:w="108" w:type="dxa"/>
</w:tblCellMar>
</w:tblPr>
</w:style>
<w:style w:type="paragraph" w:styleId="a4">
<w:name w:val="Balloon Text"/>
<wx:uiName wx:val="批注框文本"/>
<w:basedOn w:val="a"/>
<w:link w:val="Char"/>
<w:rsid w:val="00F76479"/>
<w:rPr>
<wx:font wx:val="Calibri"/>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
</w:style>
<w:style w:type="character" w:styleId="Char">
<w:name w:val="批注框文本 Char"/>
<w:link w:val="a4"/>
<w:rsid w:val="00F76479"/>
<w:rPr>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
</w:style>
</w:styles>
<w:shapeDefaults>
<o:shapedefaults v:ext="edit" spidmax="1026"/>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1"/>
</o:shapelayout>
</w:shapeDefaults>
<w:docPr>
<w:view w:val="print"/>
<w:zoom w:percent="120"/>
<w:doNotEmbedSystemFonts/>
<w:bordersDontSurroundHeader/>
<w:bordersDontSurroundFooter/>
<w:defaultTabStop w:val="420"/>
<w:drawingGridHorizontalSpacing w:val="105"/>
<w:drawingGridVerticalSpacing w:val="156"/>
<w:displayHorizontalDrawingGridEvery w:val="0"/>
<w:displayVerticalDrawingGridEvery w:val="2"/>
<w:punctuationKerning/>
<w:characterSpacingControl w:val="CompressPunctuation"/>
<w:optimizeForBrowser/>
<w:allowPNG/>
<w:validateAgainstSchema/>
<w:saveInvalidXML w:val="off"/>
<w:ignoreMixedContent w:val="off"/>
<w:alwaysShowPlaceholderText w:val="off"/>
<w:compat>
<w:spaceForUL/>
<w:balanceSingleByteDoubleByteWidth/>
<w:doNotLeaveBackslashAlone/>
<w:ulTrailSpace/>
<w:doNotExpandShiftReturn/>
<w:adjustLineHeightInTable/>
<w:breakWrappedTables/>
<w:snapToGridInCell/>
<w:wrapTextWithPunct/>
<w:useAsianBreakRules/>
<w:dontGrowAutofit/>
<w:useFELayout/>
</w:compat>
<wsp:rsids>
<wsp:rsidRoot wsp:val="00F76479"/>
<wsp:rsid wsp:val="00F76479"/>
<wsp:rsid wsp:val="00FD1158"/>
</wsp:rsids>
</w:docPr>
<w:body>
<wx:sect>
<w:tbl>
<w:tblPr>
<w:tblW w:w="0" w:type="auto"/>
<w:tblLook w:val="04A0"/>
</w:tblPr>
<w:tblGrid>
<w:gridCol w:w="2376"/>
</w:tblGrid>
外层循环开始<#list qrCodes as qrCodeList>
<w:tr wsp:rsidR="00F76479" wsp:rsidRPr="00F76479" wsp:rsidTr="00F76479">
<w:trPr>
<w:trHeight w:val="2117"/>
</w:trPr>
内层循环<#list qrCodeList as qrCode>
<w:tc>
<w:tcPr>
<w:tcW w:w="2376" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p wsp:rsidR="00F76479" wsp:rsidRPr="00F76479" wsp:rsidRDefault="00F76479" wsp:rsidP="00F76479">
<w:pPr>
<w:jc w:val="center"/>
<w:rPr>
<w:rFonts w:hint="fareast"/>
</w:rPr>
</w:pPr>
<w:r wsp:rsidRPr="00F76479">
<w:rPr>
<wx:font wx:val="宋体"/>
</w:rPr>
<w:t>欢迎扫码点餐</w:t>
</w:r>
</w:p>
<w:p wsp:rsidR="00F76479" wsp:rsidRPr="00F76479" wsp:rsidRDefault="00F76479" wsp:rsidP="00F76479">
<w:pPr>
<w:jc w:val="center"/>
<w:rPr>
<w:rFonts w:hint="fareast"/>
</w:rPr>
</w:pPr>
<w:r wsp:rsidRPr="00FA2ACC">
<w:rPr>
<w:noProof/>
</w:rPr>
<w:pict>
<v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f">
<v:stroke joinstyle="miter"/>
<v:formulas>
<v:f eqn="if lineDrawn pixelLineWidth 0"/>
<v:f eqn="sum @0 1 0"/>
<v:f eqn="sum 0 0 @1"/>
<v:f eqn="prod @2 1 2"/>
<v:f eqn="prod @3 21600 pixelWidth"/>
<v:f eqn="prod @3 21600 pixelHeight"/>
<v:f eqn="sum @0 0 1"/>
<v:f eqn="prod @6 1 2"/>
<v:f eqn="prod @7 21600 pixelWidth"/>
<v:f eqn="sum @8 21600 0"/>
<v:f eqn="prod @7 21600 pixelHeight"/>
<v:f eqn="sum @10 21600 0"/>
</v:formulas>
<v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"/>
<o:lock v:ext="edit" aspectratio="t"/>
</v:shapetype>
记得修改name,要不图片重复第一张qrCode_index为循环下标
<w:binData w:name="${"wordml://qrcode_"+qrCodeList_index+qrCode_index+".jpg"}" xml:space="preserve">
${qrCode.imagedata}
</w:binData>
<v:shape id="图片 1" o:spid="_x0000_i1025" type="#_x0000_t75" style="width:90.5pt;height:74.5pt;visibility:visible;mso-wrap-style:square">
记得修改src,要不图片重复第一张qrCode_index为循环下标
<v:imagedata src="${"wordml://qrcode_"+qrCodeList_index+qrCode_index+".jpg"}" o:title=""/>
</v:shape>
</w:pict>
</w:r>
</w:p>
<w:p wsp:rsidR="00F76479" wsp:rsidRPr="00F76479" wsp:rsidRDefault="00F76479" wsp:rsidP="00F76479">
<w:pPr>
<w:jc w:val="center"/>
</w:pPr>
<w:r wsp:rsidRPr="00F76479">
<w:rPr>
<w:rFonts w:hint="fareast"/>
</w:rPr>
<w:t>${qrCode.row}</w:t>
</w:r>
<w:r wsp:rsidRPr="00F76479">
<w:rPr>
<w:rFonts w:hint="fareast"/>
<wx:font wx:val="宋体"/>
</w:rPr>
<w:t>排</w:t>
</w:r>
<w:r wsp:rsidRPr="00F76479">
<w:rPr>
<w:rFonts w:hint="fareast"/>
</w:rPr>
<w:t>${qrCode.col}</w:t>
</w:r>
<w:r wsp:rsidRPr="00F76479">
<w:rPr>
<w:rFonts w:hint="fareast"/>
<wx:font wx:val="宋体"/>
</w:rPr>
<w:t>座</w:t>
</w:r>
</w:p>
</w:tc>
内层循环结束</#list>
</w:tr>
<w:tr wsp:rsidR="005E20D3" wsp:rsidRPr="005E20D3" wsp:rsidTr="005E20D3">
<w:tc>
<w:tcPr>
<w:tcW w:w="2802" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p wsp:rsidR="005E20D3" wsp:rsidRPr="005E20D3" wsp:rsidRDefault="005E20D3" wsp:rsidP="00522DAD"/>
</w:tc>
</w:tr>
外层循环结束</#list>
</w:tbl>
<w:p wsp:rsidR="00F76479" wsp:rsidRDefault="00F76479"/>
<w:sectPr wsp:rsidR="00F76479" wsp:rsidSect="00F76479">
<w:pgSz w:w="16838" w:h="11906" w:orient="landscape"/>
<w:pgMar w:top="1800" w:right="1440" w:bottom="1800" w:left="1440" w:header="851" w:footer="992" w:gutter="0"/>
<w:cols w:space="425"/>
<w:docGrid w:type="lines" w:line-pitch="312"/>
</w:sectPr>
</wx:sect>
</w:body>
</w:wordDocument>

 

 

 

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
SpringBoot_Freemarker生成Word_多个表格+两层嵌套循环; 步骤说明: 1.用Microsoft Office Word打开word原件;将文档需要动态生成的内容,替换为属性名 ${name} 2.另存为,选择保存类型Word 2003 XML 文档(*.xml) 3.用Firstobject free XML editor打开文件,选择Tools下的Indent【或者按快捷键F8】格式化文件内容。左边是文档结构,右边是文档内容; 4. 文档生成后有时需要手动修改,查找第一步设置的属性名,可能会产生类似${n.....ame}类似的样子,我们将将名字间的标签删掉,恢复为${name} 5. word模板有表格,需要循环的位置, 用 标签将第二对 标签(即除表头的w:tr标签后的一对)包围起来 同时表格内的属性例如${name},在这里需要修改为${user.name} (userList是集合在dataMap的key, user是集合的每个元素, 类似), 如图: PLUS:若表格之外还有嵌套的循环,也需要用,注意这里的标签不要和某对其他标签交叉,不可以出现这种 6. 标识替换完之后,另存为.ftl后缀文件即可。 代码里是相对有一丢丢复杂的,两层嵌套循环; 总(dataMap) deptName 部门名 list(Table)表的集合 table1(map) table-名字 ${map.table} tableName-文名 ${map.tableName} columnCount-字段数 ${map.columnCount} recordCount-记录数 ${map.recordCount} listA-List--表格1 map.listA column Model属性——字段名 ${model.column} columnName Model属性——字段文名 ${model.column} rate Model属性——字段占比 ${model.rate} nullValueCount Model属性——字段空值数 ${model.nullValueCount} listB-List--表格2 map.listB …… listC-List--表格3 map.listC …… table2 table-名字 ${map.table} tableName-文名 ${map.tableName} columnCount-字段数 ${map.columnCount} recordCount-记录数 ${map.recordCount} listA-List--表格1 map.listA column Model属性——字段名 ${model.column} columnName Model属性——字段文名 ${model.column} rate Model属性——字段占比 ${model.rate} nullValueCount Model属性——字段空值数 ${model.nullValueCount} listB-List--表格2 map.listB …… listC-List--表格3 map.listC …… table3 ……

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值