Android使用模板生成支持手機(jī)直接查看的Word文檔
最近在項目工作中,碰到一個很棘手的需求,說是要在手機(jī)端根據(jù)模板生成word文檔,而且不借助第三方的軟件可以查看word文檔,一開始聽這個需求差不多蒙了,這要怎么做,為什么不把生成word文檔這個工作放在后臺呢,抱怨歸抱怨,但是面對需求只能硬著頭皮做了,經(jīng)過各種拷問度娘和谷哥,終于找了一個比較好用的方法。特此跟他家分享。
Apache 公司推出的 Apache POI,我們來看下他的介紹:Apache POI 是用Java編寫的免費(fèi)開源的跨平臺的 Java API,Apache POI提供API給Java程式對Microsoft Office格式檔案讀和寫的功能。
廢話少說開始編碼,首先我們要下Apache POI的開發(fā)jar包,下載地址,這里推薦不要下最新版本的,因為一開始我用最新版本的會出一下莫名其妙的問題,后面換舊的版本就OK了。這里我用的是3.9的還是比較穩(wěn)定的、
開發(fā)有2個包,有一點(diǎn)我就非常郁悶Apache居然沒有提供api穩(wěn)定,開發(fā)起來還是比較難受,可能是我自己沒有找到把,如果有知道的筒子可以@我、嘿嘿。不過Apache還是提供了Demo大家可以參考。還有我們要準(zhǔn)備我們使用的word模板文件、這里我們放在了assets下面了。首先我們來看看怎么使用模板:
package com.test.poiword; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; import com.test.poiword.utils.FileUtils; import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.hwpf.usermodel.Range; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; public class MainActivity extends Activity { // 模板文集地址 private static final String demoPath = "/mnt/sdcard/doc/test.doc"; // 創(chuàng)建生成的文件地址 private static final String newPath = "/mnt/sdcard/doc/testS.doc"; private Button btn,btns; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn=(Button)findViewById(R.id.btn); btns=(Button)findViewById(R.id.btns); btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { try { InputStream inputStream = getAssets().open("test.doc"); FileUtils.writeFile(new File(demoPath), inputStream); } catch (Exception e) { e.printStackTrace(); } doScan(); } }); btns.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { Intent intent = new Intent(MainActivity.this,WordHtmlActivity.class); startActivity(intent); } }); } private void doScan(){ //獲取模板文件 File demoFile=new File(demoPath); //創(chuàng)建生成的文件 File newFile=new File(newPath); Map<String, String> map = new HashMap<String, String>(); map.put("$QYMC$", "xxx科技股份有限公司"); map.put("$QYDZ$", "上海市楊浦區(qū)xx路xx號"); map.put("$QYFZR$", "張三"); map.put("$FRDB$", "李四"); map.put("$CJSJ$", "2000-11-10"); map.put("$SCPZMSJWT$", "5"); map.put("$XCJCJBQ$", "6"); map.put("$JLJJJFF$", "7"); map.put("$QYFZRQM$", "張三"); map.put("$CPRWQM$", "趙六"); map.put("$ZFZH$", "100001"); map.put("$BZ$", "無"); writeDoc(demoFile,newFile,map); //查看 doOpenWord(); } /** * 調(diào)用手機(jī)中安裝的可打開word的軟件 */ private void doOpenWord(){ Intent intent = new Intent(); intent.setAction("android.intent.action.VIEW"); intent.addCategory("android.intent.category.DEFAULT"); String fileMimeType = "application/msword"; intent.setDataAndType(Uri.fromFile(new File(newPath)), fileMimeType); try{ MainActivity.this.startActivity(intent); } catch(ActivityNotFoundException e) { //檢測到系統(tǒng)尚未安裝OliveOffice的apk程序 Toast.makeText(MainActivity.this, "未找到軟件", Toast.LENGTH_LONG).show(); //請先到www.olivephone.com/e.apk下載并安裝 } } /** * demoFile 模板文件 * newFile 生成文件 * map 要填充的數(shù)據(jù) * */ public void writeDoc(File demoFile ,File newFile ,Map<String, String> map) { try { FileInputStream in = new FileInputStream(demoFile); HWPFDocument hdt = new HWPFDocument(in); // Fields fields = hdt.getFields(); // 讀取word文本內(nèi)容 Range range = hdt.getRange(); // System.out.println(range.text()); // 替換文本內(nèi)容 for(Map.Entry<String, String> entry : map.entrySet()) { range.replaceText(entry.getKey(), entry.getValue()); } ByteArrayOutputStream ostream = new ByteArrayOutputStream(); FileOutputStream out = new FileOutputStream(newFile, true); hdt.write(ostream); // 輸出字節(jié)流 out.write(ostream.toByteArray()); out.close(); ostream.close(); } catch(IOException e) { e.printStackTrace(); } catch(Exception e) { e.printStackTrace(); } } }
上面代碼的代碼并不多,首先我們要注意的是我們使用的poi的api大部分是在org.apache.poi.hwpf下面的,大家不要導(dǎo)錯包了,因為apache每個包對應(yīng)的內(nèi)容不同:
上面代碼不難懂,就是把我們要放的內(nèi)容使用特定的代號組裝一個map塞到我們的模板里面去,然后重新存儲下,不過我們模板也要使用相同的代號、poi才能識別:
這樣我們就使用模板大功告成了,就可以查看了、但是有些手機(jī)并沒有裝wps類似的工具,要是手機(jī)可以直接查看那就好了,嘿嘿、當(dāng)然apache肯定也想到了、提供了這樣的api下面上代碼:
package com.test.poiword; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.webkit.WebSettings; import android.webkit.WebView; import com.test.poiword.utils.FileUtils; import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.hwpf.converter.PicturesManager; import org.apache.poi.hwpf.converter.WordToHtmlConverter; import org.apache.poi.hwpf.usermodel.Picture; import org.apache.poi.hwpf.usermodel.PictureType; import org.w3c.dom.Document; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.List; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; /** * Created by fuweiwei on 2015/11/28. */ public class WordHtmlActivity extends FragmentActivity { //文件存儲位置 private String docPath = "/mnt/sdcard/doc/"; //文件名稱 private String docName = "test.doc"; //html文件存儲位置 private String savePath = "/mnt/sdcard/doc/"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.html); String name = docName.substring(0, docName.indexOf(".")); try { convert2Html(docPath + docName, savePath + name + ".html"); } catch (Exception e) { e.printStackTrace(); } //WebView加載顯示本地html文件 WebView webView = (WebView)this.findViewById(R.id.office); WebSettings webSettings = webView.getSettings(); webSettings.setLoadWithOverviewMode(true); webSettings.setSupportZoom(true); webSettings.setBuiltInZoomControls(true); webView.loadUrl("file:/"+savePath+name+".html"); } /** * word文檔轉(zhuǎn)成html格式 * */ public void convert2Html(String fileName, String outPutFile) { HWPFDocument wordDocument = null; try { wordDocument = new HWPFDocument(new FileInputStream(fileName)); WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter( DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument()); //設(shè)置圖片路徑 wordToHtmlConverter.setPicturesManager(new PicturesManager() { public String savePicture(byte[] content, PictureType pictureType, String suggestedName, float widthInches, float heightInches) { String name = docName.substring(0, docName.indexOf(".")); return name + "/" + suggestedName; } }); //保存圖片 List<Picture> pics=wordDocument.getPicturesTable().getAllPictures(); if(pics!=null){ for(int i=0;i<pics.size();i++){ Picture pic = (Picture)pics.get(i); System.out.println( pic.suggestFullFileName()); try { String name = docName.substring(0,docName.indexOf(".")); String file = savePath+ name + "/" + pic.suggestFullFileName(); FileUtils.makeDirs(file); pic.writeImageContent(new FileOutputStream(file)); } catch (FileNotFoundException e) { e.printStackTrace(); } } } wordToHtmlConverter.processDocument(wordDocument); Document htmlDocument = wordToHtmlConverter.getDocument(); ByteArrayOutputStream out = new ByteArrayOutputStream(); DOMSource domSource = new DOMSource(htmlDocument); StreamResult streamResult = new StreamResult(out); TransformerFactory tf = TransformerFactory.newInstance(); Transformer serializer = tf.newTransformer(); serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8"); serializer.setOutputProperty(OutputKeys.INDENT, "yes"); serializer.setOutputProperty(OutputKeys.METHOD, "html"); serializer.transform(domSource, streamResult); out.close(); //保存html文件 writeFile(new String(out.toByteArray()), outPutFile); } catch (Exception e) { e.printStackTrace(); } } /** * 將html文件保存到sd卡 * */ public void writeFile(String content, String path) { FileOutputStream fos = null; BufferedWriter bw = null; try { File file = new File(path); if(!file.exists()){ file.createNewFile(); } fos = new FileOutputStream(file); bw = new BufferedWriter(new OutputStreamWriter(fos,"utf-8")); bw.write(content); } catch (FileNotFoundException fnfe) { fnfe.printStackTrace(); } catch (IOException ioe) { ioe.printStackTrace(); } finally { try { if (bw != null) bw.close(); if (fos != null) fos.close(); } catch (IOException ie) { } } } }
上面的代碼的原理起始也很簡單,poi提供了讓word文檔轉(zhuǎn)換成html頁面的方法、我們只需要使用webview來加載這個html就ok了,這樣我們就可以再手機(jī)端直接查看我們的word文檔了,是不是好強(qiáng)大。其實看起來的比較復(fù)雜的功能只要我們靜下心來想想就沒有我們想象中的那么復(fù)雜,今天就為大家分享到這了。
分享Demo的源碼:Android使用模板生成Word文檔
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android布局ConstraintLayout代碼修改約束及輔助功能
這篇文章主要為大家介紹了Android布局ConstraintLayout代碼修改約束及輔助功能示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09Android Vitamio和ExoPlayer兩種播放器優(yōu)劣分析
Vitamio和ExoPlayer都是用于安卓平臺的視頻播放器庫,它們各有優(yōu)缺點(diǎn),具體使用哪一個,需要根據(jù)你的實際需求、開發(fā)經(jīng)驗、項目規(guī)模等多個因素綜合考慮2023-04-04

Android開發(fā)中父組件調(diào)用子組件方法demo

Android自定義view利用Xfermode實現(xiàn)動態(tài)文字加載動畫

Android Fragment滑動組件ViewPager的實例詳解

Android自定View實現(xiàn)滑動驗證效果的代碼

Android中TextView自動識別url且實現(xiàn)點(diǎn)擊跳轉(zhuǎn)