每日一博 | 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();}@Overridepublic 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
到底啦