使用JAVA调用热敏打印机接口实现打印功能

一 前言

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

二 准备工作

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");

	@Override
	public 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 开始的索引 ,即页号
	 */
	@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("操作员:"+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 类提供文档的表示形式,该文档的页面可以使用不同的页面格式和页面 painter
            Book 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)
    @ResponseBody
    public 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);

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

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

  • 4
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
### 回答1: 使用iText打印PDF文件可以通过以下步骤实现: 1. 导入iText库 首先,需要将iText库添加到Java项目中。可以在Maven中添加以下依赖项: ``` <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.13</version> </dependency> ``` 或者可以从iText的官方网站下载库并手动添加到项目中。 2. 创建PDF文档 使用iText创建PDF文档。这可以通过以下代码实现: ``` Document document = new Document(); PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("sample.pdf")); document.open(); document.add(new Paragraph("Hello World!")); document.close(); writer.close(); ``` 这段代码创建一个包含“Hello World!”文本的PDF文档。 3. 打印PDF文件 使用Java的PrintService类来获取系统中的打印机,并使用PdfReader类读取创建的PDF文档。以下代码演示了如何实现: ``` PrintService[] printers = PrintServiceLookup.lookupPrintServices(null, null); PdfReader reader = new PdfReader("sample.pdf"); PrintService printer = printers[0]; // 选择系统中的第一个打印机 DocPrintJob job = printer.createPrintJob(); PdfPrint pdfPrint = new PdfPrint(reader, job); pdfPrint.print(); ``` 这段代码选择系统中的第一个打印机,并使用PdfPrint类来打印PDF文档。注意,在运行此代码之前,确保有打印机可用。 以上是使用iText在Java调用打印机打印PDF文件的基本步骤。您可以根据自己的需求对其进行修改和调整。 ### 回答2: 使用iText调用打印机打印PDF,可以通过以下步骤实现: 1. 首先,确保已经正确安装和配置了iText库,并将其添加到Java项目中的类路径中。 2. 创建一个空白的PDF文档对象,可以使用`PdfWriter`类来实现,通过指定输出流将其与文件关联起来。 3. 使用iText的API来添加文本、图片、表格等内容到PDF文档中。这些内容可以使用`com.itextpdf.text`包中的相应类来创建和设置。 4. 在将PDF文档打印之前,需要首先将其导出为临时文件。可以使用`java.io.File`类来生成一个带有唯一名称的临时文件,并将PDF内容写入该文件。 5. 调用系统的打印机服务,使用Java的`java.awt.Desktop.print(File file)`方法,将PDF文件发送给打印机进行打印。 下面是一个示例代码,演示了如何使用iText将PDF文档打印打印机: ```java import com.itextpdf.text.Document; import com.itextpdf.text.Paragraph; import com.itextpdf.text.pdf.PdfWriter; import java.awt.*; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; public class PrintPdfWithIText { public static void main(String[] args) { // 创建PDF文档 Document document = new Document(); try { // 绑定到一个临时PDF文件 File outputFile = File.createTempFile("temp", ".pdf"); PdfWriter.getInstance(document, new FileOutputStream(outputFile)); // 打开文档 document.open(); // 添加内容 document.add(new Paragraph("Hello, World!")); // 关闭文档 document.close(); // 打印PDF文件 if (Desktop.isDesktopSupported()) { Desktop.getDesktop().print(outputFile); } } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } } ``` 这是一个简单的示例代码,演示了使用iText创建一个包含"Hello, World!"文本的PDF文档,并将其打印到默认打印机。可以根据具体需求修改和扩展代码。 ### 回答3: Java可以使用iText库来调用打印机打印PDF文件。iText是一个功能强大的Java库,可以用于创建、操纵和处理PDF文档。 使用iText调用打印机打印PDF文件的步骤如下: 1. 首先,需要通过下载iText库的jar文件并将其导入到Java项目中。 2. 创建一个打印任务,并指定要打印的PDF文件的路径。可以使用FileInputStream类来读取PDF文件。 3. 创建一个打印机的选择对话框,以显示可用的打印机列表供用户选择。可以使用javax.print包中的类来实现功能。 4. 获取用户选择的打印机,并将其作为参数传递给PrintServiceLookup类的lookupDefaultPrintService方法。 5. 创建一个DocFlavor对象,指定打印的文档类型为PDF。可以使用javax.print包中的DocFlavor类来实现。 6. 创建一个Doc对象,将读取的PDF文件和DocFlavor对象作为参数传递给Doc类的构造函数。 7. 创建一个PrintJob对象,并将打印机和Doc对象作为参数传递给PrintService类的createPrintJob方法。 8. 调用PrintJob对象的print方法,开始进行打印操作。 9. 最后,关闭文件输入流和打印作业。 使用iText库调用打印机打印PDF文件可以实现灵活的打印功能,可以选择不同的打印机和页面设置,同时也能够处理PDF文档的内容和样式。通过iText,Java可以轻松地实现PDF文件的打印操作。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值