Java代码小demon(一)SpringBoot+二维码和条形码生成

1. 简介

  • 原由

需要一个工具类,可以将数据存储在二维码中,通过扫一扫可以获取到信息,条形码不能接受中文字符 收藏和转载以及自己应用时拓展,具体实现和底层原理还不会,有时间我会去了解或者忘记

  • 借鉴博客

带妳心菲
ljheee

项目依赖

主要的jar包依赖:

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

代码实现和原理分析

import com.google.zxing.*;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.apache.commons.lang3.StringUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 描述:生成二维码的工具类
 *
 * @author hehe ~_~
 * @date 2021-05-14 14:45
 */
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;
    private static final int HEIGHT = 60;

    /**
     * 生成二维码图片
     *
     * @param content      二维码内容
     * @param imagePath    二维码内部图片路径
     * @param needCompress 二维码内部图片是否需要压缩标识
     * @return 二维码图片
     * @throws WriterException 异常
     */
    private static BufferedImage createQrCode(String content,String imagePath,boolean needCompress) throws WriterException, IOException {
    	/**
         * EncodeHintType 编码提示类型 枚举类型:
         * CHARACTER_SET: 设置字符编码类型 "UTF-8" QR_CODE类型默认的编码格式 "ISO-8859-1"
         * MARGIN: 设置二维码边距,单位像素,值越小,二维码距离四周越近
         * ERROR_CORRECTION: 设置误差校正
         *  ErrorCorrectionLevel:误差校正等级,L = ~7% correction、M = ~15% correction、Q = ~25% correction、H = ~30% correction
         *    不设置时,默认为 L 等级,等级不一样,生成的图案不同,但扫描的结果是一样的
         */
        Map<EncodeHintType, Object> hints = new ConcurrentHashMap<>(3);
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        //加密生成二维码的矩阵对象 二维的0 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 i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                //设置二维码的黑色0xFF000000 和白色0xFFFFFFFF
                image.setRGB(i, j, bitMatrix.get(i, j) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        if (StringUtils.isBlank(imagePath)) {
            return image;
        }
        //插入小图标 logo
        QrCodeUtils.insertImage(image, imagePath, needCompress);
        return image;
    }

    /**
     * 创建线性的条形码
     *
     * @param content 条形码内容
     * @return 生成的条形码
     * @throws WriterException 异常
     */
    private static BufferedImage createLinearCode(String content) throws WriterException {
        Map<EncodeHintType, Object> hints = new ConcurrentHashMap<>();
        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.ITF, QRCODE_SIZE, 200, hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                image.setRGB(i, j, bitMatrix.get(i, j) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        return image;
    }

    /**
     * 将logo插入二维码中间
     *
     * @param source       生成的二位码存储对象
     * @param imagePath    二维码内部图片的路径
     * 一般的业务场景会把插入的小logo放到oss生成url
     * @param needCompress 二维码内部图片是否需要压缩
     * @throws IOException 异常
     */
    private static void insertImage(BufferedImage source, String imagePath, boolean needCompress) throws IOException {
        File file = new File(imagePath);
        if (!file.exists()) {
            //可以自定义抛出异常
            System.out.println("文件路径不存在:" + imagePath);
            return;
        }
        //这里修改ImageIO.read() 内可以接受Url InputStream File ImageInputStream
        Image src  = ImageIO.read(file);
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        //是否压缩
        if (needCompress) {
            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;
        }
        Graphics2D graphics = source.createGraphics();
        int x = (QRCODE_SIZE - width) / 2;
        int y = (QRCODE_SIZE - height) / 2;
        graphics.drawImage(src,x,y,width,height,null);
        Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
        graphics.setStroke(new BasicStroke(3f));
        graphics.draw(shape);
        graphics.dispose();
    }

    /**
     * 生成带logo二维码,并保存到磁盘
     *
     * @param content      二维码的内容
     * @param imgPath      二维码内部插入的图片路径
     * @param destPath     整个二维码存储的路径
     * @param needCompress 二维码内部插入的图片是否需要压缩的标识
     * @throws Exception 异常
     */
    public static void encode(String content, String imgPath, String destPath, boolean needCompress) throws Exception {
        BufferedImage image = QrCodeUtils.createQrCode(content, imgPath, needCompress);
        mkdirs(destPath);
        //生成随机文件名
        String file = UUID.randomUUID() + ".jpg";
        ImageIO.write(image, FORMAT_NAME, new File(destPath + "/" + file));
    }

	/**
     * 生成条形码
     *
     * @param content  内容 不能有中文
     * @param destPath 文件存放路径
     * @throws Exception
     */
    public static void encode1(String content,String destPath) throws Exception {
        BufferedImage image = QrCodeUtils.createLinearCode(content);
        mkdirs(destPath);
        //生成随机文件名
        String file = UUID.randomUUID() + ".jpg";
        ImageIO.write(image, FORMAT_NAME, new File(destPath + "/" + file));
    }

    public static void mkdirs(String destPath) {
        File file = new File(destPath);
        // 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir。(mkdir如果父目录不存在则会抛出异常)
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

    public static void encode(String content, String imgPath, OutputStream output, boolean needCompress)
            throws Exception {
        BufferedImage image = QrCodeUtils.createQrCode(content, imgPath, needCompress);
        ImageIO.write(image, FORMAT_NAME, output);
    }

	//我主要用的是这个方法,其他方法我没有用
    public static void encode(String content, OutputStream output) throws Exception {
        QrCodeUtils.encode(content, null, output, false);
    }

    public static String decode(String path) throws Exception {
        return QrCodeUtils.decode(new File(path));
    }

}

这里我拓展一下,我使用的是临时文件上传到oss生成url返回给前端,我直接将url存放在本地磁盘的

public static void main(String[] args) throws Exception {
        Long companyId = 0L;
        Long userId = 520L;
        String fileName = new StringBuilder().append(System.currentTimeMillis()).append(companyId).append(userId).append(".jpg").toString();
        /**
         * setSizeThreshold: 设置内存缓冲区的大小 默认大小 10240 == 10K 这里默认为1 1024 1k的缓冲区
         * setRepository: 指定临时文件存放目录
         */
        DiskFileItemFactory fileItemFactory = new DiskFileItemFactory(1,null);
        FileItem fileItem = fileItemFactory.createItem("file", "multipart/form-data", true, fileName);
        OutputStream outputStream = null;
        String url = "";
        try {
            outputStream = fileItem.getOutputStream();
            //生成二维码将二维码的数据存放在流中上传到oss中
            QrCodeUtils.encode("12345", outputStream);
            //生成二维码
            //虽然没有指定路径 但是在机器中存放的路径是fileItem文件 /var/folders/d4/q_9n50d57gjd4hzngg1lr_8c0000gn/T/ 这是我的
            MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
            //上传到oss中
            //url = oss.uploadQrCode(multipartFile, fileName);
        } catch (Exception e){
            throw new Exception("创建二维码异常");
        } finally {
            //临时文件记得最后一定需要执行删除操作,占用磁盘空间
            fileItem.delete();
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    System.out.println(e.toString());
                }
            }
        }
    }

关于实现二维码和条形码的枚举类

public enum BarcodeFormat {

  /** Aztec 2D barcode format. */
  AZTEC,

  /** CODABAR 1D format. */
  CODABAR,

  /** Code 39 1D format. */
  CODE_39,

  /** Code 93 1D format. */
  CODE_93,

  /** Code 128 1D format. */
  CODE_128,

  /** Data Matrix 2D barcode format. */
  DATA_MATRIX,

  /** EAN-8 1D format. */
  EAN_8,//这个我测试的时候只支持8位数字或字母 超出就会报错

  /** EAN-13 1D format. */
  EAN_13,//13位数字或字母

  /** ITF (Interleaved Two of Five) 1D format. */
  ITF,

  /** MaxiCode 2D barcode format. */
  MAXICODE,

  /** PDF417 format. */
  PDF_417,

  /** QR Code 2D barcode format. */
  QR_CODE,//这个指定的是二维码的类型 其他的没有测试

  /** RSS 14 */
  RSS_14,

  /** RSS EXPANDED */
  RSS_EXPANDED,

  /** UPC-A 1D format. */
  UPC_A,

  /** UPC-E 1D format. */
  UPC_E,

  /** UPC/EAN extension format. Not a stand-alone format. */
  UPC_EAN_EXTENSION

}

标有1D的应该是条形码,2D是二维码,至于区别后面自己挖掘

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值