在开发二维码打印的过程中走过几次弯路,所以在这里特意将其记录下来留作备忘。一开始参考其他博主写的文章,有介绍通过编写JAVA后台代码来获取本地默认打印机的驱动实现打印。BUT!这样就导致在本地开发测试时看似一切正常,一旦项目部署到linux环境下,就会完全失效了(JAVA后台代码去获取linux本地的打印机驱动)。还有介绍并提供编写的插件的(不甚了解这块),鉴于时间要求比较苛刻,那就简单的来吧。
需求:生成带水印效果的二维码图片,可以批量预览,并连接打印机批量打印。
开发思路:
1.编写二维码生成工具类,实现二维码图片的生成
2.提供二维码打印前的预览
3.通过隐藏的iframe实现打印(简单粗暴)
以下是自己编写的一个小案例,可以直接运行测试,并提供了code下载。如果有其它更好的实现方式,也希望大家多提出宝贵的意见。
一、项目结构
-
二、主要CODE
1.MyQRUtils.java 二维码工具类
1 package com.webprint.qr.tools; 2 3 import java.awt.Color; 4 import java.awt.Font; 5 import java.awt.Graphics2D; 6 import java.awt.image.BufferedImage; 7 import java.io.File; 8 import java.io.IOException; 9 import java.io.OutputStream; 10 import java.util.Hashtable; 11 12 import javax.imageio.ImageIO; 13 14 import org.apache.commons.logging.Log; 15 import org.apache.commons.logging.LogFactory; 16 17 import com.google.zxing.BarcodeFormat; 18 import com.google.zxing.EncodeHintType; 19 import com.google.zxing.MultiFormatWriter; 20 import com.google.zxing.WriterException; 21 import com.google.zxing.common.BitMatrix; 22 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; 23 24 public class MyQRUtils{ 25 26 private static final Log logger = LogFactory.getLog(MyQRUtils.class); 27 28 private static final int BLACK = 0xFF000000; 29 private static final int WHITE = 0xFFFFFFFF; 30 private static final int LogoPart = 4; 31 32 /** 33 * 生成二维码前的配置信息 34 * @param content 生成二维码图片内容 35 * @param width 二维码图片的宽度 36 * @param height 二维码图片的高度 37 * @return 38 */ 39 public static BitMatrix setBitMatrix(String content,int width,int height){ 40 Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); 41 hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 42 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); //指定纠错等级 43 BitMatrix bitMatrix=null; 44 try { 45 bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints); 46 } catch (WriterException e) { 47 logger.error("生成二维码错误",e); 48 } 49 return bitMatrix; 50 } 51 52 /** 53 * 将LOGO图片放在二维码中间(水印效果) 54 * 将生成的图片以流的形式输出到页面展示 55 * @param matrix BitMatrix 56 * @param format 图片格式 57 * @param outStream 输出流 58 * @param logoPath LOGO地址 59 * @param showBottomText 二维码图片底部需要显示的问题 60 * @throws IOException 61 */ 62 public static void megerToFile(BitMatrix matrix,String format,OutputStream outStream,String logoPath,String showBottomText) throws IOException { 63 BufferedImage image = toBufferedImage(matrix); 64 Graphics2D gs = image.createGraphics(); 65 66 //1.加入LOGO水印效果 67 if(null != logoPath && !"".equals(logoPath)){ 68 //1.1 载入LOGO图片 69 BufferedImage logoImg = ImageIO.read(new File(logoPath)); 70 //1.2 考虑到LOGO图片贴到二维码中,建议大小不要超过二维码的1/5; 71 int width = image.getWidth() / LogoPart; 72 int height = image.getHeight() / LogoPart; 73 //1.3 LOGO居中显示 74 int x = (image.getWidth() - width) / 2; 75 int y = (image.getHeight() - height) / 2; 76 gs.drawImage(logoImg, x, y, logoImg.getWidth(), logoImg.getHeight(), null); 77 logoImg.flush(); 78 } 79 //2.二维码图片底部插入文字 80 if(null != showBottomText && !"".equals(showBottomText)){ 81 //2.1 设置字体样式 82 Font font = new Font("微软雅黑", Font.PLAIN, 14); 83 gs.setColor(Color.BLACK); 84 gs.setFont(font); 85 //2.2 字体显示位置 86 int x = (image.getWidth() - getWatermarkLength(showBottomText, gs))/2; 87 int y = image.getHeight()-2; 88 gs.drawString(showBottomText, x, y); 89 } 90 gs.dispose(); 91 ImageIO.write(image, format, outStream); 92 } 93 94 /** 95 * 将LOGO图片放在二维码中间(水印效果) 96 * 将生成的图片生成到本地硬盘路径下 97 * @param matrix BitMatrix 98 * @param format 图片格式 99 * @param imagePath 图片存放路径 100 * @param logoPath LOGO地址 101 * @param showBottomText 二维码图片底部需要显示的问题 102 * @throws IOException 103 */ 104 public static void megerToFile2(BitMatrix matrix,String format,String imagePath,String logoPath,String showBottomText) throws IOException { 105 BufferedImage image = toBufferedImage(matrix); 106 Graphics2D gs = image.createGraphics(); 107 108 //1.加入LOGO水印效果 109 if(null != logoPath && !"".equals(logoPath)){ 110 BufferedImage logoImg = ImageIO.read(new File(logoPath)); 111 int width = image.getWidth() / LogoPart; 112 int height = image.getHeight() / LogoPart; 113 int x = (image.getWidth() - width) / 2; 114 int y = (image.getHeight() - height) / 2; 115 gs.drawImage(logoImg, x, y, logoImg.getWidth(), logoImg.getHeight(), null); 116 logoImg.flush(); 117 } 118 119 //2.二维码图片底部插入文字 120 if(null != showBottomText && !"".equals(showBottomText)){ 121 //2.1 设置字体样式 122 Font font = new Font("微软雅黑", Font.PLAIN, 14); 123 gs.setColor(Color.BLACK); 124 gs.setFont(font); 125 //2.2 字体显示位置 126 int x = (image.getWidth() - getWatermarkLength(showBottomText, gs))/2; 127 int y = image.getHeight()-2; 128 gs.drawString(showBottomText, x, y); 129 } 130 gs.dispose(); 131 ImageIO.write(image, format, new File(imagePath)); 132 } 133 134 /** 135 * 获取水印字体的长度 136 * @param fontString 137 * @param gs 138 * @return 139 */ 140 public static int getWatermarkLength(String fontString,Graphics2D gs){ 141 return gs.getFontMetrics(gs.getFont()).charsWidth(fontString.toCharArray(),0,fontString.length()); 142 } 143 144 public static BufferedImage toBufferedImage(BitMatrix matrix){ 145 int width = matrix.getWidth(); 146 int height = matrix.getHeight(); 147 BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR); 148 149 for(int x=0;x<width;x++){ 150 for(int y=0;y<height;y++){ 151 image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE); 152 } 153 } 154 return image; 155 } 156 }
说明:二维码实现方式有多种,此处代码可根据具体需求具体开发。
2.WebPrintController.java SpringMVC的controller层代码
1 package com.webprint.qr.controller; 2 3 import java.io.IOException; 4 import java.io.OutputStream; 5 import java.util.ArrayList; 6 import java.util.HashMap; 7 import java.util.List; 8 import java.util.Map; 9 10 import javax.servlet.http.HttpServletRequest; 11 import javax.servlet.http.HttpServletResponse; 12 13 import org.apache.commons.logging.Log; 14 import org.apache.commons.logging.LogFactory; 15 import org.springframework.stereotype.Controller; 16 import org.springframework.ui.Model; 17 import org.springframework.web.bind.annotation.RequestMapping; 18 19 import com.google.zxing.common.BitMatrix; 20 import com.webprint.qr.tools.MyQRUtils; 21 22 @Controller("WebPrintController") 23 @RequestMapping("/qrPrint") 24 public class WebPrintController { 25 26 private static final Log logger = LogFactory.getLog(MyQRUtils.class); 27 28 /** 29 * 二维码预览页面 30 * @param model 31 * @return 32 */ 33 @RequestMapping("/showList.do") 34 public String showQRList(Model model){ 35 //模拟获取数据库数据 36 List listData = new ArrayList(); 37 StringBuffer ids = new StringBuffer(); 38 String code = "print00"; 39 for (int i = 0; i < 3; i++) { 40 Map<String,String> map = new HashMap<String,String>(); //模拟VO 41 map.put("id",code+""+i); 42 ids.append(code+""+i).append(","); 43 listData.add(map); 44 } 45 model.addAttribute("showListData", listData); 46 model.addAttribute("ids", ids); 47 return "showQR"; 48 } 49 50 /** 51 * 二维码打印页面 52 * 隐藏在iframe中 53 * @param model 54 * @return 55 */ 56 @RequestMapping("/printEWM.do") 57 public String printQRFrame(Model model,HttpServletRequest request){ 58 String ids = request.getParameter("ids"); 59 model.addAttribute("ids", ids); 60 return "printFrameQR"; 61 } 62 63 /** 64 * 显示二维码图片 65 * @param request 66 * @param response 67 * @throws Exception 68 */ 69 @RequestMapping("/showEWMImage.do") 70 public void showImageByType(HttpServletRequest request,HttpServletResponse response){ 71 String id = request.getParameter("showID"); //ID 72 73 //此处可从数据库中获取内容 74 String content ="打印二维码\n打印测试\nID:"+id; 75 76 OutputStream outStream = null; 77 try { 78 outStream = response.getOutputStream(); 79 String format = "jpg"; 80 String bottomText = "一路不停"; //水印文字 81 82 BitMatrix bitMatrix = MyQRUtils.setBitMatrix(content, 180 , 180); 83 //暂时不使用LOGO图片 84 MyQRUtils.megerToFile(bitMatrix, format, outStream, null,bottomText); 85 86 } catch (Exception e) { 87 logger.error("二维码生成失败", e); 88 }finally{ 89 try { 90 if(outStream!=null){ 91 outStream.flush(); 92 outStream.close(); 93 } 94 } catch (IOException e) { 95 logger.error("关闭数据流失败", e); 96 } 97 98 } 99 } 100 101 102 }
说明:二维码图片的展示及其打印以流的方式操作,这样就无需将图片保存在服务器上了。
3.index.jsp 首页
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 3 <html> 4 <head> 5 <meta http-equiv="pragma" content="no-cache"> 6 <meta http-equiv="cache-control" content="no-cache"> 7 <meta http-equiv="expires" content="0"> 8 <%@include file="/include.jsp" %> 9 <title></title> 10 </head> 11 <iframe id="iframePrintEWM" frameborder="0" width="0" height="0"></iframe> 12 <body> 13 <div> 1.二维码预览</br> 14 2.二维码打印 15 </div></br> 16 </br></br> 17 <hr> 18 </br> 19 <input type="button" id ="showQRList" name="showQRList" value="二维码预览" onclick="showQRList()"/> 20 <div id=‘divDialog‘></div> 21 <div id=‘divPrintDialog‘></div> 22 </body> 23 <script type="text/javascript"> 24 var height = $("body").height(); 25 var width = $("body").width(); 26 27 //二维码预览 28 function showQRList(){ 29 var url ="${rootPath}/qrPrint/showList.do"; 30 $("#divDialog").dialog({ 31 title:"预览", 32 width:260, 33 height:500, 34 top:(height-500)/2, 35 left:(width-260)/2, 36 href:url, 37 cache:false, 38 closed:false, 39 modal:true 40 }); 41 } 42 43 //二维码打印 44 function printEWM(ids){ 45 $(‘#divDialog‘).window(‘close‘); 46 var url = ‘${rootPath}/qrPrint/printEWM.do?ids=‘+ids; 47 $(‘#iframePrintEWM‘).attr("src", url); 48 } 49 </script> 50 </html>
说明:将iframe放在body标签外,并将其宽高和border都设置为0,达到隐藏的效果。
4.showQR.jsp 二维码预览页
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <html> 3 <head> 4 <%@include file="/include.jsp" %> 5 <title>showQRList</title> 6 </head> 7 <body> 8 <div > 9 <div align="left" > 10 <a href="javascript:printEWM(‘${ids }‘);" class="easyui-linkbutton" iconCls="icon-printer" style="width: 95px">二维码打印</a> 11 </div> 12 </div> 13 <div> 14 <c:forEach var="printID" items="${showListData}" varStatus="lis"> 15 <table align="center" class="codetable" cellpadding="0" style="float: left;border:1px solid #333333;"> 16 <tr> 17 <td align="center"> 18 <div id="bcTarget${lis.index }"> 19 <img src="${rootPath}/qrPrint/showEWMImage.do?showID=${printID.id}"> 20 </div> 21 </td> 22 </tr> 23 </table> 24 </c:forEach> 25 </div> 26 </body> 27 </html>
说明:如果项目中不需要自定义预览,此处代码可以去掉。
5.printFrameQR.jsp 隐藏的iframe页,用于打印(非常简单,非常强大)
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <html> 3 <head> 4 <%@include file="/include.jsp" %> 5 <title>printFrameQR</title> 6 </head> 7 <body > 8 <div> 9 <c:forEach var="printID" items="${ids}" varStatus="lis"> 10 <div id="bcTarget${lis.index }"> 11 <img src="${rootPath}/qrPrint/showEWMImage.do?showID=${printID}"> 12 </div></br> 13 </c:forEach> 14 </div> 15 </body> 16 </html>
说明:简单粗暴的方式,打印的关键就在于body标签中的
三、预览效果
注意对IE打印页面的设置;
四、code下载部署说明
以上是周末自己编写的小案例,供大家参考。
环境:myeclipse8.5 + tomcat6 + jdk7 +jQuery EasyUI + core-3.3.0.jar(google zxing)
地址:http://download.csdn.net/detail/onepersontz/9794722
原文地址:https://www.cnblogs.com/c2013/p/10249200.html