小编最近完成了一个“套打”的工作,做个总结,以备后续参考。
一、套打是什么
起初组长让我做“工行信用卡套打”功能时,我还是比较懵的,什么是套打,百度了一下,类似发票打印,把要打印的内容放到预留的空位上,执行打印。如图,是我这次套打需要的模板:
二、方案选型
开始工作前,做了调研,可实行的方案:
1.“jasperreport + ireport”
2."lodop"
3."itext"
4."fineReport"
5."ActiveX控件"
在详细说明我的选型方案之间,分享一些针对各个方案我花了好几天时间找到的好的素材:
(1)jasper + ipreport 文字教程(很详细)
(3)jasper免费视频教程
(4)jasper书籍
以及不错的几篇博客,关于套打:
http://blog.csdn.net/qq_18875541/article/details/69392215
http://blog.csdn.net/smvcn/article/details/8672537 (本地打印jasper)
http://blog.csdn.net/gong0585/article/details/5319367 (套打模板布局设计)
http://blog.csdn.net/u014704879/article/details/49613775
1.起初,我是确定使用“jasper+ireport”方式来做的,这个方式国外用的比较多,但是奈何学习成本比较高,学习资料少,那段时间晚上回家我都是在YouTuBe上搜索教学视频学习,遇到问题能够咨询的人也比较少,最致命的一点,是工行的单子打印点实在是太密了,jasper打印的精度不能打到我的要求。
2.尝试Itext,基本上就是手动挖空,预留位置,实现套打,也不能满足要求。
3.fineReport需要付费,如果涉及复杂的企业报表,使用这种比价好。
4.ActiveX,用于PDF的打印比较好,套打需要程序控制C端打印机,很难做到,而且目前各大浏览器开始放弃对ActiveX的维护。
5.lodop,最后确定使用lodop实现,能实现精准打印,国人开发的插件,如果说2010年之前套打用外国人的插件很必要,现在我们国人做的东西也不是吹出来的。
三、注意问题
1.套打之前需要1:1扫描“工行信用卡申请表”,自己把握不好就赶紧去打印店吧,不然上线了还会影响C端使用。
2.套打按钮的数据权限,一定要做好。
3.如何引导C端用户,首次使用套打功能时,能够按照提示,顺利安装成对应浏览器版本下的Lodop插件版本。
4.c端门店打印机型号如果不确定,最好提前在程序中进行埋点获取门店打印机型号,或者找业务人员去调查,做适配。
5.关于lodop水印问题,提前想好是先通过预览窗口再打印,还是直接买lodop正版。
四、实现思路
这里不展示,具体lodop的教程,详情参考官网,由于最终会有大量入下代码出现:
LODOP=getLodop();
LODOP.PRINT_INITA(0,0,1500,900,"0");
LODOP.SET_PRINT_PAGESIZE(2,3780,2080,"");
LODOP.SET_SHOW_MODE("BKIMG_LEFT",0);
LODOP.SET_SHOW_MODE("BKIMG_TOP",0);
LODOP.SET_SHOW_MODE("BKIMG_WIDTH","378.09mm");
LODOP.SET_SHOW_MODE("BKIMG_HEIGHT","207.96mm");
LODOP.SET_SHOW_MODE("BKIMG_PRINT",true);
LODOP.ADD_PRINT_TEXT(168,46,133,20,custom);
LODOP.ADD_PRINT_TEXT(197,57,17,18,man);
LODOP.ADD_PRINT_TEXT(197,83,16,18,woman);
LODOP.ADD_PRINT_RECT(914,1455,65,21,0,1);
LODOP.ADD_PRINT_TEXT(195,256,80,20,birthYear);
LODOP.SET_PRINT_STYLEA(0,"LetterSpacing",9);
LODOP.ADD_PRINT_TEXT(195,327,42,20,birthMonth);
LODOP.SET_PRINT_STYLEA(0,"LetterSpacing",8);
LODOP.ADD_PRINT_TEXT(195,366,60,20,birthDay);
LODOP.SET_PRINT_STYLEA(0,"LetterSpacing",10)
LODOP.ADD_PRINT_TEXT(233,47,403,20,idNumber);
LODOP.SET_PRINT_STYLEA(0,"LetterSpacing",7);
LODOP.ADD_PRINT_TEXT(254,264,69,20,validdateEndYear);
LODOP.ADD_PRINT_TEXT(253,335,38,20,validdateEndMonth);
LODOP.SET_PRINT_STYLEA(0,"LetterSpacing",6);
LODOP.ADD_PRINT_TEXT(253,373,43,20,validdateEndDay);
我采取的方案是在目录下新建好html模板,比如起名“vincent-print.html”,其中会在lodop的CreatePrintPage()函数中放入lodop生成代码,这里我用一个套打“快递单”(不涉及公司隐私)为例,
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK">
<style>
*{
padding:0;
margin:0
}
@font-face {
font-family: 'HYZhongJianHeiJ', 'simhei';
src: url(hyjh.ttf), url(hei.ttf);
}
@page {
size: A4;
margin-left: 1cm;
margin-right: 1cm;
margin-top: 0cm;
margin-bottom: 0cm;
}
body {
font-family: 'HYZhongJianHeiJ';
}
@charset "utf-8";
html, body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, textarea, p, blockquote, th, td, em, button {
margin: 0;
padding: 0
}
body {
line-height: 2em;
color: #333;
background-color: #fff;
}
img, fieldset {
border: none;
vertical-align: middle
}
table {
border-collapse: collapse
}
a {
color: #06c;
text-decoration: none;
cursor: pointer
}
</style>
</head>
<body>
<script language="javascript" src="LodopFuncs.js"></script>
<script language="javascript" type="text/javascript">
var LODOP; //声明为全局变量
function CreatePrintPage() {
var custom = document.getElementById("customName").innerHTML;
var idNumber = document.getElementById("idNumber").innerHTML;
var memberName = document.getElementById("memberName").innerHTML;
LODOP=getLodop();
LODOP.PRINT_INIT("套打EMS的模板");
LODOP.ADD_PRINT_SETUP_BKIMG("D:\\b_work\\lodop\\kuaidi.jpg");
LODOP.SET_SHOW_MODE("BKIMG_WIDTH","209.02mm");
LODOP.SET_SHOW_MODE("BKIMG_HEIGHT","112.98mm");
LODOP.SET_SHOW_MODE("BKIMG_PRINT",true);
LODOP.ADD_PRINT_TEXT(97,91,90,20,custom);
LODOP.ADD_PRINT_TEXT(97,246,90,20,idNumber);
LODOP.ADD_PRINT_TEXT(164,34,320,20,memberName);
};
</script>
进入<a href="javascript:;" οnclick="javascript:CreatePrintPage();LODOP.PRINT_DESIGN();">模板设计</a><br><br>
进入<a href="javascript:;" οnclick="javascript:CreatePrintPage();LODOP.PREVIEW();">模板的打印预览</a>
<div hidden>
<p id="customName"><#if customName??>${customName}</#if></p>
<p id="memberName"><#if memberName??>${memberName}</#if></span></p>
<p id="idNumber"><#if idNumber??>${idNumber}</#if></span></p>
</div>
</body>
</html>
预留了一些变量,比如“customName”,"memberName","idNumber",之后在后台查询相关逻辑中,通过:
Map<Object, Object> varsb = new HashMap<Object, Object>();
作为一个容器,存放我查询出来的需要在套打单上显示的字段,之后通过类似方法:
return XXXXUtil.generateHtml(TEMPLATE_NEST, varsb).getBytes("UTF-8");
写一个工具类,将html页面,连同varbs变量值,一同返给前台去加载,再通过上述的<div>标签中截取回传的值,推送到预览页,最终实现打印,思路有了,工具类就不展示了,通过ServletContext来做的。
五、打印展示
最终做到了精确套打的功能,而且适配各种主流浏览器。
如有疑惑,欢迎交流。