前面我們知道了怎么通過 使用 zxing 生成二維碼以及條形碼, 由于我們現在都是 web 端的項目了,那么我們看下怎么使用 Spring Boot
集成然后返回給前端展示:
工程源碼
對應的工程源碼我放到了這里:github源碼路徑,點擊這里查看
開始搭建
這里的整個過程就很簡單了,引入依賴包還是和之前一樣,另外搭建就兩部分:
- controller 層
- utils 層
引入依賴
<dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.4.1</version>
</dependency><dependency><groupId>com.google.zxing</groupId><artifactId>javase</artifactId><version>3.4.1</version>
</dependency>
生成二維碼
對應的 controller
代碼示例:
@RestController
@RequestMapping(path = "/qrcode")
public class QrCodeController {// http://localhost:8080/qrcode/create?content=www.baidu.com@GetMapping(path = "/createQrCode")public void createQrCode(HttpServletResponse response, @RequestParam("content") String content) {try {// 創建二維碼BufferedImage bufferedImage = QrCodeUtils.createImage(content, null, false);// 通過流的方式返回給前端responseImage(response, bufferedImage);} catch (Exception e) {e.printStackTrace();}}/*** 設置 可通過 postman 或者瀏覽器直接瀏覽** @param response response* @param bufferedImage bufferedImage* @throws Exception e*/public void responseImage(HttpServletResponse response, BufferedImage bufferedImage) throws Exception {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ImageOutputStream imageOutput = ImageIO.createImageOutputStream(byteArrayOutputStream);ImageIO.write(bufferedImage, "jpeg", imageOutput);InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());OutputStream outputStream = response.getOutputStream();response.setContentType("image/jpeg");response.setCharacterEncoding("UTF-8");IOUtils.copy(inputStream, outputStream);outputStream.flush();}
}
對應的 工具類 QrCodeUtils
@Component
public class QrCodeUtils {private static final String CHARSET = "UTF-8";private static final String FORMAT_NAME = "JPG";/*** 二維碼尺寸*/private static final int QRCODE_SIZE = 300;/*** LOGO寬度*/private static final int WIDTH = 60;/*** LOGO高度*/private static final int HEIGHT = 60;/*** 創建二維碼圖片** @param content 內容* @param logoPath logo* @param isCompress 是否壓縮Logo* @return 返回二維碼圖片* @throws WriterException e* @throws IOException BufferedImage*/public static BufferedImage createImage(String content, String logoPath, boolean isCompress) throws WriterException, IOException {Hashtable<EncodeHintType, Object> hints = new Hashtable<>();// 設置二維碼的錯誤糾正級別 高hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);// 設置字符集hints.put(EncodeHintType.CHARACTER_SET, CHARSET);// 設置邊距hints.put(EncodeHintType.MARGIN, 1);// 生成二維碼BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);int width = bitMatrix.getWidth();int height = bitMatrix.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++) {image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);}}if (logoPath == null || "".equals(logoPath)) {return image;}// 在二維碼中增加 logoQrCodeUtils.insertImage(image, logoPath, isCompress);return image;}/*** 添加Logo** @param source 二維碼圖片* @param logoPath Logo* @param isCompress 是否壓縮Logo* @throws IOException void*/private static void insertImage(BufferedImage source, String logoPath, boolean isCompress) throws IOException {File file = new File(logoPath);if (!file.exists()) {return;}Image src = ImageIO.read(new File(logoPath));int width = src.getWidth(null);int height = src.getHeight(null);// 壓縮LOGOif (isCompress) {if (width > WIDTH) {width = WIDTH;}if (height > HEIGHT) {height = HEIGHT;}Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);Graphics g = tag.getGraphics();// 繪制縮小后的圖g.drawImage(image, 0, 0, null);g.dispose();src = image;}// 插入LOGOGraphics2D graph = source.createGraphics();int x = (QRCODE_SIZE - width) / 2;int y = (QRCODE_SIZE - height) / 2;graph.drawImage(src, x, y, width, height, null);Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);graph.setStroke(new BasicStroke(3f));graph.draw(shape);graph.dispose();}/*** 生成帶Logo的二維碼** @param content 二維碼內容* @param logoPath Logo* @param destPath 二維碼輸出路徑* @param isCompress 是否壓縮Logo* @throws Exception void*/public static void create(String content, String logoPath, String destPath, boolean isCompress) throws Exception {BufferedImage image = QrCodeUtils.createImage(content, logoPath, isCompress);mkdirs(destPath);ImageIO.write(image, FORMAT_NAME, new File(destPath));}/*** 生成不帶Logo的二維碼** @param content 二維碼內容* @param destPath 二維碼輸出路徑*/public static void create(String content, String destPath) throws Exception {QrCodeUtils.create(content, null, destPath, false);}/*** 生成帶Logo的二維碼,并輸出到指定的輸出流** @param content 二維碼內容* @param logoPath Logo* @param output 輸出流* @param isCompress 是否壓縮Logo*/public static void create(String content, String logoPath, OutputStream output, boolean isCompress) throws Exception {BufferedImage image = QrCodeUtils.createImage(content, logoPath, isCompress);ImageIO.write(image, FORMAT_NAME, output);}/*** 生成不帶Logo的二維碼,并輸出到指定的輸出流** @param content 二維碼內容* @param output 輸出流* @throws Exception void*/public static void create(String content, OutputStream output) throws Exception {QrCodeUtils.create(content, null, output, false);}/*** 二維碼解析** @param file 二維碼* @return 返回解析得到的二維碼內容* @throws Exception String*/public static String parse(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<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>();hints.put(DecodeHintType.CHARACTER_SET, CHARSET);result = new MultiFormatReader().decode(bitmap, hints);return result.getText();}/*** 二維碼解析** @param path 二維碼存儲位置* @return 返回解析得到的二維碼內容* @throws Exception String*/public static String parse(String path) throws Exception {return QrCodeUtils.parse(new File(path));}/*** 判斷路徑是否存在,如果不存在則創建** @param dir 目錄*/public static void mkdirs(String dir) {if (dir != null && !"".equals(dir)) {File file = new File(dir);if (!file.isDirectory()) {file.mkdirs();}}}
}
測試
生成條形碼
對應的 controller
代碼示例:
@RestController
@RequestMapping(path = "/barcode")
public class BarCodeController {@AutowiredBarCodeUtils barCodeUtils;// http://localhost:8080/barcode/createCode?content=987654132&barCodeWord=123456789@GetMapping(path = "/createCode")public void createQrCode(HttpServletResponse response, @RequestParam("content") String content, @RequestParam("content") String barCodeWord) {try {// 創建二維碼ByteArrayOutputStream byteArrayOutputStream = barCodeUtils.barcodeGenerator(content, barCodeWord);// 通過流的方式返回給前端InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());OutputStream outputStream = response.getOutputStream();response.setContentType("image/jpeg");response.setCharacterEncoding("UTF-8");IOUtils.copy(inputStream, outputStream);outputStream.flush();} catch (Exception e) {e.printStackTrace();}}}
對應的 工具類 BarCodeUtils
@Component
public class BarCodeUtils {/*** 條形碼寬度*/private static final int WIDTH = 200;/*** 條形碼高度*/private static final int HEIGHT = 50;/*** 生成條形碼,并加文字,以流的方式返回** @param content 內容* @param barCodeWord 二維碼的文字* @return ByteArrayOutputStream*/public ByteArrayOutputStream barcodeGenerator(String content, String barCodeWord) {// 設置條形碼參數HashMap<EncodeHintType, Object> hints = new HashMap<>();hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); // 設置糾錯級別為L(低)hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 設置字符編碼為UTF-8try {// 生成條形碼的矩陣BitMatrix matrix = new MultiFormatWriter().encode(content, BarcodeFormat.CODE_128, WIDTH, HEIGHT, hints);ByteArrayOutputStream outputStream = new ByteArrayOutputStream();BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(matrix);//底部加單號BufferedImage image = this.insertWords(bufferedImage, barCodeWord);if (Objects.isNull(image)) {throw new RuntimeException("條形碼加文字失敗");}ImageIO.write(image, "png", outputStream);return outputStream;} catch (WriterException | IOException e) {throw new RuntimeException("條形碼生成失敗", e);}}private BufferedImage insertWords(BufferedImage image, String words) {// 新的圖片,把帶logo的二維碼下面加上文字if (StringUtils.hasLength(words)) {BufferedImage outImage = new BufferedImage(WIDTH, HEIGHT + 20, BufferedImage.TYPE_INT_RGB);Graphics2D g2d = outImage.createGraphics();// 抗鋸齒this.setGraphics2D(g2d);// 設置白色this.setColorWhite(g2d);// 畫條形碼到新的面板g2d.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);// 畫文字到新的面板Color color = new Color(0, 0, 0);g2d.setColor(color);// 字體、字型、字號g2d.setFont(new Font("微軟雅黑", Font.PLAIN, 16));//文字長度int strWidth = g2d.getFontMetrics().stringWidth(words);//總長度減去文字長度的一半 (居中顯示)int wordStartX = (WIDTH - strWidth) / 2;//height + (outImage.getHeight() - height) / 2 + 12int wordStartY = HEIGHT + 20;// time 文字長度// 畫文字g2d.drawString(words, wordStartX, wordStartY);g2d.dispose();outImage.flush();return outImage;}return null;}/*** 設置 Graphics2D 屬性 (抗鋸齒)** @param g2d Graphics2D提供對幾何形狀、坐標轉換、顏色管理和文本布局更為復雜的控制*/private void setGraphics2D(Graphics2D g2d) {// 消除畫圖鋸齒g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// 消除文字鋸齒g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT);Stroke s = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER);g2d.setStroke(s);}private void setColorWhite(Graphics2D g2d) {g2d.setColor(Color.WHITE);//填充整個屏幕g2d.fillRect(0, 0, WIDTH, HEIGHT + 20);//設置筆刷g2d.setColor(Color.BLACK);}
}