ソースを参照

add CreditCodeUtil

Looly 5 年 前
コミット
249f20d0ed

+ 1 - 0
CHANGELOG.md

@@ -14,6 +14,7 @@
 * 【db     】     设置全局忽略大小写DbUtil.setCaseInsensitiveGlobal(true)(issue#784@Github)
 * 【core   】     增加CallerUtil.getCallerMethodName方法
 * 【core   】     Tree增加getParent方法,可以获取父节点,抽象Node接口
+* 【core   】     增加社会信用代码工具CreditCodeUtil(pr#112@Gitee)
 
 ### Bug修复
 * 【core   】     修复TypeUtil无法获取泛型接口的泛型参数问题(issue#I1BRFI@Gitee)

ファイルの差分が大きいため隠しています
+ 95 - 44
hutool-core/src/main/java/cn/hutool/core/lang/PatternPool.java


+ 14 - 43
hutool-core/src/main/java/cn/hutool/core/lang/Validator.java

@@ -2,14 +2,13 @@ package cn.hutool.core.lang;
 
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.exceptions.ValidateException;
+import cn.hutool.core.util.CreditCodeUtil;
 import cn.hutool.core.util.NumberUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.ReUtil;
 import cn.hutool.core.util.StrUtil;
 
 import java.net.MalformedURLException;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -90,17 +89,6 @@ public class Validator {
 	public final static Pattern PLATE_NUMBER = PatternPool.PLATE_NUMBER;
 
 	/**
-	 * 社会统一信用代码
-	 */
-	public static final List<Character> BASE_CODES = new ArrayList<>();
-
-	public static final String BASE_CODE_STRING = "0123456789ABCDEFGHJKLMNPQRTUWXY";
-
-	public static final int[] WEIGHT = {1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28};
-
-	public static final char[] BASE_CODE_ARRAY = BASE_CODE_STRING.toCharArray();
-
-	/**
 	 * 给定值是否为<code>true</code>
 	 *
 	 * @param value 值
@@ -136,7 +124,7 @@ public class Validator {
 		if (isFalse(value)) {
 			throw new ValidateException(errorMsgTemplate, params);
 		}
-		return value;
+		return true;
 	}
 
 	/**
@@ -153,7 +141,7 @@ public class Validator {
 		if (isTrue(value)) {
 			throw new ValidateException(errorMsgTemplate, params);
 		}
-		return value;
+		return false;
 	}
 
 	/**
@@ -191,7 +179,7 @@ public class Validator {
 		if (isNotNull(value)) {
 			throw new ValidateException(errorMsgTemplate, params);
 		}
-		return value;
+		return null;
 	}
 
 	/**
@@ -1118,37 +1106,20 @@ public class Validator {
 	}
 
 	/**
-	 * 简单校验统一社会信用代码
-	 * 18位(大写字母+数字)
-	 *
-	 * @param creditCode 统一社会信用代码
-	 * @return 校验结果
-	 */
-	public static boolean isCreditCodeBySimple(String creditCode) {
-		if (StrUtil.isBlank(creditCode)) {
-			return false;
-		}
-		return Pattern.matches(PatternPool.CREDIT_CODE, creditCode);
-	}
-
-	/**
 	 * 是否是有效的统一社会信用代码
+	 * <pre>
+	 * 第一部分:登记管理部门代码1位 (数字或大写英文字母)
+	 * 第二部分:机构类别代码1位 (数字或大写英文字母)
+	 * 第三部分:登记管理机关行政区划码6位 (数字)
+	 * 第四部分:主体标识码(组织机构代码)9位 (数字或大写英文字母)
+	 * 第五部分:校验码1位 (数字或大写英文字母)
+	 * </pre>
 	 *
 	 * @param creditCode 统一社会信用代码
 	 * @return 校验结果
+	 * @since 5.2.4
 	 */
-	public static boolean isCreditCode(String creditCode) {
-		if (StrUtil.isBlank(creditCode) || !Pattern.matches(PatternPool.BASE_CODE_REGEX, creditCode)) {
-			return false;
-		}
-		char[] businessCodeArray = creditCode.toCharArray();
-		char check = businessCodeArray[17];
-		int sum = 0, length = 17;
-		for (int i = 0; i < length; i++) {
-			char key = businessCodeArray[i];
-			sum += (BASE_CODES.indexOf(key) * WEIGHT[i]);
-		}
-		int value = 31 - sum % 31;
-		return check == BASE_CODE_ARRAY[value % 31];
+	public static boolean isCreditCode(CharSequence creditCode) {
+		return CreditCodeUtil.isCreditCode(creditCode);
 	}
 }

+ 131 - 0
hutool-core/src/main/java/cn/hutool/core/util/CreditCodeUtil.java

@@ -0,0 +1,131 @@
+package cn.hutool.core.util;
+
+import cn.hutool.core.lang.PatternPool;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Pattern;
+
+/**
+ * 统一社会信用代码工具类
+ *
+ * <pre>
+ * 第一部分:登记管理部门代码1位 (数字或大写英文字母)
+ * 第二部分:机构类别代码1位 (数字或大写英文字母)
+ * 第三部分:登记管理机关行政区划码6位 (数字)
+ * 第四部分:主体标识码(组织机构代码)9位 (数字或大写英文字母)
+ * 第五部分:校验码1位 (数字或大写英文字母)
+ * </pre>
+ *
+ * @author looly
+ * @since 5.2.4
+ */
+public class CreditCodeUtil {
+
+	public static final Pattern CREDIT_CODE_PATTERN = PatternPool.CREDIT_CODE;
+
+	private static final int[] WEIGHT = {1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28};
+	private static final char[] BASE_CODE_ARRAY = "0123456789ABCDEFGHJKLMNPQRTUWXY".toCharArray();
+	private static final Map<Character, Integer> CODE_INDEX_MAP;
+
+	static {
+		CODE_INDEX_MAP = new ConcurrentHashMap<>();
+		for (int i = 0; i < BASE_CODE_ARRAY.length; i++) {
+			CODE_INDEX_MAP.put(BASE_CODE_ARRAY[i], i);
+		}
+	}
+
+	/**
+	 * 正则校验统一社会信用代码(18位)
+	 *
+	 * <pre>
+	 * 第一部分:登记管理部门代码1位 (数字或大写英文字母)
+	 * 第二部分:机构类别代码1位 (数字或大写英文字母)
+	 * 第三部分:登记管理机关行政区划码6位 (数字)
+	 * 第四部分:主体标识码(组织机构代码)9位 (数字或大写英文字母)
+	 * 第五部分:校验码1位 (数字或大写英文字母)
+	 * </pre>
+	 *
+	 * @param creditCode 统一社会信用代码
+	 * @return 校验结果
+	 */
+	public static boolean isCreditCodeSimple(CharSequence creditCode) {
+		if (StrUtil.isBlank(creditCode)) {
+			return false;
+		}
+		return ReUtil.isMatch(CREDIT_CODE_PATTERN, creditCode);
+	}
+
+	/**
+	 * 是否是有效的统一社会信用代码
+	 * <pre>
+	 * 第一部分:登记管理部门代码1位 (数字或大写英文字母)
+	 * 第二部分:机构类别代码1位 (数字或大写英文字母)
+	 * 第三部分:登记管理机关行政区划码6位 (数字)
+	 * 第四部分:主体标识码(组织机构代码)9位 (数字或大写英文字母)
+	 * 第五部分:校验码1位 (数字或大写英文字母)
+	 * </pre>
+	 *
+	 * @param creditCode 统一社会信用代码
+	 * @return 校验结果
+	 */
+	public static boolean isCreditCode(CharSequence creditCode) {
+		if (false == isCreditCodeSimple(creditCode)) {
+			return false;
+		}
+
+		final int parityBit = getParityBit(creditCode);
+		if (parityBit < 0) {
+			return false;
+		}
+
+		return creditCode.charAt(17) == BASE_CODE_ARRAY[parityBit];
+	}
+
+	/**
+	 * 获取一个随机的统一社会信用代码
+	 *
+	 * @return 统一社会信用代码
+	 */
+	public static String randomCreditCode() {
+		final StringBuilder buf = new StringBuilder(18);
+
+
+		//
+		for (int i = 0; i < 2; i++) {
+			int num = RandomUtil.randomInt(BASE_CODE_ARRAY.length - 1);
+			buf.append(Character.toUpperCase(BASE_CODE_ARRAY[num]));
+		}
+		for (int i = 2; i < 8; i++) {
+			int num = RandomUtil.randomInt(10);
+			buf.append(Character.toUpperCase(BASE_CODE_ARRAY[num]));
+		}
+		for (int i = 8; i < 17; i++) {
+			int num = RandomUtil.randomInt(BASE_CODE_ARRAY.length - 1);
+			buf.append(Character.toUpperCase(BASE_CODE_ARRAY[num]));
+		}
+
+		final String code = buf.toString();
+		return code + BASE_CODE_ARRAY[getParityBit(code)];
+	}
+
+	/**
+	 * 获取校验码
+	 *
+	 * @param creditCode 统一社会信息代码
+	 * @return 获取较验位的值
+	 */
+	private static int getParityBit(CharSequence creditCode) {
+		int sum = 0;
+		Integer codeIndex;
+		for (int i = 0; i < 17; i++) {
+			codeIndex = CODE_INDEX_MAP.get(creditCode.charAt(i));
+			if (null == codeIndex) {
+				return -1;
+			}
+			sum += codeIndex * WEIGHT[i];
+		}
+		final int result = 31 - sum % 31;
+		return result == 31 ? 0 : result;
+	}
+}

+ 25 - 0
hutool-core/src/test/java/cn/hutool/core/util/CreditCodeUtilTest.java

@@ -0,0 +1,25 @@
+package cn.hutool.core.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class CreditCodeUtilTest {
+
+	@Test
+	public void isCreditCodeBySimple() {
+		String testCreditCode = "91310115591693856A";
+		Assert.assertTrue(CreditCodeUtil.isCreditCodeSimple(testCreditCode));
+	}
+
+	@Test
+	public void isCreditCode() {
+		String testCreditCode = "91310110666007217T";
+		Assert.assertTrue(CreditCodeUtil.isCreditCode(testCreditCode));
+	}
+
+	@Test
+	public void randomCreditCode() {
+		final String s = CreditCodeUtil.randomCreditCode();
+		Assert.assertTrue(CreditCodeUtil.isCreditCode(s));
+	}
+}