tjf 4 сар өмнө
parent
commit
904bca718b

+ 45 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/OcrController.java

@@ -0,0 +1,45 @@
+package com.ruoyi.web.controller.common;
+
+
+import com.ruoyi.common.annotation.RepeatSubmit;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.IdCardVo;
+import com.ruoyi.common.utils.IdCardUtil;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @Author: tjf
+ * @Date: 2024/4/22 14:24
+ * @Describe:
+ */
+@RestController
+@RequestMapping("/ocr")
+public class OcrController {
+
+    /**
+     * 身份证识别
+     *
+     * @return
+     */
+    @PostMapping("/ocrIdCard")
+    @RepeatSubmit(interval = 1000, message = "请求过于频繁")
+    public AjaxResult ocrIdCard(@RequestBody IdCardVo idCardVo) {
+        return IdCardUtil.idCard(idCardVo.getImage(), idCardVo.getIdCardSide());
+    }
+
+    /**
+     * 营业执照识别
+     *
+     * @return
+     */
+    @PostMapping("/ocrBusinessLicense")
+    @RepeatSubmit(interval = 1000, message = "请求过于频繁")
+    @PreAuthorize("@ss.hasPermi('wuYe:ocr:ocrBusinessLicense')")
+    public AjaxResult ocrBusinessLicense(@RequestBody IdCardVo idCardVo) {
+        return IdCardUtil.businessLicense(idCardVo.getImage());
+    }
+}

+ 8 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/communityNews/CommunityNewsController.java

@@ -91,6 +91,14 @@ public class CommunityNewsController extends BaseController {
     }
 
 
+    /**
+     * 获取未读互动数量
+     */
+    @PreAuthorize("@ss.hasPermi('wuYe:news:getCommentInteractionCount')")
+    @PostMapping("/getCommentInteractionCount")
+    public AjaxResult getCommentInteractionCount(@RequestBody CommentInteractionVo commentInteractionVo) {
+        return communityNewsService.getCommentInteractionCount(commentInteractionVo);
+    }
     /**
      * 获取未读互动列表
      */

+ 6 - 0
ruoyi-common/pom.xml

@@ -16,6 +16,12 @@
     </description>
 
     <dependencies>
+        <!--身份验证依赖-->
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>credentials-java</artifactId>
+            <version>LATEST</version>
+        </dependency>
         <!--thumbnailator 压缩工具-->
         <dependency>
             <groupId>net.coobird</groupId>

+ 4 - 1
ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java

@@ -178,6 +178,9 @@ public class Constants
     public static final String FIV ="5";
 
 
+    public static final String FRONT = "front";
+    public static final String BACK = "back";
+
     //------------------文章的key----------------------------
     //社区资讯文章点赞的人员集合的key value = 该文章的[userId]
     public static final String ONE_LIKE ="one_like:";
@@ -214,7 +217,7 @@ public class Constants
     public static final String STARS_PARTY_NEWS_COUNT ="stars_party_news_count:";
 
     //-------------------未读互动的key-----------------
-    //记录社区资讯某个用户一共有多少个未读的互动(点赞,收藏,回复),记录成map形式{} key = comment_interaction_user:{userId} hkey = {targetType:targetId} value= CommentInteractionVo
+    //记录社区资讯某个用户一共有多少个未读的互动(点赞,收藏,回复)的具体信息,记录成map形式{} key = comment_interaction_user:{userId} hkey = {targetType:targetId} value= CommentInteractionVo
     public static final String COMMENT_INTERACTION_USER ="comment_interaction_user:";
     //记录社区资讯某个用户一共有多少个未读的互动的数量key = comment_interaction_user_count:{userId} value = 未读的互动的数量
     public static final String COMMENT_INTERACTION_USER_COUNT ="comment_interaction_user_count:";

+ 71 - 0
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/IdCardVo.java

@@ -0,0 +1,71 @@
+package com.ruoyi.common.core.domain;
+
+import java.io.Serializable;
+
+/**
+ * @Author: tjf
+ * @Date: 2024/4/23 14:58
+ * @Describe:
+ */
+public class IdCardVo implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 身份证号码
+     */
+    private String idCard;
+    /**
+     * 姓名
+     */
+    private String name;
+    /**
+     * 图片
+     */
+    private String image;
+    /**
+     *-front:身份证含照片的一面
+     * -back:身份证带国徽的一面
+     */
+    private String idCardSide;
+
+    public String getIdCardSide() {
+        return idCardSide;
+    }
+
+    public void setIdCardSide(String idCardSide) {
+        this.idCardSide = idCardSide;
+    }
+
+    public String getIdCard() {
+        return idCard;
+    }
+
+    public void setIdCard(String idCard) {
+        this.idCard = idCard;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getImage() {
+        return image;
+    }
+
+    public void setImage(String image) {
+        this.image = image;
+    }
+
+    @Override
+    public String toString() {
+        return "IdCardVo{" +
+                "idCard='" + idCard + '\'' +
+                ", name='" + name + '\'' +
+                ", image='" + image + '\'' +
+                ", idCardSide='" + idCardSide + '\'' +
+                '}';
+    }
+}

+ 65 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/Base64Util.java

@@ -0,0 +1,65 @@
+package com.ruoyi.common.utils;
+
+/**
+ * Base64 工具类
+ */
+public class Base64Util {
+    private static final char last2byte = (char) Integer.parseInt("00000011", 2);
+    private static final char last4byte = (char) Integer.parseInt("00001111", 2);
+    private static final char last6byte = (char) Integer.parseInt("00111111", 2);
+    private static final char lead6byte = (char) Integer.parseInt("11111100", 2);
+    private static final char lead4byte = (char) Integer.parseInt("11110000", 2);
+    private static final char lead2byte = (char) Integer.parseInt("11000000", 2);
+    private static final char[] encodeTable = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
+
+    public Base64Util() {
+    }
+
+    public static String encode(byte[] from) {
+        StringBuilder to = new StringBuilder((int) ((double) from.length * 1.34D) + 3);
+        int num = 0;
+        char currentByte = 0;
+
+        int i;
+        for (i = 0; i < from.length; ++i) {
+            for (num %= 8; num < 8; num += 6) {
+                switch (num) {
+                    case 0:
+                        currentByte = (char) (from[i] & lead6byte);
+                        currentByte = (char) (currentByte >>> 2);
+                    case 1:
+                    case 3:
+                    case 5:
+                    default:
+                        break;
+                    case 2:
+                        currentByte = (char) (from[i] & last6byte);
+                        break;
+                    case 4:
+                        currentByte = (char) (from[i] & last4byte);
+                        currentByte = (char) (currentByte << 2);
+                        if (i + 1 < from.length) {
+                            currentByte = (char) (currentByte | (from[i + 1] & lead2byte) >>> 6);
+                        }
+                        break;
+                    case 6:
+                        currentByte = (char) (from[i] & last2byte);
+                        currentByte = (char) (currentByte << 4);
+                        if (i + 1 < from.length) {
+                            currentByte = (char) (currentByte | (from[i + 1] & lead4byte) >>> 4);
+                        }
+                }
+
+                to.append(encodeTable[currentByte]);
+            }
+        }
+
+        if (to.length() % 4 != 0) {
+            for (i = 4 - to.length() % 4; i > 0; --i) {
+                to.append("=");
+            }
+        }
+
+        return to.toString();
+    }
+}

+ 72 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/FileUtil.java

@@ -0,0 +1,72 @@
+package com.ruoyi.common.utils;
+
+import java.io.*;
+
+/**
+ * 文件读取工具类
+ */
+public class FileUtil {
+
+    /**
+     * 读取文件内容,作为字符串返回
+     */
+    public static String readFileAsString(String filePath) throws IOException {
+        File file = new File(filePath);
+        if (!file.exists()) {
+            throw new FileNotFoundException(filePath);
+        } 
+
+        if (file.length() > 1024 * 1024 * 1024) {
+            throw new IOException("File is too large");
+        } 
+
+        StringBuilder sb = new StringBuilder((int) (file.length()));
+        // 创建字节输入流  
+        FileInputStream fis = new FileInputStream(filePath);  
+        // 创建一个长度为10240的Buffer
+        byte[] bbuf = new byte[10240];  
+        // 用于保存实际读取的字节数  
+        int hasRead = 0;  
+        while ( (hasRead = fis.read(bbuf)) > 0 ) {  
+            sb.append(new String(bbuf, 0, hasRead));  
+        }  
+        fis.close();  
+        return sb.toString();
+    }
+
+    /**
+     * 根据文件路径读取byte[] 数组
+     */
+    public static byte[] readFileByBytes(String filePath) throws IOException {
+        File file = new File(filePath);
+        if (!file.exists()) {
+            throw new FileNotFoundException(filePath);
+        } else {
+            ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length());
+            BufferedInputStream in = null;
+
+            try {
+                in = new BufferedInputStream(new FileInputStream(file));
+                short bufSize = 1024;
+                byte[] buffer = new byte[bufSize];
+                int len1;
+                while (-1 != (len1 = in.read(buffer, 0, bufSize))) {
+                    bos.write(buffer, 0, len1);
+                }
+
+                byte[] var7 = bos.toByteArray();
+                return var7;
+            } finally {
+                try {
+                    if (in != null) {
+                        in.close();
+                    }
+                } catch (IOException var14) {
+                    var14.printStackTrace();
+                }
+
+                bos.close();
+            }
+        }
+    }
+}

+ 77 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/HttpUtils.java

@@ -0,0 +1,77 @@
+package com.ruoyi.common.utils;
+
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * http 工具类
+ */
+public class HttpUtils {
+
+    public static String post(String requestUrl, String accessToken, String params)
+            throws Exception {
+        String contentType = "application/x-www-form-urlencoded";
+        return HttpUtils.post(requestUrl, accessToken, contentType, params);
+    }
+
+    public static String post(String requestUrl, String accessToken, String contentType, String params)
+            throws Exception {
+        String encoding = "UTF-8";
+        if (requestUrl.contains("nlp")) {
+            encoding = "GBK";
+        }
+        return HttpUtils.post(requestUrl, accessToken, contentType, params, encoding);
+    }
+
+    public static String post(String requestUrl, String accessToken, String contentType, String params, String encoding)
+            throws Exception {
+        String url = requestUrl + "?access_token=" + accessToken;
+        return HttpUtils.postGeneralUrl(url, contentType, params, encoding);
+    }
+
+    public static String postGeneralUrl(String generalUrl, String contentType, String params, String encoding)
+            throws Exception {
+        URL url = new URL(generalUrl);
+        // 打开和URL之间的连接
+        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+        connection.setRequestMethod("POST");
+        // 设置通用的请求属性
+        connection.setRequestProperty("Content-Type", contentType);
+        connection.setRequestProperty("Connection", "Keep-Alive");
+        connection.setUseCaches(false);
+        connection.setDoOutput(true);
+        connection.setDoInput(true);
+
+        // 得到请求的输出流对象
+        DataOutputStream out = new DataOutputStream(connection.getOutputStream());
+        out.write(params.getBytes(encoding));
+        out.flush();
+        out.close();
+
+        // 建立实际的连接
+        connection.connect();
+        // 获取所有响应头字段
+        Map<String, List<String>> headers = connection.getHeaderFields();
+        // 遍历所有的响应头字段
+        for (String key : headers.keySet()) {
+            System.err.println(key + "--->" + headers.get(key));
+        }
+        // 定义 BufferedReader输入流来读取URL的响应
+        BufferedReader in = null;
+        in = new BufferedReader(
+                new InputStreamReader(connection.getInputStream(), encoding));
+        String result = "";
+        String getLine;
+        while ((getLine = in.readLine()) != null) {
+            result += getLine;
+        }
+        in.close();
+        System.err.println("result:" + result);
+        return result;
+    }
+}

+ 610 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/IdCardUtil.java

@@ -0,0 +1,610 @@
+package com.ruoyi.common.utils;
+
+/**
+ * @Author: tjf
+ * @Date: 2024/4/17 9:35
+ * @Describe:
+ */
+
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.common.core.domain.AjaxResult;
+import okhttp3.*;
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.*;
+import java.net.URLEncoder;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.*;
+
+import static com.ruoyi.common.constant.Constants.BACK;
+import static com.ruoyi.common.constant.Constants.FRONT;
+
+
+public class IdCardUtil {
+    /**
+     * 重要提示代码中所需工具类
+     * FileUtil,HttpUtil请从
+     * https://ai.baidu.com/file/658A35ABAB2D404FBF903F64D47C1F72
+     * https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3
+     * 下载
+     * <p>
+     * https://cloud.baidu.com/doc/OCR/s/rk3h7xzck 文档地址
+     */
+
+    // aes key 从console控制台获取 身份证识别使用
+    static String aesKey = "ce539dc069ad0908";
+
+    static byte[] originAesKey = null;
+
+    /**
+     * 身份证识别
+     * {
+     * "log_id": "1559208562721579319",
+     * "direction": 0,
+     * "image_status": "normal",
+     * "photo": "/9j/4AAQSkZJRgABA......",
+     * "photo_location": {
+     * "width": 1189,
+     * "top": 638,
+     * "left": 2248,
+     * "height": 1483
+     * },
+     * "card_image": "/9j/4AAQSkZJRgABA......",
+     * "card_location": {
+     * "top": 328,
+     * "left": 275,
+     * "width": 1329,
+     * "height": 571
+     * },
+     * "words_result": {
+     * "住址": {
+     * "location": {
+     * "left": 267,
+     * "top": 453,
+     * "width": 459,
+     * "height": 99
+     * },
+     * "words": "南京市江宁区弘景大道3889号"
+     * },
+     * "公民身份号码": {
+     * "location": {
+     * "left": 443,
+     * "top": 681,
+     * "width": 589,
+     * "height": 45
+     * },
+     * "words": "330881199904173914"
+     * },
+     * "出生": {
+     * "location": {
+     * "left": 270,
+     * "top": 355,
+     * "width": 357,
+     * "height": 45
+     * },
+     * "words": "19990417"
+     * },
+     * "姓名": {
+     * "location": {
+     * "left": 267,
+     * "top": 176,
+     * "width": 152,
+     * "height": 50
+     * },
+     * "words": "伍云龙"
+     * },
+     * "性别": {
+     * "location": {
+     * "left": 269,
+     * "top": 262,
+     * "width": 33,
+     * "height": 52
+     * },
+     * "words": "男"
+     * },
+     * "民族": {
+     * "location": {
+     * "left": 492,
+     * "top": 279,
+     * "width": 30,
+     * "height": 37
+     * },
+     * "words": "汉"
+     * }
+     * },
+     * "words_result_num": 6
+     * }
+     * <p>
+     * <p>
+     * {
+     * "words_result": {
+     * "失效日期": {
+     * "words": "20390711",
+     * "location": {
+     * "top": 445,
+     * "left": 523,
+     * "width": 153,
+     * "height": 38
+     * }
+     * },
+     * "签发机关": {
+     * "words": "陆丰市公安局",
+     * "location": {
+     * "top": 377,
+     * "left": 339,
+     * "width": 195,
+     * "height": 38
+     * }
+     * },
+     * "签发日期": {
+     * "words": "20190606",
+     * "location": {
+     * "top": 445,
+     * "left": 343,
+     * "width": 152,
+     * "height": 38
+     * }
+     * }
+     * },
+     * "log_id": "1559208562721579328",
+     * "words_result_num": 3,
+     * "error_code": 0,
+     * "image_status": "normal"
+     * }
+     *
+     * @return
+     */
+    public static AjaxResult idCard(String image, String idCardSide) {
+        try {
+            // 文件路径
+            byte[] imgData = FileUtil.readFileByBytes(image);
+
+            String imgStr = encryptImg(aesKey, imgData);
+
+            String imgParam = URLEncoder.encode(imgStr, "UTF-8");
+            String url = "https://aip.baidubce.com/rest/2.0/ocr/v1/idcard";
+            //-front:身份证含照片的一面
+            //-back:身份证带国徽的一面
+            //自动检测身份证正反面,如果传参指定方向与图片相反,支持正常识别,返回参数image_status字段为"reversed_side"
+            String param = "id_card_side=" + idCardSide +
+                    "&image=" + imgParam +
+                    "&AESEncry=" + true;
+            String accessToken = getAccessToken("TvvuZOOh7MgnlDFnw11ln67n", "CY47OI0eKAzYBD2LO55SM3OITzsyq6DK");
+            String encryptResult = HttpUtils.post(url, accessToken, param);
+            String decryptResult = parseResult(encryptResult);
+            JSONObject jsonObject = JSON.parseObject(decryptResult);
+            String wordsResult = jsonObject.getString("words_result");
+            Map<String, Object> map = new HashMap<>(3);
+            if (StringUtils.isNotEmpty(wordsResult)) {
+                JSONObject jsonObjectWordsResult = JSON.parseObject(wordsResult);
+                if (FRONT.equals(idCardSide)) {
+                    String name = JSON.parseObject(jsonObjectWordsResult.getString("姓名")).getString("words");
+                    String address = JSON.parseObject(jsonObjectWordsResult.getString("住址")).getString("words");
+                    String idCard = JSON.parseObject(jsonObjectWordsResult.getString("公民身份号码")).getString("words");
+                    map.put("realName", name);
+                    map.put("address", address);
+                    map.put("idCard", idCard);
+                } else if (BACK.equals(idCardSide)) {
+                    String date = JSON.parseObject(jsonObjectWordsResult.getString("失效日期")).getString("words");
+                    map.put("expirationDate", date);
+                }
+            }
+            return AjaxResult.success(map);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return AjaxResult.error();
+    }
+
+    /**
+     * 加密图片
+     *
+     * @param aesKey
+     * @param imgData
+     * @return
+     * @throws Exception
+     */
+    private static String encryptImg(String aesKey, byte[] imgData) throws Exception {
+        originAesKey = AesKeyUtil.parseAesKey(aesKey);
+        byte[] encImgBytes = AesUtil.encrypt(imgData, originAesKey);
+        String imgStr = Base64Util.encodeBase64(encImgBytes);
+        return imgStr;
+    }
+
+    /**
+     * 解密结果
+     *
+     * @param encryptResult
+     * @return
+     * @throws Exception
+     */
+    private static String parseResult(String encryptResult) throws Exception {
+        JSONObject obj = JSONObject.parseObject(encryptResult);
+        String result = obj.getString("result");
+        byte[] arr = Base64Util.decodeBase64(result);
+        String decryptResult = new String(AesUtil.decrypt(arr, originAesKey));
+        return decryptResult;
+    }
+
+
+    static class AesKeyUtil {
+        private static final String HEX = "0123456789abcdef";
+
+        /**
+         * 获得原生的128位的aeskey
+         * 因为一个byte位8位最后生成的byte数组长度为16
+         * <p>
+         * 16 * 8 = 128
+         *
+         * @param hex
+         * @return
+         */
+        public static byte[] parseAesKey(String hex) throws Exception {
+            char[] data = hex.toCharArray();
+            if (data.length != 16) {
+                throw new Exception(" ase key illegal ");
+            }
+            return decode(hex.toCharArray());
+        }
+
+        private static byte[] decode(char[] data) throws IllegalArgumentException {
+            int len = data.length;
+
+            byte[] out = new byte[len];
+
+            for (int i = 0; i < len; i++) {
+                int f = toDigit(data[i]);
+                out[i] = (byte) (f);
+            }
+            return out;
+        }
+
+        private static int toDigit(char ch) {
+            return HEX.indexOf(ch);
+        }
+    }
+
+    static class AesUtil {
+
+        private static final String ALGORITHM = "AES";
+
+        private static final String ALGORITHM_STR = "AES/ECB/PKCS5Padding";
+
+        /**
+         * aes 加密
+         */
+        private static byte[] encrypt(byte[] src, byte[] aesKey) throws Exception {
+            Cipher cipher = getCipher(aesKey, Cipher.ENCRYPT_MODE);
+            byte[] ret = cipher.doFinal(src);
+            return ret;
+        }
+
+        /**
+         * aes 解密
+         */
+        public static byte[] decrypt(byte[] src, byte[] aesKey) throws Exception {
+            Cipher cipher = getCipher(aesKey, Cipher.DECRYPT_MODE);
+            byte[] original = cipher.doFinal(src);
+            return original;
+        }
+
+        private static Cipher getCipher(byte[] aesKey, int mode) throws Exception {
+            SecretKeySpec secretKeySpec = new SecretKeySpec(aesKey, ALGORITHM);
+            Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
+            cipher.init(mode, secretKeySpec);
+            return cipher;
+        }
+    }
+
+    static class Base64Util {
+
+        private static Base64.Encoder ENCODER = Base64.getEncoder();
+
+        // base64 加密
+        private static Base64.Decoder DECODER = Base64.getDecoder();
+
+        /**
+         * base64加密
+         *
+         * @param arr
+         * @return
+         */
+        private static String encodeBase64(byte[] arr) {
+            String base64 = null;
+            try {
+                base64 = ENCODER.encodeToString(arr);
+            } catch (Exception e) {
+            }
+            return base64;
+        }
+
+        /**
+         * base64解密
+         *
+         * @param str
+         * @return
+         */
+        public static byte[] decodeBase64(String str) {
+            byte[] encodeBase64 = new byte[0];
+            try {
+                encodeBase64 = DECODER.decode(str);
+            } catch (Exception e) {
+            }
+            return encodeBase64;
+        }
+    }
+
+    /**
+     * 营业执照识别
+     * 重要提示代码中所需工具类
+     * FileUtil,Base64Util,HttpUtil,GsonUtils请从
+     * https://ai.baidu.com/file/658A35ABAB2D404FBF903F64D47C1F72
+     * https://ai.baidu.com/file/C8D81F3301E24D2892968F09AE1AD6E2
+     * https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3
+     * https://ai.baidu.com/file/470B3ACCA3FE43788B5A963BF0B625F3
+     * 下载
+     */
+    public static AjaxResult businessLicense(String image) {
+        // 请求url
+        String url = "https://aip.baidubce.com/rest/2.0/ocr/v1/business_license";
+        try {
+            // 本地文件路径
+            byte[] imgData = FileUtil.readFileByBytes(image);
+            String imgStr = com.ruoyi.common.utils.Base64Util.encode(imgData);
+            String imgParam = URLEncoder.encode(imgStr, "UTF-8");
+            String param = "image=" + imgParam;
+            String accessToken = getAccessToken("TvvuZOOh7MgnlDFnw11ln67n", "CY47OI0eKAzYBD2LO55SM3OITzsyq6DK");
+            String result = HttpUtils.post(url, accessToken, param);
+            /**
+             *
+             {
+             "words_result": {
+             "经营范围": {
+             "location": {
+             "top": 589,
+             "left": 381,
+             "width": 90,
+             "height": 19
+             },
+             "words": "商务服务业"
+             },
+             "组成形式": {
+             "location": {
+             "top": -1,
+             "left": -1,
+             "width": 0,
+             "height": 0
+             },
+             "words": "无"
+             },
+             "法人": {
+             "location": {
+             "top": 537,
+             "left": 381,
+             "width": 36,
+             "height": 19
+             },
+             "words": "方平"
+             },
+             "证件编号": {
+             "location": {
+             "top": 218,
+             "left": 302,
+             "width": 140,
+             "height": 15
+             },
+             "words": "921MA190538210301"
+             },
+             "注册资本": {
+             "location": {
+             "top": 431,
+             "left": 1044,
+             "width": 152,
+             "height": 21
+             },
+             "words": "200万元"
+             },
+             "单位名称": {
+             "location": {
+             "top": 431,
+             "left": 384,
+             "width": 71,
+             "height": 20
+             },
+             "words": "有限公司"
+             },
+             "有效期": {
+             "location": {
+             "top": 536,
+             "left": 1044,
+             "width": 198,
+             "height": 20
+             },
+             "words": "长期"
+             },
+             "社会信用代码": {
+             "location": {
+             "top": 300,
+             "left": 241,
+             "width": 156,
+             "height": 16
+             },
+             "words": "10440119MA06M85"
+             },
+             "实收资本": {
+             "location": {
+             "top": -1,
+             "left": -1,
+             "width": 0,
+             "height": 0
+             },
+             "words": "无"
+             },
+             "有效期起始日期": {
+             "location": {
+             "top": 536,
+             "left": 1044,
+             "width": 198,
+             "height": 20
+             },
+             "words": "2019年01月01日"
+             },
+             "核准日期": {
+             "location": {
+             "top": 884,
+             "left": 1188,
+             "width": 199,
+             "height": 22
+             },
+             "words": "2019年01月01日"
+             },
+             "成立日期": {
+             "location": {
+             "top": 484,
+             "left": 1043,
+             "width": 126,
+             "height": 19
+             },
+             "words": "2019年01月01日"
+             },
+             "税务登记号": {
+             "location": {
+             "top": -1,
+             "left": -1,
+             "width": 0,
+             "height": 0
+             },
+             "words": "无"
+             },
+             "地址": {
+             "location": {
+             "top": 588,
+             "left": 1043,
+             "width": 55,
+             "height": 22
+             },
+             "words": "广州市"
+             },
+             "登记机关": {
+             "location": {
+             "top": 0,
+             "left": 0,
+             "width": 0,
+             "height": 0
+             },
+             "words": "无"
+             },
+             "类型": {
+             "location": {
+             "top": 484,
+             "left": 382,
+             "width": 258,
+             "height": 20
+             },
+             "words": "有限责任公司(自然人投资或控股)"
+             }
+             },
+             "direction": 0,
+             "words_result_num": 16,
+             "log_id": "3166723741167575145"
+             }
+             */
+            JSONObject jsonObject = JSONObject.parseObject(result);
+            String wordsResult = jsonObject.getString("words_result");
+            Map<String, Object> map = new HashMap<>(9);
+            if (StringUtils.isNotEmpty(wordsResult)) {
+                JSONObject jsonObjectWordsResult = JSON.parseObject(wordsResult);
+                String creditCode = JSON.parseObject(jsonObjectWordsResult.getString("社会信用代码")).getString("words");
+                String enterpriseName = JSON.parseObject(jsonObjectWordsResult.getString("单位名称")).getString("words");
+                String enterpriseType = JSON.parseObject(jsonObjectWordsResult.getString("类型")).getString("words");
+                String enterpriseAddress = JSON.parseObject(jsonObjectWordsResult.getString("地址")).getString("words");
+                String legalName = JSON.parseObject(jsonObjectWordsResult.getString("法人")).getString("words");
+                String registeredCapital = JSON.parseObject(jsonObjectWordsResult.getString("注册资本")).getString("words");
+                String establishData = JSON.parseObject(jsonObjectWordsResult.getString("成立日期")).getString("words");
+                String businessTerm = JSON.parseObject(jsonObjectWordsResult.getString("有效期")).getString("words");
+                String businessScope = JSON.parseObject(jsonObjectWordsResult.getString("经营范围")).getString("words");
+                map.put("creditCode", creditCode);
+                map.put("enterpriseName", enterpriseName);
+                map.put("enterpriseType", enterpriseType);
+                map.put("enterpriseAddress", enterpriseAddress);
+                map.put("legalName", legalName);
+                map.put("registeredCapital", registeredCapital);
+                map.put("establishData", establishData);
+                map.put("businessTerm", businessTerm);
+                map.put("businessScope", businessScope);
+            } else {
+                return AjaxResult.error("营业执照识别失败,请检查。");
+            }
+            return AjaxResult.success(map);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return AjaxResult.error();
+    }
+
+
+
+    /**
+     * 获取文件base64编码
+     *
+     * @param path      文件路径
+     * @param urlEncode 如果Content-Type是application/x-www-form-urlencoded时,传true
+     * @return base64编码信息,不带文件头
+     * @throws IOException IO异常
+     */
+    static String getFileContentAsBase64(String path, boolean urlEncode) {
+        byte[] b = new byte[0];
+        try {
+            b = Files.readAllBytes(Paths.get(path));
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        String base64 = Base64.getEncoder().encodeToString(b);
+        if (urlEncode) {
+            try {
+                base64 = URLEncoder.encode(base64, "utf-8");
+            } catch (UnsupportedEncodingException e) {
+                e.printStackTrace();
+            }
+        }
+        return base64;
+    }
+
+    /**
+     * 获取百度开放平台的AccessToken
+     * client_id: 必须参数,应用的API Key;
+     * client_secret: 必须参数,应用的Secret Key;不同的功能不同
+     *
+     * @return
+     */
+    public static String getAccessToken(String apiKey, String secretKey) {
+        String url = "https://aip.baidubce.com/oauth/2.0/token";
+        /**
+         *grant_type: 必须参数,固定为client_credentials;
+         *client_id: 必须参数,应用的API Key;
+         *client_secret: 必须参数,应用的Secret Key;
+         */
+        HashMap<String, Object> paramMap = new HashMap<>(3);
+        paramMap.put("grant_type", "client_credentials");
+        paramMap.put("client_id", apiKey);
+        paramMap.put("client_secret", secretKey);
+        String post = HttpUtil.post(url, paramMap);
+        JSONObject jsonObject = JSONObject.parseObject(post);
+        String accessToken = jsonObject.getString("access_token");
+        return accessToken;
+    }
+
+
+
+
+
+
+
+
+
+
+    static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().build();
+}

+ 1 - 1
ruoyi-system/src/main/java/com/ruoyi/system/mapper/CommentIndexMapper.java

@@ -37,7 +37,7 @@ public interface CommentIndexMapper
      * @param commentId
      * @return
      */
-    public List<Long> selectCommentIdListByCommentId(Long commentId);
+    public List<CommentIndex> selectCommentIdListByCommentId(Long commentId);
 
     /**
      * 查询社区资讯评论审核列表

+ 7 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/ICommunityNewsService.java

@@ -75,4 +75,11 @@ public interface ICommunityNewsService
      * @return
      */
     public AjaxResult getCommentInteraction(CommentInteractionVo commentInteractionVo);
+
+    /**
+     * 获取未读互动数量
+     * @param commentInteractionVo
+     * @return
+     */
+    public AjaxResult getCommentInteractionCount(CommentInteractionVo commentInteractionVo);
 }

+ 73 - 5
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CommentIndexServiceImpl.java

@@ -6,6 +6,7 @@ import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.system.domain.communityNews.CommentContent;
 import com.ruoyi.system.domain.communityNews.CommentIndex;
+import com.ruoyi.system.domain.communityNews.CommunityNews;
 import com.ruoyi.system.domain.communityNews.vo.CommentChildrenVo;
 import com.ruoyi.system.domain.communityNews.vo.CommentIndexShVo;
 import com.ruoyi.system.domain.communityNews.vo.CommentIndexVo;
@@ -14,6 +15,7 @@ import com.ruoyi.system.mapper.CommentIndexMapper;
 import com.ruoyi.system.mapper.CommunityNewsMapper;
 import com.ruoyi.system.service.ICommentIndexService;
 import com.ruoyi.system.service.ICommunityNewsService;
+import org.apache.commons.lang3.ObjectUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -182,12 +184,12 @@ public class CommentIndexServiceImpl implements ICommentIndexService {
             //对应用户点赞的回复key=two_my_like:{用户id} value = [评论id]
             Long userId = SecurityUtils.getUserId();
             List<Long> commentIdList = redisCache.getCacheList(TWO_MY_LIKE + userId);
-            if (commentIdList != null && commentIdList.size() > 0){
+            if (commentIdList != null && commentIdList.size() > 0) {
                 commentIdList.remove(commentId);
             }
             redisCache.deleteObject(TWO_MY_LIKE + userId);
-            if (commentIdList != null && commentIdList.size() > 0){
-                redisCache.setCacheList(TWO_MY_LIKE + userId,commentIdList);
+            if (commentIdList != null && commentIdList.size() > 0) {
+                redisCache.setCacheList(TWO_MY_LIKE + userId, commentIdList);
             }
 /*            //删除该资讯点赞的数量需要知道所有评论的id
             //首先获取该文章资讯的总点赞数量
@@ -217,12 +219,78 @@ public class CommentIndexServiceImpl implements ICommentIndexService {
                 likeCount = 0;
             }
             redisCache.setCacheObject(ONE_LIKE_COUNT + communityId, likeCount);*/
-            //todo 删除后还需要减少未读互动的数据
-
+            //删除评论需要根据这个评论是根评论还子评论,根评论删除对应资讯发布人的未读互动里面对应的值(如果有)根评论还会删除所有子评论,子评论删除评论对象的未读互动
+            Integer isRoot = commentIndex.getIsRoot();
+            if (1 == isRoot) {
+                //如果是根评论先查询是否有子集评论
+                List<CommentIndex> commentIndexList = commentIndexMapper.selectCommentIdListByCommentId(commentId);
+                if (commentIndexList !=null && commentIndexList.size() > 0){
+                    for (CommentIndex index : commentIndexList) {
+                        //删除未读互动中的子评论相关信息
+                        deleteCommentChildren(index);
+                    }
+                }
+                //删除根评论相关信息
+                //根据资讯id查询资讯发布人的id
+                CommunityNews communityNews = communityNewsMapper.selectCommunityNewsByCommunityId(communityId);
+                Long toUserId = communityNews.getUserId();
+                String commentInteractionUserKey = COMMENT_INTERACTION_USER + toUserId;
+                //hKey={targetType:targetId}
+                String hKey = ONE + ":" + commentId;
+                if (redisCache.hasCacheMapKey(commentInteractionUserKey, hKey)) {
+                    //说明有对应的未读互动删除对应的key
+                    redisCache.deleteCacheMapValue(commentInteractionUserKey, hKey);
+                    //目标人员的未读数量-1
+                    String commentInteractionUserCountKey = COMMENT_INTERACTION_USER_COUNT + toUserId;
+                    Object commentInteractionUserCount = redisCache.getCacheObject(commentInteractionUserCountKey);
+                    if (ObjectUtils.isNotEmpty(commentInteractionUserCount)) {
+                        redisCache.setCacheObject(commentInteractionUserCountKey, Math.max(Integer.parseInt(commentInteractionUserCount.toString()) - 1, 0));
+                    }
+                    //对应资讯下的未读数量-1
+                    Object communityUserCount = redisCache.getCacheMapValue(COMMENT_INTERACTION_COMMUNITY_USER_COUNT + toUserId, communityId.toString());
+                    if (ObjectUtils.isNotEmpty(communityUserCount)){
+                        redisCache.setCacheMapValue(COMMENT_INTERACTION_COMMUNITY_USER_COUNT + toUserId, communityId.toString(),Math.max(Integer.parseInt(communityUserCount.toString())-1,0));
+                    }
+                }
+            } else {
+                //删除未读互动中的子评论相关信息
+                deleteCommentChildren(commentIndex);
+            }
         }
         return result;
     }
 
+    /**
+     * 删除未读互动中的子评论相关信息
+     * @param commentIndex
+     */
+    public void deleteCommentChildren(CommentIndex commentIndex){
+        Long commentId = commentIndex.getCommentId();
+        Long communityId = commentIndex.getCommunityId();
+        //子评论
+        //获取到回复的人的id
+        Long toUserId = commentIndex.getToUserId();
+        //判断该用户是否有未读的子评论互动
+        String commentInteractionUserKey = COMMENT_INTERACTION_USER + toUserId;
+        //hKey={targetType:targetId}
+        String hKey = FOR + ":" + commentId;
+        if (redisCache.hasCacheMapKey(commentInteractionUserKey, hKey)) {
+            //说明有对应的未读互动删除对应的key
+            redisCache.deleteCacheMapValue(commentInteractionUserKey, hKey);
+            //目标人员的未读数量-1
+            String commentInteractionUserCountKey = COMMENT_INTERACTION_USER_COUNT + toUserId;
+            Object commentInteractionUserCount = redisCache.getCacheObject(commentInteractionUserCountKey);
+            if (ObjectUtils.isNotEmpty(commentInteractionUserCount)) {
+                redisCache.setCacheObject(commentInteractionUserCountKey, Math.max(Integer.parseInt(commentInteractionUserCount.toString()) - 1, 0));
+            }
+            //对应资讯下的未读数量-1
+            Object communityUserCount = redisCache.getCacheMapValue(COMMENT_INTERACTION_COMMUNITY_USER_COUNT + toUserId, communityId.toString());
+            if (ObjectUtils.isNotEmpty(communityUserCount)){
+                redisCache.setCacheMapValue(COMMENT_INTERACTION_COMMUNITY_USER_COUNT + toUserId, communityId.toString(),Math.max(Integer.parseInt(communityUserCount.toString())-1,0));
+            }
+        }
+    }
+
     /**
      * 根据parent_id查询所有评论组装成前端所需要的子集数据结构 带分页
      *

+ 2 - 10
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CommentLikesServiceImpl.java

@@ -325,12 +325,8 @@ public class CommentLikesServiceImpl implements ICommentLikesService {
             // ---------点赞数量操作------------------
             //先获取永久点赞数量的值
             Integer likeCount = redisCache.getCacheObject(likeOneCountKey);
-            likeCount = likeCount - 1;
-            if (likeCount < 0) {
-                likeCount = 0;
-            }
             //更新永久点赞数量
-            redisCache.setCacheObject(likeOneCountKey, likeCount);
+            redisCache.setCacheObject(likeOneCountKey, Math.max(likeCount - 1,0));
             //给数据库同步数据在 redis中增加一个有过期时间的key 1分钟过期时间
             redisCache.setCacheObject(likeOneCountTimeKey + "#" + likeCount, likeCount, 1, TimeUnit.MINUTES);
             return AjaxResult.success();
@@ -366,12 +362,8 @@ public class CommentLikesServiceImpl implements ICommentLikesService {
             // ---------点赞数量操作------------------
             //先获取永久点赞数量的值
             Integer likeCount = redisCache.getCacheObject(likeTwoCountKey);
-            likeCount = likeCount - 1;
-            if (likeCount < 0) {
-                likeCount = 0;
-            }
             //更新永久点赞数量
-            redisCache.setCacheObject(likeTwoCountKey, likeCount);
+            redisCache.setCacheObject(likeTwoCountKey, Math.max(likeCount - 1,0));
             //给数据库同步数据在 redis中增加一个有过期时间的key 1分钟过期时间
             redisCache.setCacheObject(likeTwoCountTimeKey + "#" + likeCount, likeCount, 1, TimeUnit.MINUTES);
             return AjaxResult.success();

+ 2 - 10
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CommentStarsServiceImpl.java

@@ -135,11 +135,7 @@ public class CommentStarsServiceImpl implements ICommentStarsService {
                 }
                 //收藏数量-1
                 starsCount = redisCache.getCacheObject(starsUserCountKey);
-                starsCount = starsCount - 1;
-                if (starsCount < 0) {
-                    starsCount = 0;
-                }
-                redisCache.setCacheObject(starsUserCountKey, starsCount);
+                redisCache.setCacheObject(starsUserCountKey, Math.max(starsCount - 1,0));
                 commentStars.setDelFlag("Y");
                 //更新数据库
                 commentStarsMapper.updateCommentStarsByUserIdAndCommunityId(commentStars);
@@ -211,11 +207,7 @@ public class CommentStarsServiceImpl implements ICommentStarsService {
                 }
                 commentStarsMapper.updateCommentStarsByUserIdAndCommunityId(commentStars);
                 if (ObjectUtils.isNotEmpty(starsPartyNewsCount)) {
-                    starsCount = Integer.parseInt(starsPartyNewsCount.toString()) - 1;
-                    if (starsCount < 0) {
-                        starsCount = 0;
-                    }
-                    redisCache.setCacheObject(STARS_PARTY_NEWS_COUNT + targetId, starsCount);
+                    redisCache.setCacheObject(STARS_PARTY_NEWS_COUNT + targetId, Math.max(Integer.parseInt(starsPartyNewsCount.toString()) - 1,0));
                 }
             } else {
                 //则收藏

+ 23 - 9
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CommunityNewsServiceImpl.java

@@ -94,8 +94,7 @@ public class CommunityNewsServiceImpl implements ICommunityNewsService {
             for (CommunityNews news : communityNewsList) {
                 news.setIsInteraction("N");
                 //key=comment_interaction_community_user_count:{userId} hkey = {community_id} value = 资讯下有多少个未读的互动(点赞,收藏,回复)
-                Object commentInteractionCommunityUserCount = redisCache.getCacheMapValue(COMMENT_INTERACTION_COMMUNITY_USER_COUNT + userId, news.getCommunityId().toString());
-                if (ObjectUtils.isNotEmpty(commentInteractionCommunityUserCount)) {
+                if (redisCache.hasCacheMapKey(COMMENT_INTERACTION_COMMUNITY_USER_COUNT + userId, news.getCommunityId().toString())) {
                     news.setIsInteraction("Y");
                 }
             }
@@ -171,17 +170,13 @@ public class CommunityNewsServiceImpl implements ICommunityNewsService {
         }
         //-------------------获取设置用户的未读互动数量----------------
         String commentInteractionUserCountKey = COMMENT_INTERACTION_USER_COUNT + targetUserId;
-        Integer commentInteractionUserCount = redisCache.getCacheObject(commentInteractionUserCountKey);
+        Object commentInteractionUserCount = redisCache.getCacheObject(commentInteractionUserCountKey);
         if (commentInteractionUserCount != null) {
             //判断是删除还是新增
             if (ONE.equals(type)) {
-                redisCache.setCacheObject(commentInteractionUserCountKey, commentInteractionUserCount + 1);
+                redisCache.setCacheObject(commentInteractionUserCountKey, Integer.parseInt(commentInteractionUserCount.toString()) + 1);
             } else {
-                commentInteractionUserCount = commentInteractionUserCount - 1;
-                if (commentInteractionUserCount < 0) {
-                    commentInteractionUserCount = 0;
-                }
-                redisCache.setCacheObject(commentInteractionUserCountKey, commentInteractionUserCount);
+                redisCache.setCacheObject(commentInteractionUserCountKey, Math.max(Integer.parseInt(commentInteractionUserCount.toString()) - 1,0));
             }
         } else {
             if (ONE.equals(type)) {
@@ -252,6 +247,25 @@ public class CommunityNewsServiceImpl implements ICommunityNewsService {
             resultList.addAll(commentInteractionUserMap.values());
         }
         resultMap.put("list", resultList);
+        //清空未读key
+        redisCache.deleteObject(commentInteractionUserCountKey);
+        redisCache.deleteObject(commentInteractionUserKey);
+        redisCache.deleteObject(COMMENT_INTERACTION_COMMUNITY_USER_COUNT+userId);
         return AjaxResult.success(resultMap);
     }
+
+    /**
+     * 获取未读互动数量
+     */
+    @Override
+    public AjaxResult getCommentInteractionCount(CommentInteractionVo commentInteractionVo) {
+        Long userId = SecurityUtils.getUserId();
+        String commentInteractionUserCountKey = COMMENT_INTERACTION_USER_COUNT + userId;
+        Object commentInteractionUserCount = redisCache.getCacheObject(commentInteractionUserCountKey);
+        int commentInteractionUserCountInt = 0;
+        if (ObjectUtils.isNotEmpty(commentInteractionUserCount)) {
+            commentInteractionUserCountInt = Integer.parseInt(commentInteractionUserCount.toString());
+        }
+        return AjaxResult.success(commentInteractionUserCountInt);
+    }
 }

+ 24 - 2
ruoyi-system/src/main/resources/mapper/system/CommentIndexMapper.xml

@@ -231,6 +231,7 @@
             comment_index i
                 LEFT JOIN comment_content c ON i.content_id = c.content_id
         <where>
+            i.del_flag = 'N'
             <if test="communityId != null ">and i.community_id = #{communityId}</if>
             <if test="communityType != null  and communityType != ''">and i.community_type = #{communityType}</if>
             <if test="isRoot != null ">and i.is_root = #{isRoot}</if>
@@ -246,8 +247,29 @@
             <if test="type != null "> and c.type = #{type}</if>
         </where>
     </select>
-    <select id="selectCommentIdListByCommentId" resultType="java.lang.Long">
-        select comment_id from comment_index where parent_id = #{commentId}
+    <select id="selectCommentIdListByCommentId" resultMap="CommentIndexResult">
+        SELECT
+            i.comment_id,
+            i.community_id,
+            i.community_type,
+            i.community_title,
+            i.is_root,
+            i.parent_id,
+            i.user_id,
+            i.nick_name,
+            i.avatar,
+            i.to_user_id,
+            i.to_nick_name,
+            i.to_avatar,
+            i.content_id,
+            i.comment_content,
+        FROM
+            comment_index i
+                LEFT JOIN comment_content c ON i.comment_id = c.comment_id
+        WHERE
+            i.parent_id = #{commentId}
+          AND i.del_flag = 'N'
+          AND c.`status` = 2
     </select>