最近搞定了一个比较头疼的事情,邮政快递面单打印的需求。
需求:系统需要支持邮政下单、打印快递面单。
坑爹之处:邮政就是牛叉任性,其他家快递都可以提供面单查询接口,直接返回面单PDF数据,可以直接打印。邮政EMS就是丢给你一个面单规格说明书。你需要自己画出面单。
在网站查找了好久关于EMS面单实现的资料分享很少,只能死磕,最后还是实现了。这里把整个实现流程分享出来,这是最终实现的效果图片
Java 邮政EMS面单打印邮政EMS面单打印实现步骤:
1、请求EMS下单接口获取面单号
2、Java Graphics2D 画出快递面单图片。(这一步利用 Graphics2D 绘制出来 )
3、将图片生成PDF文件。
4、页面获取PDF文件打印
详细的实现步骤以及
一、下单接口请求数据
根据邮政提供的相关接口文档组装数据,发送请求。
/** * 下单接口 * * @param order * @return */ @Override public boolean placeOrder(BatOrder order, HospitalInformation hospitalInformation) throws IOException, NoSuchAlgorithmException, DocumentException { String logistics_interface = "<OrderNormal>" + "<created_time>" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss") + "</created_time>" + "<logistics_provider>B</logistics_provider>" + "<ecommerce_no>CICPSSYSTEM</ecommerce_no>" + "<ecommerce_user_id>2</ecommerce_user_id>" + "<sender_type>1</sender_type>" + "<inner_channel>0</inner_channel>" + "<logistics_order_no>" + order.getId().trim() + "</logistics_order_no>" + "<contents_attribute>3</contents_attribute>" + "<base_product_no>1</base_product_no>" + "<biz_product_no></biz_product_no>" + "<insurance_flag>1</insurance_flag>" + "<payment_mode>1</payment_mode>" + "<receipt_flag>1</receipt_flag>" + "<valuable_flag>0</valuable_flag>" + "<sender_safety_code>0</sender_safety_code>" + "<sender>" + "<name>" + hospitalInformation.getHospitalName() + "</name>" + "<post_code></post_code>" + "<phone>" + hospitalInformation.getPhoneNumber() + "</phone>" + "<mobile>" + hospitalInformation.getPhoneNumber() + "</mobile>" + "<prov>" + hospitalInformation.getProvince() + "</prov>" + "<city>" + hospitalInformation.getCity() + "</city>" + "<county>" + hospitalInformation.getCounty() + "</county>" + "<address>" + hospitalInformation.getArea() + "</address>" + "</sender>" + "<receiver>" + "<name>" + order.getAddressName() + "</name>" + "<post_code/>" + "<phone>" + order.getAddressPhone() + "</phone>" + "<mobile>" + order.getAddressPhone() + "</mobile>" + "<prov>" + order.getProvince() + "</prov>" + "<city>" + order.getCity() + "</city>" + "<county>" + order.getCounty() + "</county>" + "<address>" + order.getAddress() + "</address>" + "</receiver>" + "<cargos>" + "<Cargo>" + "<cargo_name>文件</cargo_name>" + "<cargo_category/><cargo_quantity/>" + "<cargo_value/><cargo_weight/>" + "</Cargo>" + "</cargos>" + "</OrderNormal>"; //签名 String data_digest = makeSignEMS(logistics_interface, hospitalInformation.getYunda_key1()); HashMap<String, Object> paramMap = new HashMap<>(); paramMap.put("msg_type", "邮政提供"); paramMap.put("ecCompanyId", "邮政提供"); paramMap.put("data_digest", data_digest); paramMap.put("logistics_interface", logistics_interface); String xml = HttpUtil.get(placeOrderUrl, paramMap); log.info("邮政下单接口返回值:{}", xml); //解析邮政返回的回执信息 //返回值格式: // <responses> // <responseItems> // <response> // <success>true</success> // <waybill_no>1200002779901</waybill_no> // <routeCode>310-新A-沙区02-沙区揽投-*</routeCode> // <packageCode></packageCode> // <packageCodeName>310-新A</packageCodeName> // <markDestinationCode>310-新A</markDestinationCode> // <markDestinationName>310-新A</markDestinationName> // </response> // </responseItems> // </responses> Map<String, String> data = XMLUtil.getDateFromEMSXML(xml); if (data.get("success").equals("true")) { //修改订单状态 order.setTracking_number(data.get("waybill_no")); order.setUpdateTime(new Date()); order.setFilePath(data.get("routeCode")); order.setSendDate(new Date()); int ret = batOrderService.updateBatOrder(order); if (ret > 0) { createPDF(order,hospitalInformation); return true; } else { log.error("修改更新数据库状态失败"); return false; } } else { log.error("邮政 下单取号接口失败"); return false; } } /** * 邮政 生成签名的方法 * * @param data * @param parentId * @return * @throws NoSuchAlgorithmException * @throws UnsupportedEncodingException */ public String makeSignEMS(String data, String parentId) throws NoSuchAlgorithmException, UnsupportedEncodingException { MessageDigest md = MessageDigest.getInstance("MD5"); BASE64Encoder base64en = new BASE64Encoder(); String Ret = base64en.encode(MessageDigest.getInstance("MD5").digest((data + parentId).getBytes("UTF-8"))); return Ret; }解析接口返回数据方法
/** * 从XML字符串中获取数据 * @param xml 例如: String xml2="<responses><responseItems><response><success>true</success><waybill_no>1200002779901</waybill_no><routeCode>310-新A-沙区02-沙区揽投-*</routeCode><packageCode></packageCode><packageCodeName>310-新A</packageCodeName><markDestinationCode>310-新A</markDestinationCode><markDestinationName>310-新A</markDestinationName></response></responseItems></responses>"; * @return */ public static Map<String, String> getDateFromEMSXML(String xml) { Map<String, String> retMap = new HashMap<String,String>(); Document document = null; try { //得到document document = DocumentHelper.parseText(xml); //得到之一个根节点 Element root = document.getRootElement(); retMap.put("success", root.element("responseItems").element("response").element("success").getText()); retMap.put("waybill_no", root.element("responseItems").element("response").element("waybill_no").getText()); retMap.put("routeCode", root.element("responseItems").element("response").element("routeCode").getText()); } catch (Exception e) { log.error("从传输报文获取数据异常:" + e); } return retMap; }二、Java Graphics2D 画出快递面单图片
邮政EMS面单设计规范,本次实现的是热敏100* 150 (单位 mm)标准快递打印效果。
这里需要注意单位毫米、像素之间的转换。因为规范说明采用毫米单位,代码中使用了像素单位。这里踩坑了。
他们之间想要实现转换,首先固定分辨率。一般快递单打印的热敏打印机分辨率是203 ,这里我就是固定203分辨率。
设计规范
邮政面单设计规格这一步利用 Java Graphics2D 绘制出来,比较返回,难度就是各种尺寸的把握。
package com.chunge.hospital.util; import java.awt.*; import java.awt.image.BufferedImage; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.util.Date; import javax.imageio.ImageIO; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.resource.ResourceUtil; import com.chunge.hospital.domain.BatOrder; import com.chunge.hospital.domain.HospitalInformation; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGEncodeParam; import com.sun.image.codec.jpeg.JPEGImageEncoder; import org.springframework.util.ResourceUtils; /** * 生成电子面单图片工具 * * @author chunge * @version 1.0 * @time 2021/08/01 */ @Slf4j public class EMSGenerateUtil { //图片的宽度 public static final int IMG_WIDTH = 799; //图片的宽度 public static final int IMG_HEIGHT = 1199; //LOGO的宽度 public static final int LOGO_WIDTH = 220; //LOGO高度 public static final int LOGO_HEIGHT = 70; //Logo路径 public static final String LOGO_PATH = "D:\\image\\ems_logo.png"; public static BufferedImage image; public static void createImage(String fileLocation) { FileOutputStream fos = null; BufferedOutputStream bos = null; try { fos = new FileOutputStream(fileLocation); bos = new BufferedOutputStream(fos); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(bos); encoder.encode(image); } catch (Exception e) { e.printStackTrace(); } finally { try { if (bos != null) bos.close(); if (fos != null) fos.close(); } catch (Exception e2) { e2.printStackTrace(); } } } /** * 插入图片 自定义图片的宽高 * * @param imgPath 插入图片的路径 * @param imgWidth 设置图片的宽度 * @param imgHeight 设置图片的高度 * @param isCompress 是否按输入的宽高定义图片的尺寸,只有为true时 输入的宽度和高度才起作用<br/> * 为false时输入的宽高不起作用,按输入图片的默认尺寸 * @return * @throws Exception */ private static Image insertImage(String imgPath, int imgWidth, int imgHeight, boolean isCompress) throws Exception { File fileimage = new File(imgPath); Image src = ImageIO.read(fileimage); if (isCompress) { Image image = src.getScaledInstance(imgWidth, imgHeight, Image.SCALE_ *** OOTH); return image; } return src; } /** * 生成 */ public static boolean generateOrder(String orderPath, BatOrder orderParam, HospitalInformation hospitalInformation, boolean isCompress, int imgWidth, int imgHeidht) { if (null == orderParam) return false; String picPath = orderPath; int startHeight = 0; //表格的起始高度 int startWidth = 0; //表格的起始宽度 try { image = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, BufferedImage.TYPE_INT_RGB); Graphics2D g = image.createGraphics(); //以运单号为名称创建存放订单的目录 File mk = new File(picPath + orderParam.getTracking_number()); if (mk.exists()) { FileUtils.deleteDirectory(mk); } FileUtils.forceMkdir(mk); //设置背景色为白色 g.setColor(Color.WHITE); //设置颜 *** 域大小 g.fillRect(0, 0, IMG_WIDTH, IMG_HEIGHT); /* * 绘制表格 填充内容 * */ //表格线条的颜色 g.setColor(Color.BLACK); //边框加粗 g.setStroke(new BasicStroke(2.0f)); //消除文本出现锯齿现象 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); //设置虚线条 Stroke bs = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{16, 4}, 0); g.setStroke(bs); //表格的四个边框 g.drawLine(startWidth + 16, startHeight + 16, startWidth + 783, startHeight + 16); //上边框 g.drawLine(startWidth + 16, startHeight + 16, startWidth + 16, startHeight + 1183); //左边框 g.drawLine(startWidth + 16, startHeight + 1183, startWidth + 783, startHeight + 1183); //下边框 g.drawLine(startWidth + 783, startHeight + 16, startWidth + 783, startHeight + 1183); //右边框 //分割线左边 //标准快递 Font fontSfTyp = new Font("黑体", Font.BOLD, 45);//Font.BOLD(加粗) g.setFont(fontSfTyp); g.drawString("标准快递", startWidth + 78, startHeight + 120); Font fontSfTyp2 = new Font("黑体", Font.BOLD, 16);//Font.BOLD(加粗) g.setFont(fontSfTyp2); g.drawString("时间:" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"), startWidth + 75, startHeight + 145); //之一行竖 分割线 g.drawLine(startWidth + 336, startHeight + 16, startWidth + 336, startHeight + 176); //右边框 //分割线右边 //生成code128a 条码 SFBarCodeGenerateUtil.generateBarCode128_a(orderParam.getTracking_number(), //运单号 picPath + orderParam.getTracking_number() + ".png", //图片名称 440, //图片宽度 100); //导入条码图片 Image sfBarImg = insertImage(picPath + orderParam.getTracking_number() + ".png", 0, 0, false); g.drawImage(sfBarImg, startWidth + 340, startHeight + 32, null); g.drawString(orderParam.getTracking_number(), startWidth + 500, startHeight + 150); //绘制表格内容 第1行 g.drawLine(startWidth + 16, startHeight + 176, startWidth + 783, startHeight + 176); //绘制表格内容 第2行 g.drawLine(startWidth + 16, startHeight + 248, startWidth + 783, startHeight + 248); g.setFont(fontSfTyp); g.drawString(orderParam.getFilePath(), startWidth + 100, startHeight + 220); Font fontSfTyp3 = new Font("黑体", Font.BOLD, 28); g.setFont(fontSfTyp3); //收: g.drawString("收:" + orderParam.getAddressName() + " " + orderParam.getAddressPhone(), startWidth + 18, startHeight + 280); if (orderParam.getAddress().length() > 22) { g.drawString(" " + orderParam.getAddress().substring(0, 22), startWidth + 18, startHeight + 310); g.drawString(" " + orderParam.getAddress().substring(22, orderParam.getAddress().length()), startWidth + 18, startHeight + 340); } else { g.drawString(" " + orderParam.getAddress().substring(0, orderParam.getAddress().length()), startWidth + 18, startHeight + 310); } //绘制表格内容 第3行 g.drawLine(startWidth + 16, startHeight + 408, startWidth + 783, startHeight + 408); //寄 Font fontSfTyp4 = new Font("黑体", Font.PLAIN, 20);//Font.PLAIN(普通) g.setFont(fontSfTyp4); //绘制表格内容 第4行 g.drawLine(startWidth + 16, startHeight + 472, startWidth + 783, startHeight + 472); g.drawString("寄:" + hospitalInformation.getHospitalName() + " " + hospitalInformation.getPhoneNumber(), startWidth + 18, startHeight + 430); String address = hospitalInformation.getProvince() + hospitalInformation.getCity() + hospitalInformation.getCounty() + hospitalInformation.getArea(); if (address.length() > 30) { g.drawString(" " + address.substring(0, 30), startWidth + 18, startHeight + 450); g.drawString(" " + address.substring(30, address.length()), startWidth + 18, startHeight + 470); } else { g.drawString(" " + address.substring(0, address.length()), startWidth + 18, startHeight + 450); } g.drawString("付款方式:", startWidth + 18, startHeight + 500); g.drawString("计费重量(KG):", startWidth + 18, startHeight + 530); g.drawString("保价金额:", startWidth + 18, startHeight + 560); //第5行竖 分割线 g.drawLine(startWidth + 464, startHeight + 472, startWidth + 464, startHeight + 583); //右边框 g.drawString("收件人\\代收人:", startWidth + 468, startHeight + 495); g.drawString("签收时间 : 年 月 日 时", startWidth + 468, startHeight + 530); Font fontSfTyp5 = new Font("黑体", Font.PLAIN, 16);//Font.PLAIN(普通) g.setFont(fontSfTyp5); g.drawString("快件送达收货人地址:经收件人或收件人允", startWidth + 468, startHeight + 560); g.drawString("许的代收人签字,视为送达", startWidth + 468, startHeight + 580); //绘制表格内容 第5行 g.drawLine(startWidth + 16, startHeight + 583, startWidth + 783, startHeight + 583); g.setFont(fontSfTyp4); g.drawString("件数: 重量(KG)", startWidth + 18, startHeight + 600); g.drawString("配货信息:物品", startWidth + 18, startHeight + 620); //绘制表格内容 第5行 g.drawLine(startWidth + 16, startHeight + 719, startWidth + 783, startHeight + 719); g.drawString("配货信息:物品", startWidth + 18, startHeight + 620); g.drawLine(startWidth + 16, startHeight + 735, startWidth + 783, startHeight + 735); //分割线右边 //生成code128a 条码 SFBarCodeGenerateUtil.generateBarCode128_a(orderParam.getTracking_number(), //运单号 picPath + orderParam.getTracking_number() + ".png", //图片名称 440, //图片宽度 60); //导入条码图片 Image sfBarImg2 = insertImage(picPath + orderParam.getTracking_number() + ".png", 0, 0, false); g.drawImage(sfBarImg2, startWidth + 20, startHeight + 750, null); g.drawString(orderParam.getTracking_number(), startWidth + 180, startHeight + 830); //插入Logo //从springboot资源目录获取获取logo图片地址: String logoPath = ResourceUtils.getFile("classpath:static/pic/ems_logo.png").getPath(); Image sublogoImg = insertImage(logoPath, LOGO_WIDTH, LOGO_HEIGHT, true); g.drawImage(sublogoImg, startWidth + 480, startHeight + 750, null); g.drawLine(startWidth + 16, startHeight + 855, startWidth + 783, startHeight + 855); g.drawString("收:" + orderParam.getAddressName() + " " + orderParam.getAddressPhone(), startWidth + 18, startHeight + 880); if (orderParam.getAddress().length() > 20) { g.drawString(" " + orderParam.getAddress().substring(0, 20), startWidth + 18, startHeight + 900); g.drawString(" " + orderParam.getAddress().substring(20, orderParam.getAddress().length()), startWidth + 18, startHeight + 920); } else { g.drawString(" " + orderParam.getAddress().substring(0, orderParam.getAddress().length()), startWidth + 18, startHeight + 900); } //竖线 g.drawLine(startWidth + 464, startHeight + 855, startWidth + 464, startHeight + 991); g.drawString("寄:" + hospitalInformation.getHospitalName(), startWidth + 468, startHeight + 880); g.drawString(" " + hospitalInformation.getPhoneNumber(), startWidth + 468, startHeight + 900); if (address.length() > 14) { g.drawString(" " + address.substring(0, 14), startWidth + 468, startHeight + 920); g.drawString(" " + address.substring(14, address.length()), startWidth + 468, startHeight + 940); } else { g.drawString(" " + address.substring(0, address.length()), startWidth + 468, startHeight + 920); } g.drawLine(startWidth + 16, startHeight + 991, startWidth + 783, startHeight + 991); g.drawString("备注:", startWidth + 18, startHeight + 1020); g.drawLine(startWidth + 16, startHeight + 1127, startWidth + 783, startHeight + 1127); g.drawString("网址:www.ems.com.cn 客服电话:11183", startWidth + 45, startHeight + 1160); g.drawLine(startWidth + 559, startHeight + 1127, startWidth + 559, startHeight + 1183); g.drawString("L", startWidth + 750, startHeight + 1170); g.dispose(); File sfbarFile = new File(picPath + orderParam.getId() + ".jpg"); if (sfbarFile.exists() && sfbarFile.isFile()) { sfbarFile.delete(); } //生成订单图片 createImage(picPath + orderParam.getId() + ".jpg"); if (isCompress) { compressImg(picPath + orderParam.getId() + ".jpg", imgWidth, imgHeidht); } log.info("订单生成成功. " + picPath + orderParam.getId() + ".jpg"); return true; } catch (Exception e) { e.printStackTrace(); } return false; } /** * 水平翻转图像 顺时针旋转90度、左右翻转 * * @param bi 目标图像 * @return */ private static BufferedImage rotate90DX(BufferedImage bi) { int width = bi.getWidth(); int height = bi.getHeight(); BufferedImage biFlip = new BufferedImage(height, width, bi.getType()); for (int i = 0; i < width; i++) for (int j = 0; j < height; j++) biFlip.setRGB(height - 1 - j, width - 1 - i, bi.getRGB(i, j)); return biFlip; } /** * 水平翻转图像 逆时针旋转90度、左右翻转 * * @param bi 目标图像 * @return */ private static BufferedImage rotate90SX(BufferedImage bi) { int width = bi.getWidth(); int height = bi.getHeight(); BufferedImage biFlip = new BufferedImage(height, width, bi.getType()); for (int i = 0; i < width; i++) for (int j = 0; j < height; j++) biFlip.setRGB(j, i, bi.getRGB(i, j)); return biFlip; } /** * 根据规定尺寸压缩图片 * @param imgPath 图片路径 * @param width 图片宽度 * @param height 图片高度 */ private static void compressImg(String imgPath, int width, int height) { /** * 设置条码图片的尺寸 * */ BufferedInputStream bis = null; BufferedOutputStream out = null; FileOutputStream fis = null; try { File sfFile = new File(imgPath); if (sfFile.isFile() && sfFile.exists()) { //读取图片 bis = new BufferedInputStream(new FileInputStream(imgPath)); //转换成图片对象 Image bi = ImageIO.read(bis).getScaledInstance(width, height, Image.SCALE_ *** OOTH); //构建图片流 设置图片宽和高 BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); //绘制改变尺寸后的图 tag.getGraphics().drawImage(bi, 0, 0, width, height, null); //保存图片 fis = new FileOutputStream(imgPath); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(fis); JPEGEncodeParam jep = JPEGCodec.getDefaultJPEGEncodeParam(tag); //设置压缩图片质量 jep.setQuality(3f, true); encoder.encode(tag, jep); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (fis != null) fis.close(); if (out != null) out.close(); if (bis != null) bis.close(); } catch (Exception e2) { e2.printStackTrace(); } } } //创建目录 private static boolean createDir(String destDirName) { try { File file = new File(destDirName); if (destDirName.endsWith(File.separator)) destDirName += File.separator; if (file.mkdir()) return true; } catch (Exception e) { e.printStackTrace(); } return false; } //删除目录 public static boolean removeDir(File dir) { File[] files = dir.listFiles(); for (File file : files) { if (file.isDirectory()) { return removeDir(file); } else { return file.delete(); } } return dir.delete(); } //删除目录 public static boolean deleteMk(String dirPath) { File dirFile = new File(dirPath); if (dirFile.isDirectory()) { File[] files = dirFile.listFiles(); for (int i = 0; i < files.length; i++) { files[i].delete(); } } return dirFile.delete(); } /** * 把文件转换为byte[] * * @param filePath 文件路径 */ public static byte[] getFileBytes(String filePath) { byte[] buffer = null; FileInputStream fis = null; ByteArrayOutputStream bos = null; try { File file = new File(filePath); fis = new FileInputStream(file); bos = new ByteArrayOutputStream(1000); byte[] b = new byte[1000]; int n; while ((n = fis.read(b)) != -1) { bos.write(b, 0, n); } buffer = bos.toByteArray(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (bos != null) { bos.close(); } if (fis != null) { fis.close(); } } catch (Exception e2) { e2.printStackTrace(); } } return buffer; } }测试打印面单图片图片:
public static void main(String[] args) { BatOrder param = new BatOrder(); param.setTracking_number("883987638272"); param.setTracking_number("883987638272"); param.setFilePath("310-新A-沙区02-沙区揽投-*"); param.setAddressName("春哥"); param.setAddressPhone("15261800000"); param.setAddress("重庆市重庆市南岸区南岸区测试大道重庆交通大学测试小区1栋00单元00"); HospitalInformation hospitalInformation = new HospitalInformation(); hospitalInformation.setHospitalName("江苏大学"); hospitalInformation.setPhoneNumber("025-91918230"); hospitalInformation.setProvince("江苏"); hospitalInformation.setCity("南京市市"); hospitalInformation.setCounty("栖霞区区"); hospitalInformation.setArea("南京仙林大学城199号"); EMSGenerateUtil.generateOrder( "D:\\12345\\", param, hospitalInformation, false, 600, 400); }打印效果:
遇到的问题以及注意事项:
问题1、
上面使用Java Graphics2D 代码可能会遇到一个问题:
程序包com.sun.image.codec.jpeg不存在
解决办法:该原因是(JPEGCodec类)在JDK1.7之后移除,使用 JDK1.8 打包时会报错
在当前工程的pom.xml文件中添加
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <!--改成自己本机maven版本号---> <version>3.8.1</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> <encoding>${project.build.sourceEncoding}</encoding> <compilerArguments> <verbose/> <bootclasspath>${java.home}/lib/rt.jar;${java.home}/lib/jce.jar</bootclasspath> </compilerArguments> </configuration> </plugin>注意2、
借鉴了别人的代码,发现一个问题,关于条形码的生成需要注意:邮政使用的是code128 A码,好像顺丰使用的是code128 C码。是不一样的。
code128编码 有3套编码:A码,B码,C码。
这里A码,我们采用的 zxing 技术
代码如下
/** * 快递单号 wayBillNo * * @param generatePathName 指定文件名 * @param wayBillNo 写入的内容 * @param width 尺寸宽 * @param height 尺寸高 */ public static void generateBarCode128_a(String wayBillNo, String generatePathName, int width, int height) { Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); // 字符集 hints.put(EncodeHintType.CHARACTER_SET, "GBK");// Constant.CHARACTER); // 容错质量 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); try { // 尺寸 BitMatrix bitMatrix = new MultiFormatWriter().encode(wayBillNo, BarcodeFormat.CODE_128, width, height, hints); BufferedOutputStream buffer = null; buffer = new BufferedOutputStream(new FileOutputStream(generatePathName)); // ok MatrixToImageWriter.writeToStream(bitMatrix, "png", new FileOutputStream(new File(generatePathName))); buffer.close(); } catch (WriterException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }到这里邮政的EMS面单图片其实就可以了,你可以直接选择打印图片。
因为兼容以前的代码,这里我们还需要面单图片转成一个PDF文件,方便前端打印,原来我们前端就是获取PDF文件打印的,减少前端前端代码的改动量。
三、面单图片生成PDF文件
我们使用Itext技术,这里我们封装成了一个工具类
package com.chunge.hospital.util; import com.itextpdf.text.*; import com.itextpdf.text.pdf.PdfWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; public class PDFUtil { public static String createPDF(String pdfPath, String imagePath) throws IOException, DocumentException { Document doc = new Document(new Rectangle(283.0F, 425.0F)); PdfWriter.getInstance(doc, new FileOutputStream(new File(pdfPath))); doc.open(); Image image = Image.getInstance(imagePath); image.setAlignment(2); image.setBorder(0); //image.setBorderWidth(2.0F); //image.setBorderColor(BaseColor.RED); float scalePercentage = (100 / 300f) * 100.0f; image.setAbsolutePosition(0, 0); //image.scalePercent(26f,31f); //image.scalePercent(26f,31f); image.scaleAbsolute(283.0f, 425.0f); // 将图像缩放到绝对宽度和绝对高度。 image.setAlignment(Element.ALIGN_CENTER); doc.add(image); doc.close(); return pdfPath; } public static void main(String[] args) { try { createPDF("C:\\bat\\yunda\\e9eae660d94d42548a675442ce1f502d\\2021-08-01\\1.pdf", "C:\\bat\\yunda\\e9eae660d94d42548a675442ce1f502d\\2021-08-01\\0020200707151336201.jpg"); } catch (IOException e) { e.printStackTrace(); } catch (DocumentException e) { e.printStackTrace(); } } }难点:注意就是图片的位置和缩放那一块,调试了很久;
生成的PDF效果:
四、页面获取PDF文件打印
<!DOCTYPE html> <html lang="zh" xmlns:th="http://www.thymeleaf.org" > <head> <th:block th:include="include :: header(打印)" /> <th:block th:include="include :: datetimepicker-css" /> <script type="text/javascript"> function print(){ var printIframe = document.getElementById("Iframe"); printIframe.contentWindow.print(); } </script> </head> <body class="white-bg"> <div style="padding:3px 5px;"><input style="border:0px;width:40px;height:20px;" onclick="print();" type="button" value="打印" /></div> <iframe id="Iframe" th:src="@{/hospital/advance_batorder/loadPdf?id=+${id}}" frameborder="0" style="width: 100%; height: 100%" > </iframe> </body> </html>打印效果:
到此,邮政EMS面单打印功能实现。码字不易。有问题私聊吧
健康食品 产品推荐 洗护测评 知识科普 牛牛说喷剂 霸王液精华液 七月七胶囊 牛鲨延时喷剂 今枪哥延时喷剂 小牛测评网 赛无双 银豹鹿鞭糖 无限神力虫草鹿血糖