赞
踩
最近做的项目,需要将一些信息导出到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(); //换行
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。