本篇讲解关于如何实现纯后台的打印操作,无前端代码,使用JAVA.AWT类实现。代码分为两个部分:打印直连数据库数据以及打印功能的实现。
依赖:
<dependency>
<groupId>com.google.zxinggroupId>
<artifactId>coreartifactId>
<version>3.3.0version>
dependency>
本demo的打印内容包括:标题、资产名称、型号、部门、责任人、启用日期和二维码图片。类定义如下:
/**
* @Author: Mr.ZJW
* @Description: 测试数据
* @Date: 2022/4/12 16:42
**/
public class DemoDto implements Serializable {
private static final long serialVersionUID = 1L;
private String assetName; //资产名称
private String assetType; //型号
private String deptName; //部门
private String responsible; //责任人
private Date useTime; //启用日期
private String qrCodePath; //二维码路径
private String title; //标签页标题
public DemoDto(String assetName, String assetType, String deptName,
String responsible, Date useTime, String qrCodePath, String title) {
super();
this.assetName = assetName;
this.assetType = assetType;
this.deptName = deptName;
this.responsible = responsible;
this.useTime = useTime;
this.qrCodePath = qrCodePath;
this.title = title;
}
//父类构造器必须声明,避免小几率的异常或无响应
public DemoDto() {
super();
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getQrCodePath() {
return qrCodePath;
}
public void setQrCodePath(String qrCodePath) {
this.qrCodePath = qrCodePath;
}
public String getAssetName() {
return assetName;
}
public void setAssetName(String assetName) {
this.assetName = assetName;
}
public String getAssetType() {
return assetType;
}
public void setAssetType(String assetType) {
this.assetType = assetType;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getResponsible() {
return responsible;
}
public void setResponsible(String responsible) {
this.responsible = responsible;
}
public Date getUseTime() {
return useTime;
}
public void setUseTime(Date useTime) {
this.useTime = useTime;
}
}
/**
* @Author: Mr.ZJW
* @Date: 2022-04-12 16:43
* @Description: 打印功能实现类
*/
public class PrintDemo implements Printable {
private static int COUNT = 0; //待打印数据的条数,此变量需定义在数据集合之前
private static List<DemoDto> DEMODTO_LIST = getDemoDto(); //待打印的文字数据
@Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
System.out.println("-----------------执行第"+(COUNT+1)+"次打印-------------------");
System.out.println("pageIndex = "+pageIndex);
Component c = null;
//转换成Graphics2D
Graphics2D g2 = (Graphics2D) graphics;
//设置打印颜色为黑色
g2.setColor(Color.black);
//打印起点坐标
double x = pageFormat.getImageableX();
double y = pageFormat.getImageableY();
System.out.println("起点坐标x="+x+";y="+y);
switch(pageIndex){
case 0:
//设置打印字体(字体名称、样式和点大小)(字体名称可以是物理或者逻辑名称)
//Java平台所定义的五种字体系列:Serif、SansSerif、Monospaced、Dialog 和 DialogInput
Font font = new Font("新宋体", Font.PLAIN, 7);
g2.setFont(font);//设置字体
float[] dash1 = {2.0f};
//设置打印线的属性。
//1.线宽 2、3、不知道,4、空白的宽度,5、虚线的宽度,6、偏移量
g2.setStroke(new BasicStroke(0.5f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 2.0f, dash1, 0.0f));
//获取需要打印的图片,若是动态生成,直接传入绝对路径即可
Image src = Toolkit.getDefaultToolkit().getImage(DEMODTO_LIST.get(COUNT).getQrCodePath());
if (src == null) {
System.out.println("没有找到图像");
}
/**
* 参数2:打印的x坐标起点 参数3 打印的y坐标起点
* 参数4:打印图片的宽度 参数5:打印图片的高度
*/
g2.drawImage(src,(int)80,(int)15,(int)48,(int)48,c);
//标题,固定不变
g2.drawString(DEMODTO_LIST.get(COUNT).getTitle(), (float)30, (float)18);
//以下为动态的文字内容
font = new Font("新宋体", Font.PLAIN, 5);
g2.setFont(font);
g2.drawString("资产名称:"+DEMODTO_LIST.get(COUNT).getAssetName(), (float)10, (float)30);
g2.drawString("型 号:"+DEMODTO_LIST.get(COUNT).getAssetType(), (float)10, (float)40);
g2.drawString("部 门:"+DEMODTO_LIST.get(COUNT).getDeptName(), (float)10, (float)50);
g2.drawString("责 任 人:"+DEMODTO_LIST.get(COUNT).getResponsible(), (float)10, (float)60);
System.out.println("-----------------打印成功-------------------");
return PAGE_EXISTS;
default:
return NO_SUCH_PAGE;
}
}
/**
* 封装测试数据
* @return
*/
private static List<DemoDto> getDemoDto() {
List<DemoDto> dtos = new ArrayList<DemoDto>();
dtos.add(new DemoDto("戒毒所打印机01", "惠普打印机", "技术支持部", "责任人01", new Date(), "E:\\货位码.png", "宝丰戒毒所"));
if (dtos.size()>0) {
COUNT = dtos.size()-1;
System.out.println("总共需打印"+(COUNT+1)+"次");
}
return dtos;
}
public static void main(String[] args) {
// 通俗理解就是书、文档
Book book = new Book();
// 设置成竖打
PageFormat pf = new PageFormat();
pf.setOrientation(PageFormat.PORTRAIT);
// 通过Paper设置页面的空白边距和可打印区域。必须与实际打印纸张大小相符。
Paper p = new Paper();
p.setSize(142,82);//纸张大小
p.setImageableArea(10,10, 142,70);
pf.setPaper(p);
// 把 PageFormat 和 Printable 添加到书中,组成一个页面
book.append(new PrintDemo(), pf);
//获取打印服务对象
PrinterJob job = PrinterJob.getPrinterJob();
System.out.println("job.getJobName() = " + job.getJobName());
// 设置打印类
job.setPageable(book);
try {
//直接打印 ,不显示对话框
if (DEMODTO_LIST.size()>0) {
for (int i=0;i<DEMODTO_LIST.size();i++) {
job.print();
--COUNT;
}
}
} catch (PrinterException e) {
e.printStackTrace();
}
}
}
这里打印物料标签,可根据真是业务场景修改数据以及想要的效果!
/**
* @Author: Mr.ZJW
* @Date: 2022-03-29 16:18
* @Description: 物料标签返回结果集
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MessageQrCodeVo {
/**
* 入库子项ID
*/
private Long id;
/**
* 物料标签id
*/
private Integer materialLabelId;
/**
* 货位id
*/
private Long goodsAllocationId;
/**
* 物料id
*/
private Long itemId;
/**
* 标签表里的入库子项id
*/
private Long rukuSubitemId;
/**
* 项目号
*/
private String projectNumber;
/**
* 数量
*/
private Integer hadQty;
/**
* 供应商名称
*/
private String supplierName;
/**
* 规格信息号
*/
private String originalModel;
/**
* 物料名称
*/
private String materialName;
/**
* 订单号
*/
private String billNumber;
/**
* 版本
*/
private String version;
/**
* 组件号
*/
private String parentItemId;
}
/**
* @Author: Mr.ZJW
* @Date: 2022-04-13 18:28
* @Description: 物料标签打印工具类
*/
@Slf4j
public class MaterialLablePrinte implements Printable {
public MaterialLablePrinte() {
}
public MaterialLablePrinte(List<MessageQrCodeVo> messageQrCodeVos) {
this.DEMODTO_LIST = messageQrCodeVos;
COUNT = messageQrCodeVos.size() - 1;
}
private static int COUNT; //待打印数据的条数,此变量需定义在数据集合之前
private static List<MessageQrCodeVo> DEMODTO_LIST; //待打印的文字数据
@Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
log.info("-----------------执行第" + (COUNT + 1) + "次打印-------------------");
Component c = null;
//转换成Graphics2D
Graphics2D g2 = (Graphics2D) graphics;
//设置打印颜色为黑色
g2.setColor(Color.black);
//打印起点坐标
double x = pageFormat.getImageableX();
double y = pageFormat.getImageableY();
switch (pageIndex) {
case 0:
//设置打印字体(字体名称、样式和点大小)(字体名称可以是物理或者逻辑名称)
//Java平台所定义的五种字体系列:Serif、SansSerif、Monospaced、Dialog 和 DialogInput
Font font = new Font("新宋体", Font.PLAIN, 7);
g2.setFont(font);//设置字体
float[] dash1 = {2.0f};
//设置打印线的属性。
//1.线宽 2、3、不知道,4、空白的宽度,5、虚线的宽度,6、偏移量
g2.setStroke(new BasicStroke(0.5f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 2.0f, dash1, 0.0f));
//二维码信息字符串
String deviceId = String.valueOf(DEMODTO_LIST.get(COUNT).getMaterialLabelId());
BufferedImage image = null;
try {
//先创建一个图片编辑器,生成一个二维码,二维码生成图片后再创建另一个图片编辑器,用来编写表格
Hashtable<EncodeHintType, ErrorCorrectionLevel> hintMap = new Hashtable<EncodeHintType, ErrorCorrectionLevel>();
hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); // 矫错级别
QRCodeWriter qrCodeWriter = new QRCodeWriter();
//创建比特矩阵(位矩阵)的QR码编码的字符串
deviceId = new String(deviceId.getBytes("UTF-8"), "ISO-8859-1");
int qrCodeSize = 200;
BitMatrix byteMatrix = qrCodeWriter.encode(deviceId, BarcodeFormat.QR_CODE, qrCodeSize, qrCodeSize, hintMap);
// 使BufferedImage勾画QRCode (matrixWidth 是行二维码像素点)
int matrixWidth = byteMatrix.getWidth();
image = new BufferedImage(matrixWidth - 20, matrixWidth - 20, BufferedImage.TYPE_INT_RGB);
image.createGraphics();
Graphics2D graphics2 = (Graphics2D) image.getGraphics();
graphics2.setColor(Color.WHITE);
graphics2.fillRect(0, 0, matrixWidth, matrixWidth);
// 使用比特矩阵画并保存图像
graphics2.setColor(Color.BLACK);
for (int i = 0; i < matrixWidth; i++) {
for (int j = 0; j < matrixWidth; j++) {
if (byteMatrix.get(i, j)) {
graphics2.fillRect(i - 10, j - 10, 1, 1);
}
}
}
image.flush();
} catch (Exception e) {
e.printStackTrace();
}
/**
* 参数2:打印的x坐标起点 参数3 打印的y坐标起点
* 参数4:打印图片的宽度 参数5:打印图片的高度
*/
g2.drawImage(image, (int) 120, (int) 70, (int) 66, (int) 66, c);
String titleStr = "1001";
String projectNo = "1001";//项目号
int amount = 123;
String supplier = "宁德";//供应商
String spec = "小一整箱";//规格型号
String name = "电机";//物料名称信息
String orderNo = "D0001";
String packedNo = "010101";
String version = "v2.1";
// 设置标题的字体,字号,大小
Font titleFont = new Font("黑体", Font.BOLD, 5);
FontMetrics fm = g2.getFontMetrics(titleFont);
int titleWidth = fm.stringWidth("物料标签码");
int titleWidthX = 120;// 感觉不居中,向左移动35个单位
g2.setFont(new Font("黑体", Font.BOLD, 10));
//标题,固定不变
g2.drawString("物料标签码", titleWidthX, (float) 18);
int firColumnX = 50;
// 项目号
g2.setFont(new Font("黑体", Font.BOLD, 8));
g2.drawString("项目号:" + DEMODTO_LIST.get(COUNT).getProjectNumber(), firColumnX, 32);
// 数量
g2.drawString("数量:" + DEMODTO_LIST.get(COUNT).getHadQty(), firColumnX, 44);
//供应商
g2.drawString("供应商:" + DEMODTO_LIST.get(COUNT).getSupplierName(), firColumnX, 54);
// 规格型号信息
g2.drawString("规格型号:" + DEMODTO_LIST.get(COUNT).getOriginalModel(), firColumnX, 64);
int secColumnX = 170;
// 物料名称信息
g2.drawString("物料名称:" + DEMODTO_LIST.get(COUNT).getMaterialName(), secColumnX, 32);
// 订单号
g2.drawString("订单号:" + DEMODTO_LIST.get(COUNT).getBillNumber(), secColumnX, 44);
// 版本号
g2.drawString("版本号:" + DEMODTO_LIST.get(COUNT).getVersion(), secColumnX, 54);
// 组件号
g2.drawString("组件号:" + DEMODTO_LIST.get(COUNT).getParentItemId(), secColumnX, 64);
return PAGE_EXISTS;
default:
return NO_SUCH_PAGE;
}
}
/**
* @Author: Mr.ZJW
* @Description: 打印
* @Date: 2022/4/13 18:49
**/
public void printMaterial() {
synchronized (MaterialLablePrinte.class) {
// 通俗理解就是书、文档
Book book = new Book();
// 设置成竖打
PageFormat pf = new PageFormat();
pf.setOrientation(PageFormat.PORTRAIT);
// 通过Paper设置页面的空白边距和可打印区域。必须与实际打印纸张大小相符。
Paper p = new Paper();
p.setSize(566, 144);//纸张大小
p.setImageableArea(0, 0, 566, 144);
pf.setPaper(p);
// 把 PageFormat 和 Printable 添加到书中,组成一个页面
book.append(new MaterialLablePrinte(), pf);
//获取打印服务对象
PrinterJob job = PrinterJob.getPrinterJob();
System.out.println("job.getJobName() = " + job.getJobName());
// 设置打印类
job.setPageable(book);
try {
//直接打印 ,不显示对话框
if (DEMODTO_LIST.size() > 0) {
for (int i = 0; i < DEMODTO_LIST.size(); i++) {
job.print();
--COUNT;
}
}
} catch (PrinterException e) {
e.printStackTrace();
}
}
}
}
1.Controller:
/**
* @Author: Mr.ZJW
* @Description: 打印物料标签
* @Date: 2022/3/29 14:21
**/
@GetMapping("/printerMaterialLabel")
public Result printerMaterialLabelDemo(HttpServletResponse httpResponse, Long[] id){
return rukuService.printerMaterialLabelDemo(httpResponse,id);
}
2.Service:
/**
* @Author: Mr.ZJW
* @Description: 打印物料标签
* @Date: 2022/4/13 18:34
**/
Result printerMaterialLabelDemo(HttpServletResponse httpResponse, Long[] ids);
3.ServiceImpl:
/**
* @Author: Mr.ZJW
* @Description: 打印物料标签
* @Date: 2022/4/13 18:35
**/
@Override
public Result printerMaterialLabelDemo(HttpServletResponse httpResponse, Long[] ids) {
//查询数据库
List<MessageQrCodeVo> messageQrCodeVoList = new ArrayList<>();
//设置物料标签码
for (Long id : ids) {
//根据入库子项ID形成物料标签二维码
MessageQrCodeVo messageQrCode = rukuHeadMapper.printerMaterialLabel(id);
//判断数据是否为空
if (ObjectUtils.isEmpty(messageQrCode)){
return Result.error(CodeMsg.NOT_FIND_DATA);
}
MessageQrCodeVo messageQrCodeVo = new MessageQrCodeVo();
//判断是否已有物料标签数据
if (null != messageQrCode.getRukuSubitemId()){
messageQrCodeVo.setMaterialLabelId(messageQrCode.getMaterialLabelId()); //标签内容
messageQrCodeVo.setProjectNumber(messageQrCode.getProjectNumber()+"");
messageQrCodeVo.setHadQty(messageQrCode.getHadQty());
messageQrCodeVo.setSupplierName(messageQrCode.getSupplierName()+" ");
messageQrCodeVo.setOriginalModel(messageQrCode.getOriginalModel() + "");
messageQrCodeVo.setMaterialName(messageQrCode.getMaterialName() + "");
messageQrCodeVo.setBillNumber(messageQrCode.getBillNumber() + "");
messageQrCodeVo.setVersion(messageQrCode.getVersion() + "");
messageQrCodeVo.setParentItemId(messageQrCode.getParentItemId() + "");
messageQrCodeVoList.add(messageQrCodeVo);
} else {
//如果没有新增物料标签表数据并且产生标签码
WarMaterialLabel warMaterialLabel = new WarMaterialLabel();
warMaterialLabel.setRukuSubitemId(messageQrCode.getId());
warMaterialLabel.setItemId(messageQrCode.getItemId());
warMaterialLabel.setGoodsAllocationId(messageQrCode.getGoodsAllocationId());
warMaterialLabel.setCreator(UserUtils.getUserName());
materialLabelMapper.insert(warMaterialLabel);
//拿到新建的物料标签
WarMaterialLabel newWarMaterialLabel = materialLabelMapper.selectOne(new LambdaQueryWrapper<WarMaterialLabel>().eq(WarMaterialLabel::getRukuSubitemId, warMaterialLabel.getRukuSubitemId()));
messageQrCodeVo.setMaterialLabelId(newWarMaterialLabel.getMaterialLabelId()); //标签内容
messageQrCodeVo.setProjectNumber(messageQrCode.getProjectNumber() + "");
messageQrCodeVo.setHadQty(messageQrCode.getHadQty());
messageQrCodeVo.setSupplierName(messageQrCode.getSupplierName() + " ");
messageQrCodeVo.setOriginalModel(messageQrCode.getOriginalModel() + "");
messageQrCodeVo.setMaterialName(messageQrCode.getMaterialName() + "");
messageQrCodeVo.setBillNumber(messageQrCode.getBillNumber() + "");
messageQrCodeVo.setVersion(messageQrCode.getVersion() + "");
messageQrCodeVo.setParentItemId(messageQrCode.getParentItemId() + "");
messageQrCodeVoList.add(messageQrCodeVo);
}
}
try {
System.out.println("aaaaaaaaaaaaaaaaaaa");
new MaterialLablePrinte(messageQrCodeVoList).printMaterial();
} catch (Exception e) {
log.error("生成二维码出错:"+e.getMessage() , e);
}
return Result.success("打印成功");
}
4.Mapper接口:
//查询物料标签结果集
MessageQrCodeVo printerMaterialLabel(Long id);
5.MapperXML:
<!--查询物料标签-->
<select id="printerMaterialLabel" resultType="com.geesun.war.entity.vo.MessageQrCodeVo">
SELECT
wrs.id,
wml.material_label_id,
wmi.id AS itemId,
wga.id AS goodsAllocationId,
wml.ruku_subitem_id,
wrs.project_number,
wrs.had_qty,
wrh.supplier_name,
wmi.original_model,
wmi.material_name,
wrh.bill_number,
wrs.version,
wrs.parent_item_id
FROM
war_ruku_head wrh
LEFT JOIN war_ruku_subitem wrs ON wrs.ruku_head_id = wrh.id
LEFT JOIN war_material_info wmi ON wmi.id = wrs.item_id
LEFT JOIN war_material_label wml ON wml.ruku_subitem_id = wrs.id
LEFT JOIN war_goods_allocation wga ON wga.goods_allocation_name = wrs.location_code
WHERE wrs.id = #{id}
</select>
首先可以打印单个以及打印多个,看业务场景打印,我这里是根据id查询相关数据,打印单个只需要传入单个id,多个传入多个id,以逗号分隔
1.利用ApiPost测试: