實現跨平臺Java處理word模板替換,包括標籤替換文字、標籤替換圖片、設置文字樣式、圖片大小,word轉pdf(藉助OpenOffice插件)。html
package com.sdp.utils; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.hwpf.usermodel.Range; import org.apache.poi.xwpf.usermodel.UnderlinePatterns; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; import org.apache.xmlbeans.XmlToken; import org.artofsolving.jodconverter.OfficeDocumentConverter; import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration; import org.artofsolving.jodconverter.office.OfficeManager; 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 org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFonts; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHpsMeasure; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr; import com.jfinal.kit.Prop; import com.jfinal.kit.PropKit; public class PoiWordUtil { private static final String DOC = "doc"; private static final String DOCX = "docx"; private static final String SYSTEM_TYPE_W = "Windows"; private static final String SYSTEM_TYPE_L = "Linux"; private static String errorMsg = ""; private static String templatePath = ""; private static String newFilePath = ""; private static OfficeManager officeManager; /** * 替換模板方法 * @param templateName 模板名稱 * @param params 替換參數 * @return * @throws Exception */ public static Map<String,String> executeWord(String templateName, List<?> params) throws Exception { //獲取模板路徑 getTemplate(templateName); //獲取新文件生成路徑 getFileStore(templateName); //判斷模板類型 if(templatePath.endsWith(DOC)){ //處理03版word replaceWordDoc(params); }else if(templatePath.endsWith(DOCX)){ //處理07版word replaceWordDocx(params); } //返回處理結果(新生成文件路徑、錯誤信息) Map<String,String> map = new HashMap<String,String>(); map.put("newFilePath", newFilePath); map.put("errorMsg", errorMsg); return map; } /** * 替換模板文本內容(2007) * @param params 替換參數 * @throws Exception */ private static void replaceWordDocx(List<?> params) throws Exception{ InputStream is = new FileInputStream(templatePath); XWPFDocument doc = new XWPFDocument(is); Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator(); XWPFParagraph para; //替換文本 while (iterator.hasNext()) { para = iterator.next(); replaceInParaDocx(doc, para, params); } //寫出文件 OutputStream out = new FileOutputStream(newFilePath); doc.write(out); //關閉輸出流 close(out); } /** * 替換方法(2007) * @param para * @param params * @throws Exception */ @SuppressWarnings("unchecked") private static void replaceInParaDocx(XWPFDocument doc, XWPFParagraph para, List<?> params) throws Exception { List<XWPFRun> runs; Matcher matcher; String imgPath = ""; int width = 0,height = 0; if (matcher(para.getParagraphText()).find()) { runs = para.getRuns(); for (int i=0; i<runs.size(); i++) { XWPFRun run = runs.get(i); String runText = run.toString(); matcher = matcher(runText); if (matcher.find()) { Map<String,Object> infoMap = new HashMap<String,Object>(); while ((matcher = matcher(runText)).find()) { System.err.println("查找替換標籤:" + matcher.group(1)); int index = Integer.valueOf(matcher.group(1)) - 1; if(index >= params.size()) break; if(params.get(index) instanceof Map){ infoMap = (Map<String,Object>)params.get(index); if(infoMap.get("img") != null){ //處理圖片 imgPath = infoMap.get("Path").toString(); width = Integer.parseInt(infoMap.get("Width").toString()); height = Integer.parseInt(infoMap.get("Height").toString()); //若是爲圖片替換空值 runText = matcher.replaceFirst(""); }else{ runText = matcher.replaceFirst(String.valueOf(infoMap.get("Text"))); } }else if(params.get(index) instanceof String){ runText = matcher.replaceFirst(String.valueOf(params.get(index))); } } //直接調用XWPFRun的setText()方法設置文本時,在底層會從新建立一個XWPFRun,把文本附加在當前文本後面, //因此咱們不能直接設值,須要先刪除當前run,而後再本身手動插入一個新的run。 para.removeRun(i); XWPFRun newRun = para.insertNewRun(i); newRun.setText(runText); if(!infoMap.isEmpty()){ //設置字體樣式 setFont(newRun, infoMap); } if(Str.isNotAnyEmpty(imgPath)){ //得到當前CTInline CTInline inline = newRun.getCTR().addNewDrawing().addNewInline(); doc.addPictureData(new FileInputStream(imgPath), 5); insertPicture(doc, inline, width, height); } imgPath = ""; infoMap.clear(); System.err.println("替換"); } } } } /** * 2007字體樣式設置 * @param run * @param param */ private static void setFont(XWPFRun run, Map<String,Object> param) { CTRPr pRpr = null; if (run.getCTR() != null) { pRpr = run.getCTR().getRPr(); if (pRpr == null) { pRpr = run.getCTR().addNewRPr(); } } // 設置字體 if(param.get("Name") != null){ CTFonts fonts = pRpr.isSetRFonts()?pRpr.getRFonts():pRpr.addNewRFonts(); fonts.setAscii(param.get("Name").toString()); fonts.setEastAsia(param.get("Name").toString()); fonts.setHAnsi(param.get("Name").toString()); } //粗體 run.setBold(param.get("Bold")!=null?true:false); //斜體 run.setItalic(param.get("Italic")!=null?true:false); //下劃線 if (param.get("Underline") != null) { run.setUnderline(UnderlinePatterns.SINGLE); } //字體大小 if(param.get("Size") != null){ CTHpsMeasure sz = pRpr.isSetSz() ? pRpr.getSz() : pRpr.addNewSz(); sz.setVal(new BigInteger(param.get("Size").toString())); CTHpsMeasure szCs = pRpr.isSetSzCs() ? pRpr.getSzCs() : pRpr.addNewSzCs(); szCs.setVal(new BigInteger(param.get("Size").toString())); } //字體顏色 if (param.get("Color") != null) { run.setColor(param.get("Color").toString()); } } /** * 插入圖片 * * @param document * @param inline * @param width * @param height * @throws Exception */ public static void insertPicture(XWPFDocument document, CTInline inline,int width, int height) throws Exception { int id = document.getAllPictures().size()-1; final int EMU = 9525; width *= EMU; height *= EMU; String blipId = document.getAllPictures().get(id).getPackageRelationship().getId(); 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; xmlToken = XmlToken.Factory.parse(picXml); 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("IMG_" + id); docPr.setDescr("IMG_" + id); } /** * 替換模板文本內容(2003) * @param params 替換參數 * @throws Exception */ private static void replaceWordDoc(List<?> params) throws Exception{ InputStream is = new FileInputStream(templatePath); HWPFDocument doc = new HWPFDocument(is); Range bodyRange = doc.getRange(); //替換文本 replaceInParaDoc(bodyRange, params); //輸出新文件 FileOutputStream out = new FileOutputStream(newFilePath); doc.write(out); out.flush(); //關閉輸出流 out.close(); } /** * 替換方法(2003) * @param range * @param params */ @SuppressWarnings("unchecked") private static void replaceInParaDoc(Range range, List<?> params) { Matcher matcher; while ((matcher = matcher(range.text())).find()) { int index = Integer.valueOf(matcher.group(1)) - 1; if(index >= params.size()) break; if(params.get(index) instanceof String){ range.replaceText(matcher.group(), String.valueOf(params.get(index))); }else if(params.get(index) instanceof Map){ Map<String,Object> infoMap = (Map<String,Object>)params.get(index); range.replaceText(matcher.group(), String.valueOf(infoMap.get("Text"))); } } } /** * 正則匹配字符串 * @param str 帶替換字符串 * @return */ private static Matcher matcher(String str) { Pattern pattern = Pattern.compile("\\{(.+?)\\}", Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(str); return matcher; } /** * 獲取文件模板路徑 * @param templateName 模板文件名稱 * @return * @throws IOException */ private static void getTemplate(String templateName) throws Exception { String path = JacobWordUtil.class.getClassLoader().getResource("word-template").getPath(); String docPath = path + templateName + ".doc"; String docxPath = path + templateName + ".docx"; if(new File(docPath).exists()){ templatePath = docPath; }else if(new File(docxPath).exists()){ templatePath = docxPath; }else{ System.err.println("docPath:" + docPath); System.err.println("docxPath:" + docxPath); errorMsg = "模板文件不存在"; } } /** * 獲取文件存儲路徑 * @param templateName 模板文件名稱 * @return * @throws IOException */ private static void getFileStore(String templateName) throws IOException { Prop propFile = PropKit.use("fileserver.properties"); //操做系統類型(Windows、Linux) String sysType = propFile.get("fileserver.system.type"); //文件存儲跟目錄 String fileRoot = propFile.get("fileserver.local.root"); //文件生產目錄 String fileStore = propFile.get("fileserver.store"); //生成文件名稱 String name = templateName + "_" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); if(SYSTEM_TYPE_W.equals(sysType)){ //Windows newFilePath = fileRoot + fileStore + "/" + templateName + "/"; }else if(SYSTEM_TYPE_L.equals(sysType)){ //Linux newFilePath = File.separator + "usr/fileserver/"; }else{ //其餘服務器系統處理 } //生成目錄不存在建立目錄 File file = new File(newFilePath); if(!file.exists()){ file.mkdirs(); } newFilePath = newFilePath + name + ".doc"; } /** * word文件轉PDF文件 * * @param sfileName 待轉word文件 * @param toFileName pdf保存路徑 * @throws Exception */ public static void wordToPDF(String sfileName,String toFileName) throws Exception{ //打開服務 startService(); OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager); //開始轉換 converter.convert(new File(sfileName),new File(toFileName)); //關閉 stopService(); } /** * 啓動openOffice服務 * @throws Exception */ private static void startService() throws Exception { Prop propFile = PropKit.use(Bs.Prop.BS_FILESERVER); DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration(); configuration.setOfficeHome(propFile.get("bs.openoffice.server.dir"));//設置安裝目錄 configuration.setPortNumbers(8100); //設置端口 configuration.setTaskExecutionTimeout(1000 * 60 * 5L); configuration.setTaskQueueTimeout(1000 * 60 * 60 * 24L); officeManager = configuration.buildOfficeManager(); officeManager.start(); //啓動服務 } /** * 關閉openOffice服務 */ private static void stopService(){ if (officeManager != null) { officeManager.stop(); } } /** * 關閉輸出流 * @param os */ public static void close(OutputStream os) { if (os != null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * 關閉輸入流 * @param os */ public static void close(InputStream in) { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } }
調用示例:java
public static void main(String[] args) { /**圖片替換參數(圖片參數均爲必傳參數)**/ Map<String,Object> map = new HashMap<String,Object>(); map.put("img", true); map.put("Width", 30); map.put("Height", 40); map.put("Path", "D:\\wyh.png"); /**帶格式字符替換參數**/ Map<String,Object> mapF = new HashMap<String,Object>(); mapF.put("Text", "地址:張川縣竹園鎮"); mapF.put("Name", "華文隸書"); //字體 mapF.put("Bold", true); //粗體 mapF.put("Italic", true); //斜體 mapF.put("Underline", true); //下劃線 mapF.put("Color", "FF0000"); //顏色(例如紅s色:FF0000) mapF.put("Size", 26); //字體大小 /**無格式字符替換參數**/ List<Object> params = Lists.newArrayList(); params.add("李四"); params.add("610321000000111111"); params.add(mapF); //備註:模板名稱test.docx PoiWordUtil.executeWord("test", params); }
相關jar包、模板文件下載地址:https://pan.baidu.com/s/1dGqVHVb 密碼:5a39apache
OpenOffice插件下載地址:http://www.openoffice.org/download/index.html服務器