不知道從什麼時候開始,我們的生活突然之間就充滿了二維碼,連街邊大媽的雞蛋餅早餐攤也貼上了二維碼。而且這次疫情的管控也用上了二維碼,避免手工填寫造成交叉感染。那麼 Java 如何開發二維碼功能呢?今天來簡單探討一下。歡迎加入微信圈子程式設計師交流圈 交流編程經驗,歡迎投稿。
2. 關於二維碼作為開發者我們肯定會想到二維碼是將內容編碼成了二維碼的圖案。對於其原理我們並不需要知道,就是一個編碼和解碼的過程。但是我們開發中還是需要知道了解一些關於二維碼的東西:
完全相同的二維碼在算法一致的前提下內容完全相同,反之不成立。內容越多二維碼越複雜,這可以從二維碼的圖像上肉眼可見。意味著解碼就越耗時。二維碼有容錯率,容錯率越高意味著二維碼包含的信息量越大。根據以上的幾點,我們在開發中根據實際情況來作出一些調整,後面會來講一下我自己的經驗。
3. Java 實現二維碼的生成通常我們使用 Google 開源的 1D/2D 條碼圖像處理庫 ZXing 來實現。我們可以通過引入其依賴來集成二維碼生成功能:
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.4.0</version>
</dependency>然後我們可以通過下面短短幾行代碼就生成了一個二維碼並將其保存到本地:
QRCodeWriter qrCodeWriter = new QRCodeWriter();
# 第一個參數為二維碼的內容 第二個參數不變 第三 四 個參數依次為 寬高
BitMatrix bitMatrix = qrCodeWriter.encode("https://www.felord.cn", BarcodeFormat.QR_CODE, 30, 30);
# 將二維碼保存為 png 本地圖片。
MatrixToImageWriter.writeToPath(encode, "png", Paths.get("E:\\workbase\\qr.png"));如果你要控制編碼的字符集和糾錯率,上面的代碼可更改為:
QRCodeWriter qrCodeWriter = new QRCodeWriter();
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.CHARACTER_SET,"UTF-8");
BitMatrix bitMatrix = qrCodeWriter.encode("https://www.felord.cn", BarcodeFormat.QR_CODE, 80, 80,hints);
# 將二維碼保存為 png 本地圖片。
MatrixToImageWriter.writeToPath(encode, "png", Paths.get("E:\\workbase\\qr.png"));其實 MatrixToImageWriter 不但提供將二維碼保存為文件,還可以轉化為流:
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
MatrixToImageWriter.writeToStream(bitMatrix,"png",byteArrayOutputStream);
byte[] bytes = byteArrayOutputStream.toByteArray();
String base64Image = new BASE64Encoder().encode(bytes);生成的 base64Image 我們可以在前端通過以下方式進行展示:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQAQAAAACmas8AAAAAvklEQVR42tXSsRGDMAwFUKWxV0jl
rGY39gpOg6BxVoDGWQ0aewVorOQOzgeCARJVr9G/rzsB1YEfZgHh5QjIiPn1zoVTu6SsOLPIdMEh
2BMxJ1lzK0FYq4GRqJgWt76V5e665Na1HQ1F09/oSIpu6qaIRxaztG5pOZXrmy1sRzPjqJ7EKIQ2
Ye27o8clD4ETJxrB0JHfg7xqOAvIrtgGGTFH3XhObS3ABTHn+UQXXAROTI88a04QGB6R8Q9e+QOH
lnNzjaH0oAAAAABJRU5ErkJggg==" alt="">Base64 展示體積小的二維碼是沒有問題的,如果生成的 Base64 字符串比較長將會有較大的渲染消耗。實際生產中要權衡利弊。
4. 動態二維碼如果我們需要動態的來生成二維碼,或者換句話來說將二維碼作為服務。我們可以藉助於 Servlet 來實現一個動態的二維碼服務。我們使用 Spring MVC 來實現:
package cn.felord.qr.format;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* @author dax
* @since 2020/2/29 21:09
*/
@Controller
@RequestMapping("/qr")
public class QRController {
@GetMapping("/felord")
public void gen(HttpServletResponse response) throws IOException, WriterException {
response.setContentType("image/png");
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(imageBytes());
outputStream.flush();
outputStream.close();
}
private byte [] imageBytes() throws IOException, WriterException {
QRCodeWriter qrCodeWriter = new QRCodeWriter();
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.CHARACTER_SET,"UTF-8");
BitMatrix bitMatrix = qrCodeWriter.encode("https://www.felord.cn", BarcodeFormat.QR_CODE, 80, 80,hints);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
MatrixToImageWriter.writeToStream(bitMatrix,"png",byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
}
5. 一些實踐中的經驗在實際生產中我們要注意以下幾點:
儘量避免在二維碼中傳遞敏感的明文信息,應對其進行摘要處理或者脫敏。對於比較長的網址應該使用短網址服務以減少二維碼的信息載荷。儘量保證二維碼一定時間內的唯一性,比如加一些無意義隨機值等。其實也有其它一些功能強大開箱即用的的 zxing 二次封裝庫可用,比如 qrext4j6. 總結今天就 Java 開發二維碼功能進行了一些探討,從二維碼的一些特點到 ZXing 生成二維碼並開發為服務,最後還對實際使用中的一些要點進行了羅列,希望對你有用。歡迎通過留言發表你的看法和疑問。更多精彩文章可通過公眾號分類菜單獲取。