POI完成从多个word模板到一个报告(word2007)

背景:

         先说一下,作者为什么要选择POI来生成报告。之前项目中使用的是jacob,但是偶尔会出现windows错误提示框,word已停止工作,每次都需要手动关闭这个提示框,才能继续生成报告。虽然说是偶尔发生(大概100次中,会发生一次),但是问题还是要解决的。于是作者就尝试杀进程,虽然错误发生的概率降低了,但是还是会偶有发生。查过很多资料,有你提到jacob这种控件本身也有不稳定的问题(问题是这种错误在程序中没法  try   catch)。于是乎就换掉jacob啦!之前使用的是word2003,发现poi对word2003的支持还是很弱的。于是乎,就采用word2007啦!这是个大胆的决定,之后还会遇到很多想不到的问题。
        作者尝试过 iText,但是好像缺word模板的替换,但是项目中必须要有这个功能;
           soa  office, 还有国内的xxxx office  是要收费的,于是乎放弃使用了;
           docx4j  有篇帖子写的很好,http://blog.csdn.net/zhyh1986/article/details/8766131,但是由于作者先尝试了poi2007,所以没有再尝试使用docx4j。

word2007模板字段和图片的替换

作者使用的是poi3.7版本,这里直接上代码吧。
WordUtil.java
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; 
import java.io.InputStream; 
import java.util.Iterator; 
import java.util.List; 
import java.util.Map; 
import java.util.Map.Entry; 
import org.apache.poi.POIXMLDocument; 
import org.apache.poi.openxml4j.opc.OPCPackage; 
import org.apache.poi.xwpf.usermodel.XWPFParagraph; 
import org.apache.poi.xwpf.usermodel.XWPFRun; 
import org.apache.poi.xwpf.usermodel.XWPFTable; 
import org.apache.poi.xwpf.usermodel.XWPFTableCell; 
import org.apache.poi.xwpf.usermodel.XWPFTableRow;


/**
* 适用于word 2007
* poi 版本 3.7
*/ 
public class WordUtil { 
	  /**
		 * 复制文件
		 * @param fromDocPath
		 * @param toDocPath
		 */
		public void saveTemplate(String fromDocPath,String toDocPath){
			//String url = "/word/template/subproject.doc";
			//String docPath = "c:/template/subproject.doc";
			InputStream fis;
			FileOutputStream fos;
			int bytesum = 0;   
	        int byteread = 0;
			try {
				fis = this.getClass().getResourceAsStream(fromDocPath);
				fos = new FileOutputStream(toDocPath);
				byte[] buffer = new byte[1444]; 
	            while ( (byteread = fis.read(buffer)) != -1) {   
	                bytesum += byteread; //字节数 文件大小  
	                fos.write(buffer, 0, byteread);   
	            }   
	            fis.close(); 
	            fos.close();
			} catch (FileNotFoundException e1) {
				e1.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		public void saveTemplate(InputStream fis,String toDocPath){
			FileOutputStream fos;
			int bytesum = 0;   
	        int byteread = 0;
			try {
				fos = new FileOutputStream(toDocPath);
				byte[] buffer = new byte[1444]; 
	            while ( (byteread = fis.read(buffer)) != -1) {   
	                bytesum += byteread; //字节数 文件大小  
	                fos.write(buffer, 0, byteread);   
	            }   
	            fis.close(); 
	            fos.close();
			} catch (FileNotFoundException e1) {
				e1.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
 
    /**
     * 根据指定的参数值、模板,生成 word 文档
     * @param param 需要替换的变量
     * @param template 模板
     */ 
    public static CustomXWPFDocument generateWord(Map param, String template) { 
        CustomXWPFDocument doc = null; 
        try { 
            OPCPackage pack = POIXMLDocument.openPackage(template); 
            doc = new CustomXWPFDocument(pack); 
            if (param != null && param.size() > 0) { 
                 
                //处理段落 
                List paragraphList = doc.getParagraphs(); 
                processParagraphs(paragraphList, param, doc); 
                 
                //处理表格 
                Iterator it = doc.getTablesIterator(); 
                while (it.hasNext()) { 
                    XWPFTable table = it.next(); 
                    List rows = table.getRows(); 
                    for (XWPFTableRow row : rows) { 
                        List cells = row.getTableCells(); 
                        for (XWPFTableCell cell : cells) { 
                            List paragraphListTable =  cell.getParagraphs(); 
                            processParagraphs(paragraphListTable, param, doc); 
                        } 
                    } 
                } 
            } 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
        return doc; 
    } 
    /**
     * 处理段落
     * @param paragraphList
     */ 
    public static void processParagraphs(List paragraphList,Map param,CustomXWPFDocument doc){ 
        if(paragraphList != null && paragraphList.size() > 0){ 
            for(XWPFParagraph paragraph:paragraphList){ 
                List runs = paragraph.getRuns(); 
                for (XWPFRun run : runs) { 
                    String text = run.getText(0); 
                    if(text != null){ 
                        boolean isSetText = false; 
                        for (Entry 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()); 
                                } 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 { 
                                        int ind = doc.addPicture(byteInputStream,picType); 
                                        doc.createPicture(ind, width , height,paragraph); 
                                    } catch (Exception e) { 
                                        e.printStackTrace(); 
                                    } 
                                } 
                            } 
                        } 
                        if(isSetText){ 
                            run.setText(text,0); 
                        } 
                    } 
                } 
            } 
        } 
    } 
    /**
     * 根据图片类型,取得对应的图片类型代码
     * @param picType
     * @return int
     */ 
    private static 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 in
     * @return
     */ 
    public static byte[] inputStream2ByteArray(InputStream in,boolean isClose){ 
        byte[] byteArray = null; 
        try { 
            int total = in.available(); 
            byteArray = new byte[total]; 
            in.read(byteArray); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        }finally{ 
            if(isClose){ 
                try { 
                    in.close(); 
                } catch (Exception e2) { 
                    System.out.println("关闭流失败"); 
                } 
            } 
        } 
        return byteArray; 
    } 
} 
测试功能:
Test.java
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class Test {
	public static void main(String[] args) throws Exception {  
        
        Map param = new HashMap();  
        param.put("${name}", "小明");  
        param.put("${date}", new Date().toString());  
          
        Map imageMap = new HashMap();  
        imageMap.put("width", 100);  
        imageMap.put("height", 150);  
        imageMap.put("type", "jpg");  
        imageMap.put("content", WordUtil.inputStream2ByteArray(new FileInputStream("c:\\lightningDensityImg_url1480488635791.jpg"), true));  
        param.put("${image}",imageMap);  
          
          
        CustomXWPFDocument doc = WordUtil.generateWord(param, "c:/template.docx");  
        FileOutputStream fopts = new FileOutputStream("c:/report.docx");  
        doc.write(fopts);  
        fopts.close();  
    }  
}
template.docx
POI完成从多个word模板到一个报告(word2007)_第1张图片
report.docx
POI完成从多个word模板到一个报告(word2007)_第2张图片
报告中插入表格
由于word中插入表格的位置没法定位,于是作者将word模板在需要插入表格的位置分开(一个word,分为两个),这样将新生成的word(含表格)合并到之前的两个word中,便实现了插入表格的功能。

生成表格

CreateTablesWithXWPF.java
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
public class CreateTablesWithXWPF
{

    public static void main(String[] args){
    	XWPFDocument document = new XWPFDocument();

		XWPFParagraph para1 =  document.createParagraph();
		XWPFRun run1 = para1.createRun();
		run1.setText("I am Title");
		run1.setBold(true);
		run1.setFontSize( 28 );
		para1.setAlignment( ParagraphAlignment.CENTER );
		
        // New 2x2 table
        XWPFTable tableOne = document.createTable();
        XWPFTableRow tableOneRowOne = tableOne.getRow(0);
        tableOneRowOne.getCell(0).setText("Hello");
        tableOneRowOne.addNewTableCell().setText("World");
 
        XWPFTableRow tableOneRowTwo = tableOne.createRow();
        tableOneRowTwo.getCell(0).setText("This is");
        tableOneRowTwo.getCell(1).setText("a table");
 
        //Add a break between the tables
        document.createParagraph().createRun().addBreak();
        
        
        // New 3x3 table
        XWPFTable tableTwo = document.createTable();
        XWPFTableRow tableTwoRowOne = tableTwo.getRow(0);
        tableTwoRowOne.getCell(0).setText("col one, row one");
        tableTwoRowOne.addNewTableCell().setText("col two, row one");
        tableTwoRowOne.addNewTableCell().setText("col three, row one");
 
        XWPFTableRow tableTwoRowTwo = tableTwo.createRow();
        tableTwoRowTwo.getCell(0).setText("col one, row two");
        tableTwoRowTwo.getCell(1).setText("col two, row two");
        tableTwoRowTwo.getCell(2).setText("col three, row two");
 
        XWPFTableRow tableTwoRowThree = tableTwo.createRow();
        tableTwoRowThree.getCell(0).setText("col one, row three");
        tableTwoRowThree.getCell(1).setText("col two, row three");
        tableTwoRowThree.getCell(2).setText("col three, row three");
 
        FileOutputStream outStream = null;
        try{
            outStream = new FileOutputStream( new File("D:\\demo1.docx") );
        } catch(FileNotFoundException e) {
            e.printStackTrace();
        }
 
        try{
            document.write(outStream);
            outStream.close();
        } catch(FileNotFoundException e) {
            e.printStackTrace();
        } catch(IOException e) {
            e.printStackTrace();
        }

        System.out.println("end of xwpf");
      }
 }
POI完成从多个word模板到一个报告(word2007)_第3张图片

docx4j完成word的合并

Word2007Util.java
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.PartName;
import org.docx4j.openpackaging.parts.WordprocessingML.AlternativeFormatInputPart;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.org.apache.poi.util.IOUtils;
import org.docx4j.relationships.Relationship;
import org.docx4j.wml.CTAltChunk;

public class Word2007Util {
	public void mergeDocx(List list,String path){
		List  inList=new ArrayList();
		  for(int i=0;i streams)  
            throws Docx4JException, IOException {  
  
    WordprocessingMLPackage target = null;  
    final File generated = File.createTempFile("generated", ".docx");  
  
    int chunkId = 0;  
    Iterator it = streams.iterator();  
    while (it.hasNext()) {  
        InputStream is = it.next();  
        if (is != null) {  
            if (target == null) {  
                // Copy first (master) document  
                OutputStream os = new FileOutputStream(generated);  
                os.write(IOUtils.toByteArray(is));  
                os.close();  
  
                target = WordprocessingMLPackage.load(generated);  
            } else {  
                // Attach the others (Alternative input parts)  
                insertDocx(target.getMainDocumentPart(),  
                        IOUtils.toByteArray(is), chunkId++);  
            }  
        }  
    }  
  
    if (target != null) {  
        target.save(generated);  
        return new FileInputStream(generated);  
    } else {  
        return null;  
    }  
}  
  
// 插入文档  
private void insertDocx(MainDocumentPart main, byte[] bytes, int chunkId) {  
    try {  
        AlternativeFormatInputPart afiPart = new AlternativeFormatInputPart(  
                new PartName("/part" + chunkId + ".docx"));  
     //   afiPart.setContentType(new ContentType(CONTENT_TYPE));  
        afiPart.setBinaryData(bytes);  
        Relationship altChunkRel = main.addTargetPart(afiPart);  
  
        CTAltChunk chunk = Context.getWmlObjectFactory().createCTAltChunk();  
        chunk.setId(altChunkRel.getId());  
  
        main.addObject(chunk);  
    } catch (Exception e) {  
        e.printStackTrace();  
    }  
}  

public  void saveTemplate(InputStream fis,String toDocPath){
	FileOutputStream fos;
	int bytesum = 0;   
    int byteread = 0;
	try {
		fos = new FileOutputStream(toDocPath);
		byte[] buffer = new byte[1444]; 
        while ( (byteread = fis.read(buffer)) != -1) {   
            bytesum += byteread; //字节数 文件大小  
            fos.write(buffer, 0, byteread);   
        }   
        fis.close(); 
        fos.close();
	} catch (FileNotFoundException e1) {
		e1.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	}
}
}
测试word合并功能
MyTest.java
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.docx4j.openpackaging.exceptions.Docx4JException;

public class MyTest {
	public static void main(String[] args) throws Docx4JException, IOException{
		Word2007Util wordUtil=new Word2007Util();
		String template="c:/template";
		List list=new ArrayList();
		list.add(template+"/conclusion1482388112517.docx");
		list.add(template+"/1482388076496_conclusion.docx");
		wordUtil.mergeDocx(list, template+"/4.docx");		
   }	
}
docx4j用到的jar包
POI完成从多个word模板到一个报告(word2007)_第4张图片





























你可能感兴趣的:(poi)