V13
This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
package com.ruoyi.cai.trdpay;
|
package com.ruoyi.cai.trdpay;
|
||||||
|
|
||||||
|
import cn.hutool.core.codec.Base64;
|
||||||
|
import cn.hutool.crypto.SecureUtil;
|
||||||
|
import cn.hutool.crypto.asymmetric.Sign;
|
||||||
|
import cn.hutool.crypto.asymmetric.SignAlgorithm;
|
||||||
import cn.hutool.crypto.digest.DigestUtil;
|
import cn.hutool.crypto.digest.DigestUtil;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
@@ -41,6 +45,24 @@ public class PayMd5Util {
|
|||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MultiValueMap<String,String> createParamsOfMapMD5(Map<String, String> params, String key) {
|
||||||
|
return createParamsOfMapMD5(params,key,"","sign");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MultiValueMap<String,String> createParamsOfMapMD5(Map<String, String> params, String key, String keyPre, String signKey) {
|
||||||
|
MultiValueMap<String, String> resp = new LinkedMultiValueMap<>();
|
||||||
|
List<String> url = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||||
|
url.add(entry.getKey() + "=" + entry.getValue());
|
||||||
|
resp.add(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
url = url.stream().sorted().collect(Collectors.toList());
|
||||||
|
String stringSignTemp = StringUtils.join(url, "&") + keyPre + key;
|
||||||
|
String sign = DigestUtil.md5Hex(stringSignTemp).toUpperCase();
|
||||||
|
resp.add(signKey,sign);
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
public static String createParams(Map<String, String> params, String key) {
|
public static String createParams(Map<String, String> params, String key) {
|
||||||
List<String> url = new ArrayList<>();
|
List<String> url = new ArrayList<>();
|
||||||
for (Map.Entry<String, String> entry : params.entrySet()) {
|
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package com.ruoyi.cai.trdpay;
|
||||||
|
|
||||||
|
import cn.hutool.core.codec.Base64;
|
||||||
|
import cn.hutool.crypto.SecureUtil;
|
||||||
|
import cn.hutool.crypto.asymmetric.Sign;
|
||||||
|
import cn.hutool.crypto.asymmetric.SignAlgorithm;
|
||||||
|
import cn.hutool.crypto.digest.DigestUtil;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class PaySignUtil {
|
||||||
|
|
||||||
|
public static String createMD5ToUpperCase(Map<String, String> params,String subKey) {
|
||||||
|
return createMD5(params,subKey).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String createMD5ToLowerCase(Map<String, String> params,String subKey) {
|
||||||
|
return createMD5(params,subKey).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String createMD5(Map<String, String> params,String subKey) {
|
||||||
|
List<String> url = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||||
|
url.add(entry.getKey() + "=" + entry.getValue());
|
||||||
|
}
|
||||||
|
url = url.stream().sorted().collect(Collectors.toList());
|
||||||
|
String stringSignTemp = StringUtils.join(url, "&") + subKey;
|
||||||
|
return DigestUtil.md5Hex(stringSignTemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean checkRSA256(Map<String, String> params, String privateKey, String publicKey,String sign,String ... ignoreKeys) {
|
||||||
|
if(sign == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Set<String> ignoreKeySet = ignoreKeys == null ? new HashSet<>() : new HashSet<>(Arrays.asList(ignoreKeys));
|
||||||
|
List<String> url = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||||
|
if(ignoreKeySet.contains(entry.getKey())){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
url.add(entry.getKey() + "=" + entry.getValue());
|
||||||
|
}
|
||||||
|
url = url.stream().sorted().collect(Collectors.toList());
|
||||||
|
String stringSignTemp = StringUtils.join(url, "&");
|
||||||
|
String signLLL = rsa256(stringSignTemp, privateKey, publicKey);
|
||||||
|
return signLLL.equals(sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String createRSA256(Map<String, String> params, String privateKey, String publicKey) {
|
||||||
|
List<String> url = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||||
|
url.add(entry.getKey() + "=" + entry.getValue());
|
||||||
|
}
|
||||||
|
url = url.stream().sorted().collect(Collectors.toList());
|
||||||
|
String stringSignTemp = StringUtils.join(url, "&");
|
||||||
|
return rsa256(stringSignTemp,privateKey,publicKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String rsa256(String privateKey,String publicKey,String data) {
|
||||||
|
String privateKeyBase = Base64.encode(privateKey);
|
||||||
|
String publicKeyBase = Base64.encode(publicKey);
|
||||||
|
Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, privateKeyBase, publicKeyBase);
|
||||||
|
String s = sign.signHex(data);
|
||||||
|
return Base64.encode(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -128,7 +128,11 @@ public enum TrdPayTypeEnum {
|
|||||||
* 支付宝 8 微信 4
|
* 支付宝 8 微信 4
|
||||||
*/
|
*/
|
||||||
V11("http://bgxa.peiqi.zhifusg.com","/Pay_Index.html","/Pay_Trade_query.html","/api/pay/trd/notify/v11","OK"),
|
V11("http://bgxa.peiqi.zhifusg.com","/Pay_Index.html","/Pay_Trade_query.html","/api/pay/trd/notify/v11","OK"),
|
||||||
V12("https://cashapi.sandpay.com.cn","/gateway/trade","/Pay_Trade_query.html","/api/pay/trd/notify/v11","OK"),
|
V12("https://cashapi.sandpay.com.cn","/gateway/trade","/Pay_Trade_query.html","/api/pay/trd/notify/v12","OK"),
|
||||||
|
/**
|
||||||
|
* https://pp123.bghyvwk.cn/doc/pay_create.html
|
||||||
|
*/
|
||||||
|
V13("https://pp123.bghyvwk.cn","/api/pay/create","/api/pay/query","/api/pay/trd/notify/v12","success"),
|
||||||
|
|
||||||
;
|
;
|
||||||
private final String gatewayUrl;
|
private final String gatewayUrl;
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
package com.ruoyi.cai.trdpay.handle;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.ruoyi.cai.domain.PayTrdConfig;
|
||||||
|
import com.ruoyi.cai.pay.PayManager;
|
||||||
|
import com.ruoyi.cai.pay.PayOrderInfoDTO;
|
||||||
|
import com.ruoyi.cai.pay.PayReturnResp;
|
||||||
|
import com.ruoyi.cai.service.OrderLogsService;
|
||||||
|
import com.ruoyi.cai.service.PayTrdConfigService;
|
||||||
|
import com.ruoyi.cai.trdpay.PayMd5Util;
|
||||||
|
import com.ruoyi.cai.trdpay.PaySignUtil;
|
||||||
|
import com.ruoyi.cai.trdpay.PayTrdService;
|
||||||
|
import com.ruoyi.cai.trdpay.TrdPayTypeEnum;
|
||||||
|
import com.ruoyi.cai.trdpay.dto.NotifyResp;
|
||||||
|
import com.ruoyi.cai.util.MapUtils;
|
||||||
|
import com.ruoyi.cai.util.RestTemplateUtil;
|
||||||
|
import com.ruoyi.common.exception.ServiceException;
|
||||||
|
import com.ruoyi.common.utils.ServletUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class PayTrdV13Service implements PayTrdService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OrderLogsService orderLogsService;
|
||||||
|
@Autowired
|
||||||
|
private PayManager payManager;
|
||||||
|
@Autowired
|
||||||
|
private PayTrdConfigService payTrdConfigService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TrdPayTypeEnum getType() {
|
||||||
|
return TrdPayTypeEnum.V13;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String PUBLIC_KEY = "";
|
||||||
|
|
||||||
|
private String v1(PayOrderInfoDTO payOrderInfoDTO, PayTrdConfig payTrdConfig, boolean wx){
|
||||||
|
TrdPayTypeEnum type = getType();
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put("pid", payTrdConfig.getMchId());
|
||||||
|
params.put("device", "mobile");
|
||||||
|
if(wx){
|
||||||
|
params.put("type", "wxpay");
|
||||||
|
}else{
|
||||||
|
params.put("type", "alipay");
|
||||||
|
}
|
||||||
|
params.put("out_trade_no", payOrderInfoDTO.getOrderNo());
|
||||||
|
String notifyUrl = type.getNotifyUrl(payTrdConfig.getNotifyUrl(), wx);
|
||||||
|
params.put("notify_url", notifyUrl);
|
||||||
|
// params.put("return_url", notifyUrl);
|
||||||
|
params.put("name", payOrderInfoDTO.getSubject());
|
||||||
|
params.put("money", payOrderInfoDTO.getPriceYuanStr());
|
||||||
|
params.put("clientip", ServletUtils.getClientIP());
|
||||||
|
String sign = PaySignUtil.createMD5ToLowerCase(params, "");
|
||||||
|
MultiValueMap<String, String> multiValueMap = MapUtils.mapToMultiValueMap(params);
|
||||||
|
multiValueMap.add("sign", sign);
|
||||||
|
multiValueMap.add("sign_type", "MD5");
|
||||||
|
String gatewayUrl = getGatewayUrl(payTrdConfig);
|
||||||
|
String createOrderUrl = gatewayUrl + type.getCreateOrderUrl();
|
||||||
|
return RestTemplateUtil.postFormData(createOrderUrl, multiValueMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PayReturnResp createOrderAli(PayOrderInfoDTO payOrderInfoDTO, PayTrdConfig payTrdConfig, boolean wx) {
|
||||||
|
TrdPayTypeEnum type = getType();
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put("param", payTrdConfig.getId()+"");
|
||||||
|
params.put("pid", payTrdConfig.getMchId());
|
||||||
|
params.put("method", "jump");
|
||||||
|
params.put("device", "mobile");
|
||||||
|
if(wx){
|
||||||
|
params.put("type", "wxpay");
|
||||||
|
}else{
|
||||||
|
params.put("type", "alipay");
|
||||||
|
}
|
||||||
|
params.put("out_trade_no", payOrderInfoDTO.getOrderNo());
|
||||||
|
String notifyUrl = type.getNotifyUrl(payTrdConfig.getNotifyUrl(), wx);
|
||||||
|
params.put("notify_url", notifyUrl);
|
||||||
|
// params.put("return_url", notifyUrl);
|
||||||
|
params.put("name", payOrderInfoDTO.getSubject());
|
||||||
|
params.put("money", payOrderInfoDTO.getPriceYuanStr());
|
||||||
|
params.put("clientip", ServletUtils.getClientIP());
|
||||||
|
params.put("timestamp", System.currentTimeMillis()/1000+"");
|
||||||
|
String rsa = PaySignUtil.createRSA256(params, payTrdConfig.getSign(), PUBLIC_KEY);
|
||||||
|
MultiValueMap<String, String> multiValueMap = MapUtils.mapToMultiValueMap(params);
|
||||||
|
MultiValueMap<String, String> map = PayMd5Util.createParamsOfMapMD5(params, payTrdConfig.getSign());
|
||||||
|
multiValueMap.add("sign", rsa);
|
||||||
|
multiValueMap.add("sign_type", "RSA");
|
||||||
|
String gatewayUrl = getGatewayUrl(payTrdConfig);
|
||||||
|
String createOrderUrl = gatewayUrl + type.getCreateOrderUrl();
|
||||||
|
String body = RestTemplateUtil.postFormData(createOrderUrl, multiValueMap);
|
||||||
|
JSONObject jsonObject = JSON.parseObject(body);
|
||||||
|
boolean success = checkSuccess(jsonObject);
|
||||||
|
orderLogsService.createAliPayLogs(payOrderInfoDTO.getOrderNo(), createOrderUrl+JSON.toJSONString(map), jsonObject, success, type, getStepName(wx));
|
||||||
|
if(!success){
|
||||||
|
log.info("第三方支付失败 V13 统一支付失败失败 url={} params={} body={}, payTrdConfig={}", createOrderUrl,JSON.toJSONString(map), body, JSON.toJSONString(payTrdConfig));
|
||||||
|
throw new ServiceException("调用支付失败");
|
||||||
|
}
|
||||||
|
String payUrl = jsonObject.getString("pay_info");
|
||||||
|
return PayReturnResp.createH5(payUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkSuccess(JSONObject jsonObject) {
|
||||||
|
if(jsonObject == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!"0".equals(jsonObject.getString("code"))){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NotifyResp getNotifyResp(Map<String, String> sourceData) {
|
||||||
|
String sign = sourceData.get("sign");
|
||||||
|
String mchOrderNo = sourceData.get("trade_no");
|
||||||
|
String payOrderId = sourceData.get("out_trade_no");
|
||||||
|
String status = sourceData.get("trade_status");
|
||||||
|
String params = sourceData.get("params");
|
||||||
|
NotifyResp resp = new NotifyResp();
|
||||||
|
resp.setOrderNo(mchOrderNo);
|
||||||
|
resp.setTrdOrderNo(payOrderId);
|
||||||
|
resp.setPayTypeEnum(getType());
|
||||||
|
resp.setSourceData(sourceData);
|
||||||
|
PayTrdConfig payTrdConfig = payTrdConfigService.getById(params);
|
||||||
|
if(payTrdConfig == null){
|
||||||
|
resp.setSuccess(false);
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
boolean checked = PaySignUtil.checkRSA256(sourceData, PUBLIC_KEY, payTrdConfig.getSign(), sign, "sign", "sign_type");
|
||||||
|
if(!checked){
|
||||||
|
resp.setSuccess(false);
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
resp.setSuccess("TRADE_SUCCESS".equals(status));
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject queryOrder(String orderNo, PayTrdConfig payTrdConfig) {
|
||||||
|
throw new ServiceException("V13不支持订单查询");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject resetOrder(String orderNo, PayTrdConfig payTrdConfig, boolean updateData) {
|
||||||
|
throw new ServiceException("V13不支持订单查询");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
15
ruoyi-cai/src/main/java/com/ruoyi/cai/util/MapUtils.java
Normal file
15
ruoyi-cai/src/main/java/com/ruoyi/cai/util/MapUtils.java
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package com.ruoyi.cai.util;
|
||||||
|
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class MapUtils {
|
||||||
|
|
||||||
|
public static MultiValueMap<String, String> mapToMultiValueMap(Map<String, String> map) {
|
||||||
|
MultiValueMap<String, String> multiValueMap = new LinkedMultiValueMap<>();
|
||||||
|
map.forEach(multiValueMap::add);
|
||||||
|
return multiValueMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -71,4 +71,18 @@ public class RestTemplateUtil {
|
|||||||
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
|
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
|
||||||
return restTemplate.postForObject(url, request, String.class);
|
return restTemplate.postForObject(url, request, String.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String postFormData(String url, MultiValueMap<String, String> map) {
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||||
|
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
|
||||||
|
return restTemplate.postForObject(url, request, String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String postFormDataNoSSL(String url, MultiValueMap<String, String> map) {
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||||
|
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
|
||||||
|
return NO_SSL_REST_TEMPLATE.postForObject(url, request, String.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user