一 前言

前段时间在开发项目时,需要实现打印的功能,有着封装好的工具类,不过使用的时候有些地方还是遇到了一些小坑,在此整理出来希望对大家有所帮助。

二 准备工作

1.实体类和工具类

实体类

package com.yc.entity;import lombok.Data;import java.io.Serializable;/*** @author  Wzh* Create by Wzh on 2018/4/21*/
@Data
public class Orders implements Serializable{private static final long serialVersionUID = -560708444936642252L;/*** id*/private Integer id;/*** 寄件人姓名*/private String sendname;/*** 寄件人电话*/private String sendtel;/*** 寄件人地址*/private String sendaddress;/*** 收件人姓名*/private String recname;/*** 收件人电话*/private String rectel;/*** 收件人地址*/private String recaddress;/*** 收件人邮编*/private String reccode;/*** 订单日期*/private Long orderstime;/*** 商品类型*/private String goodstype;/*** 重量 (kg)*/private Double weight;/*** 体积 (m^3)*/private Double volume;/*** 配送费*/private Double price;/*** 报价金额*/private Double insureprice;/*** 订单类型(0快件, 1慢件,  2大宗)*/private Integer orderstype;/*** 订单状态 (0未发件, 1已发件, 2已送达,3 已取消,4 正在排件(备用属性,不一定使用), 100前台下单)*/private Integer status;/*** 条形码编码*/private Long barcode;/*** 条形码图片*/private String barpic;/*** 预计到达时间*/private Long endtime;/*** 配送点姓名*/private String recspname;/*** 备注*/private String remark;/*** 客户信息(Id)*/private Integer usid;/*** 代理点(PID)*/private Integer pid;/*** 系统管理员id*/private Integer sysid;/*** 路线(rid)*/private Integer rid;/*** 凭证,图片*/private String url;/*** 4个备用字段*//*** 付款方式*/private String res1;private String res2;private String res3;private String res4;/*** 路线名称*/private String rname;/*** 路线地址*/private String raddr;private Client client;private Route route;private Proxy proxy;public Orders(){super();}public Orders(String sendname, String sendtel, String sendaddress, String recname, String rectel, String recaddress, String goodstype, Double price) {super();this.sendname = sendname;this.sendtel = sendtel;this.sendaddress = sendaddress;this.recname = recname;this.rectel = rectel;this.recaddress = recaddress;this.goodstype = goodstype;this.price = price;}
}

这是关于物流订单的实体类,实体类可以自行创建根据你需要打印的信息。我这里使用的是lombok的工具,如果没有请自行添加实体属性的get 和 set 方法。末尾的有参的构造方法是你所需要打印的信息

工具类实现打印机的接口

package com.yc.util;import com.yc.entity.Orders;import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;/*** 源辰信息* 销售清单对象* @author navy* 2017年5月23日*/
public class SalesTicket  implements Printable{private List<Orders> goods; //商品列表private String operatorName="源辰信息"; //操作员private String orderId; //订单编号private String totalGoodsNum; //商品总数private String totalPrice; //总金额private String actualCollection; //实收款private String giveChange; //找零private String cardNumber; //会员编号private String integral; //积分private SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss EEE");@Overridepublic String toString() {return "SalesTicket [goods=" + goods + ", operatorName=" + operatorName + ", orderId=" + orderId+ ", totalGoodsNum=" + totalGoodsNum + ", totalPrice=" + totalPrice + ", actualCollection="+ actualCollection + ", giveChange=" + giveChange + ", cardNumber=" + cardNumber + ", integral="+ integral + "]";}public SalesTicket(List<Orders> goods, String operatorName, String orderId, String totalGoodsNum,String totalPrice, String actualCollection, String giveChange, String cardNumber, String integral) {super();this.goods = goods;this.operatorName = operatorName;this.orderId = orderId;this.totalGoodsNum = totalGoodsNum;this.totalPrice = totalPrice;this.actualCollection = actualCollection;this.giveChange = giveChange;this.cardNumber = cardNumber;this.integral = integral;}public SalesTicket(List<Orders> goods, String operatorName, String orderId, String totalGoodsNum,String totalPrice, String actualCollection, String giveChange) {super();this.goods = goods;this.operatorName = operatorName;this.orderId = orderId;this.totalGoodsNum = totalGoodsNum;this.totalPrice = totalPrice;this.actualCollection = actualCollection;this.giveChange = giveChange;}/*** 打印方法* graphics - 用来绘制页面的上下文,即打印的图形* pageFormat - 将绘制页面的大小和方向,即设置打印格式,如页面大小一点为计量单位(以1/72 英寸为单位,1英寸为25.4毫米。A4纸大致为595 × 842点)*              小票纸宽度一般为58mm,大概为165点* pageIndex - 要绘制的页面从 0 开始的索引 ,即页号*/@Overridepublic int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {//此 Graphics2D 类扩展 Graphics 类,以提供对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制。//它是用于在 Java(tm) 平台上呈现二维形状、文本和图像的基础类。 Graphics2D g2 = (Graphics2D) graphics;  g2.setColor(Color.black);//设置打印颜色为黑色  //打印起点坐标  double x= pageFormat.getImageableX();  //返回与此 PageFormat相关的 Paper对象的可成像区域左上方点的 x坐标。  double y= pageFormat.getImageableY();  //返回与此 PageFormat相关的 Paper对象的可成像区域左上方点的 y坐标。//Font.PLAIN: 普通样式常量     Font.ITALIC 斜体样式常量  Font.BOLD 粗体样式常量。Font font = new Font("宋体",Font.BOLD,10); //根据指定名称、样式和磅值大小,创建一个新 Font。g2.setFont(font);//设置标题打印字体     float heigth = font.getSize2D();//获取字体的高度  //设置小票的标题标题  g2.drawString("源辰信息科技有限公司",(float)x+25,(float)y+heigth); float line = 2*heigth; //下一行开始打印的高度g2.setFont(new Font("宋体", Font.PLAIN,8));//设置正文字体  heigth = font.getSize2D();// 字体高度  line+=2;//设置操作员 g2.drawString("操作员:"+operatorName,(float)x+20,(float)y+line); line+=heigth;//设置订单号  g2.drawString("订单号:"+orderId, (float)x+20,(float)y+line);  line+=heigth+2;//***********************************打印图片*********************************************////Component c = null;//Image src =Toolkit.getDefaultToolkit().getImage(Common.GITPATH+"\\"+orderId+".gif");//使图片旋转90度//BufferedImage simage = RotateImage.Rotate(src,90);//Image image = simage;//获取图片的宽度//int width=image.getWidth(c);//获取图片的高度//int height2=image.getHeight(c);// g2.drawImage(src,(int)x,40,c); 打印原图 ,因为图片的原宽度超出了纸张,所以打印机会报错误//**************************************************************************************////设置标题  //g2.drawString("名称",(float)x+20, (float)y+line);//g2.drawString("单价",(float)x+60, (float)y+line);//g2.drawString("数量",(float)x+90, (float)y+line);//g2.drawString("小计",(float)x+120, (float)y+line);line+=heigth;/** 虚线绘制设置    setStroke(Stroke):为 Graphics2D 上下文设置 Stroke* 由 BasicStroke定义的呈现属性描述了用画笔沿 Shape 的轮廓绘制的某个标记的形状,以及应用在 Shape 路径线段的末端和连接处的装饰。* 这些呈现属性包括: * width:画笔的宽度,是垂直于画笔轨迹的测量值。  此宽度必须大于或等于 0.0f,0.0f为最细线条。  * end caps:在未封闭子路径和虚线线段的末端应用的一些装饰。如果子路径没有 CLOSE 段,则在同一点上开始和结束的子路径仍被认为是未封闭的。*    关于 CLOSE 段的更多信息,请参阅 SEG_CLOSE。三个不同的装饰是:*      CAP_BUTT:无装饰地结束未封闭的子路径和虚线线段。*        CAP_ROUND:使用半径等于画笔宽度一半的圆形装饰结束未封闭的子路径和虚线线段。*      CAP_SQUARE:使用正方形结束未封闭的子路径和虚线线段,正方形越过线段端点,并延长等于线条宽度一半的距离。 * line joins:在两个路径线段的交汇处,以及使用 SEG_CLOSE 封闭的子路径端点的交汇处应用的装饰。*         三个不同的装饰是:*           JOIN_BEVEL:通过直线连接宽体轮廓的外角,将路径线段连接在一起。 *            JOIN_MITER:扩展路径线段的外边缘,直到它们连接在一起。 *            JOIN_ROUND:通过舍去半径为线长的一半的圆角,将路径线段连接在一起。 * miter limit:对剪裁具有 JOIN_MITER 装饰的线接合点的限制。当斜接长度与笔划宽度的比大于 miterlimit 值时,需要剪裁线接合点。*        斜接长度是斜接的对角线长度,即交汇处的内棱角和外棱角之间的距离。两条线段形成的角度越小,斜接长度就越长,交汇处的角度就越尖锐。*       默认 miterlimit 值为 10.0f,它会使所有小于 11 度的角都被剪裁。剪裁斜接会使线接合点的装饰变成斜角。 必须大于或等于 1.0f。* dash attributes:关于如何通过在不透明和透明部分之间交替形成一个虚线模式的定义。 表示虚线模式的数组  * dash phase - 开始虚线模式的偏移量  *///虚线设置g2.setStroke(new BasicStroke(1f,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER,4.0f,new float[]{4.0f},0.0f));  //在此图形上下文的坐标系中使用当前颜色在点 (x1, y1) 和 (x2, y2) 之间画一条线。 即绘制虚线g2.drawLine((int)x,(int)(y+line),(int)x+158,(int)(y+line));  line+=heigth; //设置商品清单if(goods!=null && goods.size()>0){for(Orders gdf:goods){g2.drawString("寄件人姓名:",(float)x+15,(float)y+line);g2.drawString(gdf.getSendname(),(float)x+60, (float)y+line);line+=heigth;g2.drawString("寄件电话:",(float)x+15,(float)y+line);g2.drawString(gdf.getSendtel(),(float)x+60, (float)y+line);line+=heigth;g2.drawString("寄件地址:",(float)x+15,(float)y+line);line+=heigth;g2.drawString(gdf.getSendaddress(),(float)x+15,(float)y+line);line+=heigth;g2.drawString("收件人姓名:",(float)x+15,(float)y+line);g2.drawString(gdf.getRecname(),(float)x+60,(float)y+line);line+=heigth;g2.drawString("收件人电话:",(float)x+15,(float)y+line);g2.drawString(gdf.getRectel(),(float)x+60,(float)y+line);line+=heigth;g2.drawString("收件人地址:",(float)x+15,(float)y+line);line+=heigth;g2.drawString(gdf.getRecaddress(),(float)x+15,(float)y+line);line+=heigth;g2.drawString("商品类型:",(float)x+15,(float)y+line);g2.drawString(gdf.getGoodstype(),(float)x+60,(float)y+line);line+=heigth;g2.drawString("配送费:",(float)x+15,(float)y+line);g2.drawString(String.valueOf(gdf.getPrice()),(float)x+60,(float)y+line);line += heigth; }}g2.drawLine((int) x, (int)(y+line), (int) x + 158, (int)(y+line));  line += heigth+2;  g2.drawString("商品总数:"+"一"+ "件",(float)x+15,(float)y+line);line += heigth;//从新设置打印图片的大小//g2.drawImage(image, (int)x+5,200, width,height2, c);if(cardNumber!=null && !"".equals(cardNumber)){g2.drawString("当前会员:"+cardNumber,(float)x+15,(float)y+line);line += heigth;g2.drawString("积分:"+integral,(float)x+15,(float)y+line);  }g2.drawString("时间:"+sdf.format(new Date()),(float)x+15,(float)y+line);  line += heigth; g2.drawString("钱票请当面点清,离开柜台恕不负责",(float)x+15,(float)y+line);  switch (pageIndex) {  case 0:  return PAGE_EXISTS;  //0 default:  return NO_SUCH_PAGE;   //1}  }
}

goods的集合为你所要打印的实体类的泛型

package com.yc.util;import java.awt.print.Book;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;/*** 源辰信息* 打印对象 -> 实现Printable接口即可调用打印机打印* @author navy* 2017年5月23日*/
public class YcPrinter{private SalesTicket salesTicket;public YcPrinter(SalesTicket salesTicket){this.salesTicket=salesTicket;}public void printer() {  try {  //Book 类提供文档的表示形式,该文档的页面可以使用不同的页面格式和页面 painterBook book = new Book(); //要打印的文档//PageFormat类描述要打印的页面大小和方向  PageFormat pf = new PageFormat();  //初始化一个页面打印对象pf.setOrientation(PageFormat.PORTRAIT); //设置页面打印方向,从上往下,从左往右//设置打印纸页面信息。通过Paper设置页面的空白边距和可打印区域。必须与实际打印纸张大小相符。  Paper paper = new Paper(); paper.setSize(158,30000);// 纸张大小paper.setImageableArea(0,0,158,30000);// A4(595 X 842)设置打印区域,其实0,0应该是72,72,因为A4纸的默认X,Y边距是72  pf.setPaper(paper);  book.append(salesTicket,pf);  PrinterJob job = PrinterJob.getPrinterJob();   //获取打印服务对象  job.setPageable(book);  //设置打印类  job.print(); //开始打印 } catch (PrinterException e) {  e.printStackTrace();  }  }
}

然后就是调用这个功能,因为是web项目我在控制层来调用打印功能

 @RequestMapping(value = "printOrders.action",method =RequestMethod.POST)@ResponseBodypublic JsonMode printOrders(String sendname,String sendtel,String sendaddress,String recname,String rectel,String recaddress,String goodstype,Double price,Long barcode){JsonMode jsonMode = new JsonMode();List<Orders> goods=new ArrayList<Orders>();goods.add(new Orders(sendname,sendtel,sendaddress,recname,rectel,recaddress,goodstype,price));SalesTicket stk=new SalesTicket(goods,"源辰信息",""+barcode,"3","38400","38400","0");YcPrinter p=new YcPrinter(stk);p.printer();jsonMode.setCode(1);return jsonMode;}

至此我们可以调用windows默认的打印机把样式文件打印到桌面上,如果要调用外部打印机需要自己去下载打印机对应的驱动来实现打印.

3细节描述(小坑)

1.打印的范围一定要按自己打印机纸张的规模来,如果超出范围(如字段的长度)打印机会报错,但后台是不会报异常的,于是打印机就会一直重复打印同一份文档遇到超出范围的地方便会报错然后重新打印变成死循环,可以选择断开电源或者在右下角点开打印机的图标终止打印的文档.(在看后台的时候,打印机打印了好几份。。。所以浪费了很多纸)

2.调用drawImage可以实现打印图片,颜色样式是看你的打印机所决定。

获取到图片

Image src =Toolkit.getDefaultToolkit().getImage(Common.GITPATH+"\\"+orderId+".gif");

获取图片的长和宽

 //获取图片的宽度//int width=image.getWidth(c);//获取图片的高度//int height2=image.getHeight(c);
g2.drawImage(src,(int)x,40,c); 打印原图 ,因为图片的原宽度超出了纸张,所以打印机会报错误
g2.drawImage(image, (int)x+5,200, width,height2, c);

第一个方法,只设置了图片所打印的位置,图片的尺寸是原图如果范围超过了纸张,那么打印机就会报错

第二个方法新加的两个参数决定了打印图片的宽度和高度,实现的图片打印的缩放,但是对于条形码会破坏它的结构,导致光枪可能扫描不出来。

使用JAVA调用热敏打印机接口实现打印功能相关推荐

  1. java调用热敏打印机打印(包含二维码生成)

    项目中需要用到热敏打印机,并且在打印的同时,要生成二维码.并且打印,先说说二维码的生成吧 package com.jinke.util; import com.google.zxing.common. ...

  2. 手把手教你用JAVA调用Websocket实现“声音转换”功能(变声)标贝科技

    手把手教你用JAVA调用Websocket实现"声音转换"功能(变声)标贝科技 前言 什么是声音转换? 基于深度学习和迁移学习技术,精准将原说话人的声音转换为目标说话人,同时保留原 ...

  3. Java 调用http接口(基于OkHttp的Http工具类方法示例)

    目录 Java 调用http接口(基于OkHttp的Http工具类方法示例) OkHttp3 MAVEN依赖 Http get操作示例 Http Post操作示例 Http 超时控制 工具类示例 Ja ...

  4. 第二篇:java调用公共数据接口:上海市车辆基本信息查询(java调用soap接口)

    java调用公共数据接口:上海市数据公共开放平台 前言 一.找个接口作为案例 二.查看文档 1.查看接口文档 2.确认接口地址与参数 三.编码(找代码直接跳这里!) 1.先创建一个返回数据的实体类 2 ...

  5. 第一篇:java调用公共数据接口:QQ在线状态查询(java调用http接口)

    java调用公共数据接口: webxml 前言 一.以webxml上的一个接口为案例 二.查看接口文档 1.查看支持的调用方式 2.确认接口地址与参数 三.编码(找代码直接跳这里!) 1.配置Rest ...

  6. 【转】java调用http接口的几种方式总结

    java调用http接口的几种方式总结 本文参考: https://blog.csdn.net/fightingXia/article/details/71775516 https://www.cnb ...

  7. Java 调用第三方接口方法

    Java 调用第三方接口方法 一. 通过JDK网络类Java.net.HttpURLConnection 1.java.net包下的原生java api提供的http请求 使用步骤: 1.通过统一资源 ...

  8. java调用飞信接口免费短信发送到对方手机

    原文:java调用飞信接口免费短信发送到对方手机 源代码下载地址:http://www.zuidaima.com/share/1550463460084736.htm 飞信发送信息限(移动用户) 1. ...

  9. 前端—基于Flask框架调用百度接口实现语音识别功能(使用蓝图blueprint)

    配合"基于Flask框架调用百度接口实现语音识别功能"使用的前端参考代码 后端代码链接 Python-基于Flask框架调用百度接口实现语音识别功能:基于Flask框架调用百度接口 ...

最新文章

  1. 愿疫情早日过去,向那些在疫情战斗中牺牲的战士致敬
  2. Spring之使用注解实例化Bean并注入属性
  3. 用Excel的VBA实现文本匹配与替换
  4. 探索7.x, 全面解析Activity启动框架 (1)
  5. 翻译python语言命令_有道词典命令行快速翻译,Python编程的利器
  6. Orleans MultiClient 多个Silo复合客户端
  7. 面试中的网红虚拟DOM,你知多少呢?深入解读diff算法
  8. UVA 847 - A Multiplication Game(游戏)
  9. 在vs2005中遇到的调试问题以及解决办法
  10. web前端顶岗实习总结报告_实习报告-web前端实习报告范文三篇 精品
  11. c语言求余运算作用,C语言中的整数除法和求余运算
  12. android usb键盘监听,android设备外接键盘实现监听事件
  13. 虚拟机超线程性能分析深入浅出
  14. 从现在看未来,在未来看现在
  15. linux查看tomcat在,在陌生Linux环境查看Tomcat服务的方法
  16. 根据冯诺依曼模型组装一台电脑
  17. UE4 物理系统实现
  18. docker的容器下使用apt-get update卡在[0%] Working问题解决办法
  19. Oriented R-CNN for Object Detection 论文解读
  20. 社区团购讲堂之精耕细作的互联网下半场,社区团购将改变实体商超格局?

热门文章

  1. 在大学里计算机专业总分多少,计算机专业高考多少分录取?附中国计算机专业大学排名及分数线...
  2. 实验十八 CISCO设备IOS的备份与升级
  3. C#--color颜色对照表
  4. 数据库连接驱动介绍及参数简单设置
  5. 评分卡分箱原则及单调性
  6. 【ESP 保姆级教程】疯狂Node.js服务器篇 ——案例:ESP8266 + MQ3酒精传感器 + NodeJs本地服务 + 文件存储数据
  7. Linux---查看内存型号
  8. java项目编码问题解决
  9. eclipse设置工作空间的默认编码和设置项目的编码
  10. Word文档编辑受限解决办法