Spring Boot 集成 zxing 生成条形码与二维码

目录

前面我们知道了怎么通过 使用 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;
        }

        // 在二维码中增加 logo
        QrCodeUtils.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);
        // 压缩LOGO
        if (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;
        }

        // 插入LOGO
        Graphics2D 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 {

    @Autowired
    BarCodeUtils 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-8

        try {
            // 生成条形码的矩阵
            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 + 12
            int 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);
    }
}

测试

访问返回对应的条码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/674898.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

80V高耐压低静态线性稳压器/LDO,Vout 1v-65v 3.3V及5V方案最佳选择

概述 PC93XX系列专为动力而设计-敏感应用程序。它包括一个精度第二个高压输入级&#xff0c;超低功率 偏置电流分支&#xff0c;并产生超低功率和低压差线性调节器。PC93XX通过输入电压工作VOUT1V至65V&#xff0c;仅消耗1.8μA的静态电流&#xff0c;并提供1%的初始精度和低…

Maven项目打包成jar项目后运行报错误: 找不到或无法加载主类 Main.Main 和 jar中没有主清单属性解决方案

已经用maven工程的package功能进行了打包 找不到或无法加载主类 Main.Main 规定主类 主要在maven的配置文件当中 这边一定要绑定自己的启动类 jar中没有主清单属性 删掉这一行就行哈 正确的插件代码 <plugin><groupId>org.springframework.boot</groupId&…

孩子出生后为什么要做听力筛查?

孩子出生后为什么要做听力筛查&#xff1f; 新生儿听力筛查&#xff0c;就是对所有新生儿在尽早的时间&#xff08;出生48小时后&#xff09;进行系统的听力筛查测试。据相关文献报道&#xff0c;在我国&#xff0c;正常分娩的新生儿听力障碍的发生率约为0.1&#xff5e;0.3%&a…

gomail发送邮件的参数如何设置?如何使用?

gomail发送邮件的认证方式有哪些&#xff1f;怎么设置邮件发信&#xff1f; Gomail是一个常用的Go语言邮件发送库&#xff0c;它提供了简单易用的接口&#xff0c;使得邮件发送变得非常方便。AokSend将详细介绍如何设置gomail发送邮件的参数&#xff0c;帮助开发者更好地理解和…

Window11开放端口

&#xff08;1&#xff09;打开控制面板&#xff0c;进入【控制面板\系统和安全\Windows Defender 防火墙】 &#xff08;2&#xff09;点击左侧菜单【高级设置】&#xff0c;进入防火墙设置页面 &#xff08;3&#xff09;根据需要选择【入站规则】或者【出站规则】&#xff…

《猎杀:对决》是适合什么样的人玩 Mac电脑怎么玩《猎杀:对决》

《猎杀&#xff1a;对决》是一款集合了生存、竞技和恐怖元素的多人在线游戏&#xff0c;自推出以来受到了广大玩家的热爱。本文将详细探讨《猎杀&#xff1a;对决》适合什么样的人玩以及Mac电脑怎么玩《猎杀&#xff1a;对决》。本文将一一解析&#xff0c;帮助你了解这款游戏是…

全球家纺热潮持续!有哪些家纺爆款类目推荐入驻沃尔玛?

在全球家纺热潮中&#xff0c;选择沃尔玛家纺爆款类目入驻是明智之举。沃尔玛作为全球零售巨头&#xff0c;拥有庞大的消费者群体和销售渠道&#xff0c;对家纺产品销售具有显著优势。 ​以下是一些推荐的家纺爆款类目&#xff0c;供您参考&#xff1a; 一、高品质床品套件 床…

迪普微震撼发布:全新Xilinx Kintex-7 XC7K325 FPGA开发板!

01 产品概述 本公司基于Xilinx Kintex-7系列的开发平台采用核心板加扩展主板的方式&#xff0c;方便用户对相关板卡的二次开发利用。 其中&#xff0c;核心板包含一片芯片XC7K325T&#xff0c;使用FFG900封装&#xff0c;外挂4片512MB的高速DDR3芯片和1片256Mb的QSPI Flash芯…

mysql 如果有按照时间范围查询结果

1.前端传2024-06-21 到我们xml sql 文件中默认实际是 2024-06-21 00:00:00 <if test"dto.startTime ! null">and ps.created_at > #{dto.startTime}</if><if test"dto.endTime ! null">and ps.created_at < #{dto.endTime}</if…

(2) qml诞生的原因 和Qt Creator开发环境的介绍

文章目录 qml诞生原因Qt Quick应⽤程序Qt Creator环境1、MSVC2、MinGWMSVC的优缺点MinGW的优缺点 最后的选择延伸阅读 一些常用的快捷键统一格式化代码统一qml 语言的格式Locator 定位器帮助 qml诞生原因 可以在Qt5中开发的不同类型的经典应⽤程序。桌⾯应⽤程 序正在发⽣着改…

如何制作不限扫描次数的视频二维码?1分钟教程

不可否认的是&#xff0c;视频二维码正在各行各业发挥重要作用。不论是在线上宣传、线下活动&#xff0c;还是产品包装、展览展会上&#xff0c;只需要扫描视频二维码&#xff0c;就能在手机端获得专业的视频教程、查看品牌宣传视频、了解活动流程、快速获取关键信息等&#xf…

AI精选付费资料包【37GB】

课程介绍 一、人工智能论文合集 二、AI必读经典书籍 三、超详细人工智能学习大纲 四、机器学习基础算法教程 五、深度学习神经网络基础教程 六、计算机视觉实战项目 课程获取 资料&#xff1a;AI精选付费资料包&#xff08;37.4GB&#xff09;获取&#xff1a;扫码关注公z号…

msconfig修改引导导致电脑无法进入系统 和 启动蓝屏问题

目录 解决方法遇到的问题开机蓝屏进入【指定UFEI固件设置】进入bios启动系统选择界面&#xff08;忘了拍照&#xff09; 解决方法 找到一个移动U盘&#xff08;最好大于10G&#xff09;格式化&#xff1b;找一个好的电脑安装WEPE软件&#xff08;wepe安装链接&#xff09;&…

[leetcode hot150]第五十七题,插入区间

题目&#xff1a; 给你一个 无重叠的 &#xff0c;按照区间起始端点排序的区间列表 intervals&#xff0c;其中 intervals[i] [starti, endi] 表示第 i 个区间的开始和结束&#xff0c;并且 intervals 按照 starti 升序排列。同样给定一个区间 newInterval [start, end] 表示…

解决odbc 数据源创建之后删除失败问题

问题描述 该问题一般存在于用32位odbc管理程序删除了64位管理程序创建的数据源&#xff0c;被提示失败&#xff0c;然后再用64位odbc管理程序删除时发现删除不掉。怎么都删除不掉&#xff0c;不会影响体验&#xff0c;但是很膈应 问题解决 将该路径下的对应的ODBC数据源&…

判断JavaScript对象是否为空,最佳方法与性能对比

引言&#xff1a;在日常开发中&#xff0c;你是否经常需要判断一个对象是否为空&#xff1f;你知道有哪些高效的方法可以做到这一点吗&#xff1f;今天&#xff0c;我们不仅要探讨这些方法&#xff0c;还要通过性能对比找出最优解。快来看看&#xff0c;你平常用的方法是最佳选…

Windows系统电脑本地部署AI音乐创作工具并实现无公网IP远程使用

文章目录 前言1. 本地部署2. 使用方法介绍3. 内网穿透工具下载安装4. 配置公网地址5. 配置固定公网地址 前言 本文主要介绍如何在Windows系统电脑上快速本地部署一个文字生成音乐的AI创作工具MusicGPT&#xff0c;并结合cpolar内网穿透工具实现随时随地远程访问使用。 MusicG…

【机器学习】——驱动智能制造的青春力量,优化生产、预见故障、提升质量

目录 一.优化生产流程 1.1 数据收集 1.2 数据预处理 1.3 模型训练 1.4 优化建议 1.5 示例代码 二.预测设备故障 2.1 数据收集 2.2 数据预处理 2.3 模型训练 2.4 故障预测 2.5 示例代码 三.提升产品质量 3.1 数据收集 3.2 数据预处理 3.3 模型训练 3.4 质量提升…

R语言的Meta分析【全流程、不确定性分析】方法与Meta机器学习技术应用

Meta分析是针对某一科研问题&#xff0c;根据明确的搜索策略、选择筛选文献标准、采用严格的评价方法&#xff0c;对来源不同的研究成果进行收集、合并及定量统计分析的方法&#xff0c;最早出现于“循证医学”&#xff0c;现已广泛应用于农林生态&#xff0c;资源环境等方面。…

使用 Django 实现定时任务

文章目录 Celery 简介步骤1. 安装 Celery2. 配置 Celery3. 创建 Celery 任务4. 启动 Celery Worker5. 调度定时任务6. 定时调度任务7. 启动 Celery Beat 在许多 Web 应用程序中&#xff0c;需要执行定期的任务&#xff0c;比如数据备份、邮件发送或者清理任务。Django 提供了多…