tjf 2 mesiacov pred
rodič
commit
80051a55da

+ 7 - 1
pom.xml

@@ -18,6 +18,7 @@
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <java.version>17</java.version>
+        <fastjson.version>2.0.53</fastjson.version>
         <mybatis.version>3.5.16</mybatis.version>
         <springdoc.version>2.8.5</springdoc.version>
         <therapi-javadoc.version>0.15.0</therapi-javadoc.version>
@@ -313,7 +314,6 @@
                 <artifactId>mapstruct-plus-spring-boot-starter</artifactId>
                 <version>${mapstruct-plus.version}</version>
             </dependency>
-
             <!-- 离线IP地址定位库 ip2region -->
             <dependency>
                 <groupId>org.lionsoul</groupId>
@@ -364,6 +364,12 @@
                 <version>${revision}</version>
             </dependency>
 
+<!--            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-wuye</artifactId>
+                <version>${revision}</version>
+            </dependency>-->
+
         </dependencies>
     </dependencyManagement>
 

+ 6 - 0
ruoyi-admin/pom.xml

@@ -87,6 +87,12 @@
 <!--            <artifactId>ruoyi-demo</artifactId>-->
 <!--        </dependency>-->
 
+        <!--物业模块-->
+<!--        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-wuye</artifactId>
+        </dependency>-->
+
         <!--  工作流模块  -->
         <dependency>
             <groupId>org.dromara</groupId>

+ 6 - 3
ruoyi-common/ruoyi-common-core/pom.xml

@@ -119,9 +119,12 @@
             <groupId>org.apache.tomcat.embed</groupId>
             <artifactId>tomcat-embed-core</artifactId>
         </dependency>
-
-
-
+        <!-- 阿里JSON解析器 -->
+        <dependency>
+            <groupId>com.alibaba.fastjson2</groupId>
+            <artifactId>fastjson2</artifactId>
+            <version>2.0.53</version>
+        </dependency>
     </dependencies>
 
 </project>

+ 33 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/IdCardVo.java

@@ -0,0 +1,33 @@
+package org.dromara.common.core.domain;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @Author: tjf
+ * @Date: 2024/4/23 14:58
+ * @Describe:
+ */
+@Data
+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;
+
+}

+ 65 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Base64Util.java

@@ -0,0 +1,65 @@
+package org.dromara.common.core.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/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/FileUtil.java

@@ -0,0 +1,72 @@
+package org.dromara.common.core.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/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/HttpUtil.java

@@ -0,0 +1,77 @@
+package org.dromara.common.core.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 HttpUtil {
+
+    public static String post(String requestUrl, String accessToken, String params)
+            throws Exception {
+        String contentType = "application/x-www-form-urlencoded";
+        return HttpUtil.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 HttpUtil.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 HttpUtil.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;
+    }
+}

+ 77 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/HttpUtils.java

@@ -0,0 +1,77 @@
+package org.dromara.common.core.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;
+    }
+}

+ 875 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/IdCardUtil.java

@@ -0,0 +1,875 @@
+package org.dromara.common.core.utils;
+
+/**
+ * @Author: tjf
+ * @Date: 2024/4/17 9:35
+ * @Describe:
+ */
+
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import org.dromara.common.core.domain.R;
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.dromara.common.core.constant.Constants.BACK;
+import static org.dromara.common.core.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 R<Map<String, Object>> 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 R.ok(map);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return R.fail();
+    }
+
+    /**
+     * 加密图片
+     *
+     * @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 R<Map<String, Object>> 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 = org.dromara.common.core.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 R.fail("营业执照识别失败,请检查。");
+            }
+            return R.ok(map);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return R.fail();
+    }
+
+
+    /**
+     * 重要提示代码中所需工具类
+     * 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 R<String> licensePlate(String image) {
+        // 请求url
+        String url = "https://aip.baidubce.com/rest/2.0/ocr/v1/license_plate";
+        try {
+            // 本地文件路径
+            byte[] imgData = FileUtil.readFileByBytes(image);
+            String imgStr = org.dromara.common.core.utils.Base64Util.encode(imgData);
+            String imgParam = URLEncoder.encode(imgStr, "UTF-8");
+            String param = "image=" + imgParam;
+            // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。
+            String accessToken = getAccessToken("TvvuZOOh7MgnlDFnw11ln67n", "CY47OI0eKAzYBD2LO55SM3OITzsyq6DK");
+            String result = org.dromara.common.core.utils.HttpUtil.post(url, accessToken, param);
+            JSONObject jsonObject = JSONObject.parseObject(result);
+            String wordsResult = jsonObject.getString("words_result");
+            if (StringUtils.isNotEmpty(wordsResult)) {
+                JSONObject jsonObjectWordsResult = JSON.parseObject(wordsResult);
+                String plateNumber = jsonObjectWordsResult.getString("number");
+                System.out.println("车牌:" + plateNumber);
+                return R.ok(plateNumber);
+            }
+            /**
+             *
+             {
+             "words_result": [
+             {
+             "color": "blue",
+             "number": "京KBT355",
+             "probability": [
+             0.9999992847,
+             0.999999404,
+             0.9999910593,
+             0.9999765158,
+             0.999994874,
+             0.9998959303,
+             0.9999984503
+             ],
+             "vertexes_location": [
+             {
+             "x": 495,
+             "y": 589
+             },
+             {
+             "x": 800,
+             "y": 587
+             },
+             {
+             "x": 800,
+             "y": 676
+             },
+             {
+             "x": 496,
+             "y": 678
+             }
+             ]
+             }
+             ],
+             "log_id": "6845817085824549137"
+             }
+             */
+            System.out.println(result);
+            return R.fail("识别车牌错误返回:" + result);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return R.fail();
+    }
+
+    /**
+     * 重要提示代码中所需工具类
+     * 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 R<Map<String, Object>> vehicleLicense(String image) {
+        // 请求url
+        String url = "https://aip.baidubce.com/rest/2.0/ocr/v1/vehicle_license";
+        try {
+            // 本地文件路径
+
+            byte[] imgData = FileUtil.readFileByBytes(image);
+            String imgStr = org.dromara.common.core.utils.Base64Util.encode(imgData);
+            String imgParam = URLEncoder.encode(imgStr, "UTF-8");
+            String param = "image=" + imgParam;
+            // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。
+            String accessToken = getAccessToken("TvvuZOOh7MgnlDFnw11ln67n", "CY47OI0eKAzYBD2LO55SM3OITzsyq6DK");
+            String result = org.dromara.common.core.utils.HttpUtil.post(url, accessToken, param);
+            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 vehicleBrand = JSON.parseObject(jsonObjectWordsResult.getString("品牌型号")).getString("words");
+                String vehicleType = JSON.parseObject(jsonObjectWordsResult.getString("车辆类型")).getString("words");
+                String engineNumber = JSON.parseObject(jsonObjectWordsResult.getString("发动机号码")).getString("words");
+                String identificationNumber = JSON.parseObject(jsonObjectWordsResult.getString("车辆识别代号")).getString("words");
+                String registrationDate = JSON.parseObject(jsonObjectWordsResult.getString("注册日期")).getString("words");
+                String issueDate = JSON.parseObject(jsonObjectWordsResult.getString("发证日期")).getString("words");
+                String plateNumber = JSON.parseObject(jsonObjectWordsResult.getString("号牌号码")).getString("words");
+                map.put("vehicleBrand",vehicleBrand);
+                map.put("vehicleType",vehicleType);
+                map.put("engineNumber",engineNumber);
+                map.put("identificationNumber",identificationNumber);
+                map.put("registrationDate",registrationDate);
+                map.put("issueDate",issueDate);
+                map.put("plateNumber",plateNumber);
+                System.out.println("行驶证识别"+map);
+            }
+            System.out.println(result);
+            return R.ok(map);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return R.fail();
+    }
+
+
+    /**
+     * 重要提示代码中所需工具类
+     * 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 R<Map<String, Object>> realEstateCertificate(String image) {
+        // 请求url
+        String url = "https://aip.baidubce.com/rest/2.0/ocr/v1/real_estate_certificate";
+        try {
+            // 本地文件路径
+            byte[] imgData = FileUtil.readFileByBytes(image);
+            String imgStr = org.dromara.common.core.utils.Base64Util.encode(imgData);
+            String imgParam = URLEncoder.encode(imgStr, "UTF-8");
+
+            String param = "image=" + imgParam;
+
+            // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。
+            String accessToken = getAccessToken("TvvuZOOh7MgnlDFnw11ln67n", "CY47OI0eKAzYBD2LO55SM3OITzsyq6DK");
+            String result = org.dromara.common.core.utils.HttpUtil.post(url, accessToken, param);
+
+            /**
+             *
+             {
+             "words_result_num": 11,
+             "words_result": {
+             "权利人": [
+             {
+             "word": "阮兴武"
+             }
+             ],
+             "坐落": [
+             {
+             "word": "吉水县乌江镇前江村丰山组"
+             }
+             ],
+             "权利类型": [
+             {
+             "word": "宅基地使用权/房屋(构筑物)所有权"
+             }
+             ],
+             "面积": [
+             {
+             "word": "土地使用权面积:115.720㎡/房屋建筑面积:298.520㎡"
+             }
+             ],
+             "字第号": [
+             {
+             "word": "0042537"
+             }
+             ],
+             "不动产单元号": [
+             {
+             "word": "360822"
+             }
+             ],
+             "共有情况": [
+             {
+             "word": "家庭成员共有"
+             }
+             ],
+             "用途": [
+             {
+             "word": "农村宅基地/住宅"
+             }
+             ],
+             "使用期限": [
+             {
+             "word": ""
+             }
+             ],
+             "登记日期": [
+             {
+             "word": ""
+             }
+             ],
+             "共有人": [
+             {
+             "word": ""
+             }
+             ]
+             },
+             "log_id": 1739493844726379007
+             }
+             */
+            JSONObject jsonObject = JSONObject.parseObject(result);
+            String wordsResult = jsonObject.getString("words_result");
+            Map<String, Object> map = new HashMap<>(11);
+            if (StringUtils.isNotEmpty(wordsResult)) {
+                JSONObject jsonObjectWordsResult = JSON.parseObject(wordsResult);
+
+                JSONArray ownerNameArray = JSON.parseArray(jsonObjectWordsResult.getString("权利人"));
+                String ownerName = "";
+                if (ownerNameArray != null && ownerNameArray.size() > 0) {
+                    for (Object ownerNameResult : ownerNameArray) {
+                        ownerName = JSONObject.parseObject(ownerNameResult.toString()).getString("word") + ",";
+
+                    }
+                }
+                ownerName = ownerName.substring(0, ownerName.length() - 1);
+                String location = JSON.parseArray(jsonObjectWordsResult.getString("坐落")).getJSONObject(0).getString("word");
+                String rightType = JSON.parseArray(jsonObjectWordsResult.getString("权利类型")).getJSONObject(0).getString("word");
+                String area = JSON.parseArray(jsonObjectWordsResult.getString("面积")).getJSONObject(0).getString("word");
+                String documentNumber = JSON.parseArray(jsonObjectWordsResult.getString("字第号")).getJSONObject(0).getString("word");
+                String propertyUnitNumber = JSON.parseArray(jsonObjectWordsResult.getString("不动产单元号")).getJSONObject(0).getString("word");
+                String coOwnership = JSON.parseArray(jsonObjectWordsResult.getString("共有情况")).getJSONObject(0).getString("word");
+                String usageType = JSON.parseArray(jsonObjectWordsResult.getString("用途")).getJSONObject(0).getString("word");
+                String usagePeriod = JSON.parseArray(jsonObjectWordsResult.getString("使用期限")).getJSONObject(0).getString("word");
+                String registrationDate = JSON.parseArray(jsonObjectWordsResult.getString("登记日期")).getJSONObject(0).getString("word");
+                String coOwner = "";
+                JSONArray coOwnerArray = JSON.parseArray(jsonObjectWordsResult.getString("共有人"));
+                if (coOwnerArray != null && coOwnerArray.size() > 0) {
+                    for (Object coOwnerNameResult : coOwnerArray) {
+                        coOwner = JSONObject.parseObject(coOwnerNameResult.toString()).getString("word") + ",";
+                    }
+                }
+                coOwner = coOwner.substring(0, coOwner.length() - 1);
+                map.put("ownerName", ownerName);
+                map.put("location", location);
+                map.put("rightType", rightType);
+                map.put("area", area);
+                map.put("documentNumber", documentNumber);
+                map.put("propertyUnitNumber", propertyUnitNumber);
+                map.put("coOwnership", coOwnership);
+                map.put("usageType", usageType);
+                map.put("usagePeriod", usagePeriod);
+                map.put("registrationDate", registrationDate);
+                map.put("coOwner", coOwner);
+            } else {
+                return R.fail("房产证识别失败,请检查。");
+            }
+            System.out.println(result);
+            return R.ok(map);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return R.fail();
+    }
+
+    /**
+     * 获取文件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 - 0
ruoyi-modules/pom.xml

@@ -11,6 +11,7 @@
 
     <modules>
 <!--        <module>ruoyi-demo</module>-->
+<!--        <module>ruoyi-wuye</module>-->
         <module>ruoyi-generator</module>
         <module>ruoyi-job</module>
         <module>ruoyi-system</module>

+ 1 - 1
ruoyi-modules/ruoyi-generator/src/main/resources/generator.yml

@@ -3,7 +3,7 @@ gen:
   # 作者
   author: boman
   # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool
-  packageName: org.dromara.system
+  packageName: org.dromara.wuye
   # 自动去除表前缀,默认是false
   autoRemovePre: false
   # 表前缀(生成类名不会包含表前缀,多个用逗号分隔)

+ 4 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java

@@ -28,6 +28,10 @@ public class SysUserBo extends BaseEntity {
      * 用户ID
      */
     private Long userId;
+    /**
+     * 租户ID
+     */
+    private String tenantId;
 
     /**
      * 部门ID

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java

@@ -61,7 +61,7 @@ public class SysUserVo implements Serializable {
     /**
      * 用户邮箱
      */
-    @Sensitive(strategy = SensitiveStrategy.EMAIL, perms = "system:user:edit")
+    //@Sensitive(strategy = SensitiveStrategy.EMAIL, perms = "system:user:edit")
     private String email;
 
     /**

+ 9 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java

@@ -169,6 +169,13 @@ public interface ISysUserService {
      */
     int updateUser(SysUserBo user);
 
+    /**
+     * 根据id更新用户信息
+     * @param user 用户
+     * @return
+     */
+    int updateUserById(SysUserBo user);
+
     /**
      * 用户授权角色
      *
@@ -228,6 +235,8 @@ public interface ISysUserService {
      */
     int resetUserPwd(String phonenumber, String password);
 
+     void insertUserRole(SysUserBo user, boolean clear);
+
     /**
      * 通过用户ID删除用户
      *

+ 16 - 2
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java

@@ -336,7 +336,6 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
         insertUserRole(user, false);
         // 新增用户账号与租户
         SysUserVo sysUserVo = baseMapper.selectVoById(sysUser.getUserId());
-
         boolean enable = TenantHelper.isEnable();
         if (enable) {
             sysUserTenantMapper.insert(MapstructUtils.convert(sysUserVo, SysUserTenant.class));
@@ -382,6 +381,21 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
         return flag;
     }
 
+    /**
+     * 根据id更新用户信息
+     * @param user 用户
+     * @return
+     */
+    @Override
+    public int updateUserById(SysUserBo user) {
+        SysUser sysUser = MapstructUtils.convert(user, SysUser.class);
+        int flag = baseMapper.updateById(sysUser);
+        if (flag < 1) {
+            throw new ServiceException("修改用户" + user.getUserName() + "信息失败");
+        }
+        return flag;
+    }
+
     /**
      * 用户授权角色
      *
@@ -494,7 +508,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
      * @param user  用户对象
      * @param clear 清除已存在的关联数据
      */
-    private void insertUserRole(SysUserBo user, boolean clear) {
+    public void insertUserRole(SysUserBo user, boolean clear) {
         this.insertUserRole(user.getUserId(), user.getRoleIds(), clear);
     }