使用其他方式實現潤乾報表的靜默打印

思路分析

靜默打印:在頁面上點擊打印按鈕,不需要選擇預覽,也不需要選擇打印機,直接向打印機發送打印任務。

潤乾現有方法

潤乾報表目前網頁端支持三種打印方式:applet打印、flash打印、PDF打印

  1. applet打印
    支持靜默打印,但是僅僅在IE流程中可以使用applet打印,侷限性太大。而且瀏覽器的配置較複雜,且不能輕易升級jar的版本,如果升級則打印失效。
  2. flash打印
    不支持靜默打印,谷歌瀏覽器將於2020年末停止支持flash。
  3. PDF打印
    打印效果很好,但是依然不支持靜默打印。

新方案

  1. 思路借鑑:
    瀏覽器實現靜默打印的難點在於瀏覽器無法獲取打印機的相關配置,探索階段瞭解了lodop軟件,它是通過插件來實現打印,原理類似在本地安裝一個windows NT服務,然後html頁面將需要打印的內容發送到NT服務,再由服務去調用打印執行打印任務。

  2. 受到上面的思路啓發,我在想我們是不是也可以做成這樣的:用戶在前臺點擊打印按鈕,我們將需要打印的數據記錄到數據庫打印任務中(字段包括打印機名稱、打印報表名稱、打印參數等),然後再寫一個【客戶端】運行在服務器上,定時查詢打印任務去調用打印機進行打印。這個方案適用於我們當前的項目,項目是一個倉庫軟件位於局域網中。

具體實現

下面展示客戶端的主要代碼

  1. 主要打印代碼
public class RaqPrint {
    
    static final Logger logger = Logger.getLogger(RaqPrint.class);
    
    /**
     * TODO 執行單個打印任務
     * @param exepath
     * @param printTask
     * @author kaixin
     * @throws Throwable
     */
    public static void ChildPrint(String exepath, Map<String, String> printTask) throws Throwable {
        // 如果是打印模板不爲空
        if (printTask.get("printtemplate") != null && !"".equals(printTask.get("printtemplate"))) {
            // 1.設置潤乾報表授權
            	setRaqLicense();
            // 2.計算報表
            IReport report = CalculateIReport.getReport(exepath, printTask);
            // 3.執行打印任務;查詢該機器是否配置有該打印機
            logger.info("打印機名稱:" + printTask.get("printer"));
            if (PrintUtil.getPrinterNames().contains(printTask.get("printer"))) {
                ReportUtils3.print(report, false, printTask.get("printer"));
                // 返回結果
                logger.info(printTask.toString()+"打印任務下發成功");
            } else {
                logger.error("找不到打印機:" + printTask.get("printer") + "。。。。。");
            }
        }
    }
 
    /**
     * 內部的授權文件
     * @throws Exception
     */
    public static void setRaqLicense() throws Exception {
        InputStream lis = ClassLoader.getSystemResourceAsStream("reportLicense20190531.xml");
        Sequence.readLicense(Sequence.P_RPT, lis);
    }
}

注:潤乾報表測試版授權可在
潤乾試用產品授權下載
2. 計算報表

// An highlighted block
/**
* TODO 計算並返回報表
* 
* @author kaixin
*
*/
public class CalculateIReport {

   static IConnectionFactory connFactory = new ConnFactory(); // 構造數據源工廠類,一般爲自定義類
   
   static final Logger logger = Logger.getLogger(CalculateIReport.class);

   /**
    * @title: getReport
    * @Description: 運算報表並返回報表啊
    * @param path  當前運行路徑
    * @param reportParams  報表參數以及報表名稱以及打印機等信息
    * @throws Exception
    * @return
    */
   public static IReport getReport(String exepath, Map<String, String> reportParams) throws Exception {
       String templateAddress = exepath + "/PrintTemplate/" + reportParams.get("printtemplate") + ".rpx";
       //創建報表
       ReportDefine rd = (ReportDefine) ReportUtils.read(templateAddress);
       System.out.println(templateAddress);
       //創建報表運行環境
       Context cxt = new Context();
       //設置數據源工廠
       cxt.setConnectionFactory("ds1", connFactory);
       
       //獲取報表所需要參數名稱
       ParamMetaData pmd = rd.getParamMetaData();
       
       //獲取print task 任務給定的參數集合
       String paramOrMocrName[] = reportParams.get("templateparams").split(",");
       Map<String, String> paramOrMocrNameMap = new HashMap<String, String>();
       for (int i = 0; i < paramOrMocrName.length; i++) {
           String key = paramOrMocrName[i].split("=")[0];
           String value = paramOrMocrName[i].split("=")[1];
           paramOrMocrNameMap.put(key, value);
       }
       logger.info("打印任務id:" + reportParams.get("id") + "任務參數如下"
               + paramOrMocrNameMap);
       
       //給報表參數賦值
       if (pmd != null) {
           for (int i = 0, count = pmd.getParamCount(); i < count; i++) { // 講究優化的寫法
               String param = pmd.getParam(i).getParamName(); // 獲取參數名
               cxt.setParamValue(param, paramOrMocrNameMap.get(param)); // 設參數值
           }
       }
       // 構造報表引擎
       Engine engine = new Engine(rd, cxt); 
       
       // 運算報表
       IReport iReport = engine.calc(); 
       return iReport;
   }
}
  1. 執行打印
// An highlighted block
import javax.swing.JFrame;

import com.raqsoft.report.control.PrintFrame;
import com.raqsoft.report.usermodel.IReport;

public class ReportUtils3 {

   public static void print(final IReport report, final boolean needSelectPrinter, String printerName)
           throws Throwable , Exception{
       final PrintFrame frame = new PrintFrame(report, (JFrame) null);
       frame.setModal(false);
       frame.setLocation(-1000, -1000);
       //判斷是否需要指定打印機名稱
       if (!needSelectPrinter) {
           frame.setPrinterName(printerName);
       }
       frame.show();
       frame.directPrint(needSelectPrinter);
   }
}
  1. 獲取本機打印機列表
import java.util.ArrayList;
import java.util.List;

import javax.print.DocFlavor;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;

import org.apache.log4j.Logger;

public class PrintUtil {
   
   static final Logger logger = Logger.getLogger(PrintUtil.class);
   /**
    * @title: getPrinterNames
    * @Description: 獲取打印機列表
    * @return List<String>
    * @author kaixin
    */
   public static List<String>  getPrinterNames() throws Exception{
        PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
        DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
        List<String> printNames = new ArrayList<String>();
        //可用的打印機列表(字符串數組)
        PrintService printService[] = PrintServiceLookup.lookupPrintServices(flavor, pras);
        
        //當前默認打印機
        for (int i = 0; i < printService.length; i++) {
            String serviceName = printService[i].getName();
            printNames.add(serviceName);
        }
        return printNames;
   }
   
}

末尾

以上是自己探索的一些拐着彎實現的靜默打印,不適用大多數互聯網場景,只適用於部分特定場景。
如果小夥伴有什麼好的建議,歡迎評論告訴小弟。

後記

爲了防止用戶不慎關閉或者多開,目前在考慮有沒有可能實現成網頁版本,用tomcat的manager去管理

類似:在前臺點擊打印按鈕,然後服務器後臺彈出Jframe(潤乾打印的PrintFrame是實現了Jframe的),然後調用服務器配置的打印機進行打印。

已經實現點擊startup.bat啓動的時候,可以彈出Jframe彈窗。但是通過service.bat把tomcat寫成一個NT服務的時候就不能彈出彈窗了。

看到一種方法,打開服務的屬性,選中【允許服務與桌面交互】,重啓服務即可。不知道是否在win10下可行,有機會試一下。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章