• 执法文书打印的实现(一)


        最近公司做质检的执法项目,牵涉到执法文书的打印。这个功能实现的时候走了不少弯路,简单记录下,以备后用。

        甲方的要求比较苛刻:1、打印功能不依赖于客户pc机上的word程序 2、打印功能不依赖于特定的浏览器插件 3、不依赖于其他商业程序。 这样,我只能通过调用IE内置的IEWebBrowser控件进行打印。大部分文书可以调整显示样式,来达到标准文书的要求,而一些比较特殊的文书如《现场检查笔录》,由于嵌套富文本,前台很难实现标准文书的打印效果。这类特殊文书的打印,我的思路是服务器生成打印图片,前台调用打印组件打印。

        打印图片的生成主要分为3步:1、根据word模板填充数据,生成新的word文件 2、word转pdf 3、pdf转图片

        生成word主要有两种方法:1、poi生成word(本例中使用的方法) 2、使用freemarker生成word

    照例先copy下poi项目介绍:POI项目的使命是创建和维护Java api操纵各种文件格式 基于Office Open XML标准(OOXML)和微软的OLE 2复合文档格式(OLE2)。 简而言之,您可以使用Java读写MS Excel文件。其中,HWPF提供对word97的支持,XWPF提供对word2007(ooxml国际标准)的支持。

    首先,参照官方代码写了测试方法:

    文本替换测试:

    @Test
        public void testPoi() {
            try {
                //docx文件的文档对象
                XWPFDocument xwpfDocument=new XWPFDocument(POIXMLDocument.openPackage("D:/testPoi.docx"));
                //XWPFParagraph 包含在文档/表格/标题中的段落(段落中包含很多样式信息)
                //需求:替换段落中的文本/图片等,不涉及新加段落
                //遍历文档的段落对象(不包括页眉页脚)
                for (XWPFParagraph xwpfParagraph : xwpfDocument.getParagraphs()) {
                    //XWPFRun对象定义了文本区域的一组公共的属性
                    for (XWPFRun xwpfRun : xwpfParagraph.getRuns()) {
                        //文本替换
                        if("${营业执照}".equalsIgnoreCase(xwpfRun.getText(xwpfRun.getTextPosition()))){
                            //{1}
                            xwpfRun.setColor("FF0000");//设置文本颜色
                            xwpfRun.setText("我的营业执照",0);//文本替换
                            //xwpfRun.setText("我的营业执照1",-1); //在当前文本后追加文本
                            //xwpfRun.setText("我的营业执照12",2); //在当前文本后追加文本
                            //xwpfRun.setText("我的营业执照11",1); //在“我的营业执照1”后追加文本
                        }
                        //图片替换添加
                        if("${二维码}".equalsIgnoreCase(xwpfRun.getText(xwpfRun.getTextPosition()))){
                            //{2}
                            xwpfRun.setText("",0);//文本替换
                            //在文档中插入图片失败
                            //xwpfParagraph.createRun().addPicture(new FileInputStream(new File("D:/二维码.PNG")), Document.PICTURE_TYPE_PNG, "二维码", Units.toEMU(200), Units.toEMU(200));
                            //xwpfRun.addPicture(new FileInputStream(new File("D:/二维码.PNG")), Document.PICTURE_TYPE_PNG, "二维码", Units.toEMU(200), Units.toEMU(200));
                            //create run需要结束当前循环
                            //break;
                        }
                    }
                }
                //文档create 添加图片失败
                //xwpfDocument.createParagraph().createRun().addPicture(new FileInputStream(new File("D:/二维码.PNG")), Document.PICTURE_TYPE_PNG, "二维码", Units.toEMU(200), Units.toEMU(200));
                FileOutputStream fos = new FileOutputStream(new File("D:/testPoi1.docx"));
                xwpfDocument.write(fos);
                fos.flush();
                fos.close();
            } catch (IOException e) {
                System.out.println("加载文件失败");
                e.printStackTrace();
            } catch (Exception e) {
                System.out.println("序列化图片失败");
                e.printStackTrace();
            }
        }
    文本替换

    比较坑的是word中写的标记会被ms解析成不同的run,需要自行修改:

    应为:

    Poi添加图片的方法存在bug,官方暂时还没有修复:

    执行添加图片方法后,打不开文档:

        文档插入图片bug修复并测试:

        新建类:CustomXWPFDocument继承XWPFDocument

      添加方法:createPic

      

     public void createPic(String blipId,int id, int width, int height,CTInline inline) {
             final int EMU = 9525;
             width *= EMU;
             height *= EMU;
             //String blipId = getAllPictures().get(id).getPackageRelationship().getId();
    
             //CTInline inline = createParagraph().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>";
    
             //CTGraphicalObjectData graphicData = inline.addNewGraphic().addNewGraphicData();
             XmlToken xmlToken = null;
             try
             {
                 xmlToken = XmlToken.Factory.parse(picXml);
             }
             catch(XmlException xe)
             {
                 xe.printStackTrace();
             }
             inline.set(xmlToken);
             //graphicData.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("Picture " + id);
             docPr.setDescr("Generated");
        }
    CustomXWPFDocument
        @Test
        public void testPoi1() {
            try {
                //docx文件的文档对象
                CustomXWPFDocument xwpfDocument=new CustomXWPFDocument(POIXMLDocument.openPackage("D:/testPoi.docx"));
                //遍历页眉页脚
                for (XWPFHeaderFooter xwpfhf : xwpfDocument.getHeaderList()) {
                    //这部分可以作为方法提取出来
                    for (XWPFParagraph xwpfParagraph : xwpfhf.getParagraphs()) {
                        for (XWPFRun xwpfRun : xwpfParagraph.getRuns()) {
                            //图片替换添加  在页眉上添加图片没有实现
                            if("${二维码}".equalsIgnoreCase(xwpfRun.getText(xwpfRun.getTextPosition()))){
                                //{2}
                                //添加图片前,设置段落行角色为    自动
                                xwpfParagraph.setSpacingLineRule(LineSpacingRule.AUTO);
                                CTInline ctinline=xwpfRun.getCTR().addNewDrawing().addNewInline();
                                String id = xwpfDocument.addPictureData(new FileInputStream(new File("D:\erweima.jpg")), Document.PICTURE_TYPE_JPEG);
                                int id2=xwpfDocument.getAllPackagePictures().size()+111;
                                xwpfDocument.createPic(id,id2, 259, 259,ctinline);
                            }
                        }
                    }
                }
                //XWPFParagraph 包含在文档/表格/标题中的段落(段落中包含很多样式信息)
                //需求:替换段落中的文本/图片等,不涉及新加段落
                //遍历文档的段落对象(不包括页眉页脚)
                for (XWPFParagraph xwpfParagraph : xwpfDocument.getParagraphs()) {
                    //XWPFRun对象定义了文本区域的一组公共的属性
                    for (XWPFRun xwpfRun : xwpfParagraph.getRuns()) {
                        //文本替换
                        if("${营业执照}".equalsIgnoreCase(xwpfRun.getText(xwpfRun.getTextPosition()))){
                            //{1}
                            xwpfRun.setColor("FF0000");//设置文本颜色
                            xwpfRun.setText("我的营业执照",0);//文本替换
                            //xwpfRun.setText("我的营业执照1",-1); //在当前文本后追加文本
                            //xwpfRun.setText("我的营业执照12",2); //在当前文本后追加文本
                            //xwpfRun.setText("我的营业执照11",1); //在“我的营业执照1”后追加文本
                        }
                        //图片替换添加
                        if("${二维码}".equalsIgnoreCase(xwpfRun.getText(xwpfRun.getTextPosition()))){
                            //{2}
                            //添加图片前,设置段落行角色为    自动
                            xwpfParagraph.setSpacingLineRule(LineSpacingRule.AUTO);
                            CTInline ctinline=xwpfRun.getCTR().addNewDrawing().addNewInline();
                            String id = xwpfDocument.addPictureData(new FileInputStream(new File("D:\二维码.PNG")), Document.PICTURE_TYPE_JPEG);
                            int id2=xwpfDocument.getAllPackagePictures().size()+1;
                            xwpfDocument.createPic(id,id2, 259, 259,ctinline);
                        }
                    }
                }
                //文档create 添加图片失败
                //xwpfDocument.createParagraph().createRun().addPicture(new FileInputStream(new File("D:/二维码.PNG")), Document.PICTURE_TYPE_PNG, "二维码", Units.toEMU(200), Units.toEMU(200));
                FileOutputStream fos = new FileOutputStream(new File("D:/testPoi1.docx"));
                xwpfDocument.write(fos);
                fos.flush();
                fos.close();
            } catch (IOException e) {
                System.out.println("加载文件失败");
                e.printStackTrace();
            } catch (Exception e) {
                System.out.println("序列化图片失败");
                e.printStackTrace();
            }
        }
    添加图片测试

    图片添加经常出现如图的效果:

    这是图片空间不足引起的,在document.xml中查看是:

    <w:spacing w:line="500" w:lineRule="exact"/>

    所以设计模板时或者在代码中修改为  w:lineRule='auto'即可

    测试代码和word文件:http://yunpan.cn/cfKAtVfakJQpN (提取码:31a0)

    注:页眉页脚中添加/替换图片都没有实现,求探讨指教

    注:4/5年没写过文章了,特别生疏,勿怪

    注:做的时候出现不少错误,待添加

    另外,freemarker的实现会放在下一篇中。

  • 相关阅读:
    Scrapy框架-scrapy框架快速入门
    Scrapy框架-scrapy框架架构详解
    linux常用命令大全
    Redis常用命令大全
    centos7安装keepalived问题
    redis集群部署那点事
    centos7安装python3.6后导致防火墙功能无法正常工作的解决办法
    MySQL/Oracle视图的创建与使用
    通过sqoop将hdfs数据导入MySQL
    股票交易日定时爬取上交所/深交所所有股票行情数据存储到数据库
  • 原文地址:https://www.cnblogs.com/chonghua/p/4148706.html
Copyright © 2020-2023  润新知