我們是一家專業做酒店餐飲軟件的公司,餐飲軟件一個重要的功能就是后廚打印問題,前台點菜完畢,后廚立刻打印出單子,這樣就減少人工遞單的麻煩,節省時間,提高翻台率。這種信息化解決方案對打印技術要求很高,理論上最好 100% 不丟單,也就是每次點菜后廚都會相應出單子,但是實際上行不通,為什么呢?因為網線、打印機、網卡等都有可能有問題,別說打印機等硬件因為廚房油煙問題損壞,我們甚至碰到過網線被老鼠咬斷的情況,總之硬件網絡故障防不勝防,所以只能退而求其次,就是有問題不可怕,程序能夠判斷是否出了問題,並能給出提示,便於服務員處理,及時補單。
如果我們用安裝 Windows 驅動的方法來實現后廚打印,那么肯定是不行的,因為我們只能單向向驅動程序拋包,不能從驅動程序獲得任何返回值,沒有辦法了解是否打印成功,而且經過驗證后發現,熱敏打印機驅動打印時速度上非常慢。而且更為嚴重的是,有時候因為后廚打印機過多,Windows 驅動甚至會因為網絡堵塞自作主張將包丟棄,沒有任何提示。這在行業應用中是不行的,會給用戶帶來損失,所以想到了繞過 Windows 驅動,直接寫端口的方法。

1 package com.common.util.portprinter; 2 3 import java.io.IOException; 4 import java.io.OutputStream; 5 6 import com.common.util.PrinterParameterConf; 7 8 /** 9 * @author ChenMing 10 * 11 */ 12 public class PortPrinterBase { 13 private OutputStream out; 14 protected int lineCount = 40; 15 private String printType="0"; 16 public PortPrinterBase(OutputStream out, String printType){ 17 this.out = out; 18 this.printType = printType; 19 initPrinter(); 20 String lineCountStr = PrinterParameterConf.printerParameterConf.getProperty(PrinterParameterConf.LINEPRINTERCHARCOUNT_NAME); 21 try{ 22 int temp = Integer.parseInt(lineCountStr); 23 this.lineCount = temp; 24 }catch(Exception e){ 25 } 26 } 27 protected final String LEFT = "LEFT"; 28 protected final String CENTER = "CENTER"; 29 protected final String RIGHT = "RIGHT"; 30 public static final byte HT = 0x9; 31 public static final byte LF = 0x0A; 32 public static final byte CR = 0x0D; 33 public static final byte ESC = 0x1B; 34 public static final byte DLE = 0x10; 35 public static final byte GS = 0x1D; 36 public static final byte FS = 0x1C; 37 public static final byte STX = 0x02; 38 public static final byte US = 0x1F; 39 public static final byte CAN = 0x18; 40 public static final byte CLR = 0x0C; 41 public static final byte EOT = 0x04; 42 43 /* 初始化打印機 */ 44 public static final byte[] ESC_INIT = new byte[] {ESC, '@'}; 45 /* 設置標准模式 */ 46 public static final byte[] ESC_STANDARD = new byte[] {ESC, 'S'}; 47 /* 設置漢字打印模式 */ 48 public static final byte[] ESC_CN_FONT = new byte[] {FS, '&'}; 49 /* 選擇字符集 */ 50 public static final byte[] ESC_SELECT_CHARACTER = new byte[] {ESC, 'R', 9}; 51 /* 設置用戶自定義漢字字體 焗7118 */ 52 public static final byte[] ESC_FS_2 = new byte[] {FS, 0x32, 0x71, 0x18}; 53 /* 取消用戶自定義字體 */ 54 public static final byte[] ESC_CANCEL_DEFINE_FONT = new byte[]{ESC, '%', 0}; 55 /* 打開錢箱指令 */ 56 public static final byte[] ESC_OPEN_DRAWER = new byte[]{ESC, 'p', 0x00, 0x10, (byte) 0xff}; 57 /* 切紙指令GS V m 58 * m 0,48 Executes a full cut(cuts the paper completely) 59 * 1,49 Excutes a partilal cut(one point left uncut) 60 */ 61 public static final byte[] POS_CUT_MODE_FULL = new byte[]{GS, 'V', 0x00}; 62 public static final byte[] POS_CUT_MODE_PARTIAL = new byte[]{GS, 'V', 0x01}; 63 /* 西文字符 (半寬)字體A (6 ×12),漢字字符 (全寬)字體A (12×12) */ 64 public static final byte[] ESC_FONT_A = new byte[]{ESC, '!', 0}; 65 /* 西文字符 (半寬)字體B (8×16),漢字字符 (全寬)字體B (16×16) */ 66 public static final byte[] ESC_FONT_B = new byte[]{ESC, '!', 1}; 67 /* 12*24 0/48*/ 68 public static final byte[] ESC_FONTA= new byte[]{ESC, 'M', 48}; 69 /* 9*17 1/49*/ 70 public static final byte[] ESC_FONTB= new byte[]{ESC, 'M', 1}; 71 /* 默認顏色字體指令 */ 72 public static final byte[] ESC_FONT_COLOR_DEFAULT = new byte[] {ESC, 'r', 0x00}; 73 /* 紅色字體指令 */ 74 public static final byte[] ESC_FONT_COLOR_RED = new byte[] {ESC, 'r', 0x01 }; 75 /* 標准大小 */ 76 public static final byte[] FS_FONT_ALIGN = new byte[]{FS, 0x21, 1, ESC, 0x21, 1}; 77 /* 橫向放大一倍 */ 78 public static final byte[] FS_FONT_ALIGN_DOUBLE = new byte[]{FS, 0x21, 4, ESC, 0x21, 4}; 79 /* 縱向放大一倍 */ 80 public static final byte[] FS_FONT_VERTICAL_DOUBLE = new byte[]{FS, 0x21, 8, ESC, 0x21, 8, GS, '!', 0x01}; 81 /* 橫向縱向都放大一倍 */ 82 public static final byte[] FS_FONT_DOUBLE = new byte[]{FS, 0x21, 12, ESC, 0x21, 48}; 83 /* 靠左打印命令 */ 84 public static final byte[] ESC_ALIGN_LEFT = new byte[]{0x1b,'a', 0x00}; 85 /* 居中打印命令 */ 86 public static final byte[] ESC_ALIGN_CENTER = new byte[]{0x1b,'a', 0x01}; 87 /* 靠右打印命令 */ 88 public static final byte[] ESC_ALIGN_RIGHT = new byte[]{0x1b,'a', 0x02}; 89 /* 字體加粗 */ 90 public static final byte[] ESC_SETTING_BOLD = new byte[]{ESC, 0x45, 1}; 91 /* 取消字體加粗 */ 92 public static final byte[] ESC_CANCEL_BOLD = new byte[]{ESC, 0x45, 0}; 93 //DLE EOT n 實時狀態傳送 94 //如果返回結果為22 95 /** 96 * 、DLE EOT n 實時狀態傳送 97 [格式] ASCII碼 DLE EOT n 98 十六進制碼 10 04 n 99 十進制碼 16 4 n 100 [范圍] 1 ≤ n ≤ 4 101 [描述] 根據下列參數,實時傳送打印機狀態,參數 n 用來指定所要傳送的打印機狀態: 102 n = 1:傳送打印機狀態 103 n = 2:傳送脫機狀態 104 n = 3:傳送錯誤狀態 105 n = 4:傳送紙傳感器狀態 106 [注釋] 打印機收到該命令后立即返回相關狀態 107 該命令盡量不要插在2個或更多字節的命令序列中。 108 即使打印機被ESC =(選擇外設)命令設置為禁止,該命令依然有效。 109 打印機傳送當前狀態,每一狀態用1個字節數據表示。 110 打印機傳送狀態時並不確認主機是否收到。 111 打印機收到該命令立即執行。 112 該命令只對串口打印機有效。打印機在任何狀態下收到該命令都立即執行。 113 */ 114 public static final byte[] PRINT_STATE_DLE_EOT = new byte[] {DLE, EOT,0x01}; 115 116 public void initPrinter(){ 117 try { 118 //modify by gongqiyi 20090917 119 //ESC_INIT 將在清空緩存區的數據 120 //out.write(ESC_INIT); 121 //自定義字體 122 //out.write(ESC_FS_2); 123 out.write(ESC_STANDARD); 124 out.write(ESC_CANCEL_DEFINE_FONT); 125 out.write(ESC_FONTA); 126 out.write(ESC_SELECT_CHARACTER); 127 //進入漢字模式打印 128 //out.write(ESC_CN_FONT); 129 130 131 //out.write(ESC_FONT_B); 132 //out.write(ESC_FONTA); 133 } catch (IOException e) { 134 e.printStackTrace(); 135 } 136 } 137 /** 138 * 走紙到切紙位置並切紙 139 */ 140 public void executeLineFeedAndPaperCut(){ 141 try { 142 out.write(PrinterParameterConf.printerParameterConf.getProperty 143 (PrinterParameterConf.PRINTCUTLINE_NAME).getBytes()); 144 out.write(POS_CUT_MODE_PARTIAL); 145 } catch (IOException e) { 146 e.printStackTrace(); 147 } 148 } 149 /** 150 * 單據頭打印 151 * @param str 152 */ 153 public void billHeaderPrinter(String str){ 154 try { 155 out.write(ESC_ALIGN_CENTER); 156 out.write(FS_FONT_DOUBLE); 157 out.write((str+"\n").getBytes()); 158 out.write(LF); 159 } catch (IOException e) { 160 e.printStackTrace(); 161 } 162 } 163 /** 164 * 叫單號打印 165 * @param str 166 */ 167 public void callNumPrinter(String str){ 168 try { 169 out.write(ESC_ALIGN_LEFT); 170 out.write(FS_FONT_DOUBLE); 171 out.write((str+"\n").getBytes()); 172 } catch (IOException e) { 173 e.printStackTrace(); 174 } 175 } 176 /** 177 * 雙倍大小字體 178 * @param str 179 */ 180 public void doubleSizePrinter(String str, String align){ 181 try { 182 if(CENTER.equals(align)){ 183 out.write(ESC_ALIGN_LEFT); 184 }else if(RIGHT.equals(align)){ 185 out.write(ESC_ALIGN_RIGHT); 186 }else{ 187 out.write(ESC_ALIGN_LEFT); 188 } 189 out.write(FS_FONT_DOUBLE); 190 out.write((str+"\n").getBytes()); 191 //out.write(LF); 192 } catch (IOException e) { 193 e.printStackTrace(); 194 } 195 } 196 /** 197 * 標准字體打印一行 198 * @param str 需打印的字符串 199 * @param align 打印的位置 LEFT/CENTER/RIGHT 其他為默認居左打印 200 */ 201 public void standardPrinterLine(String str, String align){ 202 try{ 203 if(CENTER.equals(align)){ 204 out.write(ESC_ALIGN_CENTER); 205 out.write(FS_FONT_ALIGN); 206 out.write(ESC_CN_FONT); 207 out.write(ESC_CANCEL_BOLD); 208 if("1".equals(printType)){ 209 out.write(ESC_FONTA); 210 }else{ 211 out.write(ESC_FONT_B); 212 } 213 out.write(str.getBytes()); 214 }else if(RIGHT.equals(align)){ 215 out.write(ESC_ALIGN_RIGHT); 216 out.write(FS_FONT_ALIGN); 217 out.write(ESC_CN_FONT); 218 out.write(ESC_CANCEL_BOLD); 219 if("1".equals(printType)){ 220 out.write(ESC_FONTA); 221 }else{ 222 out.write(ESC_FONT_B); 223 } 224 out.write(str.getBytes()); 225 }else{ 226 out.write(ESC_ALIGN_LEFT); 227 out.write(FS_FONT_ALIGN); 228 out.write(ESC_CN_FONT); 229 out.write(ESC_CANCEL_BOLD); 230 if("1".equals(printType)){ 231 out.write(ESC_FONTA); 232 }else{ 233 out.write(ESC_FONT_B); 234 } 235 out.write(str.getBytes()); 236 } 237 out.write("\n".getBytes()); 238 }catch(IOException e) { 239 e.printStackTrace(); 240 } 241 } 242 243 /** 244 * 標准粗體字體打印一行 245 * @param str 需打印的字符串 246 * @param align 打印的位置 LEFT/CENTER/RIGHT 其他為默認居左打印 247 */ 248 public void standardBoldPrinterLine(String str, String align){ 249 try{ 250 if(CENTER.equals(align)){ 251 out.write(ESC_ALIGN_CENTER); 252 out.write(FS_FONT_ALIGN); 253 out.write(ESC_CN_FONT); 254 out.write(ESC_SETTING_BOLD); 255 if("1".equals(printType)){ 256 out.write(ESC_FONTA); 257 }else{ 258 out.write(ESC_FONT_B); 259 } 260 out.write(str.getBytes()); 261 }else if(RIGHT.equals(align)){ 262 out.write(ESC_ALIGN_RIGHT); 263 out.write(FS_FONT_ALIGN); 264 out.write(ESC_CN_FONT); 265 out.write(ESC_SETTING_BOLD); 266 if("1".equals(printType)){ 267 out.write(ESC_FONTA); 268 }else{ 269 out.write(ESC_FONT_B); 270 } 271 out.write(str.getBytes()); 272 }else{ 273 out.write(ESC_ALIGN_LEFT); 274 out.write(FS_FONT_ALIGN); 275 out.write(ESC_CN_FONT); 276 out.write(ESC_SETTING_BOLD); 277 if("1".equals(printType)){ 278 out.write(ESC_FONTA); 279 }else{ 280 out.write(ESC_FONT_B); 281 } 282 out.write(str.getBytes()); 283 } 284 out.write("\n".getBytes()); 285 }catch(IOException e) { 286 e.printStackTrace(); 287 } 288 } 289 290 /** 291 * 雙倍寬字體按行打印 292 * @param str 293 * @param align 294 */ 295 public void largeSizePrinterLine(String str, String align){ 296 try{ 297 if(CENTER.equals(align)){ 298 out.write(ESC_ALIGN_CENTER); 299 out.write(FS_FONT_ALIGN_DOUBLE); 300 out.write(str.getBytes()); 301 }else if(RIGHT.equals(align)){ 302 out.write(ESC_ALIGN_RIGHT); 303 out.write(FS_FONT_ALIGN_DOUBLE); 304 out.write(str.getBytes()); 305 }else{ 306 out.write(ESC_ALIGN_LEFT); 307 out.write(FS_FONT_ALIGN_DOUBLE); 308 out.write(str.getBytes()); 309 } 310 out.write("\n".getBytes()); 311 }catch(IOException e) { 312 e.printStackTrace(); 313 } 314 } 315 316 /** 317 * 雙倍高字體按行打印 318 * @param str 319 * @param align 320 */ 321 public void largeHSizePrinterLine(String str, String align){ 322 try{ 323 if(CENTER.equals(align)){ 324 out.write(ESC_ALIGN_CENTER); 325 out.write(FS_FONT_VERTICAL_DOUBLE); 326 out.write(str.getBytes()); 327 }else if(RIGHT.equals(align)){ 328 out.write(ESC_ALIGN_RIGHT); 329 out.write(FS_FONT_VERTICAL_DOUBLE); 330 out.write(str.getBytes()); 331 }else{ 332 out.write(ESC_ALIGN_LEFT); 333 out.write(FS_FONT_VERTICAL_DOUBLE); 334 out.write(str.getBytes()); 335 } 336 out.write("\n".getBytes()); 337 }catch(IOException e) { 338 e.printStackTrace(); 339 } 340 } /** 341 * 大號字體紅色按行打印 342 * @param str 343 * @param align 344 */ 345 public void largeSizeRedPrinterLine(String str, String align){ 346 try{ 347 if(CENTER.equals(align)){ 348 out.write(ESC_ALIGN_CENTER); 349 out.write(FS_FONT_ALIGN_DOUBLE); 350 out.write(ESC_FONT_COLOR_RED); 351 out.write(str.getBytes()); 352 }else if(RIGHT.equals(align)){ 353 out.write(ESC_ALIGN_RIGHT); 354 out.write(FS_FONT_ALIGN_DOUBLE); 355 out.write(ESC_FONT_COLOR_RED); 356 out.write(str.getBytes()); 357 }else{ 358 out.write(ESC_ALIGN_LEFT); 359 out.write(FS_FONT_ALIGN_DOUBLE); 360 out.write(ESC_FONT_COLOR_RED); 361 out.write(str.getBytes()); 362 } 363 out.write("\n".getBytes()); 364 }catch(IOException e) { 365 e.printStackTrace(); 366 } 367 } 368 public void openDrawer(){ 369 try { 370 out.write(ESC_OPEN_DRAWER); 371 } catch (IOException e) { 372 e.printStackTrace(); 373 } 374 } 375 public String makePrintString(int lineChars, String txt1, String txt2){ 376 if(txt1 == null){ 377 txt1 = ""; 378 } 379 if(txt2 == null){ 380 txt2 = ""; 381 } 382 int spaces = 0; 383 String tab = ""; 384 try{ 385 spaces = lineChars - (txt1.getBytes().length + txt2.getBytes().length); 386 for (int j = 0 ; j < spaces ; j++){ 387 tab += " "; 388 } 389 }catch(Exception e){ 390 e.printStackTrace(); 391 } 392 return txt1 + tab + txt2; 393 } 394 public String makePrintString(int lineChars, String txt1, String txt2, String txt3){ 395 if(txt1 == null){ 396 txt1 = ""; 397 } 398 if(txt2 == null){ 399 txt2 = ""; 400 } 401 if(txt3 == null){ 402 txt3 = ""; 403 } 404 int spaces = 0; 405 int lineChars1 = lineChars*2/3; 406 String tab = ""; 407 String returnStr = txt1; 408 try{ 409 spaces = lineChars1 - (returnStr.getBytes().length + txt2.getBytes().length); 410 for (int j = 0 ; j < spaces ; j++){ 411 tab += " "; 412 } 413 returnStr = txt1 + tab + txt2; 414 spaces = lineChars - (returnStr.getBytes().length + txt3.getBytes().length); 415 tab = ""; 416 for (int j = 0 ; j < spaces ; j++){ 417 tab += " "; 418 } 419 returnStr = returnStr + tab + txt3; 420 }catch(Exception e){ 421 e.printStackTrace(); 422 } 423 return returnStr; 424 } 425 }