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

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

甲方的要求比较苛刻: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‘即可

时间: 2024-11-02 17:20:48

执法文书打印的实现(一)的相关文章

《软件工程》课程报告 —国土资源执法监察管理信息系统建模

一.问题描述与需求分析 国土资源执法监察管理信息系统的用户需求以及面向对象建模. 分析题目,可知软件的的重点不是国土资源的执法本身,而是对执法进行监察, 主要工作有各级各部门开展核查.整改查处.督查.验收和存档,另外还应能处理群众即投诉人的举报投诉.涉及的有关部门总的有投诉人.国土资源局.政府.监察局:而国土资源局里的分工比较明确,可以进一步划分为地籍科.规划科.用地科(利用科).耕保科.监察科(在国土资源局内部也有相应的监察科):政府也可以按等级进行细分,大体有市政府.省厅. 经过查阅相关资料

执法记录仪视频恢复案例

执法记录仪又称警用执法记录仪或现场执法记录仪.集数码摄像.数码照相.对讲送话器功能于一身,能够对执法过程中进行动态.静态的现场情况数字化记录,便于公安干警在各种环境中执法使用,为执法人员提供了更为安全有效的证据. 近期遇到某支队的请求其在一次出警过程中出现暴力抗法情况,且记录仪被抢夺里面视频则全部被格式化导致现场情况视频全部丢失,客户使用执法仪为警翼执法仪,内存为32G空间,遭遇删除后没有进行录制,根据以上客户提供信息觉得恢复的可能性极大,让客户将执法仪通过专业工具进行镜像后进行视频的提取恢复操

绍兴启动“掌上执法”严查超载车辆

有违法记录的车辆迟迟无法“归案”,给路政人员办案留下了一道道难题.昨天,记者从我市公路部门了解到,我市路政人员即将启用一款APP,可实时查询运输车辆的超载记录.“与交警的警务通是一个道理,只要输入车牌号码,很快就能查到这辆车有没有超载记录.”市公路局路政科负责人介绍. 近年来,我市不断创新技术手段,提升公路治超实效.市直治超大队将辖区内50个建筑工地摄像头接入视频监控系统,实行全天候监控.此外,还建设桥梁超限车辆智能监控.治超信息抄告等4个子系统,公路视频监控与公安部门3万余个固定摄像点.380

ARP欺骗 ---网络执法官(转载)

body { font-family: 微软雅黑,"Microsoft YaHei", Georgia,Helvetica,Arial,sans-serif,宋体, PMingLiU,serif; font-size: 10.5pt; line-height: 1.5; } html, body { } h1 { font-size:1.5em; font-weight:bold; } h2 { font-size:1.4em; font-weight:bold; } h3 { fon

构建执法阅读笔记02

通过阅读构建之法,这一次了解了代码的规范性,在这之前的编写程序的时候,由于对英语的标准命题知道的不是太多,在命名德时候多数用汉语拼音进行命名,自我感觉提方便,但是阅读构建执法的代码片发现这是不好的习惯.其次平常编写程序会表明姓名和日期,进行大框架的解释,便于日后进行来了解编写的内容.同时注意缩进,行宽,括号的使用,分行的表示作用.但是了解后,含有许多需要改进的地方:例如程序设计.模块之间的关系.设计模式,当错误出现时如何进行处理.了解结对编程,两个人员相互肩并肩.平等地.互补地进行开发工作.就像

构建执法阅读笔记01

对于“程序=数据结构+算法”之前已经反复去讲解和思考了很多遍了,似乎是有一些理解,二叉树是数据结构,周游的实现细节是算法,这加起来就是程序吗?所有的程序都是这样子的吗?在JAVA和一些语言中并不会出现指针,那二叉树又有什么用呢?我们还要去学习它了解它吗?或者换一种说法,现在网络如此发达,诸如程序之类在网上随处都能搜到,我需要的时候可以直接拿来用,为什么还要去学习那么复杂的数据结构呢?我们真正需要会的程序代码是什么?究竟需要达到怎样一个水准? 在读了一部分<构建执法>后,邹欣老师的思想启发我对什

中科燕园GIS外包--环境保护执法移动GIS平台

整合分析及环境要素表达方面均有其独到的特长,非常适合处理复杂的环境系统问题.目前,GIS在环境污染监测.生态分析.环境应急等领域已积累了大量的应用.未来随着数据共享.业务模型积累.制图技术和新技术推动,GIS在环境将会迎来更加广阔的应用前景. 移动执法系统是用于环境监察部门的业务管理系统,系统中很好的体现了环保的业务工作流程.环保执法系统主要分为Web端和移动端. Web端使用ArcGIS API for Flex开发,主要有任务管理.事件管理.任务地图分布.事件地图分布.巡查轨迹和绩效考核等功

中科燕园GIS外包案例--移动执法系统

整合分析及环境要素表达方面均有其独到的特长,非常适合处理复杂的环境系统问题.目前,GIS在环境污染监测.生态分析.环境应急等领域已积累了大量的应用.未来随着数据共享.业务模型积累.制图技术和新技术推动,GIS在环境将会迎来更加广阔的应用前景. 移动执法系统是用于环境监察部门的业务管理系统,系统中很好的体现了环保的业务工作流程.环保执法系统主要分为Web端和移动端. Web端使用ArcGIS API for Flex开发,主要有任务管理.事件管理.任务地图分布.事件地图分布.巡查轨迹和绩效考核等功

《构建执法》要点总结

第一章 概论 <构建执法>中对软件工程的定义是:把系统的.有序的.可量化的方法应用到软件的开发.运营和维护上的过程.包括:软件 需求分析.软件设计.软件构建.软件测试和软件维护.软件工程与计算机科学.计算机工程.管理学.数学.项目管理学.质量管理.软件人体工学.系统工程. 工业设计和用户界面设计等学科相关. 对软件的定义是:可以运行在计算机及电子设备中的指令和数据的有序集合. 由于软件开发有复杂性.不可见性.易变性.服从性.非连续性的特点,软件的开发并没有像硬件一样得到飞速的发展. 计算机科学