Java中根據模板導出數據到word的解決方案我們需求如下給你一個模板裡面有一個表格標題已經給好程序主要就是完成把數據填寫到word中並提供給用戶下載
網上找了很久發現主要兩種開源包POI和JacobJacob首先被否決掉了因為他最後必須運行在windows平台上Excel導入導出我就是用的POI但是POI中的word操作實在不行讀取還可以寫入數據遠不能滿足項目的需要後面嘗試諸如生成PDF然後轉Word生成XML轉Word生成Html轉word生成rtf轉word這些都是可行的辦法但是網上開源包的功能有限iText對PDF操作是很強但是對PDF內容的解析不行
最後這個事情拖了四天我看文檔的時候想到mht文件於是我把Word模板導出成mht文件然後查看其源碼其實就是html代碼我想這樣可以用velocity填寫數據然後直接導出成doc格式的文檔後來這樣基本滿足我們項目的需要
#foreach($bean in $beanList)
<tr style=Dmsoyftiirow:;msoyftilastrow:yes;pagebreakinside:avoid;
height:pt>
<td width=D% style=Dwidth:%;border:solid windowtext pt;borde=
rtop:
none;msobordertopalt:solid windowtext pt;msoborderalt:solid window=
text pt;
padding:cm pt cm pt;height:pt>
<p class=DMsoNormal align=Dcenter style=Dtextalign:center><span style=Dmsobidifontsize:pt;fontfamily:SimSun>${beanseqNo}<o:p></o:p></span=
></p>
</td>
<td width=D% style=Dwidth:%;bordertop:none;borderleft:none;
borderbottom:solid windowtext pt;borderright:solid windowtext pt;
msobordertopalt:solid windowtext pt;msoborderleftalt:solid window=
text pt;
msoborderalt:solid windowtext pt;padding:cm pt cm pt;height:=
pt>
<p class=DMsoNormal align=Dcenter style=Dtextalign:center><span
style=Dmsobidifontsize:pt;fontfamily:SimSun>${beanname}<span
lang=DENUS><o:p></o:p></span></span></p>
</td>
</tr>
#end
上面是用mht源碼改寫成vm文件的部分代碼就和生成一般的文本文件一摸一樣這兒如果直接把漢字特殊字符什麼的傳給模板(當然英文不會)會出現亂碼導致根據模板導出的word文件這個都是亂碼關於亂碼的詳細解釋可以參考 也就是說導出時需要把帶漢字的字符串都進行轉碼這兒給出一些方法
/**
* 把給定的str轉換為進制表示的unicode格式為姨
* 目前只是用於mht模板的轉碼
* @param str
* @return
*/
public static String encodeHtmlUnicode(String str) {
if(str == null) return ;
StringBuilder sb = new StringBuilder(strlength() * );
for (int i = ; i < strlength(); i++) {
sbappend(encodeHtmlUnicode(strcharAt(i)));
}
return sbtoString();
}
public static String encodeHtmlUnicode(char character) {
if (character > ) {
return &# + (character & xffff) + ;;
} else {
return StringvalueOf(character);
}
}
public static String encodeHtmlUnicode(Character character) {
if(character == null) return null;
return encodeHtmlUnicode(charactercharValue());
}
public static void encodeHtmlUnicode(String[] value) {
if(value == null || valuelength < ) return;
for(int i = ; i < valuelength; i ++) {
value[i] = encodeHtmlUnicode(value[i]);
}
}
上面的這些方法在項目中可以通過遞歸來對bean進行轉碼當然我在項目中只是針對String和Character兩種數據類型進行轉碼
static Object encodeStringAndCharacter(Object value) {
if(value instanceof String) {
return StringUtilsreplaceNullString(EncodeUtilsencodeHtmlUnicode((String) value));
} else if(value instanceof Character) {
return StringUtilsreplaceNullString(EncodeUtilsencodeHtmlUnicode((Character) value));
}
return null;
}
static void encodeExceptStringAndCharacter(Object value) throws Exception {
if(value instanceof String[]) {
EncodeUtilsencodeHtmlUnicode((String[]) value);
} else if(value instanceof List) {
encodeHtmlUnicode((List) value);
} else if(value instanceof Form) {
encodeHtmlUnicode((Form) value);
} else if(value instanceof Form[]) {
encodeHtmlUnicode((Form[]) value);
}
}
@SuppressWarnings(unchecked)
static void encodeHtmlUnicode(List value) throws Exception {
if(value == null || valuesize() < ) return;
for(int i = ; i < valuesize(); i ++) {
Object ele = valueget(i);
Object result = encodeStringAndCharacter(ele);
if(result != null) {
valueset(i result);
} else {
encodeExceptStringAndCharacter(ele);
}
}
}
static void encodeHtmlUnicode(Form[] value) throws Exception {
if(value == null) return;
for(int i = ; i < valuelength; i ++) {
encodeHtmlUnicode(value[i]);
}
}
static void encodeHtmlUnicode(Form value) throws Exception {
if(value == null) return;
PropertyDescriptor[] pds = PropertyUtilsgetPropertyDescriptors(valuegetClass());
if(pds == null) return;
for(int i = ; i < pdslength; i ++) {
PropertyDescriptor pd = pds[i];
Object fieldValue = PropertyUtilsgetProperty(value pdgetName());
Class fieldType = pdgetPropertyType();
if(StringclassisAssignableFrom(fieldType)) {
PropertyUtilssetProperty(value
pdgetName()
StringUtilsreplaceNullString(EncodeUtilsencodeHtmlUnicode((String) fieldValue)));
} else if(ListclassisAssignableFrom(fieldType)) {
encodeHtmlUnicode((List) fieldValue);
} else if(FormclassisAssignableFrom(fieldType)) {
encodeHtmlUnicode((Form) fieldValue);
} else if(Form[]classisAssignableFrom(fieldType)) {
encodeHtmlUnicode((Form[]) fieldValue);
}
}
}
上面的Form類型不需要關心就是一個Bean接口這樣在傳到模板之前進行上述轉碼就基本上可以避免亂碼問題
導出結束後只需要把OutputStream導出到*doc文件中即可下載的話只要設置
responsesetHeader(Contentdisposition attachment; filename= + URLEncoderencode(***doc DEFAULT_WEB_ENCODING));
項目還有一個需求對於一些飛機零件或者領導名字要求是圖片顯示這個不難但模板做起比較繁瑣因為mht模板和難控制一般都是通過word另存的而且裡面漢字有時ascii格式所以需要顯示圖片的地方都事先放一個圖片然後再在mht代碼中替換一下
#if($manager)
<![if gte vml =
]><v:shape
id=D_x_i type=D#_x_t style=Dwidth:pt;height:pt>
<v:imagedata src=Dfilefiles/imagegif o:title=D/>
</v:shape><![endif]><![if !vml]><img width=D height=D
src=Dfilefiles/imagegif v:shapes=D_x_i><![endif]>
#end
#if($manager)
=_NextPart_CEBAECC
ContentLocation: file:///C:/CD/filefiles/imagegif
ContentTransferEncoding: base
ContentType: image/gif
${manager}
#end
在mht文件中圖片都是以base碼來存儲的所以在存取之前必須把二進制的圖片進行base編碼
static BASEEncoder baseEncoder = new BASEEncoder();
/**
* 把給定的二進制流變成base碼
* @param in
* @return
* @throws IOException
*/
public static synchronized String baseEncode(InputStream in) throws IOException {
byte[] img = new byte[inavailable()];
inread(img);
return baseEncode(img);
}
public static synchronized String baseEncode(String in) throws IOException {
return baseEncode(ingetBytes());
}
public static synchronized String baseEncode(byte[] in) throws IOException {
return baseEncoderencode(in);
}
轉換成String以後在傳到模板文件中顯示則可關於任何格式布局等等等的調整你可以事先在word裡先全部調整好再另存導出效果如下圖
上面的編號表格數據橫線上的都是填寫的
這種導出到word的方法的一個缺點是模板復雜繁瑣尤其修改的時候更是如此而且必須是officexp及其以上版本
From:http://tw.wingwit.com/Article/program/Java/hx/201311/25981.html