因为项目需要,开发一个使用条码打印机打印商品条形码和吊牌的功能,首先先上个最后的结果图
过程中遇到了一些坑,先简单说明一下
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 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 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 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 getBarCodeContent(String content,String sn,Integer length){
List 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 list=new ArrayList();
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来控制需要打印的模块即可,如样式(
过滤不需要打印的模块)
接下来说明一下为什么不用这个方式,首先这个方式肯定是可以识别到客户端的电脑打印驱动的,也能够正常打印出来,不过问题是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:打印机安装准备完成.
直接上这一块的代码
具体的大家可以参考一下其他文档,这里再讲一下一个可能需要注意的问题,LODOP这个控件好像是需要钱的,如果不预览直接打印,会显示试用版打印控件字样,通过预览,然后再打印的话,就没有改字样。
4:还有一种没有是试过的方式,先将需要打印的内容转换成PDF图片,然后保存到服务器,打印的时候再获取到图片来打印,反正看到这个说明我连试一下的想法都没有了。
以上。
如果大家有更好的方法,希望可以分享。