| | |
| | | package com.ruoyi.web.controller.smartor; |
| | | |
| | | import com.google.zxing.BarcodeFormat; |
| | | import com.google.zxing.EncodeHintType; |
| | | import com.google.zxing.WriterException; |
| | | import com.google.zxing.client.j2se.MatrixToImageWriter; |
| | | import com.google.zxing.common.BitMatrix; |
| | | import com.google.zxing.qrcode.QRCodeWriter; |
| | | import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; |
| | | import com.mchange.v2.uid.UidUtils; |
| | | import com.ruoyi.common.core.domain.AjaxResult; |
| | | import com.ruoyi.framework.config.ServerConfig; |
| | |
| | | import org.springframework.http.MediaType; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import javax.imageio.ImageIO; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.awt.Color; |
| | | import java.awt.Graphics2D; |
| | | import java.awt.RenderingHints; |
| | | import java.awt.image.BufferedImage; |
| | | import java.io.File; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.io.StringWriter; |
| | | import java.net.URI; |
| | | import java.util.*; |
| | | |
| | | @Slf4j |
| | |
| | | |
| | | @Value("${ruoyi.profile}") |
| | | private String profile; |
| | | |
| | | /** |
| | | * 公司logo在classpath中的路径,打包进jar后任何环境都能读取到 |
| | | */ |
| | | private static final String LOGO_CLASSPATH = "/images/hrslogo.png"; |
| | | |
| | | @Autowired |
| | | private ServerConfig serverConfig; |
| | |
| | | @PostMapping(value = "/getQRcode") |
| | | public AjaxResult getQRcode(@RequestParam("url") String url) { |
| | | log.info("获取问卷二维码的入参:{}", url); |
| | | String uuid = UUID.randomUUID().toString().replace("-", ""); |
| | | String filePath = profile + "\\qrpath" + "\\" + uuid + ".png"; // 保存二维码图像的文件路径 |
| | | // 尝试从url中提取p参数的值作为图片名称,值为空则用UUID |
| | | String fileName = UUID.randomUUID().toString().replace("-", ""); |
| | | try { |
| | | URI uri = new URI(url); |
| | | String query = uri.getQuery(); |
| | | if (query != null) { |
| | | for (String param : query.split("&")) { |
| | | String[] pair = param.split("=", 2); |
| | | if ("p".equals(pair[0]) && pair.length > 1 && !pair[1].isEmpty()) { |
| | | fileName = pair[1] + "-" + System.currentTimeMillis(); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | log.warn("解析url中的p参数失败,使用UUID作为文件名"); |
| | | } |
| | | String filePath = profile + "\\qrpath" + "\\" + fileName + ".png"; // 保存二维码图像的文件路径 |
| | | //判断文件夹是否存在 |
| | | File file = new File(profile + "\\qrpath"); |
| | | if (!file.exists()) { |
| | | file.mkdirs(); |
| | | } |
| | | generateQRCode(url, filePath); |
| | | return AjaxResult.success(serverConfig.getUrl() + "/profile/qrpath/" + uuid + ".png"); |
| | | return AjaxResult.success(serverConfig.getUrl() + "/profile/qrpath/" + fileName + ".png"); |
| | | } |
| | | |
| | | private void generateQRCode(String url, String filePath) { |
| | | QRCodeWriter qrCodeWriter = new QRCodeWriter(); |
| | | try { |
| | | BitMatrix bitMatrix = qrCodeWriter.encode(url, BarcodeFormat.QR_CODE, 500, 500); |
| | | // 使用高容错级别(H级,30%容错),确保二维码中间嵌入logo后仍可正常扫描 |
| | | Map<EncodeHintType, Object> hints = new HashMap<>(); |
| | | hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); |
| | | hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); |
| | | hints.put(EncodeHintType.MARGIN, 1); |
| | | |
| | | BitMatrix bitMatrix = qrCodeWriter.encode(url, BarcodeFormat.QR_CODE, 500, 500, hints); |
| | | |
| | | // 将BitMatrix转为二值BufferedImage(黑白) |
| | | BufferedImage binaryImage = MatrixToImageWriter.toBufferedImage(bitMatrix); |
| | | |
| | | // 创建RGB彩色图像,把二维码画上去,否则后续绘制logo会丢失颜色 |
| | | BufferedImage qrImage = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB); |
| | | Graphics2D graphics = qrImage.createGraphics(); |
| | | graphics.setColor(Color.WHITE); |
| | | graphics.fillRect(0, 0, 500, 500); |
| | | graphics.drawImage(binaryImage, 0, 0, null); |
| | | |
| | | // 从classpath读取logo并绘制到二维码中间 |
| | | try (InputStream logoStream = this.getClass().getResourceAsStream(LOGO_CLASSPATH)) { |
| | | if (logoStream != null) { |
| | | BufferedImage logoImage = ImageIO.read(logoStream); |
| | | |
| | | // 计算logo尺寸,设为二维码的1/5 |
| | | int logoWidth = qrImage.getWidth() / 5; |
| | | int logoHeight = qrImage.getHeight() / 5; |
| | | |
| | | // 计算logo居中位置 |
| | | int logoX = (qrImage.getWidth() - logoWidth) / 2; |
| | | int logoY = (qrImage.getHeight() - logoHeight) / 2; |
| | | |
| | | // 绘制白色圆角背景,让logo更突出 |
| | | int padding = 6; |
| | | graphics.setColor(Color.WHITE); |
| | | graphics.fillRoundRect(logoX - padding, logoY - padding, logoWidth + padding * 2, logoHeight + padding * 2, 10, 10); |
| | | |
| | | // 绘制logo |
| | | graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); |
| | | graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); |
| | | graphics.drawImage(logoImage, logoX, logoY, logoWidth, logoHeight, null); |
| | | } else { |
| | | log.warn("classpath中未找到二维码logo: {}", LOGO_CLASSPATH); |
| | | } |
| | | } |
| | | graphics.dispose(); |
| | | |
| | | // 输出最终图片 |
| | | File outputFile = new File(filePath); |
| | | MatrixToImageWriter.writeToPath(bitMatrix, "PNG", outputFile.toPath()); |
| | | ImageIO.write(qrImage, "PNG", outputFile); |
| | | } catch (WriterException | IOException e) { |
| | | e.printStackTrace(); |
| | | } |