Java中根据模板导出数据到word的解决方案
我们需求如下:给你一个模板,里面有一个表格,标题已经给好,程序主要就是完成把数据填写到word中并提供给用户下载。
网上找了很久,发现主要两种开源包:POI和Jacob,Jacob首先被否决掉了,因为他最后必须运行在windows平台上。Excel导入导出我就是用的POI,但是POI中的word操作实在不行,读取还可以,写入数据远不能满足项目的需要。后面尝试诸如生成PDF然后转Word,生成XML转Word,生成Html转word,生成rtf转word。这些都是可行的办法,但是网上开源包的功能有限,iText对PDF操作是很强,但是对PDF内容的解析不行。
最后这个事情拖了四天,我看文档的时候想到mht文件,于是我把Word模板导出成mht文件,然后查看其源码,其实就是html代码,我想这样可以用velocity填写数据,然后直接导出成doc格式的文档,后来这样基本满足我们项目的需要。
<tr style=3D'mso-yfti-irow:1;mso-yfti-lastrow:yes;page-break-inside:avoid;
height:22.7pt'>
<td width=3D"6%" style=3D'width:6.52%;border:solid windowtext 1.0pt;borde=
r-top:
none;mso-border-top-alt:solid windowtext .5pt;mso-border-alt:solid window=
text .5pt;
padding:0cm 5.4pt 0cm 5.4pt;height:22.7pt'>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span style=3D'mso-bidi-font-size:10.5pt;font-family:SimSun'>${bean.seqNo}<o:p></o:p></span=
></p>
</td>
<td width=3D"10%" style=3D'width:10.12%;border-top:none;border-left:none;
border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
mso-border-top-alt:solid windowtext .5pt;mso-border-left-alt:solid window=
text .5pt;
mso-border-alt:solid windowtext .5pt;padding:0cm 5.4pt 0cm 5.4pt;height:2=
2.7pt'>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
style=3D'mso-bidi-font-size:10.5pt;font-family:SimSun'>${bean.name}<span
lang=3DEN-US><o:p></o:p></span></span></p>
</td>
</tr>
#end
上面是用mht源码改写成vm文件的部分代码,就和生成一般的文本文件一摸一样。这儿如果直接把汉字、特殊字符什么的传给模板(当然英文不会),会出现乱码,导致根据模板导出的word文件这个都是乱码,关于乱码的详细解释可以参考:http://blog.csdn.net/myyate/archive/2008/04/08/2260234.aspx ; 也就是说导出时需要把带汉字的字符串都进行转码,这儿给出一些方法:
- /**
- * 把给定的str转换为10进制表示的unicode,格式为:姨
- * 目前只是用于mht模板的转码
- * @param str
- * @return
- */
- public static String encode2HtmlUnicode(String str) {
- if(str == null) return "";
- StringBuilder sb = new StringBuilder(str.length() * 2);
- for (int i = 0; i < str.length(); i++) {
- sb.append(encode2HtmlUnicode(str.charAt(i)));
- }
- return sb.toString();
- }
- public static String encode2HtmlUnicode(char character) {
- if (character > 255) {
- return "&#" + (character & 0xffff) + ";";
- } else {
- return String.valueOf(character);
- }
- }
- public static String encode2HtmlUnicode(Character character) {
- if(character == null) return null;
- return encode2HtmlUnicode(character.charValue());
- }
- public static void encode2HtmlUnicode(String[] value) {
- if(value == null || value.length < 1) return;
- for(int i = 0; i < value.length; i ++) {
- value[i] = encode2HtmlUnicode(value[i]);
- }
- }
- static Object encodeStringAndCharacter(Object value) {
- if(value instanceof String) {
- return StringUtils.replaceNullString(EncodeUtils.encode2HtmlUnicode((String) value));
- } else if(value instanceof Character) {
- return StringUtils.replaceNullString(EncodeUtils.encode2HtmlUnicode((Character) value));
- }
- return null;
- }
- static void encodeExceptStringAndCharacter(Object value) throws Exception {
- if(value instanceof String[]) {
- EncodeUtils.encode2HtmlUnicode((String[]) value);
- } else if(value instanceof List) {
- encode2HtmlUnicode((List) value);
- } else if(value instanceof Form) {
- encode2HtmlUnicode((Form) value);
- } else if(value instanceof Form[]) {
- encode2HtmlUnicode((Form[]) value);
- }
- }
- @SuppressWarnings("unchecked")
- static void encode2HtmlUnicode(List value) throws Exception {
- if(value == null || value.size() < 1) return;
- for(int i = 0; i < value.size(); i ++) {
- Object ele = value.get(i);
- Object result = encodeStringAndCharacter(ele);
- if(result != null) {
- value.set(i, result);
- } else {
- encodeExceptStringAndCharacter(ele);
- }
- }
- }
- static void encode2HtmlUnicode(Form[] value) throws Exception {
- if(value == null) return;
- for(int i = 0; i < value.length; i ++) {
- encode2HtmlUnicode(value[i]);
- }
- }
- static void encode2HtmlUnicode(Form value) throws Exception {
- if(value == null) return;
- PropertyDescriptor[] pds = PropertyUtils.getPropertyDescriptors(value.getClass());
- if(pds == null) return;
- for(int i = 0; i < pds.length; i ++) {
- PropertyDescriptor pd = pds[i];
- Object fieldValue = PropertyUtils.getProperty(value, pd.getName());
- Class fieldType = pd.getPropertyType();
- if(String.class.isAssignableFrom(fieldType)) {
- PropertyUtils.setProperty(value,
- pd.getName(),
- StringUtils.replaceNullString(EncodeUtils.encode2HtmlUnicode((String) fieldValue)));
- } else if(List.class.isAssignableFrom(fieldType)) {
- encode2HtmlUnicode((List) fieldValue);
- } else if(Form.class.isAssignableFrom(fieldType)) {
- encode2HtmlUnicode((Form) fieldValue);
- } else if(Form[].class.isAssignableFrom(fieldType)) {
- encode2HtmlUnicode((Form[]) fieldValue);
- }
- }
- }
上面的Form类型不需要关心,就是一个Bean接口。这样在传到模板之前进行上述转码,就基本上可以避免乱码问题。
导出结束后,只需要把OutputStream导出到*.doc文件中即可,下载的话只要设置:
- response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode("***.doc", DEFAULT_WEB_ENCODING));
- #if($manager)
- <!--[if gte vml =
- 1]><v:shape
- id=3D"_x0000_i1026" type=3D"#_x0000_t75" style=3D'width:96pt;height:96pt'>
- <v:imagedata src=3D"file6086.files/image003.gif" o:title=3D"5080"/>
- </v:shape><![endif]--><![if !vml]><img width=3D128 height=3D128
- src=3D"file6086.files/image003.gif" v:shapes=3D"_x0000_i1026"><![endif]>
- #end
- ......
- #if($manager)
- ------=_NextPart_01C8E27B.AE1C3C80
- Content-Location: file:///C:/C071D706/file6086.files/image003.gif
- Content-Transfer-Encoding: base64
- Content-Type: image/gif
- ${manager}
- #end
在mht文件中,图片都是以base64码来存储的,所以在存取之前,必须把二进制的图片进行base64编码:
- static BASE64Encoder base64Encoder = new BASE64Encoder();
- /**
- * 把给定的二进制流变成base64码
- * @param in
- * @return
- * @throws IOException
- */
- public static synchronized String base64Encode(InputStream in) throws IOException {
- byte[] img = new byte[in.available()];
- in.read(img);
- return base64Encode(img);
- }
- public static synchronized String base64Encode(String in) throws IOException {
- return base64Encode(in.getBytes());
- }
- public static synchronized String base64Encode(byte[] in) throws IOException {
- return base64Encoder.encode(in);
- }
上面的“编号”、表格数据、横线上的都是填写的。
这种导出到word的方法的一个缺点是模板复杂繁琐,尤其修改的时候更是如此;而且必须是officexp及其以上版本。
相关推荐
1、下载资源后请先看readme文档,README.md中有项目的介绍和具体的使用流程说明和易碰到的问题及解决方案。 2、若各位项目需求与本资源的样式相符度低,例如业务有渲染单元格颜色的,或者要求字体加粗,或者写入到多...
开发中偶尔会有固定模板导出word的需求,常见的导出通常通过直接修改xml或者通过工具库代码调整样式输出,这些方式开发困难并且不利于后期维护。 一些有规则的文档需要人工填写,费时费力,此时配置数据库做模板渲染...
JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...
Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...
Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...
JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...
JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...
JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...
JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...
JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...
JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...
JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...
JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...
JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...
应用程序中的嵌入式库,以实现成熟的报告解决方案。 执照 该项目是根据以下条款获得许可的 表现 X4J 引擎旨在生成相对较大的报告,并在报告服务器、WEB 应用程序、批处理报告上消耗合理的内存量。 此实现使用顺序...
传统的word模板导出(word另存为xml,在修改后缀为ftl)是行不通的,因为他解析不了html代码(至少我目前没有找到这方便的解决方案,大神勿喷~),这样的话我就要换用一种模板来处理这个模板:word模板另存为mht格式...
JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...
JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...
JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...