前言

本文次要有以下几个知识点:

  • 占位符填充
  • 头像导出
  • 表格填充
  • word转pdf

先来看下最初的效果图:

注释

模板配置

先来看下咱们的模板:

首先咱们须要先在word模板外面设置占位符,这里有一个十分重要的点就是咱们是依据${占位符}来替换的,其实word文档实质上就是一个xml文件,因而咱们须要保障占位符不被切割,具体做法如下:

1.首先用解压工具关上模板

2.关上document.xml文件

3.能够看出文件并未格式化,咱们先格式化代码

4.能够看到咱们的占位符被切割了,咱们须要干掉两头多余的。

5.点击开始后间接笼罩源文件就能够了,当初能够开始写代码了。

留神要保障咱们的每个占位符不被切割,否则是无奈进行替换的

模板填充

导入jar

<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.2</version></dependency><dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-scratchpad</artifactId> <version>4.1.2</version></dependency><dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.2</version></dependency>

首先看下咱们两个表格的实体类(不肯定要给表格建对象,依据集体需要增加即可)

// 家庭成员@Builder(toBuilder = true)@Data@AllArgsConstructor@NoArgsConstructorpublic class EpRewandpun {    private String urewdate;    private String urewunit;    private String urewdesc;}// 奖惩状况@Builder(toBuilder = true)@Data@AllArgsConstructor@NoArgsConstructorpublic class EpPmenber {    private String uconnection;    private String uname;    private String ubirthday;    private String uworkunit;    private String uploity;    private String ustatus;}

接着看下咱们的测试方法:

@SpringBootTestclass Tests {    @Test    void contextLoads() throws IOException {        String template = "C:UserslikunDesktop员工根本情况表.docx";        Map<String, Object> paramMap = new HashMap<>();        paramMap.put("${uname}", "乌龟");        paramMap.put("${usex}", "男");        paramMap.put("${ubirthdate}", "1998年10月22日");        paramMap.put("${unation}", "汉族");        paramMap.put("${unative}", "广东深圳");        paramMap.put("${uplace}", "广东汕头");        paramMap.put("${upolity}", "团员");        paramMap.put("${uworkdate}", "2020年3月16日");        paramMap.put("${uhealth}", "良好");        paramMap.put("${umajorpost}", "软件开发");        paramMap.put("${umajor}", "Java开发");                // 照片门路以及大小        Map<String, Object> phomap = new HashMap<>(8);        phomap.put("width", 100);        phomap.put("height", 130);        phomap.put("type", "png");        phomap.put("content", "E:\\Photo\\头像.jpg");        paramMap.put("${upho}", phomap);                //查问员工家庭信息        List<EpPmenber> menberlist = new ArrayList<>();        for (int i = 1; i < 3; i++) {            EpPmenber pmenber = new EpPmenber();            pmenber.setUname("小王");            pmenber.setUconnection("父亲");            pmenber.setUbirthday("1962年10月2日");            pmenber.setUploity("大众");            pmenber.setUworkunit("广东xxx公司");            pmenber.setUstatus("无");            menberlist.add(pmenber);        }        paramMap.put("menberlist", menberlist);                //查问员工处分状况        List<EpRewandpun> andpunlist = new ArrayList<>();        for (int i = 1; i < 3; i++) {            EpRewandpun rewandpun = new EpRewandpun();            rewandpun.setUrewdate("2020年5月1日");            rewandpun.setUrewunit("深圳xxx有限公司");            rewandpun.setUrewdesc("无");            andpunlist.add(rewandpun);        }        paramMap.put("andpunlist", andpunlist);                // 模板填充        XWPFDocument doc = WordUtil.generateWord(paramMap, template);        FileOutputStream fopts = new FileOutputStream("C:Users\\likun\\Desktop\\模板填充.docx");        doc.write(fopts);        fopts.close();    }}

代码比较简单不再细说,先来看下咱们的 generateWord 外围办法:

public class WordUtil {    /**     * 依据指定的参数值、模板,生成 word 文档     * 留神:其它模板须要依据状况进行调整     *     * @param param    变量汇合     * @param template 模板门路     */    public static XWPFDocument generateWord(Map<String, Object> param, String template) {        XWPFDocument doc = null;        try {            OPCPackage pack = POIXMLDocument.openPackage(template);            doc = new XWPFDocument(pack);            if (param != null && param.size() > 0) {                // 解决段落                List<XWPFParagraph> paragraphList = doc.getParagraphs();                processParagraphs(paragraphList, param, doc);                // 解决表格                Iterator<XWPFTable> it = doc.getTablesIterator();                //表格索引                int i = 0;                List<EpPmenber> menberlist = (List<EpPmenber>) param.get("menberlist");                List<EpRewandpun> andpunlist = (List<EpRewandpun>) param.get("andpunlist");                while (it.hasNext()) {                    XWPFTable table = it.next();                    int size = table.getRows().size() - 1;                    XWPFTableRow row2 = table.getRow(size);                    if (i == 1) {//家庭成员                        if (menberlist.size() > 0) {                            for (int j = 0; j < menberlist.size() - 1; j++) {                                copy(table, row2, size + j);                            }                        }                    } else if (i == 2) {//奖惩状况                        if (andpunlist.size() > 0) {                            for (int j = 0; j < andpunlist.size() - 1; j++) {                                copy(table, row2, size + j);                            }                        }                     }                        _row++;                    }                    i++;                }            }        } catch (Exception e) {            e.printStackTrace();        }        return doc;    } }

看下咱们的 copy 办法,用来拷贝行属性进行对表格进行复制

/** * 拷贝赋值行 * */public static void copy(XWPFTable table, XWPFTableRow sourceRow, int rowIndex) {    // 在表格指定地位新增一行    XWPFTableRow targetRow = table.insertNewTableRow(rowIndex);    // 复制行属性    targetRow.getCtRow().setTrPr(sourceRow.getCtRow().getTrPr());    List<XWPFTableCell> cellList = sourceRow.getTableCells();    if (null == cellList) {        return;    }    // 复制列及其属性和内容    XWPFTableCell targetCell = null;    for (XWPFTableCell sourceCell : cellList) {        targetCell = targetRow.addNewTableCell();        // 列属性        targetCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr());        // 段落属性        if (sourceCell.getParagraphs() != null && sourceCell.getParagraphs().size() > 0) {            targetCell.getParagraphs().get(0).getCTP().setPPr(sourceCell.getParagraphs().get(0).getCTP().getPPr());            if (sourceCell.getParagraphs().get(0).getRuns() != null && sourceCell.getParagraphs().get(0).getRuns().size() > 0) {                XWPFRun cellR = targetCell.getParagraphs().get(0).createRun();                cellR.setText(sourceCell.getText());                cellR.setBold(sourceCell.getParagraphs().get(0).getRuns().get(0).isBold());            } else {                targetCell.setText(sourceCell.getText());            }        } else {            targetCell.setText(sourceCell.getText());        }    }}

接下来是咱们的 processParagraphs 办法,用来进行占位符的替换以及头像的插入。

/** * 解决段落 */@SuppressWarnings({"unused", "rawtypes"})public static void processParagraphs(List<XWPFParagraph> paragraphList, Map<String, Object> param, XWPFDocument doc) throws InvalidFormatException, IOException {    if (paragraphList != null && paragraphList.size() > 0) {        for (XWPFParagraph paragraph : paragraphList) {            List<XWPFRun> runs = paragraph.getRuns();            for (XWPFRun run : runs) {                String text = run.getText(0);                if (text != null) {                    boolean isSetText = false;                    for (Entry<String, Object> entry : param.entrySet()) {                        String key = entry.getKey();                        if (text.contains(key)) {                            isSetText = true;                            Object value;                            if (entry.getValue() != null) {                                value = entry.getValue();                            } else {                                value = "";                            }                            // 文本替换                          if (value instanceof String) {                            // 解决答案中的回车换行                          if (((String) value).contains("n")) {                                    String[] lines = ((String) value).split("n");                                    if (lines.length > 0) {                                        text = text.replace(key, lines[0]);                                        for (int j = 1; j < lines.length; j++) {                                            run.addCarriageReturn();                                            run.setText(lines[j]);                                        }                                    }                                } else {                                    text = text.replace(key, value.toString());                                }                            } else if (value instanceof Map) {                                // 图片替换                                text = text.replace(key, "");                                Map pic = (Map) value;                                int width = Integer.parseInt(pic.get("width").toString());                                int height = Integer.parseInt(pic.get("height").toString());                                int picType = getPictureType(pic.get("type").toString());                                String byteArray = (String) pic.get("content");                                CTInline inline = run.getCTR().addNewDrawing().addNewInline();                                //插入图片                                insertPicture(doc, byteArray, inline, width, height, paragraph);                            }                        }                    }                    if (isSetText) {                        run.setText(text, 0);                    }                }            }        }    }}

接下来是 insertPicture 办法,用来插入图片,以及 getPictureType 办法获取图片类型。

/** * 插入图片 * */ private static void insertPicture(XWPFDocument document, String filePath, CTInline inline, int width, int height, XWPFParagraph paragraph) throws Exception {        // 读取图片门路        InputStream inputStream = new FileInputStream(new File(filePath));;                document.addPictureData(inputStream, XWPFDocument.PICTURE_TYPE_PNG);        int id = document.getAllPictures().size() - 1;        final int emu = 9525;        width *= emu;        height *= emu;        String blipId = paragraph.getDocument().getRelationId(document.getAllPictures().get(id));        String picXml = getPicXml(blipId, width, height);        XmlToken xmlToken = null;        try {            xmlToken = XmlToken.Factory.parse(picXml);        } catch (XmlException xe) {            xe.printStackTrace();        }        inline.set(xmlToken);        inline.setDistT(0);        inline.setDistB(0);        inline.setDistL(0);        inline.setDistR(0);        CTPositiveSize2D extent = inline.addNewExtent();        extent.setCx(width);        extent.setCy(height);        CTNonVisualDrawingProps docPr = inline.addNewDocPr();        docPr.setId(id);        docPr.setName("IMG_" + id);        docPr.setDescr("IMG_" + id);    }        /** * 依据图片类型,获得对应的图片类型代码 * * @param picType * @return int */ private static int getPictureType(String picType) {    int res = XWPFDocument.PICTURE_TYPE_PICT;    if (picType != null) {        if ("png".equalsIgnoreCase(picType)) {            res = XWPFDocument.PICTURE_TYPE_PNG;        } else if ("dib".equalsIgnoreCase(picType)) {            res = XWPFDocument.PICTURE_TYPE_DIB;        } else if ("emf".equalsIgnoreCase(picType)) {            res = XWPFDocument.PICTURE_TYPE_EMF;        } else if ("jpg".equalsIgnoreCase(picType) || "jpeg".equalsIgnoreCase(picType)) {            res = XWPFDocument.PICTURE_TYPE_JPEG;        } else if ("wmf".equalsIgnoreCase(picType)) {            res = XWPFDocument.PICTURE_TYPE_WMF;        }    }    return res;}

最初填充就是这个样子:

word转pdf

最初在补充一个知识点,有时候会须要咱们把 word 文档转成 pdf,其实网上是有一个免费插件 `aspose-words,具体如何破解请上网搜查,首先导入包:

<!-- Word文档转换 --><dependency> <groupId>com.aspose.words</groupId> <artifactId>aspose-words-jdk16</artifactId> <version>16.4.0</version></dependency>

接下来看下代码:

public class AsposeWordUtil {   private static final String WIN = "win";   /** * word转pdf 需引入 aspose-words-16.4.0-jdk16.jar包 免费插件windows linux下均可用 * * @param inPath * 源文件门路 * @param outPath * 输入文件门路 */ public static void convertPdfToDocx(String inPath, String outPath) {      try {         FontSettings fontSettings = new FontSettings();         File file = new File(outPath);         FileOutputStream os = new FileOutputStream(file);         Document doc = new Document(inPath);          // 另外服务器须要上传中文字体到/usr/share/fonts目录(复制windowsC:WindowsFonts目录下的字体文件即可)         String cos = System.getProperty("os.name");         if (cos.toLowerCase().startsWith(WIN)) {            // windows环境            fontSettings.setFontsFolder("C:/Windows/Fonts", false);         } else {            // Linux环境            fontSettings.setFontsFolder("/usr/share/fonts", false);         }         doc.setFontSettings(fontSettings);         // 全面反对DOC, DOCX, OOXML, RTF HTML,OpenDocument, PDF,EPUB, XPS, SWF 互相转换         doc.save(os, SaveFormat.PDF);         os.close();      } catch (Exception e) {         e.printStackTrace();      }   }}

留神:Linux服务器上须要上传中文字体,用法也很简略,只有传入word文档门路和要生成的pdf门路就能够了。

String wordPath = "C:Users\\likun\\Desktop\\人员根本状况.docx";String pdfPath = "C:Users\\likun\\Desktop\\人员根本状况.pdf";AsposeWordUtil.convertPdfToDocx(wordPath, pdfPath);

效果图:

总结

代码写到这里也就完结了,大伙可依据业务需要自行进行调整,如果有什么不对的中央请多多指教。