Browse Source

二维码加文字

peiguo 5 năm trước cách đây
mục cha
commit
1813fad91c

+ 2 - 0
whepi-doc/login.sql

@@ -243,6 +243,8 @@ CREATE TABLE sys_uptown_door  (
   door_id           bigint(20) NOT NULL DEFAULT 0 COMMENT '小区大门ID',
   uptown_id         bigint(20) NOT NULL DEFAULT 0 COMMENT '小区ID',
   door_name         varchar(20)  NOT NULL DEFAULT '' COMMENT '大门名称',
+  in_img            varchar(100)  NOT NULL DEFAULT '' COMMENT '入口二维码',
+  out_img           varchar(100)  NOT NULL DEFAULT '' COMMENT '出口二维码',
   status            int(11) NOT NULL DEFAULT 0 COMMENT '状态:1正常,0草稿,-1删除',
   time_create       datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '新增时间',
   time_update       datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '修改时间',

+ 8 - 0
whepi-web/src/main/java/com/bofeng/dao/UptownDoorMapper.java

@@ -6,6 +6,7 @@ import com.yvan.PageDb;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
 import org.springframework.stereotype.Repository;
 
 import java.util.List;
@@ -21,4 +22,11 @@ public interface UptownDoorMapper extends BaseMapper<UptownDoor> {
 
     List<UptownDoor> getAllUptownDoor(PageDb pagination, Map<String, Object> map);
 
+    /**
+     * 更改小区大门的二维码
+     * @param doorId
+     * @return
+     */
+    Integer updateDoorQc(@Param("qcName") String qcName, @Param("img") String img, @Param("doorId") Long doorId);
+
 }

+ 8 - 7
whepi-web/src/main/java/com/bofeng/entity/UptownDoor.java

@@ -28,6 +28,14 @@ public class UptownDoor {
     @TableField("door_name")
     private String doorName;
 
+    @ApiModelProperty("入口二维码")
+    @TableField("in_img")
+    private String inImg;
+
+    @ApiModelProperty("出口二维码")
+    @TableField("out_img")
+    private String outImg;
+
     @ApiModelProperty("状态:1正常,0草稿,-1删除")
     @TableField("status")
     private Integer status;
@@ -45,11 +53,4 @@ public class UptownDoor {
     @ApiModelProperty("出门间隔时间")
     @TableField(exist = false)
     private Integer goOutFre;
-
-    @TableField(exist = false)
-    private String inImg;
-
-    @TableField(exist = false)
-    private String outImg;
-
 }

+ 214 - 0
whepi-web/src/main/java/com/bofeng/unit/QRCode.java

@@ -0,0 +1,214 @@
+package com.bofeng.unit;
+
+import com.baomidou.mybatisplus.toolkit.IdWorker;
+import com.google.common.base.Strings;
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.EncodeHintType;
+import com.google.zxing.MultiFormatWriter;
+import com.google.zxing.WriterException;
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
+import org.apache.commons.codec.binary.Base64;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+public class QRCode {
+
+    private static String programUploadPath = "D:\\uoplad\\whepi";
+
+    /**
+     * CODE_WIDTH:二维码宽度,单位像素
+     * CODE_HEIGHT:二维码高度,单位像素
+     * FRONT_COLOR:二维码前景色,0x000000 表示黑色
+     * BACKGROUND_COLOR:二维码背景色,0xFFFFFF 表示白色
+     * 演示用 16 进制表示,和前端页面 CSS 的取色是一样的,注意前后景颜色应该对比明显,如常见的黑白
+     */
+    private static final int CODE_WIDTH = 256;
+    private static final int CODE_HEIGHT = 256;
+    private static final int FRONT_COLOR = 0x000000;
+    private static final int BACKGROUND_COLOR = 0xFFFFFF;
+
+    public static BufferedImage createQRCode(String content, BufferedImage bufferedImage, int topFontWidth, int topFontHeight, int bottomFontWidth, int bottomFontHeight) throws WriterException {
+        //检验参数
+        if (content == null || "".equals(content)) {
+            return null;
+        }
+        if (bufferedImage == null) {
+            return null;
+        }
+        content = content.trim();
+        int width = bufferedImage.getWidth();
+        int height = bufferedImage.getHeight();
+        int startBottomY = height + topFontHeight;
+        height = startBottomY + bottomFontHeight;
+        /**com.google.zxing.EncodeHintType:编码提示类型,枚举类型
+         * EncodeHintType.CHARACTER_SET:设置字符编码类型
+         * EncodeHintType.ERROR_CORRECTION:设置误差校正
+         * ErrorCorrectionLevel:误差校正等级,L = ~7% correction、M = ~15% correction、Q = ~25% correction、H = ~30% correction
+         * 不设置时,默认为 L 等级,等级不一样,生成的图案不同,但扫描的结果是一样的
+         * EncodeHintType.MARGIN:设置二维码边距,单位像素,值越小,二维码距离四周越近
+         * */
+        Map<EncodeHintType, Object> hints = new HashMap();
+        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
+        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.Q);
+        hints.put(EncodeHintType.MARGIN, 1);
+
+        /**
+         * MultiFormatWriter:多格式写入,这是一个工厂类,里面重载了两个 encode 方法,用于写入条形码或二维码
+         * encode(String contents,BarcodeFormat format,int width, int height,Map<EncodeHintType,?> hints)
+         *  contents:条形码/二维码内容
+         *  format:编码类型,如 条形码,二维码 等
+         *  width:码的宽度
+         *  height:码的高度
+         *  hints:码内容的编码类型
+         * BarcodeFormat:枚举该程序包已知的条形码格式,即创建何种码,如 1 维的条形码,2 维的二维码 等
+         * BitMatrix:位(比特)矩阵或叫2D矩阵,也就是需要的二维码
+         */
+        MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
+        BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
+
+        /**java.awt.image.BufferedImage:具有图像数据的可访问缓冲图像,实现了 RenderedImage 接口
+         * BitMatrix 的 get(int x, int y) 获取比特矩阵内容,指定位置有值,则返回true,将其设置为前景色,否则设置为背景色
+         * BufferedImage 的 setRGB(int x, int y, int rgb) 方法设置图像像素
+         * x:像素位置的横坐标,即列
+         * y:像素位置的纵坐标,即行
+         * rgb:像素的值,采用 16 进制,如 0xFFFFFF 白色
+         */
+        BufferedImage newBufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
+        for (int x = 0; x < width; x++) {
+            for (int y = 0; y < height; y++) {
+                //顶部文字填充区域设置为空白
+                if (y <= topFontHeight) {
+                    newBufferedImage.setRGB(x, y, BACKGROUND_COLOR);
+                }
+                //底部文字填充区域设置为空白
+                else if (y > startBottomY) {
+                    newBufferedImage.setRGB(x, y, BACKGROUND_COLOR);
+                } else {
+                    newBufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? FRONT_COLOR : BACKGROUND_COLOR);
+                }
+            }
+        }
+        bufferedImage = null; //主动释放
+        return newBufferedImage;
+    }
+
+    public static String createBase64Img(String content, String topFont, String bottomFont) throws WriterException, IOException {
+        BufferedImage bufferedImage = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_INT_RGB);
+        if (content == null || "".equals(content)) {
+            return  null;
+        }
+        topFont = topFont == null ? "" : topFont;
+        bottomFont = bottomFont == null ? "" : bottomFont;
+        bufferedImage = pressTextInImage(bufferedImage, content, topFont, bottomFont);
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        //写入流中
+        ImageIO.write(bufferedImage, "jpg", outputStream);
+        //转换成字节
+        byte[] bytes = outputStream.toByteArray();
+        //对字节数组Base64编码  -- 转换成base64串
+	   /* BASE64Encoder encoder = new BASE64Encoder();
+	    String base64Img = encoder.encodeBuffer(bytes).trim();*/
+        Base64 encoder = new Base64();
+        String base64Img = encoder.encodeToString(bytes);
+
+        //删除 \r\n
+        base64Img = base64Img.replaceAll("\n", "").replaceAll("\r", "");
+        //前面加 data:image/jpg;base64,
+        String res = "data:image/jpg;base64," + base64Img.toString();
+        //关闭流
+        if (outputStream != null) {
+            outputStream.close();
+        }
+//        System.out.println(res);
+        return decryptByBase64(res);
+    }
+
+    public static BufferedImage pressTextInImage(BufferedImage bufferedImage, String content, String topFont, String bottomFont) throws WriterException {
+        if (bufferedImage == null) {
+            return null;
+        }
+        //图片绘制对象 Color.RED
+        Graphics graphics = bufferedImage.createGraphics();
+        Font font = new Font("黑体", 5, 18);
+        FontMetrics metrics = graphics.getFontMetrics(font);
+        //获取底部字体的宽和高
+        int bottomFontWidth = metrics.stringWidth(bottomFont);
+        int bottomFontHeight = metrics.getHeight();
+        //获取顶部字体的宽和高
+        int topFontWidth = metrics.stringWidth(topFont);
+        int topFontHeight = metrics.getHeight();
+        //将image生成二维码图片对象
+        bufferedImage = createQRCode(content, bufferedImage, topFontWidth, topFontHeight, bottomFontWidth, bottomFontHeight);
+        //获取二维码图片的宽和高
+        int imageW = bufferedImage.getWidth();
+        int imageH = bufferedImage.getHeight();
+        //计算顶部文字填充位置
+        int topStartX = (imageW - topFontWidth) / 2; //居中显示
+        int topStartY = topFontHeight;
+        //计算底部文字填充位置
+        int bottomStartX = (imageW - bottomFontWidth) / 2; //居中显示
+        int bottomStartY = (imageH - bottomFontHeight) + 2;
+
+        //文字图片对象
+        BufferedImage textImag = new BufferedImage(imageW, imageH, BufferedImage.TYPE_INT_RGB);
+        Graphics textGraphics = textImag.createGraphics();
+        //画图
+        textGraphics.drawImage(bufferedImage, 0, 0, imageW, imageH, null);
+        // 写底部文字
+        textGraphics.setColor(Color.RED);
+        textGraphics.setFont(font);
+        textGraphics.drawString(bottomFont, bottomStartX, bottomStartY);
+        //写顶部字体
+        textGraphics.setColor(Color.RED);
+        textGraphics.setFont(font);
+        textGraphics.drawString(topFont, topStartX, topStartY);
+        graphics.dispose();
+        return textImag;
+    }
+
+    /**
+     * base64转存文件
+     * @param base64
+     * @return
+     */
+    public static String decryptByBase64(String base64) {
+        SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd");
+        if (Strings.isNullOrEmpty(base64)) {
+            return "";
+        }
+        String filePath = programUploadPath + sdf.format(new Date()) + "/" + IdWorker.getId() + ".jpg";
+        File path = new File(programUploadPath + sdf.format(new Date()));
+        if (!path.exists()) {
+            path.mkdirs();
+        }
+        try {
+            Files.write(Paths.get(filePath),
+                    Base64.decodeBase64(base64.substring(base64.indexOf(",") + 1)), StandardOpenOption.CREATE);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return filePath.replace(programUploadPath, "");
+    }
+
+    public static void main(String[] args) throws IOException, WriterException {
+        Long startTime = System.currentTimeMillis();
+        System.out.println("******************************");
+        String file = createBase64Img("https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx02a4ee296708dfd4&redirect_uri=http%3A%2F%2Fpeiguo.ng.yvanui.com%2Fuser%2FscanEstate.html&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect", "家园互助平台", "巡检扫码");
+        Long endTime = System.currentTimeMillis();
+        System.out.println(file);
+        System.out.println((endTime - startTime) + " |" +(endTime - startTime)/ 1000);
+    }
+}

+ 47 - 18
whepi-web/src/main/java/com/bofeng/wx/controller/ScanAdminController.java

@@ -1,10 +1,12 @@
 package com.bofeng.wx.controller;
 
+import cn.afterturn.easypoi.cache.manager.IFileLoader;
 import com.bofeng.dao.UptownDoorMapper;
 import com.bofeng.entity.SysUptownHouse;
 import com.bofeng.entity.UptownDoor;
 import com.bofeng.excel.ExcelUtils;
 import com.bofeng.service.SweepCodeService;
+import com.bofeng.unit.QRCode;
 import com.google.zxing.BarcodeFormat;
 import com.google.zxing.MultiFormatWriter;
 import com.google.zxing.WriterException;
@@ -60,11 +62,19 @@ public class ScanAdminController {
 
     @ApiOperation("小区进出二维码")
     @PostMapping("/whepi/qrImg/scanQrImg")
-    public Model<List<UptownDoor>> scanQrImg(HttpParameterParser parser, PageDb pagination) {
+    public Model<List<UptownDoor>> scanQrImg(HttpParameterParser parser, PageDb pagination) throws IOException, WriterException {
         List<UptownDoor> list = uptownDoorMapper.getAllUptownDoor(pagination, parser.getMap());
         for (UptownDoor door : list) {
-            door.setInImg("/whepi/scan/scan_qr.png?doorId=" + door.getDoorId() + "&inType=1");
-            door.setOutImg("/whepi/scan/scan_qr.png?doorId=" + door.getDoorId() + "&inType=2");
+            if (door.getInImg().equals("")) {
+                String img = scan_qr(door.getDoorId(),1,door.getUptownName()+door.getDoorName()+getName(1));
+                uptownDoorMapper.updateDoorQc("in_img", img, door.getDoorId());
+                door.setInImg(img);
+            }
+            if (door.getOutImg().equals("")) {
+                String img = scan_qr(door.getDoorId(),2,door.getUptownName()+door.getDoorName()+getName(2));
+                uptownDoorMapper.updateDoorQc("out_img", img, door.getDoorId());
+                door.setOutImg(img);
+            }
         }
         return Model.newSuccess(pagination, list);
     }
@@ -85,14 +95,18 @@ public class ScanAdminController {
      * @throws IOException
      * @throws WriterException
      */
-    @GetMapping(value = "/whepi/scan/scan_qr.png", produces = MediaType.IMAGE_PNG_VALUE)
-    public void scanQrImg(@Pd(name = "doorId") Long doorId, @Pd(name = "inType") Integer inType,
-                          HttpServletResponse response) throws IOException, WriterException {
-        @Cleanup ServletOutputStream outputStream = response.getOutputStream();
-        String msg = URLEncoder.encode( domain + "user/scan.html?doorId=" + doorId + "&inType=" + inType,"utf-8");
-        BitMatrix matrix = new MultiFormatWriter().encode(oauth2 + appId + "&redirect_uri=" +
-                msg + moreUrl, BarcodeFormat.QR_CODE, 256, 256);
-        MatrixToImageWriter.writeToStream(matrix, MediaType.IMAGE_PNG.getSubtype(), outputStream, new MatrixToImageConfig());
+//    @GetMapping(value = "/whepi/scan/scan_qr")
+//    public String scanQrImg(@Pd(name = "doorId") Long doorId, @Pd(name = "inType") Integer inType, @Pd(name = "name") String name,
+//                          HttpServletResponse response) throws IOException, WriterException {
+//        String url = oauth2+appId +"&redirect_uri="+URLEncoder.encode(domain()+"user/scan.html?doorId="+doorId+"&inType="+inType,"utf-8")+moreUrl;
+//        String file = QRCode.createBase64Img(url, "家园互助平台", name);
+//        return file;
+//    }
+    public String scan_qr(Long doorId, Integer inType, String name)
+            throws IOException, WriterException {
+        String url = oauth2+appId +"&redirect_uri="+URLEncoder.encode(domain()+"user/scan.html?doorId="+doorId+"&inType="+inType,"utf-8")+moreUrl;
+        String file = QRCode.createBase64Img(url, "家园互助平台", name);
+        return file;
     }
 
     /**
@@ -100,13 +114,28 @@ public class ScanAdminController {
      * @throws IOException
      * @throws WriterException
      */
-    @GetMapping(value = "/whepi/scan/scanEstate_qr.png", produces = MediaType.IMAGE_PNG_VALUE)
-    public void scanEstateQrImg(HttpServletResponse response) throws IOException, WriterException {
-        @Cleanup ServletOutputStream outputStream = response.getOutputStream();
-        String msg = URLEncoder.encode( domain + "user/scanEstate.html","utf-8");
-        BitMatrix matrix = new MultiFormatWriter().encode(oauth2 + appId + "&redirect_uri=" +
-                msg + moreUrl, BarcodeFormat.QR_CODE, 256, 256);
-        MatrixToImageWriter.writeToStream(matrix, MediaType.IMAGE_PNG.getSubtype(), outputStream, new MatrixToImageConfig());
+    @GetMapping(value = "/whepi/scan/scanEstate_qr")
+    public String scanEstateQrImg(HttpServletResponse response) throws IOException, WriterException {
+        String url = oauth2 + appId + "&redirect_uri=" + URLEncoder.encode( domain() + "user/scanEstate.html","utf-8") + moreUrl;
+        String file = QRCode.createBase64Img(url, "家园互助平台", "巡检扫码");
+        return file;
+    }
+
+    public String domain() {
+        if (domain.substring(domain.length()-1).equals("/")) {
+            return domain;
+        } else {
+            return domain + "/";
+        }
+    }
+
+    public String getName(Integer inType) {
+        if (inType == 1) {
+            return "进入";
+        } else if (inType == 2) {
+            return "出去";
+        }
+        return null;
     }
 
 }

+ 31 - 31
whepi-web/src/main/java/com/bofeng/wx/controller/ScanController.java

@@ -249,35 +249,35 @@ public class ScanController {
         return time.substring(0, time.length() - 1);
     }
 
-    /**
-     * 生成进出门二维码
-     * @param doorId 小区大门ID
-     * @param inType 1进入;2外出
-     * @param response
-     * @throws IOException
-     * @throws WriterException
-     */
-    @GetMapping(value = "/scan/scan_qr.png", produces = MediaType.IMAGE_PNG_VALUE)
-    public void scanQrImg(@Pd(name = "doorId") Long doorId, @Pd(name = "inType") Integer inType,
-                            HttpServletResponse response) throws IOException, WriterException {
-        @Cleanup ServletOutputStream outputStream = response.getOutputStream();
-        String msg = URLEncoder.encode( domain + "user/scan.html?doorId=" + doorId + "&inType=" + inType,"utf-8");
-        BitMatrix matrix = new MultiFormatWriter().encode(oauth2 + appId + "&redirect_uri=" +
-                msg + moreUrl, BarcodeFormat.QR_CODE, 256, 256);
-        MatrixToImageWriter.writeToStream(matrix, MediaType.IMAGE_PNG.getSubtype(), outputStream, new MatrixToImageConfig());
-    }
-
-    /**
-     * 生成校园巡逻二维码
-     * @throws IOException
-     * @throws WriterException
-     */
-    @GetMapping(value = "/scan/scanEstate_qr.png", produces = MediaType.IMAGE_PNG_VALUE)
-    public void scanEstateQrImg(HttpServletResponse response) throws IOException, WriterException {
-        @Cleanup ServletOutputStream outputStream = response.getOutputStream();
-        String msg = URLEncoder.encode( domain + "user/scanEstate.html","utf-8");
-        BitMatrix matrix = new MultiFormatWriter().encode(oauth2 + appId + "&redirect_uri=" +
-                msg + moreUrl, BarcodeFormat.QR_CODE, 256, 256);
-        MatrixToImageWriter.writeToStream(matrix, MediaType.IMAGE_PNG.getSubtype(), outputStream, new MatrixToImageConfig());
-    }
+//    /**
+//     * 生成进出门二维码
+//     * @param doorId 小区大门ID
+//     * @param inType 1进入;2外出
+//     * @param response
+//     * @throws IOException
+//     * @throws WriterException
+//     */
+//    @GetMapping(value = "/scan/scan_qr.png", produces = MediaType.IMAGE_PNG_VALUE)
+//    public void scanQrImg(@Pd(name = "doorId") Long doorId, @Pd(name = "inType") Integer inType,
+//                            HttpServletResponse response) throws IOException, WriterException {
+//        @Cleanup ServletOutputStream outputStream = response.getOutputStream();
+//        String msg = URLEncoder.encode( domain + "user/scan.html?doorId=" + doorId + "&inType=" + inType,"utf-8");
+//        BitMatrix matrix = new MultiFormatWriter().encode(oauth2 + appId + "&redirect_uri=" +
+//                msg + moreUrl, BarcodeFormat.QR_CODE, 256, 256);
+//        MatrixToImageWriter.writeToStream(matrix, MediaType.IMAGE_PNG.getSubtype(), outputStream, new MatrixToImageConfig());
+//    }
+//
+//    /**
+//     * 生成校园巡逻二维码
+//     * @throws IOException
+//     * @throws WriterException
+//     */
+//    @GetMapping(value = "/scan/scanEstate_qr.png", produces = MediaType.IMAGE_PNG_VALUE)
+//    public void scanEstateQrImg(HttpServletResponse response) throws IOException, WriterException {
+//        @Cleanup ServletOutputStream outputStream = response.getOutputStream();
+//        String msg = URLEncoder.encode( domain + "user/scanEstate.html","utf-8");
+//        BitMatrix matrix = new MultiFormatWriter().encode(oauth2 + appId + "&redirect_uri=" +
+//                msg + moreUrl, BarcodeFormat.QR_CODE, 256, 256);
+//        MatrixToImageWriter.writeToStream(matrix, MediaType.IMAGE_PNG.getSubtype(), outputStream, new MatrixToImageConfig());
+//    }
 }

+ 6 - 1
whepi-web/src/main/resources/mapper/UptownDoorMapper.xml

@@ -3,7 +3,8 @@
 <mapper namespace="com.bofeng.dao.UptownDoorMapper">
 
     <select id="getAllUptownDoor" resultType="com.bofeng.entity.UptownDoor">
-        SELECT ud.*,u.uptown_name as uptownName FROM sys_uptown_door ud left join sys_uptown u on u.uptown_id =
+        SELECT ud.*,u.uptown_name as uptownName FROM sys_uptown_door ud
+        left join sys_uptown u on u.uptown_id =
         ud.uptown_id
         <where>
             and ud.status = 1
@@ -14,4 +15,8 @@
         order by ud.time_update desc
     </select>
 
+    <update id="updateDoorQc">
+        update sys_uptown_door set ${qcName} = #{img} where door_id = #{doorId}
+    </update>
+
 </mapper>