zoukankan      html  css  js  c++  java
  • 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(); 
        }
    }

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

  • 相关阅读:
    bzoj 1588: [HNOI2002]营业额统计 treap
    Codeforces Round #135 (Div. 2) E. Parking Lot 线段数区间合并
    cdoj 851 方老师与素数 bfs
    hdu 5150 Sum Sum Sum 水
    Codeforces Round #376 (Div. 2) F. Video Cards 数学,前缀和
    POJ 1984 Navigation Nightmare 带全并查集
    POJ 1655 Balancing Act 树的重心
    POJ 3140 Contestants Division 树形DP
    HDU 3586 Information Disturbing 树形DP+二分
    HDU 1561 The more, The Better 树形DP
  • 原文地址:https://www.cnblogs.com/Joanna-Yan/p/5280272.html
Copyright © 2011-2022 走看看