java项目PC端调用条码打印机打印条码/吊牌(JS实现)

因为项目需要,开发一个使用条码打印机打印商品条形码和吊牌的功能,首先先上个最后的结果图

条码打印和吊牌打印

过程中遇到了一些坑,先简单说明一下

1:我这边使用的是佳博的条码打印机,最开始到佳博的开发平台下载了相关的文档,并按照说明文档进行了开发,能顺利打印条码和吊牌,我采用的打印方式是使用TSCLIB,也就是将TSCLIB.dll文件拷贝到系统盘Windows/system32下,然后安装好条码打印机对应的驱动(但是这里有个坑,也就是通过写后台代码来实现,这种方式来实现,会发现只能自己电脑打印,换句话说,就是只能调用服务器端的打印机驱动,也就是得在服务器端安装驱动,和将TSCLIB.dll放到服务器上的指定文件下,而不是使用客户端的电脑驱动打印,而且服务器一般都是使用Linux系统,所以这种方式好像没办法搞,坑)。网上很多这些类似调用说明的文档,以下是TSCLIB.dll方式调用驱动的代码

package com.xingwei.sale.common.utils;
import java.io.UnsupportedEncodingException;

/**
 * @class:PrintBarcodeUtil 
 *@descript:java使用编程接口打印条形码
 *@author FUYONGJIN
 *@date:2019年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值20
	        	Integer 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值20
	        	y += 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为条码打印机驱动文件

3-2: 安装说明,使用USB数据线连接电脑,会有也U盘显示连接,在U盘里有打印机安装包,拿到安装包解压,并按照说明安装打印机
  (如果安装打印机失败,可尝试 Gprinter条码打印机驱动 文件下的PrnInst.exe应用程序安装,
  安装步骤参考佳博官方最新的条码打印机驱动安装教程:http://www.gainscha.com/cjwt/202.html)
  
3-3:安装LODOP打印控件, 点击安装应用程序安装即可,(建议设置成默认开机启动) 官方控件下载路径:http://www.lodop.net/download.html

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图片,然后保存到服务器,打印的时候再获取到图片来打印,反正看到这个说明我连试一下的想法都没有了。

以上。

如果大家有更好的方法,希望可以分享。

 

 

 

 

 

 

 

 

 

 

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