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

Commit 16fee3db authored by anjiabin's avatar anjiabin

提交unionpay代码

parent 8aed8bc2
......@@ -37,7 +37,7 @@ public class DragonConstant {
}
public enum DeviceFromEnum{
WEB("web",""),WAP("wap","")
WEB("web",""),WAP("wap",""),WAPPAGE("wappage","")
,APP("app",""),JS("js",""),APPLET("applet","");
private String code;
private String message;
......
......@@ -36,6 +36,8 @@ public class DragonPayBaseRespDto implements Serializable {
private PayData payData;
private String payType;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class PayData{
......
......@@ -35,6 +35,7 @@ liquidnet:
appId: wx3498304dda39c5a1
partnerKey: itIuO65O9yKmemOu3S8g1S4orqvCGwXK
unionpay:
merchantId: 777290058194736
gateway-url: https://gateway.test.95516.com
certs-path: /Users/anjiabin/certs
......@@ -91,6 +91,7 @@ public abstract class AbstractAlipayStrategy implements IAlipayStrategy {
*/
protected DragonPayBaseRespDto buildCommonRespDto(DragonPayBaseReqDto dragonPayBaseReqDto){
DragonPayBaseRespDto respDto = new DragonPayBaseRespDto();
respDto.setPayType(dragonPayBaseReqDto.getPayType());
respDto.setCode(dragonPayBaseReqDto.getCode());
respDto.setOrderCode(dragonPayBaseReqDto.getOrderCode());
DragonPayBaseRespDto.PayData payData = new DragonPayBaseRespDto.PayData();
......
package com.liquidnet.service.dragon.channel.strategy.impl;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
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.alipay.biz.AlipayBiz;
import com.liquidnet.service.dragon.channel.alipay.constant.AlipayConstant;
import com.liquidnet.service.dragon.channel.alipay.strategy.AlipayStrategyContext;
import com.liquidnet.service.dragon.channel.strategy.annotation.StrategyPayChannelHandler;
import com.liquidnet.service.dragon.channel.strategy.biz.DragonPayBiz;
import com.liquidnet.service.dragon.channel.unionpay.biz.UnionpayBiz;
import com.liquidnet.service.dragon.channel.unionpay.strategy.UnionpayStrategyContext;
import com.liquidnet.service.dragon.constant.DragonConstant;
import com.liquidnet.service.dragon.constant.DragonErrorCodeEnum;
import com.liquidnet.service.dragon.dto.DragonOrdersDto;
......@@ -23,11 +19,9 @@ import com.liquidnet.service.dragon.service.impl.DragonOrderRefundsServiceImpl;
import com.liquidnet.service.dragon.utils.DataUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
......@@ -45,13 +39,13 @@ import java.util.Map;
@StrategyPayChannelHandler(DragonConstant.PayChannelEnum.UNIONPAY)
public class PayChannelStrategyUnionpayImpl extends AbstractPayChannelStrategyImpl {
@Autowired
private AlipayStrategyContext alipayStrategyContext;
private UnionpayStrategyContext unionpayStrategyContext;
@Autowired
private DataUtils dataUtils;
@Autowired
private AlipayBiz alipayBiz;
private UnionpayBiz unionpayBiz;
@Autowired
private DragonPayBiz dragonPayBiz;
......@@ -62,29 +56,18 @@ public class PayChannelStrategyUnionpayImpl extends AbstractPayChannelStrategyIm
@Autowired
private DragonOrderRefundsServiceImpl dragonOrderRefundsService;
@Value("${liquidnet.dragon.alipay.appId}")
private String appId;
@Value("${liquidnet.dragon.alipay.merchantPubKey}")
private String merchantPubKey;
@Value("${liquidnet.dragon.alipay.merchantPrivateKey}")
private String merchantPrivateKey;
@Value("${liquidnet.dragon.alipay.signtType}")
private String signtType;
@Value("${liquidnet.dragon.alipay.charset}")
private String charset;
@Override
public ResponseDto<DragonPayBaseRespDto> dragonPay(DragonPayBaseReqDto dragonPayBaseReqDto) {
return alipayStrategyContext.getStrategy(dragonPayBaseReqDto.getDeviceFrom()).dragonPay(dragonPayBaseReqDto);
return unionpayStrategyContext.getStrategy(dragonPayBaseReqDto.getDeviceFrom()).dragonPay(dragonPayBaseReqDto);
}
@Override
public String dragonNotify(HttpServletRequest request,String payType,String deviceFrom) {
log.info("alipay-->notify-->begin payType:{} deviceFrom:{}",payType,deviceFrom);
log.info("unionpay-->notify-->begin payType:{} deviceFrom:{}",payType,deviceFrom);
Map<String, String[]> requestParams = request.getParameterMap();
Map<String, String> notifyMap = new HashMap<String, String>();
notifyMap = alipayBiz.parseNotifyMsg(requestParams);
log.info("dragonNotify-->alipay json : {}", JSON.toJSONString(notifyMap));
notifyMap = unionpayBiz.parseNotifyMsg(requestParams);
log.info("dragonNotify-->unionpay json : {}", JSON.toJSONString(notifyMap));
log.info("接收到{}支付结果{}", payType, notifyMap);
......@@ -111,43 +94,43 @@ public class PayChannelStrategyUnionpayImpl extends AbstractPayChannelStrategyIm
}
try {
if (AlipaySignature.rsaCheckV1(notifyMap, merchantPubKey, "UTF-8", "RSA2")){
String tradeStatus = notifyMap.get("trade_status");
boolean notifyResult = false;
if (AlipayConstant.AlipayTradeStateEnum.TRADE_SUCCESS.name().equals(tradeStatus)
||AlipayConstant.AlipayTradeStateEnum.TRADE_FINISHED.name().equals(tradeStatus)) {
String gmtPaymentStr = notifyMap.get("gmt_payment");// 付款时间
LocalDateTime timeEnd = null;
if (!StringUtil.isEmpty(gmtPaymentStr)) {
timeEnd = DateUtil.Formatter.yyyyMMddHHmmss.parse(gmtPaymentStr);
}
notifyResult = this.completeSuccessOrder(dragonOrdersDto, notifyMap.get("trade_no"), timeEnd, notifyMap.toString());
} else {
notifyResult = this.completeFailOrder(dragonOrdersDto, notifyMap.toString());
}
if(notifyResult){
returnStr = "success";
}
} else {// 验证失败
log.error("alipay notify fail code:{} msg:{} ",DragonErrorCodeEnum.TRADE_ALIPAY_SIGN_ERROR.getCode(),DragonErrorCodeEnum.TRADE_ALIPAY_SIGN_ERROR.getMessage());
return returnStr;
}
} catch (AlipayApiException e) {
log.error("alipay notify fail 验签失败:e:{}" , e);
log.error("alipay notify fail 验签失败:code:{} msg:{}" ,DragonErrorCodeEnum.TRADE_ALIPAY_SIGN_ERROR.getCode(),DragonErrorCodeEnum.TRADE_ALIPAY_SIGN_ERROR.getMessage());
// if (AlipaySignature.rsaCheckV1(notifyMap, merchantPubKey, "UTF-8", "RSA2")){
// String tradeStatus = notifyMap.get("trade_status");
// boolean notifyResult = false;
//
// if (AlipayConstant.AlipayTradeStateEnum.TRADE_SUCCESS.name().equals(tradeStatus)
// ||AlipayConstant.AlipayTradeStateEnum.TRADE_FINISHED.name().equals(tradeStatus)) {
//
// String gmtPaymentStr = notifyMap.get("gmt_payment");// 付款时间
// LocalDateTime timeEnd = null;
// if (!StringUtil.isEmpty(gmtPaymentStr)) {
// timeEnd = DateUtil.Formatter.yyyyMMddHHmmss.parse(gmtPaymentStr);
// }
// notifyResult = this.completeSuccessOrder(dragonOrdersDto, notifyMap.get("trade_no"), timeEnd, notifyMap.toString());
// } else {
// notifyResult = this.completeFailOrder(dragonOrdersDto, notifyMap.toString());
// }
// if(notifyResult){
// returnStr = "success";
// }
// } else {// 验证失败
// log.error("unionpay notify fail code:{} msg:{} ",DragonErrorCodeEnum.TRADE_ALIPAY_SIGN_ERROR.getCode(),DragonErrorCodeEnum.TRADE_ALIPAY_SIGN_ERROR.getMessage());
// return returnStr;
// }
} catch (Exception e) {
log.error("unionpay notify fail 验签失败:e:{}" , e);
log.error("unionpay notify fail 验签失败:code:{} msg:{}" ,DragonErrorCodeEnum.TRADE_ALIPAY_SIGN_ERROR.getCode(),DragonErrorCodeEnum.TRADE_ALIPAY_SIGN_ERROR.getMessage());
}
log.info("返回支付通道{}信息{}", payType, returnStr);
log.info("alipay-->notify-->end payType:{} deviceFrom:{}",payType,deviceFrom);
log.info("unionpay-->notify-->end payType:{} deviceFrom:{}",payType,deviceFrom);
return returnStr;
}
@Override
public DragonPayOrderQueryRespDto checkOrderStatus(String code) {
DragonOrdersDto ordersDto = dataUtils.getPayOrderByCode(code);
Map<String, Object> resultMap = alipayBiz.tradeQuery(code);
Map<String, Object> resultMap = unionpayBiz.tradeQuery(code);
DragonPayOrderQueryRespDto respDto = dragonPayBiz.buildPayOrderQueryRespDto(ordersDto);
if ("10000".equals(resultMap.get("code"))) {
// 当返回状态为“TRADE_FINISHED”交易成功结束和“TRADE_SUCCESS”支付成功时更新交易状态
......
package com.liquidnet.service.dragon.channel.unionpay.biz;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import com.fasterxml.jackson.core.type.TypeReference;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.commons.lang.util.StringUtil;
import com.liquidnet.service.dragon.channel.alipay.req.AlipayTradePayReq;
import com.liquidnet.service.dragon.channel.alipay.sign.MD5;
import com.liquidnet.service.dragon.utils.ObjectUtil;
import com.liquidnet.service.dragon.utils.PayAlipayUtils;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.service.dragon.channel.unionpay.constant.UnionpayConstant;
import com.liquidnet.service.dragon.channel.unionpay.req.UnionpayTradePayReq;
import com.liquidnet.service.dragon.channel.unionpay.sdk.AcpService;
import com.liquidnet.service.dragon.channel.unionpay.sdk.SDKConfig;
import com.liquidnet.service.dragon.channel.unionpay.sdk.SDKConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
/**
......@@ -33,107 +30,161 @@ import java.util.*;
@Slf4j
@Component
public class UnionpayBiz {
@Autowired
private SDKConfig sdkConfig;
@Autowired
private AcpService acpService;
@Value("${liquidnet.dragon.unionpay.merchantId}")
private String merchantId;
/**
* tradeWapPay
* @param alipayTradePayReq
* @param payReq
* @return
*/
public static Map<String, Object> tradeWapPay(AlipayTradePayReq alipayTradePayReq) {
log.info("AlipayBiz.tradeWapPay-->> req : {}",alipayTradePayReq.toString());
String timeExpress = "5m";// 支付超时,线下扫码交易定义为5分钟
AlipayClient alipayClient = PayAlipayUtils.getInstance().getHttpClient();
SortedMap<String, Object> paramMap = new TreeMap<>();
paramMap.put("product_code", alipayTradePayReq.getProductCode());
paramMap.put("total_amount", alipayTradePayReq.getTotalAmount().toString());
paramMap.put("subject", alipayTradePayReq.getSubject());
paramMap.put("body", alipayTradePayReq.getBody());
paramMap.put("out_trade_no", alipayTradePayReq.getOutTradeNo());
paramMap.put("timeout_express", timeExpress);
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
request.setNotifyUrl(alipayTradePayReq.getNotifyUrl());
// request.setTimestamp(DateUtil.now());
log.info("bizContent :{}", JsonUtils.toJson(paramMap));
request.setBizContent(JsonUtils.toJson(paramMap));
try {
long startTime = System.currentTimeMillis();
AlipayTradeWapPayResponse response = alipayClient.sdkExecute(request);
// AlipayTradeWapPayResponse response = new AlipayTradeWapPayResponse();
log.info("alipay-alipayClient.sdkExecut->耗时:{}",(System.currentTimeMillis() - startTime)+"毫秒");
// Map<String,Object> responseJSON = JsonUtils.OM().convertValue(response,Map.class);
startTime = System.currentTimeMillis();
Map<String,Object> responseJSON = ObjectUtil.cloneHashMapStringAndObj();
log.info("AlipayUtil-->tradeWapPay-->cloneHashMapStringAndObj 耗时:{}",(System.currentTimeMillis() - startTime)+"毫秒");
responseJSON.put("code",response.getCode());
responseJSON.put("msg",response.getMsg());
responseJSON.put("subCode",response.getSubCode());
responseJSON.put("subMsg",response.getSubMsg());
responseJSON.put("body",response.getBody());
responseJSON.put("merchantOrderNo",response.getMerchantOrderNo());
responseJSON.put("outTradeNo",response.getOutTradeNo());
responseJSON.put("sellerId",response.getSellerId());
responseJSON.put("totalAmount",response.getTotalAmount());
responseJSON.put("tradeNo",response.getTradeNo());
startTime = System.currentTimeMillis();
// log.info("AlipayUtil-->tradeWapPay-->支付宝返回结果:{}", JsonUtils.toJson(response));
log.info("AlipayUtil-->tradeWapPay-->支付宝返回结果 耗时:{}",(System.currentTimeMillis() - startTime)+"毫秒");
return responseJSON;
} catch (Exception e) {
log.error("支付宝支付异常:{}", e);
JSONObject resultJSON = ObjectUtil.cloneJsonObjectObj();
resultJSON.put("outTradeNo", alipayTradePayReq.getOutTradeNo());
resultJSON.put("totalAmount", alipayTradePayReq.getTotalAmount().toString());
resultJSON.put("errorCode", "9999");
return resultJSON;
}
public Map<String, String> tradeWapPay(UnionpayTradePayReq payReq) {
log.info("UnionpayBiz.tradeWapPay-->> req : {}",payReq.toString());
//前台页面传过来的
String txnAmt = "100";
String orderId = IDGenerator.payCode();
//设置订单过期时间
String txnTime = DateUtil.format(LocalDateTime.now(),DateUtil.Formatter.yyyyMMddHHmmssTrim);
Map<String, String> requestData = new HashMap<String, String>();
/***银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改***/
requestData.put("version", sdkConfig.getVersion()); //版本号,全渠道默认值
requestData.put("encoding", UnionpayConstant.encoding); //字符集编码,可以使用UTF-8,GBK两种方式
requestData.put("signMethod", sdkConfig.getSignMethod()); //签名方法
requestData.put("txnType", "01"); //交易类型 ,01:消费
requestData.put("txnSubType", "01"); //交易子类型, 01:自助消费
requestData.put("bizType", "000201"); //业务类型,B2C网关支付,手机wap支付
requestData.put("channelType", "07"); //渠道类型,这个字段区分B2C网关支付和手机wap支付;07:PC,平板 08:手机
/***商户接入参数***/
requestData.put("merId", payReq.getMerId()); //商户号码,请改成自己申请的正式商户号或者open上注册得来的777测试商户号
requestData.put("accessType", "0"); //接入类型,0:直连商户
requestData.put("orderId",orderId); //商户订单号,8-40位数字字母,不能含“-”或“_”,可以自行定制规则
requestData.put("txnTime", txnTime); //订单发送时间,取系统时间,格式为yyyyMMddHHmmss,必须取当前时间,否则会报txnTime无效
requestData.put("currencyCode", "156"); //交易币种(境内商户一般是156 人民币)
requestData.put("txnAmt", txnAmt); //交易金额,单位分,不要带小数点
//requestData.put("reqReserved", "透传字段"); //请求方保留域,如需使用请启用即可;透传字段(可以实现商户自定义参数的追踪)本交易的后台通知,对本交易的交易状态查询交易、对账文件中均会原样返回,商户可以按需上传,长度为1-1024个字节。出现&={}[]符号时可能导致查询接口应答报文解析失败,建议尽量只传字母数字并使用|分割,或者可以最外层做一次base64编码(base64编码之后出现的等号不会导致解析失败可以不用管)。
// requestData.put("riskRateInfo", "{commodityName=测试商品名称}");
requestData.put("riskRateInfo", "周边商品");
//前台通知地址 (需设置为外网能访问 http https均可),支付成功后的页面 点击“返回商户”按钮的时候将异步通知报文post到该地址
//如果想要实现过几秒中自动跳转回商户页面权限,需联系银联业务申请开通自动返回商户权限
//异步通知参数详见open.unionpay.com帮助中心 下载 产品接口规范 网关支付产品接口规范 消费交易 商户通知
requestData.put("frontUrl", sdkConfig.getFrontUrl());
//后台通知地址(需设置为【外网】能访问 http https均可),支付成功后银联会自动将异步通知报文post到商户上送的该地址,失败的交易银联不会发送后台通知
//后台通知参数详见open.unionpay.com帮助中心 下载 产品接口规范 网关支付产品接口规范 消费交易 商户通知
//注意:1.需设置为外网能访问,否则收不到通知 2.http https均可 3.收单后台通知后需要10秒内返回http200或302状态码
// 4.如果银联通知服务器发送通知后10秒内未收到返回状态码或者应答码非http200,那么银联会间隔一段时间再次发送。总共发送5次,每次的间隔时间为0,1,2,4分钟。
// 5.后台通知地址如果上送了带有?的参数,例如:http://abc/web?a=b&c=d 在后台通知处理程序验证签名之前需要编写逻辑将这些字段去掉再验签,否则将会验签失败
requestData.put("backUrl", sdkConfig.getBackUrl());
// 订单超时时间。
// 超过此时间后,除网银交易外,其他交易银联系统会拒绝受理,提示超时。 跳转银行网银交易如果超时后交易成功,会自动退款,大约5个工作日金额返还到持卡人账户。
// 此时间建议取支付时的北京时间加15分钟。
// 超过超时时间调查询接口应答origRespCode不是A6或者00的就可以判断为失败。
requestData.put("payTimeout", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date().getTime() + 15 * 60 * 1000));
/**请求参数设置完毕,以下对请求参数进行签名并生成html表单,将表单写入浏览器跳转打开银联页面**/
Map<String, String> submitFromData = acpService.sign(requestData,UnionpayConstant.encoding); //报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。
//将生成的html写到浏览器中完成自动跳转打开银联支付页面;这里调用signData之后,将html写到浏览器跳转到银联页面之前均不能对html中的表单项的名称和值进行修改,如果修改会导致验签不通过
return submitFromData;
}
/**
* 支付宝支付
* @param alipayTradePayReq
* @param payReq
* @return
*/
public static Map<String, Object> tradeAppPay(AlipayTradePayReq alipayTradePayReq) {
log.info("AlipayUtil.tradeAppPay-->> req : {}",alipayTradePayReq.toString());
String timeExpress = "5m";// 支付超时,线下扫码交易定义为5分钟
AlipayClient alipayClient = PayAlipayUtils.getInstance().getHttpClient();
SortedMap<String, Object> paramMap = new TreeMap<>();
paramMap.put("product_code", alipayTradePayReq.getProductCode());
paramMap.put("total_amount", alipayTradePayReq.getTotalAmount().toString());
paramMap.put("subject", alipayTradePayReq.getSubject());
paramMap.put("body", alipayTradePayReq.getBody());
paramMap.put("out_trade_no", alipayTradePayReq.getOutTradeNo());
paramMap.put("timeout_express", timeExpress);
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
request.setNotifyUrl(alipayTradePayReq.getNotifyUrl());
// request.setTimestamp(DateUtil.now());
log.info("bizContent :{}",JSONObject.toJSONString(paramMap));
request.setBizContent(JSONObject.toJSONString(paramMap));
try {
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
// JSONObject responseJSON = JSONObject.parseObject(JSONObject.toJSONString(response));
Map<String,Object> responseJSON = JsonUtils.fromJson(JsonUtils.toJson(response), new TypeReference<Map<String,Object>>() {
});
log.info("AlipayUtil-->tradeAppPay-->支付宝返回结果:{}", responseJSON);
return responseJSON;
} catch (AlipayApiException e) {
log.error("支付宝支付异常:{}", e);
JSONObject resultJSON = new JSONObject();
resultJSON.put("outTradeNo", alipayTradePayReq.getOutTradeNo());
resultJSON.put("totalAmount", alipayTradePayReq.getTotalAmount().toString());
resultJSON.put("errorCode", "9999");
return resultJSON;
public Map<String, String> tradeAppPay(UnionpayTradePayReq payReq) {
log.info("UnionpayBiz.tradeAppPay-->> req : {}",payReq.toString());
String txnAmt = "100";
String orderId = IDGenerator.payCode();
//设置订单过期时间
String txnTime = DateUtil.format(LocalDateTime.now(),DateUtil.Formatter.yyyyMMddHHmmssTrim);
Map<String, String> contentData = new HashMap<String, String>();
/***银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改***/
contentData.put("version", sdkConfig.getVersion()); //版本号 全渠道默认值
contentData.put("encoding", UnionpayConstant.encoding); //字符集编码 可以使用UTF-8,GBK两种方式
contentData.put("signMethod", sdkConfig.getSignMethod()); //签名方法
contentData.put("txnType", "01"); //交易类型 01:消费
contentData.put("txnSubType", "01"); //交易子类 01:消费
contentData.put("bizType", "000201"); //填写000201
contentData.put("channelType", "08"); //渠道类型 08手机
/***商户接入参数***/
contentData.put("merId", payReq.getMerId()); //商户号码,请改成自己申请的商户号或者open上注册得来的777商户号测试
contentData.put("accessType", "0"); //接入类型,商户接入填0 ,不需修改(0:直连商户, 1: 收单机构 2:平台商户)
contentData.put("orderId", orderId); //商户订单号,8-40位数字字母,不能含“-”或“_”,可以自行定制规则
contentData.put("txnTime", txnTime); //订单发送时间,取系统时间,格式为yyyyMMddHHmmss,必须取当前时间,否则会报txnTime无效
contentData.put("accType", "01"); //账号类型 01:银行卡02:存折03:IC卡帐号类型(卡介质)
contentData.put("txnAmt", txnAmt); //交易金额 单位为分,不能带小数点
contentData.put("currencyCode", "156"); //境内商户固定 156 人民币
// 请求方保留域,
// 透传字段,查询、通知、对账文件中均会原样出现,如有需要请启用并修改自己希望透传的数据。
// 出现部分特殊字符时可能影响解析,请按下面建议的方式填写:
// 1. 如果能确定内容不会出现&={}[]"'等符号时,可以直接填写数据,建议的方法如下。
// contentData.put("reqReserved", "透传信息1|透传信息2|透传信息3");
// 2. 内容可能出现&={}[]"'符号时:
// 1) 如果需要对账文件里能显示,可将字符替换成全角&={}【】“‘字符(自己写代码,此处不演示);
// 2) 如果对账文件没有显示要求,可做一下base64(如下)。
// 注意控制数据长度,实际传输的数据长度不能超过1024位。
// 查询、通知等接口解析时使用new String(Base64.decodeBase64(reqReserved), UnionpayConstant.encoding);解base64后再对数据做后续解析。
// contentData.put("reqReserved", Base64.encodeBase64String("任意格式的信息都可以".toString().getBytes(UnionpayConstant.encoding)));
//后台通知地址(需设置为外网能访问 http https均可),支付成功后银联会自动将异步通知报文post到商户上送的该地址,【支付失败的交易银联不会发送后台通知】
//后台通知参数详见open.unionpay.com帮助中心 下载 产品接口规范 网关支付产品接口规范 消费交易 商户通知
//注意:1.需设置为外网能访问,否则收不到通知 2.http https均可 3.收单后台通知后需要10秒内返回http200或302状态码
// 4.如果银联通知服务器发送通知后10秒内未收到返回状态码或者应答码非http200或302,那么银联会间隔一段时间再次发送。总共发送5次,银联后续间隔1、2、4、5 分钟后会再次通知。
// 5.后台通知地址如果上送了带有?的参数,例如:http://abc/web?a=b&c=d 在后台通知处理程序验证签名之前需要编写逻辑将这些字段去掉再验签,否则将会验签失败
contentData.put("backUrl", sdkConfig.getBackUrl());
/**对请求参数进行签名并发送http post请求,接收同步应答报文**/
Map<String, String> reqData = acpService.sign(contentData,UnionpayConstant.encoding); //报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。
String requestAppUrl = sdkConfig.getAppTransUrl(); //交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.backTransUrl
Map<String, String> rspData = acpService.post(reqData,requestAppUrl,UnionpayConstant.encoding); //发送请求报文并接受同步应答(默认连接超时时间30秒,读取返回结果超时时间30秒);这里调用signData之后,调用submitUrl之前不能对submitFromData中的键值对做任何修改,如果修改会导致验签不通过
/**对应答码的处理,请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考------------->**/
//应答码规范参考open.unionpay.com帮助中心 下载 产品接口规范 《平台接入接口规范-第5部分-附录》
if(!rspData.isEmpty()){
if(acpService.validate(rspData, UnionpayConstant.encoding)){
log.info("验证签名成功");
String respCode = rspData.get("respCode") ;
if(("00").equals(respCode)){
//成功,获取tn号
//String tn = resmap.get("tn");
//TODO
log.info("成功返回结果 :{}");
}else{
//其他应答码为失败请排查原因或做失败处理
//TODO
String respMsg = rspData.get("respMsg") ;
log.info("失败返回结果 respMsg:{}",respMsg);
}
}else{
log.error("验证签名失败");
//TODO 检查验证签名失败的原因
}
}else{
//未返回正确的http状态
log.error("未获取到返回报文或返回http状态码非200");
}
String reqMessage = this.genHtmlResult(reqData);
String rspMessage = this.genHtmlResult(rspData);
log.info("请求报文:<br/>"+reqMessage+"<br/>");
log.info("应答报文:</br>"+rspMessage+"");
return rspData;
}
......@@ -142,33 +193,263 @@ public class UnionpayBiz {
*
* @return
*/
public static Map<String, Object> tradeQuery(String outTradeNo) {
log.info("AlipayBiz.tradeQuery-->> 支付宝交易查询");
AlipayClient alipayClient = PayAlipayUtils.getInstance().getHttpClient();
SortedMap<String, Object> bizContentMap = new TreeMap<>();
bizContentMap.put("out_trade_no", outTradeNo);
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent(JSONObject.toJSONString(bizContentMap));
try {
AlipayTradeQueryResponse response = alipayClient.execute(request);
JSONObject responseJSON = JSONObject.parseObject(JSONObject.toJSONString(response));
log.info("支付宝订单查询返回结果:{}", responseJSON);
return responseJSON;
} catch (AlipayApiException e) {
log.error("支付宝交易查询异常:{}", e);
return null;
public Map<String, Object> tradeQuery(String outTradeNo) {
log.info("UnionpayBiz.tradeQuery-->> ");
String orderId = "PAY202111091417193102493371";
String txnTime = DateUtil.format(LocalDateTime.now(),DateUtil.Formatter.yyyyMMddHHmmssTrim);
Map<String, String> data = new HashMap<String, String>();
/***银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改***/
data.put("version", sdkConfig.getVersion()); //版本号
data.put("encoding", UnionpayConstant.encoding); //字符集编码 可以使用UTF-8,GBK两种方式
data.put("signMethod", sdkConfig.getSignMethod()); //签名方法
data.put("txnType", "00"); //交易类型 00-默认
data.put("txnSubType", "00"); //交易子类型 默认00
data.put("bizType", "000201"); //业务类型
/***商户接入参数***/
data.put("merId", merchantId); //商户号码,请改成自己申请的商户号或者open上注册得来的777商户号测试
data.put("accessType", "0"); //接入类型,商户接入固定填0,不需修改
/***要调通交易以下字段必须修改***/
data.put("orderId", orderId); //****商户订单号,每次发交易测试需修改为被查询的交易的订单号
data.put("txnTime", txnTime); //****订单发送时间,每次发交易测试需修改为被查询的交易的订单发送时间
/**请求参数设置完毕,以下对请求参数进行签名并发送http post请求,接收同步应答报文------------->**/
Map<String, String> reqData = acpService.sign(data,UnionpayConstant.encoding); //报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。
String url = sdkConfig.getSingleQueryUrl(); //交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.singleQueryUrl
Map<String, String> rspData = acpService.post(reqData, url,UnionpayConstant.encoding); //发送请求报文并接受同步应答(默认连接超时时间30秒,读取返回结果超时时间30秒);这里调用signData之后,调用submitUrl之前不能对submitFromData中的键值对做任何修改,如果修改会导致验签不通过
/**对应答码的处理,请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考------------->**/
//应答码规范参考open.unionpay.com帮助中心 下载 产品接口规范 《平台接入接口规范-第5部分-附录》
if(!rspData.isEmpty()){
if(acpService.validate(rspData, UnionpayConstant.encoding)){
log.info("验证签名成功");
if(("00").equals(rspData.get("respCode"))){//如果查询交易成功
String origRespCode = rspData.get("origRespCode");
if(("00").equals(origRespCode)){
//交易成功,更新商户订单状态
//TODO
}else if(("03").equals(origRespCode)||
("04").equals(origRespCode)||
("05").equals(origRespCode)){
//订单处理中或交易状态未明,需稍后发起交易状态查询交易 【如果最终尚未确定交易是否成功请以对账文件为准】
//TODO
}else{
//其他应答码为交易失败
//TODO
}
}else if(("34").equals(rspData.get("respCode"))){
//订单不存在,可认为交易状态未明,需要稍后发起交易状态查询,或依据对账结果为准
}else{//查询交易本身失败,如应答码10/11检查查询报文是否正确
//TODO
}
}else{
log.error("验证签名失败");
//TODO 检查验证签名失败的原因
}
}else{
//未返回正确的http状态
log.error("未获取到返回报文或返回http状态码非200");
}
String reqMessage = this.genHtmlResult(reqData);
String rspMessage = this.genHtmlResult(rspData);
log.info("请求报文:<br/>"+reqMessage+"<br/>");
log.info("应答报文:</br>"+rspMessage+"");
return null;
}
public Map<String, Object> appSingleRefund()
throws ServletException, IOException {
String txnTime = DateUtil.format(LocalDateTime.now(),DateUtil.Formatter.yyyyMMddHHmmssTrim);
String txnAmt = "100";
String origQryId = "892111091417195454008";
Map<String, String> data = new HashMap<String, String>();
/***银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改***/
data.put("version", sdkConfig.getVersion()); //版本号
data.put("encoding", UnionpayConstant.encoding); //字符集编码 可以使用UTF-8,GBK两种方式
data.put("signMethod", sdkConfig.getSignMethod()); //签名方法
data.put("txnType", "04"); //交易类型 04-退货
data.put("txnSubType", "00"); //交易子类型 默认00
data.put("bizType", "000201"); //业务类型
data.put("channelType", "08"); //渠道类型,07-PC,08-手机
/***商户接入参数***/
data.put("merId", merchantId); //商户号码,请改成自己申请的商户号或者open上注册得来的777商户号测试
data.put("accessType", "0"); //接入类型,商户接入固定填0,不需修改
data.put("orderId", IDGenerator.refundCode()); //商户订单号,8-40位数字字母,不能含“-”或“_”,可以自行定制规则,重新产生,不同于原消费
data.put("txnTime", txnTime); //订单发送时间,格式为yyyyMMddHHmmss,必须取当前时间,否则会报txnTime无效
data.put("currencyCode", "156"); //交易币种(境内商户一般是156 人民币)
data.put("txnAmt", txnAmt); //****退货金额,单位分,不要带小数点。退货金额小于等于原消费金额,当小于的时候可以多次退货至退货累计金额等于原消费金额
data.put("backUrl", sdkConfig.getBackUrl()); //后台通知地址,后台通知参数详见open.unionpay.com帮助中心 下载 产品接口规范 网关支付产品接口规范 退货交易 商户通知,其他说明同消费交易的后台通知
/***要调通交易以下字段必须修改***/
data.put("origQryId", origQryId); //****原消费交易返回的的queryId,可以从消费交易后台通知接口中或者交易状态查询接口中获取
// 请求方保留域,
// 透传字段,查询、通知、对账文件中均会原样出现,如有需要请启用并修改自己希望透传的数据。
// 出现部分特殊字符时可能影响解析,请按下面建议的方式填写:
// 1. 如果能确定内容不会出现&={}[]"'等符号时,可以直接填写数据,建议的方法如下。
// data.put("reqReserved", "透传信息1|透传信息2|透传信息3");
// 2. 内容可能出现&={}[]"'符号时:
// 1) 如果需要对账文件里能显示,可将字符替换成全角&={}【】“‘字符(自己写代码,此处不演示);
// 2) 如果对账文件没有显示要求,可做一下base64(如下)。
// 注意控制数据长度,实际传输的数据长度不能超过1024位。
// 查询、通知等接口解析时使用new String(Base64.decodeBase64(reqReserved), UnionpayConstant.encoding);解base64后再对数据做后续解析。
// data.put("reqReserved", Base64.encodeBase64String("任意格式的信息都可以".toString().getBytes(UnionpayConstant.encoding)));
/**请求参数设置完毕,以下对请求参数进行签名并发送http post请求,接收同步应答报文------------->**/
Map<String, String> reqData = acpService.sign(data,UnionpayConstant.encoding); //报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。
String url = sdkConfig.getBackTransUrl(); //交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.backTransUrl
Map<String, String> rspData = acpService.post(reqData, url,UnionpayConstant.encoding);//这里调用signData之后,调用submitUrl之前不能对submitFromData中的键值对做任何修改,如果修改会导致验签不通过
/**对应答码的处理,请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考------------->**/
//应答码规范参考open.unionpay.com帮助中心 下载 产品接口规范 《平台接入接口规范-第5部分-附录》
if(!rspData.isEmpty()){
if(acpService.validate(rspData, UnionpayConstant.encoding)){
log.info("验证签名成功");
String respCode = rspData.get("respCode") ;
if(("00").equals(respCode)){
//交易已受理(不代表交易已成功),等待接收后台通知更新订单状态,也可以主动发起 查询交易确定交易状态。
//TODO
}else if(("03").equals(respCode)||
("04").equals(respCode)||
("05").equals(respCode)){
//后续需发起交易状态查询交易确定交易状态
//TODO
}else{
//其他应答码为失败请排查原因
//TODO
}
}else{
log.error("验证签名失败");
//TODO 检查验证签名失败的原因
}
}else{
//未返回正确的http状态
log.error("未获取到返回报文或返回http状态码非200");
}
String reqMessage = this.genHtmlResult(reqData);
String rspMessage = this.genHtmlResult(rspData);
log.info("请求报文:<br/>"+reqMessage+"<br/>");
log.info("应答报文:</br>"+rspMessage+"");
return null;
}
private static String getSign(SortedMap<String, String> paramMap, String key) {
StringBuilder signBuilder = new StringBuilder();
for (Map.Entry<String, String> entry : paramMap.entrySet()) {
if (!"sign".equals(entry.getKey()) && !"sign_type".equals(entry.getKey()) && !StringUtil.isEmpty(entry.getValue())) {
signBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
public Map<String, Object> wapSingleRefund()
throws ServletException, IOException {
// String merId = "821690048160PQY";
String txnTime = DateUtil.format(LocalDateTime.now(),DateUtil.Formatter.yyyyMMddHHmmssTrim);
String txnAmt = "100";
String origQryId = "892111091417195454008";
Map<String, String> data = new HashMap<String, String>();
/***银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改***/
data.put("version", sdkConfig.getVersion()); //版本号
data.put("encoding", UnionpayConstant.encoding); //字符集编码 可以使用UTF-8,GBK两种方式
data.put("signMethod", sdkConfig.getSignMethod()); //签名方法
data.put("txnType", "04"); //交易类型 04-退货
data.put("txnSubType", "00"); //交易子类型 默认00
data.put("bizType", "000201"); //业务类型
data.put("channelType", "08"); //渠道类型,07-PC,08-手机
/***商户接入参数***/
data.put("merId", merchantId); //商户号码,请改成自己申请的商户号或者open上注册得来的777商户号测试
data.put("accessType", "0"); //接入类型,商户接入固定填0,不需修改
data.put("orderId", IDGenerator.refundCode()); //商户订单号,8-40位数字字母,不能含“-”或“_”,可以自行定制规则,重新产生,不同于原消费
data.put("txnTime", txnTime); //订单发送时间,格式为yyyyMMddHHmmss,必须取当前时间,否则会报txnTime无效
data.put("currencyCode", "156"); //交易币种(境内商户一般是156 人民币)
data.put("txnAmt", txnAmt); //****退货金额,单位分,不要带小数点。退货金额小于等于原消费金额,当小于的时候可以多次退货至退货累计金额等于原消费金额
data.put("backUrl", sdkConfig.getBackUrl()); //后台通知地址,后台通知参数详见open.unionpay.com帮助中心 下载 产品接口规范 网关支付产品接口规范 退货交易 商户通知,其他说明同消费交易的后台通知
/***要调通交易以下字段必须修改***/
data.put("origQryId", origQryId); //****原消费交易返回的的queryId,可以从消费交易后台通知接口中或者交易状态查询接口中获取
// 请求方保留域,
// 透传字段,查询、通知、对账文件中均会原样出现,如有需要请启用并修改自己希望透传的数据。
// 出现部分特殊字符时可能影响解析,请按下面建议的方式填写:
// 1. 如果能确定内容不会出现&={}[]"'等符号时,可以直接填写数据,建议的方法如下。
// data.put("reqReserved", "透传信息1|透传信息2|透传信息3");
// 2. 内容可能出现&={}[]"'符号时:
// 1) 如果需要对账文件里能显示,可将字符替换成全角&={}【】“‘字符(自己写代码,此处不演示);
// 2) 如果对账文件没有显示要求,可做一下base64(如下)。
// 注意控制数据长度,实际传输的数据长度不能超过1024位。
// 查询、通知等接口解析时使用new String(Base64.decodeBase64(reqReserved), UnionpayConstant.encoding);解base64后再对数据做后续解析。
// data.put("reqReserved", Base64.encodeBase64String("任意格式的信息都可以".toString().getBytes(UnionpayConstant.encoding)));
/**请求参数设置完毕,以下对请求参数进行签名并发送http post请求,接收同步应答报文------------->**/
Map<String, String> reqData = acpService.sign(data,UnionpayConstant.encoding); //报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。
String url = sdkConfig.getBackTransUrl(); //交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.backTransUrl
Map<String, String> rspData = acpService.post(reqData, url,UnionpayConstant.encoding);//这里调用signData之后,调用submitUrl之前不能对submitFromData中的键值对做任何修改,如果修改会导致验签不通过
/**对应答码的处理,请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考------------->**/
//应答码规范参考open.unionpay.com帮助中心 下载 产品接口规范 《平台接入接口规范-第5部分-附录》
if(!rspData.isEmpty()){
if(acpService.validate(rspData, UnionpayConstant.encoding)){
log.info("验证签名成功");
String respCode = rspData.get("respCode") ;
if(("00").equals(respCode)){
//交易已受理(不代表交易已成功),等待接收后台通知更新订单状态,也可以主动发起 查询交易确定交易状态。
//TODO
}else if(("03").equals(respCode)||
("04").equals(respCode)||
("05").equals(respCode)){
//后续需发起交易状态查询交易确定交易状态
//TODO
}else{
//其他应答码为失败请排查原因
//TODO
}
}else{
log.error("验证签名失败");
//TODO 检查验证签名失败的原因
}
}else{
//未返回正确的http状态
log.error("未获取到返回报文或返回http状态码非200");
}
String reqMessage = this.genHtmlResult(reqData);
String rspMessage = this.genHtmlResult(rspData);
log.info("请求报文:<br/>"+reqMessage+"<br/>");
log.info("应答报文:</br>"+rspMessage+"");
return null;
}
/**
* 组装请求,返回报文字符串用于显示
* @param data
* @return
*/
private String genHtmlResult(Map<String, String> data){
TreeMap<String, String> tree = new TreeMap<String, String>();
Iterator<Map.Entry<String, String>> it = data.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> en = it.next();
tree.put(en.getKey(), en.getValue());
}
it = tree.entrySet().iterator();
StringBuffer sf = new StringBuffer();
while (it.hasNext()) {
Map.Entry<String, String> en = it.next();
String key = en.getKey();
String value = en.getValue();
if("respCode".equals(key)){
sf.append("<b>"+key + SDKConstants.EQUAL + value+"</br></b>");
}else
sf.append(key + SDKConstants.EQUAL + value+"</br>");
}
return MD5.sign(signBuilder.substring(0, signBuilder.length() - 1), key, "UTF-8");
return sf.toString();
}
public static Map<String , String> parseNotifyMsg(Map<String, String[]> requestParams){
......
......@@ -10,24 +10,6 @@ package com.liquidnet.service.dragon.channel.unionpay.constant;
* @date 2021/11/8 18:12
*/
public class UnionpayConstant {
public enum UnionpayTradeStateEnum {
TRADE_CLOSED ("TRADE_CLOSED","交易关闭"),
TRADE_FINISHED ("TRADE_FINISHED","支付完成"),
TRADE_SUCCESS ("TRADE_SUCCESS","支付成功"),
WAIT_BUYER_PAY ("WAIT_BUYER_PAY","交易创建"),
FAIL("","支付失败");
private String code;
private String message;
UnionpayTradeStateEnum(String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
}
//默认配置的是UTF-8
public static String encoding = "UTF-8";
}
package com.liquidnet.service.dragon.channel.unionpay.req;
import lombok.Data;
/**
* @author AnJiabin <anjiabin@zhengzai.tv>
* @version V1.0
* @Description: TODO
* @class: UnionpayBaseReq
* @Package com.liquidnet.service.dragon.channel.unionpay.req
* @Copyright: LightNet @ Copyright (c) 2021
* @date 2021/11/10 11:20
*/
@Data
public class UnionpayBaseReq {
/***银联全渠道系统,产品参数***/
private String version;
private String encoding;
private String signMethod;
private String txnType;
private String txnSubType;
private String bizType;
private String channelType;
/***商户接入参数***/
private String merId;
private String accessType;
private String orderId;
private String txnTime;
private String txnAmt;
private String currencyCode;
private String backUrl;
/***app支付接入***/
private String accType; //
/***wap支付接入***/
private String riskRateInfo;
private String frontUrl;
private String payTimeout;
}
......@@ -4,28 +4,19 @@ import com.alibaba.fastjson.JSON;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @author AnJiabin <anjiabin@zhengzai.tv>
* @version V1.0
* @Description: TODO
* @class: AlipayTradePayReq
* @Package com.liquidnet.service.dragon.channel.alipay.req
* @class: UnionpayTradePayReq
* @Package com.liquidnet.service.dragon.channel.unionpay.req
* @Copyright: LightNet @ Copyright (c) 2021
* @date 2021/7/9 17:50
*/
@Data
public class UnionpayTradePayReq implements Serializable, Cloneable{
public class UnionpayTradePayReq extends UnionpayBaseReq implements Serializable, Cloneable{
private static final long serialVersionUID = -5827961038383330701L;
private String productCode;
private BigDecimal totalAmount;
private String subject;
private String body;
private String outTradeNo;
private String timeExpire;
private String notifyUrl;
private String timestamp;
@Override
public String toString(){
return JSON.toJSONString(this);
......
package com.liquidnet.service.dragon.channel.unionpay.strategy.impl;
import com.liquidnet.commons.lang.util.DateUtil;
import com.alibaba.fastjson.JSON;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.dragon.biz.DragonServiceCommonBiz;
import com.liquidnet.service.dragon.channel.alipay.req.AlipayTradePayReq;
import com.liquidnet.service.dragon.channel.strategy.biz.DragonPayBiz;
import com.liquidnet.service.dragon.channel.unionpay.req.UnionpayTradePayReq;
import com.liquidnet.service.dragon.channel.unionpay.sdk.SDKConfig;
import com.liquidnet.service.dragon.channel.unionpay.sdk.SDKConstants;
import com.liquidnet.service.dragon.channel.unionpay.strategy.IUnionpayStrategy;
import com.liquidnet.service.dragon.dto.DragonPayBaseReqDto;
import com.liquidnet.service.dragon.dto.DragonPayBaseRespDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import java.math.BigDecimal;
import java.util.Map;
/**
......@@ -29,34 +33,27 @@ public abstract class AbstractUnionPayStrategy implements IUnionpayStrategy {
private DragonPayBiz dragonPayBiz;
@Autowired
private DragonServiceCommonBiz dragonServiceCommonBiz;
private SDKConfig sdkConfig;
@Autowired
private DragonServiceCommonBiz dragonServiceCommonBiz;
protected String productCode = "QUICK_WAP_PAY";
@Value("${liquidnet.dragon.unionpay.merchantId}")
private String merchantId;
@Override
public ResponseDto<DragonPayBaseRespDto> dragonPay(DragonPayBaseReqDto dragonPayBaseReqDto) {
//设置productCode
setProductCode();
AlipayTradePayReq alipayTradePayReq = AlipayTradePayReq.getNew();
alipayTradePayReq.setProductCode(this.productCode);
alipayTradePayReq.setTotalAmount(dragonPayBaseReqDto.getPrice());
alipayTradePayReq.setSubject(dragonPayBaseReqDto.getName());
alipayTradePayReq.setBody(dragonPayBaseReqDto.getDetail());
//dragon中支付编号
alipayTradePayReq.setOutTradeNo(dragonPayBaseReqDto.getCode());
//设置订单过期时间
String timeExpire = DateUtil.format(DateUtil.Formatter.yyyyMMddHHmmss.parse(dragonPayBaseReqDto.getCreateDate()).plusMinutes(Long.parseLong(dragonPayBaseReqDto.getExpireTime())),DateUtil.Formatter.yyyyMMddHHmmss);
alipayTradePayReq.setTimeExpire(timeExpire);
alipayTradePayReq.setNotifyUrl(this.getNotifyUrl());
alipayTradePayReq.setTimestamp(dragonPayBaseReqDto.getCreateDate());
//构造公共请求参数
UnionpayTradePayReq payReq = this.buildRequestParamMap(dragonPayBaseReqDto);
//构造个性化参数
payReq = this.appendRequestParam(payReq,dragonPayBaseReqDto);
//调用支付
long startTime = System.currentTimeMillis();
Map<String, Object> result = this.executePay(alipayTradePayReq);
// log.info("dragonPay:alipay:"+dragonPayBaseReqDto.getDeviceFrom()+" response xmlStr: {} ", JSON.toJSONString(result));
log.info("alipay-dragonPay->耗时:{}",(System.currentTimeMillis() - startTime)+"毫秒");
Map<String, String> result = this.executePay(payReq);
log.debug("dragonPay:unionpay:"+dragonPayBaseReqDto.getDeviceFrom()+" response xmlStr: {} ", JSON.toJSONString(result));
log.info("unionpay-dragonPay->耗时:{}",(System.currentTimeMillis() - startTime)+"毫秒");
//拼接返回参数
DragonPayBaseRespDto respDto = buildCommonRespDto(dragonPayBaseReqDto);
respDto = this.buildResponseDto(respDto,result);
......@@ -69,20 +66,48 @@ public abstract class AbstractUnionPayStrategy implements IUnionpayStrategy {
/**
* 支付请求
* @param alipayTradePayReq
* @param payReq
* @return
*/
protected abstract Map<String, Object> executePay(AlipayTradePayReq alipayTradePayReq);
protected abstract Map<String, String> executePay(UnionpayTradePayReq payReq);
/**
* 设置productCode
* 设置notifyUrl
*/
protected abstract void setProductCode();
protected abstract String getNotifyUrl();
/**
* 设置notifyUrl
* 构造请求参数
* @param dragonPayBaseReqDto
* @return
*/
protected abstract String getNotifyUrl();
protected UnionpayTradePayReq buildRequestParamMap(DragonPayBaseReqDto dragonPayBaseReqDto){
UnionpayTradePayReq payReq = UnionpayTradePayReq.getNew();
payReq.setVersion(sdkConfig.getVersion());
payReq.setEncoding(SDKConstants.UTF_8_ENCODING);
payReq.setSignMethod(sdkConfig.getSignMethod());
payReq.setTxnType("01");
payReq.setTxnSubType("01");
payReq.setBizType("000201");
payReq.setChannelType("08");
payReq.setMerId(merchantId);
payReq.setAccessType("0");
payReq.setOrderId(dragonPayBaseReqDto.getCode());
payReq.setTxnTime(dragonPayBaseReqDto.getCreateDate());
payReq.setTxnAmt(dragonPayBaseReqDto.getPrice().multiply(BigDecimal.valueOf(100L)).intValue()+"");
payReq.setCurrencyCode("156");
payReq.setBackUrl(this.getNotifyUrl());
return payReq;
};
/**
* 追加请求参数
* @param payReq
* @return
*/
abstract UnionpayTradePayReq appendRequestParam(UnionpayTradePayReq payReq,DragonPayBaseReqDto dragonPayBaseReqDto);
/**
* 构造公共返回参数
......@@ -91,6 +116,7 @@ public abstract class AbstractUnionPayStrategy implements IUnionpayStrategy {
*/
protected DragonPayBaseRespDto buildCommonRespDto(DragonPayBaseReqDto dragonPayBaseReqDto){
DragonPayBaseRespDto respDto = new DragonPayBaseRespDto();
respDto.setPayType(dragonPayBaseReqDto.getPayType());
respDto.setCode(dragonPayBaseReqDto.getCode());
respDto.setOrderCode(dragonPayBaseReqDto.getOrderCode());
DragonPayBaseRespDto.PayData payData = new DragonPayBaseRespDto.PayData();
......@@ -101,6 +127,6 @@ public abstract class AbstractUnionPayStrategy implements IUnionpayStrategy {
/**
* 构造返回参数
*/
abstract DragonPayBaseRespDto buildResponseDto(DragonPayBaseRespDto payBaseRespDto,Map<String, Object> respResult);
abstract DragonPayBaseRespDto buildResponseDto(DragonPayBaseRespDto payBaseRespDto,Map<String, String> respResult);
}
package com.liquidnet.service.dragon.channel.unionpay.strategy.impl;
import com.liquidnet.service.dragon.channel.alipay.biz.AlipayBiz;
import com.liquidnet.service.dragon.channel.alipay.req.AlipayTradePayReq;
import com.liquidnet.commons.lang.util.StringUtil;
import com.liquidnet.service.dragon.channel.unionpay.biz.UnionpayBiz;
import com.liquidnet.service.dragon.channel.unionpay.req.UnionpayTradePayReq;
import com.liquidnet.service.dragon.channel.unionpay.strategy.annotation.StrategyUnionpayHandler;
import com.liquidnet.service.dragon.constant.DragonConstant;
import com.liquidnet.service.dragon.dto.DragonPayBaseReqDto;
import com.liquidnet.service.dragon.dto.DragonPayBaseRespDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -17,7 +19,7 @@ import java.util.Map;
* @author AnJiabin <anjiabin@zhengzai.tv>
* @version V1.0
* @Description: TODO
* @class: AlipayStrategyWapImpl
* @class: UnionpayStrategyAppImpl
* @Package com.liquidnet.service.dragon.channel.unionpay.strategy.impl
* @Copyright: LightNet @ Copyright (c) 2021
* @date 2021/11/08 18:34
......@@ -26,9 +28,6 @@ import java.util.Map;
@Component
@StrategyUnionpayHandler(DragonConstant.DeviceFromEnum.APP)
public class UnionpayStrategyAppImpl extends AbstractUnionPayStrategy {
@Value("${liquidnet.dragon.alipay.gataway-url}")
private String alipayGatewayUrl;
@Value("${liquidnet.dragon.url}")
private String notifyUrl;
......@@ -36,26 +35,30 @@ public class UnionpayStrategyAppImpl extends AbstractUnionPayStrategy {
StringRedisTemplate stringRedisTemplate;
@Autowired
private AlipayBiz alipayBiz;
private UnionpayBiz unionpayBiz;
@Override
protected Map<String, Object> executePay(AlipayTradePayReq alipayTradePayReq) {
return alipayBiz.tradeAppPay(alipayTradePayReq);
protected Map<String, String> executePay(UnionpayTradePayReq payReq) {
return unionpayBiz.tradeAppPay(payReq);
}
protected void setProductCode() {
this.productCode = "QUICK_MSECURITY_PAY";
@Override
protected String getNotifyUrl() {
return notifyUrl + "/notify/unionpay/app";
}
@Override
protected String getNotifyUrl() {
// notifyUrl = "/notify/app/alipay/1";
return notifyUrl + "/notify/alipay/app";
UnionpayTradePayReq appendRequestParam(UnionpayTradePayReq payReq, DragonPayBaseReqDto dragonPayBaseReqDto) {
payReq.setAccType("01");
payReq.setChannelType("08");
return payReq;
}
@Override
DragonPayBaseRespDto buildResponseDto(DragonPayBaseRespDto payBaseRespDto, Map<String, Object> respResult) {
payBaseRespDto.getPayData().setOrderStr(respResult.get("body").toString());
DragonPayBaseRespDto buildResponseDto(DragonPayBaseRespDto payBaseRespDto, Map<String, String> respResult) {
if(StringUtil.isNotNull(respResult)&&respResult.get("tn")!=null){
payBaseRespDto.getPayData().setPrepayId(respResult.get("tn"));
}
return payBaseRespDto;
}
}
package com.liquidnet.service.dragon.channel.unionpay.strategy.impl;
import com.liquidnet.service.dragon.channel.alipay.biz.AlipayBiz;
import com.liquidnet.service.dragon.channel.alipay.req.AlipayTradePayReq;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.commons.lang.util.StringUtil;
import com.liquidnet.service.dragon.channel.unionpay.biz.UnionpayBiz;
import com.liquidnet.service.dragon.channel.unionpay.req.UnionpayTradePayReq;
import com.liquidnet.service.dragon.channel.unionpay.sdk.SDKConfig;
import com.liquidnet.service.dragon.channel.unionpay.strategy.annotation.StrategyUnionpayHandler;
import com.liquidnet.service.dragon.constant.DragonConstant;
import com.liquidnet.service.dragon.dto.DragonPayBaseReqDto;
import com.liquidnet.service.dragon.dto.DragonPayBaseRespDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -17,8 +22,8 @@ import java.util.Map;
* @author AnJiabin <anjiabin@zhengzai.tv>
* @version V1.0
* @Description: TODO
* @class: AlipayStrategyWapImpl
* @Package com.liquidnet.service.dragon.channel.alipay.strategy.impl
* @class: UnionpayStrategyWapImpl
* @Package com.liquidnet.service.dragon.channel.unionpay.strategy.impl
* @Copyright: LightNet @ Copyright (c) 2021
* @date 2021/7/10 14:34
*/
......@@ -26,9 +31,6 @@ import java.util.Map;
@Service
@StrategyUnionpayHandler(DragonConstant.DeviceFromEnum.WAP)
public class UnionpayStrategyWapImpl extends AbstractUnionPayStrategy {
@Value("${liquidnet.dragon.alipay.gataway-url}")
private String alipayGatewayUrl;
@Value("${liquidnet.dragon.url}")
private String notifyUrl;
......@@ -36,26 +38,39 @@ public class UnionpayStrategyWapImpl extends AbstractUnionPayStrategy {
StringRedisTemplate stringRedisTemplate;
@Autowired
private AlipayBiz alipayBiz;
private UnionpayBiz unionpayBiz;
@Autowired
private SDKConfig sdkConfig;
@Override
protected Map<String, Object> executePay(AlipayTradePayReq alipayTradePayReq) {
return alipayBiz.tradeWapPay(alipayTradePayReq);
protected Map<String, String> executePay(UnionpayTradePayReq payReq) {
return unionpayBiz.tradeWapPay(payReq);
}
protected void setProductCode() {
this.productCode = "QUICK_WAP_PAY";
@Override
protected String getNotifyUrl() {
return notifyUrl + "/notify/unionpay/wap";
}
@Override
protected String getNotifyUrl() {
// notifyUrl = "/notify/wap/alipay/1";
return notifyUrl + "/notify/alipay/wap";
UnionpayTradePayReq appendRequestParam(UnionpayTradePayReq payReq, DragonPayBaseReqDto dragonPayBaseReqDto) {
//设置订单过期时间
String timeExpire = DateUtil.format(DateUtil.Formatter.yyyyMMddHHmmss.parse(dragonPayBaseReqDto.getCreateDate()).plusMinutes(Long.parseLong(dragonPayBaseReqDto.getExpireTime())),DateUtil.Formatter.yyyyMMddHHmmss);
payReq.setChannelType("07");
payReq.setRiskRateInfo(dragonPayBaseReqDto.getName());
payReq.setFrontUrl(dragonPayBaseReqDto.getReturnUrl());
payReq.setPayTimeout(timeExpire);
return payReq;
}
@Override
DragonPayBaseRespDto buildResponseDto(DragonPayBaseRespDto payBaseRespDto, Map<String, Object> respResult) {
payBaseRespDto.getPayData().setRedirectUrl(alipayGatewayUrl + "?" + respResult.get("body"));
DragonPayBaseRespDto buildResponseDto(DragonPayBaseRespDto payBaseRespDto, Map<String, String> respResult) {
payBaseRespDto.getPayData().setRedirectUrl(sdkConfig.getFrontTransUrl());
if(StringUtil.isNotNull(respResult)){
payBaseRespDto.getPayData().setOrderStr(JsonUtils.toJson(respResult));
}
return payBaseRespDto;
}
}
package com.liquidnet.service.dragon.channel.unionpay.strategy.impl;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.service.dragon.channel.unionpay.biz.UnionpayBiz;
import com.liquidnet.service.dragon.channel.unionpay.constant.UnionpayConstant;
import com.liquidnet.service.dragon.channel.unionpay.req.UnionpayTradePayReq;
import com.liquidnet.service.dragon.channel.unionpay.sdk.AcpService;
import com.liquidnet.service.dragon.channel.unionpay.sdk.SDKConfig;
import com.liquidnet.service.dragon.channel.unionpay.strategy.annotation.StrategyUnionpayHandler;
import com.liquidnet.service.dragon.constant.DragonConstant;
import com.liquidnet.service.dragon.dto.DragonPayBaseReqDto;
import com.liquidnet.service.dragon.dto.DragonPayBaseRespDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.Map;
/**
* @author AnJiabin <anjiabin@zhengzai.tv>
* @version V1.0
* @Description: TODO
* @class: UnionpayStrategyWapImpl
* @Package com.liquidnet.service.dragon.channel.unionpay.strategy.impl
* @Copyright: LightNet @ Copyright (c) 2021
* @date 2021/7/10 14:34
*/
@Slf4j
@Service
@StrategyUnionpayHandler(DragonConstant.DeviceFromEnum.WAPPAGE)
public class UnionpayStrategyWapPageImpl extends AbstractUnionPayStrategy {
@Value("${liquidnet.dragon.url}")
private String notifyUrl;
@Autowired
StringRedisTemplate stringRedisTemplate;
@Autowired
private UnionpayBiz unionpayBiz;
@Autowired
private SDKConfig sdkConfig;
@Override
protected Map<String, String> executePay(UnionpayTradePayReq payReq) {
return unionpayBiz.tradeWapPay(payReq);
}
@Override
protected String getNotifyUrl() {
return notifyUrl + "/notify/unionpay/wap";
}
@Override
UnionpayTradePayReq appendRequestParam(UnionpayTradePayReq payReq, DragonPayBaseReqDto dragonPayBaseReqDto) {
//设置订单过期时间
String timeExpire = DateUtil.format(DateUtil.Formatter.yyyyMMddHHmmss.parse(dragonPayBaseReqDto.getCreateDate()).plusMinutes(Long.parseLong(dragonPayBaseReqDto.getExpireTime())),DateUtil.Formatter.yyyyMMddHHmmss);
payReq.setChannelType("07");
payReq.setRiskRateInfo(dragonPayBaseReqDto.getName());
payReq.setFrontUrl(dragonPayBaseReqDto.getReturnUrl());
payReq.setPayTimeout(timeExpire);
return payReq;
}
@Override
DragonPayBaseRespDto buildResponseDto(DragonPayBaseRespDto payBaseRespDto, Map<String, String> respResult) {
String requestFrontUrl = sdkConfig.getFrontTransUrl(); //获取请求银联的前台地址:对应属性文件acp_sdk.properties文件中的acpsdk.frontTransUrl
String html = AcpService.createAutoFormHtml(requestFrontUrl, respResult, UnionpayConstant.encoding); //生成自动跳转的Html表单
log.info("打印请求HTML,此为请求报文,为联调排查问题的依据:"+html);
payBaseRespDto.getPayData().setRedirectUrl(html);
return payBaseRespDto;
}
}
......@@ -133,6 +133,7 @@ public abstract class AbstractWepayStrategy implements IWepayStrategy {
DragonPayBaseRespDto respDto = new DragonPayBaseRespDto();
respDto.setCode(dragonPayBaseReqDto.getCode());
respDto.setOrderCode(dragonPayBaseReqDto.getOrderCode());
respDto.setPayType(dragonPayBaseReqDto.getPayType());
DragonPayBaseRespDto.PayData payData = new DragonPayBaseRespDto.PayData();
payData.setAppId(respWepayDto.getAppid());
payData.setNonceStr(nonceStr);
......
......@@ -44,7 +44,7 @@ public class PayController {
@ApiOperation("Dragon支付")
@ApiResponse(code = 200, message = "接口返回对象参数")
@ApiImplicitParams({
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "payType", value = "支付类型:alipay,wepay,iappay", example = "alipay"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "payType", value = "支付类型:alipay,wepay,unionpay,applepay", example = "unionpay"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "deviceFrom", value = "设备来源:web,wap,app,js,apple", example = "wap"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "type", value = "业务类型:TICKET,PRODUCT,COST,MBEANS,LIVE,VIDEO,VIP,CLUB,STRAWBERRY", example = "TICKET"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "price", value = "支付金额", example = "0.1"),
......@@ -53,8 +53,8 @@ public class PayController {
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "orderCode", value = "订单编号", example = "ORDER0001"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "clientIp", value = "客户端ip", example = "127.0.0.1"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "notifyUrl", value = "通知url", example = "devdragon.zhengzai.tv"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "createDate", value = "订单创建时间", example = "2021-07-13 13:00:00"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "expireTime", value = "订单过期时间", example = "5"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "createDate", value = "订单创建时间", example = "2021-11-10 13:00:00"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "expireTime", value = "订单过期时间", example = "1000"),
})
@ResponseBody
public ResponseDto<DragonPayBaseRespDto> dragonPay(
......
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