`

Java中根据模板导出数据到word的解决方案

    博客分类:
  • java
阅读更多

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格式的文档,后来这样基本满足我们项目的需要。

#foreach($bean in $beanList)
 
<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'
>
  
<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'
>
  
<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 ; 也就是说导出时需要把带汉字的字符串都进行转码,这儿给出一些方法:

 

  1.     /**
  2.      * 把给定的str转换为10进制表示的unicode,格式为:姨
  3.      * 目前只是用于mht模板的转码
  4.      * @param str
  5.      * @return
  6.      */
  7.     public static String encode2HtmlUnicode(String str) {
  8.     
  9.     if(str == nullreturn "";
  10.     
  11.     StringBuilder sb = new StringBuilder(str.length() * 2);
  12.     for (int i = 0; i < str.length(); i++) {
  13.         sb.append(encode2HtmlUnicode(str.charAt(i)));
  14.     }
  15.     return sb.toString();
  16.     }
  17.     
  18.     public static String encode2HtmlUnicode(char character) {
  19.     if (character > 255) {
  20.         return "&#" + (character & 0xffff) + ";";
  21.     } else {
  22.         return String.valueOf(character);
  23.     }
  24.     }
  25.     
  26.     public static String encode2HtmlUnicode(Character character) {
  27.     if(character == nullreturn null;
  28.     return encode2HtmlUnicode(character.charValue());
  29.     }
  30.     
  31.     public static void encode2HtmlUnicode(String[] value) {
  32.     if(value == null || value.length < 1return;
  33.     
  34.     for(int i = 0; i < value.length; i ++) {
  35.         value[i] = encode2HtmlUnicode(value[i]);
  36.     }
  37.     }
      上面的这些方法在项目中可以通过递归来对bean进行转码,当然我在项目中只是针对String和Character两种数据类型进行转码。
  1.     static Object encodeStringAndCharacter(Object value) {
  2.     if(value instanceof String) {
  3.         return StringUtils.replaceNullString(EncodeUtils.encode2HtmlUnicode((String) value));
  4.     } else if(value instanceof Character) {
  5.         return StringUtils.replaceNullString(EncodeUtils.encode2HtmlUnicode((Character) value));
  6.     }
  7.     return null;
  8.     }
  9.     
  10.     static void encodeExceptStringAndCharacter(Object value) throws Exception {
  11.     if(value instanceof String[]) {
  12.         EncodeUtils.encode2HtmlUnicode((String[]) value);
  13.     } else if(value instanceof List) {
  14.         encode2HtmlUnicode((List) value);
  15.     } else if(value instanceof Form) {
  16.         encode2HtmlUnicode((Form) value);
  17.     } else if(value instanceof Form[]) {
  18.         encode2HtmlUnicode((Form[]) value);
  19.     }
  20.     }
  21.     
  22.     @SuppressWarnings("unchecked")
  23.     static void encode2HtmlUnicode(List value) throws Exception {
  24.     if(value == null || value.size() < 1return;
  25.     
  26.     for(int i = 0; i < value.size(); i ++) {
  27.         Object ele = value.get(i);
  28.         Object result = encodeStringAndCharacter(ele);
  29.         if(result != null) {
  30.         value.set(i, result);
  31.         } else {
  32.         encodeExceptStringAndCharacter(ele);
  33.         }
  34.     }   
  35.     }
  36.     
  37.     
  38.     static void encode2HtmlUnicode(Form[] value) throws Exception {
  39.     
  40.     if(value == nullreturn;
  41.     
  42.     for(int i = 0; i < value.length; i ++) {
  43.         encode2HtmlUnicode(value[i]);
  44.     }
  45.     }
  46.     
  47.     static void encode2HtmlUnicode(Form value) throws Exception {
  48.     
  49.     if(value == nullreturn;
  50.     
  51.     PropertyDescriptor[] pds = PropertyUtils.getPropertyDescriptors(value.getClass());
  52.     if(pds == nullreturn;
  53.     
  54.     for(int i = 0; i < pds.length; i ++) {
  55.         PropertyDescriptor pd = pds[i];
  56.         Object fieldValue = PropertyUtils.getProperty(value, pd.getName());
  57.         Class fieldType = pd.getPropertyType();
  58.         if(String.class.isAssignableFrom(fieldType)) {
  59.         PropertyUtils.setProperty(value, 
  60.             pd.getName(),
  61.             StringUtils.replaceNullString(EncodeUtils.encode2HtmlUnicode((String) fieldValue)));
  62.         } else if(List.class.isAssignableFrom(fieldType)) {
  63.         encode2HtmlUnicode((List) fieldValue);
  64.         } else if(Form.class.isAssignableFrom(fieldType)) {
  65.         encode2HtmlUnicode((Form) fieldValue);
  66.         } else if(Form[].class.isAssignableFrom(fieldType)) {
  67.         encode2HtmlUnicode((Form[]) fieldValue);
  68.         }
  69.     }
  70.     }

 

      上面的Form类型不需要关心,就是一个Bean接口。这样在传到模板之前进行上述转码,就基本上可以避免乱码问题。

      导出结束后,只需要把OutputStream导出到*.doc文件中即可,下载的话只要设置:

  1. response.setHeader("Content-disposition""attachment; filename=" + URLEncoder.encode("***.doc", DEFAULT_WEB_ENCODING));
      项目还有一个需求,对于一些飞机零件或者领导名字要求是图片显示。这个不难,但模板做起比较繁琐,因为mht模板和难控制,一般都是通过word另存的,而且里面汉字有时ascii格式,所以需要显示图片的地方都事先放一个图片,然后再在mht代码中替换一下:
  1. #if($manager)
  2. <!--[if gte vml =
  3. 1]><v:shape
  4.  id=3D"_x0000_i1026" type=3D"#_x0000_t75" style=3D'width:96pt;height:96pt'>
  5.  <v:imagedata src=3D"file6086.files/image003.gif" o:title=3D"5080"/>
  6. </v:shape><![endif]--><![if !vml]><img width=3D128 height=3D128
  7. src=3D"file6086.files/image003.gif" v:shapes=3D"_x0000_i1026"><![endif]>
  8. #end
  9. ......
  10. #if($manager)
  11. ------=_NextPart_01C8E27B.AE1C3C80
  12. Content-Location: file:///C:/C071D706/file6086.files/image003.gif
  13. Content-Transfer-Encoding: base64
  14. Content-Type: image/gif
  15. ${manager}
  16. #end

 

      在mht文件中,图片都是以base64码来存储的,所以在存取之前,必须把二进制的图片进行base64编码:

  1.     static BASE64Encoder base64Encoder = new BASE64Encoder();
  2.     /**
  3.      * 把给定的二进制流变成base64码
  4.      * @param in
  5.      * @return
  6.      * @throws IOException
  7.      */
  8.     public static synchronized String base64Encode(InputStream in) throws IOException {
  9.     byte[] img = new byte[in.available()];
  10.     in.read(img);
  11.     return base64Encode(img);
  12.     }
  13.     
  14.     public static synchronized String base64Encode(String in) throws IOException {
  15.     return base64Encode(in.getBytes());
  16.     }
  17.     
  18.     public static synchronized String base64Encode(byte[] in) throws IOException {
  19.     return base64Encoder.encode(in);
  20.     }
      转换成String以后在传到模板文件中显示则可。关于任何格式、布局等等等的调整你可以事先在word里先全部调整好再另存。导出效果如下图:

      上面的“编号”、表格数据、横线上的都是填写的。

      这种导出到word的方法的一个缺点是模板复杂繁琐,尤其修改的时候更是如此;而且必须是officexp及其以上版本。

分享到:
评论

相关推荐

    关于Java使用EasyExcel导出动态数据为Excel文件SpringBoot代码项目示例

    1、下载资源后请先看readme文档,README.md中有项目的介绍和具体的使用流程说明和易碰到的问题及解决方案。 2、若各位项目需求与本资源的样式相符度低,例如业务有渲染单元格颜色的,或者要求字体加粗,或者写入到多...

    word源码java-officeexport-java:三行代码导出自定义样式word

    开发中偶尔会有固定模板导出word的需求,常见的导出通常通过直接修改xml或者通过工具库代码调整样式输出,这些方式开发困难并且不利于后期维护。 一些有规则的文档需要人工填写,费时费力,此时配置数据库做模板渲染...

    java开源包5

    JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...

    JAVA上百实例源码以及开源项目源代码

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    JAVA上百实例源码以及开源项目

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    java开源包11

    JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...

    java开源包6

    JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...

    java开源包9

    JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...

    java开源包4

    JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...

    java开源包101

    JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...

    java开源包8

    JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...

    java开源包10

    JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...

    java开源包1

    JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...

    java开源包3

    JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...

    word源码java-x4j-analytic:用于JAVA的Excel报表库

    应用程序中的嵌入式库,以实现成熟的报告解决方案。 执照 该项目是根据以下条款获得许可的 表现 X4J 引擎旨在生成相对较大的报告,并在报告服务器、WEB 应用程序、批处理报告上消耗合理的内存量。 此实现使用顺序...

    ExpordWord_demo.zip

    传统的word模板导出(word另存为xml,在修改后缀为ftl)是行不通的,因为他解析不了html代码(至少我目前没有找到这方便的解决方案,大神勿喷~),这样的话我就要换用一种模板来处理这个模板:word模板另存为mht格式...

    java开源包2

    JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...

    java开源包7

    JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...

    Java资源包01

    JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...

Global site tag (gtag.js) - Google Analytics