使用其他方式实现润乾报表的静默打印
思路分析
静默打印:在页面上点击打印按钮,不需要选择预览,也不需要选择打印机,直接向打印机发送打印任务。
润乾现有方法
润乾报表目前网页端支持三种打印方式:applet打印、flash打印、PDF打印
- applet打印
支持静默打印,但是仅仅在IE流程中可以使用applet打印,局限性太大。而且浏览器的配置较复杂,且不能轻易升级jar的版本,如果升级则打印失效。 - flash打印
不支持静默打印,谷歌浏览器将于2020年末停止支持flash。 - PDF打印
打印效果很好,但是依然不支持静默打印。
新方案
-
思路借鉴:
浏览器实现静默打印的难点在于浏览器无法获取打印机的相关配置,探索阶段了解了lodop软件,它是通过插件来实现打印,原理类似在本地安装一个windows NT服务,然后html页面将需要打印的内容发送到NT服务,再由服务去调用打印执行打印任务。 -
受到上面的思路启发,我在想我们是不是也可以做成这样的:用户在前台点击打印按钮,我们将需要打印的数据记录到数据库打印任务中(字段包括打印机名称、打印报表名称、打印参数等),然后再写一个【客户端】运行在服务器上,定时查询打印任务去调用打印机进行打印。这个方案适用于我们当前的项目,项目是一个仓库软件位于局域网中。
具体实现
下面展示客户端的主要代码
。
- 主要打印代码
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;
}
}
- 执行打印
// 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);
}
}
- 获取本机打印机列表
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下可行,有机会试一下。
上一篇: 函数
下一篇: 利用 FRP 实现外网访问 NAS