java根据word模板填充数据并导出

方法一(推荐):

1、文件处理

 

 效果图:

 

 说明:列表头部必须加标记如{{wordList}},子项必须是[xx];图片必须是{{@xx}}

所有的标签都是以 {{开始,以}} 结束。

  • {{template}} 文本

  • {{@template}} 图片

  • {{#template}} 表格

  • {{*template}} 列表

  • {{+template}} Word 文档合并

  • {{?template}}{{/template}} if 和 foreach 功能

2、引入包

复制代码
<!--    POI 依赖 使用xlsx xml的格式(即XSSFWorkbook)   -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>5.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>5.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-scratchpad</artifactId>
            <version>3.17</version>
        </dependency>
        <!--     poi模板导入,主力包      -->
        <dependency>
            <groupId>com.deepoove</groupId>
            <artifactId>poi-tl</artifactId>
            <version>1.12.1</version>
        </dependency>
复制代码

3、代码示例片段

复制代码
HashMap<String, Object> finalMap = new HashMap<>();
finalMap.put("ProjectName","2342");
finalMap.put("PROJECT_CODE","中世e招4楼评标厅");
finalMap.put("AgentUnit","23423");
finalMap.put("OwnerUnit","20221321");
finalMap.put("type","20221321");
finalMap.put("Budget","20221321");
finalMap.put("OPEN_TIME","20221321");
finalMap.put("Is_Allowed_Extract_Same_Unit","20221321");
finalMap.put("Notice_type","20221321");
finalMap.put("ExtractTime","20221321");


ArrayList<Object> workList = CollUtil.newArrayList();
for (int i = 0; i < 3; i++) {
// 模拟从mysql查询列表数据
HashMap<String, Object> workItem = new HashMap<>();
workItem.put("NAME", i + 1);
workItem.put("ORG", "四川有限公司" + i);
workItem.put("ID_CARD", i + 10 + "小时");
workItem.put("PHONE", "800" + i);
workItem.put("EXPERT_TYPE_NAME", "项目经理" + i);
workItem.put("DNAME", "java工程师" + i);
workList.add(workItem);
}
finalMap.put("workList", workList);


// 插入图片
try {
//这里也可以是用文件服务器返回的网络文件流
String pictureUrl = "http://5b0988e595225.cdn.sohucs.com/images/20171013/fec49f59b98041a4a16886893447f746.jpeg";
pictureUrl = "D:\\xx\\Java项目\\xx\\sxsoft_expert\\staticfile\\下载.png";
// 从网络流读取图片,置入word模板,等待编译
if (Validator.isNotEmpty(pictureUrl)) {
//PictureRenderData picture = Pictures.ofUrl(pictureUrl).size(40, 30).create();//网络图片地址
PictureRenderData picture = Pictures.ofLocal(pictureUrl).size(40, 30).create();//本地图片地址
finalMap.put("signPicture", picture);
}
} catch (Exception e) {
e.printStackTrace();
}


// 从网络url 下载word模板到指定文件夹
File wordTemplate = new File("D:\\xx\\Java项目\\xx\\sxsoft_expert\\staticfile\\专家抽取信息 - 副本.doc");
// 此处使用了poi-tl的<表格行循环插件>,此处一定要进行参数bind,方便word模板参数替换
LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
Configure build = Configure.builder().bind(policy, "workList").build();
XWPFTemplate render = XWPFTemplate.compile(wordTemplate, build).render(finalMap);
// 此处是利用File,直接在本地创建文件,将参数替换后的文件流写入到该文件,word就是最终的结果
String fileName =File.separator +IdUtil.getSnowflake(1,1).nextId() + ".docx";
String path ="D:\\xx\\Java项目\\xx\\sxsoft_expert\\staticfile\\" + fileName;
File word = new File(path);
try {
render.writeToFile(word.getAbsolutePath());
} catch (IOException e) {
throw new RuntimeException(e);
}
//导出并删除本地文件
DownLoadFileUtil.downloadFile(response,path,fileName,true);
复制代码

 

复制代码
    /**
     * 浏览器下载指定文件
     * @param path 完整物理路径
     * @param setFileName 文件名称
     * @param isDel 导出后是否删除磁盘文件,方法调用之前的这个文件的流必须先关闭掉才有生效
     * @return
     */
    public static HttpServletResponse downloadFile(HttpServletResponse response, String path, String setFileName,boolean isDel) {
        InputStream fis = null;
        OutputStream toClient = null;
        File file = null;
        try {
            // path是指欲下载的文件的路径。
            file = new File(path);
            // 取得文件名。
            String filename = file.getName();
            if(StringUtils.isEmpty(setFileName)){
                setFileName = filename;
            }
            // 取得文件的后缀名。
            String ext = filename.substring(filename.lastIndexOf(".") + 1).toUpperCase();
            // 以流的形式下载文件。
            fis = new BufferedInputStream(new FileInputStream(path));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            // 清空response
            response.reset();
            // 设置response的Header
            response.addHeader("Content-Disposition", "attachment;filename=" + java.net.URLDecoder.decode(setFileName, "UTF-8"));
            response.addHeader("Content-Length", "" + file.length());
            toClient = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            toClient.write(buffer);
        } catch (IOException ex) {
            ex.printStackTrace();
        }finally {
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(toClient != null){
                try {
                    toClient.flush();
                    toClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            //下载之后删除
            try {
                if(isDel && file.exists()){
                    file.delete();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return response;
    }
复制代码

 

方法二(ooxml有版本冲突时):

1、引入包

        <!--freemarker word-->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.28</version>
        </dependency>

2、代码示例片段

复制代码
 //region 把数据放进这个map里面进行填充
            Map<String,Object> dataMap = new HashMap();
            dataMap.put("ProjectName",PROJECT_NAME);
            dataMap.put("OpenAddress",OPEN_ADDRESS);
            dataMap.put("PROJECT_CODE",PROJECT_CODE);
            dataMap.put("ExtractTime",ExtractTime);
            dataMap.put("AgentUnit",AgentUnit);
            dataMap.put("type",type);
            dataMap.put("OPEN_TIME",OPEN_TIME);
            dataMap.put("OwnerUnit",OwnerUnit);
            dataMap.put("Notice_type",Notice_type);
            dataMap.put("Budget",Budget);
            dataMap.put("Is_Allowed_Extract_Same_Unit",Is_Allowed_Extract_Same_Unit);
            dataMap.put("TemporaryExpertList",dt_TemporaryExpert);
            dataMap.put("TemporaryExpertJoinList",dt_join);
            dataMap.put("TemporaryExpertNotJoinList",dt_Notjoin);
            //endregion


            //region 导出模板文件 参考 https://blog.csdn.net/yihuaiyan/article/details/87965887
            //创建模板配置
            Configuration configuration = new Configuration();
            configuration.setDefaultEncoding("utf-8");
            //模板文件的位置
            String systemDir = System.getProperty("user.dir");
            String sourcePath = systemDir + "\\staticfile";
            configuration.setDirectoryForTemplateLoading(new File(sourcePath));
            Template template = configuration.getTemplate("临时专家库抽取结果信息.ftl");   //加载---要装载的模板文件
            //输出文档路径及名称,注意后缀一定要.doc!不然代码运行完后会打不开
            String fileName = LocalDateTimeUtils.convert(LocalDateTime.now(),"yyyyMMddHHmmss") + ".doc";
            String path = systemDir + basePath + "/临时专家"+ fileName;
            File outFile = new File(path);
            if (!outFile.getParentFile().exists()) {
                outFile.getParentFile().mkdirs();
            }
            //写入模板
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile)));
            template.process(dataMap, out);

            //导出并删除本地文件
            out.close();
            DownLoadFileUtil.downloadFile(response,path,fileName,true);
            //endregion
复制代码

3、文件处理

第一步:先准备好一个模板,我使用的是比较复杂的模板,浪费了很多时间(建议各位大神制作一个简单的模板测试即可)

 

第二步:替换好了之后选择一个存储目录另存为 选择 WordXml 文档(*.xml) 这种格式进行存储

 

 


第三步:找到刚刚你存储的目录,以notepad++打开,刚才存储的.xml文件,*(最好格式化样式,不然很难找)删掉一些不必要的多余代码。

 

第四部,关于多行动态列表的处理

 

 

**最后:把改好的xml文档后缀修改成.ftl格式即可



 

posted on   五官一体即忢  阅读(9807)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8

导航

统计

点击右上角即可分享
微信分享提示