();
+
+ /**
+ * 添加
+ */
+ public static void add(String mimeType, String extension) {
+ if (!mimeTypeToExtensionMap.containsKey(mimeType)) {
+ mimeTypeToExtensionMap.put(mimeType, extension);
+ }
+ extensionToMimeTypeMap.put(extension, mimeType);
+ }
+
+ /**
+ * 根据extension获取mimeType
+ */
+ public static String getByExtension(String extension) {
+ if (extension == null || extension.isEmpty()) {
+ return null;
+ }
+ return extensionToMimeTypeMap.get(extension);
+ }
+
+ /**
+ * 根据mimeType获取extension
+ */
+ public static String getByMimeType(String mimeType) {
+ if (mimeType == null || mimeType.isEmpty()) {
+ return null;
+ }
+ return mimeTypeToExtensionMap.get(mimeType);
+ }
+
+ /**
+ * mimeType重复的,默认加载第一个
+ */
+ static {
+ add("application/andrew-inset", "ez");
+ add("application/dsptype", "tsp");
+ add("application/json", "json");
+ add("application/futuresplash", "spl");
+ add("application/hta", "hta");
+ add("application/mac-binhex40", "hqx");
+ add("application/mac-compactpro", "cpt");
+ add("application/mathematica", "nb");
+ add("application/msaccess", "mdb");
+ add("application/oda", "oda");
+ add("application/ogg", "ogg");
+ add("application/pdf", "pdf");
+ add("application/pgp-keys", "key");
+ add("application/pgp-signature", "pgp");
+ add("application/pics-rules", "prf");
+ add("application/rar", "rar");
+ add("application/rdf+xml", "rdf");
+ add("application/rss+xml", "rss");
+ add("application/zip", "zip");
+ add("application/vnd.android.package-archive", "apk");
+ add("application/vnd.cinderella", "cdy");
+ add("application/vnd.ms-pki.stl", "stl");
+ add("application/vnd.oasis.opendocument.database", "odb");
+ add("application/vnd.oasis.opendocument.formula", "odf");
+ add("application/vnd.oasis.opendocument.graphics", "odg");
+ add("application/vnd.oasis.opendocument.graphics-template", "otg");
+ add("application/vnd.oasis.opendocument.image", "odi");
+ add("application/vnd.oasis.opendocument.spreadsheet", "ods");
+ add("application/vnd.oasis.opendocument.spreadsheet-template", "ots");
+ add("application/vnd.oasis.opendocument.text", "odt");
+ add("application/vnd.oasis.opendocument.text-master", "odm");
+ add("application/vnd.oasis.opendocument.text-template", "ott");
+ add("application/vnd.oasis.opendocument.text-web", "oth");
+ add("application/vnd.google-earth.kml+xml", "kml");
+ add("application/vnd.google-earth.kmz", "kmz");
+ add("application/msword", "doc");
+ add("application/msword", "dot");
+ add("application/vnd.openxmlformats-officedocument.wordprocessingml.document", "docx");
+ add("application/vnd.openxmlformats-officedocument.wordprocessingml.template", "dotx");
+ add("application/vnd.ms-excel", "xls");
+ add("application/vnd.ms-excel", "xlt");
+ add("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "xlsx");
+ add("application/vnd.openxmlformats-officedocument.spreadsheetml.template", "xltx");
+ add("application/vnd.ms-powerpoint", "ppt");
+ add("application/vnd.ms-powerpoint", "pot");
+ add("application/vnd.ms-powerpoint", "pps");
+ add("application/vnd.openxmlformats-officedocument.presentationml.presentation", "pptx");
+ add("application/vnd.openxmlformats-officedocument.presentationml.template", "potx");
+ add("application/vnd.openxmlformats-officedocument.presentationml.slideshow", "ppsx");
+ add("application/vnd.rim.cod", "cod");
+ add("application/vnd.smaf", "mmf");
+ add("application/vnd.stardivision.calc", "sdc");
+ add("application/vnd.stardivision.draw", "sda");
+ add("application/vnd.stardivision.impress", "sdd");
+ add("application/vnd.stardivision.impress", "sdp");
+ add("application/vnd.stardivision.math", "smf");
+ add("application/vnd.stardivision.writer", "sdw");
+ add("application/vnd.stardivision.writer", "vor");
+ add("application/vnd.stardivision.writer-global", "sgl");
+ add("application/vnd.sun.xml.calc", "sxc");
+ add("application/vnd.sun.xml.calc.template", "stc");
+ add("application/vnd.sun.xml.draw", "sxd");
+ add("application/vnd.sun.xml.draw.template", "std");
+ add("application/vnd.sun.xml.impress", "sxi");
+ add("application/vnd.sun.xml.impress.template", "sti");
+ add("application/vnd.sun.xml.math", "sxm");
+ add("application/vnd.sun.xml.writer", "sxw");
+ add("application/vnd.sun.xml.writer.global", "sxg");
+ add("application/vnd.sun.xml.writer.template", "stw");
+ add("application/vnd.visio", "vsd");
+ add("application/x-abiword", "abw");
+ add("application/x-apple-diskimage", "dmg");
+ add("application/x-bcpio", "bcpio");
+ add("application/x-bittorrent", "torrent");
+ add("application/x-cdf", "cdf");
+ add("application/x-cdlink", "vcd");
+ add("application/x-chess-pgn", "pgn");
+ add("application/x-cpio", "cpio");
+ add("application/x-debian-package", "deb");
+ add("application/x-debian-package", "udeb");
+ add("application/x-director", "dcr");
+ add("application/x-director", "dir");
+ add("application/x-director", "dxr");
+ add("application/x-dms", "dms");
+ add("application/x-doom", "wad");
+ add("application/x-dvi", "dvi");
+ add("application/x-flac", "flac");
+ add("application/x-font", "pfa");
+ add("application/x-font", "pfb");
+ add("application/x-font", "gsf");
+ add("application/x-font", "pcf");
+ add("application/x-font", "pcf.Z");
+ add("application/x-freemind", "mm");
+ add("application/x-futuresplash", "spl");
+ add("application/x-gnumeric", "gnumeric");
+ add("application/x-go-sgf", "sgf");
+ add("application/x-graphing-calculator", "gcf");
+ add("application/x-gtar", "gtar");
+ add("application/x-gtar", "tgz");
+ add("application/x-gtar", "taz");
+ add("application/x-hdf", "hdf");
+ add("application/x-ica", "ica");
+ add("application/x-internet-signup", "ins");
+ add("application/x-internet-signup", "isp");
+ add("application/x-iphone", "iii");
+ add("application/x-iso9660-image", "iso");
+ add("application/x-jmol", "jmz");
+ add("application/x-kchart", "chrt");
+ add("application/x-killustrator", "kil");
+ add("application/x-koan", "skp");
+ add("application/x-koan", "skd");
+ add("application/x-koan", "skt");
+ add("application/x-koan", "skm");
+ add("application/x-kpresenter", "kpr");
+ add("application/x-kpresenter", "kpt");
+ add("application/x-kspread", "ksp");
+ add("application/x-kword", "kwd");
+ add("application/x-kword", "kwt");
+ add("application/x-latex", "latex");
+ add("application/x-lha", "lha");
+ add("application/x-lzh", "lzh");
+ add("application/x-lzx", "lzx");
+ add("application/x-maker", "frm");
+ add("application/x-maker", "maker");
+ add("application/x-maker", "frame");
+ add("application/x-maker", "fb");
+ add("application/x-maker", "book");
+ add("application/x-maker", "fbdoc");
+ add("application/x-mif", "mif");
+ add("application/x-ms-wmd", "wmd");
+ add("application/x-ms-wmz", "wmz");
+ add("application/x-msi", "msi");
+ add("application/x-ns-proxy-autoconfig", "pac");
+ add("application/x-nwc", "nwc");
+ add("application/x-object", "o");
+ add("application/x-oz-application", "oza");
+ add("application/x-pkcs12", "p12");
+ add("application/x-pkcs12", "pfx");
+ add("application/x-pkcs7-certreqresp", "p7r");
+ add("application/x-pkcs7-crl", "crl");
+ add("application/x-quicktimeplayer", "qtl");
+ add("application/x-shar", "shar");
+ add("application/x-shockwave-flash", "swf");
+ add("application/x-stuffit", "sit");
+ add("application/x-sv4cpio", "sv4cpio");
+ add("application/x-sv4crc", "sv4crc");
+ add("application/x-tar", "tar");
+ add("application/x-texinfo", "texinfo");
+ add("application/x-texinfo", "texi");
+ add("application/x-troff", "t");
+ add("application/x-troff", "roff");
+ add("application/x-troff-man", "man");
+ add("application/x-ustar", "ustar");
+ add("application/x-wais-source", "src");
+ add("application/x-wingz", "wz");
+ add("application/x-webarchive", "webarchive");
+ add("application/x-webarchive-xml", "webarchivexml");
+ add("application/x-x509-ca-cert", "crt");
+ add("application/x-x509-user-cert", "crt");
+ add("application/x-xcf", "xcf");
+ add("application/x-xfig", "fig");
+ add("application/xhtml+xml", "xhtml");
+ add("audio/3gpp", "3gpp");
+ add("audio/amr", "amr");
+ add("audio/basic", "snd");
+ add("audio/midi", "mid");
+ add("audio/midi", "midi");
+ add("audio/midi", "kar");
+ add("audio/midi", "xmf");
+ add("audio/mobile-xmf", "mxmf");
+ add("audio/mpeg", "mpga");
+ add("audio/mpeg", "mpega");
+ add("audio/mpeg", "mp2");
+ add("audio/mpeg", "mp3");
+ add("audio/mpeg", "m4a");
+ add("audio/mpegurl", "m3u");
+ add("audio/prs.sid", "sid");
+ add("audio/x-aiff", "aif");
+ add("audio/x-aiff", "aiff");
+ add("audio/x-aiff", "aifc");
+ add("audio/x-gsm", "gsm");
+ add("audio/x-mpegurl", "m3u");
+ add("audio/x-ms-wma", "wma");
+ add("audio/x-ms-wax", "wax");
+ add("audio/x-pn-realaudio", "ra");
+ add("audio/x-pn-realaudio", "rm");
+ add("audio/x-pn-realaudio", "ram");
+ add("audio/x-realaudio", "ra");
+ add("audio/x-scpls", "pls");
+ add("audio/x-sd2", "sd2");
+ add("audio/x-wav", "wav");
+ add("image/bmp", "bmp");
+ add("image/gif", "gif");
+ add("image/ico", "cur");
+ add("image/ico", "ico");
+ add("image/ief", "ief");
+ add("image/jpeg", "jpeg");
+ add("image/jpeg", "jpg");
+ add("image/jpeg", "jpe");
+ add("image/pcx", "pcx");
+ add("image/png", "png");
+ add("image/svg+xml", "svg");
+ add("image/svg+xml", "svgz");
+ add("image/tiff", "tiff");
+ add("image/tiff", "tif");
+ add("image/vnd.djvu", "djvu");
+ add("image/vnd.djvu", "djv");
+ add("image/vnd.wap.wbmp", "wbmp");
+ add("image/x-cmu-raster", "ras");
+ add("image/x-coreldraw", "cdr");
+ add("image/x-coreldrawpattern", "pat");
+ add("image/x-coreldrawtemplate", "cdt");
+ add("image/x-corelphotopaint", "cpt");
+ add("image/x-icon", "ico");
+ add("image/x-jg", "art");
+ add("image/x-jng", "jng");
+ add("image/x-ms-bmp", "bmp");
+ add("image/x-photoshop", "psd");
+ add("image/x-portable-anymap", "pnm");
+ add("image/x-portable-bitmap", "pbm");
+ add("image/x-portable-graymap", "pgm");
+ add("image/x-portable-pixmap", "ppm");
+ add("image/x-rgb", "rgb");
+ add("image/x-xbitmap", "xbm");
+ add("image/x-xpixmap", "xpm");
+ add("image/x-xwindowdump", "xwd");
+ add("model/iges", "igs");
+ add("model/iges", "iges");
+ add("model/mesh", "msh");
+ add("model/mesh", "mesh");
+ add("model/mesh", "silo");
+ add("text/calendar", "ics");
+ add("text/calendar", "icz");
+ add("text/comma-separated-values", "csv");
+ add("text/css", "css");
+ add("text/html", "htm");
+ add("text/html", "html");
+ add("text/h323", "323");
+ add("text/iuls", "uls");
+ add("text/mathml", "mml");
+ add("text/plain", "txt");
+ add("text/plain", "asc");
+ add("text/plain", "text");
+ add("text/plain", "diff");
+ add("text/plain", "po");
+ add("text/richtext", "rtx");
+ add("text/rtf", "rtf");
+ add("text/texmacs", "ts");
+ add("text/text", "phps");
+ add("text/tab-separated-values", "tsv");
+ add("text/xml", "xml");
+ add("text/x-bibtex", "bib");
+ add("text/x-boo", "boo");
+ add("text/x-c++hdr", "h++");
+ add("text/x-c++hdr", "hpp");
+ add("text/x-c++hdr", "hxx");
+ add("text/x-c++hdr", "hh");
+ add("text/x-c++src", "c++");
+ add("text/x-c++src", "cpp");
+ add("text/x-c++src", "cxx");
+ add("text/x-chdr", "h");
+ add("text/x-component", "htc");
+ add("text/x-csh", "csh");
+ add("text/x-csrc", "c");
+ add("text/x-dsrc", "d");
+ add("text/x-haskell", "hs");
+ add("text/x-java", "java");
+ add("text/x-literate-haskell", "lhs");
+ add("text/x-moc", "moc");
+ add("text/x-pascal", "p");
+ add("text/x-pascal", "pas");
+ add("text/x-pcs-gcd", "gcd");
+ add("text/x-setext", "etx");
+ add("text/x-tcl", "tcl");
+ add("text/x-tex", "tex");
+ add("text/x-tex", "ltx");
+ add("text/x-tex", "sty");
+ add("text/x-tex", "cls");
+ add("text/x-vcalendar", "vcs");
+ add("text/x-vcard", "vcf");
+ add("video/3gpp", "3gpp");
+ add("video/3gpp", "3gp");
+ add("video/3gpp", "3g2");
+ add("video/dl", "dl");
+ add("video/dv", "dif");
+ add("video/dv", "dv");
+ add("video/fli", "fli");
+ add("video/m4v", "m4v");
+ add("video/mpeg", "mpeg");
+ add("video/mpeg", "mpg");
+ add("video/mpeg", "mpe");
+ add("video/mp4", "mp4");
+ add("video/mpeg", "VOB");
+ add("video/quicktime", "qt");
+ add("video/quicktime", "mov");
+ add("video/vnd.mpegurl", "mxu");
+ add("video/x-la-asf", "lsf");
+ add("video/x-la-asf", "lsx");
+ add("video/x-mng", "mng");
+ add("video/x-ms-asf", "asf");
+ add("video/x-ms-asf", "asx");
+ add("video/x-ms-wm", "wm");
+ add("video/x-ms-wmv", "wmv");
+ add("video/x-ms-wmx", "wmx");
+ add("video/x-ms-wvx", "wvx");
+ add("video/x-msvideo", "avi");
+ add("video/x-sgi-movie", "movie");
+ add("x-conference/x-cooltalk", "ice");
+ add("x-epoc/x-sisx-app", "sisx");
+ }
+}
diff --git a/jeecg-module-main/src/main/java/org/jeecg/modules/tools/word/WordImageLabel.java b/jeecg-module-main/src/main/java/org/jeecg/modules/tools/word/WordImageLabel.java
new file mode 100644
index 00000000..c55e5b35
--- /dev/null
+++ b/jeecg-module-main/src/main/java/org/jeecg/modules/tools/word/WordImageLabel.java
@@ -0,0 +1,115 @@
+/**********************************************************************
+* $Id: WordImageLabel.java WordImageLabel ,v0.1 2018年9月19日 下午8:50:48 byx Exp $
+* Copyright ©2018 sida . All rights reserved
+***********************************************************************/
+
+package org.jeecg.modules.tools.word;
+
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+* 功能说明:从标签中读取键值,宽高和后缀内容
+* 创建者:byx
+* 创建时间:2018年9月19日
+*
+* 修改时间: 修改者:
+* 修改内容:
+*
+*/
+public class WordImageLabel {
+
+ public static final String SPLIT_STR = ",";
+
+ private String key = ""; //键值
+
+ private int width = 0; //宽
+
+ private int height = 0; //高
+
+ private String picAttch = ""; //后缀值
+
+ public WordImageLabel(Object obj){
+ if(obj instanceof String){
+ this.wordImageLabel((String)obj);
+ }
+ }
+
+ /**
+ *
+ * 功能说明 : 如:‘image,10,10,后缀’
+ * 创建者 : byx
+ * 修改日期 : 2018年9月19日
+ * @param value
+ */
+ public WordImageLabel(String value){
+ super();
+ this.wordImageLabel(value);
+ }
+
+ /**
+ *
+ * 功能说明 : 如:‘image,10,10,后缀’
+ * 创建者 : byx
+ * 修改日期 : 2018年9月19日
+ * @param value
+ */
+ public void wordImageLabel(String value) {
+ if(StringUtils.isNotBlank(value)){
+ String[] strList = StringUtils.split(value, SPLIT_STR);
+ if(strList.length == 0){
+ key = value;
+ }else if(strList.length == 1){
+ key = strList[0];
+ }else if(strList.length == 2){
+ key = strList[0];
+ width = Integer.valueOf(strList[1]);
+ }else if(strList.length == 3){
+ key = strList[0];
+ width = Integer.valueOf(strList[1]);
+ height = Integer.valueOf(strList[2]);
+ }else if(strList.length == 4){
+ key = strList[0];
+ width = Integer.valueOf(strList[1]);
+ height = Integer.valueOf(strList[2]);
+ picAttch = strList[3];
+ }
+ }
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ public String getPicAttch() {
+ return picAttch;
+ }
+
+ public void setPicAttch(String picAttch) {
+ this.picAttch = picAttch;
+ }
+
+
+
+
+}
diff --git a/jeecg-module-main/src/main/java/org/jeecg/modules/tools/word/WordOperator.java b/jeecg-module-main/src/main/java/org/jeecg/modules/tools/word/WordOperator.java
new file mode 100644
index 00000000..c51a74f3
--- /dev/null
+++ b/jeecg-module-main/src/main/java/org/jeecg/modules/tools/word/WordOperator.java
@@ -0,0 +1,1154 @@
+package org.jeecg.modules.tools.word;
+
+import cn.hutool.core.io.IoUtil;
+import com.google.common.collect.Lists;
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.util.Units;
+import org.apache.poi.xwpf.usermodel.*;
+import org.jeecg.common.util.SpringContextHolder;
+import org.jeecg.modules.tools.CommonUtil;
+import org.jeecg.modules.tools.FileUtils;
+import org.jeecg.modules.tools.Global;
+import org.jeecg.modules.tools.IdGen;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 对word模板的操作,包含替换文本和列表向下扩展两种
+ * 本工具类的使用需要配合ExportWord.class,具体Demo看ExportWord类即可
+ * @author byx
+ */
+public class WordOperator {
+
+ private static Logger logger = LoggerFactory.getLogger(WordOperator.class);
+
+ /**
+ * 模板替换标签开头
+ */
+ private final static String LABEL_STR = "{";
+ /**
+ * 模板替换标签结尾
+ */
+ private final static String LABEL_END = "}";
+ /**
+ * 模板替换图片标签开头(List)
+ */
+ private final static String LABEL_IMAGE_STR = "<";
+ /**
+ * 模板替换图片标签结尾(List)
+ */
+ private final static String LABEL_IMAGE_END = ">";
+
+ /**
+ * 模板替换图片标签开头(List)
+ */
+ private final static String LABEL_RICH_TEXT_STR = "
+ * 因为微软只提供XWPFRun对象替换文本,而它在切割段落文本的时候却是非常没有规律的,故而本方法要求模板必须遵循一定的规范来编写:
+ * 1.模板里除了标签外,其余地方禁止使用"{"和"}"字符串;
+ * 2.不允许出现"{}"这种写法,即标签必须包含key;
+ */
+ public WordOperator(InputStream is) throws Exception {
+ doc = new XWPFDocument(is);
+ }
+
+
+
+ /**
+ * 要替换标签的KV对
+ */
+ private Map replaceMap;
+
+ public Map getReplaceMap() {
+ return replaceMap;
+ }
+
+ public void setReplaceMap(Map replaceMap) {
+ this.replaceMap = replaceMap;
+ }
+
+ /**
+ *
+ * 功能说明 : 创建图片,根据段落
+ * 创建者 : byx
+ * 修改日期 : 2018年9月15日
+ * @param pic 图片位置
+ * @param picPath 图片路径
+ * @param width 图片宽度
+ * @param height 图片高度
+ * @param picAttch 图片后缀文字
+ */
+ public void createPicture(XWPFParagraph pic, String picPath, int width, int height, String picAttch){
+ pic.setAlignment(ParagraphAlignment.CENTER);
+
+ XWPFRun run = pic.createRun();
+
+ try {
+ if(StringUtils.isBlank(picPath) || picPath.lastIndexOf(".") == -1){
+ logger.error("文件路径错误:");
+ logger.error(picPath);
+ return;
+ }
+ //根据文件后缀名设置图片格式
+ String picType = picPath.substring(picPath.lastIndexOf("\\.")+1);
+ int res = XWPFDocument.PICTURE_TYPE_PICT;
+ if(picType != null){
+ if(picType.equalsIgnoreCase("png")){
+ res = XWPFDocument.PICTURE_TYPE_PNG;
+ }else if(picType.equalsIgnoreCase("gif")) {
+ res = XWPFDocument.PICTURE_TYPE_GIF;
+ }else if(picType.equalsIgnoreCase("emf")){
+ res = XWPFDocument.PICTURE_TYPE_EMF;
+ }else if(picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")){
+ res = XWPFDocument.PICTURE_TYPE_JPEG;
+ }else if(picType.equalsIgnoreCase("wmf")){
+ res = XWPFDocument.PICTURE_TYPE_WMF;
+ }else if(picType.equalsIgnoreCase("pict")){
+ res = XWPFDocument.PICTURE_TYPE_PICT;
+ }else if(picType.equalsIgnoreCase("dib")){
+ res = XWPFDocument.PICTURE_TYPE_DIB;
+ }else if(picType.equalsIgnoreCase("tiff")){
+ res = XWPFDocument.PICTURE_TYPE_TIFF;
+ }else if(picType.equalsIgnoreCase("eps")){
+ res = XWPFDocument.PICTURE_TYPE_EPS;
+ }else if(picType.equalsIgnoreCase("bmp")){
+ res = XWPFDocument.PICTURE_TYPE_BMP;
+ }else if(picType.equalsIgnoreCase("wpg")){
+ res = XWPFDocument.PICTURE_TYPE_WPG;
+ }
+ }
+ //塞进文档中
+// doc.addPictureData(new FileInputStream(picPath),res);
+ if(StringUtils.isNotBlank(picAttch)){
+ run.setText(picAttch);
+ }
+ //补充完整路径
+ Global global = SpringContextHolder.getBean(Global.class);
+ InputStream is = new FileInputStream(global.uploadPath + "/" + picPath);
+// run.addPicture(is,res,picPath,Units.pixelToEMU(width), Units.pixelToEMU(height));
+ run.addPicture(is,res,picPath,Units.toEMU(width), Units.toEMU(height));
+// run.addPicture(is,res,picPath,width, height);
+ IoUtil.close(is);
+ } catch (InvalidFormatException e) {
+ logger.error(e.toString());
+ e.printStackTrace();
+ } catch (IOException e) {
+ logger.error("没有找到相应的文件!");
+ logger.error(e.toString());
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ *
+ * 功能说明 : 多个图片支持(|分隔)
+ * 创建者 : byx
+ * 修改日期 : 2018年9月26日
+ * @param pic 图片位置
+ * @param picPath 图片路径
+ * @param width 图片宽度
+ * @param height 图片高度
+ * @param picAttch 图片后缀文字
+ */
+ public void createPicturePlus(XWPFParagraph pic, String picPath, int width, int height, String picAttch){
+ if(StringUtils.isBlank(picPath)){
+ logger.warn("文件路径错误:");
+ logger.warn(picPath);
+ return;
+ }
+ if(StringUtils.indexOf(picPath, ",") == -1){
+ //为单个时直接插入图片
+ createPicture(pic,picPath,width,height,picAttch);
+ }else{
+ //多个时,
+ String[] paths = StringUtils.split(picPath,",");
+ for (String s : paths) {
+ createPicture(pic,s,width,height,picAttch);
+ }
+ }
+// createPicture
+ }
+
+ /**
+ * 在word模板文档里,用{key}标签来表示要替换的内容,把key对应的value存储于replaceMap里,即可完成替换
+ */
+ public WordOperator replaceText(Map replaceMap) {
+ this.replaceMap = replaceMap;
+ // 替换文本内容的标签
+ List paragraphList = doc.getParagraphs();
+ replaceText(paragraphList);
+ // 替换表格内部标签
+ List tableList = doc.getTables();
+ for (XWPFTable table : tableList) {
+ for (int i = 0; i < table.getNumberOfRows(); i++) {
+ XWPFTableRow row = table.getRow(i);
+ List tableCellList = row.getTableCells();
+ for (XWPFTableCell cell : tableCellList) {
+ replaceText(cell.getParagraphs());
+ }
+ }
+ }
+ return this;
+ }
+
+ /**
+ * 在word模板文档里,用{key}标签来表示要替换的内容,把key对应的value存储于replaceMap里,即可完成替换(带有替换图片的功能)
+ */
+ public WordOperator replaceTextPlus(Map replaceMap) {
+ this.replaceMap = replaceMap;
+ // 替换文本内容的标签
+ List paragraphList = doc.getParagraphs();
+ replaceTextPlus(paragraphList);
+ // 替换表格内部标签
+ List tableList = doc.getTables();
+ for (XWPFTable table : tableList) {
+ for (int i = 0; i < table.getNumberOfRows(); i++) {
+ XWPFTableRow row = table.getRow(i);
+ List tableCellList = row.getTableCells();
+ for (XWPFTableCell cell : tableCellList) {
+ replaceTextPlus(cell.getParagraphs());
+ }
+ }
+ }
+ return this;
+ }
+
+
+ public WordOperator replaceTextPlusRemove(Map replaceMap,String removeList) {
+ this.replaceMap = replaceMap;
+ // 替换文本内容的标签
+ List paragraphList = doc.getParagraphs();
+ replaceTextPlus(paragraphList);
+ // 替换表格内部标签
+ List tableList = doc.getTables();
+ for (XWPFTable table : tableList) {
+ for (int i = 0; i < table.getNumberOfRows(); i++) {
+ XWPFTableRow row = table.getRow(i);
+ List tableCellList = row.getTableCells();
+ for (XWPFTableCell cell : tableCellList) {
+ replaceTextPlus(cell.getParagraphs());
+ }
+ }
+ }
+ return this;
+ }
+
+ /**
+ * 在word模板文档里,用{key}标签来表示要替换的内容,把key对应的value存储于replaceMap里,即可完成替换(带图片,仅支持一个图片)
+ */
+ public WordOperator replaceTextAndCreatePicture(Map replaceMap) {
+ this.replaceMap = replaceMap;
+ // 替换文本内容的标签
+ List paragraphList = doc.getParagraphs();
+ replaceText(paragraphList);
+ // 替换表格内部标签
+ List tableList = doc.getTables();
+ for (XWPFTable table : tableList) {
+ for (int i = 0; i < table.getNumberOfRows(); i++) {
+ XWPFTableRow row = table.getRow(i);
+ List tableCellList = row.getTableCells();
+ for (XWPFTableCell cell : tableCellList) {
+ replaceTextAndCreatePicture(cell.getParagraphs());
+ }
+ }
+ }
+ return this;
+ }
+
+ /**
+ * 把替换段落抽取出一个方法,在替换文本和替换表格里都可以调用
+ */
+ private void replaceText(List paragraphList) {
+ // 取出word模板里的全部段落,遍历
+ for (int i = 0; i < paragraphList.size(); i++) {
+ XWPFParagraph paragraph = paragraphList.get(i);
+ // 拿出每一个段落,判断内容里是否包含字符串"{"和"}",只有两者同时存在了才执行替换标签的逻辑
+ String paragraphText = paragraph.getText();
+ if (!StringUtils.isBlank(paragraphText) && paragraphText.indexOf(LABEL_STR) != -1 && paragraphText.indexOf(LABEL_END) != -1) {
+ // 每一个段落分很多小段文本,官方API只能否通过XWPFRun对象执行替换文本功能
+ List runList = paragraph.getRuns();
+ // 组装replaceMap的key
+ String key = "";
+ // 是否检测到有"{"字符串,有为true,没有为false
+ boolean include = false;
+ for (int j = 0; j < runList.size(); j++) {
+ XWPFRun run = runList.get(j);
+ String text = run.getText(0);
+ // 取出每一个小段里标签头和尾的角标
+ int labelStrIndex = StringUtils.indexOf(text, LABEL_STR);
+ int labelEndIndex = StringUtils.indexOf(text, LABEL_END);
+ // 只有{
+ if (labelStrIndex != -1 && labelEndIndex == -1) {
+ // 例如有"aaa{bbb",则aaa不动,{bbb去掉,同时把bbb累加到key里
+ String textBefore = text.substring(0, labelStrIndex);
+ String textAfter = text.substring(labelStrIndex + 1);
+ run.setText(textBefore, 0);
+ key += textAfter;
+ include = true;
+ // 只有}
+ } else if (labelStrIndex == -1 && labelEndIndex != -1) {
+ // 例如有"aaa}bbb",则aaa}去掉,bbb不动,同时把aaa累加到key里
+ String textBefore = text.substring(0, labelEndIndex);
+ String textAfter = text.substring(labelEndIndex + 1);
+ key += textBefore;
+ Object value = replaceMap.get(key);
+ if (value == null || StringUtils.isBlank(value.toString())) {
+ value = "";
+ }
+ key = "";
+ run.setText(value + textAfter, 0);
+ include = false;
+ // 两个都没有
+ } else if (labelStrIndex == -1 && labelEndIndex == -1) {
+ // 例如有"aaa",如果之前有{了,则把内容累加到key里,同时去掉内容;如果没有{,则说明是普通文本,跳过不管
+ if (include) {
+ key += text;
+ run.setText("", 0);
+ }
+ // 两个都存在,这种情况比较复杂。经过多次试验,XWPFRun切割内容,只会同时各出现1次而已
+ } else {
+ // {在前,}在后
+ if (labelStrIndex < labelEndIndex) {
+ // 例如有"aaa{bbb}ccc",则aaa不动,{bbb}去掉同时进行替换,ccc保留(因为有规范,所以这是一个独立完整的标签,且bbb绝对有值)
+ String textBefore = text.substring(0, labelStrIndex);
+ String textMiddle = text.substring(labelStrIndex + 1, labelEndIndex);
+ String textAfter = text.substring(labelEndIndex + 1);
+ Object value = replaceMap.get(textMiddle);
+ if (value == null || StringUtils.isBlank(value.toString())) {
+ value = "";
+ }
+ run.setText(textBefore + value + textAfter, 0);
+ key = "";
+ include = false;
+ // }在前,{在后
+ } else {
+ // 例如有"aaa}bbb{ccc",则aaa}去掉,且进行替换;bbb不动,{ccc去掉,累加到key里去
+ String textBefore = text.substring(0, labelEndIndex);
+ String textMiddle = text.substring(labelEndIndex + 1, labelStrIndex);
+ String textAfter = text.substring(labelStrIndex + 1);
+ key += textBefore;
+ Object value = replaceMap.get(key);
+ if (value == null || StringUtils.isBlank(value.toString())) {
+ value = "";
+ }
+ run.setText(value + textMiddle, 0);
+ key = textAfter;
+ include = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ /**
+ * 把替换段落抽取出一个方法,在替换文本和替换表格里都可以调用(可以替换为图片)
+ */
+ private void replaceTextPlus(List paragraphList) {
+ //InputStream imageFileIs = null;
+ // 取出word模板里的全部段落,遍历
+ for (int i = 0; i < paragraphList.size(); i++) {
+ XWPFParagraph paragraph = paragraphList.get(i);
+ // 拿出每一个段落,判断内容里是否包含字符串"{"和"}",只有两者同时存在了才执行替换标签的逻辑
+ String paragraphText = paragraph.getText();
+ if (!StringUtils.isBlank(paragraphText) && StringUtils.indexOf(paragraphText,LABEL_STR) != -1 && StringUtils.indexOf(paragraphText,LABEL_END) != -1) {
+ // 每一个段落分很多小段文本,官方API只能通过XWPFRun对象执行替换文本功能
+ List runList = paragraph.getRuns();
+ // 组装replaceMap的key
+ String key = "";
+ // 是否检测到有"{"字符串,有为true,没有为false
+ boolean include = false;
+ for (int j = 0; j < runList.size(); j++) {
+ XWPFRun run = runList.get(j);
+ //颜色
+// run.setColor("F3C917");
+ //加粗
+// run.setBold(true);
+ //背景色
+// run.getCTR().addNewRPr().addNewHighlight().setVal(STHighlightColor.YELLOW);
+ //底纹
+// CTShd shd = run.getCTR().addNewRPr().addNewShd();
+// shd.setFill("FFFF00");
+
+ String text = run.getText(0);
+ // 取出每一个小段里标签头和尾的角标
+ //是否存在两个{
+ boolean isParagraphReplaceAllText = false;
+ if(StringUtils.ordinalIndexOf(text,LABEL_STR,2) != -1){
+ isParagraphReplaceAllText = true;
+ text = paragraphReplaceAllText(text,replaceMap);
+ }
+ int labelStrIndex = StringUtils.indexOf(text, LABEL_STR);
+ int labelEndIndex = StringUtils.indexOf(text, LABEL_END);
+ // 只有{
+ if (labelStrIndex != -1 && labelEndIndex == -1) {
+ // 例如有"aaa{bbb",则aaa不动,{bbb去掉,同时把bbb累加到key里
+ String textBefore = text.substring(0, labelStrIndex);
+ String textAfter = text.substring(labelStrIndex + 1);
+ run.setText(textBefore, 0);
+ key += textAfter;
+ include = true;
+ // 只有}
+ } else if (labelStrIndex == -1 && labelEndIndex != -1) {
+ // 例如有"aaa}bbb",则aaa}去掉,bbb不动,同时把aaa累加到key里
+ String textBefore = text.substring(0, labelEndIndex);
+ String textAfter = text.substring(labelEndIndex + 1);
+ key += textBefore;
+ //Object value = replaceMap.get(key);
+ String value = (String)replaceMap.get(key);
+ if (StringUtils.isBlank(value)) value = "";
+ WordTextStyle style = (WordTextStyle)replaceMap.get(key + "_style");
+ //添加样式
+ if(style != null) style.run(run);
+ if (StringUtils.isBlank(value)) value = "";
+ value = StringEscapeUtils.unescapeHtml4(value);
+ key = "";
+ //--2020-04修改
+ String[] values = value.split("\r\n");
+ if(values.length > 1) {
+ run.setText(values[0],0);
+ for (int x = 1; x < values.length; x++) {
+ //存在分段则新建一个run
+ XWPFRun newrun = paragraph.createRun();
+ //copy样式
+ newrun.getCTR().setRPr(run.getCTR().getRPr());
+ //换行
+ newrun.addBreak();
+ //缩进
+ //newrun.addTab();
+ if(x == values.length - 1) {
+ newrun.setText(values[x] + textAfter);
+ }else {
+ newrun.setText(values[x]);
+ }
+ }
+ }else {
+ run.setText(value + textAfter, 0);
+ }
+ include = false;
+ // 两个都没有
+ } else if (labelStrIndex == -1 && labelEndIndex == -1) {
+ // 例如有"aaa",如果之前有{了,则把内容累加到key里,同时去掉内容;如果没有{,则说明是普通文本,跳过不管
+ if (include) {
+ key += text;
+ run.setText("", 0);
+ }
+ if(isParagraphReplaceAllText){
+ //替换文本
+ run.setText(text,0);
+ }
+ // 两个都存在,这种情况比较复杂。经过多次试验,XWPFRun切割内容,只会同时各出现1次而已
+ } else {
+ // {在前,}在后
+ if (labelStrIndex < labelEndIndex) {
+ // 例如有"aaa{bbb}ccc",则aaa不动,{bbb}去掉同时进行替换,ccc保留(因为有规范,所以这是一个独立完整的标签,且bbb绝对有值)
+ String textBefore = text.substring(0, labelStrIndex);
+ String textMiddle = text.substring(labelStrIndex + 1, labelEndIndex);
+ String textAfter = text.substring(labelEndIndex + 1);
+ String value = (String)replaceMap.get(textMiddle);
+ if (StringUtils.isBlank(value)) value = "";
+ WordTextStyle style = (WordTextStyle)replaceMap.get(textMiddle + "_style");
+ //添加样式
+ if(style != null) style.run(run);
+ value = StringEscapeUtils.unescapeHtml4(value);
+ //--2020-04修改
+ String[] values = value.split("\r\n");
+ if(values.length > 1) {
+ run.setText(textBefore + values[0],0);
+ for (int x = 1; x < values.length; x++) {
+ //存在分段则新建一个run
+ XWPFRun newrun = paragraph.createRun();
+ //copy样式
+ newrun.getCTR().setRPr(run.getCTR().getRPr());
+ //换行
+ newrun.addBreak();
+ //缩进
+ //newrun.addTab();
+ if(x == values.length - 1) {
+ newrun.setText(values[x] + textAfter,0);
+ }else {
+ newrun.setText(values[x]);
+ }
+ }
+ }else {
+ run.setText(textBefore + value + textAfter, 0);
+ }
+
+ key = "";
+ include = false;
+ // }在前,{在后
+ } else {
+ // 例如有"aaa}bbb{ccc",则aaa}去掉,且进行替换;bbb不动,{ccc去掉,累加到key里去
+ String textBefore = text.substring(0, labelEndIndex);
+ String textMiddle = text.substring(labelEndIndex + 1, labelStrIndex);
+ String textAfter = text.substring(labelStrIndex + 1);
+ key += textBefore;
+ String value = (String)replaceMap.get(key);
+ if (value == null || StringUtils.isBlank(value.toString())) value = "";
+ WordTextStyle style = (WordTextStyle)replaceMap.get(textMiddle + "_style");
+ //添加样式
+ if(style != null) style.run(run);
+ value = StringEscapeUtils.unescapeHtml4(value);
+ //--2020-04修改
+ String[] values = value.toString().split("\r\n");
+ if(values.length > 1) {
+ run.setText(values[0],0);
+ for (int x = 1; x < values.length; x++) {
+ //存在分段则新建一个run
+ XWPFRun newrun = paragraph.createRun();
+ //copy样式
+ newrun.getCTR().setRPr(run.getCTR().getRPr());
+ //换行
+ newrun.addBreak();
+ //缩进
+ //newrun.addTab();
+ if(x == values.length - 1) {
+ newrun.setText(values[x] + textMiddle,0);
+ }else {
+ newrun.setText(values[x]);
+ }
+ }
+ }else {
+ run.setText(value + textMiddle, 0);
+ }
+ key = textAfter;
+ include = true;
+ }
+ }
+ }
+ //富文本标签(转成图片的富文本)
+ } else if(StringUtils.isNotBlank(paragraphText) && paragraphText.indexOf(LABEL_RICH_TEXT_STR) != -1 && paragraphText.indexOf(LABEL_RICH_TEXT_END) != -1){
+ System.out.println("paragraphText="+paragraphText);
+ //如果匹配到‘<’和‘>’则开始替换为图片
+ // 每一个段落分很多小段文本,官方API只能否通过XWPFRun对象执行替换文本功能
+ List runList = paragraph.getRuns();
+ //组装replaceMap的key
+ String key = "";
+
+ //
+ //摘出key
+ int $labelStrIndex = StringUtils.indexOf(paragraphText, LABEL_RICH_TEXT_STR);
+ int $labelEndIndex = StringUtils.indexOf(paragraphText, LABEL_RICH_TEXT_END);
+
+ //必须存在开始和结束标签
+ if($labelStrIndex != -1 && $labelEndIndex != -1){
+ key = paragraphText;
+ key = key.substring($labelStrIndex + LABEL_RICH_TEXT_STR.length());
+ $labelEndIndex = StringUtils.indexOf(key, LABEL_RICH_TEXT_END);
+ key = key.substring(0,$labelEndIndex);
+ }
+
+ //去除整行(整个paragraph)
+ for (int j = 0; j < runList.size(); j++) {
+ XWPFRun run = runList.get(j);
+ run.setText("", 0);
+ }
+ //添加图片
+ //创建一个run
+ //XWPFRun $run = paragraph.createRun();
+ Object value = replaceMap.get(key);
+ if (value == null || StringUtils.isBlank(value.toString())) {
+ value = "";
+ }
+ String imagePath = getHtmlImage(value.toString());
+ //try {
+ //imageFileIs = new FileInputStream(new File(imagePath));
+ //$run.addPicture(imageFileIs, 6, "image", 595,842);
+ //} catch (InvalidFormatException | IOException e) {
+ //logger.error("图片读取或添加错误!");
+ //logger.error(e.getMessage(),e);
+ //e.printStackTrace();
+ //}
+ createPicturePlus(paragraph,imagePath,595,842,"");
+ //FileUtils.deleteFile(imagePath);
+ //$run.setText();
+ //图片标签
+ }else if(StringUtils.isNotBlank(paragraphText) && paragraphText.indexOf(LABEL_IMAGE_STR) != -1 && paragraphText.indexOf(LABEL_IMAGE_END) != -1){
+ //如果匹配到‘<’和‘>’则开始替换为图片
+ // 每一个段落分很多小段文本,官方API只能否通过XWPFRun对象执行替换文本功能
+ List runList = paragraph.getRuns();
+ // 组装replaceMap的key
+ String key = "";
+ //读取简易标签对象如:‘image,10,10,后缀’
+ WordImageLabel wordImageLabel = null;
+ // 是否检测到有"<"字符串,有为true,没有为false
+ boolean include = false;
+ for (int j = 0; j < runList.size(); j++) {
+ XWPFRun run = runList.get(j);
+ String text = run.getText(0);
+ // 取出每一个小段里标签头和尾的角标
+ int labelStrIndex = StringUtils.indexOf(text, LABEL_IMAGE_STR);
+ int labelEndIndex = StringUtils.indexOf(text, LABEL_IMAGE_END);
+ // 只有<
+ if (labelStrIndex != -1 && labelEndIndex == -1) {
+ // 例如有"aaabbb",则aaa>去掉,bbb不动,同时把aaa累加到key里
+ String textBefore = text.substring(0, labelEndIndex);
+// String textAfter = text.substring(labelEndIndex + 1);
+ key += textBefore;
+ //读取简易标签对象
+ wordImageLabel = new WordImageLabel(key);
+ Object value = replaceMap.get(wordImageLabel.getKey());
+ if (value == null || StringUtils.isBlank(value.toString())) {
+ value = "";
+ }
+ key = "";
+ //创建图片
+ run.setText("", 0);
+// run.setText(value + textAfter, 0);
+ createPicturePlus(paragraph,(String)value,wordImageLabel.getWidth(),wordImageLabel.getHeight(),wordImageLabel.getPicAttch());
+ include = false;
+ // 两个都没有
+ } else if (labelStrIndex == -1 && labelEndIndex == -1) {
+ // 例如有"aaa",如果之前有<了,则把内容累加到key里,同时去掉内容;如果没有<,则说明是普通文本,跳过不管
+ if (include) {
+ key += text;
+ run.setText("", 0);
+ }
+ // 两个都存在,这种情况比较复杂。经过多次试验,XWPFRun切割内容,只会同时各出现1次而已
+ } else {
+ // <在前,>在后
+ if (labelStrIndex < labelEndIndex) {
+ // 例如有"aaaccc",则aaa不动,去掉同时进行替换,ccc保留(因为有规范,所以这是一个独立完整的标签,且bbb绝对有值)
+// String textBefore = text.substring(0, labelStrIndex);
+ String textMiddle = text.substring(labelStrIndex + 1, labelEndIndex);
+// String textAfter = text.substring(labelEndIndex + 1);
+ wordImageLabel = new WordImageLabel(textMiddle);
+ Object value = replaceMap.get(wordImageLabel.getKey());
+ if (value == null || StringUtils.isBlank(value.toString())) {
+ value = "";
+ }
+ run.setText("", 0);
+// run.setText(textBefore + value + textAfter, 0);
+ createPicturePlus(paragraph,(String)value,wordImageLabel.getWidth(),wordImageLabel.getHeight(),wordImageLabel.getPicAttch());
+ key = "";
+ include = false;
+ // >在前,<在后
+ } else {
+ // 例如有"aaa>bbb去掉,且进行替换;bbb不动, replaceMap){
+ return CommonUtil.getReplaceMapValue(str,replaceMap,LABEL_STR,LABEL_END);
+ }
+
+ /**
+ * 把替换段落抽取出一个方法,在替换文本和替换表格里都可以调用(带图片),只替换{IMAGE}
+ */
+ private void replaceTextAndCreatePicture(List paragraphList) {
+ // 取出word模板里的全部段落,遍历
+ for (int i = 0; i < paragraphList.size(); i++) {
+ XWPFParagraph paragraph = paragraphList.get(i);
+ // 拿出每一个段落,判断内容里是否包含字符串"{"和"}",只有两者同时存在了才执行替换标签的逻辑
+ String paragraphText = paragraph.getText();
+ if (!StringUtils.isBlank(paragraphText)) {
+ //判断是否为唯一的image关键字
+ if(StringUtils.equals(paragraphText, "{IMAGE}") && paragraphText.indexOf(LABEL_STR) != -1 && paragraphText.indexOf(LABEL_END) != -1){
+ //去掉关键字标记
+ List runList = paragraph.getRuns();
+ for (int j = 0; j < runList.size(); j++) {
+ XWPFRun run = runList.get(j);
+ run.setText("", 0);
+ }
+ //获取图片地址
+ String picPath = (String) replaceMap.get("IMAGE");
+ //创建图片
+ createPicture(paragraph,picPath,83,83," ");
+ //创建后不需要普通的文字替换了,跳过本段落
+ continue;
+ }
+ // 每一个段落分很多小段文本,官方API只能否通过XWPFRun对象执行替换文本功能
+ List runList = paragraph.getRuns();
+ // 组装replaceMap的key
+ String key = "";
+ // 是否检测到有"{"字符串,有为true,没有为false
+ boolean include = false;
+ for (int j = 0; j < runList.size(); j++) {
+ XWPFRun run = runList.get(j);
+ String text = run.getText(0);
+ // 取出每一个小段里标签头和尾的角标
+ int labelStrIndex = text.indexOf(LABEL_STR);
+ int labelEndIndex = text.indexOf(LABEL_END);
+ // 只有{
+ if (labelStrIndex != -1 && labelEndIndex == -1) {
+ // 例如有"aaa{bbb",则aaa不动,{bbb去掉,同时把bbb累加到key里
+ String textBefore = text.substring(0, labelStrIndex);
+ String textAfter = text.substring(labelStrIndex + 1);
+ run.setText(textBefore, 0);
+ //createPicture(paragraph,"");
+ key += textAfter;
+ include = true;
+ // 只有}
+ } else if (labelStrIndex == -1 && labelEndIndex != -1) {
+ // 例如有"aaa}bbb",则aaa}去掉,bbb不动,同时把aaa累加到key里
+ String textBefore = text.substring(0, labelEndIndex);
+ String textAfter = text.substring(labelEndIndex + 1);
+ key += textBefore;
+ Object value = replaceMap.get(key);
+ if (value == null || StringUtils.isBlank(value.toString())) {
+ value = "";
+ }
+ key = "";
+ run.setText(value + textAfter, 0);
+ include = false;
+ // 两个都没有
+ } else if (labelStrIndex == -1 && labelEndIndex == -1) {
+ // 例如有"aaa",如果之前有{了,则把内容累加到key里,同时去掉内容;如果没有{,则说明是普通文本,跳过不管
+ if (include) {
+ key += text;
+ run.setText("", 0);
+ }
+ // 两个都存在,这种情况比较复杂。经过多次试验,XWPFRun切割内容,只会同时各出现1次而已
+ } else {
+ // {在前,}在后
+ if (labelStrIndex < labelEndIndex) {
+ // 例如有"aaa{bbb}ccc",则aaa不动,{bbb}去掉同时进行替换,ccc保留(因为有规范,所以这是一个独立完整的标签,且bbb绝对有值)
+ String textBefore = text.substring(0, labelStrIndex);
+ String textMiddle = text.substring(labelStrIndex + 1, labelEndIndex);
+ String textAfter = text.substring(labelEndIndex + 1);
+ Object value = replaceMap.get(textMiddle);
+ if (value == null || StringUtils.isBlank(value.toString())) {
+ value = "";
+ }
+ run.setText(textBefore + value + textAfter, 0);
+ key = "";
+ include = false;
+ // }在前,{在后
+ } else {
+ // 例如有"aaa}bbb{ccc",则aaa}去掉,且进行替换;bbb不动,{ccc去掉,累加到key里去
+ String textBefore = text.substring(0, labelEndIndex);
+ String textMiddle = text.substring(labelEndIndex + 1, labelStrIndex);
+ String textAfter = text.substring(labelStrIndex + 1);
+ key += textBefore;
+ Object value = replaceMap.get(key);
+ if (value == null || StringUtils.isBlank(value.toString())) {
+ value = "";
+ }
+ run.setText(value + textMiddle, 0);
+ key = textAfter;
+ include = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+// public static void main(String[] args) {
+// String text = "";
+// //摘出key
+// int $labelStrIndex = StringUtils.indexOf(text, LABEL_RICH_TEXT_STR);
+// int $labelEndIndex = StringUtils.indexOf(text, LABEL_RICH_TEXT_END);
+//
+//
+// System.out.println("$labelStrIndex=" + $labelStrIndex);
+// System.out.println("$labelEndIndex=" + $labelEndIndex);
+// //必须存在开始和结束标签
+// if($labelStrIndex != -1 && $labelEndIndex != -1){
+// String key = text;
+// key = key.substring($labelStrIndex + LABEL_RICH_TEXT_STR.length());
+// $labelEndIndex = StringUtils.indexOf(key, LABEL_RICH_TEXT_END);
+// System.out.println("key="+key);
+// key = key.substring(0,$labelEndIndex);
+// System.out.println("key="+key);
+//
+// }
+//
+// HtmlImageGenerator imageGenerator = new HtmlImageGenerator();
+//// String htmlstr = "
编号:10001
";
+// String htmlstr = "
编号:10001
";
+//// String htmlstr = "
";
+//// htmlstr = htmlstr.replaceAll("/education/", "http://127.0.0.1:9000/education/");
+// imageGenerator.loadHtml(htmlstr);
+//// imageGenerator.loadUrl("https://www.baidu.com");
+//// imageGenerator.setSize(new Dimension(595,842));
+// try {
+// imageGenerator.getBufferedImage();
+// Thread.sleep(4000);
+// } catch (InterruptedException e) {
+// e.printStackTrace();
+// }
+// imageGenerator.saveAsImage("z:/baidu.png");
+// }
+
+ public static void main0(String[] args) {
+ getHtmlImage("aa");
+ }
+ public static String getHtmlImage(String html){
+// String path = Global.getConfig("userfiles.basedir") + "/htmlImageTemp/";
+ String path = "";
+ FileUtils.createDirectory(path);
+ path += IdGen.uuid() + ".png";
+ getHtmlImage(html,path);
+ return path;
+ }
+ public static void getHtmlImage(String html, String path){
+ getHtmlImage(html,8000,path);
+ }
+ public static void getHtmlImage(String html, int sleep, String path){
+// HtmlImageGenerator imageGenerator = new HtmlImageGenerator();
+// imageGenerator.loadHtml(html);
+// imageGenerator.setSize(new Dimension(595,842));
+// try {
+// imageGenerator.getBufferedImage();
+// Thread.sleep(sleep);
+// } catch (InterruptedException e) {
+// e.printStackTrace();
+// }
+// imageGenerator.saveAsImage(path);
+ }
+ /**
+ * 表格向下扩展数据行,因为POI对word格式支持较差,故我们做一些约定
+ * 1.约定表格要有一行模板行,用于扩展数据行的样式效仿;
+ * 2.模板表格里最好不要有合并行,如非常需要,则可以用隐藏单元格或设置白色边框的方式巧妙替代合并行;
+ * 3.模板行下方不允许出现其他行
+ * @param tableIndex 表格角标,第1个表为0
+ * @param tmpRowIndex 模板行角标,第1行为0(模板行不是标题行,而是扩展数据行样式的效仿对象)
+ * @param isDelTmpRow true-删除模板行;false-不删除模板行
+ * @param rowlist 要插入的数据集合,格式为[行集合<列集合>,列集合的长度最好与模板行长度一致]
+ */
+ public WordOperator insert2Table(int tableIndex, int tmpRowIndex, boolean isDelTmpRow, List> rowlist) {
+ // 因为需要对rowlist进行添加操作,故而我们重新做一个变量,防止因为改变而产生问题
+ List> dataList = new ArrayList<>(rowlist);
+ // 根据角标取出表格对像
+ XWPFTable table = doc.getTables().get(tableIndex);
+ // 再根据行号获取模板行
+ XWPFTableRow tmpRow = table.getRow(tmpRowIndex);
+ // 不知道是什么原因,最后一列数据会跑到模板行上一行,故而这里在最末添加一组数据,解决这个bug
+ dataList.add(new ArrayList<>());
+ // 遍历数据集合
+ for (int i = 0, len = dataList.size(); i < dataList.size(); i++) {
+ // 计算数据行编号
+ int dataIndex = tmpRowIndex + 1 + i;
+ // 按照模板行样式添加一行到数据行
+ table.addRow(tmpRow, dataIndex);
+ if (i < len - 1) {
+ // 取出这一行
+ XWPFTableRow row = table.getRow(dataIndex);
+ // 取出这一行全部单元格
+ List cellList = row.getTableCells();
+ // 取出这一行对应的数据,数据与单元格角标位置是一致的,一一替换文本
+ List colList = dataList.get(i);
+ for (int j = 0; j < cellList.size(); j++) {
+ setCellText(cellList.get(j), colList, j);
+ }
+ }
+ }
+ // 删掉那一行为了bug而添加的空白行(因为空白行跑到模板行上一行,所以tmpRowIndex为该行角标)
+ table.removeRow(tmpRowIndex);
+ // 删除模版行(因为上面已经删除了空白行了,所以tmpRowIndex就变成了下一行模板行了)
+ if (isDelTmpRow) {
+ table.removeRow(tmpRowIndex);
+ }
+ return this;
+ }
+
+ /**
+ * 替换单元格文本
+ * @param cell 单元格
+ * @param colList 替换文本的集合(角标越位了,就置空)
+ * @param j 单元格角标,也就是文本集合的角标
+ */
+ private void setCellText(XWPFTableCell cell, List colList, int j) {
+// cell.setColor("FF0000");
+ // 无论一个单元格被切割成多少个run,只需要修改第一个即可,改完就return掉了
+ List paragraphs = cell.getParagraphs();
+ for (XWPFParagraph p : paragraphs) {
+ List runs = p.getRuns();
+ for (XWPFRun r : runs) {
+ try {
+ r.setText(colList.get(j), 0);
+ //染上背景色
+// r.getCTR().addNewRPr().addNewHighlight().setVal(STHighlightColor.YELLOW);
+ } catch (Exception e) {
+ r.setText("", 0);
+ }
+ return;
+ }
+ }
+ }
+
+ /**
+ * 填充颜色
+ * @param tableIndex 第几个表格,第一个表格为0
+ * @param rowIndex 表格中的第几行,从0开始算起
+ * @param colIndex 行中的第几单元格,从0开始算起
+ * @param color 颜色,rgbStr - the desired cell color, in the hex form "RRGGBB".
+ * @return
+ */
+ public WordOperator fillCollorTable(int tableIndex, int rowIndex, int colIndex, String color) {
+ // 根据角标取出表格对像
+ XWPFTable table = doc.getTables().get(tableIndex);
+ if(table == null){
+ logger.error("没有找到表格!tableIndex: [{}] row: [{}] col: [{}]",tableIndex,rowIndex,colIndex);
+ return this;
+ }
+ XWPFTableRow row = table.getRow(rowIndex);
+ if(row == null){
+ logger.error("没有找到row!tableIndex: [{}] row: [{}] col: [{}]",tableIndex,rowIndex,colIndex);
+ return this;
+ }
+ XWPFTableCell col = row.getCell(colIndex);
+ if(col == null){
+ logger.error("没有找到col!tableIndex: [{}] row: [{}] col: [{}]",tableIndex,rowIndex,colIndex);
+ return this;
+ }
+ col.setColor(color);
+ return this;
+ }
+
+ /**
+ * 填充颜色
+ * @param tableIndex 第几个表格,第一个表格为0
+ * @param rowIndex 表格中的第几行,从0开始算起
+ * @param color 颜色,rgbStr - the desired cell color, in the hex form "RRGGBB".
+ * @return
+ */
+ public WordOperator fillRowCollorTable(int tableIndex, int rowIndex, String color) {
+ // 根据角标取出表格对像
+ XWPFTable table = doc.getTables().get(tableIndex);
+ if(table == null){
+ logger.error("没有找到表格!tableIndex: [{}] row: [{}]",tableIndex,rowIndex);
+ return this;
+ }
+ XWPFTableRow row = table.getRow(rowIndex);
+ if(row == null){
+ logger.error("没有找到row!tableIndex: [{}] row: [{}]",tableIndex,rowIndex);
+ return this;
+ }
+ List cellList = row.getTableCells();
+ cellList.forEach(col -> col.setColor(color));
+ return this;
+ }
+
+ /**
+ * 填充颜色
+ * @param tableIndex 第几个表格,第一个表格为0
+ * @param colIndex 表格中的第几列,从0开始算起
+ * @param color 颜色,rgbStr - the desired cell color, in the hex form "RRGGBB".
+ * @return
+ */
+ public WordOperator fillColCollorTable(int tableIndex, int colIndex, String color) {
+ // 根据角标取出表格对像
+ XWPFTable table = doc.getTables().get(tableIndex);
+ if(table == null){
+ logger.error("没有找到表格!tableIndex: [{}] row: [{}]",tableIndex,colIndex);
+ return this;
+ }
+ List rows = table.getRows();
+ rows.forEach(row -> {
+ List cellList = row.getTableCells();
+ for (int i = 0; i < cellList.size(); i++) {
+ if(i == colIndex){
+ cellList.get(i).setColor(color);
+ }
+ }
+ });
+ return this;
+ }
+
+ /**
+ * 给定输出流即可将word文档导出到
+ */
+ public void write(OutputStream os) throws Exception {
+ doc.write(os);
+ }
+
+ /**
+ *
+ * 功能说明 : 补充空列
+ * 创建者 : byx
+ * 修改日期 : 2018年12月25日
+ * @param returnList:填充到这个list中
+ * @param inputList:输入的list,业务信息列表,用来计算空列的初始值
+ * @param endRowNum:总共N行
+ * @param colNum:拥有几列
+ */
+ public static void fillNullCall(List> returnList, List> inputList, int endRowNum, int colNum){
+ int fillNum = 0;
+ if(inputList != null && !inputList.isEmpty()){
+ fillNum = inputList.size();
+ }
+ WordOperator.fillNullCall(returnList,fillNum,endRowNum,colNum);
+
+ }
+
+ /**
+ *
+ * 功能说明 : 补充空列
+ * 创建者 : byx
+ * 修改日期 : 2018年12月25日
+ * @param returnList:填充到这个list中
+ * @param startRowNum:从N开始循环
+ * @param endRowNum:总共N行
+ * @param colNum:拥有几列
+ */
+ public static void fillNullCall(List> returnList, int startRowNum, int endRowNum, int colNum){
+ for(int i = startRowNum;i < endRowNum; i++){
+ List twoList = Lists.newArrayList();
+ for (int j = 0; j < colNum; j++) {
+ twoList.add("");
+ }
+ returnList.add(twoList);
+ }
+ }
+
+ /**
+ * 根据第几个表格删除第几行,单独删除
+ * @param tableIndex 第几个表格
+ * @param rowIndex 删除第几行
+ * @return
+ */
+ public WordOperator removeTableRow(int tableIndex, int rowIndex,int colIndex) {
+ // 根据角标取出表格对像
+ XWPFTable table = doc.getTables().get(tableIndex);
+ if(table == null){
+ logger.error("没有找到表格!tableIndex: [{}] row: [{}]",tableIndex,rowIndex);
+ return this;
+ }
+// XWPFTableRow row = table.getRow(rowIndex);
+// XWPFTableRow nextRow = table.getRow(rowIndex + 1);
+// XWPFTableCell col = row.getCell(colIndex);
+// XWPFTableCell nextCol = nextRow.getCell(colIndex);
+//
+// System.out.println("文字内容:" + col.getText());
+// List list = Lists.newArrayList();
+// list.add(StringUtils.isBlank(col.getText())?"空的??":col.getText());
+// setCellText(nextCol,list,0);
+// XWPFTableCell nextCol = nextRow.getCell(0);
+// if (nextCol.getCTTc().getTcPr() == null) nextCol.getCTTc().addNewTcPr();
+// if (nextCol.getCTTc().getTcPr().getGridSpan() == null) nextCol.getCTTc().getTcPr().addNewGridSpan();
+// nextCol.getCTTc().getTcPr().getGridSpan().setVal(rowSpan.subtract(new BigInteger("1")));
+ table.removeRow(rowIndex);
+ return this;
+ }
+
+ /**
+ * 根据第几个表格删除多行
+ * @param tableIndex 第几个表格
+ * @param rowIndex 删除第几行的集合
+ * @return
+ */
+ public WordOperator removeTableRow(int tableIndex, List rowIndex,int colIndex) {
+ rowIndex.forEach(x -> removeTableRow(tableIndex,x,colIndex));
+ return this;
+ }
+
+ /**
+ *
+ * 功能说明 : 文档再次替换时使用,因为之前已经替换一次了,所有需要将文档片段存入内存流中,在读取到文档类里,才能替换成功
+ * 创建者 : byx
+ * 修改日期 : 2018年9月26日
+ * @param wo 文档片段对象(已经{替换内容}替换过)
+ * @param result 替换的内容
+ * @return 重新替换的文档片段
+ */
+ public static WordOperator twoReplaceWord(WordOperator wo,Map result){
+ WordOperator w2o = wo;
+ try {
+ w2o = twoReplaceWord(wo);
+ w2o.replaceTextPlus(result);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ //再次替换
+ return w2o;
+ }
+
+ /**
+ *
+ * 功能说明 : 文档再次替换时使用,因为之前已经替换一次了,所有需要将文档片段存入内存流中,在读取到文档类里,才能替换成功
+ * 创建者 : byx
+ * 修改日期 : 2018年9月26日
+ * @param wo 文档片段对象(已经{替换内容}替换过)
+ * @return 重新替换的文档片段
+ */
+ public static WordOperator twoReplaceWord(WordOperator wo) throws Exception {
+ //先创建内存输出流
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ //将文档先输出到
+ wo.write(output);
+ //根据内存输出流创建内存输入流
+ InputStream input = new ByteArrayInputStream(output.toByteArray());
+ //用这个输入流创建文档对象
+ WordOperator w2o = new WordOperator(input);
+ IoUtil.close(output);
+ IoUtil.close(input);
+ return w2o;
+ }
+
+}
diff --git a/jeecg-module-main/src/main/java/org/jeecg/modules/tools/word/WordTextStyle.java b/jeecg-module-main/src/main/java/org/jeecg/modules/tools/word/WordTextStyle.java
new file mode 100644
index 00000000..d19fc042
--- /dev/null
+++ b/jeecg-module-main/src/main/java/org/jeecg/modules/tools/word/WordTextStyle.java
@@ -0,0 +1,255 @@
+/**********************************************************************
+* $Id: WordImageLabel.java WordImageLabel ,v0.1 2018年9月19日 下午8:50:48 byx Exp $
+* Copyright ©2018 sida . All rights reserved
+***********************************************************************/
+
+package org.jeecg.modules.tools.word;
+
+
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.xwpf.usermodel.UnderlinePatterns;
+import org.apache.poi.xwpf.usermodel.VerticalAlign;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTShd;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STHighlightColor;
+
+/**
+* 功能说明:从标签中读取键值,宽高和后缀内容
+* 创建者:byx
+* 创建时间:2018年9月19日
+*
+* 修改时间: 修改者:
+* 修改内容:
+*
+*/
+@Data
+public class WordTextStyle {
+
+ /**
+ * 颜色
+ */
+ private String color;
+
+ public void runColor(XWPFRun run){
+ if(run != null && StringUtils.isNotBlank(color)){
+ run.setColor(color);
+ }
+ }
+
+ /**
+ * 加粗
+ */
+ private Boolean isBold;
+
+ public void runBold(XWPFRun run){
+ if(run != null && isBold != null){
+ run.setBold(isBold);
+ }
+ }
+
+ /**
+ * 背景色(文本突出显示颜色)
+ */
+ private STHighlightColor.Enum bColor;
+
+ public void runBColor(XWPFRun run){
+ if(run != null && bColor != null){
+ run.getCTR().addNewRPr().addNewHighlight().setVal(bColor);
+ }
+ }
+
+ /**
+ * 底纹
+ */
+ private String shading;
+
+ public void runShading(XWPFRun run){
+ if(run != null && StringUtils.isNotBlank(shading)){
+ CTShd shd = run.getCTR().addNewRPr().addNewShd();
+ shd.setFill(shading);
+ }
+ }
+
+ /**
+ * 字体
+ */
+ private String fontFamily;
+
+ public void runFontFamily(XWPFRun run){
+ if(run != null && StringUtils.isNotBlank(fontFamily)){
+ run.setFontFamily(fontFamily);
+ }
+ }
+
+ /**
+ * 字体大小
+ */
+ private Integer fontSize;
+
+ public void runFontSize(XWPFRun run){
+ if(run != null && fontSize != null){
+ run.setFontSize(fontSize);
+ }
+ }
+
+ /**
+ * 阴影
+ */
+ private Boolean shadow;
+
+ public void runShadow(XWPFRun run){
+ if(run != null && shadow != null){
+ run.setShadow(shadow);
+ }
+ }
+
+ /**
+ * 浮雕????
+ */
+ private Boolean embossed;
+
+ public void runEmbossed(XWPFRun run){
+ if(run != null && embossed != null){
+ run.setEmbossed(embossed);
+ }
+ }
+
+ /**
+ * 删除线
+ */
+ private Boolean strikeThrough;
+
+ public void runStrikeThrough(XWPFRun run){
+ if(run != null && strikeThrough != null){
+ run.setStrikeThrough(strikeThrough);
+ }
+ }
+
+ /**
+ * 双删除线
+ */
+ private Boolean doubleStrikethrough;
+
+ public void runDoubleStrikethrough(XWPFRun run){
+ if(run != null && doubleStrikethrough != null){
+ run.setDoubleStrikethrough(doubleStrikethrough);
+ }
+ }
+
+ /**
+ * 大写????
+ */
+ private Boolean capitalized;
+
+ public void runCapitalizedg(XWPFRun run){
+ if(run != null && capitalized != null){
+ run.setCapitalized(capitalized);
+ }
+ }
+
+ /**
+ * 印记????
+ */
+ private Boolean imprinted;
+
+ public void runImprinted(XWPFRun run){
+ if(run != null && imprinted != null){
+ run.setImprinted(imprinted);
+ }
+ }
+
+ /**
+ * 斜体
+ */
+ private Boolean italic;
+
+ public void runItalic(XWPFRun run){
+ if(run != null && italic != null){
+ run.setItalic(italic);
+ }
+ }
+ /**
+ * 小型大写字母??
+ */
+ private Boolean smallCaps;
+
+ public void runSmallCaps(XWPFRun run){
+ if(run != null && smallCaps != null){
+ run.setSmallCaps(smallCaps);
+ }
+ }
+ /**
+ * 字符间距
+ */
+ private Integer kerning;
+
+ public void runKerning(XWPFRun run){
+ if(run != null && kerning != null){
+ run.setKerning(kerning);
+ }
+ }
+
+ /**
+ * 文本位置
+ */
+ private Integer textPosition;
+
+ public void runTextPosition(XWPFRun run){
+ if(run != null && textPosition != null){
+ run.setTextPosition(textPosition);
+ }
+ }
+
+ /**
+ * 下标
+ */
+ private VerticalAlign subscript;
+
+ public void runSubscript(XWPFRun run){
+ if(run != null && subscript != null){
+ run.setSubscript(subscript);
+ }
+ }
+
+ /**
+ * 下划线
+ */
+ private UnderlinePatterns underline;
+
+ public void runUnderline(XWPFRun run){
+ if(run != null && underline != null){
+ run.setUnderline(underline);
+ }
+ }
+
+ /**
+ *
+ * @param run
+ */
+ public void run(XWPFRun run){
+ runColor(run);
+ runBold(run);
+ runBColor(run);
+ runShading(run);
+ runFontFamily(run);
+ runFontSize(run);
+ runShadow(run);
+ runEmbossed(run);
+ runStrikeThrough(run);
+ runDoubleStrikethrough(run);
+ runCapitalizedg(run);
+ runImprinted(run);
+ runItalic(run);
+ runSmallCaps(run);
+ runKerning(run);
+ runTextPosition(run);
+ runSubscript(run);
+ runUnderline(run);
+
+ }
+
+
+
+
+}
diff --git a/jeecg-module-main/src/main/resources/officetemplates/exp1/tpkqk.docx b/jeecg-module-main/src/main/resources/officetemplates/exp1/tpkqk.docx
new file mode 100644
index 00000000..f0bc92f7
--- /dev/null
+++ b/jeecg-module-main/src/main/resources/officetemplates/exp1/tpkqk.docx
@@ -0,0 +1,37 @@
+ {xqxn}学期听评课制度落实情况
+
+ 听课制度落实清空
+ 学院(部)党政领导、学院(部)教务委员会委员、专业负责人、基层教学组织负责人、辅导员、专任教师等人员的听评课情况,建议学院(部)党政领导关注思政课的课堂教学效果。具体要求详见《本科教育教学质量管理实施办法》(附件4)、《关于本科教学听课制度的规定》(附件5)。
+
+{xqxn}学期听课情况:
+
+学院(部)教务委员会委员人数:{oneListSize}人
+
+ 姓名
+ 职务
+ 听课次数
+
+ z
+ z
+ Z
+
+行政负责人、教学副院(部)长及系(专业)负责人等人数:{twoListSize}人
+
+ 姓名
+ 职务
+ 听课次数
+
+ z
+ z
+ z
+
+其他党政领导及辅导员人数:{threeListSize}人
+
+ 姓名
+ 职务
+ 听课次数
+
+ z
+ z
+ z
+
diff --git a/pom.xml b/pom.xml
index 872b0cb2..ecbf0da0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -393,6 +393,7 @@
eot
ttf
svg
+ docx