模板制作
制作word模版,${xxxx}是要替换的内容。注意${xxxx}是一个整体,中间不能断开,因为利用 poi 的API程序操作时,判断是否有这个${xxxx}才进行替换。

依赖的包
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.15</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.15</version> </dependency>
操作 docx 文件
POI在读写word docx文件时是通过xwpf模块来进行的,其核心是XWPFDocument。一个XWPFDocument代表一个docx文档,其可以用来读docx文档,也可以用来写docx文档。XWPFDocument中主要包含下面这几种对象:
- XWPFParagraph:代表一个段落。
- XWPFRun:代表具有相同属性的一段文本。
- XWPFTable:代表一个表格。
- XWPFTableRow:表格的一行。
- XWPFTableCell:表格对应的一个单元格
具体代码:
/**
* 根据指定的参数值、模板,生成 word 文档
* @param param 需要替换的变量,key值与模板里${xxxx}的xxx一样
* @param template 模板,docx文档
*/
public CustomXWPFDocument generateWord(Map<String, Object> param, String template) {
CustomXWPFDocument doc = null;
try {
OPCPackage pack = POIXMLDocument.openPackage(template);
doc = new CustomXWPFDocument(pack);
if (param != null && param.size() > 0) {
//处理段落
List<XWPFParagraph> paragraphList = doc.getParagraphs();
processParagraphs(paragraphList, param, 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();
processParagraphs(paragraphListTable, param, doc);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return doc;
}
/**
* 处理段落
* @param paragraphList
*/
public void processParagraphs(List<XWPFParagraph> paragraphList,Map<String, Object> param,CustomXWPFDocument doc){
if(paragraphList != null && paragraphList.size() > 0){
for(XWPFParagraph paragraph : paragraphList){
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
String text = run.getText(0);
if(text != null){
boolean isSetText = false;
for (Entry<String, Object> entry : param.entrySet()) {
String key = "${"+ entry.getKey() +"}";
if(text.indexOf(key) != -1){
isSetText = true;
Object value = entry.getValue();
if (value instanceof String) {//文本替换
text = text.replace(key, value.toString());
//System.out.println(text);
} else if (value instanceof Double) {
text = text.replace(key, value.toString());
} else if (value instanceof Map) {//图片替换
text = text.replace(key, "");
Map pic = (Map)value;
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 {
String ind = doc.addPictureData(byteInputStream, picType);
int id = doc.getNextPicNameNumber(picType);
createPicture(id, ind, width , height, run);
//System.out.println("图片替换");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
if(isSetText){
run.setText(text,0);
}
}
}
}
}
}
/** * 根据图片类型,取得对应的图片类型代码 * @param picType * @return int */ private 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 id * @param width 宽 * @param height 高 * @param run 段落 */ public void createPicture(int id, String blipId, int width, int height,XWPFRun run) { final int EMU = 9525; width *= EMU; height *= EMU; CT inline inline = run.getCTR().addNewDrawing().addNewInline(); String picXml = "" + "<a:graphic xmlns:a="">" + " <a:graphicData uri="">" + " <pic:pic xmlns:pic="">" + " <pic:nvPicPr>" + " <pic:cNvPr id="" + id + "" name="Generated"/>" + " <pic:cNvPicPr/>" + " </pic:nvPicPr>" + " <pic:blipFill>" + " <a:blip r:embed="" + blipId + "" xmlns:r=""/>" + " <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("测试"); }
输出docx文档
把返回的XWPFDocument写入到对应的流中。
FileOutputStream fopts = new FileOutputStream("E://andy.docx"); doc.write(fopts);
转pdf文档
相关包的依赖:
<dependency> <groupId>fr.opensagres.xdocreport</groupId> <artifactId>fr.opensagres.poi.xwpf.converter.core</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>fr.opensagres.xdocreport</groupId> <artifactId>fr.opensagres.poi.xwpf.converter.pdf</artifactId> <version>2.0.1</version> </dependency>
把XWPFDocument转成PDF:
FileOutputStream fopts = new FileOutputStream(new FIle("E://andy.pdf")); PdfOptions options = PdfOptions.create(); options.fontProvider(new IFontProvider() { @Override public Font getFont(String s, String s1, float v, int i, Color color) { try { BaseFont bfChinese = BaseFont.createFont(rootPath + "wordtemplate/simsun.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); Font fontChinese = new Font(bfChinese, v, i, color); if (s != null) { fontChinese.setFamily(s); } return fontChinese; } catch (Exception e) { e.printStackTrace(); return null; } } }); PdfConverter.getInstance().convert(doc, fopts, options);
其中doc就是要转的XWPFDocument。simsun.ttf 是字体文件。
最后测试后模板的处理结果:
