开发者社区> 问答> 正文

关于java代码读取现有word,追加图片的问题:报错

现有这么个需求,现有的文档里有个编号,需要使用条码图片替代,编号就是一串数字。生成条码的问题简单,问题是现有的word文档全部使用rtf模板cell里面写的标示符如,客户姓名:custName 然后后台使用map.put("custName","张三");这种方式将rtf里面的标示为替换后输出word文档;

第一种方案:使用itext,但是这个jar只能新生成,对于复杂word就显得有点麻烦,因为里面行列表格需要全部使用代码拼装。

第二种:图片存放在word里面实际东西也是字符串,但是这个字符串的规则无法得知,如果能知道这个图片的字符串格式就可以不改代码,将图片生成字符串去替换就可以。所以现在问题的关键在图片存放在word文档的字符串规则。

有过类似问题的朋友指点一下,要是有好的方案请共享一下,谢谢!

展开
收起
kun坤 2020-06-07 21:55:19 1112 0
1 条回答
写回答
取消 提交回答
  • I am sorry,忘了贴这个方法了。

    /***************************************************************************** * 获得段落中字符串的值 * @param  obj     某个段落 * @return String  段落中文字 *****************************************************************************/ public static String getParagraphStrValue(Object obj){ if(obj == null){return null;} StringBuffer sb = new StringBuffer(256); if (obj instanceof ContentAccessor){ List<Object> texts = getAllElementFromObject(obj, Text.class); for (Object child : texts) { sb.append(((Text)child).getValue()); } }else if(obj instanceof JAXBElement){ sb.append(((Text)obj).getValue()); } return sb.toString(); }




    ######回复 @anyine : 不客气,恰好我做过这方面的工作,拿出来分享。######ok ,我先试试,太感谢了!######你的word是2003格式还是2007格式?
    对于2007格式的word,遵循Ecma Office Open XML协议规范,
    我现在用的是docx4j, 我在word模版中放的是如下json串,通过解析json串来替换
    {"cat":"img","alias":"img1"}
    如下是我替换将word中文字替换成图片的方法:
    /*****************************************************************************
    	 * 替换图表
    	 * @param obj            需要替换的paragraph
    	 * @param imgPath        图片路径
    	 * @param wordMLPackage  wordMLPackage
    	 *****************************************************************************/
    	public static  void replaceChart(Object obj,String imgPath,WordprocessingMLPackage wordMLPackage){
    		if(obj == null || imgPath == null){return;}
    			List<Object> texts = getAllElementFromObject(obj, Text.class);
    			for (Object t : texts) {
    				Text content = (Text) t;
    				content.setValue("");
    			}
    			File file = new File(imgPath);
    			InputStream is = null;
    			try {
    				is = new FileInputStream(file );
    				long length = file.length();
    		        if (length > Integer.MAX_VALUE) {
    		        	return;
    		        }
    		        byte[] bytes = new byte[(int)length];
    		        int offset = 0;
    		        int numRead = 0;
    		        while (offset < bytes.length && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
    		             offset += numRead;
    		         }
    		         if (offset < bytes.length) {
    		        	 return;
    		         }
    		        
    		         String filenameHint = null;
    		         String altText = null;
    		         int id1 = 0;
    		         int id2 = 1;
    				newImage(wordMLPackage, (P)obj, bytes, filenameHint, altText, id1, id2);
    			} catch (Exception e) {
    				//e.printStackTrace();
    			}finally{
    				 if(is != null){
    					 try {
    						 is.close();
    					 } catch (IOException e) {
    						e.printStackTrace();
    					}
    				 }
    			}
    	}
    //添加图片
        private static  void newImage( WordprocessingMLPackage wordMLPackage,P p,byte[] bytes,String filenameHint, String altText,
                int id1, int id2) throws Exception {
            BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, bytes);
            Inline inline = imagePart.createImageInline( filenameHint, altText,id1, id2, false);
            // Now add the inline in w:p/w:r/w:drawing
            ObjectFactory factory = Context.getWmlObjectFactory();
            R run = factory.createR();    
            p.getContent().add(run);
            PPr ppr = factory.createPPr();
            Jc jc = factory.createJc();
            Ind ind = factory.createPPrBaseInd();
            ind.setFirstLine(new BigInteger("0"));
            ind.setFirstLineChars(new BigInteger("0"));
            jc.setVal(JcEnumeration.LEFT);
            ppr.setJc(jc);
            ppr.setInd(ind);
            p.setPPr(ppr);
            Drawing drawing = factory.createDrawing();    
            run.getContent().add(drawing);    
            drawing.getAnchorOrInline().add(inline);
        }
    
    ######回复 @bigtiger02 : 恩,这是个麻烦事儿,用你说的第一种办法可行吗?######回复 @anyine : jacob是一个java-COM中间件.通过这个组件你可以在Java应用程序中调用COM组件和Win32程序库,只能在windows环境下使用######回复 @bigtiger02 : 我的web运行在linux下 jacob还有效吗######回复 @bigtiger02 : 3Q 我先看看...######回复 @anyine : 2003的话,我以前用的是jacob来进行替换,但是觉得并不是那么好用,给个jacob例子: http://blog.csdn.net/lulongzhou_llz/article/details/6701918######

    引用来自“bigtiger02”的答案

    你的word是2003格式还是2007格式?
    对于2007格式的word,遵循Ecma Office Open XML协议规范,
    我现在用的是docx4j, 我在word模版中放的是如下json串,通过解析json串来替换
    {"cat":"img","alias":"img1"}
    如下是我替换将word中文字替换成图片的方法:
    /*****************************************************************************
    	 * 替换图表
    	 * @param obj            需要替换的paragraph
    	 * @param imgPath        图片路径
    	 * @param wordMLPackage  wordMLPackage
    	 *****************************************************************************/
    	public static  void replaceChart(Object obj,String imgPath,WordprocessingMLPackage wordMLPackage){
    		if(obj == null || imgPath == null){return;}
    			List<Object> texts = getAllElementFromObject(obj, Text.class);
    			for (Object t : texts) {
    				Text content = (Text) t;
    				content.setValue("");
    			}
    			File file = new File(imgPath);
    			InputStream is = null;
    			try {
    				is = new FileInputStream(file );
    				long length = file.length();
    		        if (length > Integer.MAX_VALUE) {
    		        	return;
    		        }
    		        byte[] bytes = new byte[(int)length];
    		        int offset = 0;
    		        int numRead = 0;
    		        while (offset < bytes.length && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
    		             offset += numRead;
    		         }
    		         if (offset < bytes.length) {
    		        	 return;
    		         }
    		        
    		         String filenameHint = null;
    		         String altText = null;
    		         int id1 = 0;
    		         int id2 = 1;
    				newImage(wordMLPackage, (P)obj, bytes, filenameHint, altText, id1, id2);
    			} catch (Exception e) {
    				//e.printStackTrace();
    			}finally{
    				 if(is != null){
    					 try {
    						 is.close();
    					 } catch (IOException e) {
    						e.printStackTrace();
    					}
    				 }
    			}
    	}
    //添加图片
        private static  void newImage( WordprocessingMLPackage wordMLPackage,P p,byte[] bytes,String filenameHint, String altText,
                int id1, int id2) throws Exception {
            BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, bytes);
            Inline inline = imagePart.createImageInline( filenameHint, altText,id1, id2, false);
            // Now add the inline in w:p/w:r/w:drawing
            ObjectFactory factory = Context.getWmlObjectFactory();
            R run = factory.createR();    
            p.getContent().add(run);
            PPr ppr = factory.createPPr();
            Jc jc = factory.createJc();
            Ind ind = factory.createPPrBaseInd();
            ind.setFirstLine(new BigInteger("0"));
            ind.setFirstLineChars(new BigInteger("0"));
            jc.setVal(JcEnumeration.LEFT);
            ppr.setJc(jc);
            ppr.setInd(ind);
            p.setPPr(ppr);
            Drawing drawing = factory.createDrawing();    
            run.getContent().add(drawing);    
            drawing.getAnchorOrInline().add(inline);
        }
    

    回复 @bigtiger02 : 我现在能读取,能写入了。但是不知道用哪个方法指定写入的位置或者替换。
    private static void addImageToPackage(WordprocessingMLPackage wordMLPackage,
                                byte[] bytes) throws Exception {
            BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, bytes);
            int docPrId = 1;
            int cNvPrId = 2;
            Inline inline = imagePart.createImageInline("Filename hint","Alternative text", docPrId, cNvPrId, false);
            P paragraph = addInlineImageToParagraph(inline);
            wordMLPackage.getMainDocumentPart().addObject(paragraph);
        }
     
        /**
         *  创建一个对象工厂并用它创建一个段落和一个可运行块R.
         *  然后将可运行块添加到段落中. 接下来创建一个图画并将其添加到可运行块R中. 最后我们将内联
         *  对象添加到图画中并返回段落对象.
         *
         * @param   inline 包含图片的内联对象.
         * @return  包含图片的段落
         */
        private static P addInlineImageToParagraph(Inline inline) {
            // 添加内联对象到一个段落中
            ObjectFactory factory = new ObjectFactory();
            P paragraph = factory.createP();
            R run = factory.createR();
            paragraph.getContent().add(run);
            Drawing drawing = factory.createDrawing();
            run.getContent().add(drawing);
            drawing.getAnchorOrInline().add(inline);
            return paragraph;
        }

    麻烦你指点一下呢

    ######之前做excel的时候发现,图片就是用图片的二进制流做base64编码得到的字符串,word估计是一样的,你可以试试看######这个确实是,找到位置很关键######

    你可以用一段文字进行标记,然后查找将这段文字替换成图片即可。
    world操作方法:

    //拷贝文件
    dstUrlTmp = copyFile(modelUrl,dstUrl);
    //开始wordMLPackage = DocxUtils.load(dstUrlTmp);
    document = wordMLPackage.getMainDocumentPart();
    //替换字符串、表格以及图片
    replace(DocxUtils.getAllElementFromObject(document,P.class));
    //保存
    DocxUtils.save(wordMLPackage, dstUrl);
    replace方法:
    //执行替换
    	private void replace(List<Object> paragraphs){
    		final int pSize = paragraphs.size();
    		for (int i = 0; i < pSize; i++) {
    			Object obj = paragraphs.get(i);
    			String text = DocxUtils.getParagraphStrValue(obj);
    			Set<String> jsons = getMatchStr("\\{(\"\\w+\":\"?\\w+\"?,*){1,}\\}", 
    					StringUtil.replace(text, CN_CHARS, CN_REPLACE_CHARS));
    			if(CollectionUtils.isNotEmpty(jsons)){//不为空则进行分发
    				for (String s : jsons) {
    					DOCJsonObject jsonObject = null;
    					try {
    						jsonObject = new Gson().fromJson(s, DOCJsonObject.class);
    					} catch (Exception e) {
    						e.printStackTrace();
    					}
    					if(jsonObject == null){
    						continue;
    					}else{
    						DocxUtils.replaceChart(obj, imgPath, wordMLPackage);
    					}
    				}
    			}
    		}
    	}
    替换方法见一楼
    getAllElementFromObject方法:
    /*****************************************************************************
    	 * 查找JAXBElement元素
    	 * @param  obj          查找目标
    	 * @param  toSearch     查找类的class
    	 * @return List<Object>
    	 *****************************************************************************/
    	public static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) {
    	    List<Object> result = new ArrayList<Object>();
    	    if (obj instanceof JAXBElement){
    	    	obj = ((JAXBElement<?>) obj).getValue();
    	    }
    	    if (obj.getClass().equals(toSearch)){
    	    	result.add(obj);
    	    }else if (obj instanceof ContentAccessor) {
    		    List<?> children = ((ContentAccessor) obj).getContent();
    		    for (Object child : children) {
    		    	result.addAll(getAllElementFromObject(child, toSearch));
    		    }
    	   }
    	   return result;
       }




    ######

    引用来自“bigtiger02”的答案

    你可以用一段文字进行标记,然后查找将这段文字替换成图片即可。
    world操作方法:

    //拷贝文件
    dstUrlTmp = copyFile(modelUrl,dstUrl);
    //开始wordMLPackage = DocxUtils.load(dstUrlTmp);
    document = wordMLPackage.getMainDocumentPart();
    //替换字符串、表格以及图片
    replace(DocxUtils.getAllElementFromObject(document,P.class));
    //保存
    DocxUtils.save(wordMLPackage, dstUrl);
    replace方法:
    //执行替换
    	private void replace(List<Object> paragraphs){
    		final int pSize = paragraphs.size();
    		for (int i = 0; i < pSize; i++) {
    			Object obj = paragraphs.get(i);
    			String text = DocxUtils.getParagraphStrValue(obj);
    			Set<String> jsons = getMatchStr("\\{(\"\\w+\":\"?\\w+\"?,*){1,}\\}", 
    					StringUtil.replace(text, CN_CHARS, CN_REPLACE_CHARS));
    			if(CollectionUtils.isNotEmpty(jsons)){//不为空则进行分发
    				for (String s : jsons) {
    					DOCJsonObject jsonObject = null;
    					try {
    						jsonObject = new Gson().fromJson(s, DOCJsonObject.class);
    					} catch (Exception e) {
    						e.printStackTrace();
    					}
    					if(jsonObject == null){
    						continue;
    					}else{
    						DocxUtils.replaceChart(obj, imgPath, wordMLPackage);
    					}
    				}
    			}
    		}
    	}
    替换方法见一楼
    getAllElementFromObject方法:
    /*****************************************************************************
    	 * 查找JAXBElement元素
    	 * @param  obj          查找目标
    	 * @param  toSearch     查找类的class
    	 * @return List<Object>
    	 *****************************************************************************/
    	public static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) {
    	    List<Object> result = new ArrayList<Object>();
    	    if (obj instanceof JAXBElement){
    	    	obj = ((JAXBElement<?>) obj).getValue();
    	    }
    	    if (obj.getClass().equals(toSearch)){
    	    	result.add(obj);
    	    }else if (obj instanceof ContentAccessor) {
    		    List<?> children = ((ContentAccessor) obj).getContent();
    		    for (Object child : children) {
    		    	result.addAll(getAllElementFromObject(child, toSearch));
    		    }
    	   }
    	   return result;
       }




    我就想知道,我怎么通过我文档里的一段标示位找到一个对象来替换

    P paragraph = 这里我想找到我要替换的东西;
    wordMLPackage.getMainDocumentPart().addObject(paragraph);

     

    ######

    引用来自“anyine”的答案

    引用来自“bigtiger02”的答案

    你可以用一段文字进行标记,然后查找将这段文字替换成图片即可。
    world操作方法:

    //拷贝文件
    dstUrlTmp = copyFile(modelUrl,dstUrl);
    //开始wordMLPackage = DocxUtils.load(dstUrlTmp);
    document = wordMLPackage.getMainDocumentPart();
    //替换字符串、表格以及图片
    replace(DocxUtils.getAllElementFromObject(document,P.class));
    //保存
    DocxUtils.save(wordMLPackage, dstUrl);
    replace方法:
    //执行替换
    	private void replace(List<Object> paragraphs){
    		final int pSize = paragraphs.size();
    		for (int i = 0; i < pSize; i++) {
    			Object obj = paragraphs.get(i);
    			String text = DocxUtils.getParagraphStrValue(obj);
    			Set<String> jsons = getMatchStr("\\{(\"\\w+\":\"?\\w+\"?,*){1,}\\}", 
    					StringUtil.replace(text, CN_CHARS, CN_REPLACE_CHARS));
    			if(CollectionUtils.isNotEmpty(jsons)){//不为空则进行分发
    				for (String s : jsons) {
    					DOCJsonObject jsonObject = null;
    					try {
    						jsonObject = new Gson().fromJson(s, DOCJsonObject.class);
    					} catch (Exception e) {
    						e.printStackTrace();
    					}
    					if(jsonObject == null){
    						continue;
    					}else{
    						DocxUtils.replaceChart(obj, imgPath, wordMLPackage);
    					}
    				}
    			}
    		}
    	}
    替换方法见一楼
    getAllElementFromObject方法:
    /*****************************************************************************
    	 * 查找JAXBElement元素
    	 * @param  obj          查找目标
    	 * @param  toSearch     查找类的class
    	 * @return List<Object>
    	 *****************************************************************************/
    	public static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) {
    	    List<Object> result = new ArrayList<Object>();
    	    if (obj instanceof JAXBElement){
    	    	obj = ((JAXBElement<?>) obj).getValue();
    	    }
    	    if (obj.getClass().equals(toSearch)){
    	    	result.add(obj);
    	    }else if (obj instanceof ContentAccessor) {
    		    List<?> children = ((ContentAccessor) obj).getContent();
    		    for (Object child : children) {
    		    	result.addAll(getAllElementFromObject(child, toSearch));
    		    }
    	   }
    	   return result;
       }




    我就想知道,我怎么通过我文档里的一段标示位找到一个对象来替换

    P paragraph = 这里我想找到我要替换的东西;
    wordMLPackage.getMainDocumentPart().addObject(paragraph);

     

    我之前的是新添加了一个段落来写入图片 现在我想用文档里面现有的地方来写入图片

    private static P addInlineImageToParagraph(Inline inline) {
            // 添加内联对象到一个段落中
            ObjectFactory factory = new ObjectFactory();
            P paragraph = factory.createP();
            R run = factory.createR();
            paragraph.getContent().add(run);
            Drawing drawing = factory.createDrawing();
            run.getContent().add(drawing);
            drawing.getAnchorOrInline().add(inline);
            return paragraph;
        }


     

    ######可以的,你可以写一个word模版,在需要替换的地方用string标记,比如标记成image,然后用
    DocxUtils.getAllElementFromObject(document,P.class)

    可以读取word里面所有的段落,用

    DocxUtils.getParagraphStrValue(obj);

    可以读取这个段落的字符串,若这个段落的字符串equals("image"),则进行替换

    DocxUtils.replaceChart(obj, imgPath, wordMLPackage);
    ######

    引用来自“bigtiger02”的答案

    可以的,你可以写一个word模版,在需要替换的地方用string标记,比如标记成image,然后用
    DocxUtils.getAllElementFromObject(document,P.class)

    可以读取word里面所有的段落,用

    DocxUtils.getParagraphStrValue(obj);

    可以读取这个段落的字符串,若这个段落的字符串equals("image"),则进行替换

    DocxUtils.replaceChart(obj, imgPath, wordMLPackage);
    DocxUtils.getParagraphStrValue 说了半天我就是不知道你这儿是怎么写的啊,查他的API不知道从哪儿查起


    ######搞定..感谢
    2020-06-07 21:55:28
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
Spring Cloud Alibaba - 重新定义 Java Cloud-Native 立即下载
The Reactive Cloud Native Arch 立即下载
JAVA开发手册1.5.0 立即下载