Java获取配置打印机,并(佳博打印机)打印小票
因项目需求,需要打印类似超市的收银小票。
贴上代码,以供记录和参考。
一:获取电脑本地所有的打印服务。
@RequestMapping("/getPrint")
@ResponseBody
public Object getPrint(){
PrintRequestAttributeSet printRequestAttributeSet = new HashPrintRequestAttributeSet();
DocFlavor flavor = DocFlavor.BYTE_ARRAY.PNG;
PrintService printService[] = PrintServiceLookup.lookupPrintServices(flavor,printRequestAttributeSet );
//获取打印机列表
List<String> printList = new ArrayList<>();
for (int i = 0;i<printService.length;i++){
printList.add(printService[i].getName());
}
return new ReportResponse(printList);
}
返回结果:
{
"header": {
"code": "200",
"memo": "success"
},
"result": [
"Microsoft XPS Document Writer",
"GP-U80250 Series",
"Fax"
]
}
二:打印小票。
1:配置打印机
public class Printer {
private SalesTicket salesTicket;
public Printer(SalesTicket salesTicket) {
this.salesTicket = salesTicket;
}
public void printer(String printerName) {
//Book 类提供文档的表示形式,该文档的页面可以使用不同的页面格式和页面 painter
//要打印的文档
Book book = new Book();
//PageFormat类描述要打印的页面大小和方向
//初始化一个页面打印对象
PageFormat pf = new PageFormat();
//设置页面打印方向,从上往下,从左往右
pf.setOrientation(PageFormat.PORTRAIT);
//设置打印纸页面信息。通过Paper设置页面的空白边距和可打印区域。必须与实际打印纸张大小相符。
Paper paper = new Paper();
MediaSize mediaSize = new MediaSize(80, 3276, MediaPrintableArea.MM);
//paper.setSize(200,30000);// 纸张大小
//paper.setImageableArea(0,0,200,30000);// A4(595 X 842)设置打印区域,其实0,0应该是72,72,因为A4纸的默认X,Y边距是72
paper.setSize((double) mediaSize.getX(25400) * 72.0D, (double) mediaSize.getY(25400) * 72.0D);
paper.setImageableArea(0.0D, 0.0D, paper.getWidth(), paper.getHeight());
pf.setPaper(paper);
book.append(salesTicket, pf);
HashAttributeSet hs = new HashAttributeSet();
hs.add(new PrinterName(printerName, null));
PrintService[] pss = PrintServiceLookup.lookupPrintServices(null, hs);
if (pss.length == 0) {
throw new ServiceException(ErrorCodes.PRINTER_NOTHAVE);
}
//获取打印服务对象
PrinterJob job = PrinterJob.getPrinterJob();
//设置打印类
job.setPageable(book);
try {
// 添加指定的打印机
job.setPrintService(pss[0]);
// 打印执行
job.print();
} catch (PrinterException e) {
throw new ServiceException(ErrorCodes.PRINTER_ERROR);
}
}
}
2:配置小票格式以及数据
public class SalesTicket implements Printable {
private List<GoodsInfoPo> goods;
private List<PayTypePo> payTypePos;
private String deptNum;
private String orderNum;
private Integer peopleCount;
private String orgName;
private String turntableInfo;
private Long orderPeopleNum;
private String orderPeopleName;
private String openTime;
private String payTime;
private Integer payCount;
private Double shouldPayAmount;
private Double truePayAmount;
private Double discountAmount;
private SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss EEE");
public SalesTicket(List<GoodsInfoPo> goods, List<PayTypePo> payTypePos, String deptNum, String orderNum, Integer peopleCount, String orgName, String turntableInfo, Long orderPeopleNum, String orderPeopleName, String openTime, String payTime, Integer payCount, Double shouldPayAmount, Double truePayAmount, Double discountAmount) {
super();
this.goods = goods;
this.payTypePos = payTypePos;
this.deptNum = deptNum;
this.orderNum = orderNum;
this.peopleCount = peopleCount;
this.orgName = orgName;
this.turntableInfo = turntableInfo;
this.orderPeopleNum = orderPeopleNum;
this.orderPeopleName = orderPeopleName;
this.openTime = openTime;
this.payTime = payTime;
this.payCount = payCount;
this.shouldPayAmount = shouldPayAmount;
this.truePayAmount = truePayAmount;
this.discountAmount = discountAmount;
}
@Override
public String toString() {
return "SalesTicket{" +
"goods=" + goods +
", payTypePos=" + payTypePos +
", deptNum='" + deptNum + '\'' +
", orderNum='" + orderNum + '\'' +
", peopleCount=" + peopleCount +
", orgName='" + orgName + '\'' +
", turntableInfo='" + turntableInfo + '\'' +
", orderPeopleNum=" + orderPeopleNum +
", orderPeopleName='" + orderPeopleName + '\'' +
", openTime='" + openTime + '\'' +
", payTime='" + payTime + '\'' +
", payCount=" + payCount +
", shouldPayAmount=" + shouldPayAmount +
", truePayAmount=" + truePayAmount +
", discountAmount=" + discountAmount +
'}';
}
/**
* 打印方法
* graphics - 用来绘制页面的上下文,即打印的图形
* pageFormat - 将绘制页面的大小和方向,即设置打印格式,如页面大小一点为计量单位(以1/72 英寸为单位,1英寸为25.4毫米。A4纸大致为595 × 842点)
* 小票纸宽度一般为58mm,大概为165点
* pageIndex - 要绘制的页面从 0 开始的索引 ,即页号
*/
@Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
//此 Graphics2D 类扩展 Graphics 类,以提供对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制。
//它是用于在 Java(tm) 平台上呈现二维形状、文本和图像的基础类。
Graphics2D g2 = (Graphics2D) graphics;
//设置打印颜色为黑色
g2.setColor(Color.black);
//虚线设置
g2.setStroke(new BasicStroke(0.5f,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER,1.0f,new float[]{1.0f},0.0f));
//打印起点坐标
//返回与此 PageFormat相关的 Paper对象的可成像区域左上方点的 x坐标。
double x= pageFormat.getImageableX();
//返回与此 PageFormat相关的 Paper对象的可成像区域左上方点的 y坐标。
double y= pageFormat.getImageableY();
//Font.PLAIN: 普通样式常量 Font.ITALIC 斜体样式常量 Font.BOLD 粗体样式常量。
//根据指定名称、样式和磅值大小,创建一个新 Font。
Font font = new Font("宋体",Font.BOLD,12);
//设置标题打印字体
g2.setFont(font);
//获取字体的高度
float heigth = font.getSize2D();
//设置小票的标题标题
FontMetrics fm = g2.getFontMetrics(font);
int textWidth = fm.stringWidth(orgName);
//获取标题居中宽度
int widthX = (210 - textWidth) / 2;
g2.drawString(orgName,(float)x+widthX,(float)y+heigth);
heigth+=heigth;
textWidth = fm.stringWidth("结算单");
widthX = (210 - textWidth) / 2;
g2.drawString("结算单",(float)x+widthX,(float)y+heigth);
heigth+=heigth;
g2.drawString("桌号:"+deptNum,(float)x+5 , (float)y+heigth);
textWidth = fm.stringWidth("人数:"+peopleCount);
g2.drawString("人数:"+peopleCount, 200 - textWidth, (float)y+heigth);
//0.25不能改
heigth+=heigth * 0.25;
//下一行开始打印的高度
float line = heigth;
g2.drawLine((int)x,(int)(y+line),(int)x+227,(int)(y+line));
line+=15;
//设置正文字体
g2.setFont(new Font("宋体", Font.PLAIN,8));
// 字体高度
heigth = font.getSize2D();
//设置单号
g2.drawString("单号:"+orderNum,(float)x+5,(float)y+line);
//设置收银员
textWidth = fm.stringWidth("收银员:"+orderPeopleName);
g2.drawString("收银员:"+orderPeopleName,210 - textWidth,(float)y+line);
line+=heigth;
//设置订台人编号
g2.drawString("订台人编号:"+orderPeopleNum,(float)x+5,(float)y+line);
//设置订台人
textWidth = fm.stringWidth("订台人:"+orderPeopleName);
g2.drawString("订台人:"+orderPeopleName,210 - textWidth,(float)y+line);
line+=heigth;
//设置开台时间
g2.drawString("开台时间:"+openTime,(float)x+5,(float)y+line);
line+=heigth;
//设置结算时间
g2.drawString("结算时间:"+payTime,(float)x+5,(float)y+line);
line+=heigth;
g2.drawLine((int)x,(int)(y+line),(int)x+227,(int)(y+line));
line+=heigth;
//设置标题
g2.drawString("商品名称",(float)x+5, (float)y+line);
g2.drawString("数量",(float)x+75, (float)y+line);
g2.drawString("规格",(float)x+100, (float)y+line);
g2.drawString("单价",(float)x+140, (float)y+line);
g2.drawString("小计",(float)x+170, (float)y+line);
line+=heigth;
g2.drawLine((int)x,(int)(y+line),(int)x+227,(int)(y+line));
line+=heigth;
//设置商品清单
if(goods!=null && goods.size()>0){
for(GoodsInfoPo gdf:goods){
g2.drawString(gdf.getGname(),(float)x+5, (float)y+line);
g2.drawString(gdf.getCount().toString(),(float)x+80, (float)y+line);
g2.drawString(gdf.getSpec(),(float)x+105, (float)y+line);
g2.drawString(gdf.getPrice(),(float)x+140,(float)y+line);
g2.drawString(gdf.getAmount(),(float)x+170,(float)y+line);
line += heigth + 3;
if (gdf.getPrintGoodsComboPoList()!=null && gdf.getPrintGoodsComboPoList().size()>0){
for (PrintGoodsComboPo printGoodsComboPo:gdf.getPrintGoodsComboPoList()){
g2.drawString(printGoodsComboPo.getName(), (float)x+15, (float)y+line);
g2.drawString(printGoodsComboPo.getCount().toString(),(float)x+80 ,(float)y+line );
g2.drawString(printGoodsComboPo.getSpec(), (float)x+105, (float)y+line);
line += heigth + 3;
}
}
}
}
g2.drawLine((int) x, (int)(y+line), (int) x + 227, (int)(y+line));
line += heigth;
g2.drawString("结算明细",(float)x+5,(float)y+line);
line += heigth;
g2.drawLine((int) x, (int)(y+line), (int) x + 227, (int)(y+line));
line += heigth;
if(payTypePos!=null && payTypePos.size()>0){
for(PayTypePo payTypePo:payTypePos){
if (payTypePo.getAmount() != 0){
g2.drawString(payTypePo.getCnlName(),(float)x+5,(float)y+line);
textWidth = fm.stringWidth(payTypePo.getAmount().toString());
g2.drawString("¥ "+payTypePo.getAmount().toString(),200 - textWidth,(float)y+line);
}
}
}
line += heigth;
g2.drawLine((int) x, (int)(y+line), (int) x + 227, (int)(y+line));
line += heigth;
g2.drawString("账单合计:¥ "+shouldPayAmount, (float)x+110, (float)y+line);
line += heigth;
g2.drawString("实收金额:¥ "+truePayAmount, (float)x+110, (float)y+line);
line += heigth;
g2.drawString("赠送合计:¥ 0", (float)x+110, (float)y+line);
line += heigth;
g2.drawString("折扣合计:¥ "+discountAmount, (float)x+110, (float)y+line);
line += heigth;
g2.drawString("券优惠合计:¥ 0", (float)x+110, (float)y+line);
line += heigth;
g2.drawString("积分合计:¥ 0", (float)x+110, (float)y+line);
line += heigth;
g2.drawString("赠送比例:0%", (float)x+110, (float)y+line);
line += heigth;
g2.drawString("抵消比例:999%", (float)x+110, (float)y+line);
line += heigth;
g2.drawString("换桌:"+turntableInfo,(float)x+5,(float)y+line);
line += heigth;
g2.drawString("打印时间:"+payTime,(float)x+5,(float)y+line);
line += heigth;
g2.drawString("结账次数:"+payCount,(float)x+5,(float)y+line);
switch (pageIndex) {
case 0:
return PAGE_EXISTS;
default:
return NO_SUCH_PAGE;
}
}
}
3:实现接口:
@RequestMapping("/printReport")
@ResponseBody
public Object testPrint(@Validated @RequestBody PrintFrom printFrom){
Map<String,Object> map = new HashMap<>(1);
List<PrintContentPo> printContentPoList = printMapper.getPrintContent(printFrom);
for (PrintContentPo printContentPo:printContentPoList){
List<GoodsInfoPo> goods = printGoodsMapper.getPrintGoods(printContentPo.getPayId());
List<PayTypePo> payTypePos = printPayTypeMapper.getPayTypeList(printContentPo.getPayId());
for (GoodsInfoPo goodsInfoPo:goods){
if (goodsInfoPo.getIsCombo().equals(ComboType.COMBO.getCode())){
List<PrintGoodsComboPo> comboPoList = printGoodsComboMapper.getGoodsCombo(printContentPo.getPayId(),goodsInfoPo.getBarConfigId());
goodsInfoPo.setPrintGoodsComboPoList(comboPoList);
}
}
SalesTicket stk=new SalesTicket(goods,payTypePos,printContentPo.getDeptNum(),printContentPo.getOrderNum(),printContentPo.getPeopleCount(),printContentPo.getOrgName(),printContentPo.getTurntableInfo(),printContentPo.getOrderPeopleNum(),printContentPo.getOrderPeopleName(),printContentPo.getOpenTime(),printContentPo.getPayTime(),printContentPo.getPayCount(),printContentPo.getShouldPayAmount(),printContentPo.getTruePayAmount(),printContentPo.getDiscountAmount());
Printer p=new Printer(stk);
p.printer(printFrom.getPrinterName());
map.put("result","success" );
}
return new ReportResponse(map);
}
4:注意事项:
主要实现方法就这些。
实体类,mapper和sql就不展示了。
另外,设置小票格式根据自己的需求配置。
谢谢!