1. 程式人生 > >Java多種方式動態生成doc文件

Java多種方式動態生成doc文件

本來是要在Android端生成doc的(這需求...),最後方法沒有好的方法能夠在Android上做到完美,最後還是隻能搬遷到伺服器。不浪費,還是記錄下各框架不支援Android的原因以及他們的特點。Java相關的這類框架還是很多的,有幾個還不錯,可惜要麼不支援Android,要麼要收費還價格不低。

經過親自測試,Android不支援Java的awt很多包不能直接在Android上用,FreeMarker挺不錯的,能生成複雜漂亮的doc,可惜不支援Android。用POI在Android上能執行,但是一路因為版本,格式等走了很多坑,用WFS開啟還是亂碼。Jword、Aspose.word能完美支援,Jword試用期只有30天兩者收費都不菲。itext沒有測試,不過聽說也不支援Android。

方法一:freemarker

該方法需要先手動建立一個doc模板(圖片記得使用佔位符),並儲存為xml檔案。通過動態替換特定標籤${}中的內容生成。example:

先上效果圖:

複製程式碼
public class DocUtil {
    public Configuration configure=null;
    
    public DocUtil(){
        configure=new Configuration(Configuration.VERSION_2_3_22);
        configure.setDefaultEncoding("utf-8");
    }
    
/** * 根據Doc模板生成word檔案 * @param dataMap 需要填入模板的資料 * @param downloadType 檔名稱 * @param savePath 儲存路徑 */ public void createDoc(Map<String,Object> dataMap,String downloadType,String savePath){ try { //載入需要裝填的模板 Template template=null;
//設定模板裝置方法和路徑,FreeMarker支援多種模板裝載方法。可以重servlet,classpath,資料庫裝載。 //載入模板檔案,放在testDoc下 configure.setClassForTemplateLoading(this.getClass(), "/testDoc"); //設定物件包裝器 // configure.setObjectWrapper(new DefaultObjectWrapper()); //設定異常處理器 configure.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER); //定義Template物件,注意模板型別名字與downloadType要一致 template=configure.getTemplate(downloadType+".xml"); File outFile=new File(savePath); Writer out=null; out=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8")); template.process(dataMap, out); out.close(); } catch (IOException e) { e.printStackTrace(); } catch (TemplateException e) { e.printStackTrace(); } } public String getImageStr(String imgFile){ InputStream in=null; byte[] data=null; try { in=new FileInputStream(imgFile); data=new byte[in.available()]; in.read(data); in.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } BASE64Encoder encoder=new BASE64Encoder(); return encoder.encode(data); } }
複製程式碼複製程式碼
public class TestDoc {
    public static void main(String[] args) {
        DocUtil docUtil=new DocUtil();
        Map<String, Object> dataMap=new HashMap<String, Object>();
        dataMap.put("name", "Joanna");
        dataMap.put("examNum", "111111111111");
        dataMap.put("IDCard", "222222222222222222");
        dataMap.put("carModel", "C1");
        dataMap.put("drivingSchool", "測試駕校");
        dataMap.put("busyType", "初次申領");
        dataMap.put("examDate", "2016-03-10");
        dataMap.put("orderCount", "第1次");
        dataMap.put("userImg1", docUtil.getImageStr("D:\\Img\\userImg1.png"));
        dataMap.put("userImg2", docUtil.getImageStr("D:\\Img\\userImg2.png"));
        dataMap.put("firstExamTime", "12:41:17-12:44:38");
        dataMap.put("firstExamScores", "0分,不及格");
        dataMap.put("firstDeductItem", "12:44:15 20102 1號倒車入庫,車身出線 扣100分");
        dataMap.put("firstPic1", docUtil.getImageStr("D:\\Img\\firstPic1.png"));
        dataMap.put("firstPic2", docUtil.getImageStr("D:\\Img\\firstPic2.png"));
        dataMap.put("firstPic3", docUtil.getImageStr("D:\\Img\\firstPic3.png"));
        dataMap.put("secondExamTime", "12:46:50-13:05:37");
        dataMap.put("secondExamScores", "90分,通過");
        dataMap.put("secondDeductItem", "");
        dataMap.put("secondPic1", docUtil.getImageStr("D:\\Img\\secondPic1.png"));
        dataMap.put("secondPic2", docUtil.getImageStr("D:\\Img\\secondPic2.png"));
        dataMap.put("secondPic3", docUtil.getImageStr("D:\\Img\\secondPic3.png"));
        docUtil.createDoc(dataMap, "baseDoc", "D:\\yanqiong.doc");
    }
}
複製程式碼

xml檔案太長,就不貼了...

補充關於動態顯示list以及換行的問題

需求明確到:在上面的扣分項中,如果我有幾條扣分項,我希望每顯示一條換行。

直接在要顯示的內容上加換行符,並沒有什麼效果,起不到換行的作用。

其中在加ftl標籤時,如<#list></list>,就會出現一些問題,在xml中並不識別,導致專案不能執行。

解決:

在需要顯示多條扣分項的位置加,並加換行符:

<#list firstDeductItem as firstItem> 
     <w:t>${firstItem}</w:t><w:br/>
</#list>

TestDoc.java中改為:

List<String> Strs=new ArrayList<String>();
Strs.add("1111111111111111111");
Strs.add("222222222222222");
Strs.add("333333333333333");
dataMap.put("firstDeductItem", Strs);

DocUtil.java中改為:

//定義Template物件,注意模板型別名字與downloadType要一致
template=configure.getTemplate(downloadType+".ftl");

此時xml檔案會報錯,當然也不能編譯執行專案,需要將.xml檔案改為.ftl檔案儲存。再編譯執行,效果圖:

方法二:POI

用這個方法遇到了很多版本問題,這裡是基於POI3.7+Word2007的,測試能夠完美執行。

你需要用Word2007手動生成文件模板(用其他的生成會報錯:無法開啟檔案),並用${}替換需要動態更新的內容,與上面類似,但是不需要你儲存為xml文件格式了。

複製程式碼
/**
 * 自定義XWPFDocument,並重寫createPicture()方法
 * @author Joanna.Yan
 *
 */
public class CustomXWPFDocument extends XWPFDocument{
    public CustomXWPFDocument(InputStream in) throws IOException{
        super(in);
    }
    public CustomXWPFDocument(){
        super();
    }
    public CustomXWPFDocument(OPCPackage pkg) throws IOException{
        super(pkg);
    }
    public void createPicture(int id,int width,int height,XWPFParagraph paragraph){
        final int EMU=9525;
        width *=EMU;
        height *=EMU;
        String blipId=((POIXMLDocumentPart) getAllPictures().get(id)).getPackageRelationship().getId(); 
        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 e) {
            e.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("測試");
    }
}
複製程式碼複製程式碼
/**
 * 適用於word 2007
 * poi版本 3.7
 * @author Joanna.Yan
 *
 */
public class WordUtil {
    
    public static 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 (IOException e) {
            e.printStackTrace();
        }
        return doc;
    }
    
    /**
     * 處理段落
     * @param paragraphList
     * @param param
     * @param doc
     */
    public static 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());
                                }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 (InvalidFormatException e) {
                                        e.printStackTrace();
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }  
                                }
                            }
                        }
                        if(isSetText){
                            run.setText(text, 0);
                        }
                    }
                }
            }
        }
    }
    
    /**
     * 根據圖片型別獲取對應的圖片型別程式碼
     * @param picType
     * @return
     */
    public 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;
    }
}
複製程式碼複製程式碼
public class TestPoi {

    public static void main(String[] args) throws IOException {
        Map<String, Object> param=new HashMap<String, Object>();
        param.put("${name}", "Joanna.Yan");
        param.put("${examNum}", "000000000001");
        param.put("${IDCard}", "111111111111111111");
        param.put("${carModel}", "C1");
        CustomXWPFDocument doc=WordUtil.generateWord(param, "D:\\joanna.docx");
        FileOutputStream fopts = new FileOutputStream("D:\\yan.docx"); 
        doc.write(fopts);  
        fopts.close(); 
    }
}
複製程式碼

相關推薦

Java多種方式動態生成doc

本來是要在Android端生成doc的(這需求...),最後方法沒有好的方法能夠在Android上做到完美,最後還是隻能搬遷到伺服器。不浪費,還是記錄下各框架不支援Android的原因以及他們的特點。Java相關的這類框架還是很多的,有幾個還不錯,可惜要麼不支援Android

Java 實現後臺生成doc

最近公司需要後臺報告自動生成,就查了一些實現方式。 最初想生成PDF報告,Freemark + Itext + flying saucer 可以實現,但是生成的PDF文件,後續不易修改。 就改為生成word文件,找到了java兩種實現方式 1.freemark  2. p

JAVA通過模板生成DOC

將word文件另存為xml檔案 接下來,上面寫的拼音就起到作用了. 開啟xml檔案.搜尋 要替換的內容. 改為 ${內容} 改完後,把檔案的字尾名直接改成ftl。 程式碼: package com.hentor.apps.bestsign.util; i

confd動態生成配置

per clas back git clone nod bsp zookeeper bash build 下載安裝confd $ mkdir -p $GOPATH/src/github.com/kelseyhightower $ git clone https://git

Java KeyStore 用命令生成keystore

格式 認證 什麽 rsa console www 憑證 代碼 直接 1.生成keyStore文件 在命令行下執行以下命令: Shell代碼 收藏代碼 keytool -genkey -validity 36000 -alias www.zlex.org -keyalg R

java項目打包生成MD5

md5 操作 -c 判斷 ava cap 任務 文檔 系統 之所以發出這篇博客,因為我前幾天搞這個問題搞了幾天,各種百度居然都沒有找到相關的案例,雖然很簡單的事件。可是百度博客上面居然都搜不到案例o(* ̄︶ ̄*)o覺得奇怪!!! 新總監來了,項目要上線

C# 動態生成word

本文以一個簡單的小例子,簡述利用C#語言開發word表格相關的知識,僅供學習分享使用,如有不足之處,還請指正。 在工程中引用word的動態庫 在專案中,點選專案名稱右鍵-->管理NuGet程式包,開啟NuGet包管理器視窗,進行搜尋下載即可,如下圖所示: 涉及知識點 _Applicat

動態生成Word

在某些情況下,使用者想動態生成一個內容無法預知的公文,換句話說,就是無法事先準備一個固定格式的模板,這種情況就需要開發人員完全用編碼實現從零到圖文並茂的Word文件的動態生成功能了。這裡的“零”指的就是Word空白文件。 那如何實現Word文件的從無到有呢,下面我就把自己實現這一功能的過程介紹一

Java根據Word模板生成Word(Freemarker實現)

public class WordExportUtil { private static Configuration configuration; static { configuration = new Configuration(); configur

Aspose.Words for .NET動態生成word中的圖片或水印

1、概述   在專案中生成word文件,這個功能很普遍的,一般生成都是純文字或是列表的比較多,便於客戶列印,而要把圖片也生成到word文件中的需求有些客戶也是需要的,例如產品圖片。這次我們介紹的是如何利用Aspose.Words for .NET在Word中動態的生成圖

Java實現HTML程式碼生成PDF

1、IText實現html2pdf,速度快,糾錯能力差,支援中文(要求HTML使用unicode編碼),但中支援一種中文字型,開源。 2、Flying Sauser實現html2pdf,糾錯能力差,支援多種中文字型(部分樣式不能識別),開源。 3、PD4ML實現h

java後臺利用模板生成Word提供前臺下載

----------------------------------------------------------------------------------------------------------------------------------------

C#也能動態生成Word並填充資料, 匯出EXCEL 方法

        public string CreateWordFile(string CheckedInfo)         ...{             string message = "";             try             ...{                 Ob

Java解析XML與生成XML

mysq for 二進制 根據 port des void pub pack XML是eXtensible Markup Language(可擴展標記語言)的簡寫形式,它是一種元標記語言(meta-markup language),也就是說它沒有一套能夠適用於各個領域中所

java根據ftl模板生成word(列表)

1、在專案開發中很多時候我們要做的事匯出資料列表,那麼如果使用freemarker的時候,list也是不會少的 <#list datelist ?sort_by("name") as data>//根據name排序 reverse為降序 <#list

java利用Freemarker模板生成格式友好的doc(這種方式不支援docx)

近期做專案需要生成複雜的帶格式的word文件,選擇過poi和itext來寫文件,發現文件生成沒問題,但是格式不好調,後來就想要利用freemarker模板來生成,效果還可以,今天就貼出來。 主要分為

POI以SAX方式解析Excel2007大(包含空單元格的處理) Java生成CSV實例詳解

arraylist api csdn false gif pac apache all top http://blog.csdn.net/l081307114/article/details/46009015 http://www.cnblogs.com/dreammyl

Java Web 生成Word(freemarker方式

首先在pom檔案中加入下面這個依賴(不是Maven專案的話,把jar包匯入專案即可) <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</ar

java 生成 xml

new output org enc class 註意 created ear str   解析會了,那接著來學學生成~   同樣的引入依賴: import java.io.File; import java.io.FileOutputStream; import or

java.io幾種讀寫方式

同事 com pan 語言 格式 str 字節流 get 實用 一、Java把這些不同來源和目標的數據都統一抽象為數據流。   Java語言的輸入輸出功能是十分強大而靈活的。   在Java類庫中,IO部分的內容是很龐大的,因為它涉及的領域很廣泛:標準輸入輸出,文件的操作,