记得上下班打卡 | git大法好,push需谨慎

Commit ec478858 authored by zhengfuxin's avatar zhengfuxin

抖音预支付开发

parent a9640cea
......@@ -23,6 +23,7 @@ public class DragonConstant {
ALIPAY("alipay","支付宝"),
WEPAY ("wepay","微信"),
APPLEPAY ("applepay","applepay"),
DOUYINPAY ("douyinpay","抖音"),
CLOUDPAY("cloudpay","云闪付");
private String code;
private String message;
......
package com.liquidnet.service.dragon.channel.douyinpay.constant;
/**
* @author zhangfuxin
* @Description: 抖音枚举
* @date 2021/11/9 下午3:37
*/
public class DouYinpayConstant {
public enum DouYinTradeStateEnum {
SUCCESS("0","成功");
private String code;
private String message;
DouYinTradeStateEnum(String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
}
}
package com.liquidnet.service.dragon.channel.douyinpay.strategy;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.dragon.dto.DragonPayBaseReqDto;
import com.liquidnet.service.dragon.dto.DragonPayBaseRespDto;
import com.liquidnet.service.dragon.dto.DragonPayOrderQueryRespDto;
/**
* @author zhangfuxin
* @Description: 抖音支付接口
* @date 2021/11/9 下午1:42
*/
public interface IDouYinpayStrategy {
/**
* @author zhangfuxin
* @Description: 预支付
* @date 2021/11/9 下午1:44
*/
ResponseDto<DragonPayBaseRespDto> dragonPay(DragonPayBaseReqDto dragonPayBaseReqDto);
DragonPayOrderQueryRespDto checkOrderStatus(String code);
}
package com.liquidnet.service.dragon.channel.douyinpay.strategy.annotation;
import com.liquidnet.service.dragon.constant.DragonConstant;
import java.lang.annotation.*;
/**
* @author zhangfuxin
* @Description: 抖音标记
* @date 2021/11/9 下午1:40
*/
@Documented
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface StrategyDouYinPayHandler {
DragonConstant.DeviceFromEnum value();
}
package com.liquidnet.service.dragon.channel.douyinpay.strategy.impl;
import com.liquidnet.service.dragon.channel.wepay.resp.WepayPayRespDto;
import com.liquidnet.service.dragon.channel.wepay.strategy.annotation.StrategyWepayHandler;
import com.liquidnet.service.dragon.channel.wepay.strategy.impl.AbstractWepayStrategy;
import com.liquidnet.service.dragon.constant.DragonConstant;
import com.liquidnet.service.dragon.dto.DragonPayBaseReqDto;
import com.liquidnet.service.dragon.dto.DragonPayBaseRespDto;
import com.liquidnet.service.dragon.utils.PayWepayUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
/**
* @author zhangfuxin
* @Description: 抖音小程序支付实现
* @date 2021/11/9 下午1:45
*/
@Slf4j
@Component
@StrategyWepayHandler(DragonConstant.DeviceFromEnum.APPLET)
public class DouYinPayStrategyAppletImpl extends AbstractDouYinPayStrategy {
@Value("${liquidnet.dragon.url}")
private String notifyUrl;
@Override
SortedMap<String, Object> appendRequestParam(SortedMap<String, Object> requestMap, DragonPayBaseReqDto dragonPayBaseReqDto) {
requestMap.put("appid", PayWepayUtils.getInstance().getAPP_ID());
return requestMap;
}
@Override
DragonPayBaseRespDto buildResponseDto(DragonPayBaseRespDto payBaseRespDto, Map result) {
return null;
}
@Override
protected String getRequestUrl() {
return "https://developer.toutiao.com/api/apps/ecpay/v1/create_order";
}
@Override
protected String getNotifyUrl() {
return notifyUrl + "/notify/wepay/applet";
}
@Override
protected String getAppid() {
return PayWepayUtils.getInstance().getAPP_ID();
}
}
package com.liquidnet.service.dragon.channel.strategy.impl;
import com.alibaba.fastjson.JSON;
import com.liquidnet.common.exception.LiquidnetServiceException;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.StringUtil;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.dragon.biz.DragonServiceCommonBiz;
import com.liquidnet.service.dragon.channel.strategy.annotation.StrategyPayChannelHandler;
import com.liquidnet.service.dragon.channel.strategy.biz.DragonPayBiz;
import com.liquidnet.service.dragon.channel.wepay.constant.WepayConstant;
import com.liquidnet.service.dragon.channel.wepay.strategy.WepayStrategyContext;
import com.liquidnet.service.dragon.constant.DragonConstant;
import com.liquidnet.service.dragon.constant.DragonErrorCodeEnum;
import com.liquidnet.service.dragon.dto.DragonOrdersDto;
import com.liquidnet.service.dragon.dto.DragonPayBaseReqDto;
import com.liquidnet.service.dragon.dto.DragonPayBaseRespDto;
import com.liquidnet.service.dragon.dto.DragonPayOrderQueryRespDto;
import com.liquidnet.service.dragon.utils.DataUtils;
import com.liquidnet.service.dragon.utils.PayWepayUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
/**
* @author zhangfuxin
* @Description: 抖音
* @date 2021/11/9 上午11:47
*/
@Slf4j
@Component
@StrategyPayChannelHandler(DragonConstant.PayChannelEnum.DOUYINPAY)
public class PayChannelStrategyDouYinImpl extends AbstractPayChannelStrategyImpl {
@Autowired
private WepayStrategyContext wepayStrategyContext;
@Autowired
private DataUtils dataUtils;
@Autowired
private DragonServiceCommonBiz dragonServiceCommonBiz;
@Autowired
private DragonPayBiz dragonPayBiz;
@Override
public ResponseDto<DragonPayBaseRespDto> dragonPay(DragonPayBaseReqDto dragonPayBaseReqDto) {
return wepayStrategyContext.getStrategy(dragonPayBaseReqDto.getDeviceFrom()).dragonPay(dragonPayBaseReqDto);
}
@Override
public String dragonNotify(HttpServletRequest request,String payType,String deviceFrom) {
String returnStr = "<xml>\n" + " <return_code><![CDATA[FAIL]]></return_code>\n" + " <return_msg><![CDATA[FAIL]]></return_msg>\n" + "</xml>";;
try {
InputStream inputStream = request.getInputStream();// 从request中取得输入流
Map<String, String> notifyMap = new HashMap<String, String>();
try {
notifyMap = PayWepayUtils.parseXml(inputStream);
log.info("dragonNotify-->wepay json : {}", JSON.toJSONString(notifyMap));
log.info("接收到{}支付结果{}", payType, notifyMap);
String code = notifyMap.get("out_trade_no");
//持久化通知记录
dragonServiceCommonBiz.createDragonOrderLogs(code,dragonPayBiz.getPaymentType(payType,deviceFrom),JSON.toJSONString(notifyMap));
// 根据银行订单号获取支付信息
DragonOrdersDto dragonOrdersDto = dataUtils.getPayOrderByCode(code);
if (dragonOrdersDto == null) {
throw new LiquidnetServiceException(DragonErrorCodeEnum.TRADE_ERROR_NOT_EXISTS.getCode(),DragonErrorCodeEnum.TRADE_ERROR_NOT_EXISTS.getMessage());
}
if (DragonConstant.PayStatusEnum.STATUS_PAID.getCode().equals(dragonOrdersDto.getStatus())) {
throw new LiquidnetServiceException(DragonErrorCodeEnum.TRADE_ERROR_HAS_PAID.getCode(),DragonErrorCodeEnum.TRADE_ERROR_HAS_PAID.getMessage());
}
String sign = notifyMap.remove("sign");
boolean notifyResult = false;
if (PayWepayUtils.getInstance().notifySign(notifyMap, sign)) {// 根据配置信息验证签名
if (WepayConstant.WeixinTradeStateEnum.SUCCESS.getCode().equals(notifyMap.get("result_code"))) {// 业务结果
// 成功
String timeEndStr = notifyMap.get("time_end");
LocalDateTime timeEnd = null;
if (!StringUtil.isEmpty(timeEndStr)) {
timeEnd = DateUtil.Formatter.yyyyMMddHHmmssTrim.parse(timeEndStr);
}
notifyResult = this.completeSuccessOrder(dragonOrdersDto, notifyMap.get("transaction_id"), timeEnd, notifyMap.toString());
} else {
notifyResult = this.completeFailOrder(dragonOrdersDto, notifyMap.toString());
}
if(notifyResult){
returnStr = "<xml>\n" + " <return_code><![CDATA[SUCCESS]]></return_code>\n" + " <return_msg><![CDATA[OK]]></return_msg>\n" + "</xml>";
}
} else {
log.error("wepay notify fail code:{} msg:{} ",DragonErrorCodeEnum.TRADE_WEPAY_SIGN_ERROR.getCode(),DragonErrorCodeEnum.TRADE_WEPAY_SIGN_ERROR.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
return returnStr;
}
@Override
public DragonPayOrderQueryRespDto checkOrderStatus(String code) {
DragonOrdersDto ordersDto = dataUtils.getPayOrderByCode(code);
DragonPayOrderQueryRespDto respDto = wepayStrategyContext.getStrategy(DragonConstant.PayTypeEnum.getEnumByCode(ordersDto.getPaymentType()).getDeviceFrom()).checkOrderStatus(code);
return respDto;
}
}
package com.liquidnet.service.dragon.utils;
import com.alipay.api.internal.util.file.IOUtils;
import com.liquidnet.commons.lang.util.MD5Utils;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLContext;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.util.*;
public class PayDouYinpayUtils {
private CloseableHttpClient httpClient;
private static PayDouYinpayUtils instance = new PayDouYinpayUtils();
// 池化管理
private static PoolingHttpClientConnectionManager poolConnManager =null;
private final String merchantId = "1551961491";
private final String partnerKey = "itIuO65O9yKmemOu3S8g1S4orqvCGwXK";
private final String SALT = "D3rXySlTCR15LxYnmbEOaamGoOCbBNQAbFtaK39t";
private final String APP_ID="tt0d647bd9925c076801";
public PayDouYinpayUtils() {
}
public static PayDouYinpayUtils getInstance() {
return instance;
}
public String getAPP_ID() {
return APP_ID;
}
public String getMerchantId() {
return merchantId;
}
public CloseableHttpClient getHttpClient() {
try {
if (httpClient == null) {
InputStream certStream = PayDouYinpayUtils.class.getClassLoader().getResourceAsStream("payCert/wepay/wepay_apiclient_cert.p12");
byte[] certData = IOUtils.toByteArray(certStream);
certStream.read(certData);
certStream.close();
KeyStore keyStore = KeyStore.getInstance("PKCS12");
ByteArrayInputStream inputStream = new ByteArrayInputStream(certData);
try {
keyStore.load(inputStream, merchantId.toCharArray());
} finally {
inputStream.close();
}
SSLContext sslcontext = SSLContexts.custom()
.loadKeyMaterial(keyStore, merchantId.toCharArray())
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
// 配置同时支持 HTTP 和 HTPPS
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslsf).build();
// 初始化连接管理器
poolConnManager =new PoolingHttpClientConnectionManager(socketFactoryRegistry);
poolConnManager.setMaxTotal(4000);// 同时最多连接数
// 设置最大路由
poolConnManager.setDefaultMaxPerRoute(2000);
// 初始化httpClient
httpClient = getConnection();
}
} catch (Exception e) {
e.printStackTrace();
}
return httpClient;
}
public static CloseableHttpClient getConnection() {
RequestConfig config = RequestConfig.custom().setConnectTimeout(5000).setConnectionRequestTimeout(5000).setSocketTimeout(5000).build();
CloseableHttpClient httpClient = HttpClients.custom()
// 设置连接池管理
.setConnectionManager(poolConnManager)
.setDefaultRequestConfig(config)
// 设置重试次数
.setRetryHandler(new DefaultHttpRequestRetryHandler(2,false)).build();
return httpClient;
}
//生成随机字符串nonce_str
public String getNonceStr() {
String base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 32; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
public String createSign(SortedMap<String, Object> paramsMap) {
List<String> paramsArr = new ArrayList<>();
for (Map.Entry<String, Object> entry : paramsMap.entrySet()) {
String key = entry.getKey();
if (key.equals("other_settle_params")) {
continue;
}
String value = entry.getValue().toString();
value = value.trim();
if (value.startsWith("\"") && value.endsWith("\"") && value.length() > 1) {
value = value.substring(1, value.length() - 1);
}
value = value.trim();
if (value.equals("") || value.equals("null")) {
continue;
}
switch (key) {
case "app_id":
case "thirdparty_id":
case "sign":
break;
default:
paramsArr.add(value);
break;
}
}
paramsArr.add(SALT);
Collections.sort(paramsArr);
StringBuilder signStr = new StringBuilder();
String sep = "";
for (String s : paramsArr) {
signStr.append(sep).append(s);
sep = "&";
}
return md5FromStr(signStr.toString());
}
public static String md5FromStr(String inStr) {
MessageDigest md5;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return "";
}
byte[] byteArray = inStr.getBytes(StandardCharsets.UTF_8);
byte[] md5Bytes = md5.digest(byteArray);
StringBuilder hexValue = new StringBuilder();
for (byte md5Byte : md5Bytes) {
int val = ((int) md5Byte) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
public String getPartnerKey() {
return this.partnerKey;
}
public boolean notifySign(Map<String, String> result, String sign) {
String argNotifySign = getStringByStringMap(result) + "&key=" + this.partnerKey;
String notifySign = MD5Utils.md5(argNotifySign).toUpperCase();
if (notifySign.equals(sign)) {
return true;
} else {
return false;
}
}
public static String getStringByStringMap(Map<String, String> map) {
SortedMap<String, Object> smap = new TreeMap<String, Object>(map);
StringBuffer sb = new StringBuffer();
for (Map.Entry<String, Object> m : smap.entrySet()) {
sb.append(m.getKey()).append("=").append(m.getValue()).append("&");
}
sb.delete(sb.length() - 1, sb.length());
return sb.toString();
}
public static void main(String[] args) {
SortedMap<String, Object> paramMap = new TreeMap<String, Object>();
paramMap.put("appid", "wx86f9777acf2cb585");
paramMap.put("partnerid", "1551961491");
paramMap.put("prepayid", "wx26131443671359787bb3996a1fa0fc0000");
paramMap.put("package", "Sign=WXPay");
paramMap.put("noncestr", "rGcsOnNdZ4d9zu6k3yCbVJRG8Ombp8VW");
paramMap.put("timestamp", "1627276483");
String sign = PayDouYinpayUtils.getInstance().createSign(paramMap);
System.out.println("1627274771===="+sign);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment