diff --git a/crm/src/main/java/com/kakarote/crm/util/SM2Utils.java b/crm/src/main/java/com/kakarote/crm/util/SM2Utils.java new file mode 100644 index 0000000..6019391 --- /dev/null +++ b/crm/src/main/java/com/kakarote/crm/util/SM2Utils.java @@ -0,0 +1,347 @@ +package com.kakarote.crm.util; + +import cn.hutool.core.util.HexUtil; +import cn.hutool.crypto.SmUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.SM2; +import org.apache.log4j.Logger; +import org.bouncycastle.asn1.gm.GMNamedCurves; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.signers.SM2Signer; +import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; +import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.jce.spec.ECPrivateKeySpec; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.encoders.Hex; + +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.security.spec.ECGenParameterSpec; +import java.util.Base64; + +public class SM2Utils { + private static Logger log = Logger.getLogger(SM2Utils.class); + + /** + * 使用公钥加密 + * @param publicKey + * @param data + * @return + * @throws Exception + */ + public static byte[] encrypt(byte[] publicKey, byte[] data){ + SM2 sm2 = SmUtil.sm2(null, publicKey); + byte[] encrypt = sm2.encrypt(data, KeyType.PublicKey); + + return encrypt; + } + + /** + * 使用私钥解密 + * @param privateKey + * @param data + * @return + * @throws Exception + */ + public static byte[] decrypt(byte[] privateKey, byte[] data) throws Exception { + SM2 sm2 = SmUtil.sm2(privateKey, null); + byte[] decrypt = sm2.decrypt(data, KeyType.PrivateKey); + + return decrypt; + } + + /** + * 对数据进行加密 + * @param publicKey 公钥 + * @param data 明文数据 + * @return 密文 + */ + public static String encryptData(String publicKey, String data) { + try { + byte[] encrypt = SM2Utils.encrypt(HexUtil.decodeHex(publicKey), data.getBytes()); + String encryptedData = HexUtil.encodeHexStr(encrypt); + log.info("Encrypted data: {}"+ encryptedData); + return encryptedData; + } catch (Exception e) { + log.error("使用SM2公钥加密失败,失败原因为: {}",e); + throw new RuntimeException("使用SM2公钥加密失败,失败原因为:"+e); + } + } + + /** + * 对数据进行解密 + * @param privateKey 私钥 + * @param encryptedData 密文 + * @return 明文 + */ + public static String decryptData(String privateKey, String encryptedData) { + try { + byte[] decryptedData = decrypt(HexUtil.decodeHex(privateKey), HexUtil.decodeHex(encryptedData)); + String decryptedDataResult = new String(decryptedData); + log.info("Decrypted data: {}"+ decryptedDataResult); + return decryptedDataResult; + } catch (Exception e) { + log.error("使用SM2私钥解密失败,失败原因为: {}",e); + throw new RuntimeException("使用SM2私钥解密失败,失败原因为:"+e); + } + } + + /** + * @param data + * @param priKeyHexString hex私钥,长度64 + * @return hex格式签名值 + * @throws Exception + */ + public static String sign(String data, String priKeyHexString) throws Exception { + return sign(data.getBytes(StandardCharsets.UTF_8), priKeyHexString); + } + + /** + * 签名 + * @param data 原始数据,字节数组 + * @param priKeyHexString hex私钥,64长度 + * @return Hex字符串 + * @throws Exception + */ + public static String sign(byte[] data, String priKeyHexString) throws Exception { + String signValue = null; + SM2Signer signer = new SM2Signer(); + X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1"); + //构造domain参数 + ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN()); + CipherParameters param = new ParametersWithRandom(new ECPrivateKeyParameters(new BigInteger(priKeyHexString, 16), domainParameters)); + signer.init(true, param); + signer.update(data, 0, data.length); + signValue = Hex.toHexString(signer.generateSignature()); + return signValue; + } + + /** + * 验签 + * @param data 原始数据 + * @param signValue 原始签名值(hex型) + * @param publicKeyHexString hex130长度公钥 + * @return ture or false + * @throws Exception + */ + public static boolean verify(String data, String signValue, String publicKeyHexString) throws Exception { + return verify(data.getBytes(StandardCharsets.UTF_8), Hex.decode(signValue), publicKeyHexString); + } + + /** + * 验签 + * @param data 原始数据字节数组 + * @param sign 字节数组() + * @param publicKeyHexString hex130长度公钥 + * @return true or false + * @throws Exception + */ + public static boolean verify(byte[] data, byte[] sign, String publicKeyHexString) throws Exception { + SM2Signer signer = new SM2Signer(); + X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1"); + //构造domain参数 + ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN()); + if (publicKeyHexString.length() == 128) { + publicKeyHexString = "04" + publicKeyHexString; + } + ECPoint ecPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(publicKeyHexString)); + CipherParameters param = new ECPublicKeyParameters(ecPoint, domainParameters); + signer.init(false, param); + signer.update(data, 0, data.length); + return signer.verifySignature(sign); + } + + /** + * 私钥生成公钥 + * @param priKeyHexString 私钥Hex格式,必须64位 + * @return 公钥Hex格式,04开头,130位 + * @throws Exception 例如: + * 04181db7fe400641115c0dec08e23d8ddb94c5999f2fb6efd03030780142e077a63eb4d47947ef5baee7f40fec2c29181d2a714d9c6cba87b582f252a4e3e9a9f8 + * 11d0a44d47449d48d614f753ded6b06af76033b9c3a2af2b8b2239374ccbce3a + */ + public static String getPubKeyByPriKey(String priKeyHexString) throws Exception { + if (priKeyHexString == null || priKeyHexString.length() != 64) { + System.err.println("priKey 必须是Hex 64位格式,例如:11d0a44d47449d48d614f753ded6b06af76033b9c3a2af2b8b2239374ccbce3a"); + return ""; + } + String pubKeyHexString = null; + X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1"); + //构造domain参数 + BigInteger privateKeyD = new BigInteger(priKeyHexString, 16); + + ECParameterSpec ecParameterSpec = new ECParameterSpec(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN()); + ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(privateKeyD, ecParameterSpec); + PrivateKey privateKey = null; + privateKey = KeyFactory.getInstance("EC", new BouncyCastleProvider()).generatePrivate(ecPrivateKeySpec); + + // 临时解决办法 + String pointString = privateKey.toString(); +// System.out.println(pointString); + String pointString_X = pointString.substring(pointString.indexOf("X: ") + "X: ".length(), pointString.indexOf("Y: ")).trim(); + String pointString_Y = pointString.substring(pointString.indexOf("Y: ") + "Y: ".length()).trim(); +// System.out.println(pointString_X); +// System.out.println(pointString_Y); + + pubKeyHexString = "04" + pointString_X + pointString_Y; + return pubKeyHexString; + + } + + /** + * 生成 SM2 公私钥对 + * + * @return + * @throws NoSuchAlgorithmException + * @throws InvalidAlgorithmParameterException + */ + public static KeyPair geneSM2KeyPair() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { + final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1"); + // 获取一个椭圆曲线类型的密钥对生成器 + final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider()); + // 产生随机数 + SecureRandom secureRandom = new SecureRandom(); + // 使用SM2参数初始化生成器 + kpg.initialize(sm2Spec, secureRandom); + // 获取密钥对 + KeyPair keyPair = kpg.generateKeyPair(); + return keyPair; + } + + /** + * 生产hex秘钥对 + */ + public static void geneSM2HexKeyPair(){ + try { + KeyPair keyPair = geneSM2KeyPair(); + PrivateKey privateKey = keyPair.getPrivate(); + PublicKey publicKey = keyPair.getPublic(); + System.out.println("======== EC X Y keyPair ========"); + System.out.println(privateKey); + System.out.println(publicKey); + System.out.println("======== hex keyPair ========"); + System.out.println("hex priKey: " + getPriKeyHexString(privateKey)); + System.out.println("hex pubKey: " + getPubKeyHexString(publicKey)); + System.out.println("======== base64 keyPair ========"); + System.out.println("base64 priKey: " + new String(Base64.getEncoder().encode(privateKey.getEncoded()))); + System.out.println("base64 pubKey: " + new String(Base64.getEncoder().encode(publicKey.getEncoded()))); + System.out.println("======== generate finished ========"); + } catch (Exception e) { + e.printStackTrace(); + } + } + /** + * 获取私钥(16进制字符串,头部不带00长度共64) + * + * @param privateKey 私钥PrivateKey型 + * @return + */ + public static String getPriKeyHexString(PrivateKey privateKey) { + // OK + BCECPrivateKey key = (BCECPrivateKey) privateKey; + BigInteger intPrivateKey = key.getD(); + String priKeyHexString = intPrivateKey.toString(16); + return priKeyHexString; + } + /** + * 获取私钥 base64字符串 + * + * @param privateKey 私钥PrivateKey型 + * @return + */ + public static String getPriKeyBase64String(PrivateKey privateKey) { + return new String(Base64.getEncoder().encode(privateKey.getEncoded())); + } + + /** + * 获取公钥(16进制字符串,头部带04长度共130) + * + * @param publicKey 公钥PublicKey型 + * @return + */ + public static String getPubKeyHexString(PublicKey publicKey) { + BCECPublicKey key = (BCECPublicKey) publicKey; + return Hex.toHexString(key.getQ().getEncoded(false)); + } + /** + * 获取公钥 base64字符串 + * + * @param publicKey 公钥PublicKey型 + * @return + */ + public static String getPubKeyBase64String(PublicKey publicKey) { + return new String(Base64.getEncoder().encode(publicKey.getEncoded())); + } + + public static void main(String[] args) throws Exception { + System.out.println("====== sm2utils test ======"); + + String M = "data_message"; + System.out.println("mingwen\t" + M); + + System.out.println("begin 开始生成密钥对>>>"); + KeyPair keyPair = geneSM2KeyPair(); + + PublicKey publicKey = keyPair.getPublic(); + String pubKeyHexString = getPubKeyHexString(publicKey); + System.out.println("publicKey\t" + pubKeyHexString); + + PrivateKey privateKey = keyPair.getPrivate(); + String priKeyHexString = getPriKeyHexString(privateKey); + System.out.println("privateKey\t" + priKeyHexString); + System.out.println("end 结束生成密钥对>>>"); + + priKeyHexString="4f0341e5977b175e0ec0e1fdefd2799b13dd25c51716133ef42ba76c0edd973d"; //1 + pubKeyHexString="04e523210b3407464839723558e0d82765b9e2cac9491bd86c99c89b9fc43fbe9a94395ee3138dbc4ae43daa8fe01fd512de8568102e34c66989eb2b306611b518"; //1 + + String sign = sign(M, priKeyHexString); + System.out.println("signvalue\t" + sign); + sign="304402204bbd4b026f58f1e072c2ab1f736a730ed5c2f6773ef4855df5e87f9ea54f14be02205e9b6146b5273e6f37fe6d9d8f059bc46f7042a10da224130a4e0ba8619d967c"; + + boolean verifyResult = verify(M, sign, pubKeyHexString); + System.out.println("verifyResult\t" + verifyResult); + + } + + // 测试生产密钥对 + public void testCreateKeyPair() throws Exception{ + KeyPair keyPair = SM2Utils.geneSM2KeyPair(); + System.out.println("priKeyString :"+SM2Utils.getPriKeyHexString(keyPair.getPrivate())); + System.out.println("pukKeyString :"+SM2Utils.getPubKeyHexString(keyPair.getPublic())); + } + // 私钥推算公钥 + public void testGenPubKeyByPriKey() throws Exception{ + String priKeyString ="898668e2a83b24637bd24b7c777a1efb4d145fdb5c9c16c8e699ece1ff03f519"; + String pubKeyString = SM2Utils.getPubKeyByPriKey(priKeyString); + System.out.println("priKeyString :" + priKeyString); + System.out.println("pukKeyString :" + pubKeyString); + } + // 签名 + public void testDoSign() throws Exception{ + String text="sm2test"; + String priKeyString ="898668e2a83b24637bd24b7c777a1efb4d145fdb5c9c16c8e699ece1ff03f519"; + String signValue=SM2Utils.sign(text,priKeyString); + System.out.println("text :"+text); + System.out.println("priKeyString :"+priKeyString); + System.out.println("signValue :"+signValue); + } + // 验签 + public void testSignVerify() throws Exception{ + String text="sm2test"; + String pubKeyString ="04646adab38ab0ea0105f25d22f17bce8641d289fa17c6db3fd1698bdcac1f002517eaf1acb9485dfae98f1bfcfa1667a6e72ddb87098b33afad8e71225e877cec"; + String signValue="3045022100c07596cf82b81c4dfa150eeac5feaa47a57ac9da713c0ee9feebe218d6b3867102207d4f9ae77c0342898f9afae27e8d80f4d45855923cdbcdc34458906c35cd3e58"; + boolean isPass = SM2Utils.verify(text,signValue,pubKeyString); + System.out.println("text :"+text); + System.out.println("pubKeyString :"+pubKeyString); + System.out.println("signValue :"+signValue); + System.out.println("isPass :"+isPass); + } + +} diff --git a/crm/src/main/java/com/kakarote/crm/util/StringUtil.java b/crm/src/main/java/com/kakarote/crm/util/StringUtil.java new file mode 100644 index 0000000..f23a700 --- /dev/null +++ b/crm/src/main/java/com/kakarote/crm/util/StringUtil.java @@ -0,0 +1,795 @@ +package com.kakarote.crm.util; + +import javax.servlet.http.HttpServletRequest; +import java.io.*; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.DecimalFormat; +import java.util.List; +import java.util.Random; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 字符串工具类 + * Created with IntelliJ IDEA. + * + * @author : 黄小斌 + * @since 16-9-8下午3:56 + */ +public class StringUtil { + private static final Pattern linePattern = Pattern.compile("_(\\w)"); + private static final char[] ALPHANUMERIC = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".toCharArray(); + private static final char[] NUMBER = "1234567890".toCharArray(); + private static final char[] LETTER = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); + + /** + * 生成UUID + * + * @return uuid + */ + public static String createUUID() { + String uuid = UUID.randomUUID().toString(); + uuid = uuid.replaceAll("-", ""); + return uuid; + } + + /** + * 删除左侧空格 + * + * @param str 需要删除的字符串 + * @return 删除空格后的字符串 + */ + public static String removeLeftBlank(String str) { + return null == str ? "" : str.replaceAll("^[ ]*", ""); + } + + /** + * 删除右侧空格 + * + * @param str 需要删除的字符串 + * @return 删除空格后的字符串 + */ + public static String removeRightBlank(String str) { + return null == str ? "" : str.replaceAll("[ ]*$", ""); + } + + /** + * 删除所有空格 + * + * @param str 需要删除的字符串 + * @return 删除空格后的字符串 + */ + public static String removeAllBlank(String str) { + return null == str ? "" : str.replaceAll("[ ]*", ""); + } + + /** + * 下划线转驼峰 + * + * @param str 传入的str + * @return 返回驼峰命名的str + */ + public static String line2Hump(String str) { + str = str.toLowerCase(); + Matcher matcher = linePattern.matcher(str); + StringBuffer sb = new StringBuffer(); + while (matcher.find()) { + matcher.appendReplacement(sb, matcher.group(1).toUpperCase()); + } + matcher.appendTail(sb); + return sb.toString(); + } + + /** + * 按字符分割字符串 + * + * @param str 字符串 + * @param strIn 分割符 + * @return 字符串数组 + */ + public static String[] split(String str, String strIn) { + char[] tempArray = str.toCharArray(); + int strLength = str.length(); + int strInLength = strIn.length(); + int strInTimes = 0; + int[] strIndex = new int[strLength]; + int i = 0; + int ii = 0; + while (i <= strLength - strInLength) { + StringBuilder tempStr = new StringBuilder(); + for (int j = i; j < i + strInLength; j++) { + tempStr.append(tempArray[j]); + } + + if (tempStr.toString().equals(strIn)) { + strInTimes++; + strIndex[ii] = i; + i += strInLength; + ii++; + } else { + i++; + } + } + if (strInTimes < 1) { + return (new String[]{str}); + } + String[] backStr = new String[strInTimes + 1]; + backStr[0] = str.substring(0, strIndex[0]); + for (int k = 1; k < strInTimes; k++) { + backStr[k] = str.substring(strIndex[k - 1] + strInLength, strIndex[k]); + } + + backStr[strInTimes] = str.substring(strIndex[strInTimes - 1] + strInLength, str.length()); + return backStr; + } + + /** + * 将String数组拼接成一个字符串 + * + * @param array String数组 + * @param separator 拼接字符 + * @return 拼接后的字符串 + */ + public static String join(String[] array, String separator) { + StringBuilder result = new StringBuilder(); + if (null != array && 0 < array.length) { + if (null == separator) { + separator = ""; + } + for (int i = 0; i < array.length; i++) { + result.append(getStr(array[i])); + if (i <= array.length - 1) { + result.append(separator); + } + } + } + return result.toString(); + } + + /** + * 按长度分割字符串 + * + * @param str 字符串 + * @param length 分割符 + * @return 字符串数组 + */ + public static String[] split(String str, int length) { + int count = str.length() / length; + int ys = str.length() % length; + if (ys > 0) { + count++; + } + String[] strArr = new String[count]; + if (ys == 0) { + for (int i = 0; i < count; i++) { + strArr[i] = str.substring(i * length, (i + 1) * length); + } + } else { + strArr[0] = str.substring(0, ys); + for (int i = 1; i < count; i++) { + strArr[i] = str.substring(ys + (i - 1) * length, ys + i * length); + } + } + + return strArr; + } + + /** + * 向左填充字符 + * + * @param src 原字符串 + * @param padding 填充字符串 + * @param len 最大字符串 + * @return 填充后的字符串 + */ + public static String lPad(String src, String padding, int len) { + StringBuilder str = new StringBuilder("" + src); + while (str.length() < len) { + str.insert(0, padding); + } + + return str.toString(); + } + + /** + * 判断是否为空 + * + * @param o Object + * @return true、空,false、不为空 + */ + public static boolean isEmpty(Object o) { + if (null == o) { + return true; + } + if (o instanceof String) { + return "".equals(o.toString().trim()); + } else { + return o instanceof List && ((List) o).isEmpty(); + } + } + + public static boolean isNotEmpty(Object o) { + return !isEmpty(o); + } + + /** + * 字符串中字符的个数 + * + * @param str string + * @param c char + * @return 字符串中字符的个数 + */ + public static int count(String str, char c) { + if (isEmpty(str)) { + return 0; + } + int len = str.length(); + int count = 0; + for (int i = 0; i < len; i++) { + if (c == str.charAt(i)) { + count++; + } + } + return count; + } + + /** + * 生成随机字符串 + * 只包含大小写字母和数字 + * + * @param len 随机字符串长度 + * @return 随机字符串 + */ + public static String getRandom(int len) { + return getRandom(ALPHANUMERIC, len); + } + + /** + * 生成随机字符串 + * 只包含数字 + * + * @param len 随机字符串长度 + * @return 随机字符串 + */ + public static String getNumberRandom(int len) { + return getRandom(NUMBER, len); + } + + /** + * 生成随机字符串 + * 只包含大小写字母 + * + * @param len 随机字符串长度 + * @return 随机字符串 + */ + public static String getLetterRandom(int len) { + return getRandom(LETTER, len); + } + + /** + * 根据提供的源,生成随机字符串 + * + * @param source 随机字符串的源 + * @param len 随机字符串长度 + * @return 随机字符串 + */ + public static String getRandom(String source, int len) { + if (isEmpty(source)) { + return getRandom(len); + } else { + return getRandom(source.toCharArray(), len); + } + } + + /** + * 根据提供的源,生成随机字符串 + * + * @param source 随机字符串的源 + * @param len 随机字符串长度 + * @return 随机字符串 + */ + public static String getRandom(char[] source, int len) { + StringBuilder sb = new StringBuilder(); + Random r = new Random(); + for (int x = 0; x < len; ++x) { + sb.append(source[r.nextInt(source.length)]); + } + return sb.toString(); + } + + /** + * Object to String, null to empty string + * @param key HttpServletRequest + * @param key Object + * @return String + */ + public static String getValue(HttpServletRequest HttpServletRequest, String key) { + String value = HttpServletRequest.getParameter(key); + if (value == null) { + return ""; + } else { + return String.valueOf(value); + } + } + + /** + * Object to String, null to empty string + * + * @param o Object + * @return String + */ + public static String getValue( Object o) { + if (o == null) { + return ""; + } else { + return String.valueOf(o); + } + } + + /** + * timeStr to String, null to empty string + * + * @param timeStr timeStr + * @return String + */ + public static String getDateOfTimeStr(String timeStr) { + try { + if (timeStr == null) { + return ""; + } else { + return timeStr.substring(0, 10); + } + } catch (Exception e) { + return ""; + } + } + + /** + * 手机号码中间四位脱敏 + * + * @param phoneNumber 手机号码 + * @return 脱敏后的手机号码 + */ + public static String phoneNumberSensitive(String phoneNumber) { + if (isEmpty(phoneNumber) || phoneNumber.length() != 11) { + return phoneNumber; + } else { + return phoneNumber.substring(0, 3) + "****" + phoneNumber.substring(7, 11); + } + } + + /** + * null to empty string + * + * @param s string + * @return string + */ + public static String getStr(String s) { + try { + if (null == s) { + return ""; + } else { + return s; + } + } catch (Exception e) { + return s; + } + } + + /** + * double to String, null to empty string + * + * @param d double + * @return String + */ + public static String getStr(Double d) { + try { + DecimalFormat format = new DecimalFormat("#.#######"); + return format.format(d); + } catch (Exception e) { + return ""; + } + } + + /** + * int to String, null to empty string + * + * @param i Integer + * @return String + */ + public static String getStr(Integer i) { + try { + return Integer.toString(i); + } catch (Exception e) { + return ""; + } + } + + /** + * long to String, null to empty string + * + * @param l long + * @return String + */ + public static String getStr(Long l) { + try { + DecimalFormat format = new DecimalFormat("#.#######"); + return format.format(l); + } catch (Exception e) { + return ""; + } + } + + /** + * Object to double, null to zero + * + * @param o Object + * @return double + */ + public static double getDouble(Object o) { + try { + if (o == null) { + return 0; + } else { + return getDouble(getValue(o)); + } + } catch (Exception e) { + return 0; + } + } + + /** + * String to Double, null to zero + * + * @param s String + * @return Double + */ + public static Double getDouble(String s) { + try { + if (s == null || "".equals(s)) { + return (double) 0; + } else { + return Double.valueOf(s); + } + } catch (Exception e) { + return (double) 0; + } + } + + /** + * Object to long, null to zero + * + * @param o Object + * @return long + */ + public static long getLong(Object o) { + try { + if (o == null) { + return 0; + } else { + return getLong(getValue(o)); + } + } catch (Exception e) { + return 0; + } + } + + /** + * String to Long, null to zero + * + * @param s String + * @return Long + */ + public static Long getLong(String s) { + try { + if (s == null || "".equals(s)) { + return (long) 0; + } else { + return Long.valueOf(s); + } + } catch (Exception e) { + return (long) 0; + } + } + + /** + * Object to int, null to zero + * + * @param o Object + * @return int + */ + public static int getInt(Object o) { + try { + if (o == null) { + return 0; + } else { + return getInt(getValue(o)); + } + } catch (Exception e) { + return 0; + } + } + + /** + * String to Integer, null to zero + * + * @param s String + * @return Integer + */ + public static Integer getInt(String s) { + if (null == s || "".equals(s)) { + return 0; + } else { + try { + return Integer.valueOf(s); + } catch (NumberFormatException e) { + return 0; + } + } + } + + /** + * MD5摘要加密 + * + * @param resource 需加密的字符串 + * @return 加密后的字符串 + */ + public static String md5(String resource) { + try { + MessageDigest digest = MessageDigest.getInstance("md5"); + byte[] result = digest.digest(resource.getBytes("utf-8")); + StringBuilder builder = new StringBuilder(); + for (byte b : result) { + // 与运算 + // 0xff 加盐 + int number = b & 0xff; + String str = Integer.toHexString(number); + if (1 == str.length()) { + builder.append("0"); + } + builder.append(str); + } + return builder.toString().toLowerCase(); + } catch (Exception e) { + e.printStackTrace(); + return ""; + } + } + + /** + * exception error info to string + * 将异常的堆栈信息转换成字符串 + * + * @param e Exception + * @return string + */ + public static String exception2Str(Exception e) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + return "\r\n" + sw.toString() + "\r\n"; + } + + /** + * input stream 2 string + * + * @param is InputStream + * @return string + */ + public static String inputStream2Str(InputStream is) { + StringBuilder sb = new StringBuilder(); + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); + String line; + + while ((line = reader.readLine()) != null) { + sb.append(line).append("\n"); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return sb.toString(); + } + + /** + * 转义xml字符串 + * + * @param xml 字符串 + * @return 转义后的字符串 + */ + public static String escapeXml(String xml) { + if (null == xml) { + return ""; + } else { + return xml + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll("\"", """); + } + } + + /** + * 解码Xml字符串 + * + * @param xml 字符串 + * @return 解码后的字符串 + */ + public static String unescapeXml(String xml) { + if (null == xml) { + return ""; + } else { + return xml + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll(""", "\"") + .replaceAll("&", "&"); + } + } + + /** + * 比较两个字符串是否相同 + * + * @param str1 字符串1 + * @param str2 字符串2 + * @return true:相同,false:不相同 + */ + public static boolean equals(String str1, String str2) { + return str1 == null ? str2 == null : str1.equals(str2); + } + + /** + * 比较两个字符串是否相同,忽略大小写 + * + * @param str1 字符串1 + * @param str2 字符串2 + * @return true:相同,false:不相同 + */ + public static boolean equalsIgnoreCase(String str1, String str2) { + return str1 == null ? str2 == null : str1.equalsIgnoreCase(str2); + } + + /** + * 判断是否是符合规则的手机号码 + * + * @param phoneNo 手机号码 + * @return true:是,false:否 + */ + public static boolean isPhoneNo(String phoneNo) { + String regex = "^1[0-9]{10}$"; + return isNotEmpty(phoneNo) && phoneNo.matches(regex); + } + + /** + * 是否是20位登记序号 + * + * @param taxpayerId 登记序号 + * @return true、是,false、否 + */ + public static boolean isTaxpayerId(String taxpayerId) { + String regex = "^[0-9]{20}$"; + return isNotEmpty(taxpayerId) && taxpayerId.matches(regex); + } + + /** + * 是否不为空,并且仅是字母数字 + * + * @param source 字符串 + * @return true、是,false、否 + */ + public static boolean isCharNumber(String source) { + String regex = "^[0-9a-zA-Z]+$"; + return isNotEmpty(source) && source.matches(regex); + } + + /** + * 字符串转byte数组(utf-8) + * + * @param str 字符串 + * @return byte数组 + */ + public static byte[] getBytes(String str) { + return getBytes(str, StandardCharsets.UTF_8); + } + + /** + * 字符串转byte数组(指定编码格式) + * + * @param str 字符串 + * @param charset 编码格式 + * @return byte数组 + */ + public static byte[] getBytes(String str, Charset charset) { + if (str == null) { + return null; + } + return str.getBytes(charset); + } + + /** + * byte数组转字符串(utf-8) + * + * @param bytes byte数组 + * @return 字符串 + */ + public static String byte2String(byte[] bytes) { + return byte2String(bytes, StandardCharsets.UTF_8); + } + + /** + * byte数组转字符串(指定编码格式) + * + * @param bytes byte数组 + * @param charset 编码格式 + * @return 字符串 + */ + public static String byte2String(byte[] bytes, Charset charset) { + return new String(bytes, charset); + } + + /** + * 验证整数和小数(最多两位小数) + * + * @param number 带判断字符串 + * @return 判断结果 + */ + public static boolean isDouble(String number) { + if (number != null) { + String regex = "^(([^0][0-9]+|0)\\.([0-9]{1,2})$)|^(([^0][0-9]+|0)$)|^(([1-9]+)\\.([0-9]{1,2})$)|^(([1-9]+)$)|^(100\\.[0]{0,2}$)"; + Pattern p = Pattern.compile(regex); + Matcher m = p.matcher(number); + return m.matches(); + } + return false; + } + + /** + * 利用java原生的摘要实现SHA256加密 + * + * @param str 加密前的报文 + * @return 加密后报文 + */ + public static String getSHA256StrJava(String str) { + MessageDigest messageDigest; + String encodeStr = ""; + try { + messageDigest = MessageDigest.getInstance("SHA-256"); + messageDigest.update(str.getBytes(StandardCharsets.UTF_8)); + encodeStr = byte2Hex(messageDigest.digest()); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return encodeStr; + } + + /** + * 将byte转为16进制 + * + * @param bytes 字节数 + * @return 16进制字符串 + */ + private static String byte2Hex(byte[] bytes) { + StringBuilder stringBuffer = new StringBuilder(); + String temp; + for (byte aByte : bytes) { + temp = Integer.toHexString(aByte & 0xFF); + if (temp.length() == 1) { + //1得到一位的进行补0操作 + stringBuffer.append("0"); + } + stringBuffer.append(temp); + } + return stringBuffer.toString(); + } + +} diff --git a/crm/src/main/java/com/kakarote/crm/webService/service/NsrdjxxService.java b/crm/src/main/java/com/kakarote/crm/webService/service/NsrdjxxService.java new file mode 100644 index 0000000..0a4afad --- /dev/null +++ b/crm/src/main/java/com/kakarote/crm/webService/service/NsrdjxxService.java @@ -0,0 +1,135 @@ +package com.kakarote.crm.webService.service; + +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.haiti.packet.Root; +import com.kakarote.core.exception.CrmException; +import com.kakarote.crm.entity.PO.CrmQyjbxx; +import com.kakarote.crm.util.SM2Utils; +import com.kakarote.crm.util.StringUtil; +import com.kakarote.crm.webService.config.TaxWebServiceConfig; +import lombok.extern.slf4j.Slf4j; +import okhttp3.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.concurrent.TimeUnit; + +/** + * @description: 查询纳入登记信息 + * @Author: dengLL + * @CreateTime: 2025/12/23 + */ +@Slf4j +@Component +public class NsrdjxxService { + @Autowired + private TaxWebServiceConfig taxWebServiceConfig; + + /** + * 查询纳入登记信息 + * @param shxydm 社会统一信用代码或纳税人识别号 + * @param zgswskfjDm 主管税务局科分局代码 + * @return CrmQyjbxx + * @throws Exception + */ + public CrmQyjbxx getNsrdjxx(String shxydm, String zgswskfjDm){ + + /*TaxWebServiceConfig taxWebServiceConfig = new TaxWebServiceConfig(); + taxWebServiceConfig.setUrl("https://etax.jiangxi.chinatax.gov.cn/etax/product/initExecute"); + taxWebServiceConfig.setKey("586BA1CD35F1905EE521B4213407991AEFC13E2C076724058DC7E38B083F0D5A"); + taxWebServiceConfig.setChannelCode("JXFX.DLJZ.SBFW");*/ + + String url = taxWebServiceConfig.getUrl(); + String key = taxWebServiceConfig.getKey(); + String channelCode = taxWebServiceConfig.getChannelCode(); + + String resBody = ""; + Root xmlvo = Root.getInstance("1600300", null, null); // sid 指定调用的接口,由后台提供,即后台具体执行的handler + xmlvo.getProperties().putCell("shxydm", StringUtil.getValue(shxydm)); //纳税人识别号,社会信用代码 + xmlvo.getProperties().putCell("djxh", ""); + xmlvo.getProperties().putCell("zgswskfjDm", StringUtil.getValue(zgswskfjDm)); // 可选,主管税务机关科分局代码,如果企业存在多地登记,建议传入该参数取具体的登记信息 + + log.info("请求参数:\n" + xmlvo.toString()); + try { + String times = String.valueOf(new Date().getTime()); + String text = xmlvo.getSID()+","+ channelCode +","+ times; + String sign = SM2Utils.sign(text,key); + OkHttpClient client = new OkHttpClient.Builder() + .connectTimeout(60 * 1000, TimeUnit.MILLISECONDS) + .readTimeout(5 * 60 * 1000, TimeUnit.MILLISECONDS) + .writeTimeout(5 * 60 * 1000, TimeUnit.MILLISECONDS) + .build(); + RequestBody body = RequestBody.create(MediaType.parse("application/xml"),xmlvo.toString()); + Request request = new Request.Builder().url(url).post(body) + .addHeader("sign",sign) + .addHeader("timestamp",times) + .addHeader("channelCode",channelCode) + .build(); + Response response = client.newCall(request).execute(); + if(response.isSuccessful()){ + resBody = response.body().string(); + } + log.info("响应报文:\n" + resBody); + + JSONObject jsonObject = JSONUtil.parseObj(resBody); + String reCode = StringUtil.getValue(jsonObject.getByPath("$.reCode")); + if ("1".equals(reCode)) { + CrmQyjbxx crmQyjbxx = new CrmQyjbxx(); + //登记序号 + crmQyjbxx.setDjxh(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.djxh"))); + //纳税人识别号 + crmQyjbxx.setNsrsbh(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.nsrsbh"))); + //纳税人识名称 + crmQyjbxx.setNsrmc(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.nsrmc"))); + //法定代表人 + crmQyjbxx.setFddbrxm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.fddbrxm"))); + crmQyjbxx.setFddbrsfzjlxDm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.fddbrsfzjlxDm"))); + //法定代表人身份证件号码 + crmQyjbxx.setFddbrsfzjhm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.fddbrsfzjhm"))); + //法定代表人移动电话 + crmQyjbxx.setFddbryddh(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.fddbryddh"))); + //财务负责人 + crmQyjbxx.setCwfzrxm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.cwfzrxm"))); + crmQyjbxx.setCwfzrsfzjzlDm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.cwfzrsfzjzlDm"))); + //财务负责人身份证件号码 + crmQyjbxx.setCwfzrsfzjhm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.cwfzrsfzjhm"))); + //财务负责人移动电话 + crmQyjbxx.setCwfzryddh(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.cwfzryddh"))); + //办税人 + crmQyjbxx.setBsrxm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.bsrxm"))); + //办税人身份证件号码 + crmQyjbxx.setBsrsfzjzlDm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.bsrsfzjzlDm"))); + crmQyjbxx.setBsrsfzjhm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.bsrsfzjhm"))); + crmQyjbxx.setBsryddh(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.bsryddh"))); + + crmQyjbxx.setZgswjDm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.zgswjDm"))); + crmQyjbxx.setZgswskfjDm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.zgswskfjDm"))); + crmQyjbxx.setShxydm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.shxydm"))); + + crmQyjbxx.setHyDm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.hyDm"))); + crmQyjbxx.setSsglyDm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.ssglyDm"))); + crmQyjbxx.setKzztdjlxDm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.kzztdjlxDm"))); + crmQyjbxx.setDjzclxDm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.djzclxDm"))); + crmQyjbxx.setDjrq(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.djrq"))); + crmQyjbxx.setJdxzDm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.jdxzDm"))); + crmQyjbxx.setZcdzxzqhszDm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.zcdzxzqhszDm"))); + crmQyjbxx.setNsrztDm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.nsrztDm"))); + crmQyjbxx.setScjydzxzqhszDm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.scjydzxzqhszDm"))); + crmQyjbxx.setScjydz(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.scjydz"))); + crmQyjbxx.setScjydlxdh(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.scjydlxdh"))); + crmQyjbxx.setDwlsgxDm(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.dwlsgxDm"))); + crmQyjbxx.setFjmqybz(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.fjmqybz"))); + crmQyjbxx.setJyfw(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.jyfw"))); + crmQyjbxx.setZcdlxdh(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.zcdlxdh"))); + crmQyjbxx.setZcdz(StringUtil.getValue(jsonObject.getByPath("$.retObj.obj.arrayLists[0].vos[0].map.zcdz"))); + + return crmQyjbxx; + } + }catch (Exception e){ + throw new CrmException (500,"查询纳入登记信息失败:" + e.getMessage()); + } + return null; + } +} \ No newline at end of file