add 新增条形码工具类
This commit is contained in:
parent
45eac02f4f
commit
495e2a71a6
8
pom.xml
8
pom.xml
@ -39,6 +39,8 @@
|
||||
<justauth.version>1.16.7</justauth.version>
|
||||
<!-- 离线IP地址定位库 -->
|
||||
<ip2region.version>2.7.0</ip2region.version>
|
||||
<!-- 条形码生成工具库 -->
|
||||
<barcode.version>3.5.3</barcode.version>
|
||||
|
||||
<!-- OSS 配置 -->
|
||||
<aws.sdk.version>2.28.22</aws.sdk.version>
|
||||
@ -320,6 +322,12 @@
|
||||
<version>${ip2region.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.zxing</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>${barcode.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
|
@ -34,6 +34,7 @@
|
||||
<module>ruoyi-common-tenant</module>
|
||||
<module>ruoyi-common-websocket</module>
|
||||
<module>ruoyi-common-sse</module>
|
||||
<module>ruoyi-common-barcode</module>
|
||||
</modules>
|
||||
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
|
32
ruoyi-common/ruoyi-common-barcode/pom.xml
Normal file
32
ruoyi-common/ruoyi-common-barcode/pom.xml
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-common-barcode</artifactId>
|
||||
|
||||
<description>
|
||||
ruoyi-common-barcode 条形码模块
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 条形码生成工具库 https://mvnrepository.com/artifact/com.google.zxing/core -->
|
||||
<dependency>
|
||||
<groupId>com.google.zxing</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,29 @@
|
||||
package org.dromara.common.barcode.constant;
|
||||
|
||||
/**
|
||||
* 条形码常量
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
public interface BarcodeConstant {
|
||||
|
||||
/**
|
||||
* 宽度,单位像素
|
||||
*/
|
||||
Integer CODE_WIDTH = 300;
|
||||
|
||||
/**
|
||||
* 高度,单位像素
|
||||
*/
|
||||
Integer CODE_HEIGHT = 150;
|
||||
|
||||
/**
|
||||
* 前景色,0x000000 表示黑色
|
||||
*/
|
||||
Integer FRONT_COLOR = 0x000000;
|
||||
|
||||
/**
|
||||
* 背景色,0xFFFFFF 表示白色
|
||||
*/
|
||||
Integer BACKGROUND_COLOR = 0xFFFFFF;
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
package org.dromara.common.barcode.enums;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 条形码的种类
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum BarcodeType {
|
||||
|
||||
/**
|
||||
* Aztec 2D 条形码格式
|
||||
* 适用于高信息密度的编码,类似 QR 码
|
||||
*/
|
||||
AZTEC("Aztec", Integer.MAX_VALUE, BarcodeFormat.AZTEC),
|
||||
|
||||
/**
|
||||
* CODABAR 1D 条形码格式
|
||||
* 主要用于物流标签和医疗行业
|
||||
* 最大长度:16字符
|
||||
*/
|
||||
CODABAR("Codabar", 16, BarcodeFormat.CODABAR),
|
||||
|
||||
/**
|
||||
* Code 39 1D 条形码格式
|
||||
* 广泛用于工业和物流领域
|
||||
* 最大长度:43字符
|
||||
*/
|
||||
CODE_39("Code 39", 43, BarcodeFormat.CODE_39),
|
||||
|
||||
/**
|
||||
* Code 93 1D 条形码格式
|
||||
* 改进的 Code 39,存储密度更高
|
||||
* 最大长度:48字符
|
||||
*/
|
||||
CODE_93("Code 93", 48, BarcodeFormat.CODE_93),
|
||||
|
||||
/**
|
||||
* Code 128 1D 条形码格式
|
||||
* 支持整个 ASCII 字符集,适用于物流、快递和仓库管理
|
||||
* 最大长度:48字符
|
||||
*/
|
||||
CODE_128("Code 128", 48, BarcodeFormat.CODE_128),
|
||||
|
||||
/**
|
||||
* Data Matrix 2D 条形码格式
|
||||
* 适用于小尺寸高信息密度的编码
|
||||
*/
|
||||
DATA_MATRIX("Data Matrix", Integer.MAX_VALUE, BarcodeFormat.DATA_MATRIX),
|
||||
|
||||
/**
|
||||
* EAN-8 1D 条形码格式
|
||||
* 适用于小型商品包装
|
||||
* 最大长度:8字符
|
||||
*/
|
||||
EAN_8("EAN-8", 8, BarcodeFormat.EAN_8),
|
||||
|
||||
/**
|
||||
* EAN-13 1D 条形码格式
|
||||
* 国际商品条形码标准
|
||||
* 最大长度:13字符
|
||||
*/
|
||||
EAN_13("EAN-13", 13, BarcodeFormat.EAN_13),
|
||||
|
||||
/**
|
||||
* ITF (Interleaved Two of Five) 1D 条形码格式
|
||||
* 适用于物流和仓库
|
||||
* 最大长度:14字符
|
||||
*/
|
||||
ITF("ITF", 14, BarcodeFormat.ITF),
|
||||
|
||||
/**
|
||||
* MaxiCode 2D 条形码格式
|
||||
* 美国 UPS 物流专用
|
||||
*/
|
||||
MAXICODE("MaxiCode", Integer.MAX_VALUE, BarcodeFormat.MAXICODE),
|
||||
|
||||
/**
|
||||
* PDF417 2D 条形码格式
|
||||
* 适用于身份信息存储,如身份证、机票等
|
||||
*/
|
||||
PDF_417("PDF417", Integer.MAX_VALUE, BarcodeFormat.PDF_417),
|
||||
|
||||
/**
|
||||
* QR Code 2D 条形码格式
|
||||
* 适用于网址、名片、支付等广泛场景
|
||||
*/
|
||||
QR_CODE("QR Code", Integer.MAX_VALUE, BarcodeFormat.QR_CODE),
|
||||
|
||||
/**
|
||||
* RSS-14 1D 条形码格式
|
||||
* 常用于食品和药品追溯
|
||||
* 最大长度:14字符
|
||||
*/
|
||||
RSS_14("RSS-14", 14, BarcodeFormat.RSS_14),
|
||||
|
||||
/**
|
||||
* RSS Expanded 1D 条形码格式
|
||||
* 支持更多信息存储
|
||||
*/
|
||||
RSS_EXPANDED("RSS Expanded", Integer.MAX_VALUE, BarcodeFormat.RSS_EXPANDED),
|
||||
|
||||
/**
|
||||
* UPC-A 1D 条形码格式
|
||||
* 美国零售商品标准条形码
|
||||
* 最大长度:12字符
|
||||
*/
|
||||
UPC_A("UPC-A", 12, BarcodeFormat.UPC_A),
|
||||
|
||||
/**
|
||||
* UPC-E 1D 条形码格式
|
||||
* UPC-A 的简化版本,适用于小商品
|
||||
* 最大长度:8字符
|
||||
*/
|
||||
UPC_E("UPC-E", 8, BarcodeFormat.UPC_E),
|
||||
|
||||
/**
|
||||
* UPC/EAN 扩展格式
|
||||
* 通常作为附加条码使用
|
||||
* 最大长度:2字符
|
||||
*/
|
||||
UPC_EAN_EXTENSION("UPC/EAN Extension", 2, BarcodeFormat.UPC_EAN_EXTENSION);
|
||||
|
||||
/**
|
||||
* 条形码类型的名称
|
||||
*/
|
||||
private final String typeName;
|
||||
|
||||
/**
|
||||
* 每种条形码类型的最大长度限制
|
||||
*/
|
||||
private final int maxLength;
|
||||
|
||||
/**
|
||||
* ZXing 对应的条形码格式
|
||||
*/
|
||||
private final BarcodeFormat zxingFormat;
|
||||
|
||||
/**
|
||||
* 校验条形码内容是否符合长度要求
|
||||
*
|
||||
* @param content 条形码内容
|
||||
* @return 是否符合长度限制
|
||||
*/
|
||||
public boolean isLengthValid(String content) {
|
||||
return content.length() <= this.maxLength;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,52 @@
|
||||
package org.dromara.common.barcode.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 图片枚举
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ImageFormat {
|
||||
|
||||
/**
|
||||
* PNG格式:无损压缩,适用于需要高质量图像的场景,通常用于条形码和二维码等
|
||||
*/
|
||||
PNG("PNG"),
|
||||
|
||||
/**
|
||||
* JPEG格式:有损压缩,适用于存储较大的彩色图像,常用于照片和Web图像
|
||||
*/
|
||||
JPEG("JPEG"),
|
||||
|
||||
/**
|
||||
* GIF格式:支持动画和透明背景,但只支持256种颜色。适用于简单图像或小动画
|
||||
*/
|
||||
GIF("GIF"),
|
||||
|
||||
/**
|
||||
* BMP格式:未压缩格式,适用于高质量图像存储,但文件较大,通常不适合Web使用
|
||||
*/
|
||||
BMP("BMP"),
|
||||
|
||||
/**
|
||||
* TIFF格式:无损压缩,通常用于扫描和打印高质量图像,适合需要高精度的图像存储
|
||||
*/
|
||||
TIFF("TIFF"),
|
||||
|
||||
/**
|
||||
* WEBP格式:由Google开发,支持有损和无损压缩,文件较小,适用于Web,特别适合移动端使用
|
||||
*/
|
||||
WEBP("WEBP"),
|
||||
|
||||
/**
|
||||
* JPG格式:是JPEG格式的简称,常用于照片和图像压缩。与JPEG等效,可以接受`.jpg`和`.jpeg`两种扩展名
|
||||
*/
|
||||
JPG("JPG");
|
||||
|
||||
private final String format;
|
||||
|
||||
}
|
@ -0,0 +1,256 @@
|
||||
package org.dromara.common.barcode.utils;
|
||||
|
||||
import com.google.zxing.MultiFormatWriter;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.barcode.constant.BarcodeConstant;
|
||||
import org.dromara.common.barcode.enums.BarcodeType;
|
||||
import org.dromara.common.barcode.enums.ImageFormat;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 条形码工具类
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
@Slf4j
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class BarcodeUtil {
|
||||
|
||||
/**
|
||||
* 生成条形码并保存为指定文件
|
||||
*
|
||||
* @param content 条形码内容
|
||||
* @param barcodeType 条形码种类
|
||||
* @param format 图像格式
|
||||
* @param file 保存条形码图像的文件
|
||||
* @throws Exception 可能的异常
|
||||
*/
|
||||
public static void generateBarcodeToFile(String content, BarcodeType barcodeType, ImageFormat format, File file) throws Exception {
|
||||
generateBarcodeToFile(content, barcodeType, BarcodeConstant.CODE_WIDTH, BarcodeConstant.CODE_HEIGHT, format, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成条形码并保存为指定文件
|
||||
*
|
||||
* @param content 条形码内容
|
||||
* @param barcodeType 条形码种类
|
||||
* @param width 图像宽度
|
||||
* @param height 图像高度
|
||||
* @param format 图像格式
|
||||
* @param file 保存条形码图像的文件
|
||||
* @throws Exception 可能的异常
|
||||
*/
|
||||
public static void generateBarcodeToFile(String content, BarcodeType barcodeType, int width, int height, ImageFormat format, File file) throws Exception {
|
||||
// 生成条形码的 BufferedImage 图像
|
||||
BufferedImage image = generateBarcodeImage(content, width, height, barcodeType);
|
||||
// 将图像保存为指定格式的文件
|
||||
ImageIO.write(image, format.getFormat(), file);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成条形码并将图像写入指定的输出流
|
||||
*
|
||||
* @param content 条形码内容
|
||||
* @param barcodeType 条形码种类
|
||||
* @param format 图像格式
|
||||
* @param outputStream 输出流,用于写入条形码图像
|
||||
* @throws Exception 可能的异常
|
||||
*/
|
||||
public static void generateBarcodeToOutputStream(String content, BarcodeType barcodeType, ImageFormat format, OutputStream outputStream) throws Exception {
|
||||
generateBarcodeToOutputStream(content, barcodeType, BarcodeConstant.CODE_WIDTH, BarcodeConstant.CODE_HEIGHT, format, outputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成条形码并将图像写入指定的输出流
|
||||
*
|
||||
* @param content 条形码内容
|
||||
* @param barcodeType 条形码种类
|
||||
* @param width 图像宽度
|
||||
* @param height 图像高度
|
||||
* @param format 图像格式
|
||||
* @param outputStream 输出流,用于写入条形码图像
|
||||
* @throws Exception 可能的异常
|
||||
*/
|
||||
public static void generateBarcodeToOutputStream(String content, BarcodeType barcodeType, int width, int height, ImageFormat format, OutputStream outputStream) throws Exception {
|
||||
// 生成条形码的 BufferedImage 图像
|
||||
BufferedImage image = generateBarcodeImage(content, width, height, barcodeType);
|
||||
|
||||
// 将图像写入输出流,使用指定的图像格式
|
||||
ImageIO.write(image, format.getFormat(), outputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成条形码并返回指定格式的字节数组
|
||||
*
|
||||
* @param content 条形码内容
|
||||
* @param barcodeType 条形码种类
|
||||
* @param format 图像格式
|
||||
* @return 生成的条形码图像字节数组
|
||||
* @throws Exception 可能的异常
|
||||
*/
|
||||
public static byte[] generateBarcodeByte(String content, BarcodeType barcodeType, ImageFormat format) throws Exception {
|
||||
return generateBarcodeByte(content, barcodeType, BarcodeConstant.CODE_WIDTH, BarcodeConstant.CODE_HEIGHT, format);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成条形码并返回指定格式的字节数组
|
||||
*
|
||||
* @param content 条形码内容
|
||||
* @param barcodeType 条形码种类
|
||||
* @param width 图像宽度
|
||||
* @param height 图像高度
|
||||
* @param format 图像格式
|
||||
* @return 生成的条形码图像字节数组
|
||||
* @throws Exception 可能的异常
|
||||
*/
|
||||
public static byte[] generateBarcodeByte(String content, BarcodeType barcodeType, int width, int height, ImageFormat format) throws Exception {
|
||||
BufferedImage image = generateBarcodeImage(content, width, height, barcodeType);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ImageIO.write(image, format.getFormat(), baos);
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成条形码并返回 BufferedImage
|
||||
*
|
||||
* @param content 条形码内容
|
||||
* @param barcodeType 条形码的种类
|
||||
* @return 生成的 BufferedImage
|
||||
* @throws WriterException 生成失败异常
|
||||
*/
|
||||
public static BufferedImage generateBarcodeImage(String content, BarcodeType barcodeType) throws WriterException {
|
||||
return generateBarcodeImage(content, BarcodeConstant.CODE_WIDTH, BarcodeConstant.CODE_HEIGHT, barcodeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成条形码并返回 BufferedImage
|
||||
*
|
||||
* @param content 条形码内容
|
||||
* @param width 宽度
|
||||
* @param height 高度
|
||||
* @param barcodeType 条形码的种类
|
||||
* @return 生成的 BufferedImage
|
||||
* @throws WriterException 生成失败异常
|
||||
*/
|
||||
public static BufferedImage generateBarcodeImage(String content, int width, int height, BarcodeType barcodeType) throws WriterException {
|
||||
//校验条形码内容是否符合长度要求
|
||||
if (!barcodeType.isLengthValid(content)) {
|
||||
log.error("条形码内容长度超出限制: 最大长度为 {},实际长度为 {}", barcodeType.getMaxLength(), content.length());
|
||||
throw new IllegalArgumentException("条形码内容长度超出限制");
|
||||
}
|
||||
|
||||
log.debug("开始生成条形码,内容:{}", content);
|
||||
log.debug("条形码尺寸:{}x{}", width, height);
|
||||
|
||||
// 生成 BitMatrix(二维码的黑白数据矩阵)
|
||||
MultiFormatWriter writer = new MultiFormatWriter();
|
||||
BitMatrix bitMatrix = writer.encode(content, barcodeType.getZxingFormat(), width, height);
|
||||
|
||||
// 获取矩阵大小
|
||||
int matrixWidth = bitMatrix.getWidth();
|
||||
int matrixHeight = bitMatrix.getHeight();
|
||||
|
||||
// 创建 BufferedImage,使用 RGB 颜色模式
|
||||
BufferedImage image = new BufferedImage(matrixWidth, matrixHeight, BufferedImage.TYPE_INT_RGB);
|
||||
|
||||
// 根据图片大小选择合适的填充方式
|
||||
if (matrixWidth * matrixHeight < 1000 * 1000) {
|
||||
// 适用于小图的填充方式(批量 setRGB)
|
||||
fillImageWithSetRGB(image, bitMatrix);
|
||||
} else {
|
||||
// 适用于大图的填充方式(直接操作 WritableRaster)
|
||||
fillImageWithWritableRaster(image, bitMatrix);
|
||||
}
|
||||
|
||||
log.debug("条形码图像生成完毕");
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* 方案 1:小尺寸(小于 1000x1000 像素)条形码填充,使用 setRGB 批量写入
|
||||
*
|
||||
* @param image 目标 BufferedImage
|
||||
* @param bitMatrix 二维码矩阵
|
||||
*/
|
||||
private static void fillImageWithSetRGB(BufferedImage image, BitMatrix bitMatrix) {
|
||||
int width = bitMatrix.getWidth();
|
||||
int height = bitMatrix.getHeight();
|
||||
|
||||
// 创建图形上下文
|
||||
Graphics2D graphics = image.createGraphics();
|
||||
try {
|
||||
// 先填充白色背景
|
||||
graphics.setColor(Color.WHITE);
|
||||
graphics.fillRect(0, 0, width, height);
|
||||
} finally {
|
||||
graphics.dispose();
|
||||
}
|
||||
|
||||
// 创建像素数组
|
||||
int[] pixels = new int[width * height];
|
||||
int white = Color.WHITE.getRGB();
|
||||
int black = Color.BLACK.getRGB();
|
||||
|
||||
// **先填充白色背景**
|
||||
Arrays.fill(pixels, white);
|
||||
|
||||
// **再填充黑色条形码**
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
if (bitMatrix.get(x, y)) {
|
||||
pixels[y * width + x] = black;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **将数据写入 BufferedImage**
|
||||
image.setRGB(0, 0, width, height, pixels, 0, width);
|
||||
}
|
||||
|
||||
/**
|
||||
* 方案 2:大尺寸(大于等于 1000x1000 像素)条形码填充,使用 WritableRaster 直接写入
|
||||
*
|
||||
* @param image 目标 BufferedImage
|
||||
* @param bitMatrix 二维码矩阵
|
||||
*/
|
||||
private static void fillImageWithWritableRaster(BufferedImage image, BitMatrix bitMatrix) {
|
||||
int width = bitMatrix.getWidth();
|
||||
int height = bitMatrix.getHeight();
|
||||
|
||||
// 创建图形上下文
|
||||
Graphics2D graphics = image.createGraphics();
|
||||
try {
|
||||
// 先填充白色背景
|
||||
graphics.setColor(Color.WHITE);
|
||||
graphics.fillRect(0, 0, width, height);
|
||||
} finally {
|
||||
graphics.dispose();
|
||||
}
|
||||
// 获取 WritableRaster(直接操作像素数据)
|
||||
WritableRaster raster = image.getRaster();
|
||||
// **遍历 bitMatrix,将黑色部分填充**
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
if (bitMatrix.get(x, y)) {
|
||||
// 设置 RGB 三个通道都为 0(黑色)
|
||||
raster.setSample(x, y, 0, 0);// 红色通道
|
||||
raster.setSample(x, y, 1, 0);// 绿色通道
|
||||
raster.setSample(x, y, 2, 0);// 蓝色通道
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -179,6 +179,13 @@
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 条形码模块 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-barcode</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user