java POI导出多张图片到表格(占位符方式)

4 篇文章 0 订阅

        最近做的项目,需要将一些信息导出到word中。在网上找了好多解决方案,现在将这几天的总结分享一下。

        目前来看,java导出word大致有6种解决方案:

1:Jacob是Java-COM Bridge的缩写,它在Java与微软的COM组件之间构建一座桥梁。使用Jacob自带的DLL动态链接库,并通过JNI的方式实现了在Java平台上对COM程序的调用。DLL动态链接库的生成需要windows平台的支持。该方案只能在windows平台实现,是其局限性。

2:Apache POI包括一系列的API,它们可以操作基于MicroSoft OLE 2 Compound Document Format的各种格式文件,可以通过这些API在Java中读写Excel、Word等文件。他的excel处理很强大,对于word还局限于读取,目前只能实现一些简单文件的操作,不能设置样式。

3:Java2word是一个在java程序中调用 MS Office Word 文档的组件(类库)。该组件提供了一组简单的接口,以便java程序调用他的服务操作Word 文档。 这些服务包括: 打开文档、新建文档、查找文字、替换文字,插入文字、插入图片、插入表格,在书签处插入文字、插入图片、插入表格等。填充数据到表格中读取表格数据 ,1.1版增强的功能: 指定文本样式,指定表格样式。如此,则可动态排版word文档。是一种不错的解决方案。

4:iText是著名的开放源码的站点sourceforge一个项目,是用于生成PDF文档的一个java类库。通过iText不仅可以生成PDF或rtf的文档,而且可以将XML、Html文件转化为PDF文件。功能强大。

5:JSP输出样式,该方案实现简单,但是处理样式有点缺陷,简单的导出可以使用。

6:用XML做。Word从2003开始支持XML格式,大致的思路是先用office2003或者2007编辑好word的样式,然后另存为xml,将xml翻译为FreeMarker模板,最后用java来解析FreeMarker模板并输出Doc。经测试这样方式生成的word文档完全符合office标准,样式、内容控制非常便利,打印也不会变形,生成的文档和office中编辑文档完全一样。

综合以上资料的参考,和网上的一些意见,最后我选择了,第2种用POI做导出方案。

     

     使用POI导出到word,首先你要设置导出的word模板,在要填充的模板中填入表达式,如下图所示。

占位符尽量用英文,并且保证在同一个模板里不重复。

POI的思路就是取到模板文件,然后将数据替换占位符填充模板,生成一个新的word文档。

数据放到一个map里,key就是占位符名字,value如果是文字,就是字符串,如果是图片,还得特殊处理(见下文)

 

	/**
	 * * 读取word模板并替换变量字段
	 * 
	 * @param fileName 模板名
	 * @param contentMap 要替换的内容
	 * @return word的Document
	 * @throws IOException
	 */
	public XWPFDocument replaceDocForDispatch(String fileName, Map<String, Object> contentMap) throws IOException {
		try {
			Map<String, Object> newContentMap = new HashMap<String, Object>();
			Resource filePath = resourceLoader
					.getResource("classpath:config" + System.getProperty("file.separator") + fileName);
			File file = filePath.getFile();
			String path = file.getPath();
			// 读取模板
			CustomXWPFDocument doc = null;
			try {
				OPCPackage pack = POIXMLDocument.openPackage(path);
				doc = new CustomXWPFDocument(pack);
				
				//处理会签,会签里有多个审批意见,领导签名,审批时间
				if(contentMap.containsKey("hq")) {
					List list = (List)contentMap.get("hq");
					List leaderList = getLeaderList();
					for(int i=0;i<list.size();i++) {
						String operator = list.get(i).toString();
						if(leaderList.contains(operator)) {
							Object o = this.getSignImageByAccount(operator);
							list.remove(i);
							list.add(i, o);
						}
					}
				}

				// 处理段落
				List<XWPFParagraph> paragraphList = doc.getParagraphs();
				processParagraphs2(paragraphList, contentMap, doc);
				// 处理表格
				Iterator<XWPFTable> it = doc.getTablesIterator();
				while (it.hasNext()) {
					XWPFTable table = it.next();
					List<XWPFTableRow> rows = table.getRows();
					for (XWPFTableRow row : rows) {
						List<XWPFTableCell> cells = row.getTableCells();
						for (XWPFTableCell cell : cells) {
							List<XWPFParagraph> paragraphListTable = cell.getParagraphs();
							processParagraphs2(paragraphListTable, contentMap, doc);
						}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			return doc;
		} catch (Exception e) {
			return null;
		}
	}
   /**
	 * * 通过人员名字获取对应的签名图片
	 * 
	 * @param fileName 模板名
	 * @param contentMap 要替换的内容
	 * @return word的Document
	 * @throws IOException
	 */
         private Object getSignImageByAccount(String name) {
		String account = dao.selectacountBylastname(name);
		String url = dao.selectpicurlByacount(account);
		// 获取电子签名url异常处理
		try {
			if (url == null) {
				return name;
			}
			else {
				Map<String, Object> imageMap = this.getImageMap(url, 70, 25);
				return imageMap;
			}
		} catch (Exception e) {
			return name;
		}
	}

	/**
	 * 获取图片参数
	 * 
	 * @param url
	 * @param width
	 * @param height
	 * @return
	 * @throws IOException
	 */
	private Map<String, Object> getImageMap(String url, int width, int height) throws IOException {
		Map<String, Object> imageMap = new HashMap<String, Object>();
		imageMap.put("width", width);
		imageMap.put("height", height);
		imageMap.put("type", "jpg");
		imageMap.put("content", CustomXWPFDocument.inputStream2ByteArray(new FileInputStream(url), true));

		return imageMap;
	}
	/**
	 * 处理段落
	 * 
	 * @param paragraphList
	 */
	public static void processParagraphs2(List<XWPFParagraph> paragraphList, Map<String, Object> param,
			CustomXWPFDocument doc) {
		List leaderList = getLeaderList();
		
		if (paragraphList != null && paragraphList.size() > 0) {
			for (XWPFParagraph paragraph : paragraphList) {
				List<XWPFRun> runs = paragraph.getRuns();
				for (int i = 0; i < runs.size(); i++) {
					XWPFRun run = runs.get(i);
					String text = run.getText(0);
					if (text != null&¶m.containsKey(text)) {
						Object value = param.get(text);
						
						if (value instanceof String) {// 文本替换
							text = value.toString();
							run.setText(text,0);
						} else if (value instanceof List) {
							run.setText("",0);
							List list = (List)value;
							for(int j=0;j<list.size();j++) {
								Object o = list.get(j);
								if(o instanceof String) {
									XWPFRun run1 = paragraph.createRun();
									run1.setText(o.toString());
									run1.setFontSize(run.getFontSize());
									run1.setFontFamily(run.getFontFamily());
									run1.setBold(run.isBold());
									run1.addTab();
								}
								else if (o instanceof Map) {// 图片替换
									creactPic(doc,paragraph,(Map)o);
									
								}
								if(j%3==0&&j!=0) {
									XWPFRun run1 = paragraph.createRun();
									run1.addBreak();
								}
							}
						}
					}
				}
			}
		}
	}
	/**
	 * 添加图片
	 * @param map
	 */
	private static void creactPic(CustomXWPFDocument doc,XWPFParagraph paragraph,Map picParam) {
		Map pic = (Map) picParam;
		int width = Integer.parseInt(pic.get("width").toString());
		int height = Integer.parseInt(pic.get("height").toString());
		byte[] byteArray = (byte[]) pic.get("content");
		ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);
		try {
			String ind = doc.addPictureData(byteInputStream, 5);
			int id = doc.getAllPictures().size() - 1;
			doc.createPicture(id, width, height, paragraph, ind);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

在表格里写图片的关键方法是createPicture

 

 

    /**
     * @param id
     * @param width  宽
     * @param height  高
     * @param paragraph  段落
     * @param blipId
     */
    public void createPicture(int id,int width, int height, XWPFParagraph paragraph,String blipId) {
		final int EMU = 9525;
		width *= EMU;
		height *= EMU;
		CTInline inline = paragraph.createRun().getCTR().addNewDrawing().addNewInline();
		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);
    }

图片被替换后效果如下:

 



 word的模型是
整个是一个document
然后里面有多很多个paragraph,
段落
段落和段落之间按照回车换行分割

每一段内,又可以有多个range,如果是文字,就放入XWPFRun里,然后run1.setText(o.toString());

还可以设置字体,大小,对齐方式,空格,换行

 

run1.setFontSize(run.getFontSize());
run1.setFontFamily(run.getFontFamily());
run1.setBold(run.isBold());
run1.addTab();   
run1.addBreak();   //换行
  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值