因为项目需要,开发一个使用条码打印机打印商品条形码和吊牌的功能,首先先上个最后的结果图
过程中遇到了一些坑,先简单说明一下
1:我这边使用的是佳博的条码打印机,最开始到佳博的开发平台下载了相关的文档,并按照说明文档进行了开发,能顺利打印条码和吊牌,我采用的打印方式是使用TSCLIB,也就是将TSCLIB.dll文件拷贝到系统盘Windows/system32下,然后安装好条码打印机对应的驱动(但是这里有个坑,也就是通过写后台代码来实现,这种方式来实现,会发现只能自己电脑打印,换句话说,就是只能调用服务器端的打印机驱动,也就是得在服务器端安装驱动,和将TSCLIB.dll放到服务器上的指定文件下,而不是使用客户端的电脑驱动打印,而且服务器一般都是使用Linux系统,所以这种方式好像没办法搞,坑)。网上很多这些类似调用说明的文档,以下是TSCLIB.dll方式调用驱动的代码
package com.mon.utils;import java.io.UnsupportedEncodingException;/*** @class:PrintBarcodeUtil *@descript:java使用编程接口打印条形码*@author FUYONGJIN*@date:04月19日 下午16:02*@version:V1.0*/public class PrintBarCodeUtils {//加载库文件private static final String LOAD_LIBRARY="TSCLIB";//打印机型号private static final String print_model="Gprinter GP-2120TU";/*** @class:TscLibDll *@descript:创建TSCLIB.dll编程接口*动态链接库TSCLIB.dll,支持大部分佳博打印机,和其他品牌的TSC系列的打印机*@version:V1.0*/public interface TscLibDll extends Library {TscLibDll INSTANCE = (TscLibDll) Native.loadLibrary ("TSCLIB", TscLibDll.class);//显示DLL的版本号码int about ();//指定计算机端的输出端口int openport (String pirnterName);//关闭指定计算机输出端口int closeport ();//发送内建指令到条形码打印机int sendcommand (String printerCommand);//设定标签的宽度、高度、打印速度、打印浓度、传感器类别、垂直间距、偏移距离int setup (String width,String height,String speed,String density,String sensor,String vertical,String offset);//下载单色pcx格式图文件至打印机int downloadpcx (String filename,String image_name);//使用条形码机内建条形码打印int barcode (String x,String y,String type,String height,String readable,String rotation,String narrow,String wide,String code);//使用条形码机内建文字打印int printerfont (String x,String y,String fonttype,String rotation,String xmul,String ymul,String text);//清楚int clearbuffer ();//打印标签内容 set:打印标签的个数,copy :打印标签的分数int printlabel (String set, String copy);//跳页,要在setup方法后使用int formfeed ();//设定纸张不回吐int nobackfeed ();//使用window ttf 字形打印文章int windowsfont (int x, int y, int fontheight, int rotation, int fontstyle, int fontunderline, String szFaceName, String content);}/*** 打印条码接口* @param message 条码信息* @param text 显示文本* @param sn 商品编码* @param num 打印条码数量*/public static void printBarcode(String message,String text,String sn,Integer num) throws RuntimeException{try {//加载驱动System.loadLibrary(LOAD_LIBRARY);//解决中文乱码System.setProperty("jna.encoding", "GBK"); //TscLibDll.INSTANCE.about();TscLibDll.INSTANCE.openport(print_model);//TscLibDll.INSTANCE.downloadpcx("C:\\UL.PCX", "UL.PCX");//TscLibDll.INSTANCE.sendcommand("REM ***** This is a test by JAVA. *****");TscLibDll.INSTANCE.setup("40", "35", "5", "8", "0", "2", "0");TscLibDll.INSTANCE.clearbuffer();//TscLibDll.INSTANCE.sendcommand("PUTPCX 550,10,\"UL.PCX\"");List<String> contentList = getBarCodeContent(text, sn,10);for(int i = 0 ; i < contentList.size(); i ++ ){//默认每行占高度30,起始行y值20Integer y = i*30+20;if(contentList.size() < 4){y = i*30+50;}TscLibDll.INSTANCE.printerfont("20",y.toString(),"TSS24.BF2", "0", "1", "1", contentList.get(i));}Integer barCodeY = contentList.size()*38;if(contentList.size() < 4){barCodeY = 150;}TscLibDll.INSTANCE.barcode("20", barCodeY.toString(), "128", "50", "1", "0", "2", "2", message);//TscLibDll.INSTANCE.windowsfont(400, 200, 48, 0, 0, 1, "arial", "DEG 0");TscLibDll.INSTANCE.printlabel("1", num.toString());TscLibDll.INSTANCE.closeport();} catch (Exception e) {throw new RuntimeException("打印机连接异常!", e);} catch (Error e) {throw new RuntimeException("打印机连接异常!!!", e);}}/*** 吊牌打印接口* @param attrOne 规格一:如颜色* @param attrTwo 规格二:如大小* @param text文本:如商品名称* @param sn 编码:如商品编码* @param price 直播价:如商品直播价* @param num打印数量* @throws RuntimeException*/public static void printTag(String attrOne,String attrTwo,String price,String text,String sn,Integer num) throws RuntimeException{try {//加载驱动System.loadLibrary(LOAD_LIBRARY);//解决中文乱码System.setProperty("jna.encoding", "GBK"); TscLibDll.INSTANCE.openport(print_model);TscLibDll.INSTANCE.setup("40", "35", "5", "8", "0", "2", "0");TscLibDll.INSTANCE.clearbuffer();List<String> contentList = getBarCodeContent(text, sn,10);//每行的起始y坐标值Integer y = 20;//先打印商品名称和编码for(int i = 0 ; i < contentList.size(); i ++ ){TscLibDll.INSTANCE.printerfont("20",y.toString(),"TSS24.BF2", "0", "1", "1", contentList.get(i));//默认每行占高度30,起始行y值20y += 30;}y+=10;//颜色过长做换行处理List<String> attrOneList = getBarCodeContent(attrOne, null,14);for(int i = 0 ; i < attrOneList.size(); i ++ ){TscLibDll.INSTANCE.printerfont("20",y.toString(),"TSS24.BF2", "0", "1", "1", attrOneList.get(i));y +=30;}TscLibDll.INSTANCE.printerfont("20",(y).toString(),"TSS24.BF2", "0", "1", "1", attrTwo);y+=30;TscLibDll.INSTANCE.printerfont("20",y.toString(),"TSS24.BF2", "0", "1", "1", price);TscLibDll.INSTANCE.printlabel("1", num.toString());TscLibDll.INSTANCE.closeport();} catch (Exception e) {throw new RuntimeException("打印机连接异常!", e);} catch (Error e) {throw new RuntimeException("打印机连接异常!!!", e);}}/*** 动态控制标签内容的函数,默认一行显示长度10* @param content (如商品名称)* @param sn (如商品编码)* @param length 长度,一行显示多少个字符* @return*/private static List<String> getBarCodeContent(String content,String sn,Integer length){List<String> list = new ArrayList<>();Integer lenght = content.length();//每行默认10个长度,去有多少行Integer rows = lenght / length;//去余数,如果不整除,说明还有一行Integer lastRowLenght = lenght % length;for(int i = 0;i < rows ; i++){String rowContent = content.substring(i*length, i*length+length);list.add(rowContent);}if(lastRowLenght > 0){String rowContent = content.substring(rows*length, lenght);list.add(rowContent);}if(StringUtils.isNotEmpty(sn)){list.add("货号:"+sn);}return list;}//测试public static void main(String[] args) throws UnsupportedEncodingException {List<String> list=new ArrayList<String>(); list.add("KJ4.1-0127-0001(001)"); /*list.add("KJ4.1-0128-0001(001)"); list.add("KJ4.1-0129-0001(001)"); list.add("KJ4.1-0130-0001(001)"); */String goodsName = "圆领长袖短款";if(list!=null && list.size()>0){ for(String message:list){ printBarcode(message,goodsName,"30190422114257",1);} } System.out.println("打印成功");//printTag("黄色,蓝色,白色,黑色,绿色,荧光绿,浅黄色", "S, M, L, XL, XXL", "直播价:¥39.9", "胸前钉珠蕾丝袖黑色连衣裙", "YMT0324-04366", 1);}}
如果这种方式能够满足你们的需求,你们这个工具类应该是可以直接用的了,唯一要注意的问题就是,条码打印机的纸张大小,好像不能自动换行,所以需要自己代码控制每行的长度比如getBarCodeContent这个方法,多行的话重复TscLibDll.INSTANCE.printerfont("20",y.toString(),"TSS24.BF2", "0", "1", "1", contentList.get(i));。
2:发现TSCLIB.dll这种方式没法调用客户端的打印机的时候,然后就是试了一下接下来要说的这种方法,其实也就是通过js控制来调用浏览器的打印功能 js 代码:<
a
href
=
"javascrīpt:window.print()"
rel
=
"external nofollow"
target
=
"_self"
>打印</
a
>
然后通过样式和js来控制需要打印的模块即可,如样式(
过滤不需要打印的模块)
<style type="text/css">@media print {.noprint{display: none;}}</style>
接下来说明一下为什么不用这个方式,首先这个方式肯定是可以识别到客户端的电脑打印驱动的,也能够正常打印出来,不过问题是window.print()调用去浏览器打印,默认的预览是A4纸的,而条形码根本就不需要那么大,而且都是默认居中,反正就是最后打印出来的结构不理想,或者说根本不能用,有些文档说可以通过样式来控制,也许可以,不过我调了很久样式,根本调不到合适,也许大家可以试一下,反正我果断放弃这种实现的想法了。
3:接下来就讲一下最终使用的可以的方法
使用lodop控件来实现,控件是可以识别到客户机的打印机驱动的,准备工作如下
PC端erp商品管理条码打印,吊牌打印功能,连接条码打印机功能说明:
3-1:文件夹说明 CLodop_Setup_for_Win32NT.zip 为LODOP打印控件文件,Gprinter条码打印机驱动.rar为条码打印机驱动文件
(如果安装打印机失败,可尝试 Gprinter条码打印机驱动 文件下的PrnInst.exe应用程序安装, 安装步骤参考佳博官方最新的条码打印机驱动安装教程:/cjwt/202.html) 3-3:安装LODOP打印控件, 点击安装应用程序安装即可,(建议设置成默认开机启动) 官方控件下载路径:/download.html3-2: 安装说明,使用USB数据线连接电脑,会有也U盘显示连接,在U盘里有打印机安装包,拿到安装包解压,并按照说明安装打印机
3-4:打印机安装准备完成.
直接上这一块的代码
<script language="javascript" src="${contextPath}/static/front/common/js/LodopFuncs.js"></script><object id="LODOP_OB" classid="clsid:2105C259-1E0C-4534-8141-A753534CB4CA" width=0 height=0> <embed id="LODOP_EM" type="application/x-print-lodop" width=0 height=0></embed></object><script type="text/javascript">function printBarcodeOrTag() {LODOP=getLodop(); LODOP.PRINT_INIT("条码打印/吊牌");var productNumber = $("#productNumber").text();var productIds = $("#productIds").val();var barcodeNumber = $("#barcodeNumber").val();var printType = $("#printType").val();if(0 == parseInt(productNumber)){alert("请先选择商品!!!");return ;}if(!(/(^[1-9]\d*$)/.test(barcodeNumber))){alert("打印数量只能输入正整数!!!");return;}$.ajax({ type:"POST",url:"${contextURL}/sales/product/getBarCodeOrTagData.jspx", dataType:"json",data:{"productIds":productIds},success: function(data){var data = data.data;if(data.success==false ){ alert("打印失败!"+data.errorMsg); }else{for (i=0;i<data.length ;i++ ){ var goodsName = data[i].name;var goodsSn = data[i].sn;var goodsBarcode = data[i].barCode;var goodsAttrOne = data[i].attrOne;var goodsAttrTwo = data[i].attrTwo;var goodsPrice = data[i].price.toFixed(2);var nameList = getBarCodeContent(goodsName,10);if(printType == 'tag'){ //吊牌LODOP.SET_PRINT_PAGESIZE(1,"5cm","3.8cm","");var rowHei = 10;for(var j = 0 ; j< nameList.length;j++){LODOP.ADD_PRINT_TEXT(rowHei,10,"100%","100%",nameList[j]);rowHei +=15;}LODOP.ADD_PRINT_TEXT(rowHei,10,"100%","100%","货号:"+goodsSn);LODOP.ADD_PRINT_TEXT(rowHei+15,10,"100%","100%",goodsAttrOne);LODOP.ADD_PRINT_TEXT(rowHei+30,10,"100%","100%",goodsAttrTwo);LODOP.ADD_PRINT_TEXT(rowHei+45,10,"100%","100%","直播价:¥"+goodsPrice);LODOP.SET_PRINT_STYLEA(0,"Stretch",2);//按原图比例(不变形)缩放模式}else{ //条码LODOP.SET_PRINT_PAGESIZE(1,"5cm","3.8cm","");var rowHei = 10;for(var j = 0 ; j< nameList.length;j++){LODOP.ADD_PRINT_TEXT(rowHei,10,"100%","100%",nameList[j]);rowHei +=15;}LODOP.ADD_PRINT_TEXT(rowHei,10,"100%","100%","货号:"+goodsSn);LODOP.ADD_PRINT_BARCODE(rowHei+20,10,155,40,"128Auto",goodsBarcode);LODOP.SET_PRINT_STYLEA(0,"Stretch",2);//按原图比例(不变形)缩放模式}if(i+1 != data.length){LODOP.NEWPAGE(); //分页}} $(".Modal_box").addClass("disNone");$(".Modal_box").children().hide();LODOP.SET_PRINT_COPIES(barcodeNumber); //数量LODOP.PREVIEW(); //预览打印//LODOP.PRINT(); //直接打印} }});};function getBarCodeContent(content,rowLen){var list = new Array();var contentLen = content.length;//每行默认10个长度,去有多少行var rows = parseInt(contentLen / rowLen);//去余数,如果不整除,说明还有一行var lastRowLenght = contentLen % rowLen;for(var i = 0;i < rows ; i++){let rowContent = content.substring(i*rowLen, i*rowLen+rowLen);list[i]=rowContent;}if(lastRowLenght > 0){let rowContent = content.substring(rows*rowLen, contentLen);list[list.length]=rowContent;}return list;};</script>
具体的大家可以参考一下其他文档,这里再讲一下一个可能需要注意的问题,LODOP这个控件好像是需要钱的,如果不预览直接打印,会显示试用版打印控件字样,通过预览,然后再打印的话,就没有改字样。
4:还有一种没有是试过的方式,先将需要打印的内容转换成PDF图片,然后保存到服务器,打印的时候再获取到图片来打印,反正看到这个说明我连试一下的想法都没有了。
以上。
如果大家有更好的方法,希望可以分享。