先看依赖的包:

<dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.28</version>
        </dependency>

整体思路:

1.先构建一个需要生成的word报告模板,我只需要把里边关键位置的文件和图片替换掉就可以了,那就必须要求word样式固定,里边的格式必须是这样

java xml转 java xml转word_生成word报告


2.把word文件用压缩包工具打开,解压出这个xml文件,后边主要操作这个文件,把内容替换掉就可以,必须是07以后的版本,03的word不支持

java xml转 java xml转word_生成word报告_02


处理办法:

把文件用xml编辑器打开,我用的是notepad++,必须要有xml的格式化插件,要不然里边格式是乱的,格式化之后,看到这样的东西

java xml转 java xml转word_生成word报告_03


java xml转 java xml转word_xml_04


处理号这个xml之后,就可以开始写代码了,

```java
static Template template;

static{
    //创建配置实例
    Configuration configuration = new Configuration();
    //设置编码
    configuration.setDefaultEncoding("UTF-8");
    //ftl模板文件统一放至/包下面
    configuration.setClassForTemplateLoading(CreatWordService.class,"/");
    // 获取模板
    try {
        template = configuration.getTemplate("document.xml");
        template.setOutputEncoding("UTF-8");
    } catch (IOException e) {
        log.error("[加载模板xml失败:{}]",e.getMessage());
        e.printStackTrace();
    }
}

下来使用它
主方法,生成报告的流程

```Writer out = null;
        try {
            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(xmlTemp),"UTF-8"));
            //1.需要动态传入的数据
            Map<String, Object> root = initRootData(c3Entiy);
            template.process(root, out);
            out.close();
            //3.把填充完成的xml写入到docx中
            log.info("[把填充完成的xml写入到docx中]");
            String reportPath = outDocx(new File(xmlTemp), Const.DOCX_TEMPLATE, toFilePath,c3Entiy);
            log.info("[生成报告路径:{}]",reportPath);
            return  reportPath;
        } catch (IOException e) {
            log.info("[生成报告异常:{}]",e.getMessage());
            e.printStackTrace();
            return "";
        } catch (TemplateException e) {
            log.info("[生成报告异常:{}]",e.getMessage());
            e.printStackTrace();
            return "";
        }

主要的两个方法:

private Map<String, Object> initRootData(C3ot c3Entiy) {
        Map<String, Object> root= new HashMap<>();
        root.clear();
        root.put("cheCiHao", c3Entiy.getTrainnum());     //车次号
        Calendar cal = Calendar.getInstance();
        cal.setTime(c3Entiy.getPreDisctime());

        root.put("guZhangShiJian_Nian", String.valueOf(cal.get(Calendar.YEAR)));      //故障时间年份
        root.put("guZhangShiJian_Yue", cal.get(Calendar.MONTH) + 1);          //故障时间月份
  
        List<Abislayer3message> abislayer3messageList = abislayer3messageMapper.selectRecordByC3ot(c3Entiy);
//这个list里边放map,map的key就是xml里表格配置的key,value是需要写在报告里的内容,这个方法不全,我只是举个例子,
        List<Map<String,String>> MT1_PRI_1_List = initDataListService.getMT1_PRI_1_List(c3Entiy);
        root.put("MT1_PRI_1_List",MT1_PRI_1_List);
        return root;
    }

这个方法也比较重要,遍历word模板的解压包,找到对应的文件,替换掉

/**
     *
     * @param documentFile  动态生成数据的docunment.xml文件
     * @param docxTemplate    docx的模板
     * @param toFilePath    需要导出的文件路径
     * @param c3Entiy
     * @throws ZipException
     * @throws IOException
     */

    public  String outDocx(File documentFile, String docxTemplate, String toFilePath, C3ot c3Entiy)
    {
        try {
            //String fileName = CreatWordService.class.getClassLoader().getResource(docxTemplate).toURI().getPath();
            File docxFile = new File(docxTemplate);
            ZipFile zipFile = new ZipFile(docxFile);
            Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();
            ZipOutputStream zipout = new ZipOutputStream(new FileOutputStream(toFilePath));
            int len=-1;
            byte[] buffer=new byte[1024];
            while(zipEntrys.hasMoreElements()) {
                ZipEntry next = zipEntrys.nextElement();
                InputStream is = zipFile.getInputStream(next);
                //把输入流的文件传到输出流中 如果是word/document.xml由我们输入
                zipout.putNextEntry(new ZipEntry(next.toString()));
                switch(next.toString()){
                    case "word/media/image1.png" :
                        //生成图表
                        log.info("[准备生成图表:{}]","chart1");
                        String image1Path = createChartService.createChart(c3Entiy,"chart12");
                        if(null == image1Path || "".equals(image1Path)){
                            break;
                        }
                        File file1 = new File(image1Path);
                        System.out.println("path----------->" + file1.getAbsolutePath());
                        InputStream in1 = new FileInputStream(file1);
                        while((len = in1.read(buffer))!=-1){
                            zipout.write(buffer,0,len);
                        }
                        in1.close();
                        file1.delete();
                        break;
                    case "word/media/image2.png" :
                        log.info("[准备生成图表:{}]","chart2");
                        String image2Path = createChartService.createChart(c3Entiy,"chart34");
                        if(null == image2Path || "".equals(image2Path)){
                            break;
                        }
                        File file2 = new File(image2Path);
                        InputStream in2 = new FileInputStream(file2);
                        while((len = in2.read(buffer))!=-1){
                            zipout.write(buffer,0,len);
                        }
                        in2.close();
                        file2.delete();
                        break;
                    case "word/document.xml" :
                        InputStream in = new FileInputStream(documentFile);
                        while((len = in.read(buffer))!=-1){
                            zipout.write(buffer,0,len);
                        }
                        in.close();
                        break;
                    default :
                        while((len = is.read(buffer))!=-1){
                            zipout.write(buffer,0,len);
                        }
                        is.close();
                }
            }
            zipout.close();
            log.info("[准备删除模板文件:{}]",documentFile.getAbsolutePath());
            documentFile.delete();
        }catch (FileNotFoundException e) {
            log.info("[压缩文件时异常:{}]",e.getMessage());
            e.printStackTrace();
            return "";
        } catch (ZipException e) {
            log.info("[压缩文件时异常:{}]",e.getMessage());
            e.printStackTrace();
            return "";
        } catch (IOException e) {
            log.info("[压缩文件时异常:{}]",e.getMessage());
            e.printStackTrace();
            return "";
        }
        return toFilePath;
    }

里边有个替换图片的方法,如果在word文件中有图片,解压后的word文件下,按照代码中的对应目录路径,就能找到图片,替换掉就可以了,很好理解。
至此就大功告成了