SpringBoot+zxing+Vue实现前端请求后台二维码图片
場景
ZXing是一個開源的,用Java實現的多種格式的1D/2D條碼圖像處理庫。
github地址:
https://github.com/zxing/zxing
若依微服務版手把手教你本地搭建環境并運行前后端項目:
https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/109363303
在上面搭建起來SpringBoot+Vue的前后端分離的項目的基礎上,要實現前端點擊按鈕請求后臺,
后臺將需要的內容,比如是最新版的app下載地址等生成二維碼,然后返回給前端,前端顯示的效果。
注:
博客:
https://blog.csdn.net/badao_liumang_qizhi
關注公眾號
霸道的程序猿
獲取編程相關電子書、教程推送與免費下載。
實現
SpringBoot后臺
首選在項目的pom.xml中引入xing的依賴
??????? <!-- zxing生成二維碼 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.3.3</version></dependency><dependency><groupId>com.google.zxing</groupId><artifactId>javase</artifactId><version>3.3.3</version></dependency>然后新鍵一個生成二維碼的工具類QRCodeUtil
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 lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component;import javax.imageio.ImageIO; import javax.swing.filechooser.FileSystemView; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.net.URL; import java.util.*;@Component @Slf4j public class QRCodeUtil {private static final Logger log = LoggerFactory.getLogger(QRCodeUtil.class);/*** CODE_WIDTH:二維碼寬度,單位像素* CODE_HEIGHT:二維碼高度,單位像素* FRONT_COLOR:二維碼前景色,0x000000 表示黑色* BACKGROUND_COLOR:二維碼背景色,0xFFFFFF 表示白色* 演示用 16 進制表示,和前端頁面 CSS 的取色是一樣的,注意前后景顏色應該對比明顯,如常見的黑白*/private static final int CODE_WIDTH = 400;private static final int CODE_HEIGHT = 400;private static final int FRONT_COLOR = 0x000000;private static final int BACKGROUND_COLOR = 0xFFFFFF;/*** @param codeContent??????? 二維碼參數內容,如果是一個網頁地址,如 https://www.baidu.com/ 則 微信掃一掃會直接進入此地址, 如果是一些參數,如*?????????????????????????? 1541656080837,則微信掃一掃會直接回顯這些參數值* @param codeImgFileSaveDir 二維碼圖片保存的目錄,如 D:/codes* @param fileName?????????? 二維碼圖片文件名稱,帶格式,如 123.png*/public static void createCodeToFile(String codeContent, File codeImgFileSaveDir, String fileName) {try {if (codeContent == null || "".equals(codeContent)) {log.info("二維碼內容為空,不進行操作...");return;}codeContent = codeContent.trim();if (codeImgFileSaveDir == null || codeImgFileSaveDir.isFile()) {codeImgFileSaveDir = FileSystemView.getFileSystemView().getHomeDirectory();log.info("二維碼圖片存在目錄為空,默認放在桌面...");}if (!codeImgFileSaveDir.exists()) {codeImgFileSaveDir.mkdirs();log.info("二維碼圖片存在目錄不存在,開始創建...");}if (fileName == null || "".equals(fileName)) {fileName = new Date().getTime() + ".png";log.info("二維碼圖片文件名為空,隨機生成 png 格式圖片...");}BufferedImage bufferedImage = getBufferedImage(codeContent);/** javax.imageio.ImageIO:java擴展的圖像IO* write(RenderedImage im, String formatName, File output)*?????? im:待寫入的圖像, formatName:圖像寫入的格式,output:寫入的圖像文件,文件不存在時會自動創建*/File codeImgFile = new File(codeImgFileSaveDir, fileName);ImageIO.write(bufferedImage, "png", codeImgFile);log.info("二維碼圖片生成成功:" + codeImgFile.getPath());} catch (Exception e) {e.printStackTrace();}}/*** 生成二維碼并輸出到輸出流, 通常用于輸出到網頁上進行顯示* 輸出到網頁與輸出到磁盤上的文件中,區別在于最后一句 ImageIO.write* write(RenderedImage im,String formatName,File output):寫到文件中* write(RenderedImage im,String formatName,OutputStream output):輸出到輸出流中** @param codeContent? :二維碼內容* @param outputStream :輸出流,比如 HttpServletResponse 的 getOutputStream*/public static void createCodeToOutputStream(String codeContent, OutputStream outputStream) {try {if (codeContent == null || "".equals(codeContent.trim())) {log.info("二維碼內容為空,不進行操作...");return;}codeContent = codeContent.trim();BufferedImage bufferedImage = getBufferedImage(codeContent);/** 區別就是以一句,輸出到輸出流中,如果第三個參數是 File,則輸出到文件中*/ImageIO.write(bufferedImage, "png", outputStream);log.info("二維碼圖片生成到輸出流成功...");} catch (Exception e) {e.printStackTrace();log.error("發生錯誤: {}!", e.getMessage());}}private static BufferedImage getBufferedImage(String codeContent) throws WriterException {/** com.google.zxing.EncodeHintType:編碼提示類型,枚舉類型* EncodeHintType.CHARACTER_SET:設置字符編碼類型* EncodeHintType.ERROR_CORRECTION:設置誤差校正* ErrorCorrectionLevel:誤差校正等級,L = ~7% correction、M = ~15% correction、Q = ~25% correction、H = ~30% correction*?? 不設置時,默認為 L 等級,等級不一樣,生成的圖案不同,但掃描的結果是一樣的* EncodeHintType.MARGIN:設置二維碼邊距,單位像素,值越小,二維碼距離四周越近*/Map<EncodeHintType, Object> hints = new HashMap();hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);hints.put(EncodeHintType.MARGIN, 1);/** MultiFormatWriter:多格式寫入,這是一個工廠類,里面重載了兩個 encode 方法,用于寫入條形碼或二維碼*????? encode(String contents,BarcodeFormat format,int width, int height,Map<EncodeHintType,?> hints)*????? contents:條形碼/二維碼內容*????? format:編碼類型,如 條形碼,二維碼 等*????? width:碼的寬度*????? height:碼的高度*????? hints:碼內容的編碼類型* BarcodeFormat:枚舉該程序包已知的條形碼格式,即創建何種碼,如 1 維的條形碼,2 維的二維碼 等* BitMatrix:位(比特)矩陣或叫2D矩陣,也就是需要的二維碼*/MultiFormatWriter multiFormatWriter = new MultiFormatWriter();BitMatrix bitMatrix = multiFormatWriter.encode(codeContent, BarcodeFormat.QR_CODE, CODE_WIDTH, CODE_HEIGHT, hints);/** java.awt.image.BufferedImage:具有圖像數據的可訪問緩沖圖像,實現了 RenderedImage 接口* BitMatrix 的 get(int x, int y) 獲取比特矩陣內容,指定位置有值,則返回true,將其設置為前景色,否則設置為背景色* BufferedImage 的 setRGB(int x, int y, int rgb) 方法設置圖像像素*????? x:像素位置的橫坐標,即列*????? y:像素位置的縱坐標,即行*????? rgb:像素的值,采用 16 進制,如 0xFFFFFF 白色*/BufferedImage bufferedImage = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_INT_BGR);for (int x = 0; x < CODE_WIDTH; x++) {for (int y = 0; y < CODE_HEIGHT; y++) {bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? FRONT_COLOR : BACKGROUND_COLOR);}}return bufferedImage;}/*** 根據本地二維碼圖片解析二維碼內容 注:圖片必須是二維碼圖片,但也可以是微信用戶二維碼名片,上面有名稱、頭像也是可以的)** @param file 本地二維碼圖片文件,如 E:\\logs\\2.jpg* @return* @throws Exception*/public static String parseQRCodeByFile(File file) {String resultStr = null;if (file == null || file.isDirectory() || !file.exists()) {return resultStr;}try {/** ImageIO的BufferedImage read(URL input)方法用于讀取網絡圖片文件轉為內存緩沖圖像* 同理還有:read(File input)、read(InputStream input)、、read(ImageInputStream stream)*/BufferedImage bufferedImage = ImageIO.read(file);/** com.google.zxing.client.j2se.BufferedImageLuminanceSource:緩沖圖像亮度源* 將 java.awt.image.BufferedImage 轉為 zxing 的 緩沖圖像亮度源* 關鍵就是下面這幾句:HybridBinarizer 用于讀取二維碼圖像數據,BinaryBitmap 二進制位圖*/BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(bufferedImage);BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));Hashtable hints = new Hashtable();hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");/** 如果圖片不是二維碼圖片,則 decode 拋異常:com.google.zxing.NotFoundException* MultiFormatWriter 的 encode 用于對內容進行編碼成 2D 矩陣* MultiFormatReader 的 decode 用于讀取二進制位圖數據*/Result result = new MultiFormatReader().decode(bitmap, hints);resultStr = result.getText();} catch (IOException e) {e.printStackTrace();} catch (NotFoundException e) {e.printStackTrace();log.error("圖片非二維碼圖片, 路徑是: {}!", file.getPath());}return resultStr;}/*** 根據網絡二維碼圖片解析二維碼內容, 區別僅僅在于 ImageIO.read(url); 這一個重載的方法)** @param url 二維碼圖片網絡地址,如 https://res.wx.qq.com/mpres/htmledition/images/mp_qrcode3a7b38.gif* @return* @throws Exception*/public static String parseQRCodeByUrl(URL url) {String resultStr = null;if (url == null) {return resultStr;}try {/** ImageIO 的 BufferedImage read(URL input) 方法用于讀取網絡圖片文件轉為內存緩沖圖像* 同理還有:read(File input)、read(InputStream input)、、read(ImageInputStream stream)* 如果圖片網絡地址錯誤,比如不能訪問,則 read 拋異常:javax.imageio.IIOException: Can't get input stream from URL!*/BufferedImage bufferedImage = ImageIO.read(url);/** com.google.zxing.client.j2se.BufferedImageLuminanceSource:緩沖圖像亮度源* 將 java.awt.image.BufferedImage 轉為 zxing 的 緩沖圖像亮度源* 關鍵就是下面這幾句:HybridBinarizer 用于讀取二維碼圖像數據,BinaryBitmap 二進制位圖*/BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(bufferedImage);BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));Hashtable hints = new Hashtable();/** 如果內容包含中文,則解碼的字符集格式應該和編碼時一致*/hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");/** 如果圖片不是二維碼圖片,則 decode 拋異常:com.google.zxing.NotFoundException* MultiFormatWriter 的 encode 用于對內容進行編碼成 2D 矩陣* MultiFormatReader 的 decode 用于讀取二進制位圖數據*/Result result = new MultiFormatReader().decode(bitmap, hints);resultStr = result.getText();} catch (IOException e) {e.printStackTrace();log.error("二維碼圖片地址錯誤, 地址是: {}!", url);} catch (NotFoundException e) {e.printStackTrace();log.error("圖片非二維碼圖片, 地址是: {}!", url);}return resultStr;}private static final int QRCOLOR = 0xFF000000; // 默認是黑色private static final int BGWHITE = 0xFFFFFFFF; // 背景顏色private static final int WIDTH = 400; // 二維碼寬private static final int HEIGHT = 400; // 二維碼高// 用于設置QR二維碼參數private static Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>() {private static final long serialVersionUID = 1L;{put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);// 設置QR二維碼的糾錯級別(H為最高級別)具體級別信息put(EncodeHintType.CHARACTER_SET, "utf-8");// 設置編碼方式}};// 生成帶logo的二維碼圖片public static void drawLogoQRCode(File logoFile, OutputStream outputStream, String qrUrl) {try {MultiFormatWriter multiFormatWriter = new MultiFormatWriter();// 參數順序分別為:編碼內容,編碼類型,生成圖片寬度,生成圖片高度,設置參數BitMatrix bm = multiFormatWriter.encode(qrUrl, BarcodeFormat.QR_CODE, WIDTH, HEIGHT, hints);BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);// 開始利用二維碼數據創建Bitmap圖片,分別設為黑(0xFFFFFFFF)白(0xFF000000)兩色for (int x = 0; x < WIDTH; x++) {for (int y = 0; y < HEIGHT; y++) {image.setRGB(x, y, bm.get(x, y) ? QRCOLOR : BGWHITE);}}int width = image.getWidth();int height = image.getHeight();if (Objects.nonNull(logoFile) && logoFile.exists()) {// 構建繪圖對象Graphics2D g = image.createGraphics();// 讀取Logo圖片BufferedImage logo = ImageIO.read(logoFile);// 開始繪制logo圖片g.drawImage(logo, width * 2 / 5, height * 2 / 5, width * 2 / 10, height * 2 / 10, null);g.dispose();logo.flush();}image.flush();/** 區別就是以一句,輸出到輸出流中,如果第三個參數是 File,則輸出到文件中*/ImageIO.write(image, "png", outputStream);} catch (Exception e) {e.printStackTrace();}} }然后新建一個Controller,再新建一個接口方法
??? @GetMapping("/qrcode")public void getQRCode(HttpServletResponse response) throws Exception {SysAppVersion sysAppVersion = appVersionService.getLast();String downloadpath = sysAppVersion.getDownloadLink();/*下載路徑*/try {/** 調用工具類生成二維碼并輸出到輸出流中*/QRCodeUtil.createCodeToOutputStream(downloadpath, response.getOutputStream());log.info("成功生成二維碼!");} catch (IOException e) {log.error("發生錯誤, 錯誤信息是:{}!", e.getMessage());}}在接口方法中將要在二維碼顯示的內容調用QRCodeUtil.createCodeToOutputStream設置,這個方法將二維碼輸出到輸出流。
方法說明:
生成二維碼并輸出到輸出流, 通常用于輸出到網頁上進行顯示
輸出到網頁與輸出到磁盤上的文件中,區別在于最后一句 ImageIO.write
write(RenderedImage im,String formatName,File output):寫到文件中
write(RenderedImage im,String formatName,OutputStream output):輸出到輸出流中
這個工具類除了生成普通的二維碼,還可以生成帶log的二維碼,具體看工具類的方法說明。
前端Vue
在頁面上新增一個彈窗,彈窗里面用el-image控件來顯示圖片,默認此彈窗是隱藏
????? <el-dialogtitle="請掃描二維碼下載"width="15%":visible.sync="dialogVisible":before-close="handleClose"><el-imagestyle="width: 150px; height: 150px":src="fitUrl":fit="fit"></el-image></el-dialog>需要提前聲明這些屬性
? data() {return {//返回的文件urlfileUrl: "",dialogVisible:false,};然后頁面新增一個按鈕
??????? <el-buttontype="primary"icon="el-icon-download"size="mini"@click="downApp">app下載</el-button>按鈕的點擊事件downApp中
??? downApp(){downAppImage().then((val) => {const src=window.URL.createObjectURL(val)this.fitUrl=src;this.dialogVisible=true;})}調用了downAppImage方法,并獲取其響應值val,然后通過window.URL.createObjectURL(val)
獲取圖片預覽地址,并將其賦值給el-image的圖片數據源變量fitUrl,然后讓窗口顯示。
其中downAppImage是通過
import { downAppImage } from "@/api/tool/edition.js";引入的js的方法
??? export function downAppImage(){return request({url: '/download/qrcode',method:'get',responseType:"blob"})}這個方法會去調用前面SpringBoot的后臺接口,注意這里的響應類型為blob
然后window.URL.createObjectURL說明:
URL.createObjectURL() 靜態方法會創建一個 DOMString,其中包含一個表示參數中給出的對象的URL。這個 URL 的生命周期和創建它的窗口中的 document 綁定。這個新的URL 對象表示指定的 File 對象或 Blob 對象。
效果
調用后臺接口,后臺會生成二維碼圖片的響應流
?
然后前端調用接口
?
調用window.URL.createObjectURL(val)后
?
總結
以上是生活随笔為你收集整理的SpringBoot+zxing+Vue实现前端请求后台二维码图片的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java中对接钉钉API获取数据流程
- 下一篇: Vue中集成高德地图API实现定位与自定