天天看點

怎樣自動把報表插入到 word 文檔中

在很多業務場景中需要在 word 文檔中嵌入報表。比如下圖這個報告:

怎樣自動把報表插入到 word 文檔中

這是一個某大學年度畢業生就業報告,其中表格和統計圖的資料來自資料庫,如果通過報表工具,制作這樣的表格和統計圖是輕而易舉的事情,但如果要把這些報表和統計圖做到 word 報告裡就麻煩很多。以往有兩個辦法:一個是每次做好報表和統計圖之後,導出為 word,再手工複制粘貼到 word 報告中;第二個是把整個報告都做成一個報表模闆,然後再一起導出為 word。 方法一,純手工操作效率低;方法二,報表工具排版能力有限,生成的 word 版面效果不夠完美。

那麼,還有什麼好辦法呢?

通常這類報告都有規定的模闆樣式,隻是要定期替換裡面的個别資訊,比如上圖所示的文檔編号,報告時間,标題裡的年度,圖檔,每個章節下的報表和統計圖,這些資訊是動态變化的,而其他文字描述部分以及整體樣式都是固定不變的。是以,如果能把報表嵌入 word 文檔做成流水線式的自動化過程,那就是一件兩全其美,事半功倍的事情。

潤乾報表就提供了把報表嵌入 word 的功能,實作步驟如下:

1、制作 word 模闆,将需要插入内容的位置設定好書簽

怎樣自動把報表插入到 word 文檔中

比如我們開篇看到的大學畢業生就業報告,我們可以先做成如上圖所示的 word 模闆,圖示綠色線框位置就是需要定期更新的部分,預先在這些位置插入書簽(比如書簽名為:編号,時間,logo,年度,報表,統計圖),以此标記要插入到 word 的内容對應插入到什麼位置。

2、制作報表,這一步就不詳述了。

3、調用潤乾報表的 raqsoft.report.view.oxml.word.DocxChanger 裡的方法,将圖檔,文本,報表等内容插入到指定書簽位置,生成新的 word 報告。

 eg:

//设置æ¥è¡¨æææ件
File flic = new File("c:/tmp/report5.lic");
FileInputStream lis = new FileInputStream(flic);
Sequence.readLicense( Sequence.P_RPT, lis);

File f = new File("E:/test.docx");               //模æ¿æ件
File of = new File("D:/out.docx");             //è¾åºæ件
⦠â¦
FileOutputStream fos = new FileOutputStream(of);
DocxChanger dc = new DocxChanger(f, fos); //å®ä¾åDocxChanger

//å¨ä¹¦ç­¾âç¼å·âï¼âæ¶é´âï¼â年度âå¤æå¥æå­
dc.insertText("ç¼å·", "12345678");
dc.insertText("æ¶é´", "20170730");
dc.insertText("年度", "2017");

//å¨ä¹¦ç­¾âlogoâå¤æå¥å¾çæ件
File f1 = new File("d:/logo.png");
dc.insertImage("logo", f1);

//å¨ä¹¦ç­¾âæ¥è¡¨âï¼âç»è®¡å¾âå¤æå¥æ¥è¡¨åç»è®¡å¾
File f2 = new File("d:/æ¯ä¸å»å.rpx");
FileInputStream fis = new FileInputStream(f2);
IReport report = ReportUtils.read(fis);
fis.close();
Context context = new Context();
⦠⦠ 
Engine engine = new Engine((ReportDefine) report, context);
report = engine.calc();
dc.insertReport("æ¥è¡¨", report);

File f3 = new File("d:/çå­¦.rpx");
FileInputStream fis2 = new FileInputStream(f3);
IReport report2 = ReportUtils.read(fis2);
fis2.close();
Context context2 = new Context();
⦠⦠
Engine engine2 = new Engine((ReportDefine) report2, context2);
report2 = engine2.calc();
dc.insertReport("ç»è®¡å¾", report2);

//æ§è¡ææä¿®æ¹å¨ä½ï¼ç¶åå³é­è¾åºæ件æµ
dc.execute();
fos.close(); 
      

//設定報表授權檔案 File flic = new File("c:/tmp/report5.lic"); FileInputStream lis = new FileInputStream(flic); Sequence.readLicense( Sequence.P_RPT, lis); File f = new File("E:/test.docx");               //模闆檔案 File of = new File("D:/out.docx");             //輸出檔案 … … FileOutputStream fos = new FileOutputStream(of); DocxChanger dc = new DocxChanger(f, fos); //執行個體化DocxChanger //在書簽“編号”,“時間”,“年度”處插入文字 dc.insertText("編号", "12345678"); dc.insertText("時間", "20170730"); dc.insertText("年度", "2017"); //在書簽“logo”處插入圖檔檔案 File f1 = new File("d:/logo.png"); dc.insertImage("logo", f1); //在書簽“報表”,“統計圖”處插入報表和統計圖 File f2 = new File("d:/畢業去向.rpx"); FileInputStream fis = new FileInputStream(f2); IReport report = ReportUtils.read(fis); fis.close(); Context context = new Context(); … …  Engine engine = new Engine((ReportDefine) report, context); report = engine.calc(); dc.insertReport("報表", report); File f3 = new File("d:/留學.rpx"); FileInputStream fis2 = new FileInputStream(f3); IReport report2 = ReportUtils.read(fis2); fis2.close(); Context context2 = new Context(); … … Engine engine2 = new Engine((ReportDefine) report2, context2); report2 = engine2.calc(); dc.insertReport("統計圖", report2); //執行所有修改動作,然後關閉輸出檔案流 dc.execute(); fos.close();

至此,word 報告就自動生成了,以後每次隻要執行一遍這段程式就行了,是不是友善了不少?

不過,這個辦法還有個缺點,當插入内容變化時,我們就需要修改 java 代碼,而改了代碼之後又得重編譯部署,難以做到熱切換。這個辦法還是不夠友善。

為此,潤乾報表還提供了外部配置的方法來實作 word 報表,可以預先編輯一個 xml 檔案,在裡面寫個需要替代的書簽等内容,然後程式會讀取這個配置檔案生成相應的 word 文檔。

這樣,當插入内容變化的時候,隻要修改 xml 配置資訊即可,而不用修改代碼再編譯了。我們一起來看一下:

1、編輯配置檔案 xml

該檔案中可配置多個書簽和插入對象,當對象來源于記憶體時,可配置成 map,通過 key 從記憶體中取值,key 值可以是 IReport、byte[]、Image、String,值的類型程式會自動判斷。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- file表示模æ¿docxæ件åï¼å¯éç½®ç»å¯¹è·¯å¾æç¸å¯¹è·¯å¾(web端éç½®æ¶ç¸å¯¹äºraqsoftConfig.xml中çreportFileHome) -->
<docx file="D:/test.doc">
<!-- name表示docx书签ï¼ä¸ºç©ºåä¸ä¼æå¥ã file表示å¾çæ件åï¼å¯éç½®ç»å¯¹è·¯å¾æç¸å¯¹è·¯å¾(web端éç½®æ¶ç¸å¯¹äºraqsoftConfig.xml中çreportFileHome) -->
<bookmark name="logo" type="image" file="D:/logo.png"></bookmark>
<!-- name表示docxä¹¦ç­¾ï¼ textè¦æå¥çææ¬æå­ -->
<bookmark name="ç¼å·" type="text" text="12345678"></bookmark>
<bookmark name="æ¶é´" type="text" text="20170730"></bookmark>
<bookmark name="年度" type="text" text="2017"></bookmark>
<!-- key表示ç»å®map中çkeyï¼æªå¡«æ¶è·nameç¸åï¼å¯¹åºçvalueåªè½æ¯IReportãbyte\[\]ãImageãStringï¼ -->
<bookmark name="ç»è®¡å¾" type="map" key="f"></bookmark>
<!-- reportFile表示æ¥è¡¨æ¨¡æ¿æ件åï¼å¯éç½®ç»å¯¹è·¯å¾æç¸å¯¹è·¯å¾(web端éç½®æ¶ç¸å¯¹äºraqsoftConfig.xml中çreportFileHome) -->
<bookmark name="æ¥è¡¨" type="report" reportFile="D:/æ¯ä¸å»å.rpx">
    <!-- value表示æ¥è¡¨åæ°å¼(串) -->
    <reportParam name="arg1" type="value" value="设å®åæ°1"></reportParam>
    <!-- type为mapæ¶ä¼ä»åå­ä¸­æ ¹æ®name读åkeyï¼keyæªå¡«åæ¶è·nameç¸å,key=ââæ¶ä¼åmap中key为空çå¼ -->
    <reportParam name="arg2" type="map"></reportParam>      
</bookmark>
</docx> 
      

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!-- file表示模闆docx檔案名,可配置絕對路徑或相對路徑(web端配置時相對于raqsoftConfig.xml中的reportFileHome) --> <docx file="D:/test.doc"> <!-- name表示docx書簽,為空則不會插入。 file表示圖檔檔案名,可配置絕對路徑或相對路徑(web端配置時相對于raqsoftConfig.xml中的reportFileHome) --> <bookmark name="logo" type="image" file="D:/logo.png"/> <!-- name表示docx書簽, text要插入的文本文字 --> <bookmark name="編号" type="text" text="12345678"/> <bookmark name="時間" type="text" text="20170730"/> <bookmark name="年度" type="text" text="2017"/> <!-- key表示給定map中的key(未填時跟name相同,對應的value隻能是IReport、byte\[\]、Image、String) --> <bookmark name="統計圖" type="map" key="f"/> <!-- reportFile表示報表模闆檔案名,可配置絕對路徑或相對路徑(web端配置時相對于raqsoftConfig.xml中的reportFileHome) --> <bookmark name="報表" type="report" reportFile="D:/畢業去向.rpx"> <!-- value表示報表參數值(串) --> <reportParam name="arg1" type="value" value="設定參數1"/> <!-- type為map時會從記憶體中根據name讀取key,key未填寫時跟name相同,key=””時會取map中key為空的值 --> <reportParam name="arg2" type="map"/>       </bookmark> </docx>

注:在 web 應用中,如果 web.xml 裡配置了 reportServlet,那麼程式會自動加載 raqsoftconfig.xml,讀取該檔案裡配置的 reportFileHome,資料源資訊,授權檔案等資訊。

2、根據配置資訊生成 Word 文檔

try{
    File of = new File("D:/out.docx");//è¾åºæ件
    ⦠â¦
    FileOutputStream fos = new 
    FileOutputStream(of);

    //å è½½xml,batch.xmlå容å¦ä¸ä¸å°èæ示
    String xmlConfig = DocxChanger.xmlFile2String("D:/batch.xml");

    //å½æå¥ç对象æ¥èªåå­ï¼æ¯å¦IReport对象
    File f4 = new File("d:/çå­¦.rpx");
    FileInputStream fis = new FileInputStream(f4);
    IReport report = ReportUtils.read(fis);
    fis.close();
    Context context = new Context();
    Engine engine = new Engine((ReportDefine) 
    report, context);
    report = engine.calc();

    //å½å¯¹è±¡æ¥æºäºåå­æ¶ï¼å¯éç½®æ map
    HashMap map =new HashMap();
    map.put("f", report);//设置xml中key为fçå¼
    map.put("arg2", "2014-12-15 12:00:23");//å½æå¥å¯¹è±¡æ¥èªåå­ï¼æ¯å¦Stringï¼è®¾ç½®xml中key为arg2çå¼

    DocxChanger.insert(map, xmlConfig, fos);
    fos.close();
}catch(Throwable x) {
    x.printStackTrace();
} 
      

try{ File of = new File("D:/out.docx");//輸出檔案 … … FileOutputStream fos = new FileOutputStream(of); //加載xml,batch.xml内容如上一小節所示 String xmlConfig = DocxChanger.xmlFile2String("D:/batch.xml"); //當插入的對象來自記憶體,比如IReport對象 File f4 = new File("d:/留學.rpx"); FileInputStream fis = new FileInputStream(f4); IReport report = ReportUtils.read(fis); fis.close(); Context context = new Context(); Engine engine = new Engine((ReportDefine) report, context); report = engine.calc(); //當對象來源于記憶體時,可配置成 map HashMap map =new HashMap(); map.put("f", report);//設定xml中key為f的值 map.put("arg2", "2014-12-15 12:00:23");//當插入對象來自記憶體,比如String,設定xml中key為arg2的值 DocxChanger.insert(map, xmlConfig, fos); fos.close(); }catch(Throwable x) { x.printStackTrace(); }

說了這麼多,大家肯定會覺得理想很豐滿,現實很骨感,這個功能是很完美,确實可以幫我解決這些個棘手的問題,但是都知道報表工具價格昂貴,再加上這樣小奢的功能,豈不是貴上加貴,為此特意買一套昂貴的報表工具,似乎就不劃算了,而開源報表裡面又沒有這個功能。但是你不知道的是,現在報表工具已經低端化了,潤乾率先開始了 5000 元 / 套的低價報表了,恰巧這個功能裡面有,恰巧你還看到了。

繼續閱讀