欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2024-03-13 17:05:27
本来是要在android端生成doc的(这需求...),最后方法没有好的方法能够在android上做到完美,最后还是只能搬迁到服务器。不浪费,还是记录下各框架不支持andr...

本来是要在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: 

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

先上效果图:

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

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://*.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文件保存。再编译运行,效果图: 

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

方法二: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(); 
 }
}

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