精华内容
下载资源
问答
  • Java Poi word 插入图片并添加边框 //得到Picture的Base64编码 Base64Picture p1; //打开Word文件 Resource resource = new ClassPathResource("doc/ProvinceCollectionReport.docx"); XWPFDocument document = new ...

    Java Poi word 插入图片并添加边框

    //得到Picture的Base64编码
    Base64Picture p1;
    //打开Word文件
    Resource resource = new ClassPathResource("doc/ProvinceCollectionReport.docx");
    XWPFDocument document = new XWPFDocument(resource.getInputStream());
    //遍历段落
    List<XWPFParagraph> paragraphs = document.getParagraphs();
            for (XWPFParagraph paragraph : paragraphs) {
                //判断此段落是否需要进行替换 我在word文件中用$(Picture来记录图片要存放的未知)
                if (paragraph.getText().contains("$(")) {
                    //遍历每个run
                    List<XWPFRun> runs = paragraph.getRuns();
                    for (XWPFRun run : runs) {
                        //找到要替换的run
                        if (run.text().contains("$(Picture)")) {
                            //设置单倍行距,行距为固定值时图片显示不完全
                            paragraph.setSpacingBetween(1);
                            //设置居中paragraph.setAlignment(ParagraphAlignment.CENTER);
                            //清空文字
                            run.setText("", 0);
                            //Base64解码
                            Base64Picture picture = pictures.get(pictureIndex);
                            String base64String = picture.getBase64String();
                            String head = base64String.substring(base64String.indexOf('/') + 1, base64String.indexOf(';'));
                            byte[] decoderBytes = decoder.decode(base64String.substring(base64String.indexOf(',') + 1));
                            //插入图片
                            InputStream inputStream = new ByteArrayInputStream(decoderBytes);
                            //为图片设置黑色边框
                            XWPFPicture xwpfPicture = run.addPicture(inputStream, getPictureType(head), picture.getFileName(), Units.toEMU(picture.getWidth()), Units.toEMU(picture.getHeight()));
                            xwpfPicture.getCTPicture().getSpPr().addNewLn().addNewSolidFill().addNewSchemeClr().setVal(STSchemeColorVal.Enum.forString("tx1"));
                            inputStream.close();
                        }
                    }
                }
            }
    
    
    

    至于我是怎么发现的,其实也很简单。Word可以转换为xml格式存储,新建一个有带边框图片和一个不带边框图片的word文件,另存为xml格式,用idea打开可看到xml格式化文件,找到图片位置,类似下图:

    不带边框的格式:
    在这里插入图片描述

    带边框的格式:
    在这里插入图片描述
    对比可看出带边框的图片多的是

    <a:ln>
    	<a:solidFill>
    		<a:schemeClr val="tx1"/>
    	</a:solidFill>
    </a:ln>
    

    因此,通过以下代码即可添加边框

    //插入图片并得到插入的图片对象
    XWPFPicture xwpfPicture = run.addPicture(inputStream, getPictureType(head), picture.getFileName(), Units.toEMU(picture.getWidth()), Units.toEMU(picture.getHeight()));
    //为图片添加边框
    xwpfPicture.getCTPicture().getSpPr().addNewLn().addNewSolidFill().addNewSchemeClr().setVal(STSchemeColorVal.Enum.forString("tx1"));
    

    其他属性若查不到资料或文档都可以用这种方法。

    展开全文
  • 完整的Java project demo,包含所需的所有jar包,示例文件,使用说明等
  • POIWord的操作,特别是针对生成报告模板时,向word中写入文本和图片
  • Java Poi流根据Word模板插入相应的文本、表格和图片,并生成新的Word报告。文档提供相应的jar包和Word模板文件,表格支持动态添加数据,插入图片支持多种格式!
  • Java Poi 根据文字内容 插入 word 图片

    万次阅读 2018-11-14 18:45:46
    ,则获取后面的图片的名字,然后利用POI的XWPFRun.addPicture(url,像素…)方法将图片添加到word里,然后将原有的文字清除掉。 注意:图片要放在表格的单元格里,最后单元格里的文本会被清除掉,只留下图片...

    需求描述

    如下图,我需要在word里根据一个图片的名字,将名字替换成该图片(公章)
    在这里插入图片描述

    思路:

    用POI遍历每一个表格里的每一行的每一个单元格,如果遇到我自己定义的"&章",则获取后面的图片的名字,然后利用POI的XWPFRun.addPicture(url,像素…)方法将图片添加到word里,然后将原有的文字清除掉。
    注意:图片要放在表格的单元格里,最后单元格里的文本会被清除掉,只留下图片

    简单生成图片和文字的代码:

    注: 我的代码比较复杂,因为需求很复杂,如果你只需要简单生成下图片,可以参考这个
    参考:https://stackoverflow.com/questions/26764889/how-to-insert-a-image-in-word-document-with-apache-poi

    XWPFDocument doc = new XWPFDocument();
    
        XWPFParagraph title = doc.createParagraph();    
        XWPFRun run = title.createRun();
        run.setText("Fig.1 A Natural Scene");
        run.setBold(true);
        title.setAlignment(ParagraphAlignment.CENTER);
    
        String imgFile = "encabezado.jpg"
        FileInputStream is = new FileInputStream(imgFile);
        run.addBreak();
        run.addPicture(is, XWPFDocument.PICTURE_TYPE_JPEG, imgFile, Units.toEMU(200), Units.toEMU(200)); // 200x200 pixels
        is.close();
    
        FileOutputStream fos = new FileOutputStream("test4.docx");
        doc.write(fos);
        fos.close();
    

    详细代码(原创):

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
    import org.apache.poi.util.Units;
    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 blog {
    	public static void main(String[] args) throws Exception {  
    		//测试添加图片
    		String sourceFile="D:/测试模板.docx";
        	String targetFile="D:/test.docx";
        	addStampImage(sourceFile, targetFile);
    	}
    	
    	public static void addStampImage(String sourceFile, String targetFile) {
    		XWPFDocument doc;
    		try {
    			doc = new XWPFDocument(new FileInputStream(sourceFile));
    			for(XWPFTable table : doc.getTables()) {
    				for(XWPFTableRow row : table.getRows()) {
    					for(XWPFTableCell cell : row.getTableCells()) {//遍历每一个单元格
    						if(cell.getText().contains("&章")) {//如果遇到"&章"则进行替换
    							try {
    								insertCellStamp(cell);//给带有要盖章字样的单元格 加上章的图片
    							} catch (Exception e) {
    								e.printStackTrace();
    							}
    						}
    					}
    				}
    			}
    			
    			FileOutputStream fos = new FileOutputStream(targetFile);
    			doc.write(fos);
    			fos.close();     
    
    			doc.write(new FileOutputStream(targetFile));
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
        }
    
        private static void insertCellStamp(XWPFTableCell cell) throws InvalidFormatException, IOException {//给带有要盖章字样的单元格 加上章的图片
        	List<String> stamps = new ArrayList<>();//存放要加入的图片
    		int stampOrder = 0;//图片的序号,从0开始
    		
    		//获取需要的图片,
    		for(XWPFParagraph para :cell.getParagraphs()) {
    			String paraText = para.getText();//从段落中获取要盖的章的名称
    //			System.out.println("para.getText():" + paraText);
    			if(paraText != null) {
    				String[] split = para.getText().split(" ");
    				for(String s : split) {
    					s = s.trim();
    					if(!s.isEmpty() ) {
    						stamps.add(s.replace("&章", ""));//如:&章公章01.png,去掉标识符&章,只留下章的名字
    					}
    				}
    			}
    		}
    		
    		String basedir = "E:";
    		for(XWPFParagraph para :cell.getParagraphs()) {
    			for (XWPFRun run : para.getRuns()) {
    				run.setText("", 0);//清空所有文字
    			}
    //			for (int i =para.getRuns().size()-1 ; i>=0; i--) {
    //				XWPFRun run = para.getRuns().get(i);
    //				System.out.println("清空所有文字后:run.getText(0): " + run.getText(0));
    //			}
    			
    			//插入图片
    			for(int i = 0; i<stamps.size() && i<para.getRuns().size(); i++) {
    				try {
    					XWPFRun run = para.getRuns().get(i);
    					String imgFile = basedir + "/公章管理/" + stamps.get(stampOrder++);
    					System.out.println("插入盖章图片:" + imgFile);
    					FileInputStream is = new FileInputStream(imgFile);
    					run.addPicture(is, XWPFDocument.PICTURE_TYPE_JPEG, imgFile, Units.toEMU(100), Units.toEMU(100)); // 100x100 pixels
    					is.close();
    					run.setText("  ",0);
    				} catch (Exception e) {
    					System.out.println("Error: ========  插入单个公章图片时出错了:可能是图片路径不存在。不影响主流程");
    					e.printStackTrace();
    				}
    			}
    		}
        }
    }
    

    最后样子:涉及保密就加了马赛克~
    在这里插入图片描述
    备注:有位朋友说他运行到doc = new XWPFDocument(new FileInputStream(sourceFile));这行时就直接报错:No valid entries or contents found, this is not a valid OOXML (Office Open XML) file报这个错,我和他一起尝试找了下原因,最后也是没找到原因不了了之了。
    这段代码已经上线使用了,我这边需求比较复杂,坑也很多,所以建议大家如果需求简单的话就直接参考stackoverflow的代码。

    展开全文
  • 使用POI批量添加图片word前言效果图第一步 添加依赖新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中...

    前言

    我们的需求:可以批量的向word中添加图片和文本。在网上找了很久,找到的都是只能向word添加一张图片的,而且都是使用的freemark,一个是找到的需求不满足,另外一个是我也不想使用freemark,因此,我决定用java结合着poi自己手动写一个。

    生成效果图

    该报告为代码生成,达到的效果是影像和处理建议都可以动态插入多张图片和文字
    在这里插入图片描述

    第一步 添加依赖

    该依赖为对poi封装后的依赖,还需自己添加相关poi依赖

     <dependency>
                <groupId>com.deepoove</groupId>
                <artifactId>poi-tl</artifactId>
                <version>1.6.0</version>
            </dependency>
    

    如果你还没有poi依赖,那么可以使用下面的依赖(如果有请忽略下面这些依赖)

    <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi</artifactId>
                <version>4.0.0</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>4.0.0</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-excelant</artifactId>
                <version>4.0.0</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml-schemas</artifactId>
                <version>4.0.0</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-scratchpad</artifactId>
                <version>4.0.0</version>
            </dependency>
    

    第二步 创建要封装的表单数据

    CommonReportVo将这个类换成自己的实体类数据,这个方法主要目的是给表格里面的数据赋值并返回(此步骤根据自身实际情况赋值),这里表格是两列,因此我使用二维数组,如果你的word表格数据是多列,那么你可以使用一个实体类进行封装后返回。注:此部分代码仅做表格数据赋值参考

    private String[][] setSatelliteReportTemplate(CommonReportVo commonReportVo) {
            String[] names = {"测试001","测试002,"测试0003","测试0004","测试0005","测试0006"};
            String lon = GCSUtils.changeToDFM(Double.parseDouble(commonReportVo.getLon()));
            String lat = GCSUtils.changeToDFM(Double.parseDouble(commonReportVo.getLat()));
            String status = commonReportVo.getDisaterSituatuin();
            String taskNo = commonReportVo.getTaskNo();
            String taskRecord = commonReportVo.getTaskRecord();
            //多张图片地址 对应测试0004
            String analysisResult = commonReportVo.getDataAnalysisResult();
            String suggestion = commonReportVo.getEmergencySuggestion();
            String otherMaterial = "详见附件文件";
            String[] values = {status,taskNo,taskRecord,analysisResult,suggestion,otherMaterial};
            String[][] arrs = new String[names.length][2];
            //设置行数据
            for (int i = 0;i < names.length;i ++){
                arrs[i][0] = names[i];
            }
            //设置列数据
            for (int i = 0;i < values.length;i ++){
                arrs[i][1] = values[i];
            }
            return arrs;
        }
    

    第三步 将数据设置到word

    在上面我们只赋值了表格数据,现在我们将设置标题、时间等其他字段并赋值。

    //参数1:响应体
    //参数2:上面的二维数据组,即表格中的数据
    //参数3:设置标题、时间等字段的封装类
    private File setInfo2CommonWord(HttpServletResponse response, String[][] reports,CommonReportVo commonReportVo)  {
    		//创建一个word
            XWPFDocument doc = new XWPFDocument();
            XWPFParagraph title = doc.createParagraph();
            XWPFRun xwpfRun = title.createRun();
            //设置标题  测试0001报告
            xwpfRun.setText(commonReportVo.getReportName() + "报告");
            xwpfRun.setFontSize(16);
            //设置标题加粗
            xwpfRun.setBold(true);
            //设置标题居中
            title.setAlignment(ParagraphAlignment.CENTER);
            XWPFParagraph content1 = doc.createParagraph();
            XWPFRun xwpfRun1 = content1.createRun();
            xwpfRun1.setText("报告单位:测试一下");
            //设置体字体大小
            xwpfRun1.setFontSize(12);
            XWPFParagraph content2 = doc.createParagraph();
            XWPFRun xwpfRun2 = content2.createRun();
            xwpfRun2.setText("灾害报告时间:" + DateUtil.formatDate1(commonReportVo.getReportTime()));
            xwpfRun2.setFontSize(12);
            String imgResult = commonReportVo.getSatelliteImgResult();
            try {
            	//注意 这是创建表格 创建的是几行几列  这儿需要根据自己实际的表格行列数自己设置
            	//参数1:表示行  参数2:表示列
                XWPFTable table = doc.createTable(reports.length, 2);
                //下面的两个for循环就是设置表格数据  这里仅提供样例的设置思路
                for (int i = 0;i < reports.length; i ++){ //行
                	//得到列数据对象
                    XWPFTableCell cell = table.getRow(i).getCell(0);
                    cell.setWidth("1500");
                    for (int j = 0; j < reports[0].length; j ++){ //列
                    	//设置表格每个单元格的样式
                        XWPFParagraph paragraph = table.getRow(i).getCell(j).getParagraphs().get(0);
                        //对齐方式 左边
                        paragraph.setAlignment(ParagraphAlignment.LEFT);
                        XWPFRun run = paragraph.createRun();
                        //字体9号
                        run.setFontSize(9);
                        //以下setPics方法为给表格设置多张图片和文字 看明白后根据自己的业务进行设置
                       //注意 修改此处,然后替换为自己的多张图片
                        if(i == 3 && j == 1){
                        	//给对应的单元格设置多张图片
                            setPics(reports[i][j], table.getRow(i), j,imgResult);
                        }else {
                        	//给单元格设置文本
                            String[] runTexts=reports[i][j].split("\r\n");
                            for (String s:runTexts){
                                XWPFRun tempRun=paragraph.createRun();
                                tempRun.setFontSize(9);
                                tempRun.setText(s);
                                tempRun.addBreak();
                            }
                        }
                    }
                }
                //设置表格为A4纸张 
                //注意  参数2:表格列数 需要改为自己的列数
                TableTools.widthTable(table, MiniTableRenderData.WIDTH_A4_FULL, 2);
                //以下方式自行选择
                //直接下载 方式一
                String fileName =commonReportVo.getReportName() + "测试报告";
    //            OutputStream out = response.getOutputStream();
    //            response.setHeader("Content-Type", "application/ms-winword");
    //            response.addHeader("Content-Disposition", "attachment;filename=\"" + URLEncoder.encode(fileName, "UTF-8") + ".docx\"");
    //            response.setContentType("application/octet-stream");
    //            response.setCharacterEncoding("UTF-8");
    //            doc.write(out);
                //返回文件的方式下载 方式二
                File file = new File(filePath+File.separator+fileName + ".docx");
                FileOutputStream fos = new FileOutputStream(file);
                doc.write(fos);
                doc.close();
                return file;
            } catch (IOException | InvalidFormatException e) {
                e.printStackTrace();
            }
            return null;
        }
    
    

    注意:文字换行赋值如下

    文字描述如果需要换行时要在设置赋值时的文本中添加\r\n,如:imgResult这个字段中的值是这样的,
    imgResult:这是一段测试文字\r\n这是一段测试文字\r\n这是一段测试文字
    那么取值后给对应的单元格赋值时这样的

     String[] runTexts=imgResult.split("\r\n");
                for (String s:runTexts){
                    run=p1.createRun();
                    run.setFontSize(9);
                    run.setText(s);
                    run.addBreak();
                }
    

    批量设置多张图、文字及描述

    //参数1:对应样例中测试0004的多张图片的路径 
    //参数2:行对象
    //参数3:图片上方的文字描述 
     private void setPics(String analysisResult, XWPFTableRow row, int j,String imgResult) throws InvalidFormatException, IOException {
            XWPFParagraph p1 = row.getCell(j).getParagraphs().get(0);
            //通过分隔符获取多张图片路径
            String[] filePaths = analysisResult.split(",");
            if(filePaths.length > 0){
                XWPFRun run = null;
                //设置图片上的文字描述
                String[] runTexts=imgResult.split("\r\n");
                for (String s:runTexts){
                    run=p1.createRun();
                    run.setFontSize(9);
                    run.setText(s);
                    run.addBreak();
                }
                //run.addBreak(); //换行
                //一个单元格中每行设置几张图片 我这里设置的是每行2张图片 然后换行 
                /注意: 每行几张图片根据自己业务修改
                for (int k = 0;k < filePaths.length; k +=2){
    if(filePaths[k].toUpperCase().contains(".JPG")||filePaths[k].toUpperCase().contains(".PNG")||filePaths[k].toUpperCase().contains(".SVG")){
                        run.addTab();   //添加一个tab
                        int index = filePaths[k].lastIndexOf("\\");
                        String newStr = filePaths[k].substring(index+1);
                        int indexOf = newStr.lastIndexOf(".");
                        String pic = newStr.substring(indexOf);
                        int i = newStr.indexOf("_");
                        //获取文件名
                        String name = newStr.substring(0,i) + pic;
                        //获取文件流
                        InputStream stream = new FileInputStream(filePaths[k]);
                        //设置第一张图片
                        //参数1:图片流数据 参数2:图片类型  参数3 图片名称  参数4:图片宽度  参数5:图片高度
                        run.addPicture(stream, XWPFDocument.PICTURE_TYPE_PNG, "Generated"+k, Units.toEMU(128), Units.toEMU(128));
                        run.addTab();
                        run.addTab();
                        int lastK = k + 1;
                        String name2 = "";
                        if( (lastK) <= filePaths.length-1){
                            int index1 = filePaths[lastK].lastIndexOf("\\");
                            String newStr2 = filePaths[lastK].substring(index1+1);
                            int index2 = newStr2.lastIndexOf(".");
                            String pic2 = newStr2.substring(index2);
                            int i2 = newStr2.indexOf("_");
                            name2 = newStr2.substring(0,i2) + pic2;
                            InputStream stream2 = new FileInputStream(filePaths[lastK]);
                            // 设置第二张图片
                            run.addPicture(stream2, XWPFDocument.PICTURE_TYPE_PNG, "Generated"+lastK, Units.toEMU(128), Units.toEMU(128));
                            //换行
                            run.addBreak();
                        }
                        if(k == filePaths.length-1 && filePaths.length % 2 == 1){
                            run.addBreak();
                        }
                        //设置第一张图片的名称
                        run.setText(name);
                        //这里添加了两个tab 具体添加几个 根据自己的实际格式来调
                        run.addTab();
                        run.addTab();
                         //设置第二张图片的名称
                        run.setText(name2);
    
                        if(lastK == filePaths.length-1){
                            break;
                        }
                    }
                }
            }
            row.getCell(j).setParagraph(p1);
        }
    
    

    自此,整个word批量插入多张图片完成。

    授人以鱼不如授人以渔(参考该API)

    如果你想使用我这种方式 请结合着以下API
    Apache POI Word(docx)

    展开全文
  • Java利用poi生成word(包含插入图片,动态表格,行合并) 测试模板样式: 图表 1 Word生成结果: 图表 2 需要的jar包:(具体jar可自行去maven下载) Test测试类: import java.io.FileInputStream; import java.io...

    Java利用poi生成word(包含插入图片,动态表格,行合并)

    测试模板样式:
    在这里插入图片描述
    图表 1
    Word生成结果:
    在这里插入图片描述
    图表 2
    需要的jar包:(具体jar可自行去maven下载)
    在这里插入图片描述
    Test测试类:

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.util.*;
    
    public class Main {
    
        public static void main(String[] args) throws Exception {
            //需要进行文本替换的信息
            Map<String, Object> data = new HashMap<String, Object>();
            data.put("${date}", "2018-03-06");
            data.put("${name}", "东方明珠");
            data.put("${address}", "华东院");
            data.put("${communityvalue}", "");
            data.put("${safetycode}", "华东院");
            data.put("${picture2}", "");
            data.put("${picture3}", "");
            data.put("${buildingvalue2}", "华东院");
            data.put("${patrolPhoto1}", "");
            data.put("${patrolPhoto2}", "");
            data.put("${buildingvalue3}", "中国");
    
            //图片,如果是多个图片,就新建多个map
            Map<String,Object> picture1 = new HashMap<String, Object>();
            picture1.put("width", 100);
            picture1.put("height", 150);
            picture1.put("type", "jpg");
            picture1.put("content", WorderToNewWordUtils.inputStream2ByteArray(new FileInputStream("D:/timg.jpg"), true));
            data.put("${picture1}",picture1);
    
            //需要进行动态生成的信息
            List<Object> mapList = new ArrayList<Object>();
    
            //第一个动态生成的数据列表
            List<String[]> list01 = new ArrayList<String[]>();
            list01.add(new String[]{"A","11111111111","22","22"});
            list01.add(new String[]{"A","22222222222","33","22"});
            list01.add(new String[]{"B","33333333333","44","22"});
            list01.add(new String[]{"C","44444444444","55","22"});
    
            //第二个动态生成的数据列表
            List<String[]> list02 = new ArrayList<String[]>();
            list02.add(new String[]{"A","11111111111","22","22"});
            list02.add(new String[]{"d","22222222222","33","22"});
            list02.add(new String[]{"B","33333333333","44","22"});
            list02.add(new String[]{"C","44444444444","55","22"});
    
            mapList.add(list01);
            mapList.add(list02);
    
            //需要动态改变表格的位置;第一个表格的位置为0
            int[] placeList = {1,4};
    
            CustomXWPFDocument doc = WorderToNewWordUtils.changWord("C:/Users/user/Desktop/test1.docx",data,mapList,placeList);
            FileOutputStream fopts = new FileOutputStream("D:/呵呵.docx");
            doc.write(fopts);
            fopts.close();
        }
    
    }
    

    WorderToNewWordUtils类:

    import org.apache.poi.POIXMLDocument;
    import org.apache.poi.xwpf.usermodel.*;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;
    
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.*;
    
    /**
     * Created by 王景伟 on 2018/12/19.
     */
    public class WorderToNewWordUtils {
        /**
         * 根据模板生成word文档
         * @param inputUrl 模板路径
         * @param textMap 需要替换的文本内容
         * @param mapList 需要动态生成的内容
         * @return
         */
        public static CustomXWPFDocument changWord(String inputUrl, Map<String, Object> textMap, List<Object> mapList,int[] placeList) {
            CustomXWPFDocument document = null;
            try {
                //获取docx解析对象
                document = new CustomXWPFDocument(POIXMLDocument.openPackage(inputUrl));
    
                //解析替换文本段落对象
                WorderToNewWordUtils.changeText(document, textMap);
    
                //解析替换表格对象
                WorderToNewWordUtils.changeTable(document, textMap, mapList,placeList);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return document;
        }
    
        /**
         * 替换段落文本
         * @param document docx解析对象
         * @param textMap 需要替换的信息集合
         */
        public static void changeText(CustomXWPFDocument document, Map<String, Object> 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) {
                        //替换模板原来位置
                        Object ob = changeValue(run.toString(), textMap);
                        System.out.println("段落:"+run.toString());
                        if (ob instanceof String){
                            run.setText((String)ob,0);
                        }
                    }
                }
            }
        }
    
        /**
         * 替换表格对象方法
         * @param document docx解析对象
         * @param textMap 需要替换的信息集合
         * @param mapList 需要动态生成的内容
         */
        public static void changeTable(CustomXWPFDocument document, Map<String, Object> textMap, List<Object> mapList,int[] placeList){
            //获取表格对象集合
            List<XWPFTable> tables = document.getTables();
    
            //循环所有需要进行替换的文本,进行替换
            for (int i = 0; i < tables.size(); i++) {
                XWPFTable table = tables.get(i);
                if(checkText(table.getText())){
                    List<XWPFTableRow> rows = table.getRows();
                    System.out.println("简单表格替换:"+rows);
                    //遍历表格,并替换模板
                    eachTable(document,rows, textMap);
                }
            }
    
            int index=0;
            //操作word中的表格
            for (int i = 0; i < tables.size(); i++) {
                //只处理行数大于等于2的表格,且不循环表头
                XWPFTable table = tables.get(i);
                if(placeList[index]==i){
                    List<String[]> list = (List<String[]>) mapList.get(index);
                    //第二个表格使用daList,插入数据
                    if (null != list && 0 < list.size()){
                        insertTable(table, null,list,2);
                        List<Integer[]> indexList = startEnd(list);
                        for (int c=0;c<indexList.size();c++){
                            //合并行
                            mergeCellVertically(table,0,indexList.get(c)[0]+1,indexList.get(c)[1]+1);
                        }
                    }
                    index++;
                }
    
            }
        }
        /**
         * 遍历表格
         * @param rows 表格行对象
         * @param textMap 需要替换的信息集合
         */
        public static void eachTable(CustomXWPFDocument document, List<XWPFTableRow> rows , Map<String, Object> 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) {
                                Object ob = changeValue(run.toString(), textMap);
                                if (ob instanceof String){
                                    run.setText((String)ob,0);
                                }else if (ob instanceof Map){
                                    run.setText("",0);
                                    Map pic = (Map)ob;
                                    int width = Integer.parseInt(pic.get("width").toString());
                                    int height = Integer.parseInt(pic.get("height").toString());
                                    int picType = getPictureType(pic.get("type").toString());
                                    byte[] byteArray = (byte[]) pic.get("content");
                                    ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);
                                    try {
                                        int ind = document.addPicture(byteInputStream,picType);
                                        document.createPicture(ind, width , height,paragraph);
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    
        /**
         * 为表格插入数据,行数不够添加新行
         * @param table 需要插入数据的表格
         * @param tableList 第四个表格的插入数据
         * @param daList 第二个表格的插入数据
         * @param type 表格类型:1-第一个表格 2-第二个表格 3-第三个表格 4-第四个表格
         */
        public static void insertTable(XWPFTable table, List<String> tableList,List<String[]> daList,Integer type){
            if (2 == type){
                //创建行和创建需要的列
                for(int i = 1; i < daList.size(); i++){
                    //添加一个新行
                    XWPFTableRow row = table.insertNewTableRow(1);
                    for(int k=0; k<daList.get(0).length;k++){
                        row.createCell();//根据String数组第一条数据的长度动态创建列
                    }
                }
    
                //创建行,根据需要插入的数据添加新行,不处理表头
                for(int i = 0; i < daList.size(); i++){
                    List<XWPFTableCell> cells = table.getRow(i+1).getTableCells();
                    for(int j = 0; j < cells.size(); j++){
                        XWPFTableCell cell02 = cells.get(j);
                        cell02.setText(daList.get(i)[j]);
                    }
                }
            }else if (4 == type){
                //插入表头下面第一行的数据
                for(int i = 0; i < tableList.size(); i++){
                    XWPFTableRow row = table.createRow();
                    List<XWPFTableCell> cells = row.getTableCells();
                    cells.get(0).setText(tableList.get(i));
                }
            }
        }
    
        /**
         * 判断文本中时候包含$
         * @param text 文本
         * @return 包含返回true,不包含返回false
         */
        public static boolean checkText(String text){
            boolean check  =  false;
            if(text.indexOf("$")!= -1){
                check = true;
            }
            return check;
        }
    
        /**
         * 匹配传入信息集合与模板
         * @param value 模板需要替换的区域
         * @param textMap 传入信息集合
         * @return 模板需要替换区域信息集合对应值
         */
        public static Object changeValue(String value, Map<String, Object> textMap){
            Set<Map.Entry<String, Object>> textSets = textMap.entrySet();
            Object valu = "";
            for (Map.Entry<String, Object> textSet : textSets) {
                //匹配模板与替换值 格式${key}
                String key = textSet.getKey();
                if(value.indexOf(key)!= -1){
                    valu = textSet.getValue();
                }
            }
            return valu;
        }
    
        /**
         * 将输入流中的数据写入字节数组
         * @param in
         * @return
         */
        public static byte[] inputStream2ByteArray(InputStream in, boolean isClose){
            byte[] byteArray = null;
            try {
                int total = in.available();
                byteArray = new byte[total];
                in.read(byteArray);
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                if(isClose){
                    try {
                        in.close();
                    } catch (Exception e2) {
                        System.out.println("关闭流失败");
                    }
                }
            }
            return byteArray;
        }
    
        /**
         * 根据图片类型,取得对应的图片类型代码
         * @param picType
         * @return int
         */
        private static int getPictureType(String picType){
            int res = CustomXWPFDocument.PICTURE_TYPE_PICT;
            if(picType != null){
                if(picType.equalsIgnoreCase("png")){
                    res = CustomXWPFDocument.PICTURE_TYPE_PNG;
                }else if(picType.equalsIgnoreCase("dib")){
                    res = CustomXWPFDocument.PICTURE_TYPE_DIB;
                }else if(picType.equalsIgnoreCase("emf")){
                    res = CustomXWPFDocument.PICTURE_TYPE_EMF;
                }else if(picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")){
                    res = CustomXWPFDocument.PICTURE_TYPE_JPEG;
                }else if(picType.equalsIgnoreCase("wmf")){
                    res = CustomXWPFDocument.PICTURE_TYPE_WMF;
                }
            }
            return res;
        }
    
        /**
         * 合并行
         * @param table
         * @param col 需要合并的列
         * @param fromRow 开始行
         * @param toRow 结束行
         */
        public static void mergeCellVertically(XWPFTable table, int col, int fromRow, int toRow) {
            for(int rowIndex = fromRow; rowIndex <= toRow; rowIndex++){
                CTVMerge vmerge = CTVMerge.Factory.newInstance();
                if(rowIndex == fromRow){
                    vmerge.setVal(STMerge.RESTART);
                } else {
                    vmerge.setVal(STMerge.CONTINUE);
                }
                XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
                CTTcPr tcPr = cell.getCTTc().getTcPr();
                if (tcPr != null) {
                    tcPr.setVMerge(vmerge);
                } else {
                    tcPr = CTTcPr.Factory.newInstance();
                    tcPr.setVMerge(vmerge);
                    cell.getCTTc().setTcPr(tcPr);
                }
            }
        }
        /**
         * 获取需要合并单元格的下标
         * @return
         */
        public static List<Integer[]> startEnd(List<String[]> daList){
            List<Integer[]> indexList = new ArrayList<Integer[]>();
    
            List<String> list = new ArrayList<String>();
            for (int i=0;i<daList.size();i++){
                list.add(daList.get(i)[0]);
            }
            Map<Object, Integer> tm = new HashMap<Object, Integer>();
            for (int i=0;i<daList.size();i++){
                if (!tm.containsKey(daList.get(i)[0])) {
                    tm.put(daList.get(i)[0], 1);
                } else {
                    int count = tm.get(daList.get(i)[0]) + 1;
                    tm.put(daList.get(i)[0], count);
                }
            }
            for (Map.Entry<Object, Integer> entry : tm.entrySet()) {
                String key = entry.getKey().toString();
                String value = entry.getValue().toString();
                if (list.indexOf(key) != (-1)){
                    Integer[] index = new Integer[2];
                    index[0] = list.indexOf(key);
                    index[1] = list.lastIndexOf(key);
                    indexList.add(index);
                }
            }
            return indexList;
        }
    
    }
    

    CustomXWPFDocument类:

    import org.apache.xmlbeans.XmlException;
    import org.apache.xmlbeans.XmlToken;
    import org.apache.poi.openxml4j.opc.OPCPackage;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    import org.apache.poi.xwpf.usermodel.XWPFParagraph;
    import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
    import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
    import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    /**
     * Created by 王景伟 on 2018/12/19.
     * 自定义 XWPFDocument,并重写 createPicture()方法
     */
    public class CustomXWPFDocument extends XWPFDocument{
        public CustomXWPFDocument(InputStream in) throws IOException {
            super(in);
        }
    
        public CustomXWPFDocument() {
            super();
        }
    
        public CustomXWPFDocument(OPCPackage pkg) throws IOException {
            super(pkg);
        }
    
        /**
         * @param id
         * @param width 宽
         * @param height 高
         * @param paragraph  段落
         */
        public void createPicture(int id, int width, int height,XWPFParagraph paragraph) {
            final int EMU = 9525;
            width *= EMU;
            height *= EMU;
            String blipId = getAllPictures().get(id).getPackageRelationship().getId();
            CTInline inline = paragraph.createRun().getCTR().addNewDrawing().addNewInline();
    
            System.out.println(blipId+":"+inline);
    
            String picXml = ""
                    + "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"
                    + "   <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
                    + "      <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
                    + "         <pic:nvPicPr>" + "            <pic:cNvPr id=\""
                    + id
                    + "\" name=\"Generated\"/>"
                    + "            <pic:cNvPicPr/>"
                    + "         </pic:nvPicPr>"
                    + "         <pic:blipFill>"
                    + "            <a:blip r:embed=\""
                    + blipId
                    + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"
                    + "            <a:stretch>"
                    + "               <a:fillRect/>"
                    + "            </a:stretch>"
                    + "         </pic:blipFill>"
                    + "         <pic:spPr>"
                    + "            <a:xfrm>"
                    + "               <a:off x=\"0\" y=\"0\"/>"
                    + "               <a:ext cx=\""
                    + width
                    + "\" cy=\""
                    + height
                    + "\"/>"
                    + "            </a:xfrm>"
                    + "            <a:prstGeom prst=\"rect\">"
                    + "               <a:avLst/>"
                    + "            </a:prstGeom>"
                    + "         </pic:spPr>"
                    + "      </pic:pic>"
                    + "   </a:graphicData>" + "</a:graphic>";
    
            inline.addNewGraphic().addNewGraphicData();
            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("图片" + id);
            docPr.setDescr("测试");
        }
    }
    

    方法调用:

    1. 导入jar包

    2. 复制以上CustomXWPFDocument类和WorderToNewWordUtils类到项目合适路径(根据自己项目情况判断)

    3. 主类调用方法说明(既以上Test测试类)

    4. 对于一般的字段替换,只需要保持(key,value)的键值对方式赋值替换即可,key和模板占位字符保持一致,例:

      Map<String, Object> data = new HashMap<String, Object>();
      data.put(" d a t e &quot; , &quot; 2018 − 03 − 06 &quot; ) ; d a t a . p u t ( &quot; {date}&quot;, &quot;2018-03-06&quot;); data.put(&quot; date","20180306");data.put("{name}", “东方明珠”);
      data.put(" a d d r e s s &quot; , &quot; 华 东 院 &quot; ) ; d a t a . p u t ( &quot; {address}&quot;, &quot;华东院&quot;); data.put(&quot; address","");data.put("{communityvalue}", “”);
      data.put(" s a f e t y c o d e &quot; , &quot; 华 东 院 &quot; ) ; d a t a . p u t ( &quot; {safetycode}&quot;, &quot;华东院&quot;); data.put(&quot; safetycode","");data.put("{picture2}", “”);
      data.put(" p i c t u r e 3 &quot; , &quot; &quot; ) ; d a t a . p u t ( &quot; {picture3}&quot;, &quot;&quot;); data.put(&quot; picture3","");data.put("{buildingvalue2}", “华东院”);
      data.put(" p a t r o l P h o t o 1 &quot; , &quot; &quot; ) ; d a t a . p u t ( &quot; {patrolPhoto1}&quot;, &quot;&quot;); data.put(&quot; patrolPhoto1","");data.put("{patrolPhoto2}", “”);
      data.put("${buildingvalue3}", “中国”);

    5. 如果需要插入图片,则需要重新创建一个Map集合存储图片数据:例

      Map<String,Object> picture1 = new HashMap<String, Object>();
      picture1.put(“width”, 100);
      picture1.put(“height”, 150);
      picture1.put(“type”, “jpg”);
      picture1.put(“content”, WorderToNewWordUtils.inputStream2ByteArray(new FileInputStream(“D:/timg.jpg”), true));
      data.put("${picture1}",picture1);

    如果有多张图片,则需要创建多个Map保存图片,其中它的属性值应保持不变(如上:width,height,type,content),需要注意的是对于一般字段或者是图片最终都存储在data集合中,如下:

    Map<String, Object> data = new HashMap<String, Object>();
    
    1. 对于需要根据具体数据动态生成的表格,我们将数据存储在一个List集合中,如:

      //第一个动态生成的数据列表
      List<String[]> list01 = new ArrayList<String[]>();
      list01.add(new String[]{“A”,“11111111111”,“22”,“22”});
      list01.add(new String[]{“A”,“22222222222”,“33”,“22”});
      list01.add(new String[]{“B”,“33333333333”,“44”,“22”});
      list01.add(new String[]{“C”,“44444444444”,“55”,“22”});

      //第二个动态生成的数据列表
      List<String[]> list02 = new ArrayList<String[]>();
      list02.add(new String[]{“A”,“11111111111”,“22”,“22”});
      list02.add(new String[]{“d”,“22222222222”,“33”,“22”});
      list02.add(new String[]{“B”,“33333333333”,“44”,“22”});
      list02.add(new String[]{“C”,“44444444444”,“55”,“22”});

      如上是两个我们需要根据具体数据动态生成的表格,如list01中数据,当list中String数组的第一个字段相同时,则在创建动态表格时会将这两个单元格合并,其他列数值相同不影响合并。注意:这里的创建的String数组的列数应该和模板的表格列数保持一致。数据保存好之后将list数组统一保存在mapList中,如下:
      List mapList = new ArrayList();
      注意:
      由于无法动态获取需要动态填充的表格,所以我们定义了一个静态数组保存需要动态生成的表格的位置,如下:

      //需要动态改变表格的位置;第一个表格的位置为0

      int[] placeList = {1,4};

    如图1所示,从上至下表格所在位置分别是0-4;而我们需要动态生成的是第二个和第五个,故此处传参{1,4}
    最后调用方法导出word即可;如下:

    CustomXWPFDocument doc = WorderToNewWordUtils.changWord("C:/Users/user/Desktop/test1.docx",data,mapList,placeList);
    FileOutputStream fopts = new FileOutputStream("D:/呵呵.docx");
    doc.write(fopts);
    fopts.close();
    

    在changeWord方法中,第一个参数是模板路径,第二个参数是填充数据,第三个参数是动态表格填充数据,第四个参数是动态表格位置;

    友情提醒:(以下内容若需要可采纳,不需要可跳过)
    使用poi生成Word会发生分段混乱的问题,例如:在操作POI替换word时发现getRuns将我们预设的${product}自动切换成了成了两个部分
    ${product } 或者 p r o d u c t 既 会 出 现 空 格 分 离 字 段 的 情 况 ; 建 议 使 用 从 左 往 右 的 顺 序 进 行 模 板 字 段 填 充 ( 既 : { product } 既会出现空格分离字段的情况;建议使用从左往右的顺序进行模板字段填充(既: product使→{→product→} 而不是 $→{→}→product的方式);

    亲测有效:使用notepad++的xml插件修改模板(保证解析完美)
    (一) 安装notepad++并为其添加插件XML Tools插件(具体步骤自行百度)
    (二) 将修改好的word模板另存为xml格式的文档;如下图所示
    在这里插入图片描述
    (三) 使用notepad++打开xml模板,刚开始打开是一个毫无逻辑可寻的文件,这时我们使用xml tools工具格式化xml文件:如下:
    在这里插入图片描述
    (四) 如上图可看出模板被解析成了多部分,此时我们修改文件,让其保持为一个字段:如下
    在这里插入图片描述

    (五) 保存文档之后用word打开xml文档,然后另存为所需要的docx格式word即可

    create by 王景伟
    2018-12-19

    展开全文
  • java使用poi操作word插入图片、段落、表格准备工作创建word模板.docx文件编写模板格式.xml文件java上手poimaven依赖使用到的包具体应用对应封装方法 ----------图片插入指定位置操作图片操作使用到的工具类对应封装...
  • poi导入word图片

    2019-06-06 17:38:47
    poi导入word,代码简单包含pom文件
  • 解决 Java poi 3.8等版本操作word插入图片不成功的问题 问题: 最近有一个需求是将Excel中的数据转换到word中,其中包括了文字和图片, 在使用poi 3.8向word中写入图片的时候发现怎么都不成功,具体过程如下: ...
  • WORD导出,并插入图片
  • java2WordWord任意位置插入图片

    热门讨论 2015-07-13 21:30:45
    由于项目需要,苦苦对Java操作Word进行了一番研究,包括当下比较流行的java2Word、jacob、POI、itext等,只能说各有千秋,但是没有一个是完全适合我的,没有办法,只能去各种尝试,在研究了java2Word这个jar包的API...
  • 网络上的根据模板填充Word我都看过一些, 它们的功能在数据换行的时候用的是run对象的.addCarriageReturn()方法,或者是直接用\n实现换行。这些都不符合我的需求, 因为我要的是分段,而不是换行。换行的word导致另一...
  • text解决了,表格解决了,结果才发现图片用XWPFDocument压根无法实现addPicture,POI自身有bug,图片是加入到word文件里面了,可是显示不了。。。于是乎,又折腾了2天,终于整蛊了怎么让图片在里面显示出来,其他的...
  • 书签是word里的一种标记元素,poi能很好的读出标签并进行文字替换、图片替换等。此方案利用书签进行操作,同时也更推荐用书签进行word操作,而不是使用${name}等语法进行替换。 替换文字 准备工作 书签概念 书签只有...
  • 在网上看到很少POIword文档的操作,所以自己写一些供参考,不懂的可以留言,我看到就及时回复
  • maven <...poi-tl</artifactId> <version>1.10.0</version> </dependency> Poi-tl 实现效果 {{@}} 标签才能识别 代码 import com.deepoove.poi.XWPFTe...
  • Java POI 生成Word文档

    2017-10-28 13:54:46
    Java POI 生成Word文档,支持图片插入,关键是修改XML部分,本人已测试通过。
  • POI操作Word需要的jar包 博文链接:https://lxzqz.iteye.com/blog/2428443
  • Apache poi 根据word模板生成word报表 替换 循环列表 图片,代码调试过了,修改相应的图片位置,word模板路径即可运行
  • 代码示例分两部分,一部分读取图片/*** 导入word(基本信息,word格式)* @param staffId* @param baseInfoFile*/void importStaffInfo(Integer staffId, MultipartFile file);-- 读取图片InputStream inputStream =...
  • 1.在pom.xml文件中导入poi-tl: <dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <version>1.9.1</version> </dependency>...
  • 在使用POIword插入图片的时候发现,插入图片后,生成的文件打不开,提示格式损坏,查了一下,这是POI自带的bug,真是不想说这是有多操蛋了。 直接查看word中的document.xml文件,和正常的word中的document.xml对比...
  • Java Poi Word 添加页眉文字和图片

    千次阅读 热门讨论 2019-08-11 11:03:58
    for( XWPFPictureData picturedata : header.getAllPackagePictures() ) { // 这段必须有,不然打开的logo图片不显示 blipID = header.getRelationId( picturedata ); picture.getCTPicture()....
  • 前言:poi-tl(poi template language)是Word模板引擎,基于Microsoft Word模板和数据生成新的文档。详细使用见:官方文档 1、pom.xml引入依赖 <dependency> <groupId>com.deepoove</groupId> ...
  • XWPFDocument doc = new XWPFDocument();//获取文档信息 XWPFParagraph p = doc.createParagraph(); ArrayList<String> list=new ArrayList(); list.add("C:\\Users\\lu\\Desktop\\PoiSample\\image\\1.png");...
  • 之前有写过一篇使用jacob对word插入图片的博客。点击率蛮高8800多次,当然多亏了百度搜索引擎的帮忙???? 但是小编在使用以前写的代码走了一遍流程时,发现代码貌似会报错: 即使我吧这个。 ...
  • codePNGpath:图片路径 dest:docx写出路径 aaa:书签名 try { InputStream inputStream = new FileInputStream(src); XWPFDocument document = new XWPFDocument(inputStream); List paragraphList = document....
  • poi版本选3.10以上的 要不然插入图片 word会打不开 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.11</version&...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,823
精华内容 729
关键字:

javapoiword插入图片

java 订阅
友情链接: nf_conntrack_netlink.rar