shenweidong 1 год назад
Родитель
Сommit
f6ca946577

+ 178 - 0
commons/src/main/java/com/jzg/commons/util/AESUtils.java

@@ -0,0 +1,178 @@
+package com.jzg.commons.util;
+
+import com.alibaba.fastjson.JSON;
+import org.apache.commons.codec.binary.Base64;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+import java.net.URLDecoder;
+
+/**
+ * @description:
+ * @author: shenwd
+ * @date: 2025/3/4 17:14
+ **/
+public class AESUtils {
+    private static final String ECB_PKCS5_PADDING = "AES/ECB/PKCS5Padding";
+
+    private static final String AES = "AES";
+
+    //编码方式
+    public static final String CODE_TYPE = "UTF-8";
+
+    // 秘钥
+//    private static final String sessionKey = "1237891234567589";
+
+    /**
+     * AES 加密操作  ECBPK5Hex
+     *
+     * @param content 待加密内容
+     * @return 返回Base64转码后的加密数据
+     */
+    public static String encryptECBPK5Hex(String content, String sessionKey) {
+        byte[] result = null;
+        if (content == null || "".equals(content)) {
+            return content;
+        }
+        try {
+            byte[] byteContent = content.getBytes(CODE_TYPE);
+            //使用加密秘钥
+            SecretKeySpec skeySpec = new SecretKeySpec(sessionKey.getBytes(CODE_TYPE), AES);
+            /*
+             * 新建一个密码编译器的实例,由三部分构成,用"/"分隔,分别代表如下
+             * 1. 加密的类型(如AES,DES,RC2等)
+             * 2. 模式(AES中包含ECB,CBC,CFB,CTR,CTS等)
+             * 3. 补码方式(包含nopadding/PKCS5Padding等等)
+             * 依据这三个参数可以创建很多种加密方式
+             */
+            synchronized (Cipher.class) {
+                Cipher cipher = Cipher.getInstance(ECB_PKCS5_PADDING);//"AES/ECB/PKCS5Padding";
+                cipher.init(Cipher.ENCRYPT_MODE, skeySpec);// 初始化为加密模式的密码器
+                result = cipher.doFinal(byteContent);// 加密
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+        return byteToHex(result);//通过hex转码返回
+    }
+
+    /**
+     * AES 解密操作  ECBPK5Hex
+     *
+     * @param content
+     * @return
+     */
+    public static String decryptECBPK5Hex(String content, String sessionKey) {
+        String returnStr = content;
+        byte[] result;
+        if (content == null || "".equals(content)) {
+            return content;
+        }
+        try {
+            //使用加密秘钥
+            SecretKeySpec skeySpec = new SecretKeySpec(sessionKey.getBytes(CODE_TYPE), AES);
+            synchronized (Cipher.class) {
+                //实例化
+                Cipher cipher = Cipher.getInstance(ECB_PKCS5_PADDING);
+                cipher.init(Cipher.DECRYPT_MODE, skeySpec);// 初始化为加密模式的密码器
+                result = cipher.doFinal(hexToByte(content));
+            }
+            returnStr = new String(result, CODE_TYPE);
+        } catch (Exception ex) {
+        }
+        return returnStr;
+    }
+
+    public static String byteToHex(byte[] bytes) {
+        String strHex = "";
+        StringBuilder sb = new StringBuilder("");
+        for (int n = 0; n < bytes.length; n++) {
+            strHex = Integer.toHexString(bytes[n] & 0xFF);
+            sb.append((strHex.length() == 1) ? "0" + strHex : strHex); // 每个字节由两个字符表示,位数不够,高位补0
+        }
+        return sb.toString().trim();
+    }
+
+    public static byte[] hexToByte(String hex) throws Exception {
+        hex = URLDecoder.decode(hex, CODE_TYPE);
+        int m = 0, n = 0;
+        int byteLen = hex.length() / 2; // 每两个字符描述一个字节
+        byte[] ret = new byte[byteLen];
+        for (int i = 0; i < byteLen; i++) {
+            m = i * 2 + 1;
+            n = m + 1;
+            int intVal = Integer.decode("0x" + hex.substring(i * 2, m) + hex.substring(m, n));
+            ret[i] = Byte.valueOf((byte) intVal);
+        }
+        return ret;
+    }
+
+
+    public static <T> T decryptMessage(String s, Class<T> c, String message, String sessionKey) {
+        //InsuranceLog.infoLog(InsuranceEnum.ZMBX.getPinyin(), "\n\t---------> 解密前的参数:{}", s);
+        // 解密
+        String text = decryptECBPK5Hex(s.replace("\n", ""), sessionKey);
+        //InsuranceLog.infoLog(InsuranceEnum.ZMBX.getPinyin(), "\n\t---------> {}:{}", message, text);
+        return JSON.parseObject(text, c);
+    }
+
+    /**
+     * AES 加密操作  ECBPK5-Base64
+     *
+     * @param content
+     * @return
+     */
+    public static String encryptECBPK5Base64(String content, String sessionKey) {
+        byte[] result = null;
+        if (content == null || "".equals(content)) {
+            return content;
+        }
+        try {
+            byte[] byteContent = content.getBytes(CODE_TYPE);
+            //使用加密秘钥
+            SecretKeySpec skeySpec = new SecretKeySpec(sessionKey.getBytes(CODE_TYPE), AES);
+            /*
+             * 新建一个密码编译器的实例,由三部分构成,用"/"分隔,分别代表如下
+             * 1. 加密的类型(如AES,DES,RC2等)
+             * 2. 模式(AES中包含ECB,CBC,CFB,CTR,CTS等)
+             * 3. 补码方式(包含nopadding/PKCS5Padding等等)
+             * 依据这三个参数可以创建很多种加密方式
+             */
+            synchronized (Cipher.class) {
+                Cipher cipher = Cipher.getInstance(ECB_PKCS5_PADDING);//"AES/ECB/PKCS5Padding";
+                cipher.init(Cipher.ENCRYPT_MODE, skeySpec);// 初始化为加密模式的密码器
+                result = cipher.doFinal(byteContent);// 加密
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+        return Base64.encodeBase64String(result);//通过base64转码返回
+    }
+
+    /**
+     * AES 解密操作  ECBPK5-Base64
+     *
+     * @param content
+     * @return
+     */
+    public static String decryptECBPK5Base64(String content, String sessionKey) {
+        String returnStr = content;
+        byte[] result;
+        if (content == null || "".equals(content)) {
+            return content;
+        }
+        try {
+            //使用加密秘钥
+            SecretKeySpec skeySpec = new SecretKeySpec(sessionKey.getBytes(CODE_TYPE), AES);
+            synchronized (Cipher.class) {
+                //实例化
+                Cipher cipher = Cipher.getInstance(ECB_PKCS5_PADDING);
+                cipher.init(Cipher.DECRYPT_MODE, skeySpec);// 初始化为加密模式的密码器
+                result = cipher.doFinal(Base64.decodeBase64(content));
+            }
+            returnStr = new String(result, CODE_TYPE);
+        } catch (Exception ex) {
+        }
+        return returnStr;
+    }
+}

+ 366 - 0
commons/src/main/java/com/jzg/commons/util/IDCardUtils.java

@@ -0,0 +1,366 @@
+package com.jzg.commons.util;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @description: todo
+ * @author: shenwd
+ * @date: 2025/3/3 17:35
+ **/
+public class IDCardUtils {
+    /**
+     * <p>
+     * 身份证号码合法性校验。
+     *
+     * @return boolean
+     * @author: aidy
+     */
+    public static boolean idCardValidate(String idStr) {
+        String errorInfo = null;// 记录错误信息
+        String[] ValCodeArr = {"1", "0", "x", "9", "8", "7", "6", "5", "4", "3", "2"};
+        String[] Wi = {"7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7", "9", "10", "5", "8", "4", "2"};
+        // String[] Checker = {"1","9","8","7","6","5","4","3","2","1","1"};
+        String ai = "";
+        if (StringUtils.isEmpty(idStr)) {
+            return false;
+        } else {
+
+            if (idStr.length() != 15 && idStr.length() != 18) {
+                errorInfo = "号码长度应该为15位或18位。";
+                return false;
+            }
+
+            // ================ 数字 除最后一位都为数字 ================
+            if (idStr.length() == 18) {
+                ai = idStr.substring(0, 17);
+            } else if (idStr.length() == 15) {
+                ai = idStr.substring(0, 6) + "19" + idStr.substring(6, 15);
+            }
+            if (isNumeric(ai) == false) {
+                errorInfo = "15位号码都应为数字 ; 18位号码除最后一位外,都应为数字。";
+                return false;
+            }
+            // =======================(end)========================
+
+            // ================ 出生年月是否有效 ================
+            String strYear = ai.substring(6, 10);// 年份
+            String strMonth = ai.substring(10, 12);// 月份
+            String strDay = ai.substring(12, 14);// 月份
+            String birthday = ai.substring(6, 14);
+
+            if (!isDate(birthday)) {
+                errorInfo = "生日无效。";
+                return false;
+            }
+
+            GregorianCalendar gc = new GregorianCalendar();
+            SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd");
+            try {
+                if ((gc.get(Calendar.YEAR) - Integer.parseInt(strYear)) > 150
+                        || (gc.getTime().getTime() - s.parse(strYear + "-" + strMonth + "-" + strDay).getTime()) < 0) {
+                    errorInfo = "生日不在有效范围。";
+                    return false;
+                }
+            } catch (NumberFormatException e) {
+                e.printStackTrace();
+                return false;
+            } catch (ParseException e) {
+                e.printStackTrace();
+                return false;
+            }
+            if (Integer.parseInt(strMonth) > 12 || Integer.parseInt(strMonth) == 0) {
+                errorInfo = "月份无效";
+                return false;
+            }
+            if (Integer.parseInt(strDay) > 31 || Integer.parseInt(strDay) == 0) {
+                errorInfo = "日期无效";
+                return false;
+            }
+            // =====================(end)=====================
+
+            // ================ 地区码时候有效 ================
+            Hashtable<String, String> h = GetAreaCode();
+            if (h.get(ai.substring(0, 2)) == null) {
+                errorInfo = "地区编码错误。";
+                return false;
+            }
+            // ==============================================
+
+            // ================ 判断最后一位的值 ================
+            int totalmulAiWi = 0;
+            for (int i = 0; i < 17; i++) {
+                totalmulAiWi = totalmulAiWi + Integer.parseInt(String.valueOf(ai.charAt(i))) * Integer.parseInt(Wi[i]);
+            }
+            int modValue = totalmulAiWi % 11;
+            String strVerifyCode = ValCodeArr[modValue];
+            ai = ai + strVerifyCode;
+
+            if (idStr.length() == 18) {
+                if (ai.equalsIgnoreCase(idStr) == false) {
+                    errorInfo = "身份证无效,最后一位字母错误";
+                    return false;
+                }
+            } else {
+                //				System.out.println("所在地区:" + h.get(ai.substring(0, 2).toString()));
+                //				System.out.println("新身份证号:" + ai);
+                return true;
+            }
+            // =====================(end)=====================
+
+            if (StringUtils.isEmpty(errorInfo)) {
+                return false;
+            } else {
+                return true;
+            }
+
+        }
+
+    }
+
+    /**
+     * <p>
+     * 判断字符串是否为数字
+     *
+     * @return boolean
+     * @author: aidy
+     */
+    private static boolean isNumeric(String str) {
+        Pattern pattern = Pattern.compile("[0-9]*");
+        Matcher isNum = pattern.matcher(str);
+        if (isNum.matches()) {
+            return true;
+        } else {
+            return false;
+        }
+        /**//*
+         * 判断一个字符时候为数字 if(Character.isDigit(str.charAt(0))) { return true; }
+         * else { return false; }
+         */
+    }
+
+    /**
+     * <p>
+     * 判断字符串是否为日期格式
+     *
+     * @return boolean
+     * @author: aidy
+     */
+    public static boolean isDate(String strDate) {
+        String DatePattern = "^(?:([0-9]{4}(?:(?:0?[1,3-9]|1[0-2])(?:29|30)|((?:0?[13578]|1[02])-31)))|"
+                + "([0-9]{4}(?:0?[1-9]|1[0-2])(?:0?[1-9]|1\\d|2[0-8]))|"
+                + "(((?:(\\d\\d(?:0[48]|[2468][048]|[13579][26]))|"
+                + "(?:0[48]00|[2468][048]00|[13579][26]00))0?229)))$";
+        Pattern pattern = Pattern.compile(DatePattern);
+        Matcher m = pattern.matcher(strDate);
+        if (m.matches()) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * <p>
+     * 在判定已经是正确的身份证号码之后,查找出身份证所在地区。
+     *
+     * @return String
+     * @author: aidy
+     */
+    public String GetArea(String idCard) {
+        Hashtable<String, String> ht = GetAreaCode();
+        String area = ht.get(idCard.substring(0, 2));
+        return area;
+    }
+
+    /**
+     * <p>
+     * 在判定已经是正确的身份证号码之后,查找出此人性别(1:男;2:女)。
+     *
+     * @return String
+     * @author: aidy
+     */
+    public static String GetSex(String idCard) {
+        String sex = "";
+        if (idCard.length() == 15)
+            sex = idCard.substring(idCard.length() - 3, idCard.length());
+
+        if (idCard.length() == 18)
+            sex = idCard.substring(idCard.length() - 4, idCard.length() - 1);
+
+        //		System.out.println(sex);
+        int sexNum = Integer.parseInt(sex) % 2;
+        if (sexNum == 0) {
+            return "FEMALE";
+        }
+        return "MALE";
+    }
+
+
+    /**
+     * <p>  永诚使用返回对应编码
+     * 在判定已经是正确的身份证号码之后,查找出此人性别(1:男;2:女)。
+     *
+     * @return String
+     * @author: aidy
+     */
+    public static String GetYcSex(String idCard) {
+        String sex = "";
+        if (idCard.length() == 15)
+            sex = idCard.substring(idCard.length() - 3, idCard.length());
+
+        if (idCard.length() == 18)
+            sex = idCard.substring(idCard.length() - 4, idCard.length() - 1);
+
+        //		System.out.println(sex);
+        int sexNum = Integer.parseInt(sex) % 2;
+        if (sexNum == 0) {
+            return "106002";
+        }
+        return "106001";
+    }
+
+
+    /**
+     * <p>
+     * 在判定已经是正确的身份证号码之后,查找出此人出生日期
+     *
+     * @return String
+     * @author: aidy
+     */
+    public static String GetBirthday(String idCard) {
+        String Ain = "";
+        if (idCard.length() == 18) {
+            Ain = idCard.substring(0, 17);
+        } else if (idCard.length() == 15) {
+            Ain = idCard.substring(0, 6) + "19" + idCard.substring(6, 15);
+        }
+
+        // ================ 出生年月是否有效 ================
+        String strYear = Ain.substring(6, 10);// 年份
+        String strMonth = Ain.substring(10, 12);// 月份
+        String strDay = Ain.substring(12, 14);// 日期
+        return strYear + "-" + strMonth + "-" + strDay;
+    }
+
+    /**
+     * 在判定已经是正确的身份证号码之后,查找出此人年龄
+     * @param idCard
+     * @return
+     */
+    public static int getAgeFromIDCard(String idCard) {
+        String birthday = idCard.substring(6, 14);
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
+        try {
+            Date birthDate = dateFormat.parse(birthday);
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime(birthDate);
+            Calendar now = Calendar.getInstance();
+            int age = now.get(Calendar.YEAR) - calendar.get(Calendar.YEAR);
+            if (now.get(Calendar.MONTH) < calendar.get(Calendar.MONTH)
+                    || (now.get(Calendar.MONTH) == calendar.get(Calendar.MONTH)
+                    && now.get(Calendar.DAY_OF_MONTH) < calendar.get(Calendar.DAY_OF_MONTH))) {
+                age--;
+            }
+            return age;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return 0;
+    }
+
+
+    /**
+     * <p>
+     * 设置地区编码
+     *
+     * @return Hashtable
+     * @author: aidy
+     */
+    private static Hashtable<String, String> GetAreaCode() {
+        Hashtable<String, String> hashtable = new Hashtable<String, String>();
+        hashtable.put("11", "北京");
+        hashtable.put("12", "天津");
+        hashtable.put("13", "河北");
+        hashtable.put("14", "山西");
+        hashtable.put("15", "内蒙古");
+        hashtable.put("21", "辽宁");
+        hashtable.put("22", "吉林");
+        hashtable.put("23", "黑龙江");
+        hashtable.put("31", "上海");
+        hashtable.put("32", "江苏");
+        hashtable.put("33", "浙江");
+        hashtable.put("34", "安徽");
+        hashtable.put("35", "福建");
+        hashtable.put("36", "江西");
+        hashtable.put("37", "山东");
+        hashtable.put("41", "河南");
+        hashtable.put("42", "湖北");
+        hashtable.put("43", "湖南");
+        hashtable.put("44", "广东");
+        hashtable.put("45", "广西");
+        hashtable.put("46", "海南");
+        hashtable.put("50", "重庆");
+        hashtable.put("51", "四川");
+        hashtable.put("52", "贵州");
+        hashtable.put("53", "云南");
+        hashtable.put("54", "西藏");
+        hashtable.put("61", "陕西");
+        hashtable.put("62", "甘肃");
+        hashtable.put("63", "青海");
+        hashtable.put("64", "宁夏");
+        hashtable.put("65", "新疆");
+        hashtable.put("71", "台湾");
+        hashtable.put("81", "香港");
+        hashtable.put("82", "澳门");
+        hashtable.put("91", "国外");
+        return hashtable;
+    }
+
+
+    /**
+     * 根据身份证地址提取省市区工具类
+     *
+     * @param address
+     * @return
+     */
+    public static Map<String, String> addressResolution(String address) {
+        String regex = "(?<province>[^省]+自治区|.*?省|.*?行政区|.*?市|.*?蒙古)(?<city>[^市]+自治州|.*?地区|.*?行政单位|.+盟|市辖区|.*?市|.*?县|.*?区)(?<district>[^县]+县|.*?区|.+市|.*?旗|.+海域|.+岛)?(?<town>[^区]+区|.+镇)?(?<detail>.*)";
+
+//        if(address.indexOf("重庆市") == 0 || address.indexOf("上海市") == 0){
+//            regex = "(?<province>[^市].*?市)(?<city>[^县]+县|.*?区|.+市|.*?旗|.+海域|.+岛)(?<district>[^县]+县|.*?区|.+市|.*?旗|.+海域|.+岛)?(?<town>[^区]+区|.+镇)?(?<detail>.*)";
+//        }
+        if(address.indexOf("新疆") == 0){
+            regex = "(?<province>.*?新疆)(?<city>[^县]+县|.*?区|.+市|.*?旗|.+海域|.+岛)(?<district>[^县]+县|.*?区|.+市|.*?旗|.+海域|.+岛)?(?<town>[^区]+区|.+镇)?(?<detail>.*)";
+        }
+
+        Matcher m = Pattern.compile(regex).matcher(address);
+        String province = null, city = null, district = null, town = null, detail = null;
+//        List<Map<String, String>> table = new ArrayList<Map<String, String>>();
+        Map<String, String> row = null;
+        while (m.find()) {
+            row = new LinkedHashMap<String, String>();
+            province = m.group("province");
+            row.put("province", province == null ? "" : province.trim());
+            city = m.group("city");
+            row.put("city", city == null ? "" : city.trim());
+            district = m.group("district");
+            row.put("district", district == null ? "" : district.trim());
+            town = m.group("town");
+            row.put("town", town == null ? "" : town.trim());
+            detail = m.group("detail");
+            row.put("detail", detail == null ? "" : detail.trim());
+//            table.add(row);
+        }
+//        return table;
+        return row;
+    }
+
+    public static void main(String[] args) throws ParseException {
+        Map m = addressResolution("陕西省旬阳县赤岩镇闵家河村三组109号");
+        String IDCardNum = "43282219381105414X";
+    }
+}

+ 19 - 5
tenant/insurance/quotation-zhongmei/src/main/java/com/jzg/quote/zhongmei/api/componet/ZmApiRequestComponent.java

@@ -3,6 +3,7 @@ package com.jzg.quote.zhongmei.api.componet;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.serializer.SerializerFeature;
 import com.jzg.commons.exception.SystemException;
+import com.jzg.commons.util.AESUtils;
 import com.jzg.quotation.commons.component.RequestComponent;
 import com.jzg.quote.zhongmei.api.constant.TransCode;
 import com.jzg.quote.zhongmei.api.entity.ZmApiConfigureParameters;
@@ -35,13 +36,26 @@ import java.util.concurrent.TimeUnit;
 public class ZmApiRequestComponent {
     private final ZmApiProperties zmApiProperties;
 
-    private final RedissonClient redissonClient;
-
     private final RequestComponent requestComponent;
 
-    public <T, B extends BaseResponse> B requestUrl(String url, T requestBody, Class<B> responseType) {
-        ResponseEntity<B> bResponseEntity = requestComponent.objectPost(url, requestBody, responseType);
-        return bResponseEntity.getBody();
+    public <T extends BaseRequest, B extends BaseResponse> B requestUrl(String url, T requestBody, Class<B> responseType) {
+        HttpHeaders httpHeaders = new HttpHeaders();
+        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
+
+        String jsonString = JSON.toJSONString(requestBody, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty);
+        //InsuranceLog.infoLog(InsuranceEnum.ZMBX.getPinyin(), "\n\t---------> URl: {} \n---------> 请求参数:{}", url, jsonString);
+        // 加密
+        String sessionKey = zmApiProperties.getSessionKey();
+        String s = AESUtils.encryptECBPK5Hex(jsonString, sessionKey);
+        //InsuranceLog.infoLog(InsuranceEnum.ZMBX.getPinyin(), "\n\t---------> 加密后的参数:{}", s);
+        ResponseEntity<B> bResponseEntity = requestComponent.objectPost(url, s, responseType, httpHeaders);
+        String body = bResponseEntity.toString();//后续需联调观察数据
+
+        B b = AESUtils.decryptMessage(body, responseType, "响应参数", sessionKey);
+        if (ObjectUtils.isEmpty(b)) {
+            throw new SystemException("请求失败");
+        }
+        return b;
     }
 
     /**