From daf85caf9e5198f0bc4bb29d852a9b3774e39f5c Mon Sep 17 00:00:00 2001
From: Looly
-
+
-
+
-
+
-
+
-
+
+
-
+
-
+
-
+
-
+
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java
index 339e6c4e7..998b8d13b 100644
--- a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java
@@ -1,35 +1,20 @@
package cn.hutool.core.io;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileFilter;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.io.RandomAccessFile;
-import java.io.Reader;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.file.FileReader;
+import cn.hutool.core.io.file.*;
+import cn.hutool.core.io.file.FileWriter;
+import cn.hutool.core.io.file.FileReader.ReaderHandler;
+import cn.hutool.core.io.resource.ResourceUtil;
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.*;
+
+import java.io.*;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
-import java.nio.file.CopyOption;
-import java.nio.file.DirectoryStream;
-import java.nio.file.FileVisitOption;
-import java.nio.file.FileVisitResult;
-import java.nio.file.FileVisitor;
-import java.nio.file.Files;
-import java.nio.file.LinkOption;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.StandardCopyOption;
+import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.text.DecimalFormat;
import java.util.*;
@@ -38,26 +23,6 @@ import java.util.regex.Pattern;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.io.file.FileCopier;
-import cn.hutool.core.io.file.FileMode;
-import cn.hutool.core.io.file.FileReader;
-import cn.hutool.core.io.file.FileReader.ReaderHandler;
-import cn.hutool.core.io.file.FileWriter;
-import cn.hutool.core.io.file.LineSeparator;
-import cn.hutool.core.io.file.Tailer;
-import cn.hutool.core.io.resource.ResourceUtil;
-import cn.hutool.core.lang.Assert;
-import cn.hutool.core.lang.Console;
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.CharUtil;
-import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.util.ClassUtil;
-import cn.hutool.core.util.ReUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.core.util.URLUtil;
-import cn.hutool.core.util.ZipUtil;
-
/**
* 文件工具类
*
@@ -1583,7 +1548,7 @@ public class FileUtil {
// 去除file:前缀
pathToUse = StrUtil.removePrefixIgnoreCase(pathToUse, URLUtil.FILE_URL_PREFIX);
// 统一使用斜杠
- pathToUse = pathToUse.replaceAll("[/\\\\]{1,}", StrUtil.SLASH).trim();
+ pathToUse = pathToUse.replaceAll("[/\\\\]{2,}", StrUtil.SLASH).trim();
//兼容Windows下的共享目录路径(原始路径如果以\\开头,则保留这种路径)
if(path.startsWith("\\\\")){
pathToUse = "\\" + pathToUse;
diff --git a/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java
index a1376ffd0..133a39baf 100644
--- a/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java
@@ -1,41 +1,53 @@
package cn.hutool.core.util;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Validator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
/**
* 身份证相关工具类
* see https://www.oschina.net/code/snippet_1611_2881
- *
+ *
*
* 本工具并没有对行政区划代码做校验,如有需求,请参阅(2018年10月): * http://www.mca.gov.cn/article/sj/xzqh/2018/201804-12/20181011221630.html *
- * + * * @author Looly * @since 3.0.4 */ public class IdcardUtil { - /** 中国公民身份证号码最小长度。 */ + /** + * 中国公民身份证号码最小长度。 + */ private static final int CHINA_ID_MIN_LENGTH = 15; - /** 中国公民身份证号码最大长度。 */ + /** + * 中国公民身份证号码最大长度。 + */ private static final int CHINA_ID_MAX_LENGTH = 18; - /** 每位加权因子 */ - private static final int power[] = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 }; - /** 省市代码表 */ - private static Map* 判断18位身份证的合法性 *
@@ -200,7 +207,7 @@ public class IdcardUtil { *- * [0] - 台湾、澳门、香港 [1] - 性别(男M,女F,未知N) [2] - 是否合法(合法true,不合法false) 若不是身份证件号码则返回null - *
+ *+ * [0] - 台湾、澳门、香港 [1] - 性别(男M,女F,未知N) [2] - 是否合法(合法true,不合法false) 若不是身份证件号码则返回null + *
*/ public static String[] isValidCard10(String idCard) { - if(StrUtil.isBlank(idCard)) { + if (StrUtil.isBlank(idCard)) { return null; } String[] info = new String[3]; - String card = idCard.replaceAll("[\\(|\\)]", ""); + String card = idCard.replaceAll("[()]", ""); if (card.length() != 8 && card.length() != 9 && idCard.length() != 10) { return null; } @@ -286,7 +288,7 @@ public class IdcardUtil { return info; } info[2] = isValidTWCard(idCard) ? "true" : "false"; - } else if (idCard.matches("^[1|5|7][0-9]{6}\\(?[0-9A-Z]\\)?$")) { // 澳门 + } else if (idCard.matches("^[157][0-9]{6}\\(?[0-9A-Z]\\)?$")) { // 澳门 info[0] = "澳门"; info[1] = "N"; } else if (idCard.matches("^[A-Z]{1,2}[0-9]{6}\\(?[0-9A]\\)?$")) { // 香港 @@ -301,29 +303,29 @@ public class IdcardUtil { /** * 验证台湾身份证号码 - * + * * @param idCard 身份证号码 * @return 验证码是否符合 */ public static boolean isValidTWCard(String idCard) { - if(StrUtil.isEmpty(idCard)) { + if (StrUtil.isEmpty(idCard)) { return false; } String start = idCard.substring(0, 1); - String mid = idCard.substring(1, 9); - String end = idCard.substring(9, 10); Integer iStart = twFirstCode.get(start); - if(null == iStart) { + if (null == iStart) { return false; } + String mid = idCard.substring(1, 9); + String end = idCard.substring(9, 10); int sum = iStart / 10 + (iStart % 10) * 9; final char[] chars = mid.toCharArray(); - Integer iflag = 8; + int iflag = 8; for (char c : chars) { sum += Integer.valueOf(String.valueOf(c)) * iflag; iflag--; } - return (sum % 10 == 0 ? 0 : (10 - sum % 10)) == Integer.valueOf(end) ? true : false; + return (sum % 10 == 0 ? 0 : (10 - sum % 10)) == Integer.valueOf(end); } /** @@ -334,23 +336,28 @@ public class IdcardUtil { ** 将身份证号码全部转换为数字,分别对应乘9-1相加的总和,整除11则证件号码有效 *
- * + * * @param idCard 身份证号码 * @return 验证码是否符合 */ public static boolean isValidHKCard(String idCard) { - String card = idCard.replaceAll("[\\(|\\)]", ""); - Integer sum = 0; + String card = idCard.replaceAll("[()]", ""); + int sum; if (card.length() == 9) { - sum = (Integer.valueOf(card.substring(0, 1).toUpperCase().toCharArray()[0]) - 55) * 9 + (Integer.valueOf(card.substring(1, 2).toUpperCase().toCharArray()[0]) - 55) * 8; + sum = (Character.toUpperCase(card.charAt(0)) - 55) * 9 + (Character.toUpperCase(card.charAt(1)) - 55) * 8; card = card.substring(1, 9); } else { - sum = 522 + (Integer.valueOf(card.substring(0, 1).toUpperCase().toCharArray()[0]) - 55) * 8; + sum = 522 + (Character.toUpperCase(card.charAt(0)) - 55) * 8; + } + String start = idCard.substring(0, 1); + Integer iStart = hkFirstCode.get(start); + if (null == iStart) { + return false; } String mid = card.substring(1, 7); String end = card.substring(7, 8); char[] chars = mid.toCharArray(); - Integer iflag = 7; + int iflag = 7; for (char c : chars) { sum = sum + Integer.valueOf(String.valueOf(c)) * iflag; iflag--; @@ -358,14 +365,14 @@ public class IdcardUtil { if ("A".equals(end.toUpperCase())) { sum += 10; } else { - sum += Integer.valueOf(end); + sum += Integer.parseInt(end); } - return (sum % 11 == 0) ? true : false; + return sum % 11 == 0; } /** * 根据身份编号获取生日,只支持15或18位身份证号码 - * + * * @param idCard 身份编号 * @return 生日(yyyyMMdd) * @see #getBirth(String) @@ -376,12 +383,12 @@ public class IdcardUtil { /** * 根据身份编号获取生日,只支持15或18位身份证号码 - * + * * @param idCard 身份编号 * @return 生日(yyyyMMdd) */ public static String getBirth(String idCard) { - final Integer len = idCard.length(); + final int len = idCard.length(); if (len < CHINA_ID_MIN_LENGTH) { return null; } else if (len == CHINA_ID_MIN_LENGTH) { @@ -392,7 +399,7 @@ public class IdcardUtil { /** * 从身份证号码中获取生日日期,只支持15或18位身份证号码 - * + * * @param idCard 身份证号码 * @return 日期 */ @@ -403,7 +410,7 @@ public class IdcardUtil { /** * 根据身份编号获取年龄,只支持15或18位身份证号码 - * + * * @param idCard 身份编号 * @return 年龄 */ @@ -413,8 +420,8 @@ public class IdcardUtil { /** * 根据身份编号获取指定日期当时的年龄年龄,只支持15或18位身份证号码 - * - * @param idCard 身份编号 + * + * @param idCard 身份编号 * @param dateToCompare 以此日期为界,计算年龄。 * @return 年龄 */ @@ -425,12 +432,12 @@ public class IdcardUtil { /** * 根据身份编号获取生日年,只支持15或18位身份证号码 - * + * * @param idCard 身份编号 * @return 生日(yyyy) */ public static Short getYearByIdCard(String idCard) { - Integer len = idCard.length(); + final int len = idCard.length(); if (len < CHINA_ID_MIN_LENGTH) { return null; } else if (len == CHINA_ID_MIN_LENGTH) { @@ -441,12 +448,12 @@ public class IdcardUtil { /** * 根据身份编号获取生日月,只支持15或18位身份证号码 - * + * * @param idCard 身份编号 * @return 生日(MM) */ public static Short getMonthByIdCard(String idCard) { - Integer len = idCard.length(); + final int len = idCard.length(); if (len < CHINA_ID_MIN_LENGTH) { return null; } else if (len == CHINA_ID_MIN_LENGTH) { @@ -457,12 +464,12 @@ public class IdcardUtil { /** * 根据身份编号获取生日天,只支持15或18位身份证号码 - * + * * @param idCard 身份编号 * @return 生日(dd) */ public static Short getDayByIdCard(String idCard) { - Integer len = idCard.length(); + final int len = idCard.length(); if (len < CHINA_ID_MIN_LENGTH) { return null; } else if (len == CHINA_ID_MIN_LENGTH) { @@ -473,33 +480,27 @@ public class IdcardUtil { /** * 根据身份编号获取性别,只支持15或18位身份证号码 - * + * * @param idCard 身份编号 - * @return 性别(1: 男,0: 女) + * @return 性别(1 : 男 , 0 : 女) */ public static int getGenderByIdCard(String idCard) { Assert.notBlank(idCard); final int len = idCard.length(); - if(len < CHINA_ID_MIN_LENGTH) { + if (len < CHINA_ID_MIN_LENGTH) { throw new IllegalArgumentException("ID Card length must be 15 or 18"); } - + if (len == CHINA_ID_MIN_LENGTH) { idCard = convert15To18(idCard); } char sCardChar = idCard.charAt(16); - int gender = -1; - if (Integer.parseInt(String.valueOf(sCardChar)) % 2 != 0) { - gender = 1; - } else { - gender = 0; - } - return gender; + return (sCardChar % 2 != 0) ? 1 : 0; } /** * 根据身份编号获取户籍省份,只支持15或18位身份证号码 - * + * * @param idCard 身份编码 * @return 省级编码。 */ @@ -514,22 +515,23 @@ public class IdcardUtil { /** * 隐藏指定位置的几个身份证号数字为“*” - * - * @param idCard 身份证号 + * + * @param idCard 身份证号 * @param startInclude 开始位置(包含) - * @param endExclude 结束位置(不包含) + * @param endExclude 结束位置(不包含) * @return 隐藏后的身份证号码 - * @since 3.2.2 * @see StrUtil#hide(CharSequence, int, int) + * @since 3.2.2 */ public static String hide(String idCard, int startInclude, int endExclude) { return StrUtil.hide(idCard, startInclude, endExclude); } // ----------------------------------------------------------------------------------- Private method start + /** * 获得18位身份证校验码 - * + * * @param code17 18位身份证号中的前17位 * @return 第18位 */ @@ -540,44 +542,44 @@ public class IdcardUtil { /** * 将power和值与11取模获得余数进行校验码判断 - * - * @param iSum + * + * @param iSum 加权和 * @return 校验位 */ private static char getCheckCode18(int iSum) { switch (iSum % 11) { - case 10: - return '2'; - case 9: - return '3'; - case 8: - return '4'; - case 7: - return '5'; - case 6: - return '6'; - case 5: - return '7'; - case 4: - return '8'; - case 3: - return '9'; - case 2: - return 'x'; - case 1: - return '0'; - case 0: - return '1'; - default: - return StrUtil.C_SPACE; + case 10: + return '2'; + case 9: + return '3'; + case 8: + return '4'; + case 7: + return '5'; + case 6: + return '6'; + case 5: + return '7'; + case 4: + return '8'; + case 3: + return '9'; + case 2: + return 'x'; + case 1: + return '0'; + case 0: + return '1'; + default: + return StrUtil.C_SPACE; } } /** * 将身份证的每位和对应位的加权因子相乘之后,再得到和值 - * - * @param iArr - * @return 身份证编码。 + * + * @param iArr 身份证号码的数组 + * @return 身份证编码 */ private static int getPowerSum(char[] iArr) { int iSum = 0; diff --git a/hutool-core/src/test/java/cn/hutool/core/util/IdcardUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/IdcardUtilTest.java index aa95d068f..159f34cbb 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/IdcardUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/IdcardUtilTest.java @@ -1,5 +1,6 @@ package cn.hutool.core.util; +import cn.hutool.core.lang.Console; import org.junit.Assert; import org.junit.Test; @@ -66,4 +67,10 @@ public class IdcardUtilTest { Assert.assertEquals(province2, "内蒙古"); } + @Test + public void getGenderByIdCardTest() { + int gender = IdcardUtil.getGenderByIdCard(ID_18); + Assert.assertEquals(1, gender); + } + } diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/SmUtil.java b/hutool-crypto/src/main/java/cn/hutool/crypto/SmUtil.java index 09307e0db..09c960f49 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/SmUtil.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/SmUtil.java @@ -1,10 +1,14 @@ package cn.hutool.crypto; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.math.BigInteger; - +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.crypto.asymmetric.SM2; +import cn.hutool.crypto.digest.HMac; +import cn.hutool.crypto.digest.HmacAlgorithm; +import cn.hutool.crypto.digest.SM3; +import cn.hutool.crypto.digest.mac.BCHMacEngine; +import cn.hutool.crypto.digest.mac.MacEngine; +import cn.hutool.crypto.symmetric.SM4; +import cn.hutool.crypto.symmetric.SymmetricCrypto; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Sequence; @@ -14,14 +18,10 @@ import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; -import cn.hutool.core.io.IORuntimeException; -import cn.hutool.crypto.asymmetric.SM2; -import cn.hutool.crypto.digest.Digester; -import cn.hutool.crypto.digest.HMac; -import cn.hutool.crypto.digest.HmacAlgorithm; -import cn.hutool.crypto.digest.mac.BCHMacEngine; -import cn.hutool.crypto.digest.mac.MacEngine; -import cn.hutool.crypto.symmetric.SymmetricCrypto; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; /** * SM国密算法工具类
* 私钥和公钥同时为空时生成一对新的私钥和公钥
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
- *
- * @param algorithm 算法
+ *
+ * @param algorithm 算法
* @param privateKey 私钥
- * @param publicKey 公钥
+ * @param publicKey 公钥
* @since 3.1.1
*/
public AbstractAsymmetricCrypto(String algorithm, PrivateKey privateKey, PublicKey publicKey) {
@@ -34,10 +41,11 @@ public abstract class AbstractAsymmetricCrypto