Android使用模板生成支持手機(jī)直接查看的Word文檔
最近在項(xiàng)目工作中,碰到一個(gè)很棘手的需求,說(shuō)是要在手機(jī)端根據(jù)模板生成word文檔,而且不借助第三方的軟件可以查看word文檔,一開始聽(tīng)這個(gè)需求差不多蒙了,這要怎么做,為什么不把生成word文檔這個(gè)工作放在后臺(tái)呢,抱怨歸抱怨,但是面對(duì)需求只能硬著頭皮做了,經(jīng)過(guò)各種拷問(wèn)度娘和谷哥,終于找了一個(gè)比較好用的方法。特此跟他家分享。
Apache 公司推出的 Apache POI,我們來(lái)看下他的介紹:Apache POI 是用Java編寫的免費(fèi)開源的跨平臺(tái)的 Java API,Apache POI提供API給Java程式對(duì)Microsoft Office格式檔案讀和寫的功能。
廢話少說(shuō)開始編碼,首先我們要下Apache POI的開發(fā)jar包,下載地址,這里推薦不要下最新版本的,因?yàn)橐婚_始我用最新版本的會(huì)出一下莫名其妙的問(wèn)題,后面換舊的版本就OK了。這里我用的是3.9的還是比較穩(wěn)定的、

開發(fā)有2個(gè)包,有一點(diǎn)我就非常郁悶Apache居然沒(méi)有提供api穩(wěn)定,開發(fā)起來(lái)還是比較難受,可能是我自己沒(méi)有找到把,如果有知道的筒子可以@我、嘿嘿。不過(guò)Apache還是提供了Demo大家可以參考。還有我們要準(zhǔn)備我們使用的word模板文件、這里我們放在了assets下面了。首先我們來(lái)看看怎么使用模板:
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號(hào)");
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$", "無(wú)");
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) {
//檢測(cè)到系統(tǒng)尚未安裝OliveOffice的apk程序
Toast.makeText(MainActivity.this, "未找到軟件", Toast.LENGTH_LONG).show();
//請(qǐng)先到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)錯(cuò)包了,因?yàn)閍pache每個(gè)包對(duì)應(yīng)的內(nèi)容不同:

上面代碼不難懂,就是把我們要放的內(nèi)容使用特定的代號(hào)組裝一個(gè)map塞到我們的模板里面去,然后重新存儲(chǔ)下,不過(guò)我們模板也要使用相同的代號(hào)、poi才能識(shí)別:

這樣我們就使用模板大功告成了,就可以查看了、但是有些手機(jī)并沒(méi)有裝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 {
//文件存儲(chǔ)位置
private String docPath = "/mnt/sdcard/doc/";
//文件名稱
private String docName = "test.doc";
//html文件存儲(chǔ)位置
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) {
}
}
}
}上面的代碼的原理起始也很簡(jiǎn)單,poi提供了讓word文檔轉(zhuǎn)換成html頁(yè)面的方法、我們只需要使用webview來(lái)加載這個(gè)html就ok了,這樣我們就可以再手機(jī)端直接查看我們的word文檔了,是不是好強(qiáng)大。其實(shí)看起來(lái)的比較復(fù)雜的功能只要我們靜下心來(lái)想想就沒(méi)有我們想象中的那么復(fù)雜,今天就為大家分享到這了。
分享Demo的源碼:Android使用模板生成Word文檔
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android布局ConstraintLayout代碼修改約束及輔助功能
這篇文章主要為大家介紹了Android布局ConstraintLayout代碼修改約束及輔助功能示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
Android Vitamio和ExoPlayer兩種播放器優(yōu)劣分析
Vitamio和ExoPlayer都是用于安卓平臺(tái)的視頻播放器庫(kù),它們各有優(yōu)缺點(diǎn),具體使用哪一個(gè),需要根據(jù)你的實(shí)際需求、開發(fā)經(jīng)驗(yàn)、項(xiàng)目規(guī)模等多個(gè)因素綜合考慮2023-04-04
Android實(shí)現(xiàn)全屏截圖或長(zhǎng)截屏功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)全屏截圖或長(zhǎng)截屏功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05
Android開發(fā)中父組件調(diào)用子組件方法demo
Android自定義view利用Xfermode實(shí)現(xiàn)動(dòng)態(tài)文字加載動(dòng)畫
Android Fragment滑動(dòng)組件ViewPager的實(shí)例詳解
Android自定View實(shí)現(xiàn)滑動(dòng)驗(yàn)證效果的代碼
Android中TextView自動(dòng)識(shí)別url且實(shí)現(xiàn)點(diǎn)擊跳轉(zhuǎn)
Android實(shí)現(xiàn)極簡(jiǎn)打開攝像頭

