執法文書打印的實現(一)


    最近公司做質檢的執法項目,牽涉到執法文書的打印。這個功能實現的時候走了不少彎路,簡單記錄下,以備后用。

    甲方的要求比較苛刻: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的實現會放在下一篇中。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM