diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/qccode/QRCodeUtil.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/qccode/QRCodeUtil.java new file mode 100644 index 0000000..b5960a0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/qccode/QRCodeUtil.java @@ -0,0 +1,150 @@ +package cn.iocoder.yudao.framework.common.util.qccode; + +import cn.hutool.core.util.StrUtil; +import com.google.zxing.client.j2se.BufferedImageLuminanceSource; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.common.HybridBinarizer; +import com.google.zxing.qrcode.QRCodeReader; +import com.google.zxing.qrcode.QRCodeWriter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.yaml.snakeyaml.reader.ReaderException; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; + +/** + * 二维码生成工具类 + * + * Created by FSQ + * CopyRight https://www.huamar.com + */ +public class QRCodeUtil { + public static final Logger logger = LoggerFactory.getLogger(QRCodeUtil.class); + + /** + * 生成包含字符串信息的二维码图片 + * + * @param outputStream 文件输出流路径 + * @param content 二维码携带信息 + * @param width 宽度 + * @param height 高度 + * @param imageFormat 二维码的格式 + * @param resource 原图 + */ + public static boolean createQrCode(OutputStream outputStream, String content, int width, int height, String imageFormat, String resource) { + //设置二维码纠错级别 + HashMap hints = new HashMap(); + hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); + /* width = width ; + height = height ;*/ + try { + //创建比特矩阵(位矩阵)的QR码编码的字符串 + QRCodeWriter qrCodeWriter = new QRCodeWriter(); + BitMatrix byteMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hints); + + // 使BufferedImage勾画QRCode (matrixWidth 是行二维码像素点) + int matrixWidth = byteMatrix.getWidth(); + BufferedImage image = new BufferedImage(matrixWidth - 200, matrixWidth - 200, BufferedImage.TYPE_INT_RGB); + + // 使用比特矩阵画并保存图像 + image.createGraphics(); + Graphics2D graphics = (Graphics2D) image.getGraphics(); + graphics.setColor(Color.WHITE); + graphics.fillRect(0, 0, matrixWidth, matrixWidth); + graphics.setColor(Color.BLACK); + for (int i = 0; i < matrixWidth; i++) { + for (int j = 0; j < matrixWidth; j++) { + if (byteMatrix.get(i, j)) { + graphics.fillRect(i - 100, j - 100, 1, 1); + } + } + } + + if (StrUtil.isNotEmpty(resource)) { + BufferedImage big = getRemoteBufferedImage(resource); + + BufferedImage small = image; + Graphics2D g = big.createGraphics(); + + // 二维码坐标(默认在右上角) + int x = big.getWidth() - small.getWidth() - 2; + int y = 2; + + g.drawImage(small, x, y, small.getWidth(), small.getHeight(), null); + g.dispose(); + + return ImageIO.write(big, imageFormat, outputStream); + } else { + return ImageIO.write(image, imageFormat, outputStream); + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + return false; + } + + /** + * 读二维码并输出携带的信息 + */ + public static void readQrCode(InputStream inputStream) throws IOException { + //设置二维码纠错级别 + HashMap hints = new HashMap(); + hints.put(DecodeHintType.CHARACTER_SET, "utf-8"); + //从输入流中获取字符串信息 + BufferedImage image = ImageIO.read(inputStream); + //将图像转换为二进制位图源 + LuminanceSource source = new BufferedImageLuminanceSource(image); + BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); + QRCodeReader reader = new QRCodeReader(); + Result result = null; + try { + result = reader.decode(bitmap, hints); + } catch (ReaderException e) { + logger.error(e.getMessage(), e); + } + logger.info(result.getText()); + } + + /** + * 获取远程网络图片信息 + * @param imageURL + * @return + */ + public static BufferedImage getRemoteBufferedImage(String imageURL) { + URL url; + InputStream is = null; + BufferedImage bufferedImage = null; + try { + url = new URL(imageURL); + is = url.openStream(); + bufferedImage = ImageIO.read(is); + } catch (MalformedURLException e) { + e.printStackTrace(); + System.out.println("imageURL: " + imageURL + ",无效!"); + return null; + } catch (IOException e) { + e.printStackTrace(); + System.out.println("imageURL: " + imageURL + ",读取失败!"); + return null; + } finally { + try { + if (is!=null) { + is.close(); + } + } catch (IOException e) { + e.printStackTrace(); + System.out.println("imageURL: " + imageURL + ",流关闭异常!"); + return null; + } + } + return bufferedImage; + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/qccode/vo/QRCodeConfig.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/qccode/vo/QRCodeConfig.java new file mode 100644 index 0000000..32a2337 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/qccode/vo/QRCodeConfig.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.framework.common.util.qccode.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + + +@Schema(description = "QRCodeConfig 二维码 vo") +@Data +@EqualsAndHashCode(callSuper = false) +@ToString(callSuper = true) +public class QRCodeConfig { + // 二维码内容 + @Schema(description = "二维码内容", requiredMode = Schema.RequiredMode.REQUIRED,defaultValue = "我是二维码的内容") + private String content; + + // 二维码的宽度 + @Schema(description = "二维码的宽度", requiredMode = Schema.RequiredMode.REQUIRED,defaultValue = "800") + private int width; + + // 二维码的高度 + @Schema(description = "二维码的高度", requiredMode = Schema.RequiredMode.REQUIRED,defaultValue = "800") + private int height; + + // 二维码的图片格式,如"png", "jpg"等 + @Schema(description = "二维码的高度", requiredMode = Schema.RequiredMode.REQUIRED,defaultValue = "png") + private String imageFormat; + + // 附加资源或相关信息(具体含义根据项目需求定义) + /*private String resource;*/ +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java index 62755fc..edc857c 100644 --- a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java @@ -1,19 +1,27 @@ package cn.iocoder.yudao.module.infra.controller.app.file; +import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IoUtil; +import cn.hutool.core.lang.UUID; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.qccode.QRCodeUtil; +import cn.iocoder.yudao.framework.common.util.qccode.vo.QRCodeConfig; import cn.iocoder.yudao.module.infra.controller.app.file.vo.AppFileUploadReqVO; import cn.iocoder.yudao.module.infra.service.file.FileService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import javax.validation.Valid; + +import java.io.*; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -35,4 +43,34 @@ public class AppFileController { return success(fileService.createFile(file.getOriginalFilename(), path, IoUtil.readBytes(file.getInputStream()))); } + @GetMapping("/qrCode") + @Operation(summary = "生成二维码") + public CommonResult qrCode(@Valid QRCodeConfig qrCodeConfig) { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + // 假设QRCodeUtil.createQrCode是一个正确实现的方法,用于生成二维码并写入到ByteArrayOutputStream中 + QRCodeUtil.createQrCode(out, qrCodeConfig.getContent(), qrCodeConfig.getWidth(), qrCodeConfig.getHeight(), qrCodeConfig.getImageFormat(), ""); // 使用PNG格式,不是JPG + // 创建文件,使用PNG扩展名,因为QR码是以PNG格式生成的 + File file = FileUtil.file(UUID.fastUUID()+"."+qrCodeConfig.getImageFormat()); // 注意文件扩展名应为.png + byte[] imageBytes = out.toByteArray(); + // 使用 FileOutputStream 将字节数组写入本地文件 + try (FileOutputStream fos = new FileOutputStream(file)) { + fos.write(imageBytes); + } + // 输出文件名和位置 + //System.out.println("文件名: " + file.getName()); + //System.out.println("文件位置: " + file.getAbsolutePath()); + // 假设fileService.createFile是一个正确实现的方法,用于在您的服务中创建文件记录 + // 读取文件内容并传递给createFile方法 + byte[] fileContent = IoUtil.readBytes(new FileInputStream(file)); // 使用FileInputStream读取文件内容 + String url = fileService.createFile(file.getName(), UUID.fastUUID()+"."+qrCodeConfig.getImageFormat(), fileContent); + out.close(); // 关闭ByteArrayOutputStream,虽然在这个上下文中它会在方法结束时自动关闭 + return success(url); + } catch (IOException e) { + e.printStackTrace(); // 适当的错误处理应该替换这一行,例如记录日志或向用户显示错误消息 + } + + return success(""); + } + }