java多种方式导出word文档

来源:互联网 发布:淘宝网其他账户注册 编辑:程序博客网 时间:2024/05/22 09:42

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

转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/5280272.html

本来是要在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();     }}
复制代码

如果此文对您有帮助,微信打赏我一下吧~

作者:Joanna.Yan
出处:http://www.cnblogs.com/Joanna-Yan/
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。

  
分类: java,android,office文档操作
标签: java, doc
好文要顶关注我 收藏该文
Joanna.Yan
关注 - 8
粉丝 - 87
+加关注
1
0
«上一篇:Android 中关于static的使用问题
»下一篇:Java jacob调用打印机打印word文档
posted on 2016-03-18 20:17 Joanna.Yan 阅读(8791) 评论(6)编辑 收藏
原创粉丝点击