loadEncryptOptions(String provider, String
try {
return ENCRYPT_OPTIONS_CACHE.get(getCacheKey(provider, env, appKey, encryptAlg, serverRoot));
} catch (ExecutionException e) {
- throw new YopClientException("ConfigProblem, LoadEncryptOptions Fail, appKey:"
+ throw new IllegalConfigFormatException("yop_public_key", "ConfigProblem, LoadEncryptOptions Fail, appKey:"
+ appKey + ", encryptAlg:" + encryptAlg + ", ex:", e);
}
}
/**
* 刷新加密选项,并缓存(异步操作,不立即生效)
- *
+ *
* Loads a new value for key, possibly asynchronously.
* While the new value is loading the previous value (if any) will continue to be returned by get(key) unless it is evicted.
* If the new value is loaded successfully it will replace the previous value in the cache;
@@ -94,7 +97,7 @@ public static void refreshEncryptOptions(String appKey, String encryptAlg) {
/**
* 刷新加密选项,并缓存(异步操作,不立即生效)
- *
+ *
* Loads a new value for key, possibly asynchronously.
* While the new value is loading the previous value (if any) will continue to be returned by get(key) unless it is evicted.
* If the new value is loaded successfully it will replace the previous value in the cache;
@@ -112,7 +115,7 @@ public static void refreshEncryptOptions(String provider, String env, String app
try {
ENCRYPT_OPTIONS_CACHE.refresh(getCacheKey(provider, env, appKey, encryptAlg, serverRoot));
} catch (Exception e) {
- throw new YopClientException("ConfigProblem, RefreshEncryptOptions Fail, appKey:"
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "ConfigProblem, RefreshEncryptOptions Fail, appKey:"
+ appKey + ", encryptAlg:" + encryptAlg + ", ex:", e);
}
}
@@ -142,7 +145,7 @@ public static void invalidateEncryptOptions(String provider, String env, String
try {
ENCRYPT_OPTIONS_CACHE.invalidate(getCacheKey(provider, env, appKey, encryptAlg, serverRoot));
} catch (Exception e) {
- throw new YopClientException("ConfigProblem, InvalidateEncryptOptions Fail, appKey:"
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "ConfigProblem, InvalidateEncryptOptions Fail, appKey:"
+ appKey + ", encryptAlg:" + encryptAlg + ", ex:", e);
}
}
@@ -150,7 +153,7 @@ public static void invalidateEncryptOptions(String provider, String env, String
/**
* 失效并同步加载新的加密选项,并缓存
*
- * @param appKey 应用
+ * @param appKey 应用
* @param encryptAlg 加解密算法
* @return Future
*/
@@ -174,7 +177,7 @@ public static Future reloadEncryptOptions(String provider, Strin
try {
ENCRYPT_OPTIONS_CACHE.invalidate(getCacheKey(provider, env, appKey, encryptAlg, serverRoot));
} catch (Exception e) {
- throw new YopClientException("ConfigProblem, InvalidateEncryptOptions Fail, appKey:"
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "ConfigProblem, InvalidateEncryptOptions Fail, appKey:"
+ appKey + ", encryptAlg:" + encryptAlg + ", ex:", e);
}
return loadEncryptOptions(provider, env, appKey, encryptAlg, serverRoot);
@@ -201,9 +204,7 @@ public Future load(String cacheKey) throws Exception {
Future encryptOptions = null;
try {
String[] split = StringUtils.splitPreserveAllTokens(cacheKey, COMMA);
- String provider = split[0], env = split[1]
- ,appKey = split[2], encryptAlg = split[3]
- , serverRoot = split.length > 4 ? split[4]: null;
+ String provider = split[0], env = split[1], appKey = split[2], encryptAlg = split[3], serverRoot = split.length > 4 ? split[4] : null;
YopEncryptor encryptor = YopEncryptorFactory.getEncryptor(encryptAlg);
List enhancers = Collections.singletonList(getEnhancer(provider, env, appKey, encryptAlg, serverRoot));
encryptOptions = encryptor.initOptions(encryptAlg, enhancers);
@@ -226,7 +227,7 @@ private static EncryptOptionsEnhancer getEnhancer(String provider, String env,
case AES_ECB_PKCS5PADDING:
return new RsaEnhancer(provider, env, appKey);
default:
- throw new YopClientException("not supported encryptAlg:" + encryptAlg);
+ throw new IllegalParamFormatException("encryptAlg", "not supported encryptAlg:" + encryptAlg);
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/cache/YopCertificateCache.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/cache/YopCertificateCache.java
index fc36ddc7..851d618e 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/cache/YopCertificateCache.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/cache/YopCertificateCache.java
@@ -16,6 +16,7 @@
import com.yeepay.yop.sdk.config.enums.CertStoreType;
import com.yeepay.yop.sdk.config.provider.file.YopCertConfig;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
import com.yeepay.yop.sdk.model.cert.YopPlatformCertQueryResult;
import com.yeepay.yop.sdk.model.cert.YopPlatformPlainCert;
import com.yeepay.yop.sdk.security.CertTypeEnum;
@@ -101,7 +102,7 @@ private static X509Certificate loadRootCertFromLocal(String provider, String env
} catch (Exception e) {
LOGGER.error("error when load sm2 root cert, ex:", e);
}
- throw new YopClientException("Config Error, platform sm2 root cert not found, provider:"
+ throw new IllegalConfigFormatException(DEFAULT_CFCA_ROOT_FILE, "Config Error, platform sm2 root cert not found, provider:"
+ provider + ", env:" + env + ", appKey:" + appKey);
}
@@ -138,7 +139,7 @@ private static X509Certificate loadInterCertFromLocal(String provider, String en
} catch (Exception e) {
LOGGER.error("error when load sm2 inter certs, ex:", e);
}
- throw new YopClientException("Config Error, platform sm2 inter cert not found, provider:"
+ throw new IllegalConfigFormatException(DEFAULT_YOP_INTER_FILE, "Config Error, platform sm2 inter cert not found, provider:"
+ provider + ", env:" + env + ", appKey:" + appKey);
}
@@ -151,7 +152,7 @@ private static X509Certificate loadPlatformCertFromLocal(String provider, String
return cert;
}
}
- throw new YopClientException("Config Error, platform cert not found, provider:"
+ throw new IllegalConfigFormatException("yop_public_key|yop_cert_store", "Config Error, platform cert not found, provider:"
+ provider + ", env:" + env + ", appKey:" + appKey + ", certType:" + certType + ", certFile:" + certFile);
}
@@ -216,7 +217,7 @@ private static PublicKey loadPlatformRsaKeyFromLocal(String provider, String env
} catch (Exception e) {
LOGGER.warn("error when load yop rsa certs, ex:", e);
}
- throw new YopClientException("Config Error, platform rsa certs not found, provider:"
+ throw new IllegalConfigFormatException("yop_public_key", "Config Error, platform rsa certs not found, provider:"
+ provider + ", env:" + env + ", appKey:" + appKey + ", serialNo:" + serialNo);
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/config/provider/YopSdkConfigProviderRegistry.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/config/provider/YopSdkConfigProviderRegistry.java
index d31ab141..64202267 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/config/provider/YopSdkConfigProviderRegistry.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/config/provider/YopSdkConfigProviderRegistry.java
@@ -2,7 +2,9 @@
import com.yeepay.yop.sdk.base.config.provider.file.YopFileSdkConfigProvider;
import com.yeepay.yop.sdk.config.provider.YopSdkConfigProvider;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
+
+import static com.yeepay.yop.sdk.constants.ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY;
/**
* title: SDK 配置中心
@@ -27,7 +29,7 @@ public class YopSdkConfigProviderRegistry {
*/
public static void registerProvider(YopSdkConfigProvider provider) {
if (provider == null) {
- throw new YopClientException("SetUpProblem, Custom YopSdkConfigProvider IsNull.");
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "SetUpProblem, Custom YopSdkConfigProvider IsNull.");
}
customProvider = provider;
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/config/provider/file/YopFileSdkConfigProvider.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/config/provider/file/YopFileSdkConfigProvider.java
index efd8168a..770bb5f1 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/config/provider/file/YopFileSdkConfigProvider.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/config/provider/file/YopFileSdkConfigProvider.java
@@ -5,7 +5,7 @@
import com.yeepay.yop.sdk.base.config.provider.YopFixedSdkConfigProvider;
import com.yeepay.yop.sdk.config.YopSdkConfig;
import com.yeepay.yop.sdk.config.provider.file.YopFileSdkConfig;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
import com.yeepay.yop.sdk.utils.BeanUtils;
import com.yeepay.yop.sdk.utils.JsonUtils;
import com.yeepay.yop.sdk.utils.StreamUtils;
@@ -145,7 +145,7 @@ private YopFileSdkConfig doLoadYopFileSdkConfig(String provider, String currentE
}
if (null == customSdkConfig) {
- throw new YopClientException("ConfigProblem, Can't load config, file:" + configFile);
+ throw new IllegalConfigFormatException("yop_sdk_config_xxx.json", "ConfigProblem, Can't load config, file:" + configFile);
}
return customSdkConfig;
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/cert/X509CertSupportFactory.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/cert/X509CertSupportFactory.java
index b89e9447..e78bd8c2 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/cert/X509CertSupportFactory.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/cert/X509CertSupportFactory.java
@@ -5,11 +5,13 @@
package com.yeepay.yop.sdk.base.security.cert;
import com.google.common.collect.Maps;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import java.util.Map;
import java.util.ServiceLoader;
+import static com.yeepay.yop.sdk.constants.ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY;
+
/**
* title: x509证书支持类工厂
* description: 描述
@@ -46,7 +48,7 @@ public class X509CertSupportFactory {
public static X509CertSupport getSupport(String certType) {
final X509CertSupport x509CertSupport = X509_CERT_GENERATOR_MAP.get(certType);
if (null == x509CertSupport) {
- throw new YopClientException("ConfigProblem, X509CertSupport NotFound, certType:" + certType);
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "ConfigProblem, X509CertSupport NotFound, certType:" + certType);
}
return x509CertSupport;
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/cert/parser/AbstractYopPublicKeyParser.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/cert/parser/AbstractYopPublicKeyParser.java
index d2d7096b..06f3f843 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/cert/parser/AbstractYopPublicKeyParser.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/cert/parser/AbstractYopPublicKeyParser.java
@@ -6,6 +6,7 @@
import com.yeepay.yop.sdk.base.security.cert.X509CertSupportFactory;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
import com.yeepay.yop.sdk.security.CertTypeEnum;
import com.yeepay.yop.sdk.utils.FileUtils;
import com.yeepay.yop.sdk.utils.StreamUtils;
@@ -40,7 +41,7 @@ protected X509Certificate getX509Cert(String certPath, CertTypeEnum certType) th
try {
certStream = FileUtils.getResourceAsStream(certPath);
if (null == certStream) {
- throw new YopClientException("ConfigProblem, X509Cert NotFound, path:" + certPath + ", type:" + certType);
+ throw new IllegalConfigFormatException("yop_cert_store", "ConfigProblem, X509Cert NotFound, path:" + certPath + ", type:" + certType);
}
return X509CertSupportFactory.getSupport(certType.getValue()).generate(certStream);
} finally {
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/cert/parser/YopCertParserFactory.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/cert/parser/YopCertParserFactory.java
index 4884865c..29a077cd 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/cert/parser/YopCertParserFactory.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/cert/parser/YopCertParserFactory.java
@@ -5,15 +5,17 @@
package com.yeepay.yop.sdk.base.security.cert.parser;
import com.google.common.collect.Maps;
-import com.yeepay.yop.sdk.security.cert.YopCertCategory;
-import com.yeepay.yop.sdk.exception.YopClientException;
-import com.yeepay.yop.sdk.security.CertTypeEnum;
import com.yeepay.yop.sdk.constants.CharacterConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
+import com.yeepay.yop.sdk.security.CertTypeEnum;
+import com.yeepay.yop.sdk.security.cert.YopCertCategory;
import org.apache.commons.lang3.StringUtils;
import java.util.Map;
import java.util.ServiceLoader;
+import static com.yeepay.yop.sdk.constants.ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY;
+
/**
* title: 密钥解析器工厂类
* description: 描述
@@ -60,7 +62,7 @@ public static void registerParser(String parserId, YopCertParser certParser) {
public static YopCertParser getCertParser(String parserId) {
final YopCertParser yopCertParser = YOP_CERT_PARSER_MAP.get(parserId);
if (null == yopCertParser) {
- throw new YopClientException("ConfigProblem, YopCertParser NotFound, parserId:" + parserId);
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "ConfigProblem, YopCertParser NotFound, parserId:" + parserId);
}
return yopCertParser;
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/digest/YopDigesterFactory.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/digest/YopDigesterFactory.java
index a2849df3..4a04a408 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/digest/YopDigesterFactory.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/digest/YopDigesterFactory.java
@@ -5,12 +5,14 @@
package com.yeepay.yop.sdk.base.security.digest;
import com.google.common.collect.Maps;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import com.yeepay.yop.sdk.security.digest.YopDigester;
-import com.yeepay.yop.sdk.exception.YopClientException;
import java.util.Map;
import java.util.ServiceLoader;
+import static com.yeepay.yop.sdk.constants.ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY;
+
/**
* title: 摘要器工厂类
* description: 描述
@@ -58,7 +60,7 @@ public static void registerDigester(String alg, YopDigester digester) {
public static YopDigester getDigester(String alg) {
final YopDigester yopDigester = YOP_DIGESTER_MAP.get(alg);
if (null == yopDigester) {
- throw new YopClientException("ConfigProblem, YopDigester NotFound, alg:" + alg);
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "ConfigProblem, YopDigester NotFound, alg:" + alg);
}
return yopDigester;
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/AbstractEncryptOptionsEnhancer.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/AbstractEncryptOptionsEnhancer.java
index 9280517f..a37de25f 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/AbstractEncryptOptionsEnhancer.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/AbstractEncryptOptionsEnhancer.java
@@ -5,7 +5,7 @@
package com.yeepay.yop.sdk.base.security.encrypt;
import com.yeepay.yop.sdk.auth.credentials.YopSymmetricCredentials;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
import com.yeepay.yop.sdk.security.encrypt.EncryptOptions;
import com.yeepay.yop.sdk.security.encrypt.EncryptOptionsEnhancer;
@@ -23,7 +23,7 @@ public abstract class AbstractEncryptOptionsEnhancer implements EncryptOptionsEn
protected boolean checkForEnhance(EncryptOptions source) {
if (null == source.getCredentials()) {
- throw new YopClientException("ParamProblem, EncryptOptionsCredentials IsNull, value:" + source);
+ throw new IllegalConfigFormatException("yop_public_key", "ParamProblem, EncryptOptionsCredentials IsNull, value:" + source);
}
if (source.getCredentials() instanceof YopSymmetricCredentials) {
return true;
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/Sm2Enhancer.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/Sm2Enhancer.java
index dbf5ff28..174900f0 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/Sm2Enhancer.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/Sm2Enhancer.java
@@ -9,6 +9,7 @@
import com.yeepay.yop.sdk.auth.credentials.YopSymmetricCredentials;
import com.yeepay.yop.sdk.auth.credentials.provider.YopPlatformCredentialsProvider;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
import com.yeepay.yop.sdk.security.CertTypeEnum;
import com.yeepay.yop.sdk.security.encrypt.EncryptOptions;
import com.yeepay.yop.sdk.utils.Encodes;
@@ -84,7 +85,7 @@ public EncryptOptions enhance(EncryptOptions source) {
.getLatestCredentials(provider, env, appKey, CertTypeEnum.SM2.getValue(), serverRoot);
}
if (null == platformCredentials) {
- throw new YopClientException("ConfigProblem, YopPlatformCredentials NotFound to Enhance EncryptOptions, appKey:"
+ throw new IllegalConfigFormatException("yop_public_key", "ConfigProblem, YopPlatformCredentials NotFound to Enhance EncryptOptions, appKey:"
+ appKey + ", serialNo:" + serialNo);
}
source.setEncryptedCredentials(YopEncryptorFactory.getEncryptor(YOP_CREDENTIALS_ENCRYPT_ALG_SM2).encryptToBase64(credentialBytes,
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/Sm4Enhancer.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/Sm4Enhancer.java
index 9f003b89..d6a5de1d 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/Sm4Enhancer.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/Sm4Enhancer.java
@@ -7,7 +7,7 @@
import com.yeepay.yop.sdk.YopConstants;
import com.yeepay.yop.sdk.auth.credentials.YopSymmetricCredentials;
import com.yeepay.yop.sdk.config.provider.file.YopCertConfig;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
import com.yeepay.yop.sdk.security.encrypt.EncryptOptions;
import com.yeepay.yop.sdk.utils.ClientUtils;
import com.yeepay.yop.sdk.utils.Encodes;
@@ -53,7 +53,7 @@ public EncryptOptions enhance(EncryptOptions source) {
List mainKeys = ClientUtils.getCurrentCredentialsProvider()
.getIsvEncryptKey(provider, env, appKey);
if (CollectionUtils.isEmpty(mainKeys)) {
- throw new YopClientException("ConfigProblem, IsvEncryptKey NotFound, appKey:" + appKey);
+ throw new IllegalConfigFormatException("isv_encrypt_key", "ConfigProblem, IsvEncryptKey NotFound, appKey:" + appKey);
}
EncryptOptions mainKeyOptions = source.copy();
String mainCredential = mainKeys.get(0).getValue();
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/YopEncryptProtocol.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/YopEncryptProtocol.java
index 27d65a1f..ea7986b0 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/YopEncryptProtocol.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/YopEncryptProtocol.java
@@ -8,7 +8,8 @@
import com.yeepay.yop.sdk.YopConstants;
import com.yeepay.yop.sdk.auth.credentials.YopCredentials;
import com.yeepay.yop.sdk.auth.credentials.YopSymmetricCredentials;
-import com.yeepay.yop.sdk.exception.YopCallbackException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
+import com.yeepay.yop.sdk.http.Headers;
import com.yeepay.yop.sdk.security.encrypt.BigParamEncryptMode;
import com.yeepay.yop.sdk.security.encrypt.EncryptOptions;
import com.yeepay.yop.sdk.utils.Encodes;
@@ -87,7 +88,7 @@ public static Set parseEncryptItems(String itemStr, boolean base64) {
}
return Collections.emptySet();
} catch (UnsupportedEncodingException e) {
- throw new YopCallbackException("error when parse encrypt protocol, ex:", e);
+ throw new IllegalParamFormatException(Headers.YOP_ENCRYPT, "error when parse encrypt protocol, ex:", e);
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/YopEncryptorAdaptor.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/YopEncryptorAdaptor.java
index d4c4d922..ef9f3c33 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/YopEncryptorAdaptor.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/YopEncryptorAdaptor.java
@@ -7,7 +7,9 @@
import com.google.common.collect.Queues;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.yeepay.yop.sdk.YopConstants;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.constants.ExceptionConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
+import com.yeepay.yop.sdk.exception.YopUnknownException;
import com.yeepay.yop.sdk.security.encrypt.EncryptOptions;
import com.yeepay.yop.sdk.security.encrypt.EncryptOptionsEnhancer;
import com.yeepay.yop.sdk.security.encrypt.YopEncryptor;
@@ -25,6 +27,8 @@
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
+import static com.yeepay.yop.sdk.constants.ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY;
+
/**
* title: 加解密适配器
* description: 描述
@@ -69,8 +73,8 @@ public String encryptToBase64(String plain, EncryptOptions options) {
try {
return Encodes.encodeUrlSafeBase64(encrypt(plain.getBytes(YopConstants.DEFAULT_ENCODING), options));
} catch (UnsupportedEncodingException e) {
- throw new YopClientException("UnexpectedError, EncryptFail, value:"
- + plain + ",options:" + options + ",ex:", e);
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "UnexpectedError, EncryptFail, value:"
+ + plain + ",options:" + options + ", cause:" + e.getMessage(), e);
}
}
@@ -89,7 +93,7 @@ public String decryptToPlain(byte[] cipher, EncryptOptions options) {
try {
return new String(decrypt(cipher, options), YopConstants.DEFAULT_ENCODING);
} catch (UnsupportedEncodingException e) {
- throw new YopClientException("UnexpectedError, DecryptFail, options:" + options + ",ex:", e);
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "UnexpectedError, DecryptFail, options:" + options + ", cause:" + e.getMessage(), e);
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/YopEncryptorFactory.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/YopEncryptorFactory.java
index 132783ec..b465dbce 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/YopEncryptorFactory.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/base/security/encrypt/YopEncryptorFactory.java
@@ -5,13 +5,15 @@
package com.yeepay.yop.sdk.base.security.encrypt;
import com.google.common.collect.Maps;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import com.yeepay.yop.sdk.security.encrypt.YopEncryptor;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
+import static com.yeepay.yop.sdk.constants.ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY;
+
/**
* title: 加解密器工厂类
* description: 描述
@@ -80,7 +82,7 @@ public static void registerEncryptor(Map encryptors) {
public static YopEncryptor getEncryptor(String encryptAlg) {
final YopEncryptor yopEncryptor = YOP_ENCRYPTOR_MAP.get(encryptAlg);
if (null == yopEncryptor) {
- throw new YopClientException("ConfigProblem, YopEncryptor NotFound, encryptAlg:" + encryptAlg);
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "ConfigProblem, YopEncryptor NotFound, encryptAlg:" + encryptAlg);
}
return yopEncryptor;
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/client/ClientHandlerImpl.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/client/ClientHandlerImpl.java
index c8daafbb..520ed244 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/client/ClientHandlerImpl.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/client/ClientHandlerImpl.java
@@ -23,6 +23,8 @@
import com.yeepay.yop.sdk.config.provider.YopSdkConfigProvider;
import com.yeepay.yop.sdk.config.provider.file.YopCircuitBreakerConfig;
import com.yeepay.yop.sdk.exception.*;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.http.ExecutionContext;
import com.yeepay.yop.sdk.http.Headers;
import com.yeepay.yop.sdk.http.YopHttpClient;
@@ -40,6 +42,7 @@
import com.yeepay.yop.sdk.security.encrypt.YopEncryptor;
import com.yeepay.yop.sdk.sentinel.YopSph;
import com.yeepay.yop.sdk.utils.ClientUtils;
+import com.yeepay.yop.sdk.utils.YopTraceUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
@@ -194,7 +197,8 @@ public Output execute(R
invoker.addException(invoker.getExceptionAnalyzer().analyze(hostBlockException));
throw hostBlockException;
}
- throw new YopUnknownException("UnExpected Error, ", ex);
+ // ClientHandlerImpl.doExecute封装后,理论上不会到这里
+ throw new YopUnknownException("UnExpectedError, cause:" + ex.getMessage(), ex, request.getRequestId());
} finally {
if (null != uriResource && null != uriResource.getCallback()) {
uriResource.getCallback().notify(successInvoked);
@@ -230,9 +234,9 @@ private Output doExecut
} catch (YopHttpException httpException) {//HTTP调用异常
throwable = httpException;
throw httpException;
- } catch (Throwable ex) {// 非预期异常
+ } catch (Throwable ex) {// 非预期异常,com.yeepay.yop.sdk.http.YopHttpClient.execute包装后,理论上不会到这里
throwable = ex;
- throw new YopUnknownException("UnExpected Error, ", ex);
+ throw new YopUnknownException("UnExpectedError, cause:" + ex.getMessage(), ex, request.getRequestId());
} finally {
String result = "success";
if (null != throwable) {
@@ -267,17 +271,22 @@ public YopInvoker(ClientExecutionParams executionParams,
@Override
public Output invoke() {
- // 准备http参数
- Request request = getInput().getRequestMarshaller().marshall(getInput().getInput());
- request.setEndpoint(getUriResource().getResource());
- request.addHeader(Headers.YOP_SDK_SOURCE, sdkSource);
-
- // 发起http调用
- if (isCircuitBreakerEnable() && null != circuitBreaker && !BooleanUtils.isFalse(request.getOriginalRequestObject()
- .getRequestConfig().getEnableCircuitBreaker())) {
- return circuitBreaker.execute(request, this);
- } else {
- return doExecute(request, this);
+ try {
+ // 准备http参数
+ Request request = getInput().getRequestMarshaller().marshall(getInput().getInput());
+ YopTraceUtils.setCurrentRequestId(request.getRequestId());
+ request.setEndpoint(getUriResource().getResource());
+ request.addHeader(Headers.YOP_SDK_SOURCE, sdkSource);
+
+ // 发起http调用
+ if (isCircuitBreakerEnable() && null != circuitBreaker && !BooleanUtils.isFalse(request.getOriginalRequestObject()
+ .getRequestConfig().getEnableCircuitBreaker())) {
+ return circuitBreaker.execute(request, this);
+ } else {
+ return doExecute(request, this);
+ }
+ } finally {
+ YopTraceUtils.removeCurrentRequestId();
}
}
}
@@ -286,7 +295,7 @@ private ExecutionContex
ClientExecutionParams executionParams) {
AuthorizationReq authorizationReq = getAuthorizationReq(executionParams.getInput());
if (authorizationReq == null) {
- throw new YopClientException("no authenticate req defined");
+ throw new IllegalParamFormatException("AuthorizationReq", "no authenticate req defined");
} else {
YopRequestConfig requestConfig = executionParams.getInput().getRequestConfig();
YopCredentials> credential = getCredentials(provider, env, requestConfig, authorizationReq);
@@ -345,7 +354,7 @@ private AuthorizationReq computeSecurityReq(List availableCerts, L
return authorizationReq;
}
}
- throw new YopClientException("can not computeSecurityReq, please check your cert config");
+ throw new IllegalParamFormatException("AuthorizationReq", "can not computeSecurityReq, please check your cert config");
}
private List checkAuthReqsByApi(String operationId) {
@@ -360,7 +369,7 @@ private List checkAuthReqsByApi(String operationId) {
private AuthorizationReq checkCustomSecurityReq(String customSecurityReq) {
AuthorizationReq authorizationReq = AuthorizationReqSupport.getAuthorizationReq(customSecurityReq);
if (authorizationReq == null) {
- throw new YopClientException("unsupported customSecurityReq:" + customSecurityReq);
+ throw new IllegalParamFormatException("CustomAuthorizationReq", "unsupported customSecurityReq:" + customSecurityReq);
}
return authorizationReq;
}
@@ -368,7 +377,7 @@ private AuthorizationReq checkCustomSecurityReq(String customSecurityReq) {
private List checkAvailableCerts(String appKey, String provider, String env) {
List configPrivateCerts = yopCredentialsProvider.getSupportCertTypes(provider, env, appKey);
if (CollectionUtils.isEmpty(configPrivateCerts)) {
- throw new YopClientException("can not find private key for provider:"
+ throw new IllegalConfigFormatException("isv_private_key", "can not find private key for provider:"
+ provider + ",env:" + env + ",appKey:" + appKey);
}
return configPrivateCerts;
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/client/router/SimpleGateWayRouter.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/client/router/SimpleGateWayRouter.java
index 81e0857f..6afff963 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/client/router/SimpleGateWayRouter.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/client/router/SimpleGateWayRouter.java
@@ -9,7 +9,11 @@
import com.yeepay.yop.sdk.client.metric.report.host.YopHostStatusChangePayload;
import com.yeepay.yop.sdk.client.metric.report.host.YopHostStatusChangeReport;
import com.yeepay.yop.sdk.constants.CharacterConstants;
+import com.yeepay.yop.sdk.constants.ExceptionConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.internal.Request;
import com.yeepay.yop.sdk.invoke.model.UriResource;
import com.yeepay.yop.sdk.model.YopRequestConfig;
@@ -121,7 +125,7 @@ private boolean recordMainServer(URI serverRoot, ServerRootType serverRootType,
private boolean recordMainServer(URI serverRoot, ServerRootType serverRootType, Map mainServers, boolean force) {
if (null == serverRoot) {
- throw new YopClientException("Config Error, No ServerRoot Found, type:" + serverRootType);
+ throw new IllegalConfigFormatException("server_root", "Config Error, No ServerRoot Found, type:" + serverRootType);
}
final URI oldMain = mainServers.putIfAbsent(serverRootType, serverRoot);
if (LOGGER.isDebugEnabled()) {
@@ -210,7 +214,7 @@ public UriResource route(String appKey, Request> request, List excludeSer
if (StringUtils.isNotBlank(requestConfig.getServerRoot())) {
URI serverRoot = CheckUtils.checkServerRoot(requestConfig.getServerRoot());
if (isExcludeServerRoots(serverRoot, excludeServerRoots)) {
- throw new YopClientException("RequestConfig Error, serverRoot excluded:" + serverRoot);
+ throw new IllegalParamFormatException("serverRoot", "RequestConfig Error, serverRoot excluded:" + serverRoot);
}
collectServerRootType(space.getProvider(), space.getEnv(), serverRoot, serverRootType);
return new UriResource(serverRoot);
@@ -220,7 +224,7 @@ public UriResource route(String appKey, Request> request, List excludeSer
if (independentApiGroups.contains(apiGroup)) {
final URI independentServerRoot = independentServerRoot(apiGroup, request);
if (isExcludeServerRoots(independentServerRoot, excludeServerRoots)) {
- throw new YopClientException("Config Error, ServerRoot excluded:" + independentServerRoot);
+ throw new IllegalConfigFormatException("serverRoot", "Config Error, ServerRoot excluded:" + independentServerRoot);
}
return new UriResource(independentServerRoot);
}
@@ -228,7 +232,7 @@ public UriResource route(String appKey, Request> request, List excludeSer
// 主域名准备
URI mainServer = this.serverRootRouting.getMainServers().get(serverRootType);
if (null == mainServer) {
- throw new YopClientException("Config Error, Main ServerRoot NotFound" + serverRootType);
+ throw new IllegalConfigFormatException("server_root", "Config Error, Main ServerRoot NotFound" + serverRootType);
}
// 主域名正常
@@ -263,7 +267,7 @@ private URI independentServerRoot(String apiGroup, Request> request) {
getIndependentApiGroupHost(apiGroup, serverRoot.getHost(), request.isYosRequest()),
serverRoot.getPort(), serverRoot.getPath(), serverRoot.getQuery(), serverRoot.getFragment());
} catch (Exception ex) {
- throw new YopClientException("Route Request Failure, ex:", ex);
+ throw new IllegalParamFormatException("serverRoot", "Route Request Failure, ex:", ex);
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/AbstractYopHttpClient.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/AbstractYopHttpClient.java
index 144e1e85..53ded2a2 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/AbstractYopHttpClient.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/AbstractYopHttpClient.java
@@ -16,6 +16,8 @@
import com.yeepay.yop.sdk.exception.YopClientException;
import com.yeepay.yop.sdk.exception.YopHttpException;
import com.yeepay.yop.sdk.exception.YopServiceException;
+import com.yeepay.yop.sdk.exception.io.YopIOException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.internal.Request;
import com.yeepay.yop.sdk.model.BaseRequest;
import com.yeepay.yop.sdk.model.BaseResponse;
@@ -90,9 +92,9 @@ public Output execute(R
throw e;
} catch (Exception e) {
ex = e;
- throw new YopHttpException("Unable to execute HTTP request, requestId:"
+ throw new YopIOException("", e, "Unable to execute HTTP request, requestId:"
+ request.getRequestId() + ", apiUri:" + request.getResourcePath()
- + ", serverHost:" + request.getEndpoint(), e);
+ + ", serverHost:" + request.getEndpoint());
} finally {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Analyzed Response: {}, elapsed:{}ms", analyzedResponse,
@@ -267,7 +269,7 @@ private void signRequest(Request request, Exe
protected boolean checkForMultiPart(Request request) throws YopClientException {
boolean result = request.getMultiPartFiles() != null && request.getMultiPartFiles().size() > 0;
if (result && !HttpMethodName.POST.equals(request.getHttpMethod())) {
- throw new YopClientException("ReqParam Illegal, ContentType:multipart/form-data only support Post Request");
+ throw new IllegalParamFormatException("httpMethod", "ReqParam Illegal, ContentType:multipart/form-data only support Post Request");
}
return result;
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/AbstractYopHttpResponse.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/AbstractYopHttpResponse.java
index 1134f884..408b0b3a 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/AbstractYopHttpResponse.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/AbstractYopHttpResponse.java
@@ -6,7 +6,7 @@
import com.google.common.collect.Maps;
import com.yeepay.yop.sdk.YopConstants;
-import com.yeepay.yop.sdk.exception.YopHttpException;
+import com.yeepay.yop.sdk.exception.io.YopIOException;
import com.yeepay.yop.sdk.utils.DateUtils;
import com.yeepay.yop.sdk.utils.StreamUtils;
import org.apache.commons.io.IOUtils;
@@ -67,7 +67,8 @@ public String readContent() {
contentStr = IOUtils.toString(this.content, YopConstants.DEFAULT_ENCODING);
return contentStr;
} catch (IOException ex) {
- throw new YopHttpException("ResponseError, Read Content Fail, headers:" + this.headers + ", ex:", ex);
+ throw new YopIOException("ResponseError, Read Content Fail, headers:" + this.headers, ex,
+ YopIOException.IOExceptionEnum.UNKNOWN);
} finally {
StreamUtils.closeQuietly(this.content);
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/YopHttpClientFactory.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/YopHttpClientFactory.java
index c19393ab..7eeac367 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/YopHttpClientFactory.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/YopHttpClientFactory.java
@@ -5,7 +5,7 @@
import com.yeepay.yop.sdk.client.ClientConfiguration;
import com.yeepay.yop.sdk.client.support.ClientConfigurationSupport;
import com.yeepay.yop.sdk.config.provider.YopSdkConfigProvider;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import org.apache.commons.lang3.StringUtils;
import java.util.Map;
@@ -14,6 +14,7 @@
import static com.yeepay.yop.sdk.YopConstants.YOP_DEFAULT_ENV;
import static com.yeepay.yop.sdk.YopConstants.YOP_DEFAULT_PROVIDER;
import static com.yeepay.yop.sdk.constants.CharacterConstants.COLON;
+import static com.yeepay.yop.sdk.constants.ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY;
/**
* title: YopHttpClient工厂
@@ -37,7 +38,7 @@ public class YopHttpClientFactory {
httpClientProviderMap.put(yopHttpClientProvider.name(), yopHttpClientProvider);
}
if (httpClientProviderMap.isEmpty()) {
- throw new YopClientException("SetUpProblem,YopHttpClientProvider NotFound!");
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "SetUpProblem,YopHttpClientProvider NotFound!");
}
}
@@ -61,7 +62,7 @@ public static YopHttpClient getDefaultClient(String provider, String env, YopSdk
public static YopHttpClient getClient(ClientConfiguration clientConfig) {
final YopHttpClientProvider yopHttpClientProvider = httpClientProviderMap.get(clientConfig.getClientImpl());
if (null == yopHttpClientProvider) {
- throw new YopClientException("SetUpProblem, YopHttpClientProvider NotFound, name:" + clientConfig.getClientImpl());
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "SetUpProblem, YopHttpClientProvider NotFound, name:" + clientConfig.getClientImpl());
}
return yopHttpClientProvider.get(clientConfig);
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/analyzer/YopErrorResponseAnalyzer.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/analyzer/YopErrorResponseAnalyzer.java
index 0cc2b1b8..62baab32 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/analyzer/YopErrorResponseAnalyzer.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/analyzer/YopErrorResponseAnalyzer.java
@@ -1,7 +1,7 @@
package com.yeepay.yop.sdk.http.analyzer;
-import com.yeepay.yop.sdk.exception.YopHttpException;
import com.yeepay.yop.sdk.exception.YopServiceException;
+import com.yeepay.yop.sdk.exception.io.YopIOException;
import com.yeepay.yop.sdk.http.HttpResponseAnalyzer;
import com.yeepay.yop.sdk.http.HttpResponseHandleContext;
import com.yeepay.yop.sdk.http.HttpStatus;
@@ -9,11 +9,10 @@
import com.yeepay.yop.sdk.model.BaseResponse;
import com.yeepay.yop.sdk.model.YopErrorResponse;
import com.yeepay.yop.sdk.utils.JsonUtils;
+import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static com.yeepay.yop.sdk.constants.CharacterConstants.SLASH;
-
/**
* title:YopErrorResponseAnalyzer
* description: HTTP error response handler for YOP responses.
@@ -49,37 +48,53 @@ public boolean analysis(HttpResponseHandleContext conte
String resource = context.getOriginRequest().getEndpoint() + context.getOriginRequest().getResourcePath();
// 5xx
if (statusCode >= HttpStatus.SC_INTERNAL_SERVER_ERROR && statusCode != HttpStatus.SC_BAD_GATEWAY) {
- YopServiceException yse = null;
- String content = httpResponse.readContent();
- if (null != content) {
- YopErrorResponse yopErrorResponse = null;
- try {
- yopErrorResponse = JsonUtils.loadFrom(content, YopErrorResponse.class);
- } catch (Exception ex) {
- LOGGER.warn("Response Illegal, YopErrorResponse ParseFail, content:" + content, ex);
- }
- if (yopErrorResponse != null && yopErrorResponse.getMessage() != null) {
- yse = new YopServiceException(yopErrorResponse.getMessage());
- yse.setErrorCode(yopErrorResponse.getCode());
- yse.setSubErrorCode(yopErrorResponse.getSubCode());
- yse.setSubMessage(yopErrorResponse.getSubMessage());
- yse.setRequestId(yopErrorResponse.getRequestId());
- yse.setDocUrl(yopErrorResponse.getDocUrl());
- }
- }
- if (yse == null) {
- yse = new YopServiceException(httpResponse.getStatusText());
+ YopServiceException yse = buildServiceException(httpResponse.readContent(), httpResponse, resource);
+ if (StringUtils.isBlank(yse.getRequestId())) {
yse.setRequestId(response.getMetadata().getYopRequestId());
}
- yse.setStatusCode(httpResponse.getStatusCode());
yse.setErrorType(YopServiceException.ErrorType.Service);
throw yse;
} else if (statusCode == HttpStatus.SC_BAD_GATEWAY || statusCode == HttpStatus.SC_NOT_FOUND) {
- throw new YopHttpException("ResponseError, Unexpected Response, statusCode:" + statusCode + ", resource:" + resource);
+ throw new YopIOException("ResponseError, Unexpected Response, statusCode:" + statusCode
+ + ", resource:" + resource, YopIOException.IOExceptionEnum.UNKNOWN);
+ } else if (statusCode == 429){// 429
+ final YopServiceException invokeEx = buildServiceException(httpResponse.readContent(), httpResponse, resource);
+ invokeEx.setErrorType(YopServiceException.ErrorType.Client);
+ throw invokeEx;
} else {// 4xx
final YopServiceException invokeEx = new YopServiceException("ReqParam Illegal, Bad Request, statusCode:" + statusCode + ", resource:" + resource);
+ invokeEx.setStatusCode(statusCode);
invokeEx.setErrorType(YopServiceException.ErrorType.Client);
throw invokeEx;
}
}
+
+ private YopServiceException buildServiceException(String content, YopHttpResponse httpResponse, String resource) {
+ YopServiceException yse = null;
+ if (null != content) {
+ YopErrorResponse yopErrorResponse = null;
+ try {
+ yopErrorResponse = JsonUtils.loadFrom(content, YopErrorResponse.class);
+ } catch (Exception ex) {
+ LOGGER.warn("Response Illegal, YopErrorResponse ParseFail, content:" + content, ex);
+ }
+ if (yopErrorResponse != null) {
+ if (StringUtils.isNotBlank(yopErrorResponse.getMessage())) {
+ yse = new YopServiceException(yopErrorResponse.getMessage());
+ } else {
+ yse = new YopServiceException(httpResponse.getStatusText() + "ResponseError, resource:" + resource);
+ }
+ yse.setErrorCode(yopErrorResponse.getCode());
+ yse.setSubErrorCode(yopErrorResponse.getSubCode());
+ yse.setSubMessage(yopErrorResponse.getSubMessage());
+ yse.setRequestId(yopErrorResponse.getRequestId());
+ yse.setDocUrl(yopErrorResponse.getDocUrl());
+ }
+ }
+ if (yse == null) {
+ yse = new YopServiceException(httpResponse.getStatusText() + "ResponseError, resource:" + resource);
+ }
+ yse.setStatusCode(httpResponse.getStatusCode());
+ return yse;
+ }
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/analyzer/YopJsonResponseAnalyzer.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/analyzer/YopJsonResponseAnalyzer.java
index d96fa858..efee9096 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/analyzer/YopJsonResponseAnalyzer.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/analyzer/YopJsonResponseAnalyzer.java
@@ -1,6 +1,6 @@
package com.yeepay.yop.sdk.http.analyzer;
-import com.yeepay.yop.sdk.exception.YopHttpException;
+import com.yeepay.yop.sdk.exception.io.YopIOException;
import com.yeepay.yop.sdk.http.HttpResponseAnalyzer;
import com.yeepay.yop.sdk.http.HttpResponseHandleContext;
import com.yeepay.yop.sdk.model.BaseResponse;
@@ -34,9 +34,10 @@ protected YopJsonResponseAnalyzer() {
public boolean analysis(HttpResponseHandleContext context, T response) throws Exception {
String content = context.getResponse().readContent();
if (!isJsonResponse(response.getMetadata().getContentType())) {
- throw new YopHttpException("ResponseError, Need Json, contentType:" + response.getMetadata().getContentType()
+ throw new YopIOException("ResponseError, Need Json, contentType:" + response.getMetadata().getContentType()
+ ", content:" + content + ", resource:"
- + context.getOriginRequest().getEndpoint() + SLASH + context.getOriginRequest().getResourcePath());
+ + context.getOriginRequest().getEndpoint() + SLASH + context.getOriginRequest().getResourcePath(),
+ YopIOException.IOExceptionEnum.UNKNOWN);
}
if (null != content) {
JsonUtils.load(content, response);
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/analyzer/YopSignatureCheckAnalyzer.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/analyzer/YopSignatureCheckAnalyzer.java
index 64f5d693..e5e2fda3 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/analyzer/YopSignatureCheckAnalyzer.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/http/analyzer/YopSignatureCheckAnalyzer.java
@@ -3,6 +3,7 @@
import com.yeepay.yop.sdk.auth.SignOptions;
import com.yeepay.yop.sdk.auth.credentials.YopPlatformCredentials;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
import com.yeepay.yop.sdk.http.HttpResponseAnalyzer;
import com.yeepay.yop.sdk.http.HttpResponseHandleContext;
import com.yeepay.yop.sdk.model.BaseResponse;
@@ -60,7 +61,7 @@ public boolean analysis(HttpResponseHandleContext conte
.withExpirationInSeconds(reqOptions.getExpirationInSeconds())
.withUrlSafe(!StringUtils.containsAny(metadata.getYopSign(), '+', '/', '=')));
} else {
- throw new YopClientException("ConfigProblem, YopPlatformCredentials NotFound, appKey:" + context.getAppKey() + ", serialNo:" + metadata.getYopCertSerialNo());
+ throw new IllegalConfigFormatException("yop_public_key", "ConfigProblem, YopPlatformCredentials NotFound, appKey:" + context.getAppKey() + ", serialNo:" + metadata.getYopCertSerialNo());
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("response sign verify success, requestId:{}, sign:{}", metadata.getYopRequestId(), metadata.getYopSign());
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/DefaultRequest.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/DefaultRequest.java
index f161cf0e..96781d39 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/DefaultRequest.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/DefaultRequest.java
@@ -3,7 +3,7 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yeepay.yop.sdk.constants.CharacterConstants;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.http.Headers;
import com.yeepay.yop.sdk.http.HttpMethodName;
import com.yeepay.yop.sdk.http.YopContentType;
@@ -267,7 +267,7 @@ public void addMultiPartFile(String name, File file) {
try {
files.add(new MultiPartFile(file));
} catch (Exception ex) {
- throw new YopClientException("ReqParam Illegal, FileParam, name:" + name + ", value:" + file, ex);
+ throw new IllegalParamFormatException(name, "ReqParam Illegal, FileParam, value:" + file, ex);
}
}
@@ -281,7 +281,7 @@ public void addMultiPartFile(String name, InputStream in) {
try {
files.add(new MultiPartFile(in));
} catch (Exception ex) {
- throw new YopClientException("ReqParam Illegal, InputStreamParam, name:" + name + ", ex:", ex);
+ throw new IllegalParamFormatException(name, "ReqParam Illegal, InputStreamParam, ex:", ex);
}
}
@@ -295,7 +295,7 @@ public void addMultiPartFile(String name, FileParam fileParam) {
try {
files.add(new MultiPartFile(fileParam.getFileExtName(), fileParam.getFileStream()));
} catch (Exception ex) {
- throw new YopClientException("ReqParam Illegal, InputStreamParam, name:" + name + ", ex:", ex);
+ throw new IllegalParamFormatException(name, "ReqParam Illegal, InputStreamParam, ex:", ex);
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RequestAnalyzer.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RequestAnalyzer.java
index db4ff7c2..2605b334 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RequestAnalyzer.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RequestAnalyzer.java
@@ -10,7 +10,8 @@
import com.yeepay.yop.sdk.auth.req.AuthorizationReq;
import com.yeepay.yop.sdk.base.cache.YopCredentialsCache;
import com.yeepay.yop.sdk.base.security.encrypt.YopEncryptorFactory;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.model.YopRequestConfig;
import com.yeepay.yop.sdk.security.CertTypeEnum;
import com.yeepay.yop.sdk.security.encrypt.YopEncryptor;
@@ -50,7 +51,7 @@ public static YopCredentials> getCredentials(String provider, String env, YopR
, authorizationReq.getCredentialType());
}
if (null == credential) {
- throw new YopClientException("No credentials specified");
+ throw new IllegalConfigFormatException("isv_private_key", "No credentials specified");
}
// 缓存最新调用凭证
YopCredentialsCache.put(provider, env, credential.getAppKey(), credential);
@@ -90,7 +91,7 @@ public static YopEncryptor getEncryptor(YopRequestConfig requestConfig) {
}
YopEncryptor encryptor = YopEncryptorFactory.getEncryptor(requestConfig.getEncryptAlg());
if (null == encryptor) {
- throw new YopClientException("not supported the encryptAlg: " + requestConfig.getEncryptAlg());
+ throw new IllegalParamFormatException("encryptAlg", "not supported the encryptAlg: " + requestConfig.getEncryptAlg());
}
return encryptor;
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RequestEncryptor.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RequestEncryptor.java
index 8daede30..6f51dd89 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RequestEncryptor.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RequestEncryptor.java
@@ -12,7 +12,10 @@
import com.yeepay.yop.sdk.YopConstants;
import com.yeepay.yop.sdk.base.cache.EncryptOptionsCache;
import com.yeepay.yop.sdk.base.security.encrypt.YopEncryptProtocol;
+import com.yeepay.yop.sdk.constants.ExceptionConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.http.Headers;
import com.yeepay.yop.sdk.http.YopContentType;
import com.yeepay.yop.sdk.model.BaseRequest;
@@ -202,7 +205,7 @@ private static void encryptContent(YopEncryptor encryptor, Set finalEncr
request.setContent(encryptor.encrypt(request.getContent(), encryptOptions));
finalEncryptParams.add(DOLLAR);
} else {
- throw new YopClientException("body content is not supported, contentType:" + request.getContentType());
+ throw new IllegalParamFormatException("contentType", "body content is not supported, contentType:" + request.getContentType());
}
}
@@ -246,7 +249,7 @@ private static byte[] encryptJsonParams(YopEncryptor encryptor, Set fina
LOGGER.debug("json request encrypted, source:{}, target:{}, options:{}", originJson, encryptedJson, encryptOptions);
return encryptedJson.getBytes(YopConstants.DEFAULT_ENCODING);
} catch (IOException e) {
- throw new YopClientException("error happened when encrypt json", e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY, "error happened when encrypt json", e);
}
}
@@ -260,7 +263,7 @@ private static void encryptMultiPartParams(YopEncryptor encryptor, Set f
encryptedValues.add(new MultiPartFile(
encryptor.encrypt(value.getInputStream(), encryptOptions), value.getFileName()));
} catch (IOException e) {
- throw new YopClientException("error happened when encrypt MultiPartFile", e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY, "error happened when encrypt MultiPartFile", e);
}
}
multiPartFiles.put(name, encryptedValues);
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RestartableFileInputStream.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RestartableFileInputStream.java
index ee2c3eaf..96408e2d 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RestartableFileInputStream.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RestartableFileInputStream.java
@@ -12,7 +12,7 @@
*/
package com.yeepay.yop.sdk.internal;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import java.io.File;
import java.io.FileInputStream;
@@ -42,7 +42,7 @@ public void restart() {
this.input.close();
this.input = new FileInputStream(this.file);
} catch (IOException e) {
- throw new YopClientException("Fail to restart.", e);
+ throw new IllegalParamFormatException(file.getName(), "Fail to restart.", e);
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RestartableNonResettableInputStream.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RestartableNonResettableInputStream.java
index c80839d9..a78c140a 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RestartableNonResettableInputStream.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RestartableNonResettableInputStream.java
@@ -14,6 +14,7 @@
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import java.io.IOException;
import java.io.InputStream;
@@ -46,7 +47,7 @@ public RestartableNonResettableInputStream(InputStream input, int bufferSize) {
try {
count = this.input.read(this.buffer, this.length, bufferSize - this.length);
} catch (IOException e) {
- throw new YopClientException("Fail to read data from input.", e);
+ throw new IllegalParamFormatException("InputStream", "Fail to read data from input.", e);
}
if (count < 0) {
this.eof = true;
@@ -59,7 +60,7 @@ public RestartableNonResettableInputStream(InputStream input, int bufferSize) {
@Override
public void restart() {
if (this.buffer == null) {
- throw new IllegalStateException("Fail to restart. Input buffer exhausted.");
+ throw new IllegalParamFormatException("InputStream", "Fail to restart. Input buffer exhausted.");
}
this.offset = 0;
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RestartableResettableInputStream.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RestartableResettableInputStream.java
index e9a42d12..caddbc52 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RestartableResettableInputStream.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/internal/RestartableResettableInputStream.java
@@ -13,7 +13,7 @@
package com.yeepay.yop.sdk.internal;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import java.io.IOException;
import java.io.InputStream;
@@ -38,7 +38,7 @@ public void restart() {
try {
this.input.reset();
} catch (IOException e) {
- throw new YopClientException("Fail to reset the underlying input stream.", e);
+ throw new IllegalParamFormatException("InputStream", "Fail to reset the underlying input stream.", e);
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/model/BaseRequest.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/model/BaseRequest.java
index c96166ed..3f52bf27 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/model/BaseRequest.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/model/BaseRequest.java
@@ -2,7 +2,7 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.collect.Maps;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.http.Headers;
import org.apache.commons.lang3.StringUtils;
@@ -71,13 +71,13 @@ public Map getHeaders() {
protected void validateParameter(String name, Object value) {
if (StringUtils.isEmpty(name)) {
- throw new YopClientException("ReqParam Illegal, ParamName IsEmpty, name:" + name + ",value:" + value);
+ throw new IllegalParamFormatException("EmptyField", "ReqParam Illegal, ParamName IsEmpty, name:" + name + ",value:" + value);
}
if (value == null) {
- throw new YopClientException("ReqParam Illegal, ParamValue IsNull, name:" + name);
+ throw new IllegalParamFormatException(name, "ReqParam Illegal, ParamValue IsNull" );
}
if (value instanceof File && !((File) value).exists()) {
- throw new YopClientException("ReqParam Illegal. FileParam NotExist, name:" + name + ", value:" + value);
+ throw new IllegalParamFormatException(name, "ReqParam Illegal. FileParam NotExist, value:" + value);
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/model/transform/AbstractYopRequestMarshaller.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/model/transform/AbstractYopRequestMarshaller.java
index a7e6cfc9..b0dcc607 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/model/transform/AbstractYopRequestMarshaller.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/model/transform/AbstractYopRequestMarshaller.java
@@ -2,7 +2,7 @@
import com.google.common.collect.Lists;
import com.yeepay.yop.sdk.YopConstants;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.http.Headers;
import com.yeepay.yop.sdk.http.HttpMethodName;
import com.yeepay.yop.sdk.http.YopContentType;
@@ -59,7 +59,7 @@ public Request marshall(YopRequest request) {
resetStreamIfNecessary(((FileParam) value).getFileStream());
internalRequest.addMultiPartFile(name, (FileParam) value);
} else {
- throw new YopClientException("ReqParam Illegal, FileParamType NotSupport, name:" + name + ", type:" + value.getClass() + ".");
+ throw new IllegalParamFormatException(name, "ReqParam Illegal, FileParamType NotSupport, type:" + value.getClass() + ".");
}
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/YopCallbackEngine.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/YopCallbackEngine.java
index faa104b9..7a443d03 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/YopCallbackEngine.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/YopCallbackEngine.java
@@ -16,6 +16,7 @@
import com.yeepay.yop.sdk.base.auth.signer.process.YopSignProcessorFactory;
import com.yeepay.yop.sdk.base.cache.EncryptOptionsCache;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.http.Headers;
import com.yeepay.yop.sdk.http.YopContentType;
import com.yeepay.yop.sdk.internal.Request;
@@ -71,7 +72,7 @@ public static YopCallbackRequest build(String provider, String env, YopRequest r
Request marshalled = YopCallbackRequestMarshaller.getInstance().marshall(request);
AuthorizationReq authorizationReq = AuthorizationReqSupport.getAuthorizationReq(request.getRequestConfig().getSecurityReq());
if (null == authorizationReq) {
- throw new YopClientException("no authenticate req defined");
+ throw new IllegalParamFormatException("YopRequestConfig.AuthorizationReq", "no authenticate req defined");
} else {
YopRequestConfig requestConfig = request.getRequestConfig();
YopCredentials> credential = getCredentials(provider, env, requestConfig, authorizationReq);
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/YopClientImpl.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/YopClientImpl.java
index 2a59d4cc..96dcc5e1 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/YopClientImpl.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/YopClientImpl.java
@@ -1,7 +1,7 @@
package com.yeepay.yop.sdk.service.common;
import com.yeepay.yop.sdk.client.*;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.http.HttpResponseAnalyzerSupport;
import com.yeepay.yop.sdk.http.HttpResponseHandler;
import com.yeepay.yop.sdk.http.handler.DefaultHttpResponseHandler;
@@ -33,7 +33,7 @@ public class YopClientImpl implements YopClient {
@Override
public YopResponse request(YopRequest request) {
if (request == null) {
- throw new YopClientException("request is required.");
+ throw new IllegalParamFormatException("request", "request is required");
}
RequestMarshaller requestMarshaller = YopRequestMarshaller.getInstance();
HttpResponseHandler responseHandler = new DefaultHttpResponseHandler(YopResponse.class,
@@ -47,7 +47,7 @@ public YopResponse request(YopRequest request) {
@Override
public YosDownloadResponse download(YopRequest request) {
if (request == null) {
- throw new YopClientException("request is required.");
+ throw new IllegalParamFormatException("request", "request is required");
}
RequestMarshaller requestMarshaller = YopRequestMarshaller.getInstance();
HttpResponseHandler responseHandler = new DefaultHttpResponseHandler(YosDownloadResponse.class,
@@ -61,10 +61,10 @@ public YosDownloadResponse download(YopRequest request) {
@Override
public YosUploadResponse upload(YopRequest request) {
if (request == null) {
- throw new YopClientException("request is required.");
+ throw new IllegalParamFormatException("request", "request is required");
}
if (request.getMultipartFiles().isEmpty() && request.getContent() == null) {
- throw new YopClientException("request.multiPartFiles and request.content both are empty.");
+ throw new IllegalParamFormatException("multiPartFiles|content", "request multiPartFiles or content is required");
}
RequestMarshaller requestMarshaller = YopRequestMarshaller.getInstance();
HttpResponseHandler responseHandler = new DefaultHttpResponseHandler(YosUploadResponse.class,
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/callback/handler/impl/YopWildCardCallbackHandler.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/callback/handler/impl/YopWildCardCallbackHandler.java
index cb88aacd..0651150d 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/callback/handler/impl/YopWildCardCallbackHandler.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/callback/handler/impl/YopWildCardCallbackHandler.java
@@ -1,6 +1,7 @@
package com.yeepay.yop.sdk.service.common.callback.handler.impl;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.constants.ExceptionConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import com.yeepay.yop.sdk.service.common.callback.YopCallback;
import com.yeepay.yop.sdk.service.common.callback.handler.YopCallbackHandler;
import org.slf4j.Logger;
@@ -30,7 +31,7 @@ public String getType() {
@Override
public void handle(YopCallback callback) {
LOGGER.warn("you need to handle the new yop callback, received: {}.", callback);
- throw new YopClientException("no YopCallbackHandler found");
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY, "no YopCallbackHandler found");
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/callback/protocol/YopCallbackProtocolFactory.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/callback/protocol/YopCallbackProtocolFactory.java
index db747015..19a67300 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/callback/protocol/YopCallbackProtocolFactory.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/callback/protocol/YopCallbackProtocolFactory.java
@@ -7,6 +7,7 @@
import com.google.common.collect.Maps;
import com.yeepay.yop.sdk.YopConstants;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.http.Headers;
import com.yeepay.yop.sdk.security.CertTypeEnum;
import com.yeepay.yop.sdk.service.common.callback.YopCallbackRequest;
@@ -62,7 +63,7 @@ private static YopCallbackProtocol deprecatedProtocol(YopCallbackRequest request
params = toParams(request.getParams());
break;
default:
- throw new YopClientException("unsupported content Type for YopCallback, type:" + request.getContentType());
+ throw new IllegalParamFormatException("contentType", "unsupported content Type for YopCallback, type:" + request.getContentType());
}
String appKey = params.get("customerIdentification");
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/callback/protocol/YopSm2CallbackProtocol.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/callback/protocol/YopSm2CallbackProtocol.java
index 2bf3df55..4fa72948 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/callback/protocol/YopSm2CallbackProtocol.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/callback/protocol/YopSm2CallbackProtocol.java
@@ -18,7 +18,7 @@
import com.yeepay.yop.sdk.base.security.encrypt.YopEncryptProtocol;
import com.yeepay.yop.sdk.base.security.encrypt.YopEncryptorFactory;
import com.yeepay.yop.sdk.constants.CharacterConstants;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.http.Headers;
import com.yeepay.yop.sdk.protocol.AuthenticateProtocolVersion;
import com.yeepay.yop.sdk.security.CertTypeEnum;
@@ -36,6 +36,7 @@
import java.util.*;
import static com.yeepay.yop.sdk.constants.CharacterConstants.*;
+import static com.yeepay.yop.sdk.http.Headers.YOP_ENCRYPT;
import static com.yeepay.yop.sdk.utils.HttpUtils.useEmptyAsCanonicalQueryString;
/**
@@ -160,7 +161,7 @@ private String decryptBizContent() {
templateOptions.setCredentialsAlg(certType.getValue());
YopEncryptProtocol.Inst parsedEncryptProtocol = parseEncryptProtocol(yopEncrypt, yopCredentials, templateOptions);
if (null == parsedEncryptProtocol) {
- throw new YopClientException("illegal YopSm2CallbackProtocol, request:" + originRequest);
+ throw new IllegalParamFormatException(YOP_ENCRYPT, "illegal YopSm2CallbackProtocol, request:" + originRequest);
}
if (LOGGER.isDebugEnabled()) {
@@ -199,10 +200,10 @@ private void initialize(YopCallbackRequest request) {
}
platformSerialNo = X509CertUtils.parseToHex(platformSerialNo);
platformServerRoot = request.getPlatformServerRoot();
- yopEncrypt = headers.get(Headers.YOP_ENCRYPT);
+ yopEncrypt = headers.get(YOP_ENCRYPT);
yopRequestId = headers.get(Headers.YOP_REQUEST_ID);
} catch (Exception e) {
- throw new YopClientException("error initialize YopSm2CallbackProtocol, ex:", e);
+ throw new IllegalParamFormatException("YopCallbackRequest", "error initialize YopSm2CallbackProtocol, ex:", e);
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/callback/protocol/YopSm4CallbackProtocol.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/callback/protocol/YopSm4CallbackProtocol.java
index 2fc64cff..d27a69e8 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/callback/protocol/YopSm4CallbackProtocol.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/callback/protocol/YopSm4CallbackProtocol.java
@@ -8,7 +8,8 @@
import com.yeepay.yop.sdk.auth.credentials.provider.YopCredentialsProviderRegistry;
import com.yeepay.yop.sdk.base.security.encrypt.YopEncryptorFactory;
import com.yeepay.yop.sdk.config.provider.file.YopCertConfig;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.security.CertTypeEnum;
import com.yeepay.yop.sdk.security.encrypt.BigParamEncryptMode;
import com.yeepay.yop.sdk.security.encrypt.EncryptOptions;
@@ -73,7 +74,7 @@ public YopCallback parse() {
final List isvEncryptKeys = YopCredentialsProviderRegistry.getProvider()
.getIsvEncryptKey(originRequest.getProvider(), originRequest.getEnv(), customerIdentification);
if (CollectionUtils.isEmpty(isvEncryptKeys)) {
- throw new YopClientException("no isvEncryptKeys found for appKey:" + customerIdentification);
+ throw new IllegalConfigFormatException("isv_encrypt_key", "no isvEncryptKeys found for appKey:" + customerIdentification);
}
for (YopCertConfig isvEncryptKey : isvEncryptKeys) {
@@ -91,7 +92,7 @@ public YopCallback parse() {
LOGGER.warn("fail to parse YopSm4CallbackProtocol with key:" + isvEncryptKey.getValue() + ", ex:", e);
}
}
- throw new YopClientException("fail to parse YopSm4CallbackProtocol, appKey:" + customerIdentification);
+ throw new IllegalParamFormatException("YopCallback", "fail to parse YopSm4CallbackProtocol, appKey:" + customerIdentification + ", cipherText:" + cipherText);
}
public String getAlgorithm() {
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/request/YopRequest.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/request/YopRequest.java
index 700460f2..1cdae3c1 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/request/YopRequest.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/request/YopRequest.java
@@ -3,6 +3,7 @@
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.internal.RestartableInputStream;
import com.yeepay.yop.sdk.model.BaseRequest;
import com.yeepay.yop.sdk.model.FileParam;
@@ -167,7 +168,7 @@ private InputStream restartStream(InputStream inputStream) {
baos.flush();
return RestartableInputStream.wrap(baos.toByteArray());
} catch (IOException e) {
- throw new YopClientException("ReqParam Illegal, InputStreamParam Cant Restart, ex:", e);
+ throw new IllegalParamFormatException("InputStream", "ReqParam Illegal, InputStreamParam Cant Restart, ex:", e);
}
}
@@ -185,7 +186,7 @@ public YopRequest addEncryptMultiPartFile(String name, InputStream inputStream,
public YopRequest setContent(String content) {
if (StringUtils.isEmpty(content)) {
- throw new YopClientException("ReqParam Illegal, RequestContent Is Empty");
+ throw new IllegalParamFormatException("content", "ReqParam Illegal, RequestContent Is Empty");
}
this.content = content;
return this;
@@ -207,7 +208,7 @@ public YopRequest setEncryptContent(String content, Set jsonPaths) {
public YopRequest setStream(InputStream inputStream) {
if (inputStream == null) {
- throw new YopClientException("ReqParam Illegal, InputStreamParam IsNull.");
+ throw new IllegalParamFormatException("InputStream", "ReqParam Illegal, InputStreamParam IsNull.");
}
this.content = restartStream(inputStream);
return this;
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/response/YopResponse.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/response/YopResponse.java
index af9ec2d3..25cc4001 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/response/YopResponse.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/response/YopResponse.java
@@ -4,6 +4,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.model.BaseResponse;
import com.yeepay.yop.sdk.utils.JsonUtils;
import com.yeepay.yop.sdk.utils.json.KeepAsRawStringDeserializer;
@@ -50,7 +51,7 @@ public void setStringResult(String stringResult) {
try {
this.result = JsonUtils.getObjectMapper().readValue(stringResult, Object.class);
} catch (IOException e) {
- throw new YopClientException("unable to deserialize stringResult:" + stringResult);
+ throw new IllegalParamFormatException("result", "unable to deserialize stringResult:" + stringResult);
}
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/response/YosUploadResponse.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/response/YosUploadResponse.java
index 413b7740..4197b596 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/response/YosUploadResponse.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/service/common/response/YosUploadResponse.java
@@ -4,6 +4,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.model.yos.BaseYosUploadResponse;
import com.yeepay.yop.sdk.utils.JsonUtils;
import com.yeepay.yop.sdk.utils.json.KeepAsRawStringDeserializer;
@@ -50,7 +51,7 @@ public void setStringResult(String stringResult) {
try {
this.result = JsonUtils.getObjectMapper().readValue(stringResult, Object.class);
} catch (IOException e) {
- throw new YopClientException("unable to deserialize stringResult:" + stringResult);
+ throw new IllegalParamFormatException("result", "unable to deserialize stringResult:" + stringResult);
}
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/CheckUtils.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/CheckUtils.java
index d3ad2d66..7cc458d8 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/CheckUtils.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/CheckUtils.java
@@ -4,6 +4,7 @@
import com.yeepay.yop.sdk.exception.YopClientException;
import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
import com.yeepay.yop.sdk.exception.config.MissingConfigException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import org.apache.commons.lang3.StringUtils;
import java.net.MalformedURLException;
@@ -65,7 +66,7 @@ public static void checkApiUri(String apiUri) {
if (StringUtils.isNotBlank(apiUri) && API_URI_PATTERN.matcher(apiUri).matches()) {
return;
}
- throw new YopClientException("ReqParam Illegal, ApiUri, value:" + apiUri);
+ throw new IllegalParamFormatException("apiUri", "ReqParam Illegal, ApiUri, value:" + apiUri);
}
/**
@@ -77,7 +78,7 @@ public static void checkCallbackUri(String callbackUri) {
if (StringUtils.isNotBlank(callbackUri)) {
return;
}
- throw new YopClientException("callbackUri is illegal, param:" + callbackUri);
+ throw new IllegalParamFormatException("callbackUri", "callbackUri is illegal, param:" + callbackUri);
}
/**
@@ -93,10 +94,10 @@ public static URI checkServerRoot(String serverRoot) {
try {
uri = new URI(serverRoot);
} catch (Exception e) {
- throw new YopClientException("request serverRoot is illegal, value:" + serverRoot);
+ throw new IllegalParamFormatException("serverRoot", "request serverRoot is illegal, value:" + serverRoot);
}
if (!StringUtils.equalsAny(uri.getScheme(), "http", "https")) {
- throw new YopClientException("unsupported request scheme, value:" + uri.getScheme());
+ throw new IllegalParamFormatException("httpScheme", "unsupported request scheme, value:" + uri.getScheme());
}
return uri;
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/DigitalEnvelopeUtils.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/DigitalEnvelopeUtils.java
index bbe2aaba..9262fb7b 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/DigitalEnvelopeUtils.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/DigitalEnvelopeUtils.java
@@ -15,6 +15,8 @@
import com.yeepay.yop.sdk.constants.CharacterConstants;
import com.yeepay.yop.sdk.exception.VerifySignFailedException;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.security.CertTypeEnum;
import com.yeepay.yop.sdk.security.DigestAlgEnum;
import com.yeepay.yop.sdk.security.SymmetricEncryptAlgEnum;
@@ -106,7 +108,7 @@ public static String decrypt(String cipherText, String appKey, PrivateKey privat
//分解参数
String[] args = cipherText.split("\\" + SEPARATOR);
if (args.length != 4) {
- throw new RuntimeException("source invalid : " + cipherText);
+ throw new IllegalParamFormatException("cipherText", "source invalid : " + cipherText);
}
String encryptedRandomKeyToBase64 = args[0];
String encryptedDataToBase64 = args[1];
@@ -138,7 +140,7 @@ public static String decrypt(String cipherText, String appKey, PrivateKey privat
final YopSignProcessor yopSignProcess = YopSignProcessorFactory.getSignProcessor(SIGNER_MAP.get(digestAlg));
boolean verifySign = yopSignProcess.verify(sourceData, signToBase64, platformCredentials.getCredential());
if (!verifySign) {
- throw new YopClientException("verifySign fail!");
+ throw new IllegalConfigFormatException("yop_public_key", "verifySign fail!");
}
//返回源数据
return sourceData;
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/Encodes.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/Encodes.java
index 77e6806a..caee6877 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/Encodes.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/Encodes.java
@@ -1,6 +1,6 @@
package com.yeepay.yop.sdk.utils;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
@@ -12,6 +12,8 @@
import java.net.URLEncoder;
import java.security.Key;
+import static com.yeepay.yop.sdk.constants.ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY;
+
/**
* title: 封装各种格式的编码解码工具类
* description:
@@ -57,7 +59,7 @@ public static byte[] decodeHex(String input) {
try {
return Hex.decodeHex(input.toCharArray());
} catch (DecoderException e) {
- throw new YopClientException("Decode Hex fails.", e);
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "Decode Hex fails, cause:" + e.getMessage(), e);
}
}
@@ -128,7 +130,7 @@ public static String urlEncode(String part) {
try {
return URLEncoder.encode(part, DEFAULT_URL_ENCODING);
} catch (UnsupportedEncodingException e) {
- throw new YopClientException("Url encode fails.", e);
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "Url encode fails, cause:" + e.getMessage(), e);
}
}
@@ -140,7 +142,7 @@ public static String urlDecode(String part) {
try {
return URLDecoder.decode(part, DEFAULT_URL_ENCODING);
} catch (UnsupportedEncodingException e) {
- throw new YopClientException("Url Decode fails.", e);
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "Url Decode fails, cause:" + e.getMessage(), e);
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/FileUtils.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/FileUtils.java
index b9708cdc..22e45143 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/FileUtils.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/FileUtils.java
@@ -2,7 +2,7 @@
import com.google.common.collect.Maps;
import com.yeepay.yop.sdk.constants.CharacterConstants;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import com.yeepay.yop.sdk.model.yos.YosDownloadInputStream;
import com.yeepay.yop.sdk.model.yos.YosDownloadResponse;
import org.apache.commons.io.IOUtils;
@@ -25,6 +25,7 @@
import java.nio.file.Files;
import static com.yeepay.yop.sdk.YopConstants.FILE_PROTOCOL_PREFIX;
+import static com.yeepay.yop.sdk.constants.ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY;
/**
* title:
@@ -174,7 +175,7 @@ public static File saveFile(YosDownloadResponse yosDownloadResponse) {
return tmpFile;
} catch (Throwable ex) {
LOGGER.error("fail to save file, response:" + yosDownloadResponse, ex);
- throw new YopClientException("fail to save file, response:" + yosDownloadResponse);
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "fail to save file, response:" + yosDownloadResponse);
} finally {
StreamUtils.closeQuietly(yosDownloadInputStream);
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/Holder.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/Holder.java
index 94507d7f..9c45a657 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/Holder.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/Holder.java
@@ -1,6 +1,6 @@
package com.yeepay.yop.sdk.utils;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -8,6 +8,8 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
+import static com.yeepay.yop.sdk.constants.ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY;
+
/**
* title: 单例holder
* description:
@@ -33,10 +35,10 @@ public V getValue() {
try {
return futureTask.get();
} catch (InterruptedException e) {
- throw new YopClientException("SystemError, ThreadInterrupted, ex:", e);
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "SystemError, ThreadInterrupted, ex:", e);
} catch (ExecutionException e) {
Throwable cause = e.getCause();
- throw new YopClientException("UnexpectedError, ex:", cause);
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, "UnexpectedError, ex:", cause);
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/HttpUtils.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/HttpUtils.java
index e188bc68..f5b68a19 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/HttpUtils.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/HttpUtils.java
@@ -6,7 +6,7 @@
import com.google.common.collect.Sets;
import com.yeepay.yop.sdk.YopConstants;
import com.yeepay.yop.sdk.constants.CharacterConstants;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.http.Headers;
import com.yeepay.yop.sdk.http.HttpMethodName;
import com.yeepay.yop.sdk.http.Protocol;
@@ -123,7 +123,7 @@ public static String normalize(String value) {
}
return builder.toString();
} catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e);
+ throw new IllegalParamFormatException("field", value + "encode fail", e);
}
}
@@ -253,7 +253,7 @@ public static URI appendUri(URI baseUri, String... pathComponents) {
try {
return new URI(builder.toString());
} catch (URISyntaxException e) {
- throw new RuntimeException("Unexpected error", e);
+ throw new IllegalParamFormatException("serverRoot|apiUri", "Unexpected error", e);
}
}
@@ -293,7 +293,7 @@ public static String encodeParameters(Request extends BaseRequest> request, Bo
try {
encodedNameValuePair.add(toNameValuePair(forSignature, paramName, paramValue));
} catch (UnsupportedEncodingException e) {
- throw new YopClientException("ReqParam Illegal, Charset NotSuppport, name:" + paramName + ",value:" + paramValue, e);
+ throw new IllegalParamFormatException(paramName, "ReqParam Illegal, Charset NotSuppport, name:" + paramName + ",value:" + paramValue, e);
}
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/JsonUtils.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/JsonUtils.java
index 586ac9c9..95cd63ec 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/JsonUtils.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/JsonUtils.java
@@ -17,7 +17,9 @@
import com.jayway.jsonpath.spi.json.JsonProvider;
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
import com.jayway.jsonpath.spi.mapper.MappingProvider;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.constants.ExceptionConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.utils.json.joda.DatetimeModule;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
@@ -89,7 +91,7 @@ public static String toJsonString(Object value) {
try {
return writer.writeValueAsString(value);
} catch (Exception e) {
- throw new IllegalStateException(e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY, "json", e);
}
}
@@ -104,7 +106,7 @@ public static T fromJsonString(String json, Class clazz) {
try {
return OBJECT_MAPPER.readValue(json, clazz);
} catch (Exception e) {
- throw new YopClientException("Unable to parse Json String.", e);
+ throw new IllegalParamFormatException("json", "Unable to parse Json String.", e);
}
}
@@ -119,10 +121,8 @@ public static JsonGenerator jsonGeneratorOf(Writer writer) throws IOException {
public static T loadFrom(File file, Class clazz) throws IOException {
try {
return OBJECT_MAPPER.readValue(file, clazz);
- } catch (IOException e) {
- throw e;
} catch (Exception e) {
- throw new IllegalStateException(e);
+ throw new IllegalParamFormatException(null != file ? file.getName() : "file", "Unable to load json file" ,e);
}
}
@@ -162,7 +162,7 @@ public static boolean isTotalEncrypt(Set jsonPaths) {
return true;
}
if (jsonPaths.size() > 1 && !CollectionUtils.intersection(jsonPaths, JSON_PATH_ROOT).isEmpty()) {
- throw new YopClientException("illegal json paths:" + jsonPaths);
+ throw new IllegalParamFormatException("jsonPath", "illegal json paths:" + jsonPaths);
}
return false;
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/YopSdkInitUtils.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/YopSdkInitUtils.java
index fafb2f69..3d831180 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/YopSdkInitUtils.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/YopSdkInitUtils.java
@@ -4,6 +4,10 @@
*/
package com.yeepay.yop.sdk.utils;
+import com.yeepay.yop.sdk.service.common.YopClientBuilder;
+import com.yeepay.yop.sdk.service.common.YopClientImpl;
+import com.yeepay.yop.sdk.service.common.request.YopRequest;
+import com.yeepay.yop.sdk.service.common.response.YopResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,4 +67,13 @@ private static void doLoadSpiClass(String spiClass) {
}
}
+ public static void main(String[] args) {
+ YopClientImpl yopClient = YopClientBuilder.builder().build();
+ final YopRequest yopRequest = new YopRequest("/rest/v2.0/yop/platform/certs", "GET");
+ yopRequest.getRequestConfig().setAppKey("您的国密appKey");
+ yopRequest.addParameter("certType", "SM2");
+ final YopResponse response = yopClient.request(yopRequest);
+ assert null != response;
+ }
+
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/YopSignUtils.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/YopSignUtils.java
index e0705127..b4e7bbbd 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/YopSignUtils.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/YopSignUtils.java
@@ -14,7 +14,10 @@
import com.yeepay.yop.sdk.auth.credentials.provider.YopPlatformCredentialsProviderRegistry;
import com.yeepay.yop.sdk.auth.signer.process.YopSignProcessor;
import com.yeepay.yop.sdk.base.auth.signer.process.YopSignProcessorFactory;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.constants.ExceptionConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.security.CertTypeEnum;
import org.apache.commons.lang3.StringUtils;
@@ -78,7 +81,7 @@ public static void verify(String data, String signature, String appKey, String s
if (null != yopPlatformCredentials) {
verify(data, signature, yopPlatformCredentials.getCredential());
} else {
- throw new YopClientException("can not load platform cert");
+ throw new IllegalConfigFormatException("yop_public_key", "can not load platform cert");
}
}
@@ -107,11 +110,12 @@ public static void verify(String data, String signature, CredentialsItem credent
validSignature(signature);
YopSignProcessor yopSignProcessor = YopSignProcessorFactory.getSignProcessor(credentialsItem.getCertType().name());
if (null == yopSignProcessor) {
- throw new YopClientException("unsupported certType");
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY, "unsupported certType");
}
String args[] = signature.split("\\$");
if (!yopSignProcessor.verify(data, args[0], credentialsItem)) {
- throw new YopClientException("verify fail!");
+ throw new IllegalParamFormatException("data", "verify fail!, data:" + data
+ + ", signature:" + signature + ", publicKey:" + credentialsItem);
}
}
@@ -145,7 +149,7 @@ public static String sign(String data, String certType, String appKey, String pr
public static String sign(String data, String certType, PrivateKey privateKey) {
YopSignProcessor yopSignProcessor = YopSignProcessorFactory.getSignProcessor(certType);
if (null == yopSignProcessor) {
- throw new YopClientException("unsupported certType");
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY, "unsupported certType:" + certType);
}
PKICredentialsItem pkiCredentialsItem = new PKICredentialsItem(privateKey, CertTypeEnum.parse(certType));
return yopSignProcessor.sign(data, pkiCredentialsItem) + SPLIT_CHAR + yopSignProcessor.getDigestAlg();
@@ -154,11 +158,11 @@ public static String sign(String data, String certType, PrivateKey privateKey) {
private static void validSignature(String signature) {
String args[] = signature.split("\\$");
if ((args.length != 2 && args.length != 4)) {
- throw new YopClientException("illegal signature");
+ throw new IllegalParamFormatException("signature", "illegal signature");
}
CertTypeEnum certType = digestAlgANdCertTypeMap.get(args[1]);
if (certType == null) {
- throw new YopClientException("illegal signature");
+ throw new IllegalParamFormatException("digestAlg", "illegal certType:" + args[1]);
}
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/json/JacksonJsonMarshaller.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/json/JacksonJsonMarshaller.java
index 5ac70d78..7e41c73a 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/json/JacksonJsonMarshaller.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/json/JacksonJsonMarshaller.java
@@ -6,12 +6,14 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
+import static com.yeepay.yop.sdk.constants.ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY;
+
/**
*
* 将响应对象流化成JSON。 {@link ObjectMapper}是线程安全的。
@@ -43,7 +45,7 @@ public static T unmarshal(String content, Class objectType) {
try {
return objectMapper.readValue(content, objectType);
} catch (IOException e) {
- throw new YopClientException(e.getMessage(), e);
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, e.getMessage(), e);
}
}
@@ -51,7 +53,7 @@ public static T unmarshal(InputStream content, Class objectType) {
try {
return objectMapper.readValue(content, objectType);
} catch (IOException e) {
- throw new YopClientException(e.getMessage(), e);
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, e.getMessage(), e);
}
}
@@ -59,7 +61,7 @@ public static void load(String content, Object obj) {
try {
objectMapper.readerForUpdating(obj).readValue(content);
} catch (IOException ex) {
- throw new YopClientException(ex.getMessage(), ex);
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, ex.getMessage(), ex);
}
}
@@ -67,7 +69,7 @@ public static String marshal(Object content) {
try {
return objectMapper.writeValueAsString(content);
} catch (JsonProcessingException e) {
- throw new YopClientException(e.getMessage(), e);
+ throw new YopClientBizException(SDK_CONFIG_RUNTIME_DEPENDENCY, e.getMessage(), e);
}
}
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/json/KeepAsRawStringDeserializer.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/json/KeepAsRawStringDeserializer.java
index c1b047cb..bb185477 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/json/KeepAsRawStringDeserializer.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/json/KeepAsRawStringDeserializer.java
@@ -4,6 +4,7 @@
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -53,7 +54,7 @@ private String getStringFromSource(Object sourceRef) {
if (sourceRef instanceof StringReader) {
return getStringViaReflection((StringReader) sourceRef);
}
- throw new IllegalArgumentException("source ref of json is not an instance of String/StringReader,can't use KeepAsRawStringDeserializer here!");
+ throw new IllegalParamFormatException("json", "source ref of json is not an instance of String/StringReader,can't use KeepAsRawStringDeserializer here!");
}
/**
diff --git a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/support/CashierSupport.java b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/support/CashierSupport.java
index b3bcaf4c..79fb4184 100644
--- a/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/support/CashierSupport.java
+++ b/yop-java-sdk-base/src/main/java/com/yeepay/yop/sdk/utils/support/CashierSupport.java
@@ -8,6 +8,7 @@
import com.google.common.collect.Maps;
import com.yeepay.yop.sdk.auth.credentials.PKICredentialsItem;
import com.yeepay.yop.sdk.base.auth.signer.process.YopSignProcessorFactory;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.security.CertTypeEnum;
import java.security.PrivateKey;
@@ -71,7 +72,8 @@ public static String getPayUrl(PrivateKey privateKey, String appKey, String merc
// 获取请求收银台的sign
private static String signature(String plainText, PrivateKey privateKey) {
CertTypeEnum certType = resolveCertType(privateKey);
- return YopSignProcessorFactory.getSignProcessor(certType.name()).sign(plainText, new PKICredentialsItem(privateKey, certType));
+ return YopSignProcessorFactory.getSignProcessor(certType.name()).sign(plainText, new PKICredentialsItem(privateKey, certType))
+ + "$" + digestAlgByCertType(certType);
}
private static CertTypeEnum resolveCertType(PrivateKey privateKey) {
@@ -81,7 +83,18 @@ private static CertTypeEnum resolveCertType(PrivateKey privateKey) {
case "EC":
return CertTypeEnum.SM2;
default:
- throw new RuntimeException("sign algorithm(" + privateKey.getAlgorithm() + ") not supported");
+ throw new IllegalParamFormatException("PrivateKey", "sign algorithm(" + privateKey.getAlgorithm() + ") not supported");
+ }
+ }
+
+ private static String digestAlgByCertType(CertTypeEnum certType) {
+ switch (certType) {
+ case RSA2048:
+ return "SHA256";
+ case SM2:
+ return "SM3";
+ default:
+ throw new RuntimeException("sign algorithm(" + certType + ") not supported");
}
}
diff --git a/yop-java-sdk-crypto-api/src/main/java/com/yeepay/yop/sdk/auth/credentials/PKICredentialsItem.java b/yop-java-sdk-crypto-api/src/main/java/com/yeepay/yop/sdk/auth/credentials/PKICredentialsItem.java
index 599b3242..85420ca3 100644
--- a/yop-java-sdk-crypto-api/src/main/java/com/yeepay/yop/sdk/auth/credentials/PKICredentialsItem.java
+++ b/yop-java-sdk-crypto-api/src/main/java/com/yeepay/yop/sdk/auth/credentials/PKICredentialsItem.java
@@ -8,6 +8,7 @@
import java.security.PrivateKey;
import java.security.PublicKey;
+import java.util.Base64;
/**
* title:
@@ -56,4 +57,8 @@ public CertTypeEnum getCertType() {
return certType;
}
+ @Override
+ public String toString() {
+ return null != publicKey ? "pubKey:" + Base64.getEncoder().encodeToString(publicKey.getEncoded()) : super.toString();
+ }
}
diff --git a/yop-java-sdk-crypto-api/src/main/java/com/yeepay/yop/sdk/auth/credentials/provider/YopCredentialsProviderRegistry.java b/yop-java-sdk-crypto-api/src/main/java/com/yeepay/yop/sdk/auth/credentials/provider/YopCredentialsProviderRegistry.java
index 617b1157..0cfb5c13 100644
--- a/yop-java-sdk-crypto-api/src/main/java/com/yeepay/yop/sdk/auth/credentials/provider/YopCredentialsProviderRegistry.java
+++ b/yop-java-sdk-crypto-api/src/main/java/com/yeepay/yop/sdk/auth/credentials/provider/YopCredentialsProviderRegistry.java
@@ -1,6 +1,7 @@
package com.yeepay.yop.sdk.auth.credentials.provider;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.constants.ExceptionConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import java.util.ServiceLoader;
@@ -27,7 +28,7 @@ public class YopCredentialsProviderRegistry {
public static void registerProvider(YopCredentialsProvider yopCredentialsProvider) {
if (yopCredentialsProvider == null) {
- throw new YopClientException("SetUpProblem, Custom YopCredentialsProvider IsNull.");
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY, "SetUpProblem, Custom YopCredentialsProvider IsNull.");
}
CUSTOM_PROVIDER = yopCredentialsProvider;
}
diff --git a/yop-java-sdk-crypto-api/src/main/java/com/yeepay/yop/sdk/auth/credentials/provider/YopPlatformCredentialsProviderRegistry.java b/yop-java-sdk-crypto-api/src/main/java/com/yeepay/yop/sdk/auth/credentials/provider/YopPlatformCredentialsProviderRegistry.java
index 09daf76a..54facde9 100644
--- a/yop-java-sdk-crypto-api/src/main/java/com/yeepay/yop/sdk/auth/credentials/provider/YopPlatformCredentialsProviderRegistry.java
+++ b/yop-java-sdk-crypto-api/src/main/java/com/yeepay/yop/sdk/auth/credentials/provider/YopPlatformCredentialsProviderRegistry.java
@@ -4,6 +4,8 @@
*/
package com.yeepay.yop.sdk.auth.credentials.provider;
+import com.yeepay.yop.sdk.constants.ExceptionConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import com.yeepay.yop.sdk.exception.YopClientException;
import java.util.ServiceLoader;
@@ -31,7 +33,7 @@ public class YopPlatformCredentialsProviderRegistry {
public static void registerProvider(YopPlatformCredentialsProvider yopCredentialsProvider) {
if (yopCredentialsProvider == null) {
- throw new YopClientException("SetUpProblem, Custom YopPlatformCredentialsProvider IsNull.");
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY, "SetUpProblem, Custom YopPlatformCredentialsProvider IsNull.");
}
CUSTOM_PROVIDER = yopCredentialsProvider;
}
diff --git a/yop-java-sdk-crypto-api/src/main/java/com/yeepay/yop/sdk/auth/signer/process/YopSignProcessor.java b/yop-java-sdk-crypto-api/src/main/java/com/yeepay/yop/sdk/auth/signer/process/YopSignProcessor.java
index 72aeaa50..d71e08b4 100644
--- a/yop-java-sdk-crypto-api/src/main/java/com/yeepay/yop/sdk/auth/signer/process/YopSignProcessor.java
+++ b/yop-java-sdk-crypto-api/src/main/java/com/yeepay/yop/sdk/auth/signer/process/YopSignProcessor.java
@@ -7,6 +7,7 @@
import com.yeepay.yop.sdk.auth.SignOptions;
import com.yeepay.yop.sdk.auth.credentials.CredentialsItem;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
/**
* title: YopSignProcessor
@@ -29,7 +30,7 @@ public interface YopSignProcessor {
*/
default String sign(String content, CredentialsItem credentialsItem) {
if (!isSupport(credentialsItem)) {
- throw new YopClientException("ConfigProblem, CredentialsItem Type NotSupport, type:" + credentialsItem.getClass().getSimpleName());
+ throw new IllegalParamFormatException("CredentialsItem", "ConfigProblem, CredentialsItem Type NotSupport, type:" + credentialsItem.getClass().getSimpleName());
}
return doSign(content, credentialsItem);
}
@@ -60,7 +61,7 @@ default boolean verify(String content, String signature, CredentialsItem credent
if (isSupport(credentialsItem)) {
return doVerify(content, signature, credentialsItem);
}
- throw new YopClientException("ConfigProblem, CredentialsItem Type NotSupport, type:" + credentialsItem.getClass().getSimpleName());
+ throw new IllegalParamFormatException("CredentialsItem", "ConfigProblem, CredentialsItem Type NotSupport, type:" + credentialsItem.getClass().getSimpleName());
}
default boolean doVerify(String content, String signature, CredentialsItem credentialsItem) {
diff --git a/yop-java-sdk-crypto-gm-base/src/main/java/com/yeepay/yop/sdk/gm/base/security/cert/parser/YopSm2PublicKeyParser.java b/yop-java-sdk-crypto-gm-base/src/main/java/com/yeepay/yop/sdk/gm/base/security/cert/parser/YopSm2PublicKeyParser.java
index 2ee57476..535b35ca 100644
--- a/yop-java-sdk-crypto-gm-base/src/main/java/com/yeepay/yop/sdk/gm/base/security/cert/parser/YopSm2PublicKeyParser.java
+++ b/yop-java-sdk-crypto-gm-base/src/main/java/com/yeepay/yop/sdk/gm/base/security/cert/parser/YopSm2PublicKeyParser.java
@@ -6,6 +6,7 @@
import com.yeepay.yop.sdk.config.provider.file.YopCertConfig;
import com.yeepay.yop.sdk.base.security.cert.parser.AbstractYopPublicKeyParser;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
import com.yeepay.yop.sdk.security.cert.YopCertCategory;
import com.yeepay.yop.sdk.base.security.cert.parser.YopCertParser;
import com.yeepay.yop.sdk.security.cert.YopPublicKey;
@@ -34,23 +35,25 @@ public class YopSm2PublicKeyParser extends AbstractYopPublicKeyParser implements
@Override
public YopPublicKey parse(YopCertConfig certConfig) {
if (null == certConfig.getStoreType()) {
- throw new YopClientException("ConfigProblem, YopPublicKey StoreType IsNull, certConfig:" + certConfig);
+ throw new IllegalConfigFormatException("store_type", "ConfigProblem, YopPublicKey StoreType IsNull, certConfig:" + certConfig);
}
switch (certConfig.getStoreType()) {
case STRING:
try {
return new YopPublicKey(SmUtils.string2PublicKey(certConfig.getValue()));
} catch (Exception ex) {
- throw new YopClientException("ConfigProblem, YopPublicKey Value Illegal, certConfig:" + certConfig, ex);
+ throw new IllegalConfigFormatException("value", "ConfigProblem, YopPublicKey Value Illegal, certConfig:"
+ + certConfig + ", cause:" + ex.getMessage(), ex);
}
case FILE_CER:
try {
return new YopPublicKey(getX509Cert(certConfig.getValue(), CertTypeEnum.SM2));
} catch (Exception e) {
- throw new YopClientException("ConfigProblem, YopPublicKey Value Illegal, certConfig:" + certConfig, e);
+ throw new IllegalConfigFormatException("value", "ConfigProblem, YopPublicKey Value Illegal, certConfig:"
+ + certConfig + ", cause" + e.getMessage(), e);
}
default:
- throw new YopClientException("ConfigProblem, YopPublicKey StoreType Illegal, certConfig:" + certConfig);
+ throw new IllegalConfigFormatException("store_type", "ConfigProblem, YopPublicKey StoreType Illegal, certConfig:" + certConfig);
}
}
diff --git a/yop-java-sdk-crypto-gm-base/src/main/java/com/yeepay/yop/sdk/gm/base/security/digest/YopSm3Digester.java b/yop-java-sdk-crypto-gm-base/src/main/java/com/yeepay/yop/sdk/gm/base/security/digest/YopSm3Digester.java
index 0a6b1e24..8982a610 100644
--- a/yop-java-sdk-crypto-gm-base/src/main/java/com/yeepay/yop/sdk/gm/base/security/digest/YopSm3Digester.java
+++ b/yop-java-sdk-crypto-gm-base/src/main/java/com/yeepay/yop/sdk/gm/base/security/digest/YopSm3Digester.java
@@ -5,7 +5,8 @@
package com.yeepay.yop.sdk.gm.base.security.digest;
import com.google.common.collect.Maps;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.constants.ExceptionConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import com.yeepay.yop.sdk.gm.base.utils.SmUtils;
import com.yeepay.yop.sdk.security.DigestAlgEnum;
import com.yeepay.yop.sdk.security.digest.YopDigester;
@@ -54,7 +55,8 @@ public byte[] digest(InputStream input, String alg) {
while (digestInputStream.read(buffer) > -1) {}
return digestInputStream.getMessageDigest().digest();
} catch (Exception e) {
- throw new YopClientException("UnexpectedError, MessageDigest Fail, alg:" + alg + ", ex:", e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "UnexpectedError, MessageDigest Fail, alg:" + alg + ", ex:", e);
}
}
diff --git a/yop-java-sdk-crypto-gm-base/src/main/java/com/yeepay/yop/sdk/gm/base/utils/SmUtils.java b/yop-java-sdk-crypto-gm-base/src/main/java/com/yeepay/yop/sdk/gm/base/utils/SmUtils.java
index 52a7966c..5f7d7d3f 100644
--- a/yop-java-sdk-crypto-gm-base/src/main/java/com/yeepay/yop/sdk/gm/base/utils/SmUtils.java
+++ b/yop-java-sdk-crypto-gm-base/src/main/java/com/yeepay/yop/sdk/gm/base/utils/SmUtils.java
@@ -4,7 +4,7 @@
*/
package com.yeepay.yop.sdk.gm.base.utils;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
import com.yeepay.yop.sdk.utils.Encodes;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
@@ -62,7 +62,8 @@ public static PublicKey string2PublicKey(String pubKey) {
KeyFactory kf = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME);
return kf.generatePublic(eks);
} catch (Exception e) {
- throw new YopClientException("ConfigProblem, YopPublicKey Convert Fail, value:" + pubKey, e);
+ throw new IllegalConfigFormatException("yop_public_key", "ConfigProblem, YopPublicKey Convert Fail, value:"
+ + pubKey + ", cause:" + e.getMessage(), e);
}
}
diff --git a/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/security/cert/parser/YopSm2PrivateKeyParser.java b/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/security/cert/parser/YopSm2PrivateKeyParser.java
index b5da01b0..c6fcedc9 100644
--- a/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/security/cert/parser/YopSm2PrivateKeyParser.java
+++ b/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/security/cert/parser/YopSm2PrivateKeyParser.java
@@ -8,7 +8,7 @@
import com.yeepay.yop.sdk.base.security.cert.parser.YopCertParser;
import com.yeepay.yop.sdk.config.provider.file.YopCertConfig;
import com.yeepay.yop.sdk.constants.CharacterConstants;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
import com.yeepay.yop.sdk.gm.base.utils.SmUtils;
import com.yeepay.yop.sdk.gm.utils.Sm2Utils;
import com.yeepay.yop.sdk.security.CertTypeEnum;
@@ -40,23 +40,25 @@ public class YopSm2PrivateKeyParser extends AbstractYopPrivateKeyParser implemen
@Override
public PrivateKey parse(YopCertConfig certConfig) {
if (null == certConfig.getStoreType()) {
- throw new YopClientException("ConfigProblem, IsvPrivateKey StoreType IsNull, certConfig:" + certConfig);
+ throw new IllegalConfigFormatException("store_type", "ConfigProblem, IsvPrivateKey StoreType IsNull, certConfig:" + certConfig);
}
switch (certConfig.getStoreType()) {
case STRING:
try {
return Sm2Utils.string2PrivateKey(certConfig.getValue());
} catch (Exception ex) {
- throw new YopClientException("ConfigProblem, IsvPrivateKey Value Illegal, certConfig:" + certConfig, ex);
+ throw new IllegalConfigFormatException("value", "ConfigProblem, IsvPrivateKey Value Illegal, certConfig:"
+ + certConfig + ", cause:" + ex.getMessage(), ex);
}
case FILE_P12:
try {
return parsePrivateKey(certConfig.getPassword(), certConfig.getValue());
} catch (Exception ex) {
- throw new YopClientException("ConfigProblem, IsvPrivateKey Password Illegal, certConfig:" + certConfig, ex);
+ throw new IllegalConfigFormatException("value", "ConfigProblem, IsvPrivateKey Password Illegal, certConfig:"
+ + certConfig + ", cause:" + ex.getMessage(), ex);
}
default:
- throw new YopClientException("ConfigProblem, IsvPrivateKey StoreType NotSupport, certConfig:" + certConfig);
+ throw new IllegalConfigFormatException("store_type", "ConfigProblem, IsvPrivateKey StoreType NotSupport, certConfig:" + certConfig);
}
}
diff --git a/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/security/encrypt/YopSm2Encryptor.java b/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/security/encrypt/YopSm2Encryptor.java
index fef9e72b..60ba9508 100644
--- a/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/security/encrypt/YopSm2Encryptor.java
+++ b/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/security/encrypt/YopSm2Encryptor.java
@@ -8,7 +8,8 @@
import com.yeepay.yop.sdk.auth.credentials.YopPKICredentials;
import com.yeepay.yop.sdk.auth.credentials.YopPlatformCredentials;
import com.yeepay.yop.sdk.base.security.encrypt.YopEncryptorAdaptor;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.constants.ExceptionConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import com.yeepay.yop.sdk.gm.base.utils.SmUtils;
import com.yeepay.yop.sdk.security.encrypt.EncryptOptions;
import org.bouncycastle.crypto.engines.SM2Engine;
@@ -75,7 +76,8 @@ public byte[] encrypt(byte[] plain, EncryptOptions options) {
engine.init(true, pwr);
return engine.processBlock(plain, 0, plain.length);
} catch (Throwable e) {
- throw new YopClientException("SystemError, Encrypt Fail, options:" + options, e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "SystemError, Encrypt Fail, options:" + options + ", cause:" + e.getMessage(), e);
}
}
@@ -94,7 +96,8 @@ public byte[] decrypt(byte[] cipher, EncryptOptions options) {
engine.init(false, priKeyParameters);
return engine.processBlock(cipher, 0, cipher.length);
} catch (Throwable e) {
- throw new YopClientException("SystemError, Decrypt Fail, options:" + options, e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "SystemError, Decrypt Fail, options:" + options + ", cause:" + e.getMessage(), e);
}
}
diff --git a/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/security/encrypt/YopSm4Encryptor.java b/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/security/encrypt/YopSm4Encryptor.java
index c815ce9e..31a87dc0 100644
--- a/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/security/encrypt/YopSm4Encryptor.java
+++ b/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/security/encrypt/YopSm4Encryptor.java
@@ -8,7 +8,9 @@
import com.yeepay.yop.sdk.YopConstants;
import com.yeepay.yop.sdk.auth.credentials.YopSymmetricCredentials;
import com.yeepay.yop.sdk.base.security.encrypt.YopEncryptorAdaptor;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.constants.ExceptionConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.gm.base.utils.SmUtils;
import com.yeepay.yop.sdk.gm.utils.Sm4Utils;
import com.yeepay.yop.sdk.security.encrypt.BigParamEncryptMode;
@@ -30,6 +32,7 @@
import java.util.Map;
import static com.yeepay.yop.sdk.YopConstants.SM4_CBC_PKCS5PADDING;
+import static com.yeepay.yop.sdk.YopConstants.SM4_ECB_PKCS5PADDING;
/**
* title: 对称加密器
@@ -61,9 +64,10 @@ protected Map initialValue() {
Map map = Maps.newHashMap();
try {
map.put(SM4_CBC_PKCS5PADDING, Cipher.getInstance(SM4_CBC_PKCS5PADDING, BouncyCastleProvider.PROVIDER_NAME));
+ map.put(SM4_ECB_PKCS5PADDING, Cipher.getInstance(SM4_ECB_PKCS5PADDING, BouncyCastleProvider.PROVIDER_NAME));
map.put(ALGORITHM_NAME_GCM_NOPADDING, Cipher.getInstance(ALGORITHM_NAME_GCM_NOPADDING, BouncyCastleProvider.PROVIDER_NAME));
} catch (Exception e) {
- throw new YopClientException("SystemError, YopSm4Encryptor InitFail, ex:", e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY, "SystemError, YopSm4Encryptor InitFail, ex:", e);
}
return map;
}
@@ -71,7 +75,7 @@ protected Map initialValue() {
@Override
public List supportedAlgs() {
- return Arrays.asList(SM4_CBC_PKCS5PADDING, ALGORITHM_NAME_GCM_NOPADDING);
+ return Arrays.asList(SM4_CBC_PKCS5PADDING, SM4_ECB_PKCS5PADDING, ALGORITHM_NAME_GCM_NOPADDING);
}
@Override
@@ -90,7 +94,8 @@ public byte[] encrypt(byte[] plain, EncryptOptions options) {
Cipher initializedCipher = getInitializedCipher(ENCRYPT_MODE, options);
return initializedCipher.doFinal(plain);
} catch (Throwable t) {
- throw new YopClientException("SystemError, Encrypt Fail, options:" + options + ", ex:", t);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "SystemError, Encrypt Fail, options:" + options + ", cause:" + t.getMessage(), t);
}
}
@@ -98,7 +103,8 @@ public byte[] encrypt(byte[] plain, EncryptOptions options) {
public InputStream encrypt(InputStream plain, EncryptOptions options) {
// TODO 支持chunked加密
if (BigParamEncryptMode.chunked.equals(options.getBigParamEncryptMode())) {
- throw new YopClientException("SystemError, Encrypt Chunked NotSupport, options:" + options);
+ throw new IllegalParamFormatException("BigParamEncryptMode",
+ "SystemError, Encrypt Chunked NotSupport, options:" + options);
}
return new CipherInputStream(plain, getInitializedCipher(ENCRYPT_MODE, options, false));
}
@@ -109,7 +115,8 @@ public byte[] decrypt(byte[] cipher, EncryptOptions options) {
Cipher initializedCipher = getInitializedCipher(DECRYPT_MODE, options);
return initializedCipher.doFinal(cipher);
} catch (Throwable t) {
- throw new YopClientException("SystemError, Decrypt Fail, options:" + options, t);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "SystemError, Decrypt Fail, options:" + options + ", cause:" + t.getMessage(), t);
}
}
@@ -117,7 +124,8 @@ public byte[] decrypt(byte[] cipher, EncryptOptions options) {
public InputStream decrypt(InputStream cipher, EncryptOptions options) {
// TODO 支持chunked加密
if (BigParamEncryptMode.chunked.equals(options.getBigParamEncryptMode())) {
- throw new YopClientException("SystemError, Encrypt Chunked NotSupport, options:" + options);
+ throw new IllegalParamFormatException("BigParamEncryptMode",
+ "SystemError, Encrypt Chunked NotSupport, options:" + options);
}
return new CipherInputStream(cipher, getInitializedCipher(DECRYPT_MODE, options, false));
}
@@ -151,7 +159,8 @@ private Cipher getInitializedCipher(int mode, EncryptOptions encryptOptions, boo
cipher.init(mode, sm4Key);
return cipher;
} catch (Throwable throwable) {
- throw new YopClientException("SystemError, InitCipher Fail, mode:" + mode +
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "SystemError, InitCipher Fail, mode:" + mode +
", options:" + encryptOptions + ", ex:", throwable);
}
}
diff --git a/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/utils/Sm2Utils.java b/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/utils/Sm2Utils.java
index 8294b06d..0416cf8e 100644
--- a/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/utils/Sm2Utils.java
+++ b/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/utils/Sm2Utils.java
@@ -6,7 +6,10 @@
import com.google.common.base.Charsets;
import com.yeepay.yop.sdk.auth.SignOptions;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.constants.ExceptionConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.gm.base.utils.SmUtils;
import com.yeepay.yop.sdk.utils.Encodes;
import org.bouncycastle.asn1.*;
@@ -73,7 +76,7 @@ public static KeyPair generateKeyPair() {
KeyPair kp = kpGen.generateKeyPair();
return kp;
} catch (Exception e) {
- throw new RuntimeException(e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY, "maybe missing bouncycastle jars", e);
}
}
@@ -93,7 +96,7 @@ public static PublicKey string2PublicKey(String pubKey) {
KeyFactory kf = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME);
return kf.generatePublic(eks);
} catch (Exception e) {
- throw new YopClientException("ConfigProblem, YopPublicKey Illegal, value:" + pubKey + ", ex:", e);
+ throw new IllegalConfigFormatException("yop_public_key", "ConfigProblem, YopPublicKey Illegal, value:" + pubKey + ", ex:", e);
}
}
@@ -113,7 +116,7 @@ public static PrivateKey string2PrivateKey(String priKey) {
KeyFactory kf = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME);
return kf.generatePrivate(peks);
} catch (Exception e) {
- throw new YopClientException("ConfigProblem, IsvPrivateKey Illegal, value:" + priKey + ", ex:" + e);
+ throw new IllegalConfigFormatException("isv_private_key", "ConfigProblem, IsvPrivateKey Illegal, value:" + priKey + ", ex:" + e);
}
}
@@ -155,7 +158,8 @@ public static String sign(String data, BCECPrivateKey priKey, SignOptions option
}
return Encodes.encodeUrlSafeBase64(sign(priKey, dataByte));
} catch (CryptoException e) {
- throw new YopClientException("UnexpectedError, Sign Fail, data:" + data + ", key:"
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "UnexpectedError, Sign Fail, data:" + data + ", key:"
+ priKey + ", options:" + options + ", ex:", e);
}
@@ -175,7 +179,26 @@ public static boolean verifySign(String data, String signature, BCECPublicKey pu
byte[] dataByte = data.getBytes(Charsets.UTF_8);
return verify(publicKey, dataByte, encodeSM2SignToDER(signByte));
} catch (IOException e) {
- throw new YopClientException("UnexpectedError, VerifySign Fail, data:" +
+ throw new IllegalParamFormatException("data|signature", "UnexpectedError, VerifySign Fail, data:" +
+ data + ", sign:" + signature + ", key:" + publicKey + ", ex:", e);
+ }
+ }
+
+ /**
+ * sm2密钥进行签名验证-withId
+ *
+ * @param data
+ * @param signature
+ * @param publicKey
+ * @return
+ */
+ public static boolean verifySignWithId(String data, String signature, BCECPublicKey publicKey, byte[] withId) {
+ try {
+ byte[] signByte = Encodes.decodeBase64(signature);
+ byte[] dataByte = data.getBytes(Charsets.UTF_8);
+ return verifyWithId(publicKey, dataByte, encodeSM2SignToDER(signByte), withId);
+ } catch (IOException e) {
+ throw new IllegalParamFormatException("data|signature", "UnexpectedError, VerifySign Fail, data:" +
data + ", sign:" + signature + ", key:" + publicKey + ", ex:", e);
}
}
@@ -232,6 +255,35 @@ public static byte[] sign(BCECPrivateKey priKey, byte[] srcData) throws CryptoEx
return rawSign;
}
+ /**
+ * 签名-withId
+ *
+ * @param priKey 私钥
+ * @param srcData 原文
+ * @return 64字节的纯R+S字节流
+ * @throws CryptoException
+ */
+ public static byte[] signWithId(BCECPrivateKey priKey, byte[] srcData, byte[] withId) throws CryptoException {
+ ECParameterSpec parameterSpec = priKey.getParameters();
+ ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
+ parameterSpec.getN(), parameterSpec.getH());
+ ECPrivateKeyParameters priKeyParameters = new ECPrivateKeyParameters(priKey.getD(), domainParameters);
+ //der编码后的签名值
+ byte[] derSign = sign(priKeyParameters, withId, srcData);
+
+ //der解码过程
+ ASN1Sequence as = DERSequence.getInstance(derSign);
+ byte[] rBytes = ((ASN1Integer) as.getObjectAt(0)).getValue().toByteArray();
+ byte[] sBytes = ((ASN1Integer) as.getObjectAt(1)).getValue().toByteArray();
+ //由于大数的补0规则,所以可能会出现33个字节的情况,要修正回32个字节
+ rBytes = fixToCurveLengthBytes(rBytes);
+ sBytes = fixToCurveLengthBytes(sBytes);
+ byte[] rawSign = new byte[rBytes.length + sBytes.length];
+ System.arraycopy(rBytes, 0, rawSign, 0, rBytes.length);
+ System.arraycopy(sBytes, 0, rawSign, rBytes.length, sBytes.length);
+ return rawSign;
+ }
+
/**
* 签名
*
@@ -272,6 +324,22 @@ public static boolean verify(BCECPublicKey pubKey, byte[] srcData, byte[] sign)
return verify(pubKeyParameters, null, srcData, sign);
}
+ /**
+ * 验签
+ *
+ * @param pubKey 公钥
+ * @param srcData 原文
+ * @param sign DER编码的签名值
+ * @return
+ */
+ public static boolean verifyWithId(BCECPublicKey pubKey, byte[] srcData, byte[] sign, byte[] withId) {
+ ECParameterSpec parameterSpec = pubKey.getParameters();
+ ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
+ parameterSpec.getN(), parameterSpec.getH());
+ ECPublicKeyParameters pubKeyParameters = new ECPublicKeyParameters(pubKey.getQ(), domainParameters);
+ return verify(pubKeyParameters, withId, srcData, sign);
+ }
+
/**
* 验签
*
diff --git a/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/utils/Sm4Utils.java b/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/utils/Sm4Utils.java
index 891d9c26..c2c35a55 100644
--- a/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/utils/Sm4Utils.java
+++ b/yop-java-sdk-crypto-gm/src/main/java/com/yeepay/yop/sdk/gm/utils/Sm4Utils.java
@@ -5,7 +5,8 @@
package com.yeepay.yop.sdk.gm.utils;
import com.google.common.base.Charsets;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.constants.ExceptionConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import com.yeepay.yop.sdk.gm.base.utils.SmUtils;
import com.yeepay.yop.sdk.utils.Encodes;
import org.apache.commons.lang3.StringUtils;
@@ -53,7 +54,8 @@ public static byte[] generateKey() {
try {
return generateKey(DEFAULT_KEY_SIZE);
} catch (Exception e) {
- throw new YopClientException("UnexpectedError, Generate Sm4Key Fail, ex:", e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "UnexpectedError, Generate Sm4Key Fail, ex:", e);
}
}
diff --git a/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/cert/parser/YopRsa2048PrivateKeyParser.java b/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/cert/parser/YopRsa2048PrivateKeyParser.java
index 000acb38..ed7a1286 100644
--- a/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/cert/parser/YopRsa2048PrivateKeyParser.java
+++ b/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/cert/parser/YopRsa2048PrivateKeyParser.java
@@ -8,7 +8,7 @@
import com.yeepay.yop.sdk.base.security.cert.parser.YopCertParser;
import com.yeepay.yop.sdk.config.provider.file.YopCertConfig;
import com.yeepay.yop.sdk.constants.CharacterConstants;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
import com.yeepay.yop.sdk.inter.utils.RSAKeyUtils;
import com.yeepay.yop.sdk.security.CertTypeEnum;
import com.yeepay.yop.sdk.security.cert.YopCertCategory;
@@ -33,23 +33,26 @@ public class YopRsa2048PrivateKeyParser extends AbstractYopPrivateKeyParser impl
@Override
public PrivateKey parse(YopCertConfig certConfig) {
if (null == certConfig.getStoreType()) {
- throw new YopClientException("ConfigProblem, IsvPrivateKey StoreType IsNull, certConfig:" + certConfig);
+ throw new IllegalConfigFormatException("store_type", "ConfigProblem, IsvPrivateKey StoreType IsNull, certConfig:" + certConfig);
}
switch (certConfig.getStoreType()) {
case STRING:
try {
return RSAKeyUtils.string2PrivateKey(certConfig.getValue());
} catch (Exception ex) {
- throw new YopClientException("ConfigProblem, IsvPrivateKey Parse Fail, certConfig:" + certConfig, ex);
+ throw new IllegalConfigFormatException("value",
+ "ConfigProblem, IsvPrivateKey Parse Fail, certConfig:"
+ + certConfig + ", cause:" + ex.getMessage(), ex);
}
case FILE_P12:
try {
return parsePrivateKey(certConfig.getPassword(), certConfig.getValue());
} catch (Exception ex) {
- throw new YopClientException("ConfigProblem, IsvPrivateKey Parse Fail, certConfig:" + certConfig, ex);
+ throw new IllegalConfigFormatException("value", "ConfigProblem, IsvPrivateKey Parse Fail, certConfig:"
+ + certConfig + ", cause:" + ex.getMessage(), ex);
}
default:
- throw new YopClientException("ConfigProblem, IsvPrivateKey StoreType NotSupport, certConfig:" + certConfig);
+ throw new IllegalConfigFormatException("store_type", "ConfigProblem, IsvPrivateKey StoreType NotSupport, certConfig:" + certConfig);
}
}
diff --git a/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/cert/parser/YopRsa2048PublicKeyParser.java b/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/cert/parser/YopRsa2048PublicKeyParser.java
index ee930719..be9d828e 100644
--- a/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/cert/parser/YopRsa2048PublicKeyParser.java
+++ b/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/cert/parser/YopRsa2048PublicKeyParser.java
@@ -9,6 +9,7 @@
import com.yeepay.yop.sdk.config.provider.file.YopCertConfig;
import com.yeepay.yop.sdk.constants.CharacterConstants;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
import com.yeepay.yop.sdk.inter.utils.RSAKeyUtils;
import com.yeepay.yop.sdk.security.CertTypeEnum;
import com.yeepay.yop.sdk.security.cert.YopCertCategory;
@@ -30,23 +31,24 @@ public class YopRsa2048PublicKeyParser extends AbstractYopPublicKeyParser implem
@Override
public YopPublicKey parse(YopCertConfig certConfig) {
if (null == certConfig.getStoreType()) {
- throw new YopClientException("ConfigProblem, YopPublicKey StoreType IsNull, certConfig:" + certConfig);
+ throw new IllegalConfigFormatException("store_type", "ConfigProblem, YopPublicKey StoreType IsNull, certConfig:" + certConfig);
}
switch (certConfig.getStoreType()) {
case STRING:
try {
return new YopPublicKey(RSAKeyUtils.string2PublicKey(certConfig.getValue()));
} catch (Exception ex) {
- throw new YopClientException("ConfigProblem, YopPublicKey Parse Fail, certConfig:" + certConfig + ", ex", ex);
+ throw new IllegalConfigFormatException("value", "ConfigProblem, YopPublicKey Value Illegal, certConfig:" + certConfig + ", cause:" + ex.getMessage(), ex);
}
case FILE_CER:
try {
return new YopPublicKey(getX509Cert(certConfig.getValue(), CertTypeEnum.RSA2048));
} catch (Exception e) {
- throw new YopClientException("ConfigProblem, YopPublicKey Parse Fail, certConfig:" + certConfig + ", ex", e);
+ throw new IllegalConfigFormatException("value", "ConfigProblem, YopPublicKey Value Illegal, certConfig:"
+ + certConfig + ", cause" + e.getMessage(), e);
}
default:
- throw new YopClientException("ConfigProblem, YopPublicKey StoreType NotSupport, certConfig:" + certConfig);
+ throw new IllegalConfigFormatException("store_type", "ConfigProblem, YopPublicKey StoreType Illegal, certConfig:" + certConfig);
}
}
diff --git a/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/digest/YopShaDigester.java b/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/digest/YopShaDigester.java
index 76d84972..91cd3cf8 100644
--- a/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/digest/YopShaDigester.java
+++ b/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/digest/YopShaDigester.java
@@ -6,9 +6,10 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
-import com.yeepay.yop.sdk.security.digest.YopDigester;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.constants.ExceptionConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import com.yeepay.yop.sdk.security.DigestAlgEnum;
+import com.yeepay.yop.sdk.security.digest.YopDigester;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -49,7 +50,8 @@ public byte[] digest(InputStream input, String alg) {
while (digestInputStream.read(buffer) > -1) {}
return digestInputStream.getMessageDigest().digest();
} catch (Exception e) {
- throw new YopClientException("SystemError, Digest Fail, alg:" + alg + ", ex:", e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "SystemError, Digest Fail, alg:" + alg + ", cause:" + e.getMessage(), e);
}
}
diff --git a/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/encrypt/YopAesEncryptor.java b/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/encrypt/YopAesEncryptor.java
index 4b4f6174..efc6a19b 100644
--- a/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/encrypt/YopAesEncryptor.java
+++ b/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/encrypt/YopAesEncryptor.java
@@ -5,7 +5,9 @@
import com.yeepay.yop.sdk.YopConstants;
import com.yeepay.yop.sdk.auth.credentials.YopSymmetricCredentials;
import com.yeepay.yop.sdk.base.security.encrypt.YopEncryptorAdaptor;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.constants.ExceptionConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.security.encrypt.BigParamEncryptMode;
import com.yeepay.yop.sdk.security.encrypt.EncryptOptions;
import com.yeepay.yop.sdk.utils.Encodes;
@@ -43,7 +45,8 @@ protected Map initialValue() {
map.put(AES_ECB_PKCS5PADDING, Cipher.getInstance(AES_ECB_PKCS5PADDING));
map.put(AES, Cipher.getInstance(AES));
} catch (Exception e) {
- throw new YopClientException("SystemError, InitCipher Fail, ex:", e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "SystemError, InitCipher Fail, cause:" + e.getMessage(), e);
}
return map;
}
@@ -79,7 +82,8 @@ public byte[] encrypt(byte[] plain, EncryptOptions options) {
Cipher initializedCipher = getInitializedCipher(Cipher.ENCRYPT_MODE, options);
return initializedCipher.doFinal(plain);
} catch (Throwable t) {
- throw new YopClientException("SystemError, Encrypt Fail, options:" + options + ", ex:", t);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "SystemError, Encrypt Fail, options:" + options + ", cause:" + t.getMessage(), t);
}
}
@@ -87,7 +91,8 @@ public byte[] encrypt(byte[] plain, EncryptOptions options) {
public InputStream encrypt(InputStream plain, EncryptOptions options) {
// TODO 支持chunked加密
if (BigParamEncryptMode.chunked.equals(options.getBigParamEncryptMode())) {
- throw new YopClientException("SystemError, Encrypt Chunked NotSupport, options:" + options);
+ throw new IllegalParamFormatException("BigParamEncryptMode",
+ "SystemError, Encrypt Chunked NotSupport, options:" + options);
}
return new CipherInputStream(plain, getInitializedCipher(Cipher.ENCRYPT_MODE, options, false));
}
@@ -98,7 +103,8 @@ public byte[] decrypt(byte[] cipher, EncryptOptions options) {
Cipher initializedCipher = getInitializedCipher(Cipher.DECRYPT_MODE, options);
return initializedCipher.doFinal(cipher);
} catch (Throwable t) {
- throw new YopClientException("SystemError, Decrypt Fail, options:" + options + ", ex:", t);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "SystemError, Decrypt Fail, options:" + options + ", cause:" + t.getMessage(), t);
}
}
@@ -106,7 +112,8 @@ public byte[] decrypt(byte[] cipher, EncryptOptions options) {
public InputStream decrypt(InputStream cipher, EncryptOptions options) {
// TODO 支持chunked加密
if (BigParamEncryptMode.chunked.equals(options.getBigParamEncryptMode())) {
- throw new YopClientException("SystemError, Decrypt Chunked NotSupport, options:" + options);
+ throw new IllegalParamFormatException("BigParamEncryptMode",
+ "SystemError, Decrypt Chunked NotSupport, options:" + options);
}
return new CipherInputStream(cipher, getInitializedCipher(Cipher.DECRYPT_MODE, options, false));
}
@@ -124,7 +131,8 @@ private Cipher getInitializedCipher(int mode, EncryptOptions encryptOptions, boo
cipher.init(mode, secretKey);
return cipher;
} catch (Throwable throwable) {
- throw new YopClientException("error happened when initialize cipher", throwable);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "error happened when initialize cipher, cause:" + throwable.getMessage(), throwable);
}
}
}
diff --git a/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/encrypt/YopRsaEncryptor.java b/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/encrypt/YopRsaEncryptor.java
index dc7b24da..acde2816 100644
--- a/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/encrypt/YopRsaEncryptor.java
+++ b/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/security/encrypt/YopRsaEncryptor.java
@@ -9,6 +9,8 @@
import com.yeepay.yop.sdk.auth.credentials.YopPKICredentials;
import com.yeepay.yop.sdk.auth.credentials.YopPlatformCredentials;
import com.yeepay.yop.sdk.base.security.encrypt.YopEncryptorAdaptor;
+import com.yeepay.yop.sdk.constants.ExceptionConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import com.yeepay.yop.sdk.exception.YopClientException;
import com.yeepay.yop.sdk.inter.utils.RSA;
import com.yeepay.yop.sdk.security.encrypt.EncryptOptions;
@@ -64,7 +66,8 @@ public byte[] encrypt(byte[] plain, EncryptOptions options) {
return RSA.encrypt(plain, ((PKICredentialsItem) ((YopPlatformCredentials)
options.getCredentials()).getCredential()).getPublicKey());
} catch (Throwable e) {
- throw new YopClientException("SystemError, Encrypt Fail, options:" + options + "ex:", e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "SystemError, Encrypt Fail, options:" + options + ", cause:" + e.getMessage(), e);
}
}
@@ -79,7 +82,8 @@ public byte[] decrypt(byte[] cipher, EncryptOptions options) {
try {
return RSA.decrypt(cipher, ((YopPKICredentials) options.getCredentials()).getCredential().getPrivateKey());
} catch (Throwable e) {
- throw new YopClientException("SystemError, Decrypt Fail, options:" + options + "ex:", e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "SystemError, Decrypt Fail, options:" + options + ", cause:" + e.getMessage(), e);
}
}
diff --git a/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/utils/RSA.java b/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/utils/RSA.java
index 9d79ddf2..9950246c 100644
--- a/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/utils/RSA.java
+++ b/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/utils/RSA.java
@@ -4,7 +4,9 @@
import com.google.common.collect.Maps;
import com.yeepay.yop.sdk.YopConstants;
import com.yeepay.yop.sdk.auth.SignOptions;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.constants.ExceptionConstants;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.security.DigestAlgEnum;
import com.yeepay.yop.sdk.utils.Encodes;
@@ -13,6 +15,7 @@
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
+import java.util.Base64;
import java.util.Map;
/**
@@ -49,7 +52,9 @@ public static boolean verifySign(byte[] data, byte[] sign, PublicKey publicKey,
signature.update(data);
return signature.verify(sign);
} catch (Exception e) {
- throw new YopClientException("SystemError, Sign Fail, key:" + publicKey + ", digestAlg" + digestAlg + "ex:", e);
+ throw new IllegalParamFormatException("YopPublicKey", "SystemError, Sign Fail, pubKey:"
+ + (null != publicKey ? Base64.getEncoder().encodeToString(publicKey.getEncoded()) : null)
+ + ", digestAlg" + digestAlg + ", cause:" + e.getMessage(), e);
}
}
@@ -83,7 +88,8 @@ public static byte[] sign(byte[] data, PrivateKey key, DigestAlgEnum digestAlg)
signature.update(data);
return signature.sign();
} catch (Exception e) {
- throw new YopClientException("SystemError, Sign Fail, key:" + key + ", digestAlg" + digestAlg + "ex:", e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "SystemError, Sign Fail, key:" + key + ", digestAlg" + digestAlg + ", cause:" + e.getMessage(), e);
}
}
@@ -130,7 +136,8 @@ public static byte[] encrypt(byte[] data, Key key) {
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data);
} catch (Exception e) {
- throw new YopClientException("SystemError, Encrypt Fail, key:" + key + "ex:", e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "SystemError, Encrypt Fail, key:" + key + ", cause:" + e.getMessage(), e);
}
}
@@ -145,7 +152,8 @@ public static String encryptToBase64(String data, Key key) {
try {
return Encodes.encodeUrlSafeBase64(encrypt(data.getBytes(Charsets.UTF_8), key));
} catch (Exception e) {
- throw new YopClientException("SystemError, Encrypt Fail, data:" + data + ", key:" + key + "ex:", e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "SystemError, Encrypt Fail, data:" + data + ", key:" + key + ", cause:" + e.getMessage(), e);
}
}
@@ -162,7 +170,8 @@ public static byte[] decrypt(byte[] data, Key key) {
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(data);
} catch (Exception e) {
- throw new YopClientException("SystemError, Decrypt Fail, key:" + key + "ex:", e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "SystemError, Decrypt Fail, key:" + key + ", cause:" + e.getMessage(), e);
}
}
@@ -177,7 +186,8 @@ public static String decryptFromBase64(String data, Key key) {
try {
return new String(decrypt(Encodes.decodeBase64(data), key), Charsets.UTF_8);
} catch (Exception e) {
- throw new YopClientException("SystemError, Decrypt Fail, data:" + data + ", key:" + key + "ex:", e);
+ throw new YopClientBizException(ExceptionConstants.SDK_CONFIG_RUNTIME_DEPENDENCY,
+ "SystemError, Decrypt Fail, data:" + data + ", key:" + key + ", cause:" + e.getMessage(), e);
}
}
}
diff --git a/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/utils/RSAKeyUtils.java b/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/utils/RSAKeyUtils.java
index ad3e54f6..f77e0155 100644
--- a/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/utils/RSAKeyUtils.java
+++ b/yop-java-sdk-crypto-inter/src/main/java/com/yeepay/yop/sdk/inter/utils/RSAKeyUtils.java
@@ -1,7 +1,7 @@
package com.yeepay.yop.sdk.inter.utils;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
import com.yeepay.yop.sdk.utils.Encodes;
import java.security.KeyFactory;
@@ -37,7 +37,8 @@ public static PublicKey string2PublicKey(String pubKey) {
return KeyFactory.getInstance(RSA).generatePublic(
new X509EncodedKeySpec(Encodes.decodeBase64(pubKey)));
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
- throw new YopClientException("ConfigProblem, YopPublicKey ParseFail, value:" + pubKey + ", ex:", e);
+ throw new IllegalConfigFormatException("yop_public_key",
+ "ConfigProblem, YopPublicKey ParseFail, value:" + pubKey + ", ex:", e);
}
}
@@ -52,7 +53,8 @@ public static PrivateKey string2PrivateKey(String priKey) {
return KeyFactory.getInstance(RSA).generatePrivate(
new PKCS8EncodedKeySpec(Encodes.decodeBase64(priKey)));
} catch (Exception e) {
- throw new YopClientException("ConfigProblem, IsvPrivateKey ParseFail, value:" + priKey + ", ex:", e);
+ throw new IllegalConfigFormatException("isv_private_key",
+ "ConfigProblem, IsvPrivateKey ParseFail, value:" + priKey + ", ex:", e);
}
}
diff --git a/yop-java-sdk-invoke-base/src/main/java/com/yeepay/yop/sdk/invoke/UriResourceRouteInvokerWrapper.java b/yop-java-sdk-invoke-base/src/main/java/com/yeepay/yop/sdk/invoke/UriResourceRouteInvokerWrapper.java
index 971154b2..4d7e65b2 100644
--- a/yop-java-sdk-invoke-base/src/main/java/com/yeepay/yop/sdk/invoke/UriResourceRouteInvokerWrapper.java
+++ b/yop-java-sdk-invoke-base/src/main/java/com/yeepay/yop/sdk/invoke/UriResourceRouteInvokerWrapper.java
@@ -5,7 +5,9 @@
package com.yeepay.yop.sdk.invoke;
import com.google.common.collect.Lists;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.YopTracedException;
import com.yeepay.yop.sdk.exception.YopUnknownException;
import com.yeepay.yop.sdk.invoke.model.AnalyzedException;
import com.yeepay.yop.sdk.invoke.model.RetryContext;
@@ -18,6 +20,8 @@
import java.net.URI;
import java.util.List;
+import static com.yeepay.yop.sdk.constants.ExceptionConstants.SDK_CONFIG_PARAM_FORMAT;
+
/**
* title: 基于UriResource路由的调用器实现
* description: 分析&封装异常、路由、重试等功能
@@ -69,7 +73,7 @@ public Output invoke() {
currentEx = throwable;
// 路由异常,客户端配置问题
if (null == lastServerRoot || null == lastServerRoot.getResource()) {
- throw new YopClientException("Config Error, No ServerRoot Found", throwable);
+ throw new YopClientBizException(SDK_CONFIG_PARAM_FORMAT, "No ServerRoot Found", throwable);
}
// 客户端异常、业务异常,直接抛给上层
@@ -110,7 +114,10 @@ private RuntimeException handleUnExpectedError(Throwable ex) {
if (ex instanceof YopUnknownException) {
return (YopUnknownException) ex;
}
- return new YopUnknownException("UnExpected Error, ", ex);
+ if (ex instanceof YopTracedException) {
+ throw (RuntimeException) ex;
+ }
+ return new YopUnknownException("UnExpectedError, cause:" + ex.getMessage(), ex, "");
}
@Override
diff --git a/yop-java-sdk-invoke-base/src/main/java/com/yeepay/yop/sdk/invoke/UriRouteInvokerWrapper.java b/yop-java-sdk-invoke-base/src/main/java/com/yeepay/yop/sdk/invoke/UriRouteInvokerWrapper.java
index 21c5ae3d..4af6fc39 100644
--- a/yop-java-sdk-invoke-base/src/main/java/com/yeepay/yop/sdk/invoke/UriRouteInvokerWrapper.java
+++ b/yop-java-sdk-invoke-base/src/main/java/com/yeepay/yop/sdk/invoke/UriRouteInvokerWrapper.java
@@ -5,7 +5,9 @@
package com.yeepay.yop.sdk.invoke;
import com.google.common.collect.Lists;
+import com.yeepay.yop.sdk.exception.YopClientBizException;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.YopTracedException;
import com.yeepay.yop.sdk.exception.YopUnknownException;
import com.yeepay.yop.sdk.invoke.model.AnalyzedException;
import com.yeepay.yop.sdk.invoke.model.RetryContext;
@@ -16,6 +18,8 @@
import java.net.URI;
import java.util.List;
+import static com.yeepay.yop.sdk.constants.ExceptionConstants.SDK_INVOKE_UNEXPECTED_EXCEPTION;
+
/**
* title: 基于uri路由的调用器实现
* description: 分析&封装异常、路由、重试等功能
@@ -70,6 +74,9 @@ public Output invoke() {
// 其他异常,须具体分析
final Exception analyzedEx = invoker.getLastException();
+ if (null == analyzedEx) {
+ handleUnExpectedError(throwable);
+ }
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Fail ServerRoot, {}, exDetail:{}, elapsed:{}", invoker.getUri(),
analyzedEx.getExDetail(), System.currentTimeMillis() - start);
@@ -93,7 +100,7 @@ public Output invoke() {
}
// 非预期的客户端异常
- throw new YopClientException("Client Error, ex:", throwable);
+ throw new YopClientBizException(SDK_INVOKE_UNEXPECTED_EXCEPTION, "Client Error", throwable);
}
}
@@ -111,7 +118,10 @@ private void handleUnExpectedError(Throwable ex) {
if (ex instanceof YopUnknownException) {
throw (YopUnknownException) ex;
}
- throw new YopUnknownException("UnExpected Error, ", ex);
+ if (ex instanceof YopTracedException) {
+ throw (RuntimeException) ex;
+ }
+ throw new YopUnknownException("UnExpectedError, cause:" + ex.getMessage(), ex, "");
}
@Override
diff --git a/yop-java-sdk-okhttp/src/main/java/com/yeepay/yop/sdk/http/impl/ok/YopHttpClient.java b/yop-java-sdk-okhttp/src/main/java/com/yeepay/yop/sdk/http/impl/ok/YopHttpClient.java
index f47c6356..b2efd124 100644
--- a/yop-java-sdk-okhttp/src/main/java/com/yeepay/yop/sdk/http/impl/ok/YopHttpClient.java
+++ b/yop-java-sdk-okhttp/src/main/java/com/yeepay/yop/sdk/http/impl/ok/YopHttpClient.java
@@ -7,6 +7,7 @@
import com.yeepay.yop.sdk.YopConstants;
import com.yeepay.yop.sdk.client.ClientConfiguration;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.http.AbstractYopHttpClient;
import com.yeepay.yop.sdk.http.Headers;
import com.yeepay.yop.sdk.http.YopHttpResponse;
@@ -182,7 +183,7 @@ private okhttp3.Request buildHttpRequest(Request
+
+ org.springframework
+ spring-context
+ test
+
junit
junit
@@ -44,6 +49,12 @@
jmh-generator-annprocess
test
+
+ cn.hutool
+ hutool-all
+ 5.1.5
+ test
+
\ No newline at end of file
diff --git a/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/config/provider/db/YopDbCredentialsProvider.java b/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/config/provider/db/YopDbCredentialsProvider.java
new file mode 100644
index 00000000..b1086d89
--- /dev/null
+++ b/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/config/provider/db/YopDbCredentialsProvider.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright: Copyright (c)2011
+ * Company: 易宝支付(YeePay)
+ */
+
+package com.yeepay.yop.sdk.config.provider.db;
+
+import com.yeepay.yop.sdk.auth.credentials.YopCredentials;
+import com.yeepay.yop.sdk.auth.credentials.provider.YopCredentialsProviderRegistry;
+import com.yeepay.yop.sdk.base.auth.credentials.provider.YopBaseCredentialsProvider;
+import com.yeepay.yop.sdk.base.config.YopAppConfig;
+import com.yeepay.yop.sdk.config.enums.CertStoreType;
+import com.yeepay.yop.sdk.config.provider.file.YopCertConfig;
+import com.yeepay.yop.sdk.security.CertTypeEnum;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.*;
+
+/**
+ * title: 示例:从数据库加载密钥配置
+ * description: 描述
+ * Copyright: Copyright (c)2014
+ * Company: 易宝支付(YeePay)
+ *
+ * @author wdc
+ * @version 1.0.0
+ * @since 2024/12/12
+ */
+@Component// 该注解依赖spring包, Maven坐标: org.springframework:spring-context:xxx
+public class YopDbCredentialsProvider extends YopBaseCredentialsProvider {
+
+ // 1、表结构简单设计
+ // |-------id--------|appKey-------|-----certType-----|-----certValue-----|
+ // | 1 |app_001|RSA2048|xxxxxxxxxx|
+ // | 2 |app_002|SM2|xxxxxxxxxx|
+
+ // 2、此处模拟数据库存储
+ Map mockDbStore = new HashMap<>();
+ {
+ mockDbStore.put("app_001", new String[]{"1", "app_001", "RSA2048", "app_001的密钥串xxxxxx"});
+ mockDbStore.put("app_002", new String[]{"2", "app_002", "SM2", "app_002的密钥串xxxxxx"});
+ }
+
+ // 3、借助spring 方式, 在provider构造好后,保证系统启动时注册该自定义provider为单例
+ @PostConstruct
+ public void init() {
+ YopCredentialsProviderRegistry.registerProvider(this);
+ }
+
+ // 4、指定默认的appKey,当请求时没指定appKey时,会使用该appKey
+ @Override
+ public String getDefaultAppKey() {
+ // 此处简单硬编码,可以根据自身情况指定
+ return "app_001";
+ }
+
+ // 5、模拟从数据库查询
+ private YopCertConfig mockFindCertConfigByAppKey(String appKey) {
+ YopCertConfig yopCertConfig = new YopCertConfig();
+ String[] dbRow = mockDbStore.get(appKey);
+ yopCertConfig.setStoreType(CertStoreType.STRING);
+ yopCertConfig.setCertType(CertTypeEnum.parse(dbRow[2]));
+ yopCertConfig.setValue(dbRow[3]);
+ return yopCertConfig;
+ }
+
+ // 6、实现根据appKey和certType,构造调用身份
+ @Override
+ public YopCredentials> getCredentials(String appKey, String credentialType) {
+ // 兼容默认appKey的场景
+ appKey = useDefaultIfBlank(appKey);
+
+ // 构造调用身份
+ YopAppConfig yopAppConfig = new YopAppConfig();
+ yopAppConfig.setAppKey(appKey);
+
+ // 从数据库加载密钥配置
+ YopCertConfig yopCertConfig = mockFindCertConfigByAppKey(appKey);
+
+ // 装载调用身份
+ List isvPrivateKeys = new LinkedList<>();
+ isvPrivateKeys.add(yopCertConfig);
+ yopAppConfig.setIsvPrivateKey(isvPrivateKeys);
+ return buildCredentials(yopAppConfig, credentialType);
+ }
+
+
+ // 7、实现支持的密钥类型,此处根据实际情况返回即可
+ @Override
+ public List getSupportCertTypes(String appKey) {
+ Set result = new HashSet<>();
+ // 从数据库加载支持的密钥类型列表
+ for (Map.Entry appCert : mockDbStore.entrySet()) {
+ result.add(CertTypeEnum.parse(appCert.getValue()[2]));
+ }
+ return new ArrayList<>(result);
+ }
+}
diff --git a/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/doc/ExampleTest.java b/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/doc/ExampleTest.java
index a3fcde0a..6b0fc034 100644
--- a/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/doc/ExampleTest.java
+++ b/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/doc/ExampleTest.java
@@ -17,10 +17,14 @@
import com.yeepay.yop.sdk.service.common.request.YopRequest;
import com.yeepay.yop.sdk.service.common.response.YopResponse;
import com.yeepay.yop.sdk.service.common.response.YosUploadResponse;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.exception.ExceptionUtils;
import org.junit.Ignore;
import org.junit.Test;
import java.security.PrivateKey;
+import java.util.Arrays;
+import java.util.stream.Collectors;
/**
* title:
@@ -84,13 +88,26 @@ appKey, new PKICredentialsItem(getPrivateKey(
"MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQg/WsUu5NQDTDJjjaXWLlNfBNZhamXAqCLcyLPSHDSD4qgCgYIKoEcz1UBgi2hRANCAAQUC8TdvSHnCXGlQzm62w+sqHK8wt/ZDXmuhyU4qOEJ8jRMiTzQWoX8BC0fB7ggzWIobHrJouBgnEm3AxVhShpZ",
CertTypeEnum.SM2)
, CertTypeEnum.SM2)));
- request.addParameter("parentMerchantNo", "1234321");
- request.addParameter("orderId", "1234321");
- request.addParameter("orderAmount", "100.05");
- request.addParameter("notifyUrl", "https://xxx.com/notify");
+ try {
+ request.addParameter("parentMerchantNo", "1234321");
+ request.addParameter("orderId", "1234321");
+ request.addParameter("orderAmount", "100.05");
+ request.addParameter("notifyUrl", "https://xxx.com/notify");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
assertTheRequest(yopClient, request);
}
+ @Test
+ public void testCaused() {
+ try {
+ throw new RuntimeException("1", new RuntimeException("2", new RuntimeException("3")));
+ } catch (RuntimeException e) {
+ System.out.println(Arrays.stream(ExceptionUtils.getThrowables(e)).map(t -> t.getClass().getCanonicalName() + ":" + t.getMessage()).collect(Collectors.joining(",")));
+ }
+ }
+
@Test
public void singleUpload() {
System.setProperty("yop.sdk.http", "true");//2021-12-08T11:59:16Z,d48782ac-93c1-466e-b417-f7a71e4965f0
diff --git a/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/encryptor/auth/credentials/provider/MockEncryptorCredentialsProvider.java b/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/encryptor/auth/credentials/provider/MockEncryptorCredentialsProvider.java
index 211580a6..c4fad049 100644
--- a/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/encryptor/auth/credentials/provider/MockEncryptorCredentialsProvider.java
+++ b/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/encryptor/auth/credentials/provider/MockEncryptorCredentialsProvider.java
@@ -17,6 +17,8 @@
import com.yeepay.yop.sdk.config.provider.file.YopFileSdkConfig;
import com.yeepay.yop.sdk.base.config.provider.file.YopFileSdkConfigProvider;
import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.exception.config.IllegalConfigFormatException;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.security.CertTypeEnum;
import com.yeepay.yop.sdk.utils.Encodes;
import org.apache.commons.collections4.CollectionUtils;
@@ -50,7 +52,8 @@ protected final YopCredentials> buildCredentials(YopAppConfig appConfig, Strin
CertTypeEnum certType;
if (null == appConfig || StringUtils.isEmpty(credentialType) ||
(null == (certType = CertTypeEnum.parse(credentialType)))) {
- throw new YopClientException("ConfigProblem, IsvPrivateCert NotFound, certType:" + credentialType + ", config:" + appConfig);
+ throw new IllegalConfigFormatException("isv_private_key",
+ "ConfigProblem, IsvPrivateCert NotFound, certType:" + credentialType + ", config:" + appConfig);
}
switch (certType) {
case RSA2048:
@@ -58,7 +61,8 @@ protected final YopCredentials> buildCredentials(YopAppConfig appConfig, Strin
MockEncryptorCredentialsItem credentialsItem = new MockEncryptorCredentialsItem(Encodes.encodeKey(appConfig.loadPrivateKey(certType)), certType);
return new MockEncryptorCredentials(appConfig.getAppKey(), credentialsItem);
default:
- throw new YopClientException("ConfigProblem, IsvPrivateCert Type NotSupport, certType:" + certType + ", config:" + appConfig);
+ throw new IllegalParamFormatException("credentialType",
+ "ConfigProblem, IsvPrivateCert Type NotSupport, certType:" + certType + ", config:" + appConfig);
}
}
diff --git a/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/encryptor/signer/process/MockEncryptorSignProcessor.java b/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/encryptor/signer/process/MockEncryptorSignProcessor.java
index 797d6a46..055f2b4c 100644
--- a/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/encryptor/signer/process/MockEncryptorSignProcessor.java
+++ b/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/encryptor/signer/process/MockEncryptorSignProcessor.java
@@ -4,15 +4,15 @@
*/
package com.yeepay.yop.sdk.encryptor.signer.process;
-import com.yeepay.yop.sdk.encryptor.auth.credentials.MockEncryptorCredentialsItem;
import com.google.common.collect.ImmutableMap;
import com.yeepay.yop.sdk.auth.SignOptions;
import com.yeepay.yop.sdk.auth.credentials.CredentialsItem;
import com.yeepay.yop.sdk.auth.credentials.PKICredentialsItem;
-import com.yeepay.yop.sdk.inter.auth.signer.process.YopRsaSignProcessor;
import com.yeepay.yop.sdk.auth.signer.process.YopSignProcessor;
+import com.yeepay.yop.sdk.encryptor.auth.credentials.MockEncryptorCredentialsItem;
+import com.yeepay.yop.sdk.exception.param.IllegalParamFormatException;
import com.yeepay.yop.sdk.gm.auth.signer.process.YopSm2SignProcessor;
-import com.yeepay.yop.sdk.exception.YopClientException;
+import com.yeepay.yop.sdk.inter.auth.signer.process.YopRsaSignProcessor;
import com.yeepay.yop.sdk.security.CertTypeEnum;
import com.yeepay.yop.sdk.security.DigestAlgEnum;
@@ -45,7 +45,7 @@ public String doSign(String content, CredentialsItem credentialsItem, SignOption
if (certType == CertTypeEnum.RSA2048) {
return "mock sign, to be impl by yourself";
}
- throw new YopClientException("UnSupported cert type:" + certType);
+ throw new IllegalParamFormatException("CredentialsItem", "UnSupported cert type:" + certType + ",credentialsItem:" + credentialsItem);
}
@Override
@@ -53,7 +53,7 @@ public boolean verify(String content, String signature, CredentialsItem credenti
if (credentialsItem instanceof PKICredentialsItem) {
return doVerify(content, signature, credentialsItem);
}
- throw new YopClientException("UnSupported credentialsItem type:" + credentialsItem.getClass().getSimpleName());
+ throw new IllegalParamFormatException("CredentialsItem", "UnSupported credentialsItem type:" + credentialsItem.getClass().getSimpleName());
}
@Override
diff --git a/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/example/YopRsaEncryptExample.java b/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/example/YopRsaEncryptExample.java
index 3650f012..12b0ec8f 100644
--- a/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/example/YopRsaEncryptExample.java
+++ b/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/example/YopRsaEncryptExample.java
@@ -4,45 +4,50 @@
*/
package com.yeepay.yop.sdk.example;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.base.Joiner;
-import com.google.common.collect.*;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.codec.binary.Hex;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
-import org.apache.http.HttpStatus;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.client.methods.RequestBuilder;
-import org.apache.http.client.utils.HttpClientUtils;
-import org.apache.http.entity.InputStreamEntity;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.entity.mime.HttpMultipartMode;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
-import org.joda.time.format.DateTimeFormatter;
-import org.joda.time.format.ISODateTimeFormat;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
+import java.net.URL;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
+import java.text.SimpleDateFormat;
import java.util.*;
-import static com.google.common.base.Preconditions.checkNotNull;
-
/**
* title: rsa 加密示例
* description: 描述
@@ -55,7 +60,13 @@
*/
public class YopRsaEncryptExample {
+ private static final Logger LOGGER = LoggerFactory.getLogger(YopRsaEncryptExample.class);
+
+ //须引入第三方包 org.apache.httpcomponents:httpclient
private static final CloseableHttpClient httpClient;
+ //须引入第三方包 com.fasterxml.jackson.core:jackson-databind
+ private static final ObjectMapper OBJECT_MAPPER;
+
static {
// 自定义连接池大小、默认超时时间
httpClient = HttpClients.custom()
@@ -63,11 +74,23 @@ public class YopRsaEncryptExample {
.setMaxConnTotal(200)
.setDefaultRequestConfig(
RequestConfig.custom()
- .setConnectionRequestTimeout(3000)
- .setConnectTimeout(3000)
- .setSocketTimeout(30000)
- .build())
+ .setConnectionRequestTimeout(3000)
+ .setConnectTimeout(3000)
+ .setSocketTimeout(30000)
+ .build())
.build();
+ OBJECT_MAPPER = new ObjectMapper();
+ OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
+ OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
+ OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);
+ OBJECT_MAPPER.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+ OBJECT_MAPPER.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
+ OBJECT_MAPPER.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
+ // 小数都用BigDecimal,默认的是Double
+ OBJECT_MAPPER.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
+ OBJECT_MAPPER.setNodeFactory(JsonNodeFactory.withExactBigDecimals(true));
}
private static final String APP_KEY = "sandbox_rsa_10080041523";
@@ -89,206 +112,6 @@ public class YopRsaEncryptExample {
private static final String RSA = "RSA";
private static final String DEFAULT_DIGEST_ALG = "SHA-256";
private static final String DEFAULT_SIGN_ALG = "SHA256withRSA";
- private static final Joiner QUERY_STRING_JOINER = Joiner.on('&');
-
- public static void main(String[] args) throws Exception {
- // 加密会话密钥,可每笔调用都生成,也可以多笔公用一个,建议定时更换
- String encryptKey = encodeUrlSafeBase64(generateRandomKey());
-
-// // get请求,form参数
- getFormExample(YopRequestMethod.GET, "/rest/v1.0/test/errorcode2",
- YopRequestContentType.FORM_URL_ENCODE, encryptKey);
-
- // post请求,form参数
- postFormExample(YopRequestMethod.POST, "/rest/v1.0/test/old-api-mgr/find-api-by-uri",
- YopRequestContentType.FORM_URL_ENCODE, encryptKey);
-
- // post请求,json参数
- postJsonExample(YopRequestMethod.POST, "/rest/v1.0/test-wdc/test/http-json/test",
- YopRequestContentType.JSON, encryptKey);
-
- // get请求,form参数,下载文件
- downloadExample(YopRequestMethod.GET, "/yos/v1.0/test/test/ceph-download",
- YopRequestContentType.FORM_URL_ENCODE, encryptKey);
- }
-
- private static void getFormExample(YopRequestMethod requestMethod, String requestUri,
- YopRequestContentType requestContentType,
- String encryptKey) throws Exception {
- // 请求参数
- String paramKey = "errorCode";
- String paramPlainValue = "000027",
- paramEncryptValue = encryptParam(encryptKey, paramPlainValue);
- Multimap formParams = ArrayListMultimap.create();
- // 参数不加密
-// formParams.put(paramKey, paramPlainValue);
-
- // 参数加密
- formParams.put(paramKey, paramEncryptValue);
- Set encryptHeaders = Collections.emptySet();
- Set encryptParams = Sets.newHashSet();
- encryptParams.add(paramKey);
-
- // 请求头
- Map headers = buildHeaders(requestMethod, requestUri, formParams,
- requestContentType, "", encryptKey, encryptHeaders, encryptParams);
-
- // 构造http请求
- HttpUriRequest request = buildHttpRequest(SERVER_ROOT + requestUri,
- requestMethod, headers, formParams, null);
-
- // 发起http调用
- CloseableHttpResponse response = null;
- try {
- response = httpClient.execute(request);
- handleResponse(YopRequestType.WEB, response, encryptKey);
- } finally {
- HttpClientUtils.closeQuietly(response);
- }
- }
-
- private static Map buildHeaders(YopRequestMethod httpMethod, String apiUri,
- Multimap params,
- YopRequestContentType contentType, String content,
- String encryptKey, Set encryptHeaders, Set encryptParams) throws Exception {
- Map headers = new HashMap<>();
- headers.put(YOP_SDK_LANGS, "java");
- headers.put(YOP_SDK_VERSION, "4.3.0");
- headers.put(YOP_APPKEY, APP_KEY);
- headers.put(YOP_REQUEST_ID, UUID.randomUUID().toString());
-
- // 加密头:请求参数不加密的情况, 也需设置加密头,用于响应结果加密
- headers.put(YOP_ENCRYPT, buildEncryptHeader(encryptHeaders, encryptParams, encryptKey));
-
- // 摘要头
- headers.put(YOP_CONTENT_SHA256, calculateContentHash(httpMethod, contentType, params, content));
-
- // 签名头
- headers.put(AUTHORIZATION, signRequest(httpMethod, apiUri, headers, params));
- return headers;
- }
-
- private static void postFormExample(YopRequestMethod requestMethod, String requestUri,
- YopRequestContentType requestContentType,
- String encryptKey) throws Exception {
-
- // 请求参数
- String paramKey = "apiUri";
- String paramPlainValue = "/rest/v1.0/test/product/find/lookatdoc",
- paramEncryptValue = encryptParam(encryptKey, paramPlainValue);
- Multimap params = ArrayListMultimap.create();
- // 参数不加密
-// params.put(paramKey, paramPlainValue);
-
- // 参数加密
- params.put(paramKey, paramEncryptValue);
- Set encryptHeaders = Collections.emptySet();
- Set encryptParams = Sets.newHashSet();
- encryptParams.add(paramKey);
-
- // 请求头
- Map headers = buildHeaders(requestMethod, requestUri, params,
- requestContentType, "", encryptKey, encryptHeaders, encryptParams);
-
- // 构造http请求
- HttpUriRequest request = buildHttpRequest(SERVER_ROOT + requestUri,
- requestMethod, headers, params, null);
-
- // 发起http调用
- CloseableHttpResponse response = null;
- try {
- response = httpClient.execute(request);
- handleResponse(YopRequestType.WEB, response, encryptKey);
- } finally {
- HttpClientUtils.closeQuietly(response);
- }
- }
-
- private static void postJsonExample(YopRequestMethod requestMethod, String requestUri,
- YopRequestContentType requestContentType,
- String encryptKey) throws Exception {
- // 请求参数
- String plainJsonContent = ("{\n" +
- " \"arg1\" : {\n" +
- " \"appId\" : \"app_1111111111\",\n" +
- " \"customerNo\" : \"333333333\"\n" +
- " },\n" +
- " \"arg0\" : {\n" +
- " \"string\" : \"hello\",\n" +
- " \"array\" : [ \"test\" ]\n" +
- " }\n" +
- "}"),
- encryptJsonContent = encryptParam(encryptKey, plainJsonContent);
-
- String finalJsonContent
- // 不加密
-// = plainJsonContent;
- // 加密
- = encryptJsonContent;
- Set encryptHeaders = Collections.emptySet();
- Set encryptParams = Sets.newHashSet();
- encryptParams.add("$");// 目前json推荐整体加密
-
- // 请求头
- // 目前不允许json接口带有form参数,置空即可
- final ArrayListMultimap params = ArrayListMultimap.create();
- Map headers = buildHeaders(requestMethod, requestUri, params,
- requestContentType, finalJsonContent, encryptKey, encryptHeaders, encryptParams);
-
- // 构造http请求
- HttpUriRequest request = buildHttpRequest(SERVER_ROOT + requestUri,
- requestMethod, headers, params, finalJsonContent);
-
- // 发起http调用
- CloseableHttpResponse response = null;
- try {
- response = httpClient.execute(request);
- handleResponse(YopRequestType.WEB, response, encryptKey);
- } finally {
- HttpClientUtils.closeQuietly(response);
- }
- }
-
- private static void downloadExample(YopRequestMethod requestMethod, String requestUri,
- YopRequestContentType requestContentType,
- String encryptKey) throws Exception {
- // 根据实际情况来,也可能是post方法,请求报文可能是form,也可能是json,可参考其他方式的入参处理
- // 此处仅演示文件响应流的处理
- // 请求参数
- String paramKey = "fileName";
- String paramPlainValue = "wym-test.txt",
- paramEncryptValue = encryptParam(encryptKey, paramPlainValue);
- Multimap params = ArrayListMultimap.create();
- // 不加密
-// params.put(paramKey, paramPlainValue);
-
- // 加密
- params.put(paramKey, paramEncryptValue);
- Set encryptHeaders = Collections.emptySet();
- Set encryptParams = Sets.newHashSet();
- encryptParams.add(paramKey);
-
- // 请求头
- Map headers = buildHeaders(requestMethod, requestUri, params,
- requestContentType, "", encryptKey, encryptHeaders, encryptParams);
-
- // 构造http请求
- HttpUriRequest request = buildHttpRequest(SERVER_ROOT + requestUri,
- requestMethod, headers, params, "");
-
- // 发起请求
- CloseableHttpResponse response = null;
- try {
- response = httpClient.execute(request);
- handleResponse(YopRequestType.FILE_DOWNLOAD, response, encryptKey);
- } finally {
- HttpClientUtils.closeQuietly(response);
- }
- }
-
- private static final Set DEFAULT_HEADERS_TO_SIGN = Sets.newHashSet();
- private static final Joiner HEADER_JOINER = Joiner.on('\n');
- private static final Joiner SIGNED_HEADER_STRING_JOINER = Joiner.on(';');
private static final String YOP_SDK_VERSION = "x-yop-sdk-version";
private static final String YOP_SDK_LANGS = "x-yop-sdk-langs";
@@ -296,455 +119,510 @@ private static void downloadExample(YopRequestMethod requestMethod, String reque
private static final String YOP_APPKEY = "x-yop-appkey";
private static final String YOP_CONTENT_SHA256 = "x-yop-content-sha256";
private static final String YOP_ENCRYPT = "x-yop-encrypt";
+ private static final String YOP_SIGN = "x-yop-sign";
private static final String AUTHORIZATION = "Authorization";
private static final String CONTENT_DISPOSITION = "Content-Disposition";
private static final String CONTENT_TYPE = "Content-Type";
- static {
- DEFAULT_HEADERS_TO_SIGN.add(YOP_REQUEST_ID);
- DEFAULT_HEADERS_TO_SIGN.add(YOP_APPKEY);
- DEFAULT_HEADERS_TO_SIGN.add(YOP_CONTENT_SHA256);
- DEFAULT_HEADERS_TO_SIGN.add(YOP_ENCRYPT);
- }
+ public static void main(String[] args) throws Exception {
+ // get请求,form参数,返回json
+ getFormExample();
- private static String signRequest(YopRequestMethod requestMethod, String requestUri,
- Map headers, Multimap params) throws Exception {
- // A.构造认证字符串
- String authString = buildAuthString();
+ // 文件下载接口,返回文件流
+ downloadExample();
- // B.获取规范请求串
- SortedMap headersToSign = getHeadersToSign(headers, DEFAULT_HEADERS_TO_SIGN);
- String canonicalRequest = buildCanonicalRequest(requestMethod, requestUri, params, authString, headersToSign);
+ // post请求,form参数,返回json
+ postFormExample();
- // C.计算签名
- String signature = encodeUrlSafeBase64(sign(canonicalRequest.getBytes(DEFAULT_ENCODING))) + "$" + "SHA256";
+ // post请求,json参数,返回json
+ postJsonExample();
- // D.添加认证头
- return buildAuthHeader(authString, headersToSign, signature);
+ // post请求,文件上传,返回json
+ uploadExample();
}
- private static String buildAuthHeader(String authString,
- SortedMap headersToSign,
- String signature) {
- String signedHeaders = SIGNED_HEADER_STRING_JOINER.join(headersToSign.keySet());
- signedHeaders = signedHeaders.trim().toLowerCase();
- return DEFAULT_AUTH_PREFIX_RSA2048 + " " + authString + "/" + signedHeaders + "/" + signature;
+ /**
+ * HTTP GET 请求
+ *
+ * @param serverRoot 请求端点地址
+ * @param apiUri 请求接口地址
+ * @param params 查询参数Map
+ * @param encryptParams 指定待加密参数名
+ * @param yopPublicKey 平台公钥
+ * @param isvPrivateKey 商户私钥
+ * @return ApiResponse
+ * @throws Exception
+ */
+ public static ApiResponse get(String serverRoot,
+ String apiUri,
+ Map params,
+ Set encryptParams,
+ String yopPublicKey,
+ String isvPrivateKey) throws Exception {
+ // 请求类型,具体查看枚举注释
+ YopRequestType requestType = YopRequestType.WEB;
+
+ // 请求方法
+ YopRequestMethod httpMethod = YopRequestMethod.GET;
+
+ // 请求内容类型
+ YopRequestContentType contentType = YopRequestContentType.FORM_URL_ENCODE;
+
+ // GET 请求不支持http-body参数,留空即可
+ Map bodyParams = null;
+
+ return request(serverRoot, requestType, httpMethod, apiUri, contentType, params, bodyParams,
+ encryptParams, yopPublicKey, isvPrivateKey);
}
- private static byte[] sign(byte[] data) {
- try {
- Signature signature = Signature.getInstance(DEFAULT_SIGN_ALG);
- signature.initSign(string2PrivateKey(ISV_PRIVATE_KEY));
- signature.update(data);
- return signature.sign();
- } catch (Exception e) {
- throw new RuntimeException("SystemError, Sign Fail, key:" + ISV_PRIVATE_KEY + ", ex:", e);
+ /**
+ * HTTP POST 请求
+ *
+ * @param serverRoot 请求端点地址
+ * @param apiUri 请求接口地址
+ * @param params 业务参数Map
+ * @param contentType 内容类型(form/json)
+ * @param encryptParams 指定待加密参数名
+ * @param yopPublicKey 平台公钥
+ * @param isvPrivateKey 商户私钥
+ * @return ApiResponse
+ * @throws Exception
+ */
+ public static ApiResponse post(String serverRoot,
+ String apiUri, YopRequestContentType contentType,
+ Map params,
+ Set encryptParams,
+ String yopPublicKey,
+ String isvPrivateKey) throws Exception {
+ if (null == params || params.isEmpty()) {
+ throw new IllegalArgumentException("biz params must not be null or empty");
}
- }
- private static PrivateKey string2PrivateKey(String priKey) {
- try {
- return KeyFactory.getInstance(RSA).generatePrivate(
- new PKCS8EncodedKeySpec(decodeBase64(priKey)));
- } catch (Exception e) {
- throw new RuntimeException("ConfigProblem, IsvPrivateKey ParseFail, value:" + priKey + ", ex:", e);
+ // 纠正内容类型,具体查看枚举注释
+ for (Object value : params.values()) {
+ if (isFileParam(value)) {
+ return upload(serverRoot, apiUri, params, encryptParams, yopPublicKey, isvPrivateKey);
+ }
}
- }
- private static byte[] decodeBase64(String input) {
- return Base64.decodeBase64(input);
+ // 请求类型
+ YopRequestType requestType = YopRequestType.WEB;
+
+ // 请求方法
+ YopRequestMethod httpMethod = YopRequestMethod.POST;
+
+ // http-body参数,留空即可
+ Map bodyParams = params;
+
+ return request(serverRoot, requestType, httpMethod, apiUri, contentType, null, bodyParams,
+ encryptParams, yopPublicKey, isvPrivateKey);
}
- private static String buildCanonicalRequest(YopRequestMethod httpMethod, String apiUri, Multimap params,
- String authString,
- SortedMap headersToSign) {
- String canonicalQueryString;
- if (YopRequestMethod.GET.equals(httpMethod) && null != params) {
- canonicalQueryString = getCanonicalQueryString(params, true);
- } else {
- canonicalQueryString = "";// post from 与json时,均为空,此处先简单处理
+ /**
+ * HTTP POST 请求
+ *
+ * @param serverRoot 请求端点地址
+ * @param apiUri 请求接口地址
+ * @param params 业务参数Map
+ * @param encryptParams 指定待加密参数名
+ * @param yopPublicKey 平台公钥
+ * @param isvPrivateKey 商户私钥
+ * @return ApiResponse
+ * @throws Exception
+ */
+ public static ApiResponse upload(String serverRoot,
+ String apiUri,
+ Map params,
+ Set encryptParams,
+ String yopPublicKey,
+ String isvPrivateKey) throws Exception {
+ if (null == params || params.isEmpty()) {
+ throw new IllegalArgumentException("biz params must not be null or empty");
}
- String canonicalHeaders = getCanonicalHeaders(headersToSign);
- String canonicalURI = getCanonicalURIPath(apiUri);
- return authString + "\n"
- + httpMethod.name() + "\n"
- + canonicalURI + "\n"
- + canonicalQueryString + "\n"
- + canonicalHeaders;
+ YopRequestContentType contentType = YopRequestContentType.MULTIPART_FORM;
+
+ // 请求类型
+ YopRequestType requestType = YopRequestType.WEB;
+
+ // 请求方法
+ YopRequestMethod httpMethod = YopRequestMethod.POST;
+
+ // http-body参数,留空即可
+ Map bodyParams = params;
+
+ return request(serverRoot, requestType, httpMethod, apiUri, contentType, null, bodyParams,
+ encryptParams, yopPublicKey, isvPrivateKey);
}
- private static String getCanonicalURIPath(String path) {
- if (path == null) {
- return "/";
- } else if (path.startsWith("/")) {
- return normalizePath(path);
+ /**
+ * HTTP 文件下载 请求
+ *
+ * @param serverRoot 请求端点地址
+ * @param apiUri 请求接口地址
+ * @param httpMethod 请求方法
+ * @param contentType 内容类型
+ * @param params 参数Map
+ * @param encryptParams 指定待加密参数名
+ * @param yopPublicKey 平台公钥
+ * @param isvPrivateKey 商户私钥
+ * @return
+ * @throws Exception
+ */
+ public static ApiResponse download(String serverRoot,
+ String apiUri,
+ YopRequestMethod httpMethod,
+ YopRequestContentType contentType,
+ Map params,
+ Set encryptParams,
+ String yopPublicKey,
+ String isvPrivateKey) throws Exception {
+ // 请求类型,具体查看枚举注释
+ YopRequestType requestType = YopRequestType.FILE_DOWNLOAD;
+
+ // 请求不支持http-body参数,留空即可
+ Map queryParams = null, bodyParams = null;
+
+ if (YopRequestMethod.GET == httpMethod) {
+ queryParams = params;
} else {
- return "/" + normalizePath(path);
+ bodyParams = params;
}
- }
- private static String normalizePath(String path) {
- return normalize(path).replace("%2F", "/");
+ return request(serverRoot, requestType, httpMethod, apiUri, contentType, queryParams, bodyParams,
+ encryptParams, yopPublicKey, isvPrivateKey);
}
- private static SortedMap getHeadersToSign(Map headers, Set headersToSign) {
- SortedMap ret = Maps.newTreeMap();
- if (headersToSign != null) {
- Set tempSet = Sets.newHashSet();
- for (String header : headersToSign) {
- tempSet.add(header.trim().toLowerCase());
- }
- headersToSign = tempSet;
- }
- for (Map.Entry entry : headers.entrySet()) {
- String key = entry.getKey();
- if (entry.getValue() != null && !entry.getValue().isEmpty()) {
- if ((headersToSign != null && headersToSign.contains(key.toLowerCase())
- && !AUTHORIZATION.equalsIgnoreCase(key))) {
- ret.put(key, entry.getValue());
- }
- }
- }
- return ret;
- }
+ private static void downloadExample() throws Exception {
+ // 接口地址
+ String apiUri = "/rest/v1.0/test-wdc/test-param-parse/input-stream-result";
- private static String getCanonicalHeaders(SortedMap headers) {
- if (headers.isEmpty()) {
- return "";
- }
+ // TODO 请求方法,根据接口文档,实际情况来选择GET/POST
+ YopRequestMethod httpMethod = YopRequestMethod.GET;
- List headerStrings = Lists.newArrayList();
- for (Map.Entry entry : headers.entrySet()) {
- String key = entry.getKey();
- if (key == null) {
- continue;
- }
- String value = entry.getValue();
- if (value == null) {
- value = "";
- }
- headerStrings.add(normalize(key.trim().toLowerCase()) + ':' + normalize(value.trim()));
- }
- Collections.sort(headerStrings);
+ // TODO 请求内容类型,根据接口文档,实际情况来选择form/json
+ YopRequestContentType contentType = YopRequestContentType.FORM_URL_ENCODE;
- return HEADER_JOINER.join(headerStrings);
- }
+ // TODO 构建业务参数,根据接口文档填充接口参数
+ Map params = new HashMap<>();
+ params.put("strParam", "xxx");
- private static final DateTimeFormatter alternateIso8601DateFormat =
- ISODateTimeFormat.dateTimeNoMillis().withZone(DateTimeZone.UTC);
+ // TODO 根据接口需要选择示例1或示例2,如果不涉及敏数据,建议走示例1
+ // 示例1、参数不加密
+ ApiResponse apiResponse1 = download(SERVER_ROOT, apiUri, httpMethod, contentType,
+ params, null, YOP_PUBLIC_KEY, ISV_PRIVATE_KEY);
+ LOGGER.info("apiResponse:{}", apiResponse1);
- private static String buildAuthString() {
- Date timestamp = new Date();
- return DEFAULT_YOP_PROTOCOL_VERSION + "/"
- + APP_KEY + "/"
- + alternateIso8601DateFormat.print(new DateTime(timestamp)) + "/"
- + "1800";
+ // 示例2、参数加密,填充敏感字段名
+ Set encryptParams = new HashSet<>();
+ encryptParams.add("strParam");
+ ApiResponse apiResponse2 = download(SERVER_ROOT, apiUri, httpMethod, contentType,
+ params, encryptParams, YOP_PUBLIC_KEY, ISV_PRIVATE_KEY);
+ LOGGER.info("apiResponse:{}", apiResponse2);
}
- private static String calculateContentHash(String jsonContent) throws Exception {
- InputStream contentStream = getContentStream(jsonContent);
- return Hex.encodeHexString((digest(contentStream)));
- }
+ private static void getFormExample() throws Exception {
+ // 接口地址
+ String apiUri = "/rest/v1.0/test/errorcode2";
- private static String calculateContentHash(YopRequestMethod requestMethod, YopRequestContentType requestContentType,
- Multimap params, String content) throws Exception {
- String digestSource;
+ // TODO 构建业务参数,根据接口文档填充接口参数
+ Map params = new HashMap<>();
+ params.put("errorCode", "000027");
- if (requestMethod.equals(YopRequestMethod.GET)) {
- digestSource = "";
- } else if (requestMethod.equals(YopRequestMethod.POST)
- && requestContentType.equals(YopRequestContentType.JSON)) {
- digestSource = content;
- } else {
- digestSource = getCanonicalQueryString(params, true);
- }
- InputStream contentStream = getContentStream(digestSource);
- return Hex.encodeHexString((digest(contentStream)));
+ // TODO 根据接口需要选择示例1或示例2,如果不涉及敏数据,建议走示例1
+ // 示例1、参数不加密
+ ApiResponse apiResponse1 = get(SERVER_ROOT, apiUri, params, null, YOP_PUBLIC_KEY, ISV_PRIVATE_KEY);
+ LOGGER.info("apiResponse:{}", apiResponse1);
+
+ // 示例2、参数加密,填充敏感字段名
+ Set encryptParams = new HashSet<>();
+ encryptParams.add("errorCode");
+ ApiResponse apiResponse2 = get(SERVER_ROOT, apiUri, params, encryptParams, YOP_PUBLIC_KEY, ISV_PRIVATE_KEY);
+ LOGGER.info("apiResponse:{}", apiResponse2);
}
- private static ByteArrayInputStream getContentStream(Multimap params) throws Exception {
- return getContentStream(getCanonicalQueryString(params, true));
+ private static void postFormExample() throws Exception {
+ // 接口地址
+ String apiUri = "/rest/v1.0/frontcashier/agreement/sign/confirm";
+
+ // 请求内容类型
+ YopRequestContentType contentType = YopRequestContentType.FORM_URL_ENCODE;
+
+ // POST 请求http-body参数
+ Map params = new HashMap<>();
+ params.put("parentMerchant", "10080041523");
+ params.put("merchantNo", "10080041523");
+ params.put("smsCode", "11111131");
+ params.put("merchantFlowId", "111111");
+
+ // TODO 根据接口需要选择示例1或示例2,如果不涉及敏数据,建议走示例1
+ // 示例1、参数不加密
+ ApiResponse apiResponse1 = post(SERVER_ROOT, apiUri, contentType,
+ params, null, YOP_PUBLIC_KEY, ISV_PRIVATE_KEY);
+ LOGGER.info("apiResponse:{}", apiResponse1);
+
+ // 示例2、参数加密,填充敏感字段名
+ Set encryptParams = new HashSet<>();
+ encryptParams.add("smsCode");
+ ApiResponse apiResponse2 = post(SERVER_ROOT, apiUri, contentType,
+ params, encryptParams, YOP_PUBLIC_KEY, ISV_PRIVATE_KEY);
+ LOGGER.info("apiResponse:{}", apiResponse2);
}
- private static ByteArrayInputStream getContentStream(String paramStr) throws Exception {
- byte[] bytes;
- if (StringUtils.isEmpty(paramStr)) {
- bytes = new byte[0];
- } else {
- bytes = paramStr.getBytes(DEFAULT_ENCODING);
- }
- return new ByteArrayInputStream(bytes);
+ private static void uploadExample() throws Exception {
+ // 接口地址
+ String apiUri = "/yos/v1.0/sys/merchant/qual/upload";
+
+ // POST 请求http-body参数
+ Map params = new HashMap<>();
+ params.put("clientId", APP_KEY);
+ params.put("merQual", new FileParam(new URL("https://open.yeepay.com/apis/docs/apis/common/ALL.json").openStream(), "abc.json"));
+
+ // TODO 根据接口需要选择示例1或示例2,如果不涉及敏数据,建议走示例1
+ // 示例1、参数不加密
+ ApiResponse apiResponse1 = upload(SERVER_ROOT, apiUri,
+ params, null, YOP_PUBLIC_KEY, ISV_PRIVATE_KEY);
+ LOGGER.info("apiResponse:{}", apiResponse1);
+
+ // 示例2、参数加密,填充敏感字段名
+// Set encryptParams = new HashSet<>();
+// encryptParams.add("clientId");
+// ApiResponse apiResponse2 = upload(SERVER_ROOT, apiUri,
+// params, encryptParams, YOP_PUBLIC_KEY, ISV_PRIVATE_KEY);
+// LOGGER.info("apiResponse:{}", apiResponse2);
}
- public static String getCanonicalQueryString(Multimap params, boolean forSignature) {
- Map> parameters;
- if (null == params || (parameters = params.asMap()).isEmpty()) {
- return "";
- }
+ private static void postJsonExample() throws Exception {
+ // 接口地址
+ String apiUri = "/rest/v1.0/test-wdc/test/http-json/test";
+
+ // 请求内容类型
+ YopRequestContentType contentType = YopRequestContentType.JSON;
+
+ // POST-json请求支持http-body参数,此处为嵌套复杂对象示例
+ Map params = new HashMap<>();
+ Map arg0 = new HashMap<>();
+ arg0.put("string","hello world");
+ arg0.put("array", Arrays.asList("test"));
+ params.put("arg0", arg0);
+ Map arg1 = new HashMap<>();
+ arg1.put("appId","app_1111111111");
+ arg1.put("customerNo","333333333");
+ params.put("arg1", arg1);
+
+ // TODO 根据接口需要选择示例1或示例2,如果不涉及敏数据,建议走示例1
+ // 示例1、参数不加密
+ ApiResponse apiResponse1 = post(SERVER_ROOT, apiUri, contentType,
+ params, null, YOP_PUBLIC_KEY, ISV_PRIVATE_KEY);
+ LOGGER.info("apiResponse:{}", apiResponse1);
+
+ // 示例2、参数加密,填充敏感字段名,json方式时,直接加密整个请求体即可
+ Set encryptParams = new HashSet<>();
+ encryptParams.add("$");// $代表整体加密(所有参数均加密)
+ ApiResponse apiResponse2 = post(SERVER_ROOT, apiUri, contentType,
+ params, encryptParams, YOP_PUBLIC_KEY, ISV_PRIVATE_KEY);
+ LOGGER.info("apiResponse:{}", apiResponse2);
+ }
- List parameterStrings = Lists.newArrayList();
- for (Map.Entry> entry : parameters.entrySet()) {
- if (forSignature && AUTHORIZATION.equalsIgnoreCase(entry.getKey())) {
- continue;
- }
- String key = entry.getKey();
- checkNotNull(key, "parameter key should not be null");
- Collection value = entry.getValue();
- if (value == null) {
- if (forSignature) {
- parameterStrings.add(normalize(key) + '=');
+ /**
+ * 请求响应处理
+ *
+ * @param serverRoot 请求端点地址
+ * @param requestType 请求类型
+ * @param httpMethod 请求方法
+ * @param apiUri 请求接口地址
+ * @param contentType 请求内容类型
+ * @param queryParams http-query参数
+ * @param bodyParams http-body参数
+ * @param encryptParams 待加密参数名
+ * @param yopPublicKey 平台公钥
+ * @param isvPrivateKey 商户私钥
+ * @return
+ * @throws Exception
+ */
+ public static ApiResponse request(String serverRoot,
+ YopRequestType requestType, YopRequestMethod httpMethod, String apiUri,
+ YopRequestContentType contentType, Map queryParams,
+ Map bodyParams, Set encryptParams,
+ String yopPublicKey, String isvPrivateKey) throws Exception {
+ // header 不加密
+ Set encryptHeaders = Collections.EMPTY_SET;
+
+ // 非法参数过滤
+ queryParams = autoFixParams(queryParams);
+ bodyParams = autoFixParams(bodyParams);
+
+
+ // 敏感业务参数加密
+ String encryptKey = null;
+ Map handledQueryParams = queryParams;
+ Object handledBodyParams = contentType == YopRequestContentType.JSON ? toJsonString(bodyParams) : bodyParams;
+ Set handledEncryptParams = new HashSet<>();
+ if (encryptParams != null) {
+ encryptKey = encodeBase64(generateRandomKey());
+ handledQueryParams = new HashMap<>();
+ for (String key : queryParams.keySet()) {
+ if (encryptParams.contains(key)) {
+ handledQueryParams.put(key, encryptParam(encryptKey, queryParams.get(key).toString()));
+ handledEncryptParams.add(key);
} else {
- parameterStrings.add(normalize(key));
+ handledQueryParams.put(key, queryParams.get(key));
}
+ }
+ // json请求,整体加密
+ if (contentType == YopRequestContentType.JSON) {
+ handledBodyParams = toJsonString(encryptParam(encryptKey, (String) handledBodyParams));
+ handledEncryptParams.clear();
+ handledEncryptParams.add("$");
} else {
- for (String item : value) {
- parameterStrings.add(normalize(key) + '=' + normalize(item));
+ Map tmpBodyParams = new HashMap<>();
+ for (String key : bodyParams.keySet()) {
+ Object value = bodyParams.get(key);
+ if (encryptParams.contains(key)) {
+ // 仅加密非文件参数
+ if (!isFileParam(value)) {
+ tmpBodyParams.put(key, encryptParam(encryptKey, value.toString()));
+ handledEncryptParams.add(key);
+ } else {
+ tmpBodyParams.put(key, value);
+ }
+ } else {
+ tmpBodyParams.put(key, value);
+ }
}
+ handledBodyParams = tmpBodyParams;
}
}
- Collections.sort(parameterStrings);
-
- return QUERY_STRING_JOINER.join(parameterStrings);
- }
- private static final BitSet URI_UNRESERVED_CHARACTERS = new BitSet();
- private static final String[] PERCENT_ENCODED_STRINGS = new String[256];
+ // 构建认证信息
+ Map headers = buildAuthHeaders(httpMethod, apiUri, contentType, handledQueryParams, handledBodyParams,
+ encryptKey, encryptHeaders, handledEncryptParams, yopPublicKey, isvPrivateKey);
- static {
- /*
- * StringBuilder pattern = new StringBuilder();
- *
- * pattern .append(Pattern.quote("+")) .append("|") .append(Pattern.quote("*")) .append("|")
- * .append(Pattern.quote("%7E")) .append("|") .append(Pattern.quote("%2F"));
- *
- * ENCODED_CHARACTERS_PATTERN = Pattern.compile(pattern.toString());
- */
- for (int i = 'a'; i <= 'z'; i++) {
- URI_UNRESERVED_CHARACTERS.set(i);
- }
- for (int i = 'A'; i <= 'Z'; i++) {
- URI_UNRESERVED_CHARACTERS.set(i);
- }
- for (int i = '0'; i <= '9'; i++) {
- URI_UNRESERVED_CHARACTERS.set(i);
- }
- URI_UNRESERVED_CHARACTERS.set('-');
- URI_UNRESERVED_CHARACTERS.set('.');
- URI_UNRESERVED_CHARACTERS.set('_');
- URI_UNRESERVED_CHARACTERS.set('~');
+ // 构建http请求
+ HttpUriRequest httpUriRequest = buildHttpRequest(serverRoot + apiUri, httpMethod, contentType,
+ headers, handledQueryParams, handledBodyParams);
- for (int i = 0; i < PERCENT_ENCODED_STRINGS.length; ++i) {
- PERCENT_ENCODED_STRINGS[i] = String.format("%%%02X", i);
- }
- }
+ // 发送http请求
+ HttpResponse response = httpClient.execute(httpUriRequest);
- public static String normalize(String value) {
- try {
- StringBuilder builder = new StringBuilder();
- for (byte b : value.getBytes(DEFAULT_ENCODING)) {
- if (URI_UNRESERVED_CHARACTERS.get(b & 0xFF)) {
- builder.append((char) b);
- } else {
- builder.append(PERCENT_ENCODED_STRINGS[b & 0xFF]);
- }
- }
- return builder.toString();
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e);
- }
+ // 处理API响应
+ ApiResponse apiResponse = handleResponse(requestType, response, yopPublicKey, encryptKey);
+ return apiResponse;
}
- private static byte[] digest(InputStream input) {
- try {
- MessageDigest md = MessageDigest.getInstance(DEFAULT_DIGEST_ALG);
- DigestInputStream digestInputStream = new DigestInputStream(input, md);
- byte[] buffer = new byte[1024];
- while (digestInputStream.read(buffer) > -1) {}
- return digestInputStream.getMessageDigest().digest();
- } catch (Exception e) {
- throw new RuntimeException("SystemError, Digest Fail, alg:" + DEFAULT_DIGEST_ALG + ", ex:", e);
+ private static Map autoFixParams(Map params) {
+ if (null == params || params.isEmpty()) {
+ return Collections.emptyMap();
}
+ Map result = new HashMap<>();
+ params.forEach((key, value) -> {
+ if (null != key && null!= value) {
+ result.put(key, value);
+ }
+ });
+ return result;
}
/**
- * 加密协议头(请求):
+ * 处理API响应
*
- * yop-encrypt-v1/{服务端证书序列号}/{密钥类型(必填)}_{分组模式(必填)}_{填充算法(必填)}/{加密密钥值(必填)}/{IV}{;}{附加信息}/{客户端支持的大参数加密模式(必填)}/{encryptHeaders}/{encryptParams}
+ * @param requestType 请求类型
+ * @param response HTTP响应
+ * @param publicKey 平台公钥
+ * @param encryptKey 加密会话密钥
+ * @return API响应对象
*/
- public static String buildEncryptHeader(Set encryptHeaders, Set encryptParams,
- String aesKey) throws Exception {
-
- return "yop-encrypt-v1" + SLASH +
- EMPTY + SLASH + //rsa 为空
- StringUtils.replace(AES_ENCRYPT_ALG, SLASH, UNDER_LINE) + SLASH +
- encodeUrlSafeBase64(encryptKey(decodeBase64(aesKey), string2PublicKey(YOP_PUBLIC_KEY))) + SLASH +
- EMPTY + SLASH +
- STREAM + SLASH +
- StringUtils.join(encryptHeaders, SEMICOLON) + SLASH +
- encodeUrlSafeBase64(StringUtils.join(encryptParams, SEMICOLON).getBytes(DEFAULT_ENCODING));
- }
-
- public static PublicKey string2PublicKey(String pubKey) {
- try {
- return KeyFactory.getInstance(RSA).generatePublic(
- new X509EncodedKeySpec(decodeBase64(pubKey)));
- } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
- throw new RuntimeException("ConfigProblem, YopPublicKey ParseFail, value:" + pubKey + ", ex:", e);
- }
- }
-
- private static byte[] encryptKey(byte[] data, Key key) {
- Cipher cipher;
+ public static ApiResponse handleResponse(YopRequestType requestType, HttpResponse response, String publicKey, String encryptKey) {
try {
- cipher = Cipher.getInstance(RSA_ENCRYPT_ALG);
- cipher.init(Cipher.ENCRYPT_MODE, key);
- return cipher.doFinal(data);
- } catch (Exception e) {
- throw new RuntimeException("SystemError, Encrypt Fail, key:" + key + "ex:", e);
- }
- }
+ // 1. 获取状态码
+ int statusCode = response.getStatusLine().getStatusCode();
- private static String encryptParam(String aesKey, String plain) throws Exception {
- final Cipher cipher = getInitializedCipher(Cipher.ENCRYPT_MODE, aesKey);
- return encodeUrlSafeBase64(cipher.doFinal(plain.getBytes("UTF-8")));
- }
+ // 2. 获取响应头
+ Map headers = new HashMap<>();
+ for (Header header : response.getAllHeaders()) {
+ headers.put(header.getName(), header.getValue());
+ }
+ String signature = headers.get(YOP_SIGN);
+ String requestId = headers.get(YOP_REQUEST_ID);
+ String encrypt = headers.get(YOP_ENCRYPT);
+
+ // 3. 获取响应内容
+ HttpEntity entity = response.getEntity();
+ if (requestType == YopRequestType.FILE_DOWNLOAD) {
+ // 文件下载响应
+ return handleFileDownloadResponse(headers, response, requestId, encrypt, encryptKey);
+ }
+ String responseContent = EntityUtils.toString(entity, DEFAULT_ENCODING);
- private static String decryptParam(String aesKey, String encryptContent) throws Exception {
- final Cipher cipher = getInitializedCipher(Cipher.DECRYPT_MODE, aesKey);
- return new String(cipher.doFinal(decodeBase64(encryptContent)), "UTF-8");
- }
+ // 4. 验证响应签名(如果有)
+ if (signature != null && !signature.isEmpty()) {
+ boolean validSignature = verifyResponseSignature(responseContent, signature, publicKey);
+ if (!validSignature) {
+ throw new SecurityException("响应签名验证失败");
+ }
+ }
- private static InputStream decryptStream(String aesKey, InputStream encryptStream) throws Exception {
- final Cipher cipher = getInitializedCipher(Cipher.DECRYPT_MODE, aesKey);
- return new CipherInputStream(encryptStream, cipher);
- }
+ // 5. 解析响应内容
+ ApiResponse apiResponse = new ApiResponse();
+ apiResponse.setStatusCode(statusCode);
+ apiResponse.setRequestId(requestId);
+ apiResponse.setRawContent(responseContent);
+
+ // 6. 根据状态码处理
+ if (statusCode == 200) {
+ // 成功响应
+ apiResponse.setSuccess(true);
+ apiResponse.setResult(parseSuccessResponse(responseContent, encrypt, encryptKey));
+ } else if (statusCode == 500) {
+ // 业务错误
+ apiResponse.setSuccess(false);
+ apiResponse.setError(parseErrorResponse(responseContent));
+ } else {
+ // 其他错误
+ apiResponse.setSuccess(false);
+ ApiError error = new ApiError();
+ error.setCode("SYSTEM_ERROR");
+ error.setMessage("Unexpected status code: " + statusCode);
+ apiResponse.setError(error);
+ }
- private static Cipher getInitializedCipher(int mode, String aesKey) {
- try {
- byte[] key = decodeBase64(aesKey);
- Cipher cipher = Cipher.getInstance(AES_ENCRYPT_ALG);
- Key secretKey = new SecretKeySpec(key, "AES");
- cipher.init(mode, secretKey);
- return cipher;
- } catch (Throwable throwable) {
- throw new RuntimeException("error happened when initialize cipher", throwable);
+ return apiResponse;
+ } catch (Exception e) {
+ throw new RuntimeException("处理响应失败", e);
}
}
- private static String encodeUrlSafeBase64(byte[] input) {
- return Base64.encodeBase64URLSafeString(input);
- }
-
- private static byte[] generateRandomKey() throws NoSuchAlgorithmException {
- //实例化
- KeyGenerator generator = KeyGenerator.getInstance("AES");
- //设置密钥长度
- generator.init(128);
- //生成密钥
- return generator.generateKey().getEncoded();
- }
-
- protected static HttpUriRequest buildHttpRequest(String requestUrl, YopRequestMethod requestMethod,
- Map headers, Multimap params,
- String content) throws UnsupportedEncodingException {
- RequestBuilder requestBuilder;
- if (YopRequestMethod.POST == requestMethod) {
- requestBuilder = RequestBuilder.post();
- } else if (YopRequestMethod.GET == requestMethod) {
- requestBuilder = RequestBuilder.get();
- } else {
- throw new RuntimeException("unsupported http method");
- }
- requestBuilder.setUri(requestUrl);
-
- // header
- for (Map.Entry entry : headers.entrySet()) {
- requestBuilder.addHeader(entry.getKey(), entry.getValue());
- }
-
- // body
- try {
- if (null != params) {
- for (Map.Entry> entry : params.asMap().entrySet()) {
- String paramKey = entry.getKey();
- for (String value : entry.getValue()) {
- requestBuilder.addParameter(paramKey, URLEncoder.encode(value, DEFAULT_ENCODING));
- }
- }
- }
- } catch (IOException ex) {
- throw new RuntimeException("unable to create http request.", ex);
- }
- if (YopRequestMethod.GET.equals(requestMethod)) {
- requestBuilder.addHeader(CONTENT_TYPE, "application/x-www-form-urlencoded;charset=UTF-8");
- return requestBuilder.build();
- }
- // json 请求
- if (StringUtils.isNotBlank(content)) {
- final byte[] contentBytes = content.getBytes(DEFAULT_ENCODING);
- requestBuilder.setEntity(new InputStreamEntity(new ByteArrayInputStream(contentBytes), contentBytes.length));
- requestBuilder.addHeader(CONTENT_TYPE, "application/json;charset=UTF-8");
- }
- return requestBuilder.build();
- }
-
- private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
-
- private static void handleResponse(YopRequestType requestType,
- CloseableHttpResponse httpResponse,
- String encryptKey) throws Exception {
- // header
- Map headers = Maps.newHashMap();
- for (Header header : httpResponse.getAllHeaders()) {
- headers.put(header.getName(), header.getValue());
- }
- String encryptHeader = headers.get("x-yop-encrypt"),// 加密头
- signHeader = headers.get("x-yop-sign"); //签名头
-
- boolean isEncryptResponse = StringUtils.isNotBlank(encryptHeader);
-
- // body
- HttpEntity entity = httpResponse.getEntity();
- int statusCode = httpResponse.getStatusLine().getStatusCode();
- if (statusCode / 100 == HttpStatus.SC_OK / 100 && statusCode != HttpStatus.SC_NO_CONTENT) {
- //not a error
- if (null != entity && entity.getContent() != null) {
- if (isJsonResponse(httpResponse)) {
- String content = IOUtils.toString(entity.getContent(), DEFAULT_ENCODING);
- System.out.println("Request success, response:" + content);
- final JsonNode bizData = OBJECT_MAPPER.readTree(content).get("result");
- if (isEncryptResponse) {
- System.out.println("Response decrypt success, bizData:" + decryptParam(encryptKey, bizData.asText()));
- }
- return;
- } else if (YopRequestType.FILE_DOWNLOAD.equals(requestType) || isDownloadResponse(httpResponse)) {
- InputStream fileContent = entity.getContent();
- if (isEncryptResponse) {
- fileContent = decryptStream(encryptKey, fileContent);
- System.out.println("Response file decrypt success");
- }
- final File file = saveFile(fileContent, headers);
- System.out.println("Request success, file downloaded:" + file);
- return;
- } else {
- throw new RuntimeException("Response Error, contentType:" + httpResponse.getEntity().getContentType());
- }
+ private static ApiResponse handleFileDownloadResponse(Map rspHeaders, HttpResponse response, String requestId, String encrypt, String encryptKey) throws Exception {
+ int statusCode = response.getStatusLine().getStatusCode();
+ ApiResponse apiResponse = new ApiResponse();
+ apiResponse.setStatusCode(statusCode);
+ apiResponse.setRequestId(requestId);
+
+ if (statusCode == 200 && isDownloadResponse(response)) {
+ // 成功响应
+ apiResponse.setSuccess(true);
+ InputStream rawContent;
+ if (null != encrypt && null != encryptKey) {
+ rawContent = decryptStream(encryptKey, response.getEntity().getContent());
} else {
- throw new RuntimeException("Response Error, contentType:" + httpResponse.getEntity().getContentType());
+ rawContent = response.getEntity().getContent();
}
- } else if (statusCode >= HttpStatus.SC_INTERNAL_SERVER_ERROR && statusCode != HttpStatus.SC_BAD_GATEWAY) {
- if (entity.getContent() != null) {
- String content = IOUtils.toString(entity.getContent(), DEFAULT_ENCODING);
- System.out.println("Request Fail, response:" + content);
- return;
- } else {
- throw new RuntimeException("ResponseError, Empty Content, httpStatusCode:" + httpResponse.getStatusLine().getStatusCode());
- }
- } else if (statusCode == HttpStatus.SC_BAD_GATEWAY || statusCode == HttpStatus.SC_NOT_FOUND) {
- throw new RuntimeException("Response Error, statusCode:" + statusCode);
+ apiResponse.setRawContent(rawContent);
+ File tmpFile = saveFile(rawContent, rspHeaders);
+ apiResponse.setResult(tmpFile);
+ } else if (statusCode == 500) {
+ // 业务错误
+ apiResponse.setSuccess(false);
+ apiResponse.setError(parseErrorResponse(EntityUtils.toString(response.getEntity(), DEFAULT_ENCODING)));
+ } else {
+ apiResponse.setSuccess(false);
+ apiResponse.setRawContent(EntityUtils.toString(response.getEntity(), DEFAULT_ENCODING));
+ ApiError error = new ApiError();
+ error.setCode("SYSTEM_ERROR");
+ error.setMessage("Unexpected status code: " + statusCode);
+ apiResponse.setError(error);
}
- throw new RuntimeException("ReqParam Illegal, Bad Request, statusCode:" + statusCode);
+ return apiResponse;
}
/**
@@ -761,22 +639,23 @@ public static File saveFile(InputStream content, Map headers) {
final String contentDisposition = headers.get(CONTENT_DISPOSITION);
try {
String fileName = getFileNameFromHeader(contentDisposition);
- if (StringUtils.isNotBlank(fileName)) {
+ if (isNotBlank(fileName)) {
final String[] split = fileName.split("\\.");
if (split.length == 2) {
- if (StringUtils.length(split[0]) > 3) {
+ if (strLength(split[0]) > 3) {
filePrefix = split[0];
}
- if (StringUtils.isNotBlank(split[1])) {
+ if (isNotBlank(split[1])) {
fileSuffix = "." + split[1];
}
}
}
} catch (Exception e) {
- System.out.println(("parse Content-Disposition fail, value:" + contentDisposition + ", ex:" + e));
+ LOGGER.error("parse Content-Disposition fail, value:{}, ex:", contentDisposition, e);
}
File tmpFile = File.createTempFile(filePrefix, fileSuffix);
- IOUtils.copy(fileContent, Files.newOutputStream(tmpFile.toPath()));
+ long fileSize = copyStream(fileContent, Files.newOutputStream(tmpFile.toPath()));
+ LOGGER.info("downloaded file, name:{}, size:{}", tmpFile.getName(), fileSize);
return tmpFile;
} catch (Throwable ex) {
throw new RuntimeException("fail to save file", ex);
@@ -785,6 +664,32 @@ public static File saveFile(InputStream content, Map headers) {
}
}
+ private static long copyStream(final InputStream input, final OutputStream output)
+ throws IOException {
+ long count = 0;
+ if (input != null) {
+ byte[] buffer = new byte[8192];
+ int n;
+ while (-1 != (n = input.read(buffer))) {
+ output.write(buffer, 0, n);
+ count += n;
+ }
+ }
+ return count;
+ }
+
+ private static boolean isNotBlank(String str) {
+ return null != str && !str.trim().isEmpty();
+ }
+
+ private static int strLength(final CharSequence cs) {
+ return cs == null ? 0 : cs.length();
+ }
+
+ private static String strTrim(final String str) {
+ return str == null ? null : str.trim();
+ }
+
public static void closeQuietly(Closeable closeable) {
try {
if (null != closeable) {
@@ -796,64 +701,867 @@ public static void closeQuietly(Closeable closeable) {
}
private static String getFileNameFromHeader(String contentDisposition) {
- if (StringUtils.isBlank(contentDisposition)) {
+ if (!isNotBlank(contentDisposition)) {
return null;
}
final String[] parts = contentDisposition.split( "filename=");
if (parts.length == 2) {
- return StringUtils.trim(parts[1]);
+ return strTrim(parts[1]);
}
return null;
}
- private static final String CONTENT_TYPE_JSON = "application/json";
- private static final String CONTENT_TYPE_STREAM = "application/octet-stream";
-
- private static boolean isJsonResponse(CloseableHttpResponse response) {
- return null != response.getEntity() && StringUtils.startsWith(response.getEntity().getContentType().getValue(), CONTENT_TYPE_JSON);
+ private static boolean isDownloadResponse(HttpResponse response) {
+ return null != response.getEntity() && null != response.getEntity().getContentType() &&
+ response.getEntity().getContentType().getValue().startsWith(YOP_HTTP_CONTENT_TYPE_STREAM);
}
- private static boolean isDownloadResponse(CloseableHttpResponse response) {
- return null != response.getEntity() && StringUtils.startsWith(response.getEntity().getContentType().getValue(), CONTENT_TYPE_STREAM);
- }
+ private static String decryptIfNecessary(String responseContent, String encryptHeader) {
+ if (null == encryptHeader) {
+ return responseContent;
+ }
- public enum YopRequestMethod {
- GET,
- POST
+ return null;
}
- public enum YopRequestType {
- WEB,
- FILE_DOWNLOAD,
- MULTI_FILE_UPLOAD,
- }
+ /**
+ * 解析错误响应
+ *
+ * 须引入第三方包 com.fasterxml.jackson.core:jackson-databind
+ * @param content 响应内容
+ * @return 错误对象
+ */
+ private static ApiError parseErrorResponse(String content) throws Exception {
+ JsonNode rootNode = OBJECT_MAPPER.readTree(content);
- private static final String YOP_HTTP_CONTENT_TYPE_JSON = "application/json";
- private static final String YOP_HTTP_CONTENT_TYPE_FORM = "application/x-www-form-urlencoded";
- private static final String YOP_HTTP_CONTENT_TYPE_MULTIPART_FORM = "multipart/form-data";
- private static final String YOP_HTTP_CONTENT_TYPE_STREAM = "application/octet-stream";
- private static final String YOP_HTTP_CONTENT_TYPE_TEXT = "text/plain;charset=UTF-8";
+ ApiError error = new ApiError();
- public enum YopRequestContentType {
- FORM_URL_ENCODE(YOP_HTTP_CONTENT_TYPE_FORM),
- MULTIPART_FORM(YOP_HTTP_CONTENT_TYPE_MULTIPART_FORM),
- JSON(YOP_HTTP_CONTENT_TYPE_JSON),
- OCTET_STREAM(YOP_HTTP_CONTENT_TYPE_STREAM),
- TEXT_PLAIN(YOP_HTTP_CONTENT_TYPE_TEXT);
+ // 提取错误信息
+ if (rootNode.has("code")) {
+ error.setCode(rootNode.get("code").asText());
+ }
- private String value;
+ if (rootNode.has("message")) {
+ error.setMessage(rootNode.get("message").asText());
+ }
- YopRequestContentType(String value) {
- this.value = value;
+ if (rootNode.has("subCode")) {
+ error.setSubCode(rootNode.get("subCode").asText());
}
- public String getValue() {
- return value;
+ if (rootNode.has("subMessage")) {
+ error.setSubMessage(rootNode.get("subMessage").asText());
}
- public void setValue(String value) {
- this.value = value;
+ return error;
+ }
+
+ /**
+ * 解析成功响应
+ *
+ * 须引入第三方包 com.fasterxml.jackson.core:jackson-databind
+ * @param content 响应内容
+ * @param encryptHeader 响应加密头
+ * @param encryptKey 加密会话密钥
+ * @return 解析后的结果对象
+ */
+ private static Object parseSuccessResponse(String content, String encryptHeader, String encryptKey) throws Exception {
+ JsonNode rootNode = OBJECT_MAPPER.readTree(content);
+
+ // 获取result节点
+ JsonNode resultNode = rootNode.get("result");
+ if (resultNode != null) {
+ if (null != encryptHeader && null != encryptKey) {
+ String decryptBizData = decryptParam(encryptKey, resultNode.asText());
+ return OBJECT_MAPPER.readValue(decryptBizData, Object.class);
+ }
+ return OBJECT_MAPPER.convertValue(resultNode, Object.class);
+ }
+
+ // 没有result节点
+ throw new RuntimeException("Unexpected响应字符串:" + content);
+ }
+
+ private static String decryptParam(String aesKey, String encryptContent) throws Exception {
+ final Cipher cipher = getInitializedCipher(Cipher.DECRYPT_MODE, aesKey);
+ // 返回的json有格式化,需要去掉后再解码
+ return new String(cipher.doFinal(decodeBase64(urlSafeDecode(encryptContent.replaceAll("[\r\n]", EMPTY)))), DEFAULT_ENCODING);
+ }
+
+ private static InputStream decryptStream(String aesKey, InputStream encryptStream) throws Exception {
+ final Cipher cipher = getInitializedCipher(Cipher.DECRYPT_MODE, aesKey);
+ return new CipherInputStream(encryptStream, cipher);
+ }
+
+ /**
+ * 验证响应签名
+ *
+ * @param content 响应内容
+ * @param signature 响应签名(来自x-yop-sign头)
+ * @param publicKeyBase64Str 平台公钥(base64格式)
+ * @return 验证结果
+ */
+ public static boolean verifyResponseSignature(
+ String content,
+ String signature,
+ String publicKeyBase64Str) {
+
+ try {
+ // 1. 准备验证数据(移除空白字符)
+ String normalizedContent = content.replaceAll("[ \t\n]", EMPTY);
+ byte[] contentBytes = normalizedContent.getBytes(DEFAULT_ENCODING);
+
+ // 2. 解析签名
+ String signatureValue = signature;
+ String algorithm = "SHA256";
+
+ // 如果签名包含算法标识,分离出来
+ if (signature.contains("$")) {
+ String[] parts = signature.split("\\$");
+ signatureValue = parts[0];
+ algorithm = parts[1];
+ }
+
+ // 3. 解码签名(URL安全Base64 -> 标准Base64 -> 二进制)
+ String standardBase64 = urlSafeDecode(signatureValue);
+ byte[] signatureBytes = decodeBase64(standardBase64);
+
+ // 4. 加载公钥
+ PublicKey publicKey = string2PublicKey(publicKeyBase64Str);
+
+ // 5. 验证签名
+ Signature verifier = Signature.getInstance(DEFAULT_SIGN_ALG);
+ verifier.initVerify(publicKey);
+ verifier.update(contentBytes);
+
+ return verifier.verify(signatureBytes);
+ } catch (Exception e) {
+ throw new RuntimeException("验证响应签名失败", e);
+ }
+ }
+
+ /**
+ * 构造HttpRequest
+ *
+ * @param requestUrl 请求URL
+ * @param requestMethod 请求方法
+ * @param contentType 请求体格式
+ * @param headers 请求头
+ * @param queryParams 请求URL参数
+ * @param bodyParams 请求体参数
+ * @return
+ * @throws UnsupportedEncodingException
+ */
+ public static HttpUriRequest buildHttpRequest(String requestUrl,
+ YopRequestMethod requestMethod,
+ YopRequestContentType contentType,
+ Map headers,
+ Map queryParams,
+ Object bodyParams)
+ throws UnsupportedEncodingException, JsonProcessingException, FileNotFoundException {
+ // 3. 创建请求
+ HttpRequestBase request;
+
+ if (requestMethod == YopRequestMethod.POST) {
+ // POST请求
+ HttpPost post = new HttpPost(requestUrl);
+ if (null != bodyParams) {
+ if (contentType == YopRequestContentType.JSON) {
+ // application/json格式请求体
+ StringEntity entity = new StringEntity((String) bodyParams, DEFAULT_ENCODING);
+ entity.setContentType(contentType.getValue());
+ post.setEntity(entity);
+ post.addHeader(CONTENT_TYPE, contentType.getValue());
+ } else if (contentType == YopRequestContentType.MULTIPART_FORM) {
+ // multipart/form-data格式请求体
+ MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+ builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
+ for (Map.Entry entry : ((Map) bodyParams).entrySet()) {
+ String name = entry.getKey();
+ Object value = entry.getValue();
+ if (value instanceof FileParam) {
+ // 文件包装类参数
+ FileParam file = (FileParam) value;
+ builder.addBinaryBody(name, file.getInputStream(),
+ ContentType.DEFAULT_BINARY, file.getFilaName());
+ } else if (value instanceof File) {
+ // 文件参数
+ File file = (File) value;
+ builder.addBinaryBody(name, new FileInputStream(file), ContentType.DEFAULT_BINARY, file.getName());
+ } else if (value instanceof InputStream) {
+ // 流文件参数
+ builder.addBinaryBody(name, (InputStream) value, ContentType.DEFAULT_BINARY, randomFileName());
+ } else {
+ // 普通字符串参数,注意,此处urlEncode一次
+ builder.addTextBody(name, URLEncoder.encode(value.toString(), DEFAULT_ENCODING), ContentType.TEXT_PLAIN);
+ }
+ post.setEntity(builder.build());
+ }
+ } else {
+ // application/x-www-form-urlencoded格式请求体,注意,此处需要urlEncode两次(手动一次+httpclient处理一次)
+ List formParams = new ArrayList<>();
+ for (Map.Entry entry : ((Map) bodyParams).entrySet()) {
+ formParams.add(new BasicNameValuePair(entry.getKey(), URLEncoder.encode(entry.getValue().toString(), DEFAULT_ENCODING)));
+ }
+ post.setEntity(new UrlEncodedFormEntity(formParams, DEFAULT_ENCODING));
+ post.addHeader(CONTENT_TYPE, YopRequestContentType.FORM_URL_ENCODE.getValue());
+ }
+ }
+ request = post;
+ } else {
+ // GET请求
+ StringBuilder urlWithParams = new StringBuilder(requestUrl);
+
+ // 添加查询参数
+ if (queryParams != null && !queryParams.isEmpty()) {
+ urlWithParams.append("?");
+ List paramPairs = new ArrayList<>();
+
+ for (Map.Entry entry : queryParams.entrySet()) {
+ String encodedName = URLEncoder.encode(entry.getKey(), DEFAULT_ENCODING);
+ // 注意,此处需要urlEncode两次
+ String encodedValue = URLEncoder.encode(entry.getValue().toString(), DEFAULT_ENCODING);
+ paramPairs.add(encodedName + "=" + URLEncoder.encode(encodedValue, DEFAULT_ENCODING));
+ }
+
+ urlWithParams.append(String.join("&", paramPairs));
+ }
+
+ request = new HttpGet(urlWithParams.toString());
+ request.addHeader(CONTENT_TYPE, YopRequestContentType.FORM_URL_ENCODE.getValue());
+ }
+
+ // 4. 添加请求头
+ for (Map.Entry entry : headers.entrySet()) {
+ request.addHeader(entry.getKey(), entry.getValue());
+ }
+ return request;
+ }
+
+ private static byte[] generateRandomKey() throws NoSuchAlgorithmException {
+ //实例化
+ KeyGenerator generator = KeyGenerator.getInstance("AES");
+ //设置密钥长度
+ generator.init(128);
+ //生成密钥
+ return generator.generateKey().getEncoded();
+ }
+
+
+ private static Map buildAuthHeaders(YopRequestMethod httpMethod,
+ String apiUri,
+ YopRequestContentType contentType,
+ Map queryParams,
+ Object bodyParams,
+ String encryptKey, Set encryptHeaders, Set encryptParams,
+ String yopPublicKey, String isvPrivateKey) throws Exception {
+ Map headers = new HashMap<>();
+ headers.put(YOP_SDK_LANGS, "java");
+ headers.put(YOP_SDK_VERSION, "4.0.0");
+ headers.put(YOP_APPKEY, APP_KEY);
+ headers.put(YOP_REQUEST_ID, UUID.randomUUID().toString());
+
+ // 加密头
+ if (null != encryptKey && null != encryptParams) {
+ headers.put(YOP_ENCRYPT, buildEncryptHeader(encryptHeaders, encryptParams, encryptKey, yopPublicKey));
+ }
+
+ // 摘要头
+ headers.put(YOP_CONTENT_SHA256, calculateContentSha256(httpMethod, contentType == YopRequestContentType.JSON, bodyParams));
+
+ // 签名头
+ headers.put(AUTHORIZATION, signRequest(httpMethod, apiUri, contentType, headers, queryParams, isvPrivateKey));
+ return headers;
+ }
+
+ private static String signRequest(YopRequestMethod requestMethod, String requestUri,
+ YopRequestContentType contentType,
+ Map headers,
+ Map queryParams,
+ String isvPrivateKey) throws Exception {
+ // 1.构造认证字符串
+ String authString = buildAuthString(APP_KEY, 1800);
+
+ // 2.获取规范请求方法
+ String httpRequestMethod = requestMethod.name();
+
+ // 3.获取规范请求URI
+ String canonicalURI = requestUri;
+
+ // 4.获取规范化查询字符串
+ String canonicalQueryString = buildCanonicalQueryString(requestMethod, contentType == YopRequestContentType.JSON,
+ queryParams);
+
+ // 5.获取规范请求头
+ String canonicalHeaders = buildCanonicalHeaders(headers);
+
+ // 6.获取规范请求串
+ StringBuilder canonicalRequest = new StringBuilder()
+ .append(authString)
+ .append("\n")
+ .append(httpRequestMethod)
+ .append("\n")
+ .append(canonicalURI)
+ .append("\n")
+ .append(canonicalQueryString)
+ .append("\n")
+ .append(canonicalHeaders);
+
+
+ // 7.计算签名
+ String signature = urlSafeEncode(encodeBase64(sign(canonicalRequest.toString().getBytes(DEFAULT_ENCODING), isvPrivateKey))) + "$" + "SHA256";
+
+ // 8.构建认证头
+ return buildAuthorizationHeader(authString, String.join(SEMICOLON, HEADERS_TO_SIGN), signature);
+ }
+
+ /**
+ * 构建认证头
+ *
+ * @param authString 认证字符串
+ * @param signedHeaders 已签名的请求头
+ * @param signature 签名结果
+ * @return 认证头值
+ */
+ public static String buildAuthorizationHeader(String authString, String signedHeaders, String signature) {
+ return DEFAULT_AUTH_PREFIX_RSA2048 + " " +
+ authString + SLASH +
+ signedHeaders + SLASH +
+ signature;
+ }
+
+ // 签名计算时至少包含这三个头
+ private static final List HEADERS_TO_SIGN = Arrays.asList(
+ "x-yop-appkey",
+ "x-yop-content-sha256",
+ "x-yop-request-id"
+ );
+
+ /**
+ * 构建规范请求头
+ */
+ private static String buildCanonicalHeaders(Map headers) {
+ if (headers == null || headers.isEmpty()) {
+ return EMPTY;
+ }
+
+ // 1. 转换头名称为小写并排序
+ List canonicalHeaders = new ArrayList<>();
+ for (Map.Entry entry : headers.entrySet()) {
+ String headerName = entry.getKey().toLowerCase().trim();
+ String headerValue = entry.getValue().trim();
+ if (HEADERS_TO_SIGN.contains(headerName)) {
+ canonicalHeaders.add(headerName + ":" + headerValue);
+ }
+ }
+ // 2. 排序
+ Collections.sort(canonicalHeaders);
+
+ // 3. 用\n连接所有签名头
+ return String.join("\n", canonicalHeaders);
+ }
+
+ /**
+ * 构建规范查询字符串
+ *
+ * @param queryParams 请求query参数
+ * @return 规范查询字符串
+ */
+ private static String buildCanonicalQueryString(YopRequestMethod httpMethod,
+ boolean isJsonRequest,
+ Map queryParams) {
+ // 针对POST请求,且内容类型为form,即application/x-www-form-urlencoded或者multipart/form-data的请求,返回空字符串
+ if (httpMethod == YopRequestMethod.POST && !isJsonRequest) {
+ return EMPTY;
+ }
+ // 参数编码&排序
+ return sortAndEncodeParams(queryParams);
+ }
+
+ public static byte[] sign(byte[] data, String isvPrivateKey) {
+ try {
+ Signature signature = Signature.getInstance(DEFAULT_SIGN_ALG);
+ signature.initSign(string2PrivateKey(isvPrivateKey));
+ signature.update(data);
+ return signature.sign();
+ } catch (Exception e) {
+ throw new RuntimeException("SystemError, Sign Fail, key:" + ISV_PRIVATE_KEY + ", ex:", e);
+ }
+ }
+
+ private static PrivateKey string2PrivateKey(String priKey) {
+ try {
+ return KeyFactory.getInstance(RSA).generatePrivate(
+ new PKCS8EncodedKeySpec(decodeBase64(priKey)));
+ } catch (Exception e) {
+ throw new RuntimeException("ConfigProblem, IsvPrivateKey ParseFail, value:" + priKey + ", ex:", e);
+ }
+ }
+
+ /**
+ * 构建认证字符串
+ *
+ * @param appKey 应用标识
+ * @param expiredSeconds 过期时间(秒)
+ * @return 认证字符串
+ */
+ public static String buildAuthString(String appKey, int expiredSeconds) {
+ // 1. 协议版本
+ String protocolVersion = DEFAULT_YOP_PROTOCOL_VERSION + SLASH;
+
+ // 2. 应用标识
+ String appKeyPart = appKey + SLASH;
+
+ // 3. ISO8601格式时间戳
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+ sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
+ String timestamp = sdf.format(new Date()) + SLASH;
+
+ // 4. 过期时间(秒)
+ String expired = String.valueOf(expiredSeconds);
+
+ // 5. 组合认证字符串
+ return protocolVersion + appKeyPart + timestamp + expired;
+ }
+
+ /**
+ * 计算请求摘要头
+ */
+ private static String calculateContentSha256(YopRequestMethod httpMethod,
+ boolean isJsonRequest,
+ Object bodyParams) {
+ // 针对GET请求,计算为空字符串
+ if (httpMethod == YopRequestMethod.GET) {
+ return sha256ToHex(EMPTY);
+ }
+
+ // 针对POST-JSON格式请求,计算整个json请求体
+ if (isJsonRequest) {
+ return sha256ToHex((String) bodyParams);
+ }
+
+ // 其他格式请求,仅计算非文件类参数
+ Map nonFileParams = new HashMap<>();
+ for (Map.Entry entry : ((Map) bodyParams).entrySet()) {
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ if (value != null && !isFileParam(value)) {
+ nonFileParams.put(key, value.toString());
+ }
+ }
+ return sha256ToHex(sortAndEncodeParams(nonFileParams));
+ }
+
+ /**
+ * 参数编码&排序
+ */
+ private static String sortAndEncodeParams(Map params) {
+ if (params == null || params.isEmpty()) {
+ return EMPTY;
+ }
+
+ // 1. 参数排序(按键名ASCII升序)
+ List paramNames = new ArrayList<>(params.keySet());
+ Collections.sort(paramNames);
+
+ // 2. 构建规范查询字符串
+ List queryParts = new ArrayList<>();
+ for (String name : paramNames) {
+ String value = params.get(name).toString();
+ // URL编码参数名和值
+ String encodedName = urlEncodeForSign(name);
+ String encodedValue = urlEncodeForSign(value);
+ queryParts.add(encodedName + "=" + encodedValue);
+ }
+
+ // 3. 用&连接所有参数对
+ return String.join("&", queryParts);
+ }
+
+ /**
+ * URL编码(签名版)
+ */
+ private static String urlEncodeForSign(String value) {
+ try {
+ return URLEncoder.encode(value, DEFAULT_ENCODING)
+ .replace("+", "%20")
+ .replace("*", "%2A")
+ .replace("%7E", "~");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("URL编码失败", e);
+ }
+ }
+
+ private static boolean isFileParam(Object value) {
+ return null != value && (value instanceof File || value instanceof InputStream || value instanceof FileParam);
+ }
+
+ /**
+ * 转json字符串
+ */
+ private static String toJsonString(Object bodyParams) {
+ try {
+ return OBJECT_MAPPER.writeValueAsString(bodyParams);
+ } catch (Exception e) {
+ throw new RuntimeException("toJsonString fail", e);
+ }
+ }
+
+ /**
+ * 计算sha256并转16进制字符串
+ */
+ private static String sha256ToHex(String content) {
+ try {
+ MessageDigest md = MessageDigest.getInstance(DEFAULT_DIGEST_ALG);
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(content.getBytes(DEFAULT_ENCODING));
+ DigestInputStream digestInputStream = new DigestInputStream(inputStream, md);
+ byte[] buffer = new byte[1024];
+ while (digestInputStream.read(buffer) > -1) {
+ }
+ byte[] digestBytes = digestInputStream.getMessageDigest().digest();
+ return encodeHex(digestBytes);
+ } catch (Exception e) {
+ throw new RuntimeException("sha256 fail", e);
+ }
+ }
+
+ private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+ private static String encodeHex(byte[] data) {
+ int l = data.length;
+ char[] out = new char[l << 1];
+ int i = 0;
+
+ for (int j = 0; i < l; ++i) {
+ out[j++] = DIGITS[(240 & data[i]) >>> 4];
+ out[j++] = DIGITS[15 & data[i]];
+ }
+
+ return new String(out);
+ }
+
+ /**
+ * 加密协议头(请求):
+ *
+ * yop-encrypt-v1/{服务端证书序列号}/{密钥类型(必填)}_{分组模式(必填)}_{填充算法(必填)}/{加密密钥值(必填)}/{IV}{;}{附加信息}/{客户端支持的大参数加密模式(必填)}/{encryptHeaders}/{encryptParams}
+ */
+ public static String buildEncryptHeader(Set encryptHeaders, Set encryptParams,
+ String encryptKey, String yopPublicKey) throws Exception {
+ if (null == encryptHeaders) {
+ encryptHeaders = Collections.emptySet();
+ }
+ if (null == encryptParams) {
+ encryptParams = Collections.emptySet();
+ }
+
+ return "yop-encrypt-v1" + SLASH +
+ EMPTY + SLASH + //rsa 为空
+ AES_ENCRYPT_ALG.replace(SLASH, UNDER_LINE) + SLASH +
+ urlSafeEncode(encodeBase64(encryptKey(decodeBase64(encryptKey), string2PublicKey(yopPublicKey)))) + SLASH +
+ EMPTY + SLASH +
+ STREAM + SLASH +
+ String.join(SEMICOLON, encryptHeaders) + SLASH +
+ urlSafeEncode(encodeBase64(String.join(SEMICOLON, encryptParams).getBytes(DEFAULT_ENCODING)));
+ }
+
+ private static byte[] encryptKey(byte[] data, Key key) {
+ Cipher cipher;
+ try {
+ cipher = Cipher.getInstance(RSA_ENCRYPT_ALG);
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ return cipher.doFinal(data);
+ } catch (Exception e) {
+ throw new RuntimeException("SystemError, Encrypt Fail, key:"
+ + key + ", cause:" + e.getMessage(), e);
+ }
+ }
+
+ private static String encryptParam(String aesKey, String plain) throws Exception {
+ final Cipher cipher = getInitializedCipher(Cipher.ENCRYPT_MODE, aesKey);
+ return urlSafeEncode(encodeBase64(cipher.doFinal(plain.getBytes(DEFAULT_ENCODING))));
+ }
+
+ private static Cipher getInitializedCipher(int mode, String aesKey) {
+ try {
+ byte[] key = decodeBase64(aesKey);
+ Cipher cipher = Cipher.getInstance(AES_ENCRYPT_ALG);
+ Key secretKey = new SecretKeySpec(key, "AES");
+ cipher.init(mode, secretKey);
+ return cipher;
+ } catch (Throwable throwable) {
+ throw new RuntimeException("error happened when initialize cipher", throwable);
+ }
+ }
+
+ public static PublicKey string2PublicKey(String pubKey) {
+ try {
+ return KeyFactory.getInstance(RSA).generatePublic(
+ new X509EncodedKeySpec(decodeBase64(pubKey)));
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+ throw new RuntimeException("ConfigProblem, YopPublicKey ParseFail, value:" + pubKey + ", ex:", e);
+ }
+ }
+
+ /**
+ * Base64 URL安全替换
+ * 将标准Base64中的'+'替换为'-','/'替换为'_'
+ *
+ * @param unSafeBase64Str 标准Base64编码字符串
+ * @return URL安全的Base64编码字符串
+ */
+ public static String urlSafeEncode(String unSafeBase64Str) {
+ if (unSafeBase64Str == null) {
+ return null;
+ }
+ return unSafeBase64Str.replace('+', '-')
+ .replace('/', '_');
+ }
+
+ /**
+ * Base64 URL解码转换
+ * 将URL安全Base64中的'-'替换回'+','_'替换回'/'
+ *
+ * @param safeBase64Str URL安全的Base64编码字符串
+ * @return 标准Base64编码字符串
+ */
+ public static String urlSafeDecode(String safeBase64Str) {
+ if (safeBase64Str == null) {
+ return null;
+ }
+ return safeBase64Str.replace('-', '+')
+ .replace('_', '/');
+ }
+
+ /**
+ * Base64 解码(非url安全)
+ *
+ * @param input
+ * @return
+ */
+ public static byte[] decodeBase64(String input) {
+ return Base64.getDecoder().decode(input);
+ }
+
+ /**
+ * Base64 编码(非url安全)
+ *
+ * @param input
+ * @return
+ */
+ public static String encodeBase64(byte[] input) {
+ return Base64.getEncoder().encodeToString(input);
+ }
+
+ public enum YopRequestMethod {
+ GET,
+ POST
+ }
+
+ public enum YopRequestType {
+ /**
+ * 普通请求,json返回
+ */
+ WEB,
+ /**
+ * 文件下载请求,返回文件流
+ */
+ FILE_DOWNLOAD,
+
+ /**
+ * 文件上传请求,返回json
+ */
+ MULTI_FILE_UPLOAD,
+ }
+
+ private static final String YOP_HTTP_CONTENT_TYPE_JSON = "application/json;charset=UTF-8";
+ private static final String YOP_HTTP_CONTENT_TYPE_FORM = "application/x-www-form-urlencoded;charset=UTF-8";
+ private static final String YOP_HTTP_CONTENT_TYPE_MULTIPART_FORM = "multipart/form-data";
+ private static final String YOP_HTTP_CONTENT_TYPE_STREAM = "application/octet-stream";
+ private static final String YOP_HTTP_CONTENT_TYPE_TEXT = "text/plain;charset=UTF-8";
+
+ public enum YopRequestContentType {
+ FORM_URL_ENCODE(YOP_HTTP_CONTENT_TYPE_FORM),
+ MULTIPART_FORM(YOP_HTTP_CONTENT_TYPE_MULTIPART_FORM),
+ JSON(YOP_HTTP_CONTENT_TYPE_JSON),
+ OCTET_STREAM(YOP_HTTP_CONTENT_TYPE_STREAM),
+ TEXT_PLAIN(YOP_HTTP_CONTENT_TYPE_TEXT);
+
+ private String value;
+
+ YopRequestContentType(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+ }
+
+ private static String randomFileName() {
+ return UUID.randomUUID() + ".bin";
+ }
+
+ public static class FileParam implements Serializable {
+ private static final long serialVersionUID = -1L;
+
+ // 文件流
+ private InputStream inputStream;
+
+ // 文件名
+ private String filaName = randomFileName();
+
+ public FileParam(InputStream inputStream) {
+ this.inputStream = inputStream;
+ }
+
+ // 本地文件
+ public FileParam(File file) throws FileNotFoundException {
+ this.inputStream = new FileInputStream(file);
+ this.filaName = file.getName();
+ }
+
+ // 文件流
+ public FileParam(InputStream inputStream, String filaName) {
+ this.inputStream = inputStream;
+ this.filaName = filaName;
+ }
+
+ // 远端文件
+ public FileParam(URL url, String filaName) throws IOException {
+ this.inputStream = url.openStream();
+ this.filaName = filaName;
+ }
+
+ public InputStream getInputStream() {
+ return inputStream;
+ }
+
+ public String getFilaName() {
+ return filaName;
+ }
+ }
+
+ public static class ApiResponse implements Serializable {
+ private static final long serialVersionUID = -1L;
+
+ private int statusCode;
+ private String requestId;
+ private Object rawContent;
+ private boolean success;
+ private Object result;
+ private ApiError error;
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public void setStatusCode(int statusCode) {
+ this.statusCode = statusCode;
+ }
+
+ public String getRequestId() {
+ return requestId;
+ }
+
+ public void setRequestId(String requestId) {
+ this.requestId = requestId;
+ }
+
+ public Object getRawContent() {
+ return rawContent;
+ }
+
+ public void setRawContent(Object rawContent) {
+ this.rawContent = rawContent;
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public void setSuccess(boolean success) {
+ this.success = success;
+ }
+
+ public Object getResult() {
+ return result;
+ }
+
+ public void setResult(Object result) {
+ this.result = result;
+ }
+
+ public ApiError getError() {
+ return error;
+ }
+
+ public void setError(ApiError error) {
+ this.error = error;
+ }
+
+ @Override
+ public String toString() {
+ return "ApiResponse{" +
+ "statusCode=" + statusCode +
+ ", requestId='" + requestId + '\'' +
+ ", rawContent='" + rawContent + '\'' +
+ ", success=" + success +
+ ", result=" + result +
+ ", error=" + error +
+ '}';
+ }
+ }
+
+ public static class ApiError implements Serializable {
+ private static final long serialVersionUID = -1L;
+ private String code;
+ private String message;
+ private String subCode;
+ private String subMessage;
+
+ public ApiError() {
+ }
+
+ public ApiError(String code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public String getSubCode() {
+ return subCode;
+ }
+
+ public void setSubCode(String subCode) {
+ this.subCode = subCode;
+ }
+
+ public String getSubMessage() {
+ return subMessage;
+ }
+
+ public void setSubMessage(String subMessage) {
+ this.subMessage = subMessage;
}
}
}
diff --git a/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/example/YopSM2EncryptExample.java b/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/example/YopSM2EncryptExample.java
new file mode 100644
index 00000000..8f625740
--- /dev/null
+++ b/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/example/YopSM2EncryptExample.java
@@ -0,0 +1,1233 @@
+/*
+ * Copyright: Copyright (c)2014
+ * Company: 易宝支付(YeePay)
+ */
+package com.yeepay.yop.sdk.example;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Joiner;
+import com.google.common.collect.*;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.methods.RequestBuilder;
+import org.apache.http.client.utils.HttpClientUtils;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.InputStreamEntity;
+import org.apache.http.entity.mime.HttpMultipartMode;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.CryptoException;
+import org.bouncycastle.crypto.engines.SM2Engine;
+import org.bouncycastle.crypto.params.*;
+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.math.ec.ECPoint;
+import org.bouncycastle.math.ec.custom.gm.SM2P256V1Curve;
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.KeyGenerator;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.*;
+import java.math.BigInteger;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.file.Files;
+import java.security.*;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.*;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * title: SM2 加密示例
+ * description: 描述
+ * Copyright: Copyright (c)2014
+ * Company: 易宝支付(YeePay)
+ *
+ * @author wdc
+ * @version 1.0.0
+ * @since 2023/9/27
+ */
+public class YopSM2EncryptExample {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(YopSM2EncryptExample.class);
+ static {
+ try {
+ if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ LOGGER.debug("BouncyCastleProvider added");
+ } catch (Exception e) {
+ LOGGER.warn("error when add BouncyCastleProvider", e);
+ }
+ }
+
+ private static final CloseableHttpClient httpClient;
+ static {
+ // 自定义连接池大小、默认超时时间
+ httpClient = HttpClients.custom()
+ .setMaxConnPerRoute(100)
+ .setMaxConnTotal(200)
+ .setDefaultRequestConfig(
+ RequestConfig.custom()
+ .setConnectionRequestTimeout(3000)
+ .setConnectTimeout(3000)
+ .setSocketTimeout(30000)
+ .build())
+ .build();
+ }
+
+ private static final String APP_KEY = "sandbox_sm_10080041523";
+ private static final BCECPrivateKey ISV_PRIVATE_KEY = string2PrivateKey("MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgr0mQ3/jjQOczWI6bnJFdqF4D/DFYHaqXftqXU/jGKpCgCgYIKoEcz1UBgi2hRANCAAQPpkZNnOnXTCXOIHJbfR+i6ea1QkM8HxkdO8KSWK8IgltHZxr5xlxiqR8inOREmmrxUQQagOH5i3oELWgXZz8G");
+ private static final String YOP_PUBLIC_KEY_SERIAL_NO = "4059376239";
+ // 注意:此处为测试环境国密证书,生产环境请联系技术支持获取
+ private static final BCECPublicKey YOP_PUBLIC_KEY = string2PublicKey("MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEStsxeNDxhJzM61Uy0rCmnW9Zs4Ze7oIKX27dgFTB7FsTsiCEzvxD7OTCKd7F17Xa1vpJ07C+2+H2OOFBSyadZA==");
+ private static final Map YOP_PUBLIC_KEY_MAP = Collections.singletonMap(YOP_PUBLIC_KEY_SERIAL_NO, YOP_PUBLIC_KEY);
+ private static final String SERVER_ROOT = "https://sandbox.yeepay.com/yop-center";
+ private static final String SLASH = "/";
+ private static final String UNDER_LINE = "_";
+ private static final String SEMICOLON = ";";
+ private static final String EMPTY = "";
+
+
+
+ private static final String SM4_CBC_PKCS5PADDING = "SM4/CBC/PKCS5Padding";
+ private static final byte[] SM4_IV = new SecureRandom().generateSeed(16);
+
+ private static final String STREAM = "stream";
+ private static final String DEFAULT_ENCODING = "UTF-8";
+ private static final String DEFAULT_YOP_PROTOCOL_VERSION = "yop-auth-v3";
+ public static final String DEFAULT_AUTH_PREFIX_SM2 = "YOP-SM2-SM3";
+ private static final String DEFAULT_DIGEST_ALG = "SM3";
+ private static final Joiner QUERY_STRING_JOINER = Joiner.on('&');
+
+ // mode 指定密文结构,旧标准的为C1C2C3,新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2
+ // 注意:我们采用C1C3C2,如果bcprov-jdk15on包版本太低(小于1.62),则【不支持报文参数加密】
+ private static final boolean BIZ_PARAM_ENCRYPT_SUPPORTED = false;// 当前环境是否支持参数加密
+ // 根据mode不同,输出的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。
+ private static final ThreadLocal engineThreadLocal = new ThreadLocal() {
+ @Override
+ protected SM2Engine initialValue() {
+ // bcprov-jdk15on包版本太低(小于1.62时),不支持报文参数加密
+ if (!BIZ_PARAM_ENCRYPT_SUPPORTED) {
+ return new SM2Engine();
+ } else {
+ //return new SM2Engine(SM2Engine.Mode.C1C3C2);
+ }
+ return null;
+ }
+ };
+
+
+
+
+ public static void main(String[] args) throws Exception {
+ // 加密会话密钥,可每笔调用都生成,也可以多笔公用一个,建议定时更换
+ String encryptKey = encodeUrlSafeBase64(generateRandomKey());
+
+ // 注意:以下分别展示了不同请求方式的参数构造、加密、解密、验签的完整流程,请根据接口实际情况进行选择
+
+ // get请求,form参数
+ getFormExample(YopRequestMethod.GET, "/rest/v1.0/test/errorcode2",
+ YopRequestContentType.FORM_URL_ENCODE, encryptKey);
+
+ //post请求,form参数
+ postFormExample(YopRequestMethod.POST, "/rest/v1.0/frontcashier/agreement/sign/confirm",
+ YopRequestContentType.FORM_URL_ENCODE, encryptKey);
+
+ // post请求,文件参数
+ postMultipartFormExample(YopRequestMethod.POST, "/yos/v1.0/sys/merchant/qual/upload",
+ YopRequestContentType.MULTIPART_FORM, encryptKey);
+
+ // post请求,json参数
+ postJsonExample(YopRequestMethod.POST, "/rest/v1.0/test-wdc/test/http-json/test",
+ YopRequestContentType.JSON, encryptKey);
+
+ // get请求,form参数,下载文件
+ downloadExample(YopRequestMethod.GET, "/yos/v1.0/test/test/ceph-download",
+ YopRequestContentType.FORM_URL_ENCODE, encryptKey);
+ }
+
+ private static void getFormExample(YopRequestMethod requestMethod, String requestUri,
+ YopRequestContentType requestContentType,
+ String encryptKey) throws Exception {
+ // 请求参数
+ Multimap formParams = ArrayListMultimap.create();
+ Set encryptHeaders = Collections.emptySet();
+ Set encryptParams = Sets.newHashSet();
+
+ // 注意:以下两个代码块分别展示了加密、不加密两种示例,请根据情况选择其一
+
+ // 参数不加密-------------->开始
+// formParams.put("errorCode", "000027");
+ // 参数不加密-------------->结束
+
+ // 参数加密-------------->开始
+ formParams.put("errorCode", encryptParam(encryptKey, "000027"));
+ encryptParams.add("errorCode");
+ // 参数加密-------------->结束
+
+ // 请求头
+ Map headers = buildHeaders(requestMethod, requestUri, formParams,
+ requestContentType, "", encryptKey, encryptHeaders, encryptParams);
+
+ // 构造http请求
+ HttpUriRequest request = buildHttpRequest(SERVER_ROOT + requestUri,
+ requestMethod, headers, formParams, null);
+
+ // 发起http调用
+ CloseableHttpResponse response = null;
+ try {
+ response = httpClient.execute(request);
+ handleResponse(YopRequestType.WEB, response, encryptKey);
+ } finally {
+ HttpClientUtils.closeQuietly(response);
+ }
+ }
+
+
+ private static Map buildHeaders(YopRequestMethod httpMethod, String apiUri,
+ Multimap params,
+ YopRequestContentType contentType, String content,
+ String encryptKey, Set encryptHeaders, Set encryptParams) throws Exception {
+ Map headers = new HashMap<>();
+ headers.put(YOP_SDK_LANGS, "java");
+ headers.put(YOP_SDK_VERSION, "4.3.0");
+ headers.put(YOP_APPKEY, APP_KEY);
+ headers.put(YOP_REQUEST_ID, UUID.randomUUID().toString());
+
+ // 加密头:请求参数不加密的情况, 也需设置加密头,用于响应结果加密
+ if (BIZ_PARAM_ENCRYPT_SUPPORTED) {
+ headers.put(YOP_ENCRYPT, buildEncryptHeader(encryptHeaders, encryptParams, encryptKey));
+ }
+
+ // 摘要头
+ headers.put(YOP_CONTENT_SM3, calculateContentHash(httpMethod, contentType, params, content));
+
+ // 签名头
+ headers.put(AUTHORIZATION, signRequest(httpMethod, apiUri, headers, params));
+ return headers;
+ }
+
+ private static void postFormExample(YopRequestMethod requestMethod, String requestUri,
+ YopRequestContentType requestContentType,
+ String encryptKey) throws Exception {
+
+ // 请求参数
+ Multimap params = ArrayListMultimap.create();
+ Set encryptHeaders = Collections.emptySet();
+ Set encryptParams = Sets.newHashSet();
+
+ // 注意:以下两个代码块分别展示了加密、不加密两种示例,请根据情况选择其一
+
+ // 参数不加密-------------->开始
+ params.put("parentMerchant", "10080041523");
+ params.put("merchantNo", "10080041523");
+ params.put("smsCode", "11111131");
+ params.put("merchantFlowId", "11111131");
+ // 参数不加密-------------->结束
+
+
+ // 参数加密-------------->开始
+// params.put("parentMerchant", encryptParam(encryptKey , "10080041523" ));
+// params.put("merchantNo", encryptParam(encryptKey , "10080041523" ));
+// params.put("smsCode", encryptParam(encryptKey , "11111131" ));
+// params.put("merchantFlowId", encryptParam(encryptKey , "111111" ));
+// encryptParams.add("parentMerchant");
+// encryptParams.add("merchantNo");
+// encryptParams.add("smsCode");
+// encryptParams.add("merchantFlowId");
+ // 参数加密-------------->结束
+
+ // 请求头
+ Map headers = buildHeaders(requestMethod, requestUri, params,
+ requestContentType, "", encryptKey, encryptHeaders, encryptParams);
+
+ // 构造http请求
+ HttpUriRequest request = buildHttpRequest(SERVER_ROOT + requestUri,
+ requestMethod, headers, params, null);
+
+ // 发起http调用
+ CloseableHttpResponse response = null;
+ try {
+ response = httpClient.execute(request);
+ handleResponse(YopRequestType.WEB, response, encryptKey);
+ } finally {
+ HttpClientUtils.closeQuietly(response);
+ }
+ }
+
+ private static void postMultipartFormExample(YopRequestMethod requestMethod, String requestUri,
+ YopRequestContentType requestContentType, String encryptKey) throws Exception {
+
+
+ // 普通参数参与签名,clientId
+ Multimap params = ArrayListMultimap.create();
+ Set encryptHeaders = Collections.emptySet();
+ Set encryptParams = Sets.newHashSet();
+
+ // 注意:以下两个代码块分别展示了加密、不加密两种示例,请根据情况选择其一
+
+ // 参数不加密--------------->开始
+ params.put("clientId", APP_KEY);
+ // 参数不加密--------------->结束
+
+ // 参数加密--------------->开始
+// params.put("clientId", encryptParam(encryptKey, APP_KEY));
+// encryptParams.add("clientId");
+ // 参数加密--------------->结束
+
+ // 请求头
+ Map headers = buildHeaders(requestMethod, requestUri, params,
+ requestContentType, "", encryptKey, encryptHeaders, encryptParams);
+
+ // 构造http请求
+ HttpPost postMethod = new HttpPost(SERVER_ROOT + requestUri);
+ MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+ builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
+
+ // 添加普通参数
+ for (Map.Entry> entry : params.asMap().entrySet()) {
+ String paramKey = entry.getKey();
+ for (String value : entry.getValue()) {
+ builder.addTextBody(normalize(paramKey), normalize(value));
+ }
+ }
+
+ // 注意:以下两个代码块分别展示了本地文件、远程文件两种示例,请根据情况选择其一
+ // 添加文件参数,merQual
+ // 方式一:本地文件流
+// builder.addBinaryBody("merQual", new FileInputStream("abc.txt"),
+// ContentType.DEFAULT_BINARY, "abc.txt");
+ // 方式二:远程文件流
+ builder.addBinaryBody("merQual", new URL("https://open.yeepay.com/apis/docs/apis/common/ALL.json").openStream(),
+ ContentType.DEFAULT_BINARY, "abc.txt");
+
+ postMethod.setEntity(builder.build());
+
+ // 添加请求头
+ for (Map.Entry entry : headers.entrySet()) {
+ postMethod.addHeader(entry.getKey(), entry.getValue());
+ }
+
+ // 发起http调用
+ CloseableHttpResponse response = null;
+ try {
+ response = httpClient.execute(postMethod);
+ handleResponse(YopRequestType.WEB, response, encryptKey);
+ } finally {
+ HttpClientUtils.closeQuietly(response);
+ }
+
+ }
+
+ private static void postJsonExample(YopRequestMethod requestMethod, String requestUri,
+ YopRequestContentType requestContentType,
+ String encryptKey) throws Exception {
+ Set encryptHeaders = Collections.emptySet();
+ Set encryptParams = Sets.newHashSet();
+
+ String plainJsonContent = "{\n" +
+ " \"arg1\" : {\n" +
+ " \"appId\" : \"app_1111111111\",\n" +
+ " \"customerNo\" : \"333333333\"\n" +
+ " },\n" +
+ " \"arg0\" : {\n" +
+ " \"string\" : \"hello\",\n" +
+ " \"array\" : [ \"test\" ]\n" +
+ " }\n" +
+ "}",
+ encryptJsonContent = encryptParam(encryptKey, plainJsonContent);
+
+ // 注意:以下两个代码块分别展示了加密、不加密两种示例,请根据情况选择其一
+ String finalJsonContent
+ // 不加密------------------->开始
+ = plainJsonContent;
+ // 不加密------------------->结束
+
+
+ // 加密-------------------->开始
+// = encryptJsonContent;
+// encryptParams.add("$"); // 目前json推荐整体加密,$代表整体加密
+ // 加密-------------------->结束
+
+ // 请求头
+ // 目前不允许json接口带有form参数,置空即可
+ final ArrayListMultimap params = ArrayListMultimap.create();
+ Map headers = buildHeaders(requestMethod, requestUri, params,
+ requestContentType, finalJsonContent, encryptKey, encryptHeaders, encryptParams);
+
+ // 构造http请求
+ HttpUriRequest request = buildHttpRequest(SERVER_ROOT + requestUri,
+ requestMethod, headers, params, finalJsonContent);
+
+ // 发起http调用
+ CloseableHttpResponse response = null;
+ try {
+ response = httpClient.execute(request);
+ handleResponse(YopRequestType.WEB, response, encryptKey);
+ } finally {
+ HttpClientUtils.closeQuietly(response);
+ }
+ }
+
+ private static void downloadExample(YopRequestMethod requestMethod, String requestUri,
+ YopRequestContentType requestContentType,
+ String encryptKey) throws Exception {
+
+ // 根据实际情况来,【文件下载接口】可能是post方法,请求报文可能是form,也可能是json,可参考其他方式的入参处理
+ // 此处仅演示文件响应流的处理
+
+ // 请求参数
+ Multimap params = ArrayListMultimap.create();
+ Set encryptHeaders = Collections.emptySet();
+ Set encryptParams = Sets.newHashSet();
+
+ // 注意:以下两个代码块分别展示了加密、不加密两种示例,请根据情况选择其一
+ // 不加密------------------->开始
+ params.put("fileName", "wym-test.txt");
+ // 不加密------------------->结束
+
+ // 加密--------------------->开始
+// params.put("fileName", encryptParam(encryptKey, "wym-test.txt"));
+// encryptParams.add("fileName");
+ // 加密--------------------->结束
+
+ // 请求头
+ Map headers = buildHeaders(requestMethod, requestUri, params,
+ requestContentType, "", encryptKey, encryptHeaders, encryptParams);
+
+ // 构造http请求
+ HttpUriRequest request = buildHttpRequest(SERVER_ROOT + requestUri,
+ requestMethod, headers, params, "");
+
+ // 发起请求
+ CloseableHttpResponse response = null;
+ try {
+ response = httpClient.execute(request);
+ handleResponse(YopRequestType.FILE_DOWNLOAD, response, encryptKey);
+ } finally {
+ HttpClientUtils.closeQuietly(response);
+ }
+ }
+
+ private static final Set DEFAULT_HEADERS_TO_SIGN = Sets.newHashSet();
+ private static final Joiner HEADER_JOINER = Joiner.on('\n');
+ private static final Joiner SIGNED_HEADER_STRING_JOINER = Joiner.on(';');
+
+ private static final String YOP_SDK_VERSION = "x-yop-sdk-version";
+ private static final String YOP_SDK_LANGS = "x-yop-sdk-langs";
+ private static final String YOP_REQUEST_ID = "x-yop-request-id";
+ private static final String YOP_APPKEY = "x-yop-appkey";
+ private static final String YOP_CONTENT_SM3 = "x-yop-content-sm3";
+ private static final String YOP_ENCRYPT = "x-yop-encrypt";
+ private static final String AUTHORIZATION = "Authorization";
+ private static final String CONTENT_DISPOSITION = "Content-Disposition";
+ private static final String CONTENT_TYPE = "Content-Type";
+
+ static {
+ DEFAULT_HEADERS_TO_SIGN.add(YOP_REQUEST_ID);
+ DEFAULT_HEADERS_TO_SIGN.add(YOP_APPKEY);
+ DEFAULT_HEADERS_TO_SIGN.add(YOP_CONTENT_SM3);
+ DEFAULT_HEADERS_TO_SIGN.add(YOP_ENCRYPT);
+ }
+
+ private static String signRequest(YopRequestMethod requestMethod, String requestUri,
+ Map headers, Multimap params) throws Exception {
+ // A.构造认证字符串
+ String authString = buildAuthString();
+
+ // B.获取规范请求串
+ SortedMap headersToSign = getHeadersToSign(headers, DEFAULT_HEADERS_TO_SIGN);
+ String canonicalRequest = buildCanonicalRequest(requestMethod, requestUri, params, authString, headersToSign);
+
+ // C.计算签名
+ String signature = encodeUrlSafeBase64(sign(canonicalRequest.getBytes(DEFAULT_ENCODING))) + "$" + DEFAULT_DIGEST_ALG;
+
+ // D.添加认证头
+ return buildAuthHeader(authString, headersToSign, signature);
+ }
+
+ private static String buildAuthHeader(String authString,
+ SortedMap headersToSign,
+ String signature) {
+ String signedHeaders = SIGNED_HEADER_STRING_JOINER.join(headersToSign.keySet());
+ signedHeaders = signedHeaders.trim().toLowerCase();
+ return DEFAULT_AUTH_PREFIX_SM2 + " " + authString + "/" + signedHeaders + "/" + signature;
+ }
+
+ // SM2
+ public static final SM2P256V1Curve CURVE = new SM2P256V1Curve();
+ public final static BigInteger SM2_ECC_N = CURVE.getOrder();
+ public final static BigInteger SM2_ECC_H = CURVE.getCofactor();
+ public final static BigInteger SM2_ECC_GX = new BigInteger(
+ "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16);
+ public final static BigInteger SM2_ECC_GY = new BigInteger(
+ "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16);
+ public static final ECPoint G_POINT = CURVE.createPoint(SM2_ECC_GX, SM2_ECC_GY);
+ public static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters(CURVE, G_POINT,
+ SM2_ECC_N, SM2_ECC_H);
+ public static final int CURVE_LEN = getCurveLength(DOMAIN_PARAMS);
+ public static int getCurveLength(ECDomainParameters domainParams) {
+ return (domainParams.getCurve().getFieldSize() + 7) / 8;
+ }
+
+ private static byte[] sign(byte[] data) {
+ try {
+ ECParameterSpec parameterSpec = ISV_PRIVATE_KEY.getParameters();
+ ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
+ parameterSpec.getN(), parameterSpec.getH());
+ ECPrivateKeyParameters priKeyParameters = new ECPrivateKeyParameters(ISV_PRIVATE_KEY.getD(), domainParameters);
+ //der编码后的签名值
+ byte[] derSign = sign(priKeyParameters, null, data);
+
+ //der解码过程
+ ASN1Sequence as = DERSequence.getInstance(derSign);
+ byte[] rBytes = ((ASN1Integer) as.getObjectAt(0)).getValue().toByteArray();
+ byte[] sBytes = ((ASN1Integer) as.getObjectAt(1)).getValue().toByteArray();
+ //由于大数的补0规则,所以可能会出现33个字节的情况,要修正回32个字节
+ rBytes = fixToCurveLengthBytes(rBytes);
+ sBytes = fixToCurveLengthBytes(sBytes);
+ byte[] rawSign = new byte[rBytes.length + sBytes.length];
+ System.arraycopy(rBytes, 0, rawSign, 0, rBytes.length);
+ System.arraycopy(sBytes, 0, rawSign, rBytes.length, sBytes.length);
+ return rawSign;
+ } catch (Exception e) {
+ throw new RuntimeException("SystemError, Sign Fail, key:" + ISV_PRIVATE_KEY + ", ex:", e);
+ }
+ }
+
+ private static boolean verifySign(String content, String signature, BCECPublicKey publicKey) {
+ try {
+ byte[] srcData = content.getBytes(DEFAULT_ENCODING);
+ byte[] signData = decodeBase64(signature);
+ ECParameterSpec parameterSpec = publicKey.getParameters();
+ ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
+ parameterSpec.getN(), parameterSpec.getH());
+ ECPublicKeyParameters pubKeyParameters = new ECPublicKeyParameters(publicKey.getQ(), domainParameters);
+ return verify(pubKeyParameters, null, srcData, encodeSM2SignToDER(signData));
+ } catch (IOException e) {
+ throw new RuntimeException("UnexpectedError, VerifySign Fail, data:" +
+ content + ", sign:" + signature + ", key:" + publicKey + ", ex:", e);
+ }
+ }
+
+ /**
+ * 把64字节的纯R+S字节数组编码成DER编码
+ *
+ * @param rawSign 64字节数组形式的SM2签名值,前32字节为R,后32字节为S
+ * @return DER编码后的SM2签名值
+ * @throws IOException
+ */
+ private static byte[] encodeSM2SignToDER(byte[] rawSign) throws IOException {
+ //要保证大数是正数
+ BigInteger r = new BigInteger(1, extractBytes(rawSign, 0, 32));
+ BigInteger s = new BigInteger(1, extractBytes(rawSign, 32, 32));
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ v.add(new ASN1Integer(r));
+ v.add(new ASN1Integer(s));
+ return new DERSequence(v).getEncoded(ASN1Encoding.DER);
+ }
+
+ private static byte[] extractBytes(byte[] src, int offset, int length) {
+ byte[] result = new byte[length];
+ System.arraycopy(src, offset, result, 0, result.length);
+ return result;
+ }
+
+ /**
+ * 验签
+ *
+ * @param pubKeyParameters 公钥
+ * @param withId 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes()
+ * @param srcData 原文
+ * @param sign DER编码的签名值
+ * @return 验签成功返回true,失败返回false
+ */
+ public static boolean verify(ECPublicKeyParameters pubKeyParameters, byte[] withId, byte[] srcData, byte[] sign) {
+ SM2Signer signer = new SM2Signer();
+ CipherParameters param;
+ if (withId != null) {
+ param = new ParametersWithID(pubKeyParameters, withId);
+ } else {
+ param = pubKeyParameters;
+ }
+ signer.init(false, param);
+ signer.update(srcData, 0, srcData.length);
+ return signer.verifySignature(sign);
+ }
+
+ private static byte[] fixToCurveLengthBytes(byte[] src) {
+ if (src.length == CURVE_LEN) {
+ return src;
+ }
+
+ byte[] result = new byte[CURVE_LEN];
+ if (src.length > CURVE_LEN) {
+ System.arraycopy(src, src.length - result.length, result, 0, result.length);
+ } else {
+ System.arraycopy(src, 0, result, result.length - src.length, src.length);
+ }
+ return result;
+ }
+
+ /**
+ * 签名
+ *
+ * @param priKeyParameters 私钥
+ * @param withId 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes()
+ * @param srcData 源数据
+ * @return DER编码后的签名值
+ * @throws CryptoException
+ */
+ public static byte[] sign(ECPrivateKeyParameters priKeyParameters, byte[] withId, byte[] srcData)
+ throws CryptoException {
+ SM2Signer signer = new SM2Signer();
+ CipherParameters param;
+ ParametersWithRandom pwr = new ParametersWithRandom(priKeyParameters, new SecureRandom());
+ if (withId != null) {
+ param = new ParametersWithID(pwr, withId);
+ } else {
+ param = pwr;
+ }
+ signer.init(true, param);
+ signer.update(srcData, 0, srcData.length);
+ return signer.generateSignature();
+ }
+
+ private static BCECPrivateKey string2PrivateKey(String priKey) {
+ try {
+ return (BCECPrivateKey)KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME).generatePrivate(
+ new PKCS8EncodedKeySpec(decodeBase64(priKey)));
+ } catch (Exception e) {
+ throw new RuntimeException("ConfigProblem, IsvPrivateKey ParseFail, value:" + priKey + ", ex:", e);
+ }
+ }
+
+ private static byte[] decodeBase64(String input) {
+ return Base64.decodeBase64(input);
+ }
+
+ private static String buildCanonicalRequest(YopRequestMethod httpMethod, String apiUri, Multimap params,
+ String authString,
+ SortedMap headersToSign) {
+ String canonicalQueryString;
+ if (YopRequestMethod.GET.equals(httpMethod) && null != params) {
+ canonicalQueryString = getCanonicalQueryString(params, true);
+ } else {
+ canonicalQueryString = "";// post from 与json时,均为空,此处先简单处理
+ }
+ String canonicalHeaders = getCanonicalHeaders(headersToSign);
+
+ String canonicalURI = getCanonicalURIPath(apiUri);
+ return authString + "\n"
+ + httpMethod.name() + "\n"
+ + canonicalURI + "\n"
+ + canonicalQueryString + "\n"
+ + canonicalHeaders;
+ }
+
+ private static String getCanonicalURIPath(String path) {
+ if (path == null) {
+ return "/";
+ } else if (path.startsWith("/")) {
+ return normalizePath(path);
+ } else {
+ return "/" + normalizePath(path);
+ }
+ }
+
+ private static String normalizePath(String path) {
+ return normalize(path).replace("%2F", "/");
+ }
+
+ private static SortedMap getHeadersToSign(Map headers, Set headersToSign) {
+ SortedMap ret = Maps.newTreeMap();
+ if (headersToSign != null) {
+ Set tempSet = Sets.newHashSet();
+ for (String header : headersToSign) {
+ tempSet.add(header.trim().toLowerCase());
+ }
+ headersToSign = tempSet;
+ }
+ for (Map.Entry entry : headers.entrySet()) {
+ String key = entry.getKey();
+ if (entry.getValue() != null && !entry.getValue().isEmpty()) {
+ if ((headersToSign != null && headersToSign.contains(key.toLowerCase())
+ && !AUTHORIZATION.equalsIgnoreCase(key))) {
+ ret.put(key, entry.getValue());
+ }
+ }
+ }
+ return ret;
+ }
+
+ private static String getCanonicalHeaders(SortedMap headers) {
+ if (headers.isEmpty()) {
+ return "";
+ }
+
+ List headerStrings = Lists.newArrayList();
+ for (Map.Entry entry : headers.entrySet()) {
+ String key = entry.getKey();
+ if (key == null) {
+ continue;
+ }
+ String value = entry.getValue();
+ if (value == null) {
+ value = "";
+ }
+ headerStrings.add(normalize(key.trim().toLowerCase()) + ':' + normalize(value.trim()));
+ }
+ Collections.sort(headerStrings);
+
+ return HEADER_JOINER.join(headerStrings);
+ }
+
+ private static final DateTimeFormatter alternateIso8601DateFormat =
+ ISODateTimeFormat.dateTimeNoMillis().withZone(DateTimeZone.UTC);
+
+ private static String buildAuthString() {
+ Date timestamp = new Date();
+ return DEFAULT_YOP_PROTOCOL_VERSION + "/"
+ + APP_KEY + "/"
+ + alternateIso8601DateFormat.print(new DateTime(timestamp)) + "/"
+ + "1800";
+ }
+
+ private static String calculateContentHash(String jsonContent) throws Exception {
+ InputStream contentStream = getContentStream(jsonContent);
+ return Hex.encodeHexString((digest(contentStream)));
+ }
+
+ private static String calculateContentHash(YopRequestMethod requestMethod, YopRequestContentType requestContentType,
+ Multimap params, String content) throws Exception {
+ String digestSource;
+
+ if (requestMethod.equals(YopRequestMethod.GET)) {
+ digestSource = "";
+ } else if (requestMethod.equals(YopRequestMethod.POST)
+ && requestContentType.equals(YopRequestContentType.JSON)) {
+ digestSource = content;
+ } else {
+ digestSource = getCanonicalQueryString(params, true);
+ }
+ InputStream contentStream = getContentStream(digestSource);
+ return Hex.encodeHexString((digest(contentStream)));
+ }
+
+ private static ByteArrayInputStream getContentStream(Multimap params) throws Exception {
+ return getContentStream(getCanonicalQueryString(params, true));
+ }
+
+ private static ByteArrayInputStream getContentStream(String paramStr) throws Exception {
+ byte[] bytes;
+ if (StringUtils.isEmpty(paramStr)) {
+ bytes = new byte[0];
+ } else {
+ bytes = paramStr.getBytes(DEFAULT_ENCODING);
+ }
+ return new ByteArrayInputStream(bytes);
+ }
+
+ public static String getCanonicalQueryString(Multimap params, boolean forSignature) {
+ Map> parameters;
+ if (null == params || (parameters = params.asMap()).isEmpty()) {
+ return "";
+ }
+
+ List parameterStrings = Lists.newArrayList();
+ for (Map.Entry> entry : parameters.entrySet()) {
+ if (forSignature && AUTHORIZATION.equalsIgnoreCase(entry.getKey())) {
+ continue;
+ }
+ String key = entry.getKey();
+ checkNotNull(key, "parameter key should not be null");
+ Collection value = entry.getValue();
+ if (value == null) {
+ if (forSignature) {
+ parameterStrings.add(normalize(key) + '=');
+ } else {
+ parameterStrings.add(normalize(key));
+ }
+ } else {
+ for (String item : value) {
+ parameterStrings.add(normalize(key) + '=' + normalize(item));
+ }
+ }
+ }
+ Collections.sort(parameterStrings);
+
+ return QUERY_STRING_JOINER.join(parameterStrings);
+ }
+
+ private static final BitSet URI_UNRESERVED_CHARACTERS = new BitSet();
+ private static final String[] PERCENT_ENCODED_STRINGS = new String[256];
+
+ static {
+ /*
+ * StringBuilder pattern = new StringBuilder();
+ *
+ * pattern .append(Pattern.quote("+")) .append("|") .append(Pattern.quote("*")) .append("|")
+ * .append(Pattern.quote("%7E")) .append("|") .append(Pattern.quote("%2F"));
+ *
+ * ENCODED_CHARACTERS_PATTERN = Pattern.compile(pattern.toString());
+ */
+ for (int i = 'a'; i <= 'z'; i++) {
+ URI_UNRESERVED_CHARACTERS.set(i);
+ }
+ for (int i = 'A'; i <= 'Z'; i++) {
+ URI_UNRESERVED_CHARACTERS.set(i);
+ }
+ for (int i = '0'; i <= '9'; i++) {
+ URI_UNRESERVED_CHARACTERS.set(i);
+ }
+ URI_UNRESERVED_CHARACTERS.set('-');
+ URI_UNRESERVED_CHARACTERS.set('.');
+ URI_UNRESERVED_CHARACTERS.set('_');
+ URI_UNRESERVED_CHARACTERS.set('~');
+
+ for (int i = 0; i < PERCENT_ENCODED_STRINGS.length; ++i) {
+ PERCENT_ENCODED_STRINGS[i] = String.format("%%%02X", i);
+ }
+ }
+
+ public static String normalize(String value) {
+ try {
+ StringBuilder builder = new StringBuilder();
+ for (byte b : value.getBytes(DEFAULT_ENCODING)) {
+ if (URI_UNRESERVED_CHARACTERS.get(b & 0xFF)) {
+ builder.append((char) b);
+ } else {
+ builder.append(PERCENT_ENCODED_STRINGS[b & 0xFF]);
+ }
+ }
+ return builder.toString();
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static byte[] digest(InputStream input) {
+ try {
+ MessageDigest md = MessageDigest.getInstance(DEFAULT_DIGEST_ALG, BouncyCastleProvider.PROVIDER_NAME);
+ DigestInputStream digestInputStream = new DigestInputStream(input, md);
+ byte[] buffer = new byte[1024];
+ while (digestInputStream.read(buffer) > -1) {}
+ return digestInputStream.getMessageDigest().digest();
+ } catch (Exception e) {
+ throw new RuntimeException("SystemError, Digest Fail, alg:" + DEFAULT_DIGEST_ALG + ", ex:", e);
+ }
+ }
+
+ /**
+ * 加密协议头(请求):
+ *
+ * yop-encrypt-v1/{服务端证书序列号}/{密钥类型(必填)}_{分组模式(必填)}_{填充算法(必填)}/{加密密钥值(必填)}/{IV}{;}{附加信息}/{客户端支持的大参数加密模式(必填)}/{encryptHeaders}/{encryptParams}
+ */
+ public static String buildEncryptHeader(Set encryptHeaders, Set encryptParams,
+ String sm4Key) throws Exception {
+
+ return "yop-encrypt-v1" + SLASH +
+ YOP_PUBLIC_KEY_SERIAL_NO + SLASH + //平台SM2证书序列号
+ StringUtils.replace(SM4_CBC_PKCS5PADDING, SLASH, UNDER_LINE) + SLASH +
+ encodeUrlSafeBase64(encryptKey(decodeBase64(sm4Key))) + SLASH +
+ encodeUrlSafeBase64(SM4_IV) + SEMICOLON + EMPTY + SLASH +
+ STREAM + SLASH +
+ StringUtils.join(encryptHeaders, SEMICOLON) + SLASH +
+ encodeUrlSafeBase64(StringUtils.join(encryptParams, SEMICOLON).getBytes(DEFAULT_ENCODING));
+ }
+
+ public static BCECPublicKey string2PublicKey(String pubKey) {
+ try {
+ return (BCECPublicKey) KeyFactory.getInstance("EC").generatePublic(
+ new X509EncodedKeySpec(decodeBase64(pubKey)));
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+ throw new RuntimeException("ConfigProblem, YopPublicKey ParseFail, value:" + pubKey + ", ex:", e);
+ }
+ }
+
+ private static byte[] encryptKey(byte[] sm4Key) {
+ try {
+ SM2Engine engine = engineThreadLocal.get();
+ ECPublicKeyParameters pubKeyParameters = convertPublicKeyToParameters();
+ ParametersWithRandom pwr = new ParametersWithRandom(pubKeyParameters, new SecureRandom());
+ engine.init(true, pwr);
+ return engine.processBlock(sm4Key, 0, sm4Key.length);
+ } catch (Throwable e) {
+ throw new RuntimeException("SystemError, Encrypt Fail, publicKey:"
+ + YOP_PUBLIC_KEY + ", cause:" + e.getMessage(), e);
+ }
+ }
+
+ private static ECPublicKeyParameters convertPublicKeyToParameters() {
+ ECParameterSpec parameterSpec = YOP_PUBLIC_KEY.getParameters();
+ ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
+ parameterSpec.getN(), parameterSpec.getH());
+ return new ECPublicKeyParameters(YOP_PUBLIC_KEY.getQ(), domainParameters);
+ }
+
+ private static String encryptParam(String sm4Key, String plain) throws Exception {
+ if (BIZ_PARAM_ENCRYPT_SUPPORTED) {
+ final Cipher cipher = getInitializedCipher(Cipher.ENCRYPT_MODE, sm4Key);
+ return encodeUrlSafeBase64(cipher.doFinal(plain.getBytes("UTF-8")));
+ } else {
+ return plain;
+ }
+ }
+
+ private static String decryptParam(String sm4Key, String encryptContent) throws Exception {
+ final Cipher cipher = getInitializedCipher(Cipher.DECRYPT_MODE, sm4Key);
+ return new String(cipher.doFinal(decodeBase64(encryptContent)), "UTF-8");
+ }
+
+ private static InputStream decryptStream(String sm4Key, InputStream encryptStream) throws Exception {
+ final Cipher cipher = getInitializedCipher(Cipher.DECRYPT_MODE, sm4Key);
+ return new CipherInputStream(encryptStream, cipher);
+ }
+
+ private static Cipher getInitializedCipher(int mode, String sm4Key) {
+ try {
+ byte[] key = decodeBase64(sm4Key);
+ Cipher cipher = Cipher.getInstance(SM4_CBC_PKCS5PADDING, BouncyCastleProvider.PROVIDER_NAME);
+ IvParameterSpec spec = new IvParameterSpec(SM4_IV);
+ Key secretKey = new SecretKeySpec(key, "SM4");
+ cipher.init(mode, secretKey, spec);
+ return cipher;
+ } catch (Throwable throwable) {
+ throw new RuntimeException("error happened when initialize cipher", throwable);
+ }
+ }
+
+ private static String encodeUrlSafeBase64(byte[] input) {
+ return Base64.encodeBase64URLSafeString(input);
+ }
+
+ private static byte[] generateRandomKey() throws NoSuchAlgorithmException, NoSuchProviderException {
+ //实例化
+ KeyGenerator generator = KeyGenerator.getInstance("SM4", BouncyCastleProvider.PROVIDER_NAME);
+ //设置密钥长度,SM4算法目前只支持128位(即密钥16字节)
+ generator.init(128);
+ //生成密钥
+ return generator.generateKey().getEncoded();
+ }
+
+ protected static HttpUriRequest buildHttpRequest(String requestUrl, YopRequestMethod requestMethod,
+ Map headers, Multimap params,
+ String content) throws UnsupportedEncodingException {
+ RequestBuilder requestBuilder;
+ if (YopRequestMethod.POST == requestMethod) {
+ requestBuilder = RequestBuilder.post();
+ } else if (YopRequestMethod.GET == requestMethod) {
+ requestBuilder = RequestBuilder.get();
+ } else {
+ throw new RuntimeException("unsupported http method");
+ }
+ requestBuilder.setUri(requestUrl);
+
+ // header
+ for (Map.Entry entry : headers.entrySet()) {
+ requestBuilder.addHeader(entry.getKey(), entry.getValue());
+ }
+
+ // body
+ try {
+ if (null != params) {
+ for (Map.Entry> entry : params.asMap().entrySet()) {
+ String paramKey = entry.getKey();
+ for (String value : entry.getValue()) {
+ requestBuilder.addParameter(paramKey, URLEncoder.encode(value, DEFAULT_ENCODING));
+ }
+ }
+ }
+ } catch (IOException ex) {
+ throw new RuntimeException("unable to create http request.", ex);
+ }
+ if (YopRequestMethod.GET.equals(requestMethod)) {
+ requestBuilder.addHeader(CONTENT_TYPE, "application/x-www-form-urlencoded;charset=UTF-8");
+ return requestBuilder.build();
+ }
+ // json 请求
+ if (StringUtils.isNotBlank(content)) {
+ final byte[] contentBytes = content.getBytes(DEFAULT_ENCODING);
+ requestBuilder.setEntity(new InputStreamEntity(new ByteArrayInputStream(contentBytes), contentBytes.length));
+ requestBuilder.addHeader(CONTENT_TYPE, "application/json;charset=UTF-8");
+ }
+ return requestBuilder.build();
+ }
+
+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+ private static void handleResponse(YopRequestType requestType,
+ CloseableHttpResponse httpResponse,
+ String encryptKey) throws Exception {
+ // header
+ Map headers = Maps.newHashMap();
+ for (Header header : httpResponse.getAllHeaders()) {
+ headers.put(header.getName(), header.getValue());
+ }
+ String encryptHeader = headers.get("x-yop-encrypt"),// 加密头
+ signHeader = headers.get("x-yop-sign"), //签名头
+ signSerialNo = headers.get("x-yop-sign-serial-no"); //签名序列号,可能会变
+
+ boolean isEncryptResponse = StringUtils.isNotBlank(encryptHeader);
+
+ // body
+ HttpEntity entity = httpResponse.getEntity();
+ int statusCode = httpResponse.getStatusLine().getStatusCode();
+ if (statusCode / 100 == HttpStatus.SC_OK / 100 && statusCode != HttpStatus.SC_NO_CONTENT) {
+ //not a error
+ if (null != entity && entity.getContent() != null) {
+ if (isJsonResponse(httpResponse)) {
+ String content = IOUtils.toString(entity.getContent(), DEFAULT_ENCODING);
+ System.out.println("Request success, response:" + content);
+ verifyResponseSign(signHeader, content, signSerialNo);
+ final JsonNode bizData = OBJECT_MAPPER.readTree(content).get("result");
+ if (isEncryptResponse) {
+ System.out.println("Response decrypt success, bizData:" + decryptParam(encryptKey, bizData.asText()));
+ }
+ return;
+ } else if (YopRequestType.FILE_DOWNLOAD.equals(requestType) || isDownloadResponse(httpResponse)) {
+ InputStream fileContent = entity.getContent();
+ if (isEncryptResponse) {
+ fileContent = decryptStream(encryptKey, fileContent);
+ System.out.println("Response file decrypt success");
+ }
+ final File file = saveFile(fileContent, headers);
+ System.out.println("Request success, file downloaded:" + file);
+ return;
+ } else {
+ throw new RuntimeException("Response Error, contentType:" + httpResponse.getEntity().getContentType());
+ }
+ } else {
+ throw new RuntimeException("Response Error, contentType:" + httpResponse.getEntity().getContentType());
+ }
+ } else if (statusCode >= HttpStatus.SC_INTERNAL_SERVER_ERROR && statusCode != HttpStatus.SC_BAD_GATEWAY) {
+ if (entity.getContent() != null) {
+ String content = IOUtils.toString(entity.getContent(), DEFAULT_ENCODING);
+ System.out.println("Request Fail, response:" + content);
+ verifyResponseSign(signHeader, content, signSerialNo);
+ return;
+ } else {
+ throw new RuntimeException("ResponseError, Empty Content, httpStatusCode:" + httpResponse.getStatusLine().getStatusCode());
+ }
+ } else if (statusCode == HttpStatus.SC_BAD_GATEWAY || statusCode == HttpStatus.SC_NOT_FOUND) {
+ throw new RuntimeException("Response Error, statusCode:" + statusCode);
+ }
+ throw new RuntimeException("ReqParam Illegal, Bad Request, statusCode:" + statusCode);
+ }
+
+ private static void verifyResponseSign(String signHeader, String content, String signSerialNo) {
+ if (StringUtils.isBlank(signHeader) || StringUtils.isBlank(content)|| StringUtils.isBlank(signSerialNo)) {
+ System.out.println("Response Sign Skip, signature:" + signHeader + ", content:" + content + ", signSerialNo:" + signSerialNo);
+ return;
+ }
+ String signContent = content.replaceAll("[ \t\n]", "");
+ System.out.println("Response Sign Begin, signature:" + signHeader + ", content:" + signContent + ", signSerialNo:" + signSerialNo);
+ if (!YOP_PUBLIC_KEY_MAP.containsKey(signSerialNo)) {
+ System.out.println("Response Sign Skip verify, No YopPublicKey Found");
+ }
+ if (!verifySign(signContent, signHeader, YOP_PUBLIC_KEY_MAP.get(signSerialNo))) {
+ System.out.println("Response Sign Verify Fail");
+ } else {
+ System.out.println("Response Sign Verify Success");
+ }
+ }
+
+ /**
+ * 保存文件到本地
+ *
+ * @param content
+ * @param headers
+ * @return File
+ */
+ public static File saveFile(InputStream content, Map headers) {
+ InputStream fileContent = content;
+ try {
+ String filePrefix = "yos-", fileSuffix = ".tmp";
+ final String contentDisposition = headers.get(CONTENT_DISPOSITION);
+ try {
+ String fileName = getFileNameFromHeader(contentDisposition);
+ if (StringUtils.isNotBlank(fileName)) {
+ final String[] split = fileName.split("\\.");
+ if (split.length == 2) {
+ if (StringUtils.length(split[0]) > 3) {
+ filePrefix = split[0];
+ }
+ if (StringUtils.isNotBlank(split[1])) {
+ fileSuffix = "." + split[1];
+ }
+ }
+ }
+ } catch (Exception e) {
+ System.out.println(("parse Content-Disposition fail, value:" + contentDisposition + ", ex:" + e));
+ }
+ File tmpFile = File.createTempFile(filePrefix, fileSuffix);
+ IOUtils.copy(fileContent, Files.newOutputStream(tmpFile.toPath()));
+ return tmpFile;
+ } catch (Throwable ex) {
+ throw new RuntimeException("fail to save file");
+ } finally {
+ closeQuietly(fileContent);
+ }
+ }
+
+ public static void closeQuietly(Closeable closeable) {
+ try {
+ if (null != closeable) {
+ closeable.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static String getFileNameFromHeader(String contentDisposition) {
+ if (StringUtils.isBlank(contentDisposition)) {
+ return null;
+ }
+
+ final String[] parts = contentDisposition.split( "filename=");
+ if (parts.length == 2) {
+ return StringUtils.trim(parts[1]);
+ }
+ return null;
+ }
+
+ private static final String CONTENT_TYPE_JSON = "application/json";
+ private static final String CONTENT_TYPE_STREAM = "application/octet-stream";
+
+ private static boolean isJsonResponse(CloseableHttpResponse response) {
+ return null != response.getEntity() && StringUtils.startsWith(response.getEntity().getContentType().getValue(), CONTENT_TYPE_JSON);
+ }
+
+ private static boolean isDownloadResponse(CloseableHttpResponse response) {
+ return null != response.getEntity() && StringUtils.startsWith(response.getEntity().getContentType().getValue(), CONTENT_TYPE_STREAM);
+ }
+
+ public enum YopRequestMethod {
+ GET,
+ POST
+ }
+
+ public enum YopRequestType {
+ WEB,
+ FILE_DOWNLOAD,
+ MULTI_FILE_UPLOAD,
+ }
+
+ private static final String YOP_HTTP_CONTENT_TYPE_JSON = "application/json";
+ private static final String YOP_HTTP_CONTENT_TYPE_FORM = "application/x-www-form-urlencoded";
+ private static final String YOP_HTTP_CONTENT_TYPE_MULTIPART_FORM = "multipart/form-data";
+ private static final String YOP_HTTP_CONTENT_TYPE_STREAM = "application/octet-stream";
+ private static final String YOP_HTTP_CONTENT_TYPE_TEXT = "text/plain;charset=UTF-8";
+
+ public enum YopRequestContentType {
+ FORM_URL_ENCODE(YOP_HTTP_CONTENT_TYPE_FORM),
+ MULTIPART_FORM(YOP_HTTP_CONTENT_TYPE_MULTIPART_FORM),
+ JSON(YOP_HTTP_CONTENT_TYPE_JSON),
+ OCTET_STREAM(YOP_HTTP_CONTENT_TYPE_STREAM),
+ TEXT_PLAIN(YOP_HTTP_CONTENT_TYPE_TEXT);
+
+ private String value;
+
+ YopRequestContentType(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+ }
+
+
+ // 附录:jar包依赖情况
+ /**
+ *
+ * org.apache.httpcomponents
+ * httpcore
+ * 4.4.13
+ *
+ *
+ * org.apache.httpcomponents
+ * httpclient
+ * 4.5.13
+ *
+ *
+ * org.apache.httpcomponents
+ * httpmime
+ * 4.5.13
+ *
+ *
+ *
+ * commons-codec
+ * commons-codec
+ * 1.10
+ *
+ *
+ * commons-io
+ * commons-io
+ * 2.8.0
+ *
+ *
+ * com.google.guava
+ * guava
+ * 30.0-jre
+ *
+ *
+ * joda-time
+ * joda-time
+ * 2.9.4
+ *
+ *
+ * org.apache.commons
+ * commons-lang3
+ * 3.6
+ *
+ *
+ * com.fasterxml.jackson.core
+ * jackson-databind
+ * 2.13.2
+ *
+ *
+ * org.bouncycastle
+ * bcprov-jdk15on
+ * 1.67
+ *
+ *
+ * org.bouncycastle
+ * bcpkix-jdk15on
+ * 1.67
+ *
+ */
+}
diff --git a/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/example/YopSm2CallbackExample.java b/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/example/YopSm2CallbackExample.java
index 4468c7ca..6247ca05 100644
--- a/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/example/YopSm2CallbackExample.java
+++ b/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/example/YopSm2CallbackExample.java
@@ -5,21 +5,18 @@
import com.google.common.collect.Sets;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
-import org.bouncycastle.asn1.ASN1EncodableVector;
-import org.bouncycastle.asn1.ASN1Encoding;
-import org.bouncycastle.asn1.ASN1Integer;
-import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.*;
import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.engines.SM2Engine;
-import org.bouncycastle.crypto.params.ECDomainParameters;
-import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
-import org.bouncycastle.crypto.params.ECPublicKeyParameters;
-import org.bouncycastle.crypto.params.ParametersWithID;
+import org.bouncycastle.crypto.params.*;
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.math.ec.ECPoint;
+import org.bouncycastle.math.ec.custom.gm.SM2P256V1Curve;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -29,10 +26,7 @@
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
-import java.security.Key;
-import java.security.KeyFactory;
-import java.security.NoSuchAlgorithmException;
-import java.security.Security;
+import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
@@ -176,6 +170,98 @@ public static void main(String[] args) throws Exception {
// 解密业务参数
final String bizContent = decryptBizContent(jsonReqBody, decryptedSecretKey, iv);
LOGGER.info("解密结果:{}", bizContent);
+
+ // 构造应答报文
+// String respBody = "{\"result\":\"SUCCESS\"}";
+ //HttpServletResponse resp;
+// resp.addHeader("x-yop-sign", encodeUrlSafeBase64(sign(respBody.getBytes(UTF_8))));
+// // 注意:此处为测试环境国密证书,生产环境请联系技术支持获取
+// resp.addHeader("x-yop-sign-serial-no", "4059376239");
+// resp.setContentType("application/json");
+// resp.getOutputStream().write(respBody.getBytes(UTF_8));
+ }
+
+ private static byte[] sign(byte[] data, String appKey) {
+ BCECPrivateKey isvPrivateKey = isvPrivateKeyMap.get(appKey);
+ try {
+ ECParameterSpec parameterSpec = isvPrivateKey.getParameters();
+ ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
+ parameterSpec.getN(), parameterSpec.getH());
+ ECPrivateKeyParameters priKeyParameters = new ECPrivateKeyParameters(isvPrivateKey.getD(), domainParameters);
+ //der编码后的签名值
+ byte[] derSign = sign(priKeyParameters, null, data);
+
+ //der解码过程
+ ASN1Sequence as = DERSequence.getInstance(derSign);
+ byte[] rBytes = ((ASN1Integer) as.getObjectAt(0)).getValue().toByteArray();
+ byte[] sBytes = ((ASN1Integer) as.getObjectAt(1)).getValue().toByteArray();
+ //由于大数的补0规则,所以可能会出现33个字节的情况,要修正回32个字节
+ rBytes = fixToCurveLengthBytes(rBytes);
+ sBytes = fixToCurveLengthBytes(sBytes);
+ byte[] rawSign = new byte[rBytes.length + sBytes.length];
+ System.arraycopy(rBytes, 0, rawSign, 0, rBytes.length);
+ System.arraycopy(sBytes, 0, rawSign, rBytes.length, sBytes.length);
+ return rawSign;
+ } catch (Exception e) {
+ throw new RuntimeException("SystemError, Sign Fail, key:" + isvPrivateKey + ", ex:", e);
+ }
+ }
+
+ /**
+ * 签名
+ *
+ * @param priKeyParameters 私钥
+ * @param withId 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes()
+ * @param srcData 源数据
+ * @return DER编码后的签名值
+ * @throws CryptoException
+ */
+ public static byte[] sign(ECPrivateKeyParameters priKeyParameters, byte[] withId, byte[] srcData)
+ throws CryptoException {
+ SM2Signer signer = new SM2Signer();
+ CipherParameters param;
+ ParametersWithRandom pwr = new ParametersWithRandom(priKeyParameters, new SecureRandom());
+ if (withId != null) {
+ param = new ParametersWithID(pwr, withId);
+ } else {
+ param = pwr;
+ }
+ signer.init(true, param);
+ signer.update(srcData, 0, srcData.length);
+ return signer.generateSignature();
+ }
+
+ public static final SM2P256V1Curve CURVE = new SM2P256V1Curve();
+ public final static BigInteger SM2_ECC_N = CURVE.getOrder();
+ public final static BigInteger SM2_ECC_H = CURVE.getCofactor();
+ public final static BigInteger SM2_ECC_GX = new BigInteger(
+ "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16);
+ public final static BigInteger SM2_ECC_GY = new BigInteger(
+ "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16);
+ public static final ECPoint G_POINT = CURVE.createPoint(SM2_ECC_GX, SM2_ECC_GY);
+ public static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters(CURVE, G_POINT,
+ SM2_ECC_N, SM2_ECC_H);
+ public static final int CURVE_LEN = getCurveLength(DOMAIN_PARAMS);
+ public static int getCurveLength(ECDomainParameters domainParams) {
+ return (domainParams.getCurve().getFieldSize() + 7) / 8;
+ }
+
+ private static byte[] fixToCurveLengthBytes(byte[] src) {
+ if (src.length == CURVE_LEN) {
+ return src;
+ }
+
+ byte[] result = new byte[CURVE_LEN];
+ if (src.length > CURVE_LEN) {
+ System.arraycopy(src, src.length - result.length, result, 0, result.length);
+ } else {
+ System.arraycopy(src, 0, result, result.length - src.length, src.length);
+ }
+ return result;
+ }
+
+ private static String encodeUrlSafeBase64(byte[] input) {
+ return Base64.encodeBase64URLSafeString(input);
}
private static byte[] decryptKey(byte[] encryptedCredentialBytes, BCECPrivateKey isvPrivateKey) {
diff --git a/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/service/CustomFixedSdkConfigProvider.java b/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/service/CustomFixedSdkConfigProvider.java
index f26f7a77..e77b6a70 100644
--- a/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/service/CustomFixedSdkConfigProvider.java
+++ b/yop-java-sdk-test/src/test/java/com/yeepay/yop/sdk/service/CustomFixedSdkConfigProvider.java
@@ -4,9 +4,12 @@
*/
package com.yeepay.yop.sdk.service;
-import com.yeepay.yop.sdk.YopConstants;
import com.yeepay.yop.sdk.base.config.provider.YopFixedSdkConfigProvider;
import com.yeepay.yop.sdk.config.YopSdkConfig;
+import com.yeepay.yop.sdk.config.provider.file.YopCertStore;
+import com.yeepay.yop.sdk.config.provider.file.YopProxyConfig;
+
+import java.util.Arrays;
/**
* title: 自定义SDK配置
@@ -23,10 +26,26 @@ public class CustomFixedSdkConfigProvider extends YopFixedSdkConfigProvider {
@Override
protected YopSdkConfig loadSdkConfig() {
YopSdkConfig yopSdkConfig = new YopSdkConfig();
- // 可以根据当前环境(测试/灰度/生产等等),自定义其他请求根路径
- yopSdkConfig.setServerRoot(YopConstants.DEFAULT_SERVER_ROOT);
- yopSdkConfig.setYosServerRoot(YopConstants.DEFAULT_YOS_SERVER_ROOT);
- yopSdkConfig.setSandboxServerRoot(YopConstants.DEFAULT_SANDBOX_SERVER_ROOT);
+
+ // 示例:普通接口请求端点地址,配置多个时,遇到故障可以自动切换
+ yopSdkConfig.setPreferredServerRoots(Arrays.asList("https://域名A","https://域名B"));
+ // 示例:文件上传、下载类接口请求端点地址
+ yopSdkConfig.setYosServerRoot("https://域名C");
+ // 示例:沙箱环境请求地址
+ yopSdkConfig.setSandboxServerRoot("https://域名D");
+
+ // 示例:请求代理配置
+ final YopProxyConfig proxyConfig = new YopProxyConfig();
+ proxyConfig.setHost("xxx");
+ proxyConfig.setPort(1234);
+ yopSdkConfig.setProxy(proxyConfig);
+
+ // 示例:国密证书分发配置
+ YopCertStore yopCertStore = new YopCertStore();
+ yopCertStore.setEnable(true);// 默认会开启本地存储,将远程拉取的证书存放本地文件
+ yopCertStore.setPath("/tmp/yop/certs");//默认存放位置
+ yopSdkConfig.setYopCertStore(yopCertStore);
+
// 连接超时时间、读取超时时间等其他配置,可根据需要setXXX即可
return yopSdkConfig;
}