exception handler

This commit is contained in:
xiafang
2020-11-04 14:27:04 +08:00
parent 71887fdc13
commit cb98993e8f
15 changed files with 157 additions and 139 deletions

View File

@@ -0,0 +1,27 @@
package com.enongm.dianji.payment;
/**
* @author Dax
* @since 14:18
*/
public class PayException extends RuntimeException {
public PayException() {
}
public PayException(String message) {
super(message);
}
public PayException(String message, Throwable cause) {
super(message, cause);
}
public PayException(Throwable cause) {
super(cause);
}
public PayException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@@ -0,0 +1,71 @@
package com.enongm.dianji.payment.alipay;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.enongm.dianji.payment.PayException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
/**
* @author Dax
* @since 14:35
*/
@Slf4j
@Configuration
@EnableConfigurationProperties(AliPayProperties.class)
public class AliPayConfiguration {
@Bean
public AlipayClient alipayClient(AliPayProperties aliPayProperties) throws AlipayApiException {
PropertyMapper propertyMapper = PropertyMapper.get().alwaysApplyingWhenNonNull();
AliPayProperties.V1 v1 = aliPayProperties.getV1();
CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
propertyMapper.from(v1::getServerUrl).to(certAlipayRequest::setServerUrl);
propertyMapper.from(v1::getAppId).to(certAlipayRequest::setAppId);
propertyMapper.from(v1::getAppPrivateKeyPath).as(this::appRSAPrivateKey).to(certAlipayRequest::setPrivateKey);
propertyMapper.from(v1::getFormat).to(certAlipayRequest::setFormat);
propertyMapper.from(v1::getCharset).to(certAlipayRequest::setCharset);
propertyMapper.from(v1::getSignType).to(certAlipayRequest::setSignType);
propertyMapper.from(v1::getAppCertPublicKeyPath).as(this::getFileAbsolutePath).to(certAlipayRequest::setCertPath);
propertyMapper.from(v1::getAlipayPublicCertPath).as(this::getFileAbsolutePath).to(certAlipayRequest::setAlipayPublicCertPath);
propertyMapper.from(v1::getAlipayRootCertPath).as(this::getFileAbsolutePath).to(certAlipayRequest::setRootCertPath);
return new DefaultAlipayClient(certAlipayRequest);
}
private String getFileAbsolutePath(String classPath) {
try {
return new ClassPathResource(classPath).getFile().getAbsolutePath();
} catch (IOException e) {
log.error("ali pay cert path is not exist ,{}", e.getMessage());
throw new PayException("ali pay cert path is not exist");
}
}
private String appRSAPrivateKey(String classPath) {
try {
File file = new ClassPathResource(classPath).getFile();
return new BufferedReader(new FileReader(file)).readLine();
} catch (IOException e) {
log.error("ali pay app private key is required ,{}", e.getMessage());
throw new PayException("ali pay app private key is required");
}
}
}

View File

@@ -1,12 +1,14 @@
package com.enongm.dianji.payment.autoconfigure; package com.enongm.dianji.payment.alipay;
import lombok.Data; import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty; import org.springframework.boot.context.properties.NestedConfigurationProperty;
/** /**
* The type Ali pay properties.
*
* @author Dax * @author Dax
* @since 14:13 * @since 14 :13
*/ */
@Data @Data
@ConfigurationProperties("ali.pay") @ConfigurationProperties("ali.pay")
@@ -18,6 +20,9 @@ public class AliPayProperties {
private V1 v1; private V1 v1;
/**
* The type V 1.
*/
@Data @Data
public static class V1{ public static class V1{
/** /**
@@ -29,13 +34,21 @@ public class AliPayProperties {
*/ */
private String appId; private String appId;
/** /**
* your app private key * your app private key, which must be in a single line
*/ */
private String appPrivateKey; private String appPrivateKeyPath;
/** /**
* sign type * sign type default RSA2
*/ */
private String signType = "md5"; private String signType = "RSA2";
/**
* data format only json now
*/
private String format ="json";
/**
* charset default utf-8
*/
private String charset ="utf-8";
/** /**
* alipay public cert path * alipay public cert path
*/ */
@@ -44,6 +57,10 @@ public class AliPayProperties {
* alipay root cert path * alipay root cert path
*/ */
private String alipayRootCertPath; private String alipayRootCertPath;
/**
* appCertPublicKey
*/
private String appCertPublicKeyPath;
} }

View File

@@ -1,91 +0,0 @@
package com.enongm.dianji.payment.alipay;
import org.springframework.util.CollectionUtils;
import java.util.*;
/**
* The type Ali pay core.
*/
public class SignatureProvider {
/**
* 生成签名结果
*
* @param params 要签名的数组
* @param key 签名密钥
* @param signType 签名类型
* @return 签名结果字符串
*/
public static String requestSign(Map<String, String> params, String key, String signType) {
String preStr = createLinkString(params);
/* if (SignType.MD5.getType().equals(signType)) {
return SecureUtil.md5(preStr.concat(key));
}*/
return null;
}
/**
* 生成要请求给支付宝的参数数组
*
* @param params 请求前的参数数组
* @param key 商户的私钥
* @param signType 签名类型
* @return 要请求的参数数组 map
*/
public static Map<String, String> buildRequestPara(Map<String, String> params, String key, String signType) {
// 除去数组中的空值和签名参数
Map<String, String> tempMap = paraFilter(params);
// 生成签名结果
String mySign = requestSign(params, key, signType);
// 签名结果与签名方式加入请求提交参数组中
tempMap.put("sign", mySign);
tempMap.put("sign_type", signType);
return tempMap;
}
/**
* 除去数组中的空值和签名参数
*
* @param sArray 签名参数组
* @return 去掉空值与签名参数后的新签名参数组 map
*/
public static Map<String, String> paraFilter(Map<String, String> sArray) {
Map<String, String> result = new HashMap<String, String>(sArray.size());
if (CollectionUtils.isEmpty(sArray)) {
return Collections.emptyMap();
}
for (String key : sArray.keySet()) {
String value = sArray.get(key);
if (value == null || "".equals(value) || "sign".equalsIgnoreCase(key)
|| "sign_type".equalsIgnoreCase(key)) {
continue;
}
result.put(key, value);
}
return result;
}
/**
* 参数自然排序拼接
*
* @param params {'k':'b','e':'f','c':'d'} -> {'c':'d','e':'f','k':'b'}
* @return 拼接后字符串 c=d&e=f&k=b
*/
public static String createLinkString(Map<String, String> params) {
TreeMap<String, String> treeMap = new TreeMap<>(params);
Set<String> keySet = treeMap.keySet();
StringBuilder content = new StringBuilder();
for (String key : keySet) {
content.append(key).append("=")
.append(treeMap.get(key))
.append("&");
}
return content.substring(0, content.length() - 1);
}
}

View File

@@ -1,14 +0,0 @@
package com.enongm.dianji.payment.autoconfigure;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @author Dax
* @since 14:35
*/
@Configuration
@EnableConfigurationProperties(AliPayProperties.class)
public class AliPayConfiguration {
}

View File

@@ -1,5 +1,7 @@
package com.enongm.dianji.payment.autoconfigure; package com.enongm.dianji.payment.autoconfigure;
import com.enongm.dianji.payment.alipay.AliPayConfiguration;
import com.enongm.dianji.payment.wechat.WechatPayConfiguration;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
@@ -8,6 +10,6 @@ import org.springframework.context.annotation.Import;
* @since 14:47 * @since 14:47
*/ */
@Configuration @Configuration
@Import({WechatPayConfiguration.class,AliPayConfiguration.class}) @Import({WechatPayConfiguration.class, AliPayConfiguration.class})
public class PayConfiguration { public class PayConfiguration {
} }

View File

@@ -1,4 +1,4 @@
package com.enongm.dianji.payment.autoconfigure; package com.enongm.dianji.payment.wechat;
import lombok.Data; import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -1,7 +1,7 @@
package com.enongm.dianji.payment.wechat.v2; package com.enongm.dianji.payment.wechat.v2;
import com.enongm.dianji.payment.autoconfigure.WechatPayProperties; import com.enongm.dianji.payment.wechat.WechatPayProperties;
import com.enongm.dianji.payment.wechat.v2.model.BaseModel; import com.enongm.dianji.payment.wechat.v2.model.BaseModel;
/** /**

View File

@@ -1,6 +1,7 @@
package com.enongm.dianji.payment.wechat.v2.model; package com.enongm.dianji.payment.wechat.v2.model;
import com.enongm.dianji.payment.PayException;
import com.enongm.dianji.payment.wechat.enumeration.V2PayType; import com.enongm.dianji.payment.wechat.enumeration.V2PayType;
import com.enongm.dianji.payment.wechat.enumeration.WeChatServer; import com.enongm.dianji.payment.wechat.enumeration.WeChatServer;
import com.enongm.dianji.payment.wechat.v2.WechatResponseBody; import com.enongm.dianji.payment.wechat.v2.WechatResponseBody;
@@ -9,11 +10,9 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy; import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import lombok.Getter; import lombok.Getter;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import okhttp3.*; import okhttp3.*;
import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.MD5Digest; import org.bouncycastle.crypto.digests.MD5Digest;
@@ -22,7 +21,6 @@ import org.springframework.util.AlternativeJdkIdGenerator;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.IdGenerator; import org.springframework.util.IdGenerator;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Objects; import java.util.Objects;
@@ -58,7 +56,9 @@ public class BaseModel {
private V2PayType payType; private V2PayType payType;
@JsonIgnore @JsonIgnore
private final WeChatServer weChatServer = WeChatServer.CHINA; private final WeChatServer weChatServer = WeChatServer.CHINA;
@JsonIgnore
private boolean sandboxMode; private boolean sandboxMode;
@JsonIgnore
private boolean partnerMode; private boolean partnerMode;
@@ -82,6 +82,15 @@ public class BaseModel {
return this; return this;
} }
public BaseModel sandboxMode(boolean sandboxMode) {
this.sandboxMode = sandboxMode;
return this;
}
public BaseModel partnerMode(boolean partnerMode) {
this.partnerMode = partnerMode;
return this;
}
/** /**
* Xml string. * Xml string.
* *
@@ -158,7 +167,7 @@ public class BaseModel {
if (Objects.nonNull(body)) { if (Objects.nonNull(body)) {
return MAPPER.readValue(body.string(), WechatResponseBody.class); return MAPPER.readValue(body.string(), WechatResponseBody.class);
} }
throw new IllegalStateException("wechat pay response body is empty"); throw new PayException("wechat pay response body is empty");
} }
} }

View File

@@ -1,6 +1,7 @@
package com.enongm.dianji.payment.wechat.v3; package com.enongm.dianji.payment.wechat.v3;
import com.enongm.dianji.payment.PayException;
import com.enongm.dianji.payment.wechat.v3.model.WechatMetaBean; import com.enongm.dianji.payment.wechat.v3.model.WechatMetaBean;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
@@ -52,7 +53,7 @@ public class KeyPairFactory {
wechatMetaBean.setSerialNumber(serialNumber); wechatMetaBean.setSerialNumber(serialNumber);
return wechatMetaBean; return wechatMetaBean;
} catch (Exception e) { } catch (Exception e) {
throw new IllegalStateException("Cannot load keys from store: " + resource, e); throw new PayException("Cannot load keys from store: " + resource, e);
} }
} }
} }

View File

@@ -1,6 +1,7 @@
package com.enongm.dianji.payment.wechat.v3; package com.enongm.dianji.payment.wechat.v3;
import com.enongm.dianji.payment.PayException;
import com.enongm.dianji.payment.wechat.enumeration.V3PayType; import com.enongm.dianji.payment.wechat.enumeration.V3PayType;
import com.enongm.dianji.payment.wechat.enumeration.WeChatServer; import com.enongm.dianji.payment.wechat.enumeration.WeChatServer;
import com.enongm.dianji.payment.wechat.v3.model.WechatMetaBean; import com.enongm.dianji.payment.wechat.v3.model.WechatMetaBean;
@@ -159,15 +160,16 @@ public class SignatureProvider {
Response response = new OkHttpClient().newCall(request).execute(); Response response = new OkHttpClient().newCall(request).execute();
if (Objects.isNull(response.body())) { if (Objects.isNull(response.body())) {
throw new RuntimeException("cant obtain the response body"); throw new PayException("cant obtain the response body");
} }
String body = response.body().string(); String body = response.body().string();
ObjectMapper MAPPER = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
ObjectNode bodyObjectNode = MAPPER.readValue(body, ObjectNode.class); ObjectNode bodyObjectNode = mapper.readValue(body, ObjectNode.class);
ArrayNode certificates = bodyObjectNode.withArray("data"); ArrayNode certificates = bodyObjectNode.withArray("data");
if (certificates.isArray() && certificates.size() > 0) { if (certificates.isArray() && certificates.size() > 0) {
CERTIFICATE_MAP.clear();
final CertificateFactory cf = CertificateFactory.getInstance("X509"); final CertificateFactory cf = CertificateFactory.getInstance("X509");
certificates.forEach(objectNode -> { certificates.forEach(objectNode -> {
JsonNode encryptCertificate = objectNode.get("encrypt_certificate"); JsonNode encryptCertificate = objectNode.get("encrypt_certificate");
@@ -184,8 +186,6 @@ public class SignatureProvider {
e.printStackTrace(); e.printStackTrace();
} }
String responseSerialNo = objectNode.get("serial_no").asText(); String responseSerialNo = objectNode.get("serial_no").asText();
CERTIFICATE_MAP.clear();
CERTIFICATE_MAP.put(responseSerialNo, certificate); CERTIFICATE_MAP.put(responseSerialNo, certificate);
}); });
@@ -217,15 +217,12 @@ public class SignatureProvider {
try { try {
bytes = cipher.doFinal(Base64Utils.decodeFromString(ciphertext)); bytes = cipher.doFinal(Base64Utils.decodeFromString(ciphertext));
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
throw new IllegalArgumentException(e); throw new PayException(e);
} }
return new String(bytes, StandardCharsets.UTF_8); return new String(bytes, StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) { } catch (NoSuchAlgorithmException | NoSuchPaddingException |
throw new IllegalStateException(e); InvalidKeyException | InvalidAlgorithmParameterException e) {
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) { throw new PayException(e);
throw new IllegalArgumentException(e);
} }
} }

View File

@@ -1,7 +1,7 @@
package com.enongm.dianji.payment.wechat.v3.filter; package com.enongm.dianji.payment.wechat.v3.filter;
import com.enongm.dianji.payment.autoconfigure.WechatPayProperties; import com.enongm.dianji.payment.wechat.WechatPayProperties;
import com.enongm.dianji.payment.wechat.v3.PayFilter; import com.enongm.dianji.payment.wechat.v3.PayFilter;
import com.enongm.dianji.payment.wechat.v3.PayFilterChain; import com.enongm.dianji.payment.wechat.v3.PayFilterChain;
import com.enongm.dianji.payment.wechat.v3.WechatPayRequest; import com.enongm.dianji.payment.wechat.v3.WechatPayRequest;

View File

@@ -1,6 +1,7 @@
package com.enongm.dianji.payment.wechat.v3.filter; package com.enongm.dianji.payment.wechat.v3.filter;
import com.enongm.dianji.payment.PayException;
import com.enongm.dianji.payment.wechat.v3.PayFilter; import com.enongm.dianji.payment.wechat.v3.PayFilter;
import com.enongm.dianji.payment.wechat.v3.PayFilterChain; import com.enongm.dianji.payment.wechat.v3.PayFilterChain;
import com.enongm.dianji.payment.wechat.v3.SignatureProvider; import com.enongm.dianji.payment.wechat.v3.SignatureProvider;
@@ -53,14 +54,13 @@ public class HttpRequestFilter implements PayFilter {
try { try {
Response response = client.newCall(httpRequest).execute(); Response response = client.newCall(httpRequest).execute();
ResponseBody responseBody = response.body(); ResponseBody responseBody = response.body();
if (Objects.isNull(responseBody)) { if (Objects.isNull(responseBody)) {
throw new IllegalStateException("cant obtain response body"); throw new IllegalStateException("cant obtain response body");
} }
// 微信请求回调id // 微信请求回调id
String RequestId = response.header("Request-ID"); // String RequestId = response.header("Request-ID");
// 微信平台证书序列号 用来取微信平台证书 // 微信平台证书序列号 用来取微信平台证书
String wechatpaySerial = response.header("Wechatpay-Serial"); String wechatpaySerial = response.header("Wechatpay-Serial");
//获取应答签名 //获取应答签名
@@ -79,12 +79,11 @@ public class HttpRequestFilter implements PayFilter {
responseConsumer.accept(body); responseConsumer.accept(body);
} }
} else { } else {
throw new IllegalArgumentException("签名验证失败"); throw new PayException("wechat pay signature failed");
} }
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); throw new PayException("wechat pay http request failed");
} }
} }
} }

View File

@@ -1,7 +1,7 @@
package com.enongm.dianji.payment.wechat.v3.model; package com.enongm.dianji.payment.wechat.v3.model;
import com.enongm.dianji.payment.autoconfigure.WechatPayProperties; import com.enongm.dianji.payment.wechat.WechatPayProperties;
import lombok.Data; import lombok.Data;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert; import org.springframework.util.Assert;