使用其他方式实现润乾报表的静默打印

思路分析

静默打印:在页面上点击打印按钮,不需要选择预览,也不需要选择打印机,直接向打印机发送打印任务。

润乾现有方法

润乾报表目前网页端支持三种打印方式: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下可行,有机会试一下。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值