精华内容
下载资源
问答
  • Java code ... import java.io.File; import java.io.FileInputStream;... /* 字节形式读取模板...----- 实现思路:模板固定部分手动输入,变化的部分用$info$表示,只需替换$info$即可。 1、采用字节的形式读取...
  • Easypoi_4.2.0源码修改 word...  首先定位到问题,当word模板中存在表格的情况下,并且表格的第一列是固定,如下图中蓝框中的内容是固定,这时使用 !fe: 遍历的时候,会发现毫无效果。问题定位到了,那就一步一步来

    Easypoi_4.2.0源码修改 word模板导出 增加表格第一列非循环语句时word导出

    1. 写在前面

      之前写过easypoi修改源码的文章,写的很细,但是发现基本没什么反响。这篇文章不会太详细的介绍如何定位问题,只会简单记录,最后把修改完的代码贴出来,并实现功能。

    2. 开始寻找突破口

      首先定位到问题,当word模板中存在表格的情况下,并且表格的第一列是固定,如下图中蓝框中的内容是固定,这时使用 !fe: 遍历的时候,会发现毫无效果。问题定位到了,那就一步一步来找到原因所在吧。
    在这里插入图片描述

    3. 解决问题

      首先找到代码入口。查看该方法exportWord07

    WordExportUtil.exportWord07("班级.docx", map)
    

    经过一系列的调试,定位到了ParseWord07类中的parseThisTable方法。源码如下:

        private void parseThisTable(XWPFTable table, Map<String, Object> map) throws Exception {
            for(int i = 0; i < table.getNumberOfRows(); ++i) {
                XWPFTableRow row = table.getRow(i);
                List<XWPFTableCell> cells = row.getTableCells();
                Object listobj = this.checkThisTableIsNeedIterator((XWPFTableCell)cells.get(0), map);
                if (listobj == null) {
                    this.parseThisRow(cells, map);
                } else if (listobj instanceof ExcelListEntity) {
                    (new ExcelEntityParse()).parseNextRowAndAddRow(table, i, (ExcelListEntity)listobj);
                    i = i + ((ExcelListEntity)listobj).getList().size() - 1;
                } else {
                    ExcelMapParse.parseNextRowAndAddRow(table, i, (List)listobj);
                    i = i + ((List)listobj).size() - 1;
                }
            }
    
        }
    

      我们需要改的地方就是第五行,之后替换表格内容的代码最重要的就是listobj参数。这源代码中第五行很明显,他只是根据第一列的内容来获取listobj,而我们的模板循环语句并未在第一列上,因此导致word导出时,无法替换内容。原因讲完了,下面都是动手节了。

      首先将ParseWord07类中的parseThisTable方法 修改成以下代码。

     private void parseThisTable(XWPFTable table, Map<String, Object> map) throws Exception {
            for (int i = 0; i < table.getNumberOfRows(); ++i) {
                XWPFTableRow row = table.getRow(i);
                List<XWPFTableCell> cells = row.getTableCells();
    
                //此部分为修改的源代码
                //作用 用于识别word中表格非第一列的循环语法
                Object listobj = null;
                int col = 0;
                for (XWPFTableCell cell : cells) {
                    listobj = this.checkThisTableIsNeedIterator(cell, map);
                    if (listobj != null) {
                        break;
                    }
                    col++;
                }
                if (listobj == null) {
                    this.parseThisRow(cells, map);
                } else if (listobj instanceof ExcelListEntity) {
                    (new ExcelEntityParse()).parseNextRowAndAddRow(table, i, (ExcelListEntity) listobj);
                    i = i + ((ExcelListEntity) listobj).getList().size() - 1;
                } else {
                    LcExcelMapParse.parseNextRowAndAddRow(table, i, (List) listobj, col);
                    i = i + ((List) listobj).size() - 1;
                }
            }
    
        }
    

      再找到ExcelMapParse类中的parseNextRowAndAddRow方法,修改成以下代码

    
        public static void parseNextRowAndAddRow(XWPFTable table, int index, List<Object> list, int col) throws Exception {
            XWPFTableRow currentRow = table.getRow(index);
            String[] params = parseCurrentRowGetParams(currentRow);
            String listname = params[col];
            boolean isCreate = !listname.contains("!fe:");
            listname = listname.replace("!fe:", "").replace("$fe:", "").replace("fe:", "").replace("{{", "");
            String[] keys = listname.replaceAll("\\s{1,}", " ").trim().split(" ");
            params[col] = keys[1];
            List<XWPFTableCell> tempCellList = new ArrayList();
            tempCellList.addAll(table.getRow(index).getTableCells());
    //        int cellIndex = false;
            Map<String, Object> tempMap = Maps.newHashMap();
            LOGGER.debug("start for each data list :{}", list.size());
            Iterator var11 = list.iterator();
    
            while (var11.hasNext()) {
                Object obj = var11.next();
                currentRow = isCreate ? table.insertNewTableRow(index++) : table.getRow(index++);
                tempMap.put("t", obj);
    
                //如果有合并单元格情况,会导致params越界,这里需要补齐
                String[] paramsNew = (String[]) ArrayUtils.clone(params);
                if (params.length < currentRow.getTableCells().size()) {
                    for (int i = 0; i < currentRow.getTableCells().size() - params.length; i++) {
                        paramsNew = (String[]) ArrayUtils.add(paramsNew, 0, "placeholderLc_" + i);
                    }
                }
    
                String val;
                int cellIndex;
                for (cellIndex = 0; cellIndex < currentRow.getTableCells().size(); ++cellIndex) {
                    val = PoiElUtil.eval(paramsNew[cellIndex], tempMap).toString();
                    //源代码的bug 此方法无法删除单元格中的内容
                    //currentRow.getTableCells().get(cellIndex).setText("");
                    //使用此方法清空单元格内容
                    if (!Strings.isNullOrEmpty(val)) {
                        currentRow.getTableCells().get(cellIndex).getParagraphs().forEach(p -> p.getRuns().forEach(r -> r.setText("", 0)));
                    }
                    PoiWordStyleUtil.copyCellAndSetValue(cellIndex >= tempCellList.size() ? tempCellList.get(tempCellList.size() - 1) : tempCellList.get(cellIndex)
                            , currentRow.getTableCells().get(cellIndex), val);
                }
    
                while (cellIndex < paramsNew.length) {
                    val = PoiElUtil.eval(paramsNew[cellIndex], tempMap).toString();
                    PoiWordStyleUtil.copyCellAndSetValue((XWPFTableCell) tempCellList.get(cellIndex), currentRow.createCell(), val);
                    ++cellIndex;
                }
            }
    
            table.removeRow(index);
        }
    

      至此源代码全部修改完毕,这次没有解释太多,因为估计真有遇到需要修改源代码的时候,大部分人选择的是放弃使用这个第三方类库,修改源码也确实有一定难度,所以这个基本用于记录自己解决问题的整个流程,方便以后看得时候能快速想起来。

    展开全文
  • 1.目的:项目中遇到一个word导出的功能,需要在固定模板里把一些字段替换掉,然后返回给前端,然后就实现 2.准备文件 a.将word文档需要填充的字段用占位字段替换${key},和map的key对应 b.将word打开然后另存为...

    1.目的:项目中遇到一个word导出的功能,需要在固定的模板里把一些字段替换掉,然后返回给前端,然后就实现
    2.准备文件
    a.将word文档需要填充的字段用占位字段替换${key},和map的key对应
    在这里插入图片描述
    b.将word打开然后另存为xml文件,直接修改文件的后缀xml改为ftl,这样就生成想要的模板文件啦。
    c.我是放入项目文件下的
    在这里插入图片描述
    3.代码实现

    package com.example.demo.service.impl;
    
    import com.example.demo.service.WordService;
    import freemarker.template.Configuration;
    import freemarker.template.Template;
    import freemarker.template.Version;
    import org.apache.tomcat.util.codec.binary.Base64;
    import org.springframework.stereotype.Service;
    
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServletResponse;
    import java.io.*;
    import java.util.HashMap;
    import java.util.Map;
    
    @Service
    public class WordServiceImpl implements WordService {
        @Override
        public String changWord(String id, HttpServletResponse httpServletResponse) {
            //用于区别不同请求的
            if (id == null) {
                id=String.valueOf(System.currentTimeMillis());
            }
            Map<String,Object> dataMap = new HashMap<String, Object>();
            try {
                //模板的参数,其中map各个字段必须要存在key,value可以为空
                dataMap.put("date","2020-06-07");
                dataMap.put("money","200");
                dataMap.put("author","taotao");
                dataMap.put("tie","测试文件");
                Configuration configuration = new Configuration(new Version("2.3.0"));
                configuration.setDefaultEncoding("utf-8");
                dataMap.put("data", "test");
                configuration.setDirectoryForTemplateLoading(new File("./config"));
                //输出文档路径及名称
                File outFile = new File("./config/test"+id+".doc");
                //以utf-8的编码读取ftl文件,模板的位置
                Template template = configuration.getTemplate("test.ftl", "utf-8");
                Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"), 10240);
                template.process(dataMap, out);
                out.close();
                try {
                    FileInputStream fileInputStream = new FileInputStream(outFile);
                    httpServletResponse.setCharacterEncoding("UTF-8");
    
                    httpServletResponse.setHeader("Content-Disposition","attachment;filename=test"+id+".doc");
                    ServletOutputStream outputStream = httpServletResponse.getOutputStream();
                    byte[] data= new byte[1024];
                    //浏览器直接下载
                    int len;
                    while ((len=fileInputStream.read(data))>0){
                        outputStream.write(data,0,len);
                    }
                    outputStream.close();
                    fileInputStream.close();
                    //字符流返回给前端
                    StringBuffer stringBuffer = new StringBuffer();
                    for (int i = 0; i <data.length ; i++) {
                        stringBuffer.append((char)data[i]);
                    }
                    //base64加密返回给前段
                    String s = new Base64().encodeAsString(data);
                    //用于文件删除
                    outFile.delete();
                        //字节流返回
               //     return new String(stringBuffer);
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    
            return null;
        }
    }
    
    

    4.测试
    a.在浏览器中输出
    localhost:8090/word/test?id=32312就可以看到下载的文件了。
    b.对于postman来说张这样

    在这里插入图片描述

    然后点击download就行。
    c.对于字符流返回的是一个string串然后你可以
    在这里插入图片描述
    点击download,他会默认存一个txt把它另存为doc,然后效果是一模一样的。

    总结:word输出比较简单主要是生成模板,然后是要输出直接下载的还是base加密的还是字符串就看自己了,在实际操作中word页数比较多,然后输出base64的字段较多,此时vue解密时,ie竟然不能获取全字符串,而chorm是可以的,这个前端问题还没解决,所以我目前用的是字符串而非base64的方式。

    方案二:
    直接通过poi进行字段的替换,为啥这样做呢,因为在实际的使用中竟然还有人在使用低版本的wps,你敢信???帮政府做的word居然乱码,但是在我们这试都好好的,就开始排查问题呀。
    大概用了一整天查这个问题,首先复现问题,问他们要了一份他们的版本(版本号:8.1.0.3000),然后我们的是(9.1.0.5024),只能把本地的wps卸载了然后再装他们版本的wps。我敲真的乱码,打开张这样和返回结果一样的,
    在这里插入图片描述

    为啥呢,再看下wps的升级,搜索xml,我去竟然在9.1.0.4940的版本新增了对xml框架的支持,我敲就是这之前的都不行啊。ps:word都可以就是低版本的wps妖路啊。
    哎,看来xml作为模板的路是不行的了,没法只能另起炉灶了。
    2.用啥方法捏?
    最终只能用比较笨的方法了,poi来操作doc对象然后对字符串进行替换。
    1.创建模板doc文件
    在这里插入图片描述

    2.引入依赖

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

    3.代码实现

     public String getWordByDoc(String id, HttpServletResponse httpServletResponse) {
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("aa", "123");
            dataMap.put("bb", "还不错");
            dataMap.put("cc", 1);
            dataMap.put("date", "2020-07-27");
            try {
                //模板文件
                FileInputStream fileInputStream = new FileInputStream("./config/1.doc");
                HWPFDocument hwpfDocument = new HWPFDocument(fileInputStream);
                Range range = hwpfDocument.getRange();
                for (Map.Entry<String, Object> entry : dataMap.entrySet()
                ) {
                    range.replaceText("${" + entry.getKey() + "}", entry.getValue().toString());
                }
                //生成的文件
                File file = new File("./config/newDoc.doc");
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                hwpfDocument.write(byteArrayOutputStream);
                FileOutputStream fileOutputStream = new FileOutputStream(file);
                fileOutputStream.write(byteArrayOutputStream.toByteArray());
                fileInputStream.close();
                fileOutputStream.close();
                byte[] bytes = FileUtils.readFileToByteArray(file);
                return new String(bytes);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return null;
        }
    

    4.测试
    允许代码生成了doc
    在这里插入图片描述
    ok,大功告成。
    在这里插入图片描述

    两种方案的对比
    1.flt方法比较智能,生成的是xml;doc能支持低版本的wps,但是用的是遍历不太行。

    展开全文
  • 请叫我小C2016-01-12 11:58:51 利用java通过freemarker模板文件...1.把需要生成固定格式的文件保存为word文档(图1) 2.把word另存为xml格式,并且格式化,好修改里面的东西 3.修改好后保存,格式改为ftl模板 ...

    请叫我小C2016-01-12 11:58:51

    利用java通过freemarker模板文件生成带格式的word文档

    最近做了个小项目,需要在线生成起诉状且带格式。做了个小工具分享给大家,也借鉴了网络上的东西,废话不多说,上干货

    1.把需要生成固定格式的文件保存为word文档(图1)

    2.把word另存为xml格式,并且格式化,好修改里面的东西

    3.修改好后保存,格式改为ftl模板

    下面代码:

    public final static String createWord(HttpServletResponse response,Map dataMap, String templateName, String fileName) {
            String result = "系统提示:Word文件导出成功!";
            try {
                OutputStream os = response.getOutputStream();
                //设置头部文件生成格式为微软word
                response.reset();
                response.setHeader("Content-disposition", "attachment; filename=" + new String(fileName.getBytes("GB2312"), "ISO8859-1"));
                response.setContentType("application/msword");
    
                Configuration configuration = new Configuration();
                configuration.setDefaultEncoding("UTF-8");
                configuration.setClassForTemplateLoading(WordUtil.class, "/");//这里是指放在classes下
                // 获取模板
                Template template = configuration.getTemplate(templateName);
                // 将模板和数据模型合并生成文件
                Writer out = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
                template.process(dataMap, out);
                // 关闭流
                out.flush();
                out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }
    
    
    
    public static void main(String[] args) throws IOException, TemplateException {
            String s = "{\"plaintiff\": [{ \"pUserName\": \"张三\", \"pUserSex\": \"男\", \"pAgeIcard\": \"44\",\"pNation\": \"汉族\",\"pAddress\": \"江苏\"},{\"pUserName\": \"得到\",\"pUserSex\": \"男\",\"pAgeIcard\": \"54\",\"pNation\": \"汉族\",\"pAddress\": \"湖南\"}],"
                    + "\"accusedMan\": [{ \"accusedManName\": \"张三\", \"accusedManAddress\": \"男\", \"accusedManPeson\": \"张三\",\"accusedManJob\": \"班长\"}],\"signData\":{\"courtName\":\"北京\",\"copyNumber\":\"1\",\"suitor\":\"张三\"},\"lawsuitReest\":\"ddd\",\"reasonsContent\":\"dfdf\"}";
            Map dataMap = new HashMap();
            Map complaintMap = JsonUtil.getJsonToObject(s, Map.class);
            List<Map> plaintiffList = new ArrayList<Map>();
            List<Map> accusedManList = new ArrayList<Map>();
            for (Object key : complaintMap.keySet()) {
                Object contentJson = complaintMap.get(key);
                if (key.equals("plaintiff")) {
                    plaintiffList.addAll(JsonUtil.queryJsonToList(contentJson.toString(), Map.class));
                } else if (key.equals("accusedman")) {
                    accusedManList.addAll(JsonUtil.queryJsonToList(contentJson.toString(), Map.class));
                } else {
                    dataMap.put(key, contentJson);
                }
            }
            dataMap.put("plaintiff", plaintiffList);
            dataMap.put("accusedman", accusedManList);
            Configuration configuration = new Configuration();
            configuration.setDefaultEncoding("UTF-8");
            configuration.setClassForTemplateLoading(WordUtil.class, "/");
            // 获取模板
            Template template = configuration.getTemplate("qsz.ftl");
            // 输出文件
            File outFile = new File("d:/" + File.separator + "cc.doc");
            // 如果输出目标文件夹不存在,则创建
            if (!outFile.getParentFile().exists()) {
                outFile.getParentFile().mkdirs();
            }
            // 将模板和数据模型合并生成文件
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "UTF-8"));
            template.process(dataMap, out);
            // 关闭流
            out.flush();
            out.close();
        }

     

    public class JsonUtil {
    
    	/**
    	 * 从一个JSON 对象字符格式中得到一个java对象
    	 * 
    	 * @param jsonString JSON 对象字符
    	 * @param pojoCalss 对象class * 
    	 * @return 返回java对象
    	 */
    	public static Object getObject4JsonString(String jsonString, Class<?> pojoCalss) {
    		Object pojo;
    		JSONObject jsonObject = JSONObject.parseObject(jsonString);
    		pojo = JSONObject.toJavaObject(jsonObject, pojoCalss);
    		return pojo;
    	}
    
    	/**
    	 * 从json HASH表达式中获取一个map,改map支持嵌套功能
    	 * 
    	 * @param jsonString json HASH表达式
    	 * @return 返回map数组
    	 */
    	public static Map<String,Object> getMap4Json(String jsonString) {
    		JSONObject jsonObject = JSONObject.parseObject(jsonString);
    		Iterator<String> keyIter = jsonObject.keySet().iterator();
    		String key;
    		Object value;
    		Map<String,Object> valueMap = new HashMap<String,Object>();
    
    		while (keyIter.hasNext()) {
    			key = (String) keyIter.next();
    			value = jsonObject.get(key);
    			valueMap.put(key, value);
    		}
    		return valueMap;
    	}
    
    	/**
    	 * 从json数组中得到相应java数组
    	 * 
    	 * @param jsonString json字符串
    	 * @return 返回java数组
    	 */
    	public static Object[] getObjectArray4Json(String jsonString) {
    		JSONArray jsonArray = JSONArray.parseArray(jsonString);
    		return jsonArray.toArray();
    	}
    
    	/**
    	 * 将一个对象转换为JSON字符串
    	 * @param obj 对象
    	 * @return 返回json字符串
    	 */
    	public static String getObjectToJsonObject(Object obj){
    		return JSON.toJSON(obj).toString();
    	}	
    	
    
    	/**
    	 * 从json数组中解析出java字符串数组
    	 * 
    	 * @param jsonString json字符串
    	 * @return 返回java字符串数字
    	 */
    	public static String[] getStringArray4Json(String jsonString) {
    		JSONArray jsonArray = JSONArray.parseArray(jsonString);
    		String[] stringArray = new String[jsonArray.size()];
    		
    		for (int i = 0; i < jsonArray.size(); i++) {
    			stringArray[i] = jsonArray.get(i).toString();
    		}
    
    		return stringArray;
    	}
    
    	/**
    	 * 将一个JSON数据转换为对应的JAVA对象</br>
    	 * JSON数据中键的名称必须和对应JAVA对象中bean字段的名称一致</br>
    	 * @param <T> java对象值
    	 * @param jsonString JSON 对象字符
    	 * @param cls 对象class * 
    	 * @return 返回java对象
    	 */
    	public static <T> T getJsonToObject(String jsonString, Class<T> cls) {
    		return JSONObject.parseObject(jsonString,cls);
    	}
    	
    	/**
    	 * 从json对象集合表达式中得到一个java对象集合</br>
    	 * JSON数据中键的名称必须和对应JAVA对象中bean字段的名称一致</br>
    	 * 
    	 * @param <T> 对象值
    	 * @param jsonString json字符串
    	 * @param cls  JAVA Bean对象
    	 * @return JAVA bean对象集合list
    	 */
    	public static <T> List<T> queryJsonToList(String jsonString,Class<T> cls) {
    		List<T> list = JSONArray.parseArray(jsonString,cls);
    		return list;
    	}
    	
    }

    利用java通过freemarker模板文件生成带格式的word文档

     

    还有一个ftl的模板文件,可以自己写个,也可以找我要

    展开全文
  • java POI对word中的表格动态插入固定数据,以及插入不具体的数据 遇到个项目本来是用Execl导出的,相对简单,客户要求用Word导出,并按照他们给的模板进行导出; 从网上百度了一下,然后自己修改下,实现了对word中...

    java POI对word中的表格动态插入固定数据,以及插入不具体的数据

    遇到个项目本来是用Execl导出的,相对简单,客户要求用Word导出,并按照他们给的模板进行导出;
    从网上百度了一下,然后自己修改下,实现了对word中的同一张表格同时进行通过key替换操作,以及从特定的行开始插入数据,根据是需要插入的数据自动增加行等;下面直接上主要代码,都有注释。

    maven依赖包引入

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

    工具类

    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Set;
    
    import org.apache.poi.POIXMLDocument;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    import org.apache.poi.xwpf.usermodel.XWPFParagraph;
    import org.apache.poi.xwpf.usermodel.XWPFRun;
    import org.apache.poi.xwpf.usermodel.XWPFTable;
    import org.apache.poi.xwpf.usermodel.XWPFTableCell;
    import org.apache.poi.xwpf.usermodel.XWPFTableRow;
    
    public class WordUtil {
    	
    	
        /**
         * 根据模板生成新word文档
         * 对表格是进行替换以及插入
         * @param inputUrl 模板存放地址
         * @param outPutUrl 新文档存放地址
         * @param textMap 需要替换的信息集合 
         * @param tableList 需要插入的表格信息集合
         * @return 成功返回true,失败返回false
         */
        public static boolean changWord(String inputUrl, String outputUrl,
                Map<String, String> textMap, List<String[]> tableList) {
            //模板转换默认成功
            boolean changeFlag = true;
            try {
                //获取docx解析对象
                XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
                //解析替换文本段落对象
                WordUtil.changeText(document, textMap);
                //解析替换表格对象
                WordUtil.changeTable(document, textMap, tableList);
                
                //生成新的word
                File file = new File(outputUrl);
                FileOutputStream stream = new FileOutputStream(file);
                document.write(stream);
                stream.close();
            } catch (IOException e) {
                e.printStackTrace();
                changeFlag = false;
            }
            return changeFlag;
    
        }
    
        /**
         * 替换段落文本
         * @param document docx解析对象
         * @param textMap 需要替换的信息集合
         */
        public static void changeText(XWPFDocument document, Map<String, String> textMap){
            //获取段落集合
            List<XWPFParagraph> paragraphs = document.getParagraphs();
            
            for (XWPFParagraph paragraph : paragraphs) {
                //判断此段落时候需要进行替换
                String text = paragraph.getText();
                if(checkText(text)){
                    List<XWPFRun> runs = paragraph.getRuns();
                    for (XWPFRun run : runs) {
                        //替换模板原来位置
                        run.setText(changeValue(run.toString(), textMap),0);
                    }
                }
            }
            
        }
        
        /**
         * 替换表格对象方法
         * @param document docx解析对象
         * @param textMap 需要替换的信息集合
         * @param tableList 需要插入的表格信息集合
         */
        public static void changeTable(XWPFDocument document, Map<String, String> textMap,
                List<String[]> tableList){
            //获取表格对象集合
            List<XWPFTable> tables = document.getTables();
            //获取第一个表格   根据实际模板情况 决定去第几个word中的表格
            XWPFTable table = tables.get(0);
            
            //表格中的内容替换
            List<XWPFTableRow> rows = table.getRows();
            eachTable(rows, textMap);//遍历表格,并替换模板
            
            //向特定位置 行插入数据
            insertTable(table, tableList);
        }
        
        /**
         * 遍历表格
         * @param rows 表格行对象
         * @param textMap 需要替换的信息集合
         */
        public static void eachTable(List<XWPFTableRow> rows ,Map<String, String> textMap){
            for (XWPFTableRow row : rows) {
                List<XWPFTableCell> cells = row.getTableCells();
                for (XWPFTableCell cell : cells) {
                    //判断单元格是否需要替换
                    if(checkText(cell.getText())){
                        List<XWPFParagraph> paragraphs = cell.getParagraphs();
                        for (XWPFParagraph paragraph : paragraphs) {
                            List<XWPFRun> runs = paragraph.getRuns();
                            for (XWPFRun run : runs) {
                                run.setText(changeValue(run.toString(), textMap),0);
                            }
                        }
                    }
                }
            }
        }
        
        /**
         * 为表格插入数据,行数不够添加新行
         * @param table 需要插入数据的表格
         * @param tableList 插入数据集合
         */
        public static void insertTable(XWPFTable table, List<String[]> tableList){
            //创建行,根据需要插入的数据添加新行,不处理表头
        	//判断需要插入的数量
        	if (tableList.size() > 5) {//我的模板预留了五行
        		for (int i=0;i<tableList.size()-4;i++) {
        			insertRow(table,10,14);
        		}
    		} 
            //遍历表格插入数据
            List<XWPFTableRow> rows = table.getRows();
            for(int i = 9; i < tableList.size() + 9; i++){
                XWPFTableRow newRow = table.getRow(i);
                List<XWPFTableCell> cells = newRow.getTableCells();
                for(int j = 0; j < cells.size(); j++){
                    XWPFTableCell cell = cells.get(j);
                    cell.setText(tableList.get(i-9)[j]);
                }
            }
            
        }
        
        /**
         * 判断文本中时候包含$
         * @param text 文本
         * @return 包含返回true,不包含返回false
         */
        public static boolean checkText(String text){
            boolean check  =  false;
            if(text.indexOf("$")!= -1){
                check = true;
            }
            return check;
            
        }
    	/**
    	 * insertRow 在word表格中指定位置插入一行,并将某一行的样式复制到新增行
    	 * @param copyrowIndex 需要复制的行位置
    	 * @param newrowIndex 需要新增一行的位置
    	 * */
    	public static void insertRow(XWPFTable table, int copyrowIndex, int newrowIndex) {
    		// 在表格中指定的位置新增一行
    		XWPFTableRow targetRow = table.insertNewTableRow(newrowIndex);
    		// 获取需要复制行对象
    		XWPFTableRow copyRow = table.getRow(copyrowIndex);
    		//复制行对象
    		targetRow.getCtRow().setTrPr(copyRow.getCtRow().getTrPr());
    		//或许需要复制的行的列
    		List<XWPFTableCell> copyCells = copyRow.getTableCells();
    		//复制列对象
    		XWPFTableCell targetCell = null;
    		for (int i = 0; i < copyCells.size(); i++) {
    			XWPFTableCell copyCell = copyCells.get(i);
    			targetCell = targetRow.addNewTableCell();
    			targetCell.getCTTc().setTcPr(copyCell.getCTTc().getTcPr());
    			if (copyCell.getParagraphs() != null && copyCell.getParagraphs().size() > 0) {
    				targetCell.getParagraphs().get(0).getCTP().setPPr(copyCell.getParagraphs().get(0).getCTP().getPPr());
    				if (copyCell.getParagraphs().get(0).getRuns() != null
    						&& copyCell.getParagraphs().get(0).getRuns().size() > 0) {
    					XWPFRun cellR = targetCell.getParagraphs().get(0).createRun();
    					cellR.setBold(copyCell.getParagraphs().get(0).getRuns().get(0).isBold());
    				} 
    			} 
    		}
    		
    	}
        /**
         * 匹配传入信息集合与模板
         * @param value 模板需要替换的区域
         * @param textMap 传入信息集合
         * @return 模板需要替换区域信息集合对应值
         */
        public static String changeValue(String value, Map<String, String> textMap){
            Set<Entry<String, String>> textSets = textMap.entrySet();
            for (Entry<String, String> textSet : textSets) {
                //匹配模板与替换值 格式${key}
                String key = "${"+textSet.getKey()+"}";
                if(value.indexOf(key)!= -1){
                    value = textSet.getValue();
                }
            }
            //模板未匹配到区域替换为空
            if(checkText(value)){
                value = "";
            }
            return value;
        }
        
        
        
        
        public static void main(String[] args) {
        	//模板文件地址
            String inputUrl = "E:\\beian\\demo1.docx";
            //新生产的模板文件
            String outputUrl = "E:\\beian\\demo3.docx";
            
            Map<String, String> testMap = new HashMap<String, String>();
            testMap.put("type0", "注销");
            testMap.put("application", "票据系统");
            testMap.put("dept", "信息中心");
            testMap.put("unit", "111111");
            testMap.put("type1", "2");
            testMap.put("type2", "3");
            testMap.put("type3", "4");
            testMap.put("type4", "5");
            
            List<String[]> testList = new ArrayList<String[]>();
            testList.add(new String[]{"1","Q1","W1","E1","R1","T1"});
            testList.add(new String[]{"2","Q2","W2","E2","R2","T2"});
            testList.add(new String[]{"3","Q3","W3","E3","R3","T3"});
            testList.add(new String[]{"4","Q4","W4","E4","R4","T4"});
            testList.add(new String[]{"5","Q5","W5","E5","R5","T5"});
            testList.add(new String[]{"6","Q6","W6","E6","R6","T6"});
            testList.add(new String[]{"7","Q7","W7","E7","R7","T7"});
            
            WordUtil.changWord(inputUrl, outputUrl, testMap, testList);
        }
    
    }
    
    

    模板
    在这里插入图片描述

    ${type0}中的内容 为要替换的部分,用text写,然后复制进来, 不然可能无法替换,直接在word中写,会可能被认为一整个对象,无法替换成功

    结果:

    在这里插入图片描述

    参考了这两位大佬的
    https://www.jianshu.com/p/6603b1ea3ad1
    https://blog.csdn.net/qq_36880602/article/details/105750590

    展开全文
  • 此工具输入Word及输出Excel的模板格式为固定格式,在源码中提供Word模板文件,用于参考。 可根据需要转换的Word文档,通过对转换格式部分代码修改,以及Excel输出格式部分代码的修改,可调整为自己想要的输出格式,...
  • 开发中偶尔会有固定模板导出word的需求,常见的导出通常通过直接修改xml或者通过工具库代码调整样式输出,这些方式开发困难并且不利于后期维护。 一些有规则的文档需要人工填写,费时费力,此时配置数据库做模板渲染...
  • 用freemarker生成word文档,并插入图片

    千次阅读 2020-07-29 10:16:58
    新建一个word文档,将需要应用的格式固定修改好格式后,将word文档保存为XML格式的文件 例: 将word保存为xml格式 将XML中base64格式的图片信息删除掉,改为占位符,如:${image} 如果需要在模板中插入不定数量的...
  • 有时候我们需要按照某种规则生成一种固定模板word报告,python能够很好的完成这项工作。本文通过一个小示例说明一下如何通过Python实现自动生成word报告。 首先我们需要有一个word报告模板,模板中内置了一些需要...
  • 反复要做的固定操作固化为“模板”“套路”。 碰到异常情况知道准确高效的解决。 01 样式的标题 1.1 设置标题 开始选项卡中样式菜单选择设置标题,此后对于标题修改可以直接在此修改。既可以整体修改,也可以单个...
  • 一、创建word文档模板 生成想要生成的word样式,保存为xml文件 2.修改为ftl文件,并用编辑器打开,将需要填入的地方用占位符表示 3.需要一些语法操作的地方,要使用ftl语法,具体参考ftl基础语法 这次用到了...
  • word使用技巧大全

    热门讨论 2011-03-18 20:37:53
    三十六、自定义模板 自动生成指定的Word文件名 68 三十七、从头到脚完美:Word文档布局 69 三十八、文件夹的内容生成文件 70 三十九、参考文献的标注 70 1、如何在word文档中加进参考文献的标注 70 2、省时省力——...
  • 有时候,我们需要在固定word模板里面插入图片,图片却无法完整显示。 首先,考虑图片本身的格式,比如改成嵌入型/四周环绕型之类的,看是否显示完全。 然后,查看插入图片的“段落”格式,看一下是否为“固定值” ...
  • freemarker生成复杂word

    热门讨论 2012-04-24 18:32:55
    在Web应用中,有时需要按照固定模板将数据导出到Word,如流程审批单,在流程处理完成后将处理过程按照流程单的要求导出,有时程序中需要实现生成标准Word文档,要求能够打印,并且保持页面样式不变,常见的方案有...
  • 因为公司的质检报告有固定的的模板,使用Qt很方便的实现生成Word版本,所以用的方法是先生成Word格式的质检报告然后格式进行转换. 一个重要的问题就是格式转换需要很长的时间,在转换期间软件会处于冻结转态.因此需要...
  • C、文档关闭前,自动读取户修改固定位置的文本到vb.net中。D、不管用户是否选择保存Word文档,都自动取得需要的文本。E、用户可以通过vb.net关闭Word,也可以手工关闭Word。 (1)选择vb.net项目,
  • 修改导出的ftl模板 在table中加入样式, 设置固定宽度,设置换行 CSS:width="800px" style="table-layout:fixed; word-wrap:break-word; word-break:break-all" th加入样式style="text-align: center;width:10%;
  • writewordrev1.zip

    2021-03-15 12:26:11
    QAxObject操作word生成模板的详细例程: 可用于生成各种表单、出库入库单、测试单等等。 包括内容有: 1、设置页眉页脚、页眉页脚距顶端及底端的距离、页面设置、页边距设置。 2、插入表格、添加行、表格单元格的...
  • Cmsez v1.03 beta 1 免费版

    2021-03-24 16:03:25
    只需简单的在后台进行修改页面模板,就可以完成网站的改版。  7. 通用灵活的模板设计方法。系统采用流行的“标签”式设计模板方法,如果你用过其他生成HTML功能的系统,设计模板将非常容易上手。与众不同的是,...
  • 只需简单的在后台进行修改页面模板,就可以完成网站的改版。  7. 通用灵活的模板设计方法。系统采用流行的“标签”式设计模板方法,如果你用过其他生成HTML功能的系统,设计模板将非常容易上手。与众不同的是,...
  • 绿叶OA协同办公软件

    2009-06-06 15:58:24
    4)流程模板模板主要用于固定流程,按照应用类别进行流程主题、路径、内容、表单附件存储管理,将企业各流程表单与路径全部固定起来,规范与统一流程。用户可使用流程模板,发起已经建立好的流程模板,包括行政、...
  • 企业网站中英文

    2012-11-30 20:30:17
    所有信息内容在线完成编辑,就象WORD一样简单、可视而又功能完善,几乎能完成你想要的所有效果。中文,英文,繁体三语使公司,企业网站,最大范围被人了解,占得网络市场.公司企业网站管理系统中英繁正式版源码有宣传,...
  • 只需简单的在后台进行修改页面模板,就可以完成网站的改版。 5.通用灵活的模板设计方法。系统采用流行的“标签”式设计模板方法,如果你用过其他生成HTML功能的系统,设计模板将非常容易上手。与6.众不同的是,...
  • 只需简单的在后台进行修改页面模板,就可以完成网站的改版。通用灵活的模板设计方法。系统采用流行的“标签”式设计模板方法,如果你用过其他生成HTML功能的系统,设计模板将非常容易上手。与众不同的是,系统提供了...
  • 双击报表模板文件(扩展名为mb的文件)即可进入报表模板修改界面(此时如果打印预览报表模板不会有数据,因为这样修改报表模板时是没有设置数据源的)。 6、解决了原EasyReport报表组件由于资源释放不及时,在多次...
  • php OA 源码 办公自动化源码

    热门讨论 2010-10-29 00:51:15
    审批的流程即可以采用固定流程,一个模板梆定一个流程的方式,也可以设定允许在流转过程中自定义流程或修改已设定的流程,流程支持直流、分流、并流、条件分支、流程嵌套以及各种协办、联办等复杂流程。 在审批中,...
  • smarty手册.chm

    2012-05-03 13:49:27
    $config_fix_newlines [配置固定换行符变量] $default_template_handler_func [默认模板处理函数变量] $php_handling [php处理变量] $security [安全变量] $secure_dir [安全目录变量] $security_settings ...
  • Smarty中文手册 chm版

    2010-05-21 15:01:58
    $config_fix_newlines [配置固定换行符变量] $default_template_handler_func [默认模板处理函数变量] $php_handling [php处理变量] $security [安全变量] $secure_dir [安全目录变量] $security_settings ...
  • 可设置Excel或Word打印模板,只需Click一下,数据即可填入模板中的指定位置,生成派工单、销售合同、审批表等文档,与纸面作业无缝衔接。 具有到期提醒功能,可设置提醒时机、收信人、提醒内容、提醒频度,系统会...
  • 系统提供多种模板满足绝大多数用户打印需求 11、只要熟悉EXCEL或WPS表格的用户就可以自定义满足各自需要的财务报表 12、轻轻松松就可以修改以前月份的凭证,不需要红字冲销 13、可以生成草稿凭证,暂时保存未录入...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 132
精华内容 52
关键字:

word固定模板修改