全是封装的工具类,复制粘贴即可使用!!!
实体类
@Data
public class Orders implements Serializable {
private static final long serialVersionUID = -560708444936642252L;
/**销售型号*/
@ApiModelProperty(value = "销售型号")
private String salesType;
/**销售价*/
@ApiModelProperty(value = "销售价")
private String sellingPrice;
/**折后价*/
@ApiModelProperty(value = "折后价")
private String discountPrice;
/**数量*/
@ApiModelProperty(value = "数量")
private String count;
/**金额*/
@ApiModelProperty(value = "金额")
private String goodAmount;
}
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
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.HashMap;
import java.util.List;
import java.util.Map;
/**
* 销售清单对象
*/
@Data
public class SalesTicket implements Printable {
private List<Orders> goods; //商品列表
/**
* 订单编号
*/
@ApiModelProperty(value = "订单编号")
private String orderNo;
/**
* 创建时间
*/
@ApiModelProperty(value = "创建时间")
private String createTime;
/**
* 所属门店名称
*/
@ApiModelProperty(value = "所属门店名称")
private String storeBelongName;
/**
* 门店地址
*/
@ApiModelProperty(value = "门店地址")
private String fullAddress;
/**
* 总数量
*/
@ApiModelProperty(value = "总数量")
private String totalCount;
/**
* 折扣率
*/
@ApiModelProperty(value = "折扣率")
private String discountRate;
/**
* 原价
*/
@ApiModelProperty(value = "原价")
private String originalPrice;
/**
* 优惠价
*/
@ApiModelProperty(value = "优惠价")
private String specialPrice;
/**
* 实付价
*/
@ApiModelProperty(value = "实付价")
private String actualPricePaid;
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss EEE");
@Override
public String toString() {
return "SalesTicket [goods=" + goods + ", orderNo=" + orderNo + ", createTime=" + createTime
+ ", storeBelongName=" + storeBelongName + ", fullAddress=" + fullAddress + ", totalCount="
+ totalCount + ", discountRate=" + discountRate + ", originalPrice=" + originalPrice + ", specialPrice="
+ specialPrice + ", actualPricePaid=" + actualPricePaid + "]";
}
public SalesTicket(List<Orders> goods, String orderNo, String createTime, String storeBelongName,
String fullAddress, String totalCount, String discountRate, String originalPrice,
String specialPrice, String actualPricePaid) {
super();
this.goods = goods;
this.orderNo = orderNo;
this.createTime = createTime;
this.storeBelongName = storeBelongName;
this.fullAddress = fullAddress;
this.totalCount = totalCount;
this.discountRate = discountRate;
this.originalPrice = originalPrice;
this.specialPrice = specialPrice;
this.actualPricePaid = actualPricePaid;
}
public SalesTicket() {
super();
}
/**
* 打印方法
* 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);
//打印起点坐标
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("订单编号:" + orderNo, (float) x + 20, (float) y + line);
line += heigth + 2;
g2.drawString("创建时间:" + createTime, (float) x + 20, (float) y + line);
line += heigth + 2;
g2.drawString("下单门店:" + storeBelongName, (float) x + 20, (float) y + line);
line += heigth + 2;
g2.drawString("门店地址:" + fullAddress, (float) x + 20, (float) y + line);
line += heigth + 2;
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) {
Graphics2D g3 = (Graphics2D) graphics;
Font font1 = new Font("宋体", Font.BOLD, 5);
g3.setFont(font1);
g2.drawString("名称:", (float) x + 15, (float) y + line);
g2.drawString(gdf.getSalesType(), (float) x + 60, (float) y + line);
line += heigth;
float column1Width = g3.getFontMetrics().stringWidth("销售价:");
float column2Width = g3.getFontMetrics().stringWidth("折后价:");
float column3Width = g3.getFontMetrics().stringWidth("数量:");
float column4Width = g3.getFontMetrics().stringWidth("金额:");
float column1X = (int) x + 15 + column1Width;
float column2X = column1X + column2Width;
float column3X = column2X + column3Width;
float column4X = column3X + column4Width;
g3.drawString("销售价:", (float) x + 15, (float) y + line);
g3.drawString("折后价:", (float) column2X + 10, (float) y + line);
g3.drawString(" 数量:", (float) column3X + 10, (float) y + line);
g3.drawString(" 金额:", (float) column4X + 10, (float) y + line);
line += heigth;
g3.drawString(String.valueOf(gdf.getSellingPrice()), (float) x + 15, (float) y + line);
g3.drawString(String.valueOf(gdf.getDiscountPrice()), (float) column2X + 10, (float) y + line);
g3.drawString(" " + String.valueOf(gdf.getCount()), (float) column3X + 10, (float) y + line);
g3.drawString(" " + String.valueOf(gdf.getGoodAmount()), (float) column4X + 10, (float) y + line);
line += heigth;
}
}
Graphics2D g4 = (Graphics2D) graphics;
Font font2 = new Font("宋体", Font.BOLD, 7);
g4.setFont(font2);
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;
g4.drawString("总数量:" + totalCount + "件" + " 折扣:" + discountRate, (float) x + 15, (float) y + line);
line += heigth;
// g2.drawString("折扣:"+ discountRate,(float)x+15,(float)y+line);
line += heigth;
g4.drawString("原价:¥" + originalPrice + " " + "优惠:¥" + specialPrice, (float) x + 15, (float) y + line);
line += heigth;
line += heigth;
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;
g4.drawString("实付:¥" + actualPricePaid, (float) x + 15, (float) y + line);
line += heigth;
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 + 10;
g4.drawString(" *温馨提醒!*", (float) x + 15, (float) y + line);
line += heigth + 10;
//在此图形上下文的坐标系中使用当前颜色在点 (x1, y1) 和 (x2, y2) 之间画一条线。 即绘制虚线
g2.drawLine((int) x, (int) (y + line), (int) x + 158, (int) (y + line));
line += heigth + 10;
g4.drawString("请您务必妥善保管好小票!", (float) x + 15, (float) y + line);
line += heigth + 10;
g4.drawString("【七天无理由退换货服务】", (float) x + 15, (float) y + line);
line += heigth;
g4.drawString("自购买日起7天内,在商品原包装完好,", (float) x + 15, (float) y + line);
line += heigth;
g4.drawString("吊牌未拆封,不影响二次销售的情况下.", (float) x + 15, (float) y + line);
line += heigth;
g4.drawString("可凭本张收银小票,前往原购买店铺", (float) x + 15, (float) y + line);
line += heigth;
g4.drawString("享受7天无理由退换货服务。", (float) x + 15, (float) y + line);
line += heigth + 10;
g4.drawString("盲盒类商品,贴身衣物类商品一经售出,", (float) x + 15, (float) y + line);
line += heigth;
g4.drawString("恕不退还!", (float) x + 15, (float) y + line);
line += heigth;
line += heigth + 10;
g4.drawString("【30天质量问题退换货服务】", (float) x + 15, (float) y + line);
line += heigth;
g4.drawString("自购买日起30天内,如产品发生质量", (float) x + 15, (float) y + line);
line += heigth;
g4.drawString("问题,可凭本张收银小票,前往原购买", (float) x + 15, (float) y + line);
line += heigth;
g4.drawString("门店销售退换货服务", (float) x + 15, (float) y + line);
line += heigth;
line += heigth + 10;
g4.drawString("质量问题鉴定请按照相关国家行业标准", (float) x + 15, (float) y + line);
line += heigth;
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 + 30;
g4.drawString("请您扫描右侧二维码开具电子发票", (float) x + 15, (float) y + line);
line += heigth;
g4.drawString("开具电子发票", (float) x + 15, (float) y + line);
BufferedImage qrcodeImg = generateQRCode("https://www.baidu.com", 60, 60);
if (qrcodeImg != null) {
//在打印页面上绘制二维码图片
g2.drawImage(qrcodeImg, (int) x + 90, (int) ((int) y + line - 40), null);
}
line += heigth + 30;
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 + 10;
g4.drawString(" *结语*", (float) x + 15, (float) y + line);
switch (pageIndex) {
case 0:
return PAGE_EXISTS; //0
default:
return NO_SUCH_PAGE; //1
}
}
/**
* 使用Zxing生成二维码
*
* @param content 二维码内容
* @param width 二维码宽度
* @param height 二维码高度
* @return 二维码图片
*/
public BufferedImage generateQRCode(String content, int width, int height) {
try {
//设置二维码参数
content = "暂不支持此功能";
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.MARGIN, 0);
//生成二维码
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix);
return image;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
设置纸张大小
import com.link.dms.base.print.Model.SalesTicket;
import java.awt.print.*;
/**
* 打印对象 -> 实现Printable接口即可调用打印机打印
*/
public class YcPrinter {
private SalesTicket salesTicket;
public YcPrinter(SalesTicket salesTicket) {
this.salesTicket = salesTicket;
}
public void printer() {
try {
//Book 类提供文档的表示形式,该文档的页面可以使用不同的页面格式和页面 painter
Book book = new Book(); //要打印的文档
//PageFormat类描述要打印的页面大小和方向
PageFormat pf = new PageFormat(); //初始化一个页面打印对象
pf.setOrientation(PageFormat.PORTRAIT); //设置页面打印方向,从上往下,从左往右
//设置打印纸页面信息。通过Paper设置页面的空白边距和可打印区域。必须与实际打印纸张大小相符。
Paper paper = new Paper();
// 纸张大小
paper.setSize(158, 30000);
// A4(595 X 842)设置打印区域,其实0,0应该是72,72,因为A4纸的默认X,Y边距是72
paper.setImageableArea(0, 0, 158, 30000);
pf.setPaper(paper);
book.append(salesTicket, pf);
PrinterJob job = PrinterJob.getPrinterJob(); //获取打印服务对象
job.setPageable(book); //设置打印类
job.print(); //开始打印
} catch (PrinterException e) {
e.printStackTrace();
}
}
}
Controller层调用
import com.link.dms.base.print.Model.SalesTicket;
import io.swagger.annotations.Api;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/print")
@Api(tags = {"定单请求处理"})
public class printReceipt {
@PostMapping("/receipt")
@ResponseBody
public String printOrder(@RequestBody SalesTicket salesTickets) {
SalesTicket stk = new SalesTicket(salesTickets.getGoods(), salesTickets.getOrderNo(), salesTickets.getCreateTime(),
salesTickets.getStoreBelongName(), salesTickets.getFullAddress(), salesTickets.getTotalCount(),
salesTickets.getDiscountRate(), salesTickets.getOriginalPrice(), salesTickets.getSpecialPrice(),
salesTickets.getActualPricePaid());
YcPrinter p = new YcPrinter(stk);
p.printer();
return "成功";
}
}