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;}// 在二维码中增加 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);}
}
测试
相关文章:

Spring Boot 集成 zxing 生成条形码与二维码
前面我们知道了怎么通过 使用 zxing 生成二维码以及条形码, 由于我们现在都是 web 端的项目了,那么我们看下怎么使用 Spring Boot 集成然后返回给前端展示: 工程源码 对应的工程源码我放到了这里:github源码路径,点击…...
C# 编程基础:注释、变量、常量、数据类型和自定义类型
C# 是一种功能强大的面向对象编程语言,它提供了丰富的特性来帮助开发者编写清晰、高效的代码。本文将介绍C#中的注释、变量、常量、基本数据类型以及如何创建和使用自定义类型。 注释 注释用于解释代码的目的,它们不会被程序执行。 单行注释使用 //。…...

网络原理-三
一、连接管理 建立连接,断开连接 建立连接,TCP有连接的. 客户端执行 socket new Socket(SeverIP,severPort); -> 这个操作就是在建立连接. 上述只是调用socket api,真正建立连接的过程,实在操作系统内核完成的. 内核是怎样完成上述的 " 建立连接 "过程的…...

使用Ollama搭建一个免费的聊天机器人
0 概述 Ollama是一个能在本机运行大语言模型的软件,它提供命令行和API的交互方式,对于需要考虑数据隐私的情景,可以方便的使用Ollama部署大语言模型,并在此基础上开发RAG等应用,而无需调用OpenAI等开放API。Ollama基本…...

计算机网络之快重传和快恢复以及TCP连接与释放的握手
快重传和快恢复 快重传可以让发送方尽早得知丢失消息, 当发送消息M1,M2,M3,M4,M5后,假如消息M2丢失,那么按照算法会发送对M2报文前一个报文M1的重复确认(M1正常接受到,已经发送了确认),然后之后收到M4,M5,也会发送两…...

vue 引用第三方库 Swpier轮播图
本文全程干货,没有废话 1.使用 npm 安装 swiper,使用 save 保存到 packjson 中 npm install --save swiper 2、把 swiper看成是第三方库或者是组件,然后按照,引用,挂载组件,使用组件三步法。 3、在 script…...

RabbitMQ-直连交换机(direct)使用方法
RabbitMQ-默认读、写方式介绍 RabbitMQ-发布/订阅模式 目录 1、概述 2、直连交换机 3、多重绑定 4、具体代码实现 4.1 生产者部分 4.2 消费者部分 5、运行代码 6、总结 1、概述 直连交换机,可以实现类似路由的功能,消息从交换机发送到哪个队列…...

942. 增减字符串匹配 - 力扣
1. 题目 由范围 [0,n] 内所有整数组成的 n 1 个整数的排列序列可以表示为长度为 n 的字符串 s ,其中: 如果 perm[i] < perm[i 1] ,那么 s[i] I 如果 perm[i] > perm[i 1] ,那么 s[i] D 给定一个字符串 s ,重构排列 pe…...
2024华为OD机试真题-机器人搬砖-C++(C卷D卷)
题目描述 机器人搬砖,一共有N堆砖存放在N个不同的仓库中,第i堆砖中有bricks[i]块砖头, 要求在8小时内搬完。机器人每小时能搬砖的数量取决于有多少能量格, 机器人一个小时中只能在一个仓库中搬砖,机器人的能量格每小时补充一次且能量格只在这一个小时有效,为使得机器人损…...

【DevOps】深入了解RabbitMQ:AMQP协议基础、消息队列工作原理和应用场景
目录 一、核心功能 二、优势 三、核心概念 四、工作原理 五、交换机类型 六、消息确认 七、持久性和可靠性 八、插件和扩展 九、集群和镜像队列 十、客户端库 十一、管理界面 十二、应用场景 RabbitMQ是一个基于AMQP协议的消息队列中间件,提供高可用、可…...
Mysql 技术实战篇
命令行 导出 - -h localhost:指定MySQL服务器的主机地址为本地主机。如果MySQL服务器在其他主机上,请将localhost替换为相应的主机地址。 - -u username:指定连接MySQL服务器的用户名。将username替换为您的有效用户名。 - -p:提…...

App自动化测试_Python+Appium使用手册
一、Appium的介绍 Appium是一款开源的自动化测试工具,支持模拟器和真机上的原生应用、混合应用、Web应用;基于Selenium二次开发,Appium支持Selenium WebDriver支持的所有语言(java、 Object-C 、 JavaScript 、p hp、 Python等&am…...

k8s-部署对象存储minio
环境信息 minio版本 :最新 k8s 版本1.22 使用nfs作为共享存储 一.单节点安装包部署 脚本部署,一键部署,单节点应用于数据量小,一些缓存存储,比如gitlab-runner的产物数据,maven的打包依赖数据 #!/bin/bash# 步骤…...
go常用命令
创建一个module(逻辑概念) #The go mod init command initializes and writes a new go.mod file in the current directory, in effect creating #a new module rooted at the current directory. #specify a module path that serves as the module’s name. go mod initclon…...
【中年危机】程序猿自救指南
中年危机,一个听起来就充满挑战的词汇,它不仅仅是一个年龄的标记,更是一个个人成长和职业发展的转折点。 构架个人品牌: 学会打造IP个人品牌是职业生涯中的重要资产。在中年时期,你已经积累了丰富的经验和知识&#x…...

vueRouter路由总结
https://blog.csdn.net/qq_24767091/article/details/119326884...

算法工程师需要学习C++的哪些知识?
在开始前刚好我有一些资料,是我根据网友给的问题精心整理了一份「C的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!!以下是算法工程师需要学习的一些…...

CTF网络安全大赛简单的web抓包题目:HEADache
题目来源于:bugku 题目难度:简单 题目 描 述: > Wanna learn about some types of headache? > Lets dig right into it! 下面是题目源代码: <!DOCTYPE html> <html> <head><meta charset"utf-8"&…...
Qt Creator创建Python界面工程并打包为可执行exe文件
Qt Creator创建Python界面工程并打包为可执行exe文件_qtcreator创建python工程-CSDN博客...
基于单片机的步进电机控制系统的研究
摘要: 步进电机控制作为一种电机控制系统的重要模式,属于现代数字化控制的重要手段,其应用已经相当广泛。步进电机属于感应电机类,利用电子电路将直流电分为分时供电、多相时序供电控制电流,利用这种电流为电机供电,驱使电机工作。步进电机不能够在常规模式下使用,必须通过双环…...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...

WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...

数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)
目录 🔍 若用递归计算每一项,会发生什么? Horners Rule(霍纳法则) 第一步:我们从最原始的泰勒公式出发 第二步:从形式上重新观察展开式 🌟 第三步:引出霍纳法则&…...

小智AI+MCP
什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析:AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github:https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...

【PX4飞控】mavros gps相关话题分析,经纬度海拔获取方法,卫星数锁定状态获取方法
使用 ROS1-Noetic 和 mavros v1.20.1, 携带经纬度海拔的话题主要有三个: /mavros/global_position/raw/fix/mavros/gpsstatus/gps1/raw/mavros/global_position/global 查看 mavros 源码,来分析他们的发布过程。发现前两个话题都对应了同一…...
LeetCode 0386.字典序排数:细心总结条件
【LetMeFly】386.字典序排数:细心总结条件 力扣题目链接:https://leetcode.cn/problems/lexicographical-numbers/ 给你一个整数 n ,按字典序返回范围 [1, n] 内所有整数。 你必须设计一个时间复杂度为 O(n) 且使用 O(1) 额外空间的算法。…...