Java多种方式动态生成doc文档

本来是要在Android端生成doc的(这需求...),最后方法没有好的方法能够在Android上做到完美,最后还是只能搬迁到服务器。不浪费,还是记录下各框架不支持Android的原因以及他们的特点。Java相关的这类框架还是很多的,有几个还不错,可惜要么不支持Android,要么要收费还价格不低。

经过亲自测试,Android不支持Java的awt很多包不能直接在Android上用,FreeMarker挺不错的,能生成复杂漂亮的doc,可惜不支持Android。用POI在Android上能运行,但是一路因为版本,格式等走了很多坑,用WFS打开还是乱码。Jword、Aspose.word能完美支持,Jword试用期只有30天两者收费都不菲。itext没有测试,不过听说也不支持Android。

方法一:freemarker

该方法需要先手动创建一个doc模板(图片记得使用占位符),并保存为xml文件。通过动态替换特定标签${}中的内容生成。example:

先上效果图:

public class DocUtil {
 public Configuration configure=null;

 public DocUtil(){
  configure=new Configuration(Configuration.VERSION_2_3_22);
  configure.setDefaultEncoding("utf-8");
 }
 /**
  * 根据Doc模板生成word文件
  * @param dataMap 需要填入模板的数据
  * @param downloadType 文件名称
  * @param savePath 保存路径
  */
 public void createDoc(Map<String,Object> dataMap,String downloadType,String savePath){
  try {
   //加载需要装填的模板
   Template template=null;
   //设置模板装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载。
   //加载模板文件,放在testDoc下
   configure.setClassForTemplateLoading(this.getClass(), "/testDoc");
   //设置对象包装器
//   configure.setObjectWrapper(new DefaultObjectWrapper());
   //设置异常处理器
   configure.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
   //定义Template对象,注意模板类型名字与downloadType要一致
   template=configure.getTemplate(downloadType+".xml");
   File outFile=new File(savePath);
   Writer out=null;
   out=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
   template.process(dataMap, out);
   out.close();
  } catch (IOException e) {
   e.printStackTrace();
  } catch (TemplateException e) {
   e.printStackTrace();
  }
 }

 public String getImageStr(String imgFile){
  InputStream in=null;
  byte[] data=null;
  try {
   in=new FileInputStream(imgFile);
   data=new byte[in.available()];
   in.read(data);
   in.close();
  } catch (FileNotFoundException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
  BASE64Encoder encoder=new BASE64Encoder();
  return encoder.encode(data);
 }
}
public class TestDoc {
 public static void main(String[] args) {
  DocUtil docUtil=new DocUtil();
  Map<String, Object> dataMap=new HashMap<String, Object>();
  dataMap.put("name", "Joanna");
  dataMap.put("examNum", "111111111111");
  dataMap.put("IDCard", "222222222222222222");
  dataMap.put("carModel", "C1");
  dataMap.put("drivingSchool", "测试驾校");
  dataMap.put("busyType", "初次申领");
  dataMap.put("examDate", "2016-03-10");
  dataMap.put("orderCount", "第1次");
  dataMap.put("userImg1", docUtil.getImageStr("D:\\Img\\userImg1.png"));
  dataMap.put("userImg2", docUtil.getImageStr("D:\\Img\\userImg2.png"));
  dataMap.put("firstExamTime", "12:41:17-12:44:38");
  dataMap.put("firstExamScores", "0分,不及格");
  dataMap.put("firstDeductItem", "12:44:15 20102 1号倒车入库,车身出线 扣100分");
  dataMap.put("firstPic1", docUtil.getImageStr("D:\\Img\\firstPic1.png"));
  dataMap.put("firstPic2", docUtil.getImageStr("D:\\Img\\firstPic2.png"));
  dataMap.put("firstPic3", docUtil.getImageStr("D:\\Img\\firstPic3.png"));
  dataMap.put("secondExamTime", "12:46:50-13:05:37");
  dataMap.put("secondExamScores", "90分,通过");
  dataMap.put("secondDeductItem", "");
  dataMap.put("secondPic1", docUtil.getImageStr("D:\\Img\\secondPic1.png"));
  dataMap.put("secondPic2", docUtil.getImageStr("D:\\Img\\secondPic2.png"));
  dataMap.put("secondPic3", docUtil.getImageStr("D:\\Img\\secondPic3.png"));
  docUtil.createDoc(dataMap, "baseDoc", "D:\\yanqiong.doc");
 }
}

xml文件太长,就不贴了...

最后附上Android不能使用的原因:http://stackoverflow.com/questions/25929542/use-freemarker-library-in-android

补充关于动态显示list以及换行的问题

需求明确到:在上面的扣分项中,如果我有几条扣分项,我希望每显示一条换行。

直接在要显示的内容上加换行符,并没有什么效果,起不到换行的作用。

其中在加ftl标签时,如<#list></list>,就会出现一些问题,在xml中并不识别,导致项目不能运行。

解决:

在需要显示多条扣分项的位置加,并加换行符:

<#list firstDeductItem as firstItem>
     <w:t>${firstItem}</w:t><w:br/>
</#list>

TestDoc.java中改为:

List<String> Strs=new ArrayList<String>();
Strs.add("1111111111111111111");
Strs.add("222222222222222");
Strs.add("333333333333333");
dataMap.put("firstDeductItem", Strs);

DocUtil.java中改为:

//定义Template对象,注意模板类型名字与downloadType要一致
template=configure.getTemplate(downloadType+".ftl");此时xml文件会报错,当然也不能编译运行项目,需要将.xml文件改为.ftl文件保存。再编译运行,效果图:

方法二:POI

用这个方法遇到了很多版本问题,这里是基于POI3.7+Word2007的,测试能够完美运行。

你需要用Word2007手动生成文档模板(用其他的生成会报错:无法打开文件),并用${}替换需要动态更新的内容,与上面类似,但是不需要你保存为xml文档格式了。

/**
 * 自定义XWPFDocument,并重写createPicture()方法
 * @author Joanna.Yan
 *
 */
public class CustomXWPFDocument extends XWPFDocument{
 public CustomXWPFDocument(InputStream in) throws IOException{
  super(in);
 }
 public CustomXWPFDocument(){
  super();
 }
 public CustomXWPFDocument(OPCPackage pkg) throws IOException{
  super(pkg);
 }
 public void createPicture(int id,int width,int height,XWPFParagraph paragraph){
  final int EMU=9525;
  width *=EMU;
  height *=EMU;
  String blipId=((POIXMLDocumentPart) getAllPictures().get(id)).getPackageRelationship().getId();
  CTInline inline=paragraph.createRun().getCTR().addNewDrawing().addNewInline();
  String picXml=""
    + "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"
    + " <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
    + "  <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
    + "   <pic:nvPicPr>" + "   <pic:cNvPr id=\""
    + id
    + "\" name=\"Generated\"/>"
    + "   <pic:cNvPicPr/>"
    + "   </pic:nvPicPr>"
    + "   <pic:blipFill>"
    + "   <a:blip r:embed=\""
    + blipId
    + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"
    + "   <a:stretch>"
    + "    <a:fillRect/>"
    + "   </a:stretch>"
    + "   </pic:blipFill>"
    + "   <pic:spPr>"
    + "   <a:xfrm>"
    + "    <a:off x=\"0\" y=\"0\"/>"
    + "    <a:ext cx=\""
    + width
    + "\" cy=\""
    + height
    + "\"/>"
    + "   </a:xfrm>"
    + "   <a:prstGeom prst=\"rect\">"
    + "    <a:avLst/>"
    + "   </a:prstGeom>"
    + "   </pic:spPr>"
    + "  </pic:pic>"
    + " </a:graphicData>" + "</a:graphic>";
  inline.addNewGraphic().addNewGraphicData();
  XmlToken xmlToken=null;
  try {
   xmlToken=XmlToken.Factory.parse(picXml);
  } catch (XmlException e) {
   e.printStackTrace();
  }
  inline.set(xmlToken);
  inline.setDistT(0);
  inline.setDistB(0);
  inline.setDistL(0);
  inline.setDistR(0);

  CTPositiveSize2D extent=inline.addNewExtent();
  extent.setCx(width);
  extent.setCy(height);

  CTNonVisualDrawingProps docPr=inline.addNewDocPr();
  docPr.setId(id);
  docPr.setName("图片"+id);
  docPr.setDescr("测试");
 }
}
/**
 * 适用于word 2007
 * poi版本 3.7
 * @author Joanna.Yan
 *
 */
public class WordUtil {

 public static CustomXWPFDocument generateWord(Map<String, Object> param,String template){
  CustomXWPFDocument doc=null;
  try {
   OPCPackage pack=POIXMLDocument.openPackage(template);
   doc=new CustomXWPFDocument(pack);
   if(param!=null&&param.size()>0){
    //处理段落
    List<XWPFParagraph> paragraphList = doc.getParagraphs();
    processParagraphs(paragraphList, param, doc);
    //处理表格
    Iterator<XWPFTable> it = doc.getTablesIterator();
    while(it.hasNext()){
     XWPFTable table = it.next();
     List<XWPFTableRow> rows = table.getRows();
     for (XWPFTableRow row : rows) {
       List<XWPFTableCell> cells = row.getTableCells();
       for (XWPFTableCell cell : cells) {
        List<XWPFParagraph> paragraphListTable = cell.getParagraphs();
        processParagraphs(paragraphListTable, param, doc);
      }
     }
    }
   }
  } catch (IOException e) {
   e.printStackTrace();
  }
  return doc;
 }

 /**
  * 处理段落
  * @param paragraphList
  * @param param
  * @param doc
  */
 public static void processParagraphs(List<XWPFParagraph> paragraphList,Map<String, Object> param,CustomXWPFDocument doc){
  if(paragraphList!=null&&paragraphList.size()>0){
   for (XWPFParagraph paragraph : paragraphList) {
    List<XWPFRun> runs=paragraph.getRuns();
    for (XWPFRun run : runs) {
     String text=run.getText(0);
     if(text!=null){
      boolean isSetText=false;
      for (Entry<String, Object> entry : param.entrySet()) {
       String key=entry.getKey();
       if(text.indexOf(key)!=-1){
        isSetText=true;
        Object value=entry.getValue();
        if(value instanceof String){//文本替换
         text=text.replace(key, value.toString());
        }else if(value instanceof Map){//图片替换
         text=text.replace(key, "");
         Map pic=(Map) value;
         int width=Integer.parseInt(pic.get("width").toString());
         int height=Integer.parseInt(pic.get("height").toString());
         int picType=getPictureType(pic.get("type").toString());
         byte[] byteArray = (byte[]) pic.get("content");
         ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);
         try {
          int ind = doc.addPicture(byteInputStream,picType);
          doc.createPicture(ind, width , height,paragraph);
         } catch (InvalidFormatException e) {
          e.printStackTrace();
         } catch (IOException e) {
          e.printStackTrace();
         }
        }
       }
      }
      if(isSetText){
       run.setText(text, 0);
      }
     }
    }
   }
  }
 }

 /**
  * 根据图片类型获取对应的图片类型代码
  * @param picType
  * @return
  */
 public static int getPictureType(String picType){
  int res = CustomXWPFDocument.PICTURE_TYPE_PICT;
  if(picType!=null){
   if(picType.equalsIgnoreCase("png")){
    res=CustomXWPFDocument.PICTURE_TYPE_PNG;
   }else if(picType.equalsIgnoreCase("dib")){
    res = CustomXWPFDocument.PICTURE_TYPE_DIB;
   }else if(picType.equalsIgnoreCase("emf")){
    res = CustomXWPFDocument.PICTURE_TYPE_EMF;
   }else if(picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")){
    res = CustomXWPFDocument.PICTURE_TYPE_JPEG;
   }else if(picType.equalsIgnoreCase("wmf")){
    res = CustomXWPFDocument.PICTURE_TYPE_WMF;
   }
  }
  return res;
 }
}
public class TestPoi {

 public static void main(String[] args) throws IOException {
  Map<String, Object> param=new HashMap<String, Object>();
  param.put("${name}", "Joanna.Yan");
  param.put("${examNum}", "000000000001");
  param.put("${IDCard}", "111111111111111111");
  param.put("${carModel}", "C1");
  CustomXWPFDocument doc=WordUtil.generateWord(param, "D:\\joanna.docx");
  FileOutputStream fopts = new FileOutputStream("D:\\yan.docx");
  doc.write(fopts);
  fopts.close();
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • PHP使用DOMDocument类生成HTML实例(包含常见标签元素)

    在这一章节里, 我们来了解下如何利用核心(core) PHP 生成 HTML 文件   最近我在查询 php.net 的时候,发现 DOMDocument 这个类非常的有意思, 可以用来生成 XML 或 HTML 文件, DOMDocument 为我们提供了一系列的方法来生成 XML/HTML 标签并插入到 DOM 中, 现在就让我们来看下如何生成的   这里先来看下, 利用它所提供的方法生成的效果, 见下图: 一.创建新的 DOM 文件 复制代码 代码如下: //实例化 DOMDocument

  • 探讨:如何使用PhpDocumentor生成文档

    命令行方式: 在phpDocumentor所在目录下,输入phpdoc –h会得到一个详细的参数表,其中几个重要的参数如下:-f 要进行分析的文件名,多个文件用逗号隔开-d 要分析的目录,多个目录用逗号分割-t 生成的文档的存放路径-o 输出的文档格式,结构为输出格式:转换器名:模板目录. 例如:phpdoc -o HTML:frames:earthli -f test.php -t docs Web界面生成 在新的phpdoc中,除了在命令行下生成文档外,还可以在客户端浏览器上操作生成文档,具

  • java使用poi读取ppt文件和poi读取excel、word示例

    Apache的POI项目可以用来处理MS Office文档,codeplex上还有一个它的.net版本.POI项目可创建和维护操作各种基于OOXML和OLE2文件格式的Java API.大多数MS Office都是OLE2格式的.POI通HSMF子项目来支持Outlook,通过HDGF子项目来支持Visio,通过HPBF子项目来支持Publisher. 使用POI抽取Word简单示例: 要引入poi-3.7.jat和poi-scratchpad-3.7.ajr这两个包. 复制代码 代码如下: p

  • Java数据导入功能之读取Excel文件实例

    在编程中经常需要使用到表格(报表)的处理主要以Excel表格为主.下面给出用java读取excel表格方法: 1.添加jar文件 java导入导出Excel文件要引入jxl.jar包,最关键的是这套API是纯Java的,并不依赖Windows系统,即使运行在Linux下,它同样能够正确的处理Excel文件.下载地址:http://www.andykhan.com/jexcelapi/ 2.jxl对Excel表格的认识 (1)每个单元格的位置认为是由一个二维坐标(i,j)给定,其中i表示列,j表示

  • Java数据导出功能之导出Excel文件实例

    在编程中经常需要使用到表格(报表)的处理主要以Excel表格为主.下面给出用java写入数据到excel表格方法: 1.添加jar文件 java导入导出Excel文件要引入jxl.jar包,最关键的是这套API是纯Java的,并不依赖Windows系统,即使运行在Linux下,它同样能够正确的处理Excel文件.下载地址:http://www.andykhan.com/jexcelapi/ 2.jxl对Excel表格的认识 可以参见:http://www.jb51.net/article/686

  • Java读取Excel文件内容的简单实例

    借助于apathe的poi.jar,由于上传文件不支持.jar所以请下载后将文件改为.jar,在应用程序中添加poi.jar包,并将需要读取的excel文件放入根目录即可 本例使用java来读取excel的内容并展出出结果,代码如下: 复制代码 代码如下: import java.io.BufferedInputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundExceptio

  • Python文档生成工具pydoc使用介绍

    在Python中有很多很好的工具来生成字符串文档(docstring),比如说: epydoc.doxygen.sphinx,但始终觉得pydoc还是不错的工具,用法非常简单,功能也算不错,本文主要介绍pydoc. pydoc是Python自带的模块,主要用于从python模块中自动生成文档,这些文档可以基于文本呈现的.也可以生成WEB 页面的,还可以在服务器上以浏览器的方式呈现! [用法] Windows下: 复制代码 代码如下: D:\>python -m pydoc <modulenam

  • java使用poi读取excel内容方法实例

    复制代码 代码如下: import java.io.BufferedInputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.nio.channels.FileChannel;import java.text.DecimalFormat;import java.text.SimpleDat

  • PhpDocumentor 2安装以及生成API文档的方法

    官网地址:http://www.phpdoc.org/项目地址:https://github.com/phpDocumentor/phpDocumentor2 phpDocumentor 2是一个可以 分析php源代码和注释块并生成文档的程序. 基于phpdocumentor 1和javadoc启发而来,它持续创新的使用了一些新技术和支持php的新特性. phpDocumentor 2的特点: 兼容php5.3,全面支持命名空间和闭包等.    识别支持任何tag,以及一些追加的 (比如 @li

  • eclipse中自动生成javadoc文档的方法

    本文实例讲述了eclipse中自动生成javadoc文档的方法.分享给大家供大家参考.具体方法如下: 使用eclipse生成文档(javadoc)主要有三种方法: 1. 在项目列表中按右键,选择Export(导出),然后在Export(导出)对话框中选择java下的javadoc,提交到下一步. 在Javadoc Generation对话框中有两个地方要注意的: javadoc command:应该选择jdk的bin/javadoc.exe destination:为生成文档的保存路径,可自由选

随机推荐