|
@@ -0,0 +1,314 @@
|
|
|
|
+package com.iotechn.unimall.data.util;
|
|
|
|
+
|
|
|
|
+import com.aliyun.oss.OSSClient;
|
|
|
|
+import com.aliyun.oss.model.ObjectMetadata;
|
|
|
|
+import com.aliyun.oss.model.PutObjectRequest;
|
|
|
|
+import com.google.zxing.BarcodeFormat;
|
|
|
|
+import com.google.zxing.EncodeHintType;
|
|
|
|
+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 lombok.Getter;
|
|
|
|
+import lombok.SneakyThrows;
|
|
|
|
+import org.apache.http.entity.ContentType;
|
|
|
|
+import org.springframework.beans.factory.InitializingBean;
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
|
+import org.springframework.core.io.ClassPathResource;
|
|
|
|
+import org.springframework.mock.web.MockMultipartFile;
|
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
|
+import org.springframework.util.StringUtils;
|
|
|
|
+import org.springframework.web.multipart.MultipartFile;
|
|
|
|
+import sun.font.FontDesignMetrics;
|
|
|
|
+
|
|
|
|
+import javax.imageio.ImageIO;
|
|
|
|
+import java.awt.*;
|
|
|
|
+import java.awt.font.FontRenderContext;
|
|
|
|
+import java.awt.font.LineMetrics;
|
|
|
|
+import java.awt.geom.RoundRectangle2D;
|
|
|
|
+import java.awt.image.BufferedImage;
|
|
|
|
+import java.io.*;
|
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
|
+import java.nio.file.FileSystems;
|
|
|
|
+import java.nio.file.Path;
|
|
|
|
+import java.util.HashMap;
|
|
|
|
+import java.util.Hashtable;
|
|
|
|
+import java.util.Properties;
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * @Author:chengchangjiang
|
|
|
|
+ * @Description: 二维码Util类
|
|
|
|
+ * @Date:Created in 9:38 2021-09-03
|
|
|
|
+ */
|
|
|
|
+@Component
|
|
|
|
+public class QRCodeUtil implements InitializingBean {
|
|
|
|
+
|
|
|
|
+ @Value("${oss.aliyun.oss.basekUrl}")
|
|
|
|
+ private String baseUrl;
|
|
|
|
+ @Value("${oss.aliyun.oss.bucket}")
|
|
|
|
+ private String bucket;
|
|
|
|
+ @Autowired
|
|
|
|
+ private OSSClient ossClient;
|
|
|
|
+ @Value("${oss.aliyun.oss.endpoint}")
|
|
|
|
+ private String endpoint;
|
|
|
|
+
|
|
|
|
+ private String host;
|
|
|
|
+ @Override
|
|
|
|
+ public void afterPropertiesSet() throws Exception {
|
|
|
|
+ host = "http://" + bucket + "." + endpoint;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /***
|
|
|
|
+ * 生成二维码图片并上传OSS
|
|
|
|
+ * @param text 二维码内容
|
|
|
|
+ * @param width 宽度
|
|
|
|
+ * @param height 高度
|
|
|
|
+ * @param type 类型
|
|
|
|
+ * @param name 图片名字
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ public String generateQRCodeImage(String text, int width, int height,String type,String name){
|
|
|
|
+ try {
|
|
|
|
+ QRCodeWriter qrCodeWriter = new QRCodeWriter();
|
|
|
|
+ Hashtable<EncodeHintType, Object> hints = new Hashtable();
|
|
|
|
+ hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
|
|
|
|
+ BitMatrix bitMatrix = qrCodeWriter.encode(type+"="+text, BarcodeFormat.QR_CODE, width, height,hints);
|
|
|
|
+
|
|
|
|
+ File file = new File( new String(("templates" + File.separator + name+".png").getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8));
|
|
|
|
+ if(!file.exists()){
|
|
|
|
+ boolean flag = file.mkdirs();
|
|
|
|
+ }
|
|
|
|
+ Path path = FileSystems.getDefault().getPath(file.getAbsoluteFile().getPath());
|
|
|
|
+
|
|
|
|
+ MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);
|
|
|
|
+
|
|
|
|
+ FileInputStream fileInputStream = new FileInputStream(file.getAbsoluteFile());
|
|
|
|
+
|
|
|
|
+ MultipartFile multipartFile = new MockMultipartFile( ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStream);
|
|
|
|
+ String result = upload(multipartFile,name);
|
|
|
|
+ file.delete();
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+ catch (Exception e){
|
|
|
|
+ System.out.println("二维码异常:"+e.toString());
|
|
|
|
+ return "error";
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ /**
|
|
|
|
+ * 后台通过服务器间接传文件
|
|
|
|
+ * @param file
|
|
|
|
+ * @return
|
|
|
|
+ * @throws IOException
|
|
|
|
+ */
|
|
|
|
+ public String upload(MultipartFile file, String sendCarNo) throws IOException {
|
|
|
|
+ ObjectMetadata objectMetadata = new ObjectMetadata();
|
|
|
|
+ objectMetadata.setContentLength(file.getSize());
|
|
|
|
+ objectMetadata.setContentType(file.getContentType());
|
|
|
|
+ PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, "QRCode/" +sendCarNo+".png", file.getInputStream(), objectMetadata);
|
|
|
|
+ ossClient.putObject(putObjectRequest);
|
|
|
|
+ return baseUrl + "QRCode/" + sendCarNo+".png";
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static final int QRCODE_SIZE = 320; // 二维码尺寸,宽度和高度均是320
|
|
|
|
+ private static final String FORMAT_TYPE = "PNG"; // 二维码图片类型
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+// //1、生成带logo和底部文字得二维码
|
|
|
|
+// @SneakyThrows
|
|
|
|
+// @GetMapping("/getQrCode1")
|
|
|
|
+// public void getQrCode1(HttpServletResponse response) {
|
|
|
|
+// ServletOutputStream os = response.getOutputStream();
|
|
|
|
+// BufferedImage bufferedImage = QRCodeUtil.getQRCodeImage("test", "底部文字");
|
|
|
|
+// response.setContentType("image/png");
|
|
|
|
+// ImageIO.write(bufferedImage,"png",os);
|
|
|
|
+// }
|
|
|
|
+// //2、生成不带logo和底部文字得二维码
|
|
|
|
+// @SneakyThrows
|
|
|
|
+// @GetMapping("/getQrCode2")
|
|
|
|
+// public void getQrCode2(HttpServletResponse response) {
|
|
|
|
+// ServletOutputStream os = response.getOutputStream();
|
|
|
|
+// BufferedImage bufferedImage = QRCodeUtil.getQRCodeImage("test", false);
|
|
|
|
+// response.setContentType("image/png");
|
|
|
|
+// ImageIO.write(bufferedImage,"png",os);
|
|
|
|
+// }
|
|
|
|
+// //3、生成默认带logo不带底部文字得二维码
|
|
|
|
+// @SneakyThrows
|
|
|
|
+// @GetMapping("/getQrCode3")
|
|
|
|
+// public void getQrCode3(HttpServletResponse response) {
|
|
|
|
+// ServletOutputStream os = response.getOutputStream();
|
|
|
|
+// BufferedImage bufferedImage = QRCodeUtil.generateQRCodeImage("test");
|
|
|
|
+// response.setContentType("image/png");
|
|
|
|
+// ImageIO.write(bufferedImage,"png",os);
|
|
|
|
+// }
|
|
|
|
+// //3、生成不带logo带底部文字得二维码
|
|
|
|
+// @SneakyThrows
|
|
|
|
+// public getQrCode3(HttpServletResponse response) {
|
|
|
|
+// ServletOutputStream os = response.getOutputStream();
|
|
|
|
+// BufferedImage bufferedImage = QRCodeUtil.getQRCodeImage("test",false,
|
|
|
|
+// "底部文字");
|
|
|
|
+// response.setContentType("image/png");
|
|
|
|
+// ImageIO.write(bufferedImage,"png",os);
|
|
|
|
+// }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取二维码图片
|
|
|
|
+ *
|
|
|
|
+ * @param dataStr 二维码内容
|
|
|
|
+ * @param needLogo 是否需要添加logo
|
|
|
|
+ * @param bottomText 底部文字 为空则不显示
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ @SneakyThrows
|
|
|
|
+ public String getQRCodeImage(String dataStr, boolean needLogo, String bottomText ,String name) {
|
|
|
|
+ if (dataStr == null) {
|
|
|
|
+ throw new RuntimeException("未包含任何信息");
|
|
|
|
+ }
|
|
|
|
+ HashMap<EncodeHintType, Object> hints = new HashMap<>();
|
|
|
|
+ hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); //定义内容字符集的编码
|
|
|
|
+ hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); //定义纠错等级
|
|
|
|
+ hints.put(EncodeHintType.MARGIN, 1);
|
|
|
|
+ QRCodeWriter qrCodeWriter = new QRCodeWriter();
|
|
|
|
+ BitMatrix bitMatrix = qrCodeWriter.encode(dataStr, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
|
|
|
|
+
|
|
|
|
+ int width = bitMatrix.getWidth();
|
|
|
|
+ int height = bitMatrix.getHeight();
|
|
|
|
+ int tempHeight = height;
|
|
|
|
+ if (StringUtils.hasText(bottomText)) {
|
|
|
|
+ tempHeight = tempHeight + 12;
|
|
|
|
+ }
|
|
|
|
+ BufferedImage image = new BufferedImage(width, tempHeight, 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);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 判断是否添加logo
|
|
|
|
+ if (needLogo) {
|
|
|
|
+ insertLogoImage(image);
|
|
|
|
+ }
|
|
|
|
+ // 判断是否添加底部文字
|
|
|
|
+ if (StringUtils.hasText(bottomText)) {
|
|
|
|
+ addFontImage(image, bottomText);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ File file = new File( new String(("templates" + File.separator + name+".png").getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8));
|
|
|
|
+ if(!file.exists()){
|
|
|
|
+ boolean flag = file.mkdirs();
|
|
|
|
+ }
|
|
|
|
+ Path path = FileSystems.getDefault().getPath(file.getAbsoluteFile().getPath());
|
|
|
|
+
|
|
|
|
+// ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
|
|
+// ImageIO.write(image,"png",path);
|
|
|
|
+// MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);
|
|
|
|
+
|
|
|
|
+ //创建一个ByteArrayOutputStream
|
|
|
|
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
|
|
|
|
+ //把BufferedImage写入ByteArrayOutputStream
|
|
|
|
+ ImageIO.write(image, "png", os);
|
|
|
|
+ //ByteArrayOutputStream转成InputStream
|
|
|
|
+ InputStream input = new ByteArrayInputStream(os.toByteArray());
|
|
|
|
+ //InputStream转成MultipartFile
|
|
|
|
+ MultipartFile multipartFile =new MockMultipartFile("file", "file.jpg", "text/plain", input);
|
|
|
|
+
|
|
|
|
+// FileInputStream fileInputStream = new FileInputStream(file.getAbsoluteFile());
|
|
|
|
+// MultipartFile multipartFile = new MockMultipartFile( ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStream);
|
|
|
|
+ String result = upload(multipartFile,name);
|
|
|
|
+ file.delete();
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 插入logo图片
|
|
|
|
+ *
|
|
|
|
+ * @param source 二维码图片
|
|
|
|
+ * @throws Exception
|
|
|
|
+ */
|
|
|
|
+ private static void insertLogoImage(BufferedImage source) throws Exception {
|
|
|
|
+ // 默认logo放于resource/static/image目录下
|
|
|
|
+ ClassPathResource classPathResource = new ClassPathResource("static/image/logo.png");
|
|
|
|
+ InputStream inputStream = classPathResource.getInputStream();
|
|
|
|
+ if (inputStream == null || inputStream.available() == 0) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ Image src = ImageIO.read(inputStream);
|
|
|
|
+ int width = 30;
|
|
|
|
+ int height = 30;
|
|
|
|
+
|
|
|
|
+ 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();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static void addFontImage(BufferedImage source, String declareText) {
|
|
|
|
+ //生成image
|
|
|
|
+ int defineWidth = QRCODE_SIZE;
|
|
|
|
+ int defineHeight = 20;
|
|
|
|
+ BufferedImage textImage = new BufferedImage(defineWidth, defineHeight, BufferedImage.TYPE_INT_RGB);
|
|
|
|
+ Graphics2D g2 = (Graphics2D) textImage.getGraphics();
|
|
|
|
+ //开启文字抗锯齿
|
|
|
|
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
|
|
|
+ g2.setBackground(Color.WHITE);
|
|
|
|
+ g2.clearRect(0, 0, defineWidth, defineHeight);
|
|
|
|
+ g2.setPaint(Color.BLACK);
|
|
|
|
+ FontRenderContext context = g2.getFontRenderContext();
|
|
|
|
+ String font_cn = getChineseFont();
|
|
|
|
+ //部署linux需要注意 linux无此字体会显示方块
|
|
|
|
+ Font font = new Font("宋体", Font.BOLD, 18);
|
|
|
|
+
|
|
|
|
+ g2.setFont(font);
|
|
|
|
+ LineMetrics lineMetrics = font.getLineMetrics(declareText, context);
|
|
|
|
+ FontMetrics fontMetrics = FontDesignMetrics.getMetrics(font);
|
|
|
|
+ float offset = (defineWidth - fontMetrics.stringWidth(declareText)) / 2;
|
|
|
|
+ float y = (defineHeight + lineMetrics.getAscent() - lineMetrics.getDescent() - lineMetrics.getLeading()) / 2;
|
|
|
|
+ g2.drawString(declareText, (int) offset, (int) y);
|
|
|
|
+
|
|
|
|
+ Graphics2D graph = source.createGraphics();
|
|
|
|
+ //开启文字抗锯齿
|
|
|
|
+ graph.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
|
|
|
+ //添加image
|
|
|
|
+ int width = textImage.getWidth(null);
|
|
|
|
+ int height = textImage.getHeight(null);
|
|
|
|
+
|
|
|
|
+ Image src = textImage;
|
|
|
|
+ graph.drawImage(src, 0, QRCODE_SIZE - 8, width, height, Color.WHITE, null);
|
|
|
|
+ graph.dispose();
|
|
|
|
+ }
|
|
|
|
+ /**
|
|
|
|
+ * 获取中文字体位置
|
|
|
|
+ *
|
|
|
|
+ * @return
|
|
|
|
+ * @author xxj 2017年4月28日
|
|
|
|
+ */
|
|
|
|
+ private static String getChineseFont() {
|
|
|
|
+
|
|
|
|
+ //宋体(对应css中的 属性 font-family: SimSun; /*宋体*/)
|
|
|
|
+ String font1 = "templates" + File.separator + "msyh.ttc";
|
|
|
|
+// String font1 = "templates" + File.separator + "simsun.ttf";
|
|
|
|
+ //判断系统类型,加载字体文件
|
|
|
|
+ Properties prop = System.getProperties();
|
|
|
|
+ String osName = prop.getProperty("os.name").toLowerCase();
|
|
|
|
+ System.out.println(osName);
|
|
|
|
+ if (osName.indexOf("linux") > -1) {
|
|
|
|
+ font1 = "/usr/share/fonts/chinese/simsun.ttc";
|
|
|
|
+ }
|
|
|
|
+ else{
|
|
|
|
+ font1 = "宋体";
|
|
|
|
+ }
|
|
|
|
+ return font1;
|
|
|
|
+ }
|
|
|
|
+}
|