基於 zxing 的二維碼生成、解析


  在很多的場景下我們需要用到二維碼,這里就通過google的zxing來對二維碼進行實現。

二維碼生成:

1.導入依賴:

<dependency>
  <groupId>com.google.zxing</groupId>
  <artifactId>core</artifactId>
  <version>2.2</version>
</dependency>
<dependency>
  <groupId>com.google.zxing</groupId>
  <artifactId>javase</artifactId>
  <version>2.2</version>
</dependency>

2.編寫二維碼工具類,用於講生成的二維碼圖片通過流的形式寫到瀏覽器,同時支持在二維碼中間添加定制圖片:

import com.google.zxing.*; import com.google.zxing.client.j2se.BufferedImageLuminanceSource; import com.google.zxing.common.BitMatrix; import com.google.zxing.common.HybridBinarizer; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletResponse; import java.awt.*; import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.Hashtable; import static org.apache.catalina.manager.Constants.CHARSET; public class RecodeUtil { private static final int WIDTH = 30; private static final int HEIGHT = 30; public static void creatRrCode(String contents, int width, int height, HttpServletResponse response) throws Exception { Hashtable hints = new Hashtable(); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); //容錯級別最高
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); //設置字符編碼
        hints.put(EncodeHintType.MARGIN, 1); //二維碼空白區域,最小為0也有白邊,只是很小,最小是6像素左右
        try { BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height, hints); // 1、讀取文件轉換為字節數組
            BufferedImage image = toBufferedImage(bitMatrix); //轉換成png格式的IO流
            ImageIO.write(image, "png", response.getOutputStream()); } catch (WriterException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * image流數據處理 */
    public static BufferedImage toBufferedImage(BitMatrix matrix) throws Exception { int width = matrix.getWidth(); int height = matrix.getHeight(); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) {//0xFF000000 0xFFFFFFFF //https://blog.csdn.net/cgwcgw_/article/details/21155229 顏色查詢
                image.setRGB(x, y, matrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF); } } insertImage(image,"D:/head.jpg",true,width,height);//調用insertImage函數插入圖片
        return image; } /** * 插入內嵌圖片 * @param source * @param imgPath 要插入圖片路徑 * @param needCompress 要插入圖片的像素是否大於60 * @throws Exception */
    private static void insertImage(BufferedImage source, String imgPath, boolean needCompress,int qrWidth,int qrHeight) throws Exception { File file = new File(imgPath); if(!file.exists()){ System.err.print(""+imgPath+"路徑不存在!"); return; } Image src = ImageIO.read(new File(imgPath)); int width = src.getWidth(null);//獲得原寬度
        int height = src.getHeight(null);//獲得源高度
        if(needCompress){//比較要插入的圖片的寬度是否大於設定的WIDTH=30像素寬
            if(width>WIDTH){ width = WIDTH; } if(height>HEIGHT){//比較要插入的圖片的高度是否大於設定的HEIGTH=30像素寬
                height = HEIGHT; } Image image = src.getScaledInstance(width, height, //把image對象的getScaledInstance方法把圖片縮小heightXwidth像素大小
 Image.SCALE_SMOOTH); BufferedImage tag = new BufferedImage(width,height,///創建一個透明色的BufferedImage對象
 BufferedImage.TYPE_INT_RGB); Graphics g = tag.getGraphics();//獲得畫筆
            g.drawImage(image, 0, 0, null);//繪制指定圖像中當前可用的image圖像,圖像的左上角位於該圖形上下文坐標(0,0)的 (x, y)
 } //開始畫內嵌圖片
        Graphics2D graph = source.createGraphics(); //計算繪畫坐標
        int x = (qrWidth-width)/2; int y = (qrHeight-height)/2; graph.drawImage(src, x, y, width, height, null);//內嵌坐標為(x,y)的地方
        Shape shape = new RoundRectangle2D.Float(x,y,width,width,6,6); graph.setStroke(new BasicStroke(3f)); graph.draw(shape); graph.dispose(); } public static String decode(File file) throws Exception { BufferedImage image; image = ImageIO.read(file); if (image == null) { return null; } BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image); BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); Result result; Hashtable hints = new Hashtable(); hints.put(DecodeHintType.CHARACTER_SET, CHARSET); result = new MultiFormatReader().decode(bitmap, hints); String resultStr = result.getText(); return resultStr; } }

3.提供請求控制器:

@RestController public class QRCodeController { @GetMapping("/qrcode") public void qrcode(HttpServletRequest request, HttpServletResponse response) throws Exception { String content = "你是豬"; long l = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli(); content += String.valueOf(l); if (StringUtils.isBlank(content)) { System.out.println("404"); return; } //調用工具類,生成二維碼
        RecodeUtil.creatRrCode(content, 180, 180, response);   //180為圖片高度和寬度
 } @PostMapping("/qrcode/parse") public void read(MultipartFile file) throws Exception { File toFile = null; InputStream ins = null; ins = file.getInputStream(); toFile = new File(file.getOriginalFilename()); inputStreamToFile(ins, toFile); ins.close(); RecodeUtil.decode(toFile); } //獲取流文件
    private static void inputStreamToFile(InputStream ins, File file) { try { OutputStream os = new FileOutputStream(file); int bytesRead = 0; byte[] buffer = new byte[8192]; while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) { os.write(buffer, 0, bytesRead); } os.close(); ins.close(); } catch (Exception e) { e.printStackTrace(); } } }

4.通過以上的代碼就完成了后端代碼的編寫,接下去看一下前端代碼。我前端代碼基於  Vue 。:

// ......省略代碼 <button v-on:click="qrcode">二維碼</button><br/>
<img :src = "qrcodeImage" >
<img src = "http://localhost:8889/qrcode" > export default { name: 'HelloWorld', data () { return { qrcodeImage: '' } }, methods: { qrcode: function () { this.qrcodeImage = null this.$axios({ method: 'get', url: '/api/qrcode', responseType: 'arraybuffer' }).then(function (res) { return 'data:image/png;base64,' + btoa( new Uint8Array(res.data) .reduce((data, byte) => data + String.fromCharCode(byte), '') ) }).then(data => { this.qrcodeImage = data }).catch(function (err) { alert(err) }) } }

5.啟動項目,不點擊二維碼按鈕的時候只有一個固定不變的二維碼。當點擊二維碼按鈕可以看到一下效果:

  這樣子就可以實現我們的二維碼。

二維碼解析:

  二維碼解析可以通過調用上述 /qrcode/parse 接口,這里采用 postman作為演示,我們先將上面得到的二維碼截圖保存:

  然后就可以得到二維碼的內容了。解析的代碼上面也已經給出。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM