前言
条码打印不同于普通打印机,条码大小各不相同,需要针对不同标签贴纸开发不同的样式
1. 条码打印的两种方案:
2. 优缺点分析:
| 优点 | 缺点 |
---|
后端ZPL指令打印 | 样式固定,不会出现兼容性问题 | 不能调用客户端打印机,打印机需要支持ZPL指令 | 前端调用浏览器打印 | 对打印机品牌没有要求,可以调用客户端打印机打印 | 样式比较难调整,中文需要单独下载字体 |
一.后端打印
前端打印主要是使用javax.print.* 包下的类通过给打印机发送ZPL指令的字符串实现打印服务, 核心的业务逻辑主要是寻找打印机,发送指令,如下:
public class ZebraService {
private static final Logger logger = LoggerFactory.getLogger(ZebraService.class);
public ZebraService(ZebraProperties zebraProperties) {
this.zebraProperties = zebraProperties;
PrintService[] services = PrintServiceLookup.lookupPrintServices(null,null);
if (services != null && services.length > 0) {
for (PrintService service : services) {
if (zebraProperties.getName().equals(service.getName())) {
printService = service;
break;
}
}
}
if (printService == null) {
logger.error("没有找到打印机:{}",zebraProperties.getName());
if (services != null && services.length > 0) {
for (PrintService service : services) {
logger.warn("可用的打印机:{}",service.getName());
}
}
}else{
logger.info("找到打印机:{},打印机名称:{}",zebraProperties.getName(),printService.getAttribute(PrinterName.class).getValue());
}
}
public boolean print(String zpl){
logger.info("当前ZPL:{}",zpl);
if(printService==null){
logger.error("打印出错:没有找到打印机{}",zebraProperties.getName());
return false;
}
DocPrintJob job = printService.createPrintJob();
byte[] by = zpl.getBytes();
DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
Doc doc = new SimpleDoc(by, flavor, null);
try {
job.print(doc, null);
logger.info("已打印");
return true;
} catch (PrintException e) {
logger.error("打印出错:{}",e.getMessage());
return false;
}
}
}
具体的组装ZPL指令可以查询ZPL手册
二.前端打印
前端打印我主要测试了两种方案:1.直接画html然后打印,2.生成pdf后打印 第一种方案css样式调整起来折磨人,直接选择第二种简单粗暴
1.这里主要使用了3个插件:
npm i jspdf
npm i jsbarcode
npm i qrcode
2. 先贴出完整代码
import {jsPDF} from "jspdf";
import './jianbaosong-normal'
const table = {
unit:'mm',
width:100,
height:80,
offset:2,
colH:10,
}
let doc;
function tableInit(){
doc = new jsPDF({
orientation: "landscape",
unit: table.unit,
format: [table.width, table.height]
});
}
function getRowY(indexRow,colH){
return table.offset+indexRow*colH;
}
export function pdfPrint(contents){
tableInit();
const length=contents.length
for (let i = 0; i < length; i++) {
if(i>0&& i<length){
doc.addPage([table.width,table.height],'landscape')
}
doc.setFont('jianbaosong');
doc.line(table.offset,table.offset,table.width-table.offset,table.offset)
doc.line(table.offset,table.offset,table.offset,table.height-table.offset)
doc.line(table.width-table.offset,table.offset,table.width-table.offset,table.height-table.offset)
doc.line(table.offset,table.height-table.offset,table.width-table.offset,table.height-table.offset)
doc.setFontSize(15)
doc.text("xxxxx股份有限公司",11,9);
doc.line(table.offset,getRowY(1,table.colH),table.width-table.offset,getRowY(1,table.colH))
doc.setFontSize(12)
doc.text("物料代码", 3, getRowY(2,table.colH)-3);
doc.text(contents[i].materialNo, 30+3, getRowY(2,table.colH)-3);
doc.line(30,getRowY(1,table.colH),30,getRowY(2,table.colH))
doc.line(table.offset,getRowY(2,table.colH),table.width-table.offset,getRowY(2,table.colH))
doc.text("物料名称", 3, getRowY(3,table.colH)-3);
doc.setFontSize(10)
doc.text(contents[i].materialName, 30+3, getRowY(3,table.colH)-3);
doc.line(30,getRowY(2,table.colH),30,getRowY(3,table.colH))
doc.line(table.offset,getRowY(3,table.colH),table.width-table.offset,getRowY(3,table.colH))
doc.setFontSize(12)
doc.text("供应商名称", 3, getRowY(4,table.colH)-3);
doc.setFontSize(10)
doc.text(contents[i].supplierName, 30+3, getRowY(4,table.colH)-3);
doc.line(30,getRowY(3,table.colH),30,getRowY(4,table.colH))
doc.line(table.offset,getRowY(4,table.colH),table.width-table.offset,getRowY(4,table.colH))
doc.setFontSize(12)
doc.text("物料数量", 3, getRowY(5,table.colH)-3);
doc.text(contents[i].volume+contents[i].mainUnit, 30+3, getRowY(5,table.colH)-3);
doc.line(30,getRowY(4,table.colH),30,getRowY(5,table.colH))
doc.line(table.offset,getRowY(5,table.colH),table.width-table.offset,getRowY(5,table.colH))
doc.text("发货日期", 3, getRowY(6,table.colH)-3);
doc.text(new Date().toISOString().split("T")[0],30+3, getRowY(6,table.colH)-3);
doc.line(30,getRowY(3,table.colH),30,getRowY(6,table.colH))
doc.line(table.offset,getRowY(6,table.colH),table.width-table.offset,getRowY(6,table.colH))
doc.addImage(contents[i].img, 'JPEG', 70, getRowY(6,table.colH)+1, 14, 14, '', 'FAST')
doc.addImage(contents[i].barcode, 'JPEG', 10, getRowY(6,table.colH)+1,48, 14, '', 'FAST')
}
window.open(doc.output('bloburl'), '_blank');
}
3. 再放生成效果
4.效果及代码解析
- 生成pdf对象
doc = new jsPDF({
orientation: "landscape",
unit: table.unit,
format: [table.width, table.height]
});
- 画线,横线竖线同理
doc.line(2,2,30,2)
- 内容,设置内容前设置字体样式,需要中文的话需要单独下载中文ttf字体,然后转成js文件,放入项目中,ttf文件转js可使用这个链接,然后直接使用字体名导入即可
doc.setFont('jianbaosong');
doc.setFontSize(12)
doc.text("供应商名称", 3, getRowY(4,table.colH)-3);
- 画一维码,二维码;这里是把一二维码图片的base64添加进pdf
doc.addImage(contents[i].img, 'JPEG', 70, getRowY(6,table.colH)+1, 14, 14, '', 'FAST')
具体一维码二维码生成方式见下篇文档
|