[update] 优化RSA加签验签部分
Some checks failed
yexuejc-base package jre11 / package_job (push) Has been cancelled

This commit is contained in:
maxf
2025-08-25 21:57:34 +08:00
parent e9c65f8866
commit d1f0cd695e
15 changed files with 882 additions and 216 deletions

View File

@@ -48,7 +48,7 @@
<validation-api.version>3.0.2</validation-api.version> <validation-api.version>3.0.2</validation-api.version>
<commons-io.version>2.11.0</commons-io.version> <commons-io.version>2.11.0</commons-io.version>
<bcprov-jdk18on.version>1.78</bcprov-jdk18on.version> <bouncycastle-jdk18on.version>1.81</bouncycastle-jdk18on.version>
<guava.version>33.1.0-jre</guava.version> <guava.version>33.1.0-jre</guava.version>
<apache-poi.version>5.2.5</apache-poi.version> <apache-poi.version>5.2.5</apache-poi.version>
<jackson.version>2.17.0</jackson.version> <jackson.version>2.17.0</jackson.version>
@@ -94,7 +94,12 @@
<dependency> <dependency>
<groupId>org.bouncycastle</groupId> <groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId> <artifactId>bcprov-jdk18on</artifactId>
<version>${bcprov-jdk18on.version}</version> <version>${bouncycastle-jdk18on.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>${bouncycastle-jdk18on.version}</version>
</dependency> </dependency>
<!--com.yexuejc.base.file.FileInput 读文件--> <!--com.yexuejc.base.file.FileInput 读文件-->
<dependency> <dependency>

View File

@@ -7,15 +7,17 @@ package com.yexuejc.base.constant;
* @date 2023/05/17 13:45 * @date 2023/05/17 13:45
*/ */
public class DateConsts { public class DateConsts {
public static final String BAR = "-"; public static final String DATE_KEY_T = "T";
public static final CharSequence DATE_KEY_AM = "AM"; public static final String DATE_KEY_AM = "AM";
public static final CharSequence DATE_KEY_PM = "PM"; public static final String DATE_KEY_PM = "PM";
public static final String DATE_TIMESTAMP_LINUX = "M/dd/yy, h:mm a";
public static final CharSequence SLASH = "/";
public static final CharSequence COLON = ":";
public static final String DATE_YYYY_MM_DD_SLASH = "yyyy/MM/dd";
public static final CharSequence DATE_KEY_T = "T";
public static final String DATE_KEY_Z = "Z"; public static final String DATE_KEY_Z = "Z";
public static final String DATE_TIMESTAMP_LINUX = "M/dd/yy, h:mm a";
public static final String DATE_YYYY_MM_DD_SLASH = "yyyy/MM/dd";
public static final String DATE_TIMESTAMP = "yyyy/MM/dd H:m:s"; public static final String DATE_TIMESTAMP = "yyyy/MM/dd H:m:s";
public static final String DATE_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; public static final String DATE_PATTERN = "yyyy-MM-dd";
public static final String TIME_PATTERN = "HH:mm:ss";
public static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
public static final String DATE_TIME_MS_PATTERN = "yyyy-MM-dd HH:mm:ss.SSS";
public static final String ISO_8601_PATTERN = "yyyy-MM-dd'T'HH:mm:ssxxx";
public static final String ISO_8601_MS_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSxxx";
} }

View File

@@ -8,9 +8,9 @@ package com.yexuejc.base.constant;
* @author: maxf * @author: maxf
* @date: 2017/12/27 16:47 * @date: 2017/12/27 16:47
*/ */
public class RespsConsts { public class RespConsts {
private RespsConsts() { private RespConsts() {
} }
/** /**

View File

@@ -0,0 +1,21 @@
package com.yexuejc.base.constant;
/**
* 常用符号常量
*
* @author maxiaofeng
* @date 2025/8/25 15:15
*/
public class SymbolicConstant {
/**常量:换行符*/
public static final String NEW_LINE = "\n";
public static final String EMPTY = "";
public static final String EQUAL = "=";
public static final String COMMA = ",";
public static final String BAR = "-";
public static final String SLASH = "/";
public static final String COLON = ":";
private SymbolicConstant() {
}
}

View File

@@ -9,6 +9,7 @@ import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonDeserializer;
import com.yexuejc.base.constant.DateConsts; import com.yexuejc.base.constant.DateConsts;
import com.yexuejc.base.constant.SymbolicConstant;
import com.yexuejc.base.util.StrUtil; import com.yexuejc.base.util.StrUtil;
/** /**
@@ -26,16 +27,16 @@ public class LocalDateDeserializer extends JsonDeserializer<LocalDate> {
if (StrUtil.isEmpty(timeString)) { if (StrUtil.isEmpty(timeString)) {
return null; return null;
} }
if (timeString.contains(DateConsts.BAR)) { if (timeString.contains(SymbolicConstant.BAR)) {
return LocalDate.parse(timeString, DateTimeFormatter.ISO_DATE); return LocalDate.parse(timeString, DateTimeFormatter.ISO_DATE);
} else if (timeString.contains(DateConsts.DATE_KEY_AM) } else if (timeString.contains(DateConsts.DATE_KEY_AM)
|| timeString.contains(DateConsts.DATE_KEY_PM)) { || timeString.contains(DateConsts.DATE_KEY_PM)) {
return LocalDate.parse(timeString, return LocalDate.parse(timeString,
DateTimeFormatter.ofPattern(DateConsts.DATE_TIMESTAMP_LINUX, Locale.ENGLISH)); DateTimeFormatter.ofPattern(DateConsts.DATE_TIMESTAMP_LINUX, Locale.ENGLISH));
} else if (timeString.contains(DateConsts.SLASH) && timeString.contains(DateConsts.COLON)) { } else if (timeString.contains(SymbolicConstant.SLASH) && timeString.contains(SymbolicConstant.COLON)) {
return LocalDate.parse(timeString.substring(0, 10), return LocalDate.parse(timeString.substring(0, 10),
DateTimeFormatter.ofPattern(DateConsts.DATE_YYYY_MM_DD_SLASH)); DateTimeFormatter.ofPattern(DateConsts.DATE_YYYY_MM_DD_SLASH));
} else if (timeString.contains(DateConsts.SLASH)) { } else if (timeString.contains(SymbolicConstant.SLASH)) {
return LocalDate.parse(timeString, DateTimeFormatter.ofPattern(DateConsts.DATE_YYYY_MM_DD_SLASH)); return LocalDate.parse(timeString, DateTimeFormatter.ofPattern(DateConsts.DATE_YYYY_MM_DD_SLASH));
} else { } else {
return LocalDate.parse(timeString, DateTimeFormatter.BASIC_ISO_DATE); return LocalDate.parse(timeString, DateTimeFormatter.BASIC_ISO_DATE);

View File

@@ -9,6 +9,7 @@ import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonDeserializer;
import com.yexuejc.base.constant.DateConsts; import com.yexuejc.base.constant.DateConsts;
import com.yexuejc.base.constant.SymbolicConstant;
import com.yexuejc.base.util.StrUtil; import com.yexuejc.base.util.StrUtil;
/** /**
@@ -33,11 +34,11 @@ public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
DateTimeFormatter.ofPattern(DateConsts.DATE_TIMESTAMP_LINUX, Locale.ENGLISH)); DateTimeFormatter.ofPattern(DateConsts.DATE_TIMESTAMP_LINUX, Locale.ENGLISH));
} else if (timeString.endsWith(DateConsts.DATE_KEY_Z)) { } else if (timeString.endsWith(DateConsts.DATE_KEY_Z)) {
return LocalDateTime.parse(timeString, DateTimeFormatter.ISO_INSTANT); return LocalDateTime.parse(timeString, DateTimeFormatter.ISO_INSTANT);
} else if (timeString.contains(DateConsts.SLASH)) { } else if (timeString.contains(SymbolicConstant.SLASH)) {
return LocalDateTime.parse(timeString, DateTimeFormatter.ofPattern(DateConsts.DATE_TIMESTAMP)); return LocalDateTime.parse(timeString, DateTimeFormatter.ofPattern(DateConsts.DATE_TIMESTAMP));
} else { } else {
return LocalDateTime.parse(timeString, return LocalDateTime.parse(timeString,
DateTimeFormatter.ofPattern(DateConsts.DATE_YYYY_MM_DD_HH_MM_SS)); DateTimeFormatter.ofPattern(DateConsts.DATE_TIME_PATTERN));
} }
} }

View File

@@ -10,6 +10,7 @@ import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonDeserializer;
import com.yexuejc.base.constant.DateConsts; import com.yexuejc.base.constant.DateConsts;
import com.yexuejc.base.constant.SymbolicConstant;
import com.yexuejc.base.util.StrUtil; import com.yexuejc.base.util.StrUtil;
/** /**
@@ -34,12 +35,12 @@ public class TimestampDeserializer extends JsonDeserializer<Timestamp> {
DateTimeFormatter.ofPattern(DateConsts.DATE_TIMESTAMP_LINUX, Locale.ENGLISH))); DateTimeFormatter.ofPattern(DateConsts.DATE_TIMESTAMP_LINUX, Locale.ENGLISH)));
} else if (timeString.endsWith(DateConsts.DATE_KEY_Z)) { } else if (timeString.endsWith(DateConsts.DATE_KEY_Z)) {
return Timestamp.valueOf(LocalDateTime.parse(timeString, DateTimeFormatter.ISO_INSTANT)); return Timestamp.valueOf(LocalDateTime.parse(timeString, DateTimeFormatter.ISO_INSTANT));
} else if (timeString.contains(DateConsts.SLASH)) { } else if (timeString.contains(SymbolicConstant.SLASH)) {
return Timestamp.valueOf( return Timestamp.valueOf(
LocalDateTime.parse(timeString, DateTimeFormatter.ofPattern(DateConsts.DATE_TIMESTAMP))); LocalDateTime.parse(timeString, DateTimeFormatter.ofPattern(DateConsts.DATE_TIMESTAMP)));
} else { } else {
return Timestamp.valueOf(LocalDateTime.parse(timeString, return Timestamp.valueOf(LocalDateTime.parse(timeString,
DateTimeFormatter.ofPattern(DateConsts.DATE_YYYY_MM_DD_HH_MM_SS))); DateTimeFormatter.ofPattern(DateConsts.DATE_TIME_PATTERN)));
} }
} }

View File

@@ -1,20 +1,36 @@
package com.yexuejc.base.encrypt; package com.yexuejc.base.encrypt;
import org.apache.commons.codec.binary.Base64; import java.io.ByteArrayOutputStream;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.io.IOException;
import java.nio.charset.Charset;
import javax.crypto.Cipher; import java.nio.charset.StandardCharsets;
import javax.crypto.NoSuchPaddingException; import java.nio.file.Files;
import java.io.*; import java.nio.file.Paths;
import java.security.*; import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey; import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException; import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec; import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.logging.Logger; import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import com.yexuejc.base.constant.SymbolicConstant;
import com.yexuejc.base.exception.BaseException;
import com.yexuejc.base.http.RequestHeader;
import com.yexuejc.base.util.StrUtil;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/** /**
* RSA加解密 配置模式 * RSA加解密 配置模式
@@ -25,8 +41,8 @@ import java.util.logging.Logger;
* @date: 2018/5/15 14:39 * @date: 2018/5/15 14:39
*/ */
public class RSA { public class RSA {
private static Logger log = Logger.getLogger(RSA.class.getName()); private static System.Logger log = System.getLogger(RSA.class.getName());
public static final String CHARSET = "UTF-8"; public static final Charset CHARSET = StandardCharsets.UTF_8;
public static final String RSA_ALGORITHM = "RSA"; public static final String RSA_ALGORITHM = "RSA";
/** /**
* 加密方式 * 加密方式
@@ -36,12 +52,12 @@ public class RSA {
* RSA/ECB/PKCS1Padding 改变加密结果 * RSA/ECB/PKCS1Padding 改变加密结果
* </pre> * </pre>
*/ */
public static String RSA_ALGORITHM_ECB = "RSA"; public static final String RSA_ALGORITHM_ECB = "RSA";
/** /**
* 是否每次改变加密结果 * 是否每次改变加密结果
* 只针对于RSA_ALGORITHM_ECB = "RSA"有效 * 只针对于RSA_ALGORITHM_ECB = "RSA"有效
*/ */
public static boolean isChangeSign = true; public static final boolean isChangeSign = true;
/** /**
* 是否使用 Base64URL 方式加密 默认正常加密 * 是否使用 Base64URL 方式加密 默认正常加密
* <pre> * <pre>
@@ -66,7 +82,7 @@ public class RSA {
/** /**
* 签名算法 * 签名算法
*/ */
public static SignAlgorithm signAlgorithm = SignAlgorithm.SHA1withRSA; public static final SignAlgorithm signAlgorithm = SignAlgorithm.SHA256withRSA;
/** /**
* 生成密钥对 * 生成密钥对
@@ -103,8 +119,8 @@ public class RSA {
Key publicKey = keyPair.getPublic(); Key publicKey = keyPair.getPublic();
//得到私钥 //得到私钥
Key privateKey = keyPair.getPrivate(); Key privateKey = keyPair.getPrivate();
String privateKeyStr = null; String privateKeyStr;
String publicKeyStr = null; String publicKeyStr;
if (encodeBase64URLSafe) { if (encodeBase64URLSafe) {
publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded()); publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded());
privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded()); privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded());
@@ -112,12 +128,33 @@ public class RSA {
publicKeyStr = Base64.encodeBase64String(publicKey.getEncoded()); publicKeyStr = Base64.encodeBase64String(publicKey.getEncoded());
privateKeyStr = Base64.encodeBase64String(privateKey.getEncoded()); privateKeyStr = Base64.encodeBase64String(privateKey.getEncoded());
} }
Map<String, String> keyPairMap = new HashMap<String, String>(2); Map<String, String> keyPairMap = new HashMap<>(2);
keyPairMap.put("publicKey", publicKeyStr); keyPairMap.put("publicKey", publicKeyStr);
keyPairMap.put("privateKey", privateKeyStr); keyPairMap.put("privateKey", privateKeyStr);
return keyPairMap; return keyPairMap;
} }
/**
* 生成密钥文件
* <p>会在指定路径下生成
* <b>private.key</b>和<b>public.key</b>
* </p>
*
* @param filePath 密钥文件路径
* @throws BaseException
*/
public static void initKey4File(String filePath) throws BaseException {
Map<String, String> keys = initKeys(2048, false);
try {
Files.write(Paths.get(filePath, "private.key"), StrUtil.chunkString(keys.get("privateKey"), 64)
.getBytes(CHARSET));
Files.write(Paths.get(filePath, "public.key"), StrUtil.chunkString(keys.get("publicKey"), 64)
.getBytes(CHARSET));
} catch (IOException e) {
throw new BaseException(e, "生成密钥文件失败");
}
}
/** /**
* 得到公钥 * 得到公钥
* *
@@ -171,9 +208,11 @@ public class RSA {
Cipher cipher = getCipher(); Cipher cipher = getCipher();
cipher.init(Cipher.ENCRYPT_MODE, publicKey); cipher.init(Cipher.ENCRYPT_MODE, publicKey);
if (encodeBase64URLSafe) { if (encodeBase64URLSafe) {
return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus().bitLength())); return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus()
.bitLength()));
} else { } else {
return Base64.encodeBase64String(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus().bitLength())); return Base64.encodeBase64String(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus()
.bitLength()));
} }
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e); throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
@@ -191,7 +230,8 @@ public class RSA {
try { try {
Cipher cipher = getCipher(); Cipher cipher = getCipher();
cipher.init(Cipher.DECRYPT_MODE, privateKey); cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), privateKey.getModulus().bitLength()), CHARSET); return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), privateKey.getModulus()
.bitLength()), CHARSET);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e); throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
} }
@@ -222,9 +262,11 @@ public class RSA {
Cipher cipher = getCipher(); Cipher cipher = getCipher();
cipher.init(Cipher.ENCRYPT_MODE, privateKey); cipher.init(Cipher.ENCRYPT_MODE, privateKey);
if (encodeBase64URLSafe) { if (encodeBase64URLSafe) {
return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), privateKey.getModulus().bitLength())); return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), privateKey.getModulus()
.bitLength()));
} else { } else {
return Base64.encodeBase64String(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), privateKey.getModulus().bitLength())); return Base64.encodeBase64String(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), privateKey.getModulus()
.bitLength()));
} }
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e); throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
@@ -243,7 +285,8 @@ public class RSA {
try { try {
Cipher cipher = getCipher(); Cipher cipher = getCipher();
cipher.init(Cipher.DECRYPT_MODE, publicKey); cipher.init(Cipher.DECRYPT_MODE, publicKey);
return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), publicKey.getModulus().bitLength()), CHARSET); return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), publicKey.getModulus()
.bitLength()), CHARSET);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e); throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
} }
@@ -304,7 +347,7 @@ public class RSA {
private static Signature signature; private static Signature signature;
/** /**
* 私钥签名默认算法SHA1withRSA * 私钥签名默认算法SHA256withRSA
* <p> * <p>
* 签名算法 {@link SignAlgorithm} * 签名算法 {@link SignAlgorithm}
* </p> * </p>
@@ -313,48 +356,38 @@ public class RSA {
* @param privateKey 签名私钥 * @param privateKey 签名私钥
* @param base64URLSafe 是否生成 base64URL 格式的密钥默认false * @param base64URLSafe 是否生成 base64URL 格式的密钥默认false
* @return * @return
* @throws NoSuchAlgorithmException * @throws BaseException
*/ */
public static String sign(String plaintext, RSAPrivateKey privateKey, boolean base64URLSafe) throws NoSuchAlgorithmException { public static String sign(String plaintext, RSAPrivateKey privateKey, boolean base64URLSafe) throws BaseException {
encodeBase64URLSafe = base64URLSafe; encodeBase64URLSafe = base64URLSafe;
return sign(plaintext, privateKey); return sign(plaintext, privateKey);
} }
/** /**
* 私钥签名默认算法SHA1withRSA * 私钥签名默认算法SHA256withRSA
* <p> * <p>
* 签名算法 {@link SignAlgorithm} * 签名算法 {@link SignAlgorithm}
* </p> * </p>
* *
* @param plaintext 签名字符串 * @param plaintext 签名字符串
* @param privateKey 签名私钥 * @param privateKey 签名私钥
* @return * @return 签名串
* @throws NoSuchAlgorithmException * @throws BaseException
*/ */
public static String sign(String plaintext, RSAPrivateKey privateKey) throws NoSuchAlgorithmException { public static String sign(String plaintext, RSAPrivateKey privateKey) throws BaseException {
signature = Signature.getInstance(signAlgorithm.getValue());
String signBase64Str = "";
try { try {
signature = Signature.getInstance(signAlgorithm.getValue());
String signBase64Str = "";
signature.initSign(privateKey); signature.initSign(privateKey);
try { signature.update(plaintext.getBytes(CHARSET));
signature.update(plaintext.getBytes(CHARSET));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException("签名字符串[" + plaintext + "]的数据时发生异常", e);
}
if (encodeBase64URLSafe) { if (encodeBase64URLSafe) {
signBase64Str = Base64.encodeBase64URLSafeString(signature.sign()); signBase64Str = Base64.encodeBase64URLSafeString(signature.sign());
} else { } else {
signBase64Str = Base64.encodeBase64String(signature.sign()); signBase64Str = Base64.encodeBase64String(signature.sign());
} }
return signBase64Str; return signBase64Str;
} catch (InvalidKeyException var6) { } catch (Exception e) {
var6.printStackTrace(); throw new BaseException(e, "签名字符串[" + plaintext + "]的数据时发生异常");
throw new RuntimeException("签名字符串[" + plaintext + "]的数据时发生异常", var6);
} catch (SignatureException var7) {
var7.printStackTrace();
throw new RuntimeException("签名字符串[" + plaintext + "]的数据时发生异常", var7);
} }
} }
@@ -364,24 +397,89 @@ public class RSA {
* @param plaintext 原串 * @param plaintext 原串
* @param signStr 签名串 * @param signStr 签名串
* @param publicKey 公钥 * @param publicKey 公钥
* @return * @return true校验成功 / false校验失败
* @throws UnsupportedEncodingException * @throws BaseException
*/ */
public static boolean verify(String plaintext, String signStr, RSAPublicKey publicKey) throws UnsupportedEncodingException, NoSuchAlgorithmException { public static boolean verify(String plaintext, String signStr, RSAPublicKey publicKey) throws BaseException {
signature = Signature.getInstance(signAlgorithm.getValue());
boolean isValid = false;
try { try {
signature = Signature.getInstance(signAlgorithm.getValue());
signature.initVerify(publicKey); signature.initVerify(publicKey);
signature.update(plaintext.getBytes(CHARSET)); signature.update(plaintext.getBytes(CHARSET));
isValid = signature.verify(Base64.decodeBase64(signStr)); return signature.verify(Base64.decodeBase64(signStr));
} catch (InvalidKeyException var6) { } catch (Exception e) {
var6.printStackTrace(); throw new BaseException(e, "校验签名字符串[" + plaintext + "]的数据时发生异常");
throw new RuntimeException("校验签名字符串[" + plaintext + "]的数据时发生异常", var6);
} catch (SignatureException var7) {
var7.printStackTrace();
throw new RuntimeException("校验签名字符串[" + plaintext + "]的数据时发生异常", var7);
} }
}
return isValid; /**
* 公钥校验签名
* <p>校验格式:</p>
* <pre>
* [HTTP-METHOD] [Response-URI]
* [Client-Id].[Response-Time].[Response-Body]
* </pre>
*
* @param uri 请求地址
* @param respHeader 请求响应头
* @param data 数据
* @param publicKeyPath 公钥文件地址
* @return true校验成功 / false校验失败
* @throws BaseException 签名校验异常
*/
public static boolean verifyByApi(String uri, RequestHeader respHeader, String data, String publicKeyPath) throws BaseException {
try {
// @formatter:off
String signContent = "POST {uri}\n{clientId}.{respTime}.{body}"
.replace("{uri}", uri)
.replace("{clientId}", respHeader.getClientId())
.replace("{respTime}", respHeader.geRespTime())
.replace("{body}", data);
// @formatter:on
String sign = respHeader.getSignature();
if (sign.contains(SymbolicConstant.COMMA)) {
sign = Arrays.stream(sign.split(SymbolicConstant.COMMA))
.map(s -> s.split(SymbolicConstant.EQUAL))
.filter(subSplit -> subSplit.length > 1 && RequestHeader.SIGNATURE.equalsIgnoreCase(subSplit[0]))
.map(subSplit -> subSplit[1])
.findFirst()
.orElse(sign);
}
log.log(System.Logger.Level.DEBUG, "签名内容:=====\n{0}\n=====", signContent);
return verify(signContent, sign, RSA2.getPublicKey(publicKeyPath));
} catch (Exception e) {
throw new BaseException(e, "校验签名时发生异常");
}
}
/**
* 签名
* <p> 签名格式:</p>
* <pre>
* [HTTP-METHOD] [Request-URI]
* [Client-Id].[Request-Time].[Request-Body]
* </pre>
*
* @param uri 请求地址
* @param requestHeader 请求头
* @param data 数据
* @param privateKeyPath 私钥文件地址
* @return 签名串
* @throws BaseException 签名异常
*/
public static String signByApi(String uri, RequestHeader requestHeader, String data, String privateKeyPath) throws BaseException {
try {
// @formatter:off
String signContent = "POST {uri}\n{clientId}.{reqTime}.{body}"
.replace("{uri}", uri)
.replace("{clientId}", requestHeader.getClientId())
.replace("{reqTime}", requestHeader.getReqTime())
.replace("{body}", data);
// @formatter:on
log.log(System.Logger.Level.DEBUG, "签名内容:=====\n{0}\n=====", signContent);
return sign(signContent, RSA2.getPrivateKeyFromPKCS1(privateKeyPath), true);
} catch (Exception e) {
throw new BaseException(e, "签名时发生异常");
}
} }
} }

View File

@@ -1,16 +1,41 @@
package com.yexuejc.base.encrypt; package com.yexuejc.base.encrypt;
import com.yexuejc.base.util.StrUtil; import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.*; import java.io.FileNotFoundException;
import java.security.*; import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey; import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Enumeration; import java.util.Enumeration;
import com.yexuejc.base.exception.BaseException;
import com.yexuejc.base.util.StrUtil;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
import org.bouncycastle.operator.InputDecryptorProvider;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
/** /**
* RSA加解密 证书模式 * RSA加解密 证书模式
* 依赖 {@link RSA} * 依赖 {@link RSA}
@@ -22,8 +47,22 @@ import java.util.Enumeration;
*/ */
public class RSA2 { public class RSA2 {
public static final String CHARSET = "UTF-8"; public static final String KEY_RSA = "RSA";
public static final String RSA_ALGORITHM = "RSA"; public static final String KEY_PKCS1 = "PKCS81";
public static final String KEY_PKCS8 = "PKCS8";
public static final String KEY_PKCS12 = "PKCS12";
public static final String KEY_JKS = "JKS";
public static final String PEM_FILE_START_CE = "-----BEGIN CERTIFICATE-----";
public static final String PEM_FILE_END_CE = "-----END CERTIFICATE-----";
public static final String PEM_FILE_START_EN = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
public static final String PEM_FILE_END_EN = "-----END ENCRYPTED PRIVATE KEY-----";
public static final String PEM_FILE_START_PUBLIC = "-----BEGIN PUBLIC KEY-----";
public static final String PEM_FILE_END_PUBLIC = "-----END PUBLIC KEY-----";
public static final String PEM_FILE_START_PRIVATE = "-----BEGIN PRIVATE KEY-----";
public static final String PEM_FILE_END_PRIVATE = "-----END PRIVATE KEY-----";
public static final String PEM_FILE_START_RSA = "-----BEGIN RSA PRIVATE KEY-----";
public static final String PEM_FILE_END_RSA = "-----END RSA PRIVATE KEY-----";
public static final String PEM_FILE_START_PREFIX = "-----BEGIN";
/** /**
* 得到公钥 * 得到公钥
@@ -32,11 +71,24 @@ public class RSA2 {
* @throws Exception * @throws Exception
*/ */
public static RSAPublicKey getPublicKey(String filepath) throws CertificateException, FileNotFoundException { public static RSAPublicKey getPublicKey(String filepath) throws CertificateException, FileNotFoundException {
//通过证书,获取公钥 try (FileInputStream pubKeyIn = new FileInputStream(filepath)) {
CertificateFactory cf = null; byte[] certData = pubKeyIn.readAllBytes();
cf = CertificateFactory.getInstance("X.509"); // 检查是否为PEM格式
Certificate c = cf.generateCertificate(new FileInputStream(filepath)); String certString = new String(certData, StandardCharsets.UTF_8);
return (RSAPublicKey) c.getPublicKey(); if (certString.contains(PEM_FILE_START_PREFIX)) {
// 这可能不是证书文件,而是公钥文件
return getPublicKey4Pem(certString);
}
//通过证书,获取公钥
try (ByteArrayInputStream bis = new ByteArrayInputStream(certData)) {
return getPublicKey(bis);
} catch (Exception e) {
// 在尝试一次读取
return getPublicKey4Pem(certString);
}
} catch (Exception e) {
throw new CertificateException("无法解析证书: " + e.getMessage(), e);
}
} }
/** /**
@@ -48,12 +100,96 @@ public class RSA2 {
*/ */
public static RSAPublicKey getPublicKey(InputStream pubKeyIn) throws CertificateException { public static RSAPublicKey getPublicKey(InputStream pubKeyIn) throws CertificateException {
//通过证书,获取公钥 //通过证书,获取公钥
CertificateFactory cf = null; CertificateFactory cf = CertificateFactory.getInstance("X.509");
cf = CertificateFactory.getInstance("X.509");
Certificate c = cf.generateCertificate(pubKeyIn); Certificate c = cf.generateCertificate(pubKeyIn);
return (RSAPublicKey) c.getPublicKey(); return (RSAPublicKey) c.getPublicKey();
} }
/**
* 从PKCS12证书中获取公钥
*
* @param pubKeyPath 密钥文件路径
* @param alias 别名
* @param password 密码
* @return RSAPublicKey
* @throws BaseException
*/
public static RSAPublicKey getPublicKeyFromPKCS12(String pubKeyPath, String alias, String password) throws BaseException {
try (FileInputStream fis = new FileInputStream(pubKeyPath)) {
return getPublicKeyFromPKCS12(fis, alias, password);
} catch (Exception e) {
throw new BaseException(e, "无法从PKCS12证书中获取公钥");
}
}
/**
* 从PKCS12证书中获取公钥
*
* @param pubKeyIn 密钥文件流
* @param alias 别名
* @param password 密码
* @return RSAPublicKey
* @throws BaseException
*/
public static RSAPublicKey getPublicKeyFromPKCS12(InputStream pubKeyIn, String alias, String password) throws BaseException {
try {
KeyStore keyStore = KeyStore.getInstance(KEY_PKCS12);
keyStore.load(pubKeyIn, password.toCharArray());
Certificate cert = keyStore.getCertificate(alias);
return (RSAPublicKey) cert.getPublicKey();
} catch (Exception e) {
throw new BaseException(e, "无法从PKCS12证书中获取公钥");
}
}
/**
* 从PEM格式的公钥文件中提取公钥
*
* @param pemContent PEM格式的内容
* @return RSAPublicKey
* @throws CertificateException
*/
private static RSAPublicKey getPublicKey4Pem(String pemContent) throws CertificateException {
try {
if (pemContent.contains(PEM_FILE_START_CE)) {
String base64Cert = pemContent.replace(PEM_FILE_START_CE, "")
.replace(PEM_FILE_END_CE, "")
.replaceAll("\\s", "");
byte[] certBytes = Base64.getDecoder()
.decode(base64Cert);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate c = cf.generateCertificate(new ByteArrayInputStream(certBytes));
return (RSAPublicKey) c.getPublicKey();
}
// 如果是公钥PEM格式
else if (pemContent.contains(PEM_FILE_START_PUBLIC)) {
String base64Key = pemContent.replace(PEM_FILE_START_PUBLIC, "")
.replace(PEM_FILE_END_PUBLIC, "")
.replaceAll("\\s", "");
byte[] keyBytes = Base64.getDecoder()
.decode(base64Key);
KeyFactory kf = KeyFactory.getInstance(KEY_RSA);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
return (RSAPublicKey) kf.generatePublic(keySpec);
} else {
String trimmedString = pemContent.replaceAll("\\s", "")
.trim();
if (!pemContent.equals(trimmedString)) {
byte[] keyBytes = Base64.getDecoder()
.decode(trimmedString);
KeyFactory kf = KeyFactory.getInstance(KEY_RSA);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
return (RSAPublicKey) kf.generatePublic(keySpec);
}
}
} catch (Exception e) {
throw new CertificateException("无法从PEM内容解析公钥: " + e.getMessage(), e);
}
throw new CertificateException("无法从PEM内容解析公钥");
}
/** /**
* 读取JKS格式的key私钥keystore格式 * 读取JKS格式的key私钥keystore格式
* *
@@ -61,14 +197,10 @@ public class RSA2 {
* @param alias 证书别名 * @param alias 证书别名
* @param password 证书密码 * @param password 证书密码
* @return * @return
* @throws NoSuchAlgorithmException * @throws BaseException
* @throws KeyStoreException
* @throws IOException
* @throws CertificateException
* @throws UnrecoverableKeyException
*/ */
public static RSAPrivateKey getPrivateKey(String filepath, String alias, String password) throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, UnrecoverableKeyException { public static RSAPrivateKey getPrivateKey(String filepath, String alias, String password) throws BaseException {
return getPrivateKey(filepath, alias, password, "JKS"); return getPrivateKey(filepath, alias, password, KEY_JKS);
} }
/** /**
@@ -78,14 +210,10 @@ public class RSA2 {
* @param alias 证书别名 * @param alias 证书别名
* @param password 证书密码 * @param password 证书密码
* @return * @return
* @throws NoSuchAlgorithmException * @throws BaseException
* @throws KeyStoreException
* @throws IOException
* @throws CertificateException
* @throws UnrecoverableKeyException
*/ */
public static RSAPrivateKey getPrivateKey(InputStream priKeyIn, String alias, String password) throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, UnrecoverableKeyException { public static RSAPrivateKey getPrivateKey(InputStream priKeyIn, String alias, String password) throws BaseException {
return getPrivateKey(priKeyIn, alias, password, "JKS"); return getPrivateKey(priKeyIn, alias, password, KEY_JKS);
} }
/** /**
@@ -95,14 +223,10 @@ public class RSA2 {
* @param alias 证书别名 可空 * @param alias 证书别名 可空
* @param password 证书密码 * @param password 证书密码
* @return * @return
* @throws NoSuchAlgorithmException * @throws BaseException
* @throws KeyStoreException
* @throws IOException
* @throws CertificateException
* @throws UnrecoverableKeyException
*/ */
public static RSAPrivateKey getPrivateKeyFromPKCS12(String filepath, String alias, String password) throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, UnrecoverableKeyException { public static RSAPrivateKey getPrivateKeyFromPKCS12(String filepath, String alias, String password) throws BaseException {
return getPrivateKey(filepath, alias, password, "PKCS12"); return getPrivateKey(filepath, alias, password, KEY_PKCS12);
} }
/** /**
@@ -112,14 +236,54 @@ public class RSA2 {
* @param alias 证书别名 可空 * @param alias 证书别名 可空
* @param password 证书密码 * @param password 证书密码
* @return * @return
* @throws NoSuchAlgorithmException * @throws BaseException
* @throws KeyStoreException
* @throws IOException
* @throws CertificateException
* @throws UnrecoverableKeyException
*/ */
public static RSAPrivateKey getPrivateKeyFromPKCS12(InputStream priKeyIn, String alias, String password) throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, UnrecoverableKeyException { public static RSAPrivateKey getPrivateKeyFromPKCS12(InputStream priKeyIn, String alias, String password) throws BaseException {
return getPrivateKey(priKeyIn, alias, password, "PKCS12"); return getPrivateKey(priKeyIn, alias, password, KEY_PKCS12);
}
/**
* 读取PKCS8格式的key私钥pem格式
*
* @param filepath 私钥路径
* @return
* @throws BaseException
*/
public static RSAPrivateKey getPrivateKeyFromPKCS8(String filepath, String password) throws BaseException {
return getPrivateKey(filepath, null, password, KEY_PKCS8);
}
/**
* 读取PKCS8格式的key私钥pem格式
*
* @param priKeyIn 私钥文件流
* @return
* @throws BaseException
*/
public static RSAPrivateKey getPrivateKeyFromPKCS8(InputStream priKeyIn, String password) throws BaseException {
return getPrivateKey(priKeyIn, null, password, KEY_PKCS8);
}
/**
* 读取PKCS8格式的key私钥pem格式
*
* @param filepath 私钥路径
* @return
* @throws BaseException
*/
public static RSAPrivateKey getPrivateKeyFromPKCS1(String filepath) throws BaseException {
return getPrivateKey(filepath, null, null, KEY_PKCS1);
}
/**
* 读取PKCS8格式的key私钥pem格式
*
* @param priKeyIn 私钥文件流
* @return
* @throws BaseException
*/
public static RSAPrivateKey getPrivateKeyFromPKCS1(InputStream priKeyIn) throws BaseException {
return getPrivateKey(priKeyIn, null, null, KEY_PKCS1);
} }
/** /**
@@ -130,60 +294,107 @@ public class RSA2 {
* @param password 证书密码 * @param password 证书密码
* @param type 证书格式 * @param type 证书格式
* @return * @return
* @throws NoSuchAlgorithmException * @throws BaseException
* @throws KeyStoreException
* @throws IOException
* @throws CertificateException
* @throws UnrecoverableKeyException
*/ */
public static RSAPrivateKey getPrivateKey(String filepath, String alias, String password, String type) throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, UnrecoverableKeyException { public static RSAPrivateKey getPrivateKey(String filepath, String alias, String password, String type) throws BaseException {
KeyStore ks = KeyStore.getInstance(type); try (FileInputStream fileInputStream = new FileInputStream(filepath)) {
FileInputStream fileInputStream = null; return getPrivateKey(fileInputStream, alias, password, type);
} catch (Exception e) {
throw new BaseException(e, "私钥读取失败。");
}
}
/**
* 读取key私钥
*
* @param priKeyIn 私钥文件流
* @param alias 证书别名 可空
* @param password 证书密码
* @param type 证书格式
* @return
* @throws BaseException
*/
public static RSAPrivateKey getPrivateKey(InputStream priKeyIn, String alias, String password, String type) throws BaseException {
try { try {
fileInputStream = new FileInputStream(filepath); if (KEY_PKCS8.equalsIgnoreCase(type) || KEY_PKCS1.equalsIgnoreCase(type)) {
ks.load(fileInputStream, password.toCharArray()); byte[] keyBytes = priKeyIn.readAllBytes();
if (StrUtil.isEmpty(alias)) { String keyString = new String(keyBytes, StandardCharsets.UTF_8);
Enumeration<?> aliases = ks.aliases(); if (keyString.contains(PEM_FILE_START_PREFIX)) {
if (aliases != null) { // 标准PEM格式内容
if (aliases.hasMoreElements()) { return getPrivateKeyByPKCS8(keyString, password);
}
// 非标准PEM格式内容尝试直接读取
String trimmedString = keyString.replaceAll("\\s", "")
.trim();
if (!keyString.equals(trimmedString)) {
keyBytes = Base64.getDecoder()
.decode(trimmedString);
}
// 验证数据是否有效
if (keyBytes.length == 0) {
throw new BaseException("Private key data is empty");
}
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance(KEY_RSA);
return (RSAPrivateKey) kf.generatePrivate(keySpec);
} else {
KeyStore ks = KeyStore.getInstance(type);
ks.load(priKeyIn, password.toCharArray());
if (StrUtil.isEmpty(alias)) {
Enumeration<?> aliases = ks.aliases();
if (aliases != null && aliases.hasMoreElements()) {
alias = (String) aliases.nextElement(); alias = (String) aliases.nextElement();
} }
} }
return (RSAPrivateKey) ks.getKey(alias, password.toCharArray());
} }
} finally { } catch (Exception e) {
if (fileInputStream != null) { throw new BaseException(e, "私钥读取失败。");
fileInputStream.close();
}
} }
return (RSAPrivateKey) ks.getKey(alias, password.toCharArray());
} }
/** /**
* 读取key私钥 * 解密并解析加密的PKCS#8私钥
* *
* @param priKeyIn 私钥文件流 * @param pemContent PEM格式的加密私钥内容
* @param alias 证书别名 可空 * @param password 密码
* @param password 证书密码 * @return RSAPrivateKey
* @param type 证书格式 * @throws Exception
* @return
* @throws NoSuchAlgorithmException
* @throws KeyStoreException
* @throws IOException
* @throws CertificateException
* @throws UnrecoverableKeyException
*/ */
public static RSAPrivateKey getPrivateKey(InputStream priKeyIn, String alias, String password, String type) throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, UnrecoverableKeyException { private static RSAPrivateKey getPrivateKeyByPKCS8(String pemContent, String password) throws Exception {
KeyStore ks = KeyStore.getInstance(type); if (Security.getProvider("BC") == null) {
ks.load(priKeyIn, password.toCharArray()); Security.addProvider(new BouncyCastleProvider());
if (StrUtil.isEmpty(alias)) { }
Enumeration<?> aliases = ks.aliases(); try (PEMParser pemParser = new PEMParser(new StringReader(pemContent))) {
if (aliases != null) { Object object = pemParser.readObject();
if (aliases.hasMoreElements()) {
alias = (String) aliases.nextElement(); // 处理PKCS#1格式的RSA私钥
} if (object instanceof org.bouncycastle.asn1.pkcs.RSAPrivateKey) {
} JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
PrivateKeyInfo privateKeyInfo = PrivateKeyInfo.getInstance(object);
return (RSAPrivateKey) converter.getPrivateKey(privateKeyInfo);
} else if (object instanceof PEMKeyPair) {
// 处理PKCS#1格式的RSA私钥
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
return (RSAPrivateKey) converter.getPrivateKey(((PEMKeyPair) object).getPrivateKeyInfo());
} else if (object instanceof PKCS8EncryptedPrivateKeyInfo) {
// 处理加密的PKCS#8私钥
PKCS8EncryptedPrivateKeyInfo encryptedInfo = (PKCS8EncryptedPrivateKeyInfo) object;
InputDecryptorProvider decryptorProvider = new JceOpenSSLPKCS8DecryptorProviderBuilder().setProvider("BC")
.build(password.toCharArray());
PrivateKeyInfo privateKeyInfo = encryptedInfo.decryptPrivateKeyInfo(decryptorProvider);
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
return (RSAPrivateKey) converter.getPrivateKey(privateKeyInfo);
} else if (object instanceof PrivateKeyInfo) {
// 处理未加密的PKCS#8私钥
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
return (RSAPrivateKey) converter.getPrivateKey((PrivateKeyInfo) object);
}
throw new IllegalArgumentException("不支持的PEM格式");
} catch (Exception e) {
throw new BaseException(e, "获取私钥失败");
} }
return (RSAPrivateKey) ks.getKey(alias, password.toCharArray());
} }
/** /**
@@ -218,8 +429,8 @@ public class RSA2 {
*/ */
public static void cover2Pfx(FileInputStream fis, FileOutputStream out, char[] oPwd, char[] nPwd) { public static void cover2Pfx(FileInputStream fis, FileOutputStream out, char[] oPwd, char[] nPwd) {
try { try {
KeyStore inputKeyStore = KeyStore.getInstance("JKS"); KeyStore inputKeyStore = KeyStore.getInstance(KEY_JKS);
cover(fis, out, oPwd, nPwd, inputKeyStore, "PKCS12"); cover(fis, out, oPwd, nPwd, inputKeyStore, KEY_PKCS12);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -258,8 +469,8 @@ public class RSA2 {
*/ */
public static void cover2keyStore(FileInputStream fis, FileOutputStream out, char[] oPwd, char[] nPwd) { public static void cover2keyStore(FileInputStream fis, FileOutputStream out, char[] oPwd, char[] nPwd) {
try { try {
KeyStore inputKeyStore = KeyStore.getInstance("PKCS12"); KeyStore inputKeyStore = KeyStore.getInstance(KEY_PKCS12);
cover(fis, out, oPwd, nPwd, inputKeyStore, "JKS"); cover(fis, out, oPwd, nPwd, inputKeyStore, KEY_JKS);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -301,7 +512,7 @@ public class RSA2 {
outputKeyStore.store(out, nPwd); outputKeyStore.store(out, nPwd);
} }
public static void main(String[] args) { // public static void main(String[] args) {
cover2Pfx("D:\\mykeystore.keystore", "D:\\m1.pfx", "123456", null); // cover2Pfx("D:\\mykeystore.keystore", "D:\\m1.pfx", "123456", null);
} // }
} }

View File

@@ -0,0 +1,147 @@
package com.yexuejc.base.exception;
import java.text.MessageFormat;
import java.util.ServiceLoader;
import com.yexuejc.base.constant.RespConsts;
import com.yexuejc.base.constant.SymbolicConstant;
import com.yexuejc.base.service.MessageService;
import com.yexuejc.base.util.StrUtil;
/**
* 异常处理
* @author yexuejc
* @date 2019/8/25 15:38
*/
public class BaseException extends Exception {
private static final System.Logger LOG = System.getLogger(BaseException.class.getName());
/** 序列化 */
private static final long serialVersionUID = 1L;
/** 异常消息CODE */
protected final String errorCode;
/** 异常消息内容 */
@SuppressWarnings("java:S1165")
protected String errorMessage;
/**
* 构造函数
*
* @param cause 异常对象
*/
public BaseException(Throwable cause) {
this(cause, RespConsts.CODE_ERROR, (Object) null);
}
/**
* 构造函数
*
* @param cause 异常对象
* @param errorCode 异常消息CODE
*/
public BaseException(Throwable cause, String errorCode) {
this(cause, errorCode, (Object) null);
}
/**
* 构造函数
*
* @param errorCode 异常消息CODE
*/
public BaseException(String errorCode) {
this((Throwable) null, errorCode, (Object) null);
}
/**
* 构造函数
*
* @param errorCode 异常消息CODE
* @param args 异常消息参数
*/
public BaseException(String errorCode, Object... args) {
this(null, errorCode, args);
}
/**
* 构造函数
*
* @param cause 异常对象
* @param errorCode 异常消息CODE
* @param args 异常消息的参数
*/
public BaseException(Throwable cause, String errorCode, Object... args) {
super(cause);
// 消息内容
if (StrUtil.isEmpty(errorCode)) {
errorCode = RespConsts.CODE_ERROR;
}
this.errorCode = errorCode;
this.errorMessage = getMessageByCode(errorCode, args);
if (cause instanceof BaseException) {
BaseException comExp = (BaseException) cause;
if (StrUtil.isNotEmpty(comExp.errorMessage)) {
this.errorMessage = StrUtil.isEmpty(this.errorMessage) ? comExp.errorMessage :
this.errorMessage + SymbolicConstant.NEW_LINE + comExp.errorMessage;
}
}
}
/**
* 获取异常消息CODE
*
* @return 异常消息CODE
*/
public String getErrorCode() {
return errorCode;
}
/**
* 获取异常消息内容
*
* @return
*/
@Override
public String getMessage() {
if (StrUtil.isNotEmpty(super.getMessage())) {
return super.getMessage();
}
return getErrorCode().equals(getFaultMessage()) ? getFaultMessage() : getErrorCode() + ":" + getFaultMessage();
}
/**
* 获取异常消息内容
*
* @return 异常消息内容,不包含异常信息
*/
public String getFaultMessage() {
return this.errorMessage;
}
/**
* 获取消息内容
*
* @param errorCode 异常消息CODE
* @param args 异常消息的参数
* @return
*/
protected String getMessageByCode(String errorCode, Object... args) {
try {
// 使用 ServiceLoader 动态加载 MessageService 实现
ServiceLoader<MessageService> loader = ServiceLoader.load(MessageService.class);
for (MessageService service : loader) {
if (service != null) {
return service.getMessage(errorCode, args);
}
}
// 如果没有找到实现,使用默认处理方式
LOG.log(System.Logger.Level.DEBUG, "No MessageService implementation found, using default message format.");
return MessageFormat.format(errorCode, args);
} catch (Exception e) {
LOG.log(System.Logger.Level.WARNING, "Error getting message for code: " + errorCode + ", using default format.", e);
return MessageFormat.format(errorCode, args);
}
}
}

View File

@@ -0,0 +1,51 @@
package com.yexuejc.base.http;
import java.util.HashMap;
import com.yexuejc.base.util.DateTimeUtil;
public class RequestHeader extends HashMap<String, String> {
public static final String CLIENT_ID = "Client-Id";
public static final String REQUEST_TIME = "Request-Time";
public static final String RESPONSE_TIME = "Response-Time";
public static final String SIGNATURE = "Signature";
public RequestHeader(String clientId) {
put("Content-Type", "application/json");
put(CLIENT_ID, clientId);
}
public static RequestHeader requestBuilder(String clientId) {
RequestHeader requestHeader = new RequestHeader(clientId);
// 2019-05-28T12:12:12+08:00
requestHeader.put(REQUEST_TIME, DateTimeUtil.formatIso8601BySystemZone());
return requestHeader;
}
public static RequestHeader responseBuilder(String clientId, String time, String signature) {
RequestHeader requestHeader = new RequestHeader(clientId);
requestHeader.put(RESPONSE_TIME, time);
requestHeader.put(SIGNATURE, signature);
return requestHeader;
}
public String getClientId() {
return get(CLIENT_ID);
}
public String getReqTime() {
return get(REQUEST_TIME);
}
public void setSignature(String signature) {
put(SIGNATURE, signature);
}
public String getSignature() {
return get(SIGNATURE);
}
public String geRespTime() {
return get(RESPONSE_TIME);
}
}

View File

@@ -1,6 +1,6 @@
package com.yexuejc.base.http; package com.yexuejc.base.http;
import com.yexuejc.base.constant.RespsConsts; import com.yexuejc.base.constant.RespConsts;
import com.yexuejc.base.util.JsonUtil; import com.yexuejc.base.util.JsonUtil;
import java.io.Serializable; import java.io.Serializable;
@@ -90,27 +90,27 @@ public class Resps<T> implements Serializable {
} }
public static Resps success(String[] msg) { public static Resps success(String[] msg) {
return new Resps(RespsConsts.CODE_SUCCESS, msg); return new Resps(RespConsts.CODE_SUCCESS, msg);
} }
public static Resps success(String msg) { public static Resps success(String msg) {
return new Resps(RespsConsts.CODE_SUCCESS, msg); return new Resps(RespConsts.CODE_SUCCESS, msg);
} }
public static Resps success() { public static Resps success() {
return new Resps(RespsConsts.CODE_SUCCESS, RespsConsts.MSG_SUCCESS_OPERATE); return new Resps(RespConsts.CODE_SUCCESS, RespConsts.MSG_SUCCESS_OPERATE);
} }
public static Resps error() { public static Resps error() {
return new Resps(RespsConsts.CODE_ERROR, RespsConsts.MSG_ERROT_OPERATE); return new Resps(RespConsts.CODE_ERROR, RespConsts.MSG_ERROT_OPERATE);
} }
public static Resps error(String msg) { public static Resps error(String msg) {
return new Resps(RespsConsts.CODE_ERROR, msg); return new Resps(RespConsts.CODE_ERROR, msg);
} }
public static Resps error(String[] msg) { public static Resps error(String[] msg) {
return new Resps(RespsConsts.CODE_ERROR, msg); return new Resps(RespConsts.CODE_ERROR, msg);
} }
public static Resps error(String code, String msg) { public static Resps error(String code, String msg) {
@@ -122,15 +122,15 @@ public class Resps<T> implements Serializable {
} }
public static Resps fail() { public static Resps fail() {
return new Resps(RespsConsts.CODE_FAIL, RespsConsts.MSG_FAIL_OPERATE); return new Resps(RespConsts.CODE_FAIL, RespConsts.MSG_FAIL_OPERATE);
} }
public static Resps fail(String msg) { public static Resps fail(String msg) {
return new Resps(RespsConsts.CODE_FAIL, msg); return new Resps(RespConsts.CODE_FAIL, msg);
} }
public static Resps fail(String[] msg) { public static Resps fail(String[] msg) {
return new Resps(RespsConsts.CODE_FAIL, msg); return new Resps(RespConsts.CODE_FAIL, msg);
} }
public static Resps fail(String code, String msg) { public static Resps fail(String code, String msg) {

View File

@@ -0,0 +1,19 @@
package com.yexuejc.base.service;
/**
* 消息获取接口
*
* @author yexuejc
* @date 2025/8/25 15:33
*/
public interface MessageService {
/**
* 通过异常CODE和参数获取对应的错误信息多语言实现
*
* @param code 异常CODE
* @param args 参数
* @return 错误信息
*/
String getMessage(String code, Object... args);
}

View File

@@ -1,12 +1,20 @@
package com.yexuejc.base.util; package com.yexuejc.base.util;
import java.text.ParseException; import java.time.DayOfWeek;
import java.time.*; import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters; import java.time.temporal.TemporalAdjusters;
import java.util.Date; import java.util.Date;
import com.yexuejc.base.constant.DateConsts;
/** /**
* 新版时间日期出来 工具 * 新版时间日期出来 工具
@@ -15,10 +23,6 @@ import java.util.Date;
* @date: 2018/3/27 10:44 * @date: 2018/3/27 10:44
*/ */
public class DateTimeUtil { public class DateTimeUtil {
public static String DATE_PATTERN = "yyyy-MM-dd";
public static String TIME_PATTERN = "HH:mm:ss";
public static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
public static String DATE_TIME_MS_PATTERN = "yyyy-MM-dd HH:mm:ss.SSS";
private DateTimeUtil() { private DateTimeUtil() {
} }
@@ -116,8 +120,8 @@ public class DateTimeUtil {
* @return * @return
*/ */
public static LocalDate getWeek4First(LocalDate date) { public static LocalDate getWeek4First(LocalDate date) {
TemporalAdjuster firstOfWeek = TemporalAdjusters.ofDateAdjuster(localDate -> TemporalAdjuster firstOfWeek = TemporalAdjusters.ofDateAdjuster(localDate -> localDate.minusDays(localDate.getDayOfWeek()
localDate.minusDays(localDate.getDayOfWeek().getValue() - DayOfWeek.MONDAY.getValue())); .getValue() - DayOfWeek.MONDAY.getValue()));
return date.with(firstOfWeek); return date.with(firstOfWeek);
} }
@@ -137,8 +141,9 @@ public class DateTimeUtil {
* @return * @return
*/ */
public static LocalDate getWeek4Last(LocalDate date) { public static LocalDate getWeek4Last(LocalDate date) {
TemporalAdjuster lastOfWeek = TemporalAdjusters.ofDateAdjuster(localDate -> TemporalAdjuster lastOfWeek =
localDate.plusDays(DayOfWeek.SUNDAY.getValue() - localDate.getDayOfWeek().getValue())); TemporalAdjusters.ofDateAdjuster(localDate -> localDate.plusDays(DayOfWeek.SUNDAY.getValue() - localDate.getDayOfWeek()
.getValue()));
return date.with(lastOfWeek); return date.with(lastOfWeek);
} }
@@ -163,7 +168,9 @@ public class DateTimeUtil {
*/ */
public static Date parseDate(LocalDate localDate) { public static Date parseDate(LocalDate localDate) {
ZoneId zone = ZoneId.systemDefault(); ZoneId zone = ZoneId.systemDefault();
Instant instant = localDate.atStartOfDay().atZone(zone).toInstant(); Instant instant = localDate.atStartOfDay()
.atZone(zone)
.toInstant();
return Date.from(instant); return Date.from(instant);
} }
@@ -200,7 +207,8 @@ public class DateTimeUtil {
public static Date parseDate(LocalDate localDate, LocalTime localTime) { public static Date parseDate(LocalDate localDate, LocalTime localTime) {
LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime); LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
ZoneId zone = ZoneId.systemDefault(); ZoneId zone = ZoneId.systemDefault();
Instant instant = localDateTime.atZone(zone).toInstant(); Instant instant = localDateTime.atZone(zone)
.toInstant();
return Date.from(instant); return Date.from(instant);
} }
@@ -213,7 +221,8 @@ public class DateTimeUtil {
public static ZonedDateTime parseZonedDateTime(Date date) { public static ZonedDateTime parseZonedDateTime(Date date) {
Instant instant = date.toInstant(); Instant instant = date.toInstant();
ZoneId zoneId = ZoneId.systemDefault(); ZoneId zoneId = ZoneId.systemDefault();
return instant.atZone(zoneId).withZoneSameInstant(zoneId); return instant.atZone(zoneId)
.withZoneSameInstant(zoneId);
} }
/** /**
@@ -225,7 +234,8 @@ public class DateTimeUtil {
public static LocalDateTime parseLocalDateTime(Date date) { public static LocalDateTime parseLocalDateTime(Date date) {
Instant instant = date.toInstant(); Instant instant = date.toInstant();
ZoneId zoneId = ZoneId.systemDefault(); ZoneId zoneId = ZoneId.systemDefault();
return instant.atZone(zoneId).toLocalDateTime(); return instant.atZone(zoneId)
.toLocalDateTime();
} }
/** /**
@@ -237,7 +247,8 @@ public class DateTimeUtil {
public static LocalDate parseLocalDate(Date date) { public static LocalDate parseLocalDate(Date date) {
Instant instant = date.toInstant(); Instant instant = date.toInstant();
ZoneId zoneId = ZoneId.systemDefault(); ZoneId zoneId = ZoneId.systemDefault();
return instant.atZone(zoneId).toLocalDate(); return instant.atZone(zoneId)
.toLocalDate();
} }
/** /**
@@ -304,7 +315,8 @@ public class DateTimeUtil {
* @return * @return
*/ */
public static LocalDateTime parserUTC(Long timestamp) { public static LocalDateTime parserUTC(Long timestamp) {
if (String.valueOf(timestamp).length() == 10) { if (String.valueOf(timestamp)
.length() == 10) {
timestamp = timestamp * 1000; timestamp = timestamp * 1000;
} }
return parseLocalDateTime13(timestamp, ZoneId.of("UTC")); return parseLocalDateTime13(timestamp, ZoneId.of("UTC"));
@@ -318,7 +330,8 @@ public class DateTimeUtil {
*/ */
public static long parseLong(LocalDateTime localDateTime) { public static long parseLong(LocalDateTime localDateTime) {
ZoneId zone = ZoneId.systemDefault(); ZoneId zone = ZoneId.systemDefault();
Instant instant = localDateTime.atZone(zone).toInstant(); Instant instant = localDateTime.atZone(zone)
.toInstant();
return instant.toEpochMilli(); return instant.toEpochMilli();
} }
@@ -330,7 +343,8 @@ public class DateTimeUtil {
*/ */
public static long parseLong(LocalDate localDate) { public static long parseLong(LocalDate localDate) {
ZoneId zone = ZoneId.systemDefault(); ZoneId zone = ZoneId.systemDefault();
Instant instant = localDate.atStartOfDay(zone).toInstant(); Instant instant = localDate.atStartOfDay(zone)
.toInstant();
return instant.toEpochMilli(); return instant.toEpochMilli();
} }
@@ -355,7 +369,7 @@ public class DateTimeUtil {
*/ */
public static String format(LocalDate dateTime, String pattern) { public static String format(LocalDate dateTime, String pattern) {
if (StrUtil.isEmpty(pattern)) { if (StrUtil.isEmpty(pattern)) {
pattern = DATE_PATTERN; pattern = DateConsts.DATE_PATTERN;
} }
DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern); DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
return df.format(dateTime); return df.format(dateTime);
@@ -381,7 +395,32 @@ public class DateTimeUtil {
*/ */
public static String format(LocalDateTime dateTime, String pattern) { public static String format(LocalDateTime dateTime, String pattern) {
if (StrUtil.isEmpty(pattern)) { if (StrUtil.isEmpty(pattern)) {
pattern = DATE_TIME_PATTERN; pattern = DateConsts.DATE_TIME_PATTERN;
}
DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
return df.format(dateTime);
}
/**
* 格式化时间 <br/>
* 格式 yyyy-MM-dd HH:mm:ss
*
* @param dateTime
* @return
*/
public static String format(OffsetDateTime dateTime) {
return format(dateTime, null);
}
/**
* 格式化时间
*
* @param dateTime
* @param pattern 格式 默认:yyyy-MM-dd HH:mm:ss
* @return
*/
public static String format(OffsetDateTime dateTime, String pattern) {
if (StrUtil.isEmpty(pattern)) {
pattern = DateConsts.DATE_TIME_PATTERN;
} }
DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern); DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
return df.format(dateTime); return df.format(dateTime);
@@ -425,7 +464,39 @@ public class DateTimeUtil {
currentZone = ZoneId.of(currentZoneId); currentZone = ZoneId.of(currentZoneId);
} }
ZoneId targetZone = ZoneId.of(targetZoneId); ZoneId targetZone = ZoneId.of(targetZoneId);
return date.atZone(currentZone).withZoneSameInstant(targetZone).toLocalDateTime(); return date.atZone(currentZone)
.withZoneSameInstant(targetZone)
.toLocalDateTime();
}
/**
* 获取 ISO8601 格式时间
*
* @return 2019-05-28T12:12:12+08:00
*/
public static String formatIso8601BySystemZone() {
return DateTimeUtil.format(OffsetDateTime.now(), DateConsts.ISO_8601_PATTERN);
}
/**
* 时间转换成ISO8601格式
*
* @param localDateTime 时间
* @return 2019-05-28T12:12:12+08:00
*/
public static String formatIso8601BySystemZone(LocalDateTime localDateTime) {
return DateTimeUtil.format(localDateTime, DateConsts.ISO_8601_PATTERN);
}
/**
* 时间转换成ISO8601格式
*
* @param timestamp 时间戳
* @param zoneId 时区
* @return 2019-05-28T12:12:12+08:00
*/
public static String formatIso8601(long timestamp, ZoneId zoneId) {
return DateTimeUtil.format(parseLocalDateTime13(timestamp, zoneId), DateConsts.ISO_8601_PATTERN);
} }

View File

@@ -37,7 +37,8 @@ public final class StrUtil {
return ((Optional<?>) obj).isEmpty(); return ((Optional<?>) obj).isEmpty();
} else if (obj instanceof CharSequence) { } else if (obj instanceof CharSequence) {
return ((CharSequence) obj).length() == 0; return ((CharSequence) obj).length() == 0;
} else if (obj.getClass().isArray()) { } else if (obj.getClass()
.isArray()) {
return Array.getLength(obj) == 0; return Array.getLength(obj) == 0;
} else if (obj instanceof Collection) { } else if (obj instanceof Collection) {
return ((Collection<?>) obj).isEmpty(); return ((Collection<?>) obj).isEmpty();
@@ -56,7 +57,9 @@ public final class StrUtil {
* @return * @return
*/ */
public static String genUUID() { public static String genUUID() {
return UUID.randomUUID().toString().replaceAll("-", ""); return UUID.randomUUID()
.toString()
.replaceAll("-", "");
} }
/** /**
@@ -91,7 +94,9 @@ public final class StrUtil {
* @return * @return
*/ */
public static String genNum() { public static String genNum() {
int hashCode = UUID.randomUUID().toString().hashCode(); int hashCode = UUID.randomUUID()
.toString()
.hashCode();
StringBuilder num = new StringBuilder(); StringBuilder num = new StringBuilder();
if (hashCode < 0) { if (hashCode < 0) {
hashCode = -hashCode; hashCode = -hashCode;
@@ -99,7 +104,8 @@ public final class StrUtil {
} else { } else {
num.append("1"); num.append("1");
} }
return num.append(String.format("%010d", hashCode)).substring(0, 8); return num.append(String.format("%010d", hashCode))
.substring(0, 8);
} }
/** /**
@@ -296,7 +302,10 @@ public final class StrUtil {
for (String key : keys) { for (String key : keys) {
Object value = sortedParams.get(key); Object value = sortedParams.get(key);
if (isNotEmpty(key) && isNotEmpty(value)) { if (isNotEmpty(key) && isNotEmpty(value)) {
content.append(index == 0 ? "" : "&").append(key).append("=").append(value); content.append(index == 0 ? "" : "&")
.append(key)
.append("=")
.append(value);
++index; ++index;
} }
} }
@@ -417,14 +426,17 @@ public final class StrUtil {
if (cause != null) { if (cause != null) {
StringBuilder msg = new StringBuilder(); StringBuilder msg = new StringBuilder();
if (isNotEmpty(cause.getMessage())) { if (isNotEmpty(cause.getMessage())) {
msg.append(cause.getMessage()).append(NEW_LINE); msg.append(cause.getMessage())
.append(NEW_LINE);
} }
String causedMsg = printStackTrace(cause, (eMessage) -> { String causedMsg = printStackTrace(cause, (eMessage) -> {
if (isNotEmpty(eMessage)) { if (isNotEmpty(eMessage)) {
msg.append(eMessage).append(NEW_LINE); msg.append(eMessage)
.append(NEW_LINE);
} }
}); });
return msg.append(causedMsg).toString(); return msg.append(causedMsg)
.toString();
} }
return ""; return "";
} }
@@ -444,21 +456,28 @@ public final class StrUtil {
private static String printStackTrace(Throwable cause, Consumer<String> consumer) { private static String printStackTrace(Throwable cause, Consumer<String> consumer) {
if (cause != null) { if (cause != null) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
String cClass = cause.getClass().getName(); String cClass = cause.getClass()
.getName();
String eMessage = cause.getMessage(); String eMessage = cause.getMessage();
StackTraceElement[] stackTrace = cause.getStackTrace(); StackTraceElement[] stackTrace = cause.getStackTrace();
Throwable caused = cause.getCause(); Throwable caused = cause.getCause();
while (caused != null) { while (caused != null) {
cClass = caused.getClass().getName(); cClass = caused.getClass()
.getName();
eMessage = caused.getMessage(); eMessage = caused.getMessage();
stackTrace = caused.getStackTrace(); stackTrace = caused.getStackTrace();
caused = caused.getCause(); caused = caused.getCause();
consumer.accept(eMessage); consumer.accept(eMessage);
} }
sb.append("Caused by: ").append(cClass).append(": ").append(eMessage).append(NEW_LINE); sb.append("Caused by: ")
.append(cClass)
.append(": ")
.append(eMessage)
.append(NEW_LINE);
for (StackTraceElement element : stackTrace) { for (StackTraceElement element : stackTrace) {
sb.append("\tat "); sb.append("\tat ");
sb.append(String.format(ERROR_MESSAGE_FORMAT, element.getClassName(), element.getMethodName(), element.getFileName(), element.getLineNumber())); sb.append(String.format(ERROR_MESSAGE_FORMAT, element.getClassName(), element.getMethodName(), element.getFileName(),
element.getLineNumber()));
sb.append(NEW_LINE); sb.append(NEW_LINE);
} }
return sb.toString(); return sb.toString();
@@ -539,13 +558,13 @@ public final class StrUtil {
* 国家代码二进制转国家代码 * 国家代码二进制转国家代码
* *
* @param countryCode 国家代码二进制转:010000000 * @param countryCode 国家代码二进制转:010000000
* <pre> * <pre>
* 1 0 1 0    1 1 1 1 1 <br> * 1 0 1 0    1 1 1 1 1 <br>
* 日本 韓国  泰国 新加坡 中国内陸 台湾  香港 澳门 其他 * 日本 韓国  泰国 新加坡 中国内陸 台湾  香港 澳门 其他
* <br> * <br>
* 右→左0位其他、1位中国澳门、2位中国香港、3位中国台湾、4位中国内陸、5位新加坡、6位泰国、7位韓国、8位日本 * 右→左0位其他、1位中国澳门、2位中国香港、3位中国台湾、4位中国内陸、5位新加坡、6位泰国、7位韓国、8位日本
* <br> 1在该国表示、0不表示该国 * <br> 1在该国表示、0不表示该国
* </pre> * </pre>
* @return JPN日本、KOR韓国、THA泰国、CHN中国内陸、SGP新加坡、TWN中国台湾、HKG中国香港、MAC中国澳门、999其他、不明 * @return JPN日本、KOR韓国、THA泰国、CHN中国内陸、SGP新加坡、TWN中国台湾、HKG中国香港、MAC中国澳门、999其他、不明
*/ */
public static String getCountryByCode(String countryCode) { public static String getCountryByCode(String countryCode) {
@@ -571,4 +590,23 @@ public final class StrUtil {
return false; return false;
} }
/**
* 将长字符串分割为多行
*
* @param str 原始字符串
* @param chunkSize 每行长度
* @return 分割后的字符串
*/
public static String chunkString(String str, int chunkSize) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < str.length(); i += chunkSize) {
int end = Math.min(str.length(), i + chunkSize);
builder.append(str, i, end);
if (end != str.length()) {
builder.append("\n");
}
}
return builder.toString();
}
} }