每日一博 | JFinal小插件:Java驱动打印小票

驱动打印小票--80热敏打印机 项目环境基于JFinal2 2 偷了个懒直接在JFinal demo上做的_ 在大神 SubLuLu thermal_printer 开

驱动打印小票--80热敏打印机

项目环境基于JFinal2.2 偷了个懒直接在JFinal demo上做的_

在大神 SubLuLu/thermal_printer 开源的项目基础上写了这个demo,SubLuLu用的是指令打印,而且环境是基于Android的,所以我用Java做的项目无法很方便的打印图片和兼容更多的热敏打印机,因此借鉴大神的构思我采用驱动方式进行打印。

* 我的项目地址:DriverPOSPrint *

打印流程

每日一博 | JFinal小插件:Java驱动打印小票

如图中所示,在项目实际使用中采用异步的方式进行打印。调用者只需要创建新的PrintJob 添加到任务队列中,挂起的线程就会被自动唤起完成打印任务

打印模板

模板采用Json格式存储,分为header、goods、warn、msg四个部分,对模板的解析采用阿里出品的fastjson,模板共5中,模板名称分别对应PrintJob中missionType

模板示例-(simple.json)

{

"header": [{

"text": "{$title}",

"size": 14,

"bold": true,

"align": 1,

"line": true,

"type": 0

},

{

"text": "品 牌:{$brandName}",

"size": 9,

"bold": false,

"align": 0,

"line": false,

"type": 0

},

{

"text": "({$shopName})",

"size": 9,

"bold": false,

"align": 0,

"line": true,

"type": 0

},

{

"text": "桌 号:{$tableNumb}",

"size": 9,

"bold": false,

"align": 0,

"line": false,

"type": 0

},

{

"text": "({$tableName})",

"size": 9,

"bold": false,

"align": 0,

"line": true,

"type": 0

},

{

"text": "--------------------------------",

"size": 9,

"bold": false,

"align": 0,

"line": true,

"type": 0

}],

"goods": [{

"name": "编码",

"width": 8,

"variable": "code"

},

{

"name": "名称",

"width": 12,

"variable": "name"

},

{

"name": "数量",

"width": 6,

"variable": "quantity"

},

{

"name": " 金额",

"width": 8,

"variable": "price"

}],

"warn": [{

"text": "-------------{$warnTitle}--------------",

"size": 9,

"bold": false,

"align": 0,

"line": true,

"type": 0

},

{

"text": " ",

"size": 9,

"bold": false,

"align": 0,

"line": true,

"type": 0

},

{

"text": "{$warnMsg}",

"size": 11,

"bold": true,

"align": 0,

"line": true,

"type": 0

}],

"msg": [{

"text": "----------{$posTitle}-----------",

"size": 9,

"bold": false,

"align": 0,

"line": true,

"type": 0

},

{

"text": "{$posMsg}",

"size": 9,

"bold": false,

"align": 0,

"line": true,

"type": 0

}]

}

打印规则

每日一博 | JFinal小插件:Java驱动打印小票

打印参数

  • 打印根据模板和打印参数合成按照顺序进行打印
  • 打印参数替换模板中的占位符
  • 打印参数解析商品信息进行输出

参数示例

 json

{

"keys": {

"dateTime": "2016-09-10 12:21:00",

"posTitle": "收银软件下单结果",

"brandName": "智慧餐厅",

"orderId": "1609101220001",

"shopName": "天山店",

"title": "网络订单",

"tableName": "外卖1",

"barCode": "7255",

"allPrice": "66.88",

"tableNumb": "0002",

"warnTitle": "异常提示",

"posMsg": "点菜成功!1001 无此菜 本次点菜3/3份。其中2成功,1失败。合计XXXX元祝您用餐愉快!欢迎下次光临",

"warnMsg": "部分菜品未下成功请联系服务员人工处理"

},

"goods": [{

"code": "01001",

"quantity": "1.0",

"price": "18.0",

"name": "牛肉"

},

{

"code": "01002",

"quantity": "1.0",

"price": "10.0",

"name": "酸辣土豆"

},

{

"code": "01003",

"quantity": "1.0",

"price": "6.0",

"name": "拍黄瓜"

}]

}

  • keys中的值负责替换模板中的占位符,如果模板中有,keys中没有则将占位符原样输出
  • goods中的参数对用模板中的goods的每个属性

封装的PrintJob

```

/**

* 任务类型:0=普通订单 1=预定单 2=支付订单 3=警告单 4=test单

*/

private int missionType;

/**

* 需要打印的参数--可扩展

*/

private Map<String, Object> param;

/**

* 打印机逻辑名称

*/

private String printerName;

``` 根据不同的missionType自动选用对应的模板,替换参数后打印

效果图(多模板)

每日一博 | JFinal小插件:Java驱动打印小票 每日一博 | JFinal小插件:Java驱动打印小票 每日一博 | JFinal小插件:Java驱动打印小票 每日一博 | JFinal小插件:Java驱动打印小票 每日一博 | JFinal小插件:Java驱动打印小票 每日一博 | JFinal小插件:Java驱动打印小票

使用示例

``` Java import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;

import com.demo.common.driverpos.PrintJob; import com.demo.common.driverpos.PrintQueue; import com.demo.common.driverpos.PrintThread; import com.jfinal.kit.JsonKit; import com.jfinal.plugin.activerecord.Db; import com.jfinal.plugin.activerecord.Record;

public class DriverPrintQueueTest extends BaseTest {

static{

System.out.println("printThread is start : " + System.currentTimeMillis());

PrintThread.start();

}

@Override

public void test() {

mySleep(5);

PrintQueue.add(new PrintJob(0, jsonParam(), "BTP-2002CP(E)"));

mySleep(15);

}

public void mySleep(int i) {

try {

System.out.println("sleep" + i*1000 + "ms ...");

Thread.sleep(i * 1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

public static Map<String, Object> jsonParam(){

Map<String, Object> template = new HashMap<String, Object>();

Map<String, Object> keys = new HashMap<String, Object>();

String posResult = "点菜成功!1001 无此菜 本次点菜3/3份。其中2成功,1失败。合计XXXX元祝您用餐愉快!欢迎下次光临";

keys.put("title", "网络订单");

keys.put("brandName", "智慧餐厅");

keys.put("shopName", "天山店");

keys.put("tableNumb", "0002");

keys.put("tableName", "外卖1");

keys.put("orderId", "1609101220001");

keys.put("dateTime", "2016-09-10 12:21:00");

keys.put("allPrice", "66.88");

keys.put("barCode","7255");

if(!posResult.contains("成功")){

if(posResult.contains("重单")){

keys.put("warnTitle", "提 示");

keys.put("warnMsg", "该订单已处理");

}else{

keys.put("warnTitle", "异常提示");

keys.put("warnMsg", "自动下单失败请人工处理");

}

}else{

if(posResult.contains("无此") || posResult.contains("沽清")

|| posResult.contains("不存在")){

keys.put("warnTitle", "异常提示");

keys.put("warnMsg", "部分菜品未下成功请联系服务员人工处理");

}

}

keys.put("posTitle", "收银软件下单结果");

keys.put("posMsg", posResult);

List<Map<String, Object>> goods = new ArrayList<Map<String,Object>>();

List<Record> menu = Db.find("select * from menu");

// int count = 0; for (Record record : menu) { Map

good = new HashMap

(); good.put("code", record.get("code")); good.put("name", record.get("name")); good.put("quantity", "1.0"); good.put("price", record.get("price")); // good.put("qrcode", "1.png"); // if(count!=1){ // good.put("remark", "免葱、免辣"); // } // count++; goods.add(good); }

template.put("goods", goods);

template.put("keys", keys);

System.out.println(JsonKit.toJson(template));

return template;

}

} ```

  • 在上面的代码中模拟多线程,一个线程取打印任务(Queue.take),当Queue队列为空时挂起。
  • 另一个线程add PrintJob,这时挂起的线程会被唤起,完成打印任务
  • 需要注意一点,示例中的baseTest类里有一个@BeforeClass 的方法加载SQLite数据库,用于读取菜品, 子类重写test方法即可用Unit进行单元测试

另外强调一点:驱动打印文本时自动换行没有采用指令方便,项目中已经实现自动换行功能,有兴趣的可以看看实现方式:)

未登录用户
全部评论0
到底啦