java poi根据模板生成docx

一、实现功能 

1、支持表格、图像、插入页脚,其中图像包含base64 位和 只传入图像路径

2、要求使用对应的模板 故只能作为参考

3、里面的以下判断时根据 模板文件里面的key进行的特殊处理

二、代码(版本 3.15)

package com.hyzs.szcg.doc.utils;
import java.awt.image.BufferedImage;
import java.io.*;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.hyzs.gz.common.core.exception.CommonException;
import com.hyzs.szcg.doc.vo.DocWordUtilVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.impl.xb.xmlschema.SpaceAttribute;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import sun.misc.BASE64Decoder;
import javax.imageio.ImageIO;



/**
 *
 * @Title: WordExport.java
 * @Description:  导出word文档
 * @author zzh
 * @version 1.0
 */
@Slf4j
@Component
public class PoiExportWord {
    @Value("${apiKey}")
    private String apiKey;
    private String templatePath;
    private XWPFDocument doc = null;
    private FileInputStream is = null;
    private OutputStream os = null;
    private DocWordUtilVO docWordUtilVO=new DocWordUtilVO();
    public DocWordUtilVO init(Map<String,Object> params,String templatePath,String targetPath) throws IOException {
        docWordUtilVO.setWordFlag(false);
        this.templatePath = templatePath;
        File file=new File(this.templatePath);
        File fileTarget=new File(targetPath);
        if (!fileTarget.getParentFile().exists()){
            //目录不存在则创建目录
            fileTarget.getParentFile().mkdirs();
        }
        //插入当前时间  年月日
        insertDate(params);
        if(file.exists()){
            is = new FileInputStream(file);
            doc = new XWPFDocument(is);
            try {
                if(export(params)){
                    docWordUtilVO.setWordFlag(generate(targetPath));
                    docWordUtilVO.setWordPath(targetPath);
                }
            } catch (Exception e) {
                throw CommonException.exception("文书生成失败!",e);
            }
        }else{
           // log.error("io error -> 文件模板不存在》"+this.templatePath);
            throw CommonException.exception("io error 模板文件不存在");
        }
        return docWordUtilVO;
    }
    /**
     * 替换掉占位符
     * @param params
     * @return
     * @throws Exception
     */
    public boolean export(Map<String,Object> params) throws Exception{
        this.replaceInPara(doc, params);
        export(params, 0);//表格数据
        return true;
    }

    /**
     * 替换掉表格中的占位符
     * @param params
     * @param tableIndex
     * @return
     * @throws Exception
     */
    public boolean export(Map<String,Object> params,int tableIndex) throws Exception{
        //动态插入表格列表数据
        this.insertTable(params);
        this.replaceInTable(doc, params,tableIndex);
        return true;
    }
    /**
     * 循环生成表格
     * @param params
     * @return
     * @throws Exception
     */
    public boolean insertTable(Map<String,Object> params) throws Exception{
        this.insertValueToTable(doc, params);
        return true;
    }
    private void insertValueToTable(XWPFDocument doc,Map<String, Object> params) throws Exception {
        List<XWPFTable> tableList = doc.getTables();
        for (int t=0;t<tableList.size();t++){
            //循环表格
            XWPFTable table = tableList.get(t);
            List<XWPFTableRow> rows = table.getRows();
            int temRowNum=0;
            String key="";//表格 列表数据的 key
            for (int j = 0; j <rows.size() ; j++) {
                String rowText = rows.get(j).getCell(0).getText();// 获取到表格行的第一个单元格
                //确定标识行的位置 标识行的下一行就是模板行  模板行 以 foreachRows_开头   列 ${foreachRows_giveDocList} giveDocList为表单的key
                boolean begin = rowText.indexOf("$")>-1;
                boolean end = rowText.indexOf("}")>-1;
                if(begin&&end){
                    Matcher matcher = this.matcher(rowText);
                    if(matcher.find()){
                        String keyText = matcher.group().substring(2,matcher.group().length()-1);
                        if(keyText!=null&&!"".equals(keyText)&&keyText.startsWith("foreachRows_")){
                            temRowNum=j;
                            key=StringUtils.removeStart(keyText,"foreachRows_");
                            break;
                        }

                    }
                }

            }
            if(rows.size()<2){
               break;
            }
            if(temRowNum==0&&"".equals(key)){
                //该表格不需要动态生成
                break;
            }
            //模板行
            XWPFTableRow tmpRow = rows.get(temRowNum+1);
            //获取列表数据
            Object value=params.get(key);
            List<Map<String,Object>> listData=new ArrayList<>();
            if(value instanceof List){
                listData=(List<Map<String,Object>>)value;
            }
            Map m=new HashMap();
            m.putAll(params);
            m.remove(key);
            for (int i = 0; i < listData.size(); i++) {
                Map<String,Object> map = listData.get(i);
                map.putAll(m);
                map.put("no",i+1);//添加表格序号
                //------------------------------------
                /* 循环生成模板行 */
                //在表格指定位置新增一行
                XWPFTableRow targetRow = table.insertNewTableRow(temRowNum+2+i);
                copyRow(targetRow,tmpRow);
                List<XWPFTableCell> cells;
                List<XWPFParagraph> paras;
                cells = targetRow.getTableCells();
                for (XWPFTableCell cell : cells) {
                    paras = cell.getParagraphs();
                    for (XWPFParagraph para : paras) {
                        this.replaceInPara(para, map);
                    }
                }
            }
            table.removeRow(temRowNum);// 删除标识行
            table.removeRow(temRowNum);// 删除模版行
        }

    }
  /**
     * 生成word文档
     * @param outDocPath
     * @return
     * @throws IOException
     */
    public boolean generate(String outDocPath){
        try {
            createFooter();
            os = new FileOutputStream(outDocPath);
            doc.write(os);
        } catch (FileNotFoundException e) {
            throw CommonException.exception("文书生成失败!",e);
        }catch (IOException e) {
            throw CommonException.exception("文书生成失败!",e);
        }finally {
            try {
                doc.close();
                this.close(os);
                this.close(is);
            } catch (IOException e) {
                throw CommonException.exception("文书IO流关闭失败!",e);
            }
        }
        return true;
    }

    /**
     * 替换表格里面的变量
     *
     * @param doc
     *            要替换的文档
     * @param params
     *            参数
     * @throws Exception
     */
    private void replaceInTable(XWPFDocument doc, Map<String, Object> params,int tableIndex) throws Exception {
        List<XWPFTable> tableList = doc.getTables();
        if(tableList.size()>tableIndex){
            for (int i=0;i<tableList.size();i++){
                XWPFTable table = tableList.get(i);
               List<XWPFTableRow> rows;
                List<XWPFTableCell> cells;
                List<XWPFParagraph> paras;
                rows = table.getRows();
                for (XWPFTableRow row : rows) {
                    cells = row.getTableCells();
                    for (XWPFTableCell cell : cells) {
                        paras = cell.getParagraphs();
                        for (XWPFParagraph para : paras) {
                            this.replaceInPara(para, params);
                        }
                    }
                }
            }

        }
    }

    /**
     * 替换段落里面的变量
     *
     * @param doc
     *            要替换的文档
     * @param params
     *            参数
     * @throws Exception
     */
    private void replaceInPara(XWPFDocument doc, Map<String, Object> params) throws Exception {
        Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
        XWPFParagraph para;
        while (iterator.hasNext()) {
            para = iterator.next();
            this.replaceInPara(para, params);
        }
    }

    /**
     * 替换段落里面的变量
     *
     * @param para
     *            要替换的段落
     * @param params
     *            参数
     * @throws Exception
     * @throws IOException
     * @throws
     */
    private boolean replaceInPara(XWPFParagraph para, Map<String, Object> params) throws Exception {
        boolean data = false;
        List<XWPFRun> runs;
        //有符合条件的占位符
        if (this.matcher(para.getParagraphText()).find()) {
            runs = para.getRuns();
            data = true;
            Map<Integer,String> tempMap = new TreeMap<>();
            for (int i = 0; i < runs.size(); i++) {
                XWPFRun run = runs.get(i);
                String runText = run.toString();
                //以"$"开头
                boolean begin = runText.indexOf("$")>-1;
                boolean end = runText.indexOf("}")>-1;
                if(begin && end){
                    tempMap.put(i, runText);
                    fillBlock(para, params, tempMap, i);
                    continue;
                }else if(begin && !end){
                    tempMap.put(i, runText);
                    continue;
                }else if(!begin && end){
                    tempMap.put(i, runText);
                    fillBlock(para, params, tempMap, i);
                    continue;
                }else{
                    if(tempMap.size()>0){
                        tempMap.put(i, runText);
                        continue;
               
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现根据docx模板生成docx并实现下载功能,可以使用Apache POI库和Servlet技术。 以下是实现步骤: 1. 在Java项目中引入Apache POI库,以便操作docx文件。 2. 创建一个Servlet类,用于处理客户端的请求。 3. 在Servlet类中,实现doGet或doPost方法,根据请求参数生成docx文件,并将其写入输出流。 4. 在处理完请求后,设置响应头,指定文件类型和文件名,并将输出流中的内容写入响应输出流中。 以下是示例代码: ```java @WebServlet("/downloadDocx") public class DownloadDocxServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 读取docx模板文件 InputStream inputStream = getServletContext().getResourceAsStream("/WEB-INF/templates/template.docx"); XWPFDocument document = new XWPFDocument(inputStream); // 获取模板中的段落和表格 List<XWPFParagraph> paragraphs = document.getParagraphs(); List<XWPFTable> tables = document.getTables(); // 根据请求参数填充模板 String name = request.getParameter("name"); for (XWPFParagraph paragraph : paragraphs) { String text = paragraph.getText(); if (text.contains("${name}")) { text = text.replace("${name}", name); paragraph.setText(text); } } for (XWPFTable table : tables) { for (XWPFTableRow row : table.getRows()) { for (XWPFTableCell cell : row.getTableCells()) { String text = cell.getText(); if (text.contains("${name}")) { text = text.replace("${name}", name); cell.setText(text); } } } } // 构建输出流 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); document.write(outputStream); // 设置响应头,指定文件类型和文件名 response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document"); response.setHeader("Content-Disposition", "attachment; filename=\"result.docx\""); // 将docx文件写入响应输出流 ServletOutputStream servletOutputStream = response.getOutputStream(); outputStream.writeTo(servletOutputStream); servletOutputStream.flush(); servletOutputStream.close(); } } ``` 在上述示例代码中,我们首先读取了docx模板文件,然后根据请求参数填充模板,接着构建了一个输出流,将填充后的内容写入其中。然后设置响应头,指定文件类型和文件名,并将输出流中的内容写入响应输出流中,实现下载功能。 最后,在web.xml文件中配置Servlet映射: ```xml <servlet> <servlet-name>DownloadDocxServlet</servlet-name> <servlet-class>com.example.DownloadDocxServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>DownloadDocxServlet</servlet-name> <url-pattern>/downloadDocx</url-pattern> </servlet-mapping> ``` 这样,当客户端发送GET或POST请求到/downloadDocx时,就会调用DownloadDocxServlet类中的doGet或doPost方法,生成docx文件并实现下载功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值