Commit ec71758a authored by 刘李鹏's avatar 刘李鹏

微信支持GET请求加签名、实现支付宝、微信的订单查询

parent 250cfbb8
package cn.quant.baa.pay.acquirer; package cn.quant.baa.pay.acquirer;
import cn.quant.baa.pay.jpa.entity.PayHistoryEntity; import cn.quant.baa.pay.jpa.entity.PayHistoryEntity;
import cn.quant.baa.pay.model.web.CheckPayRequestData;
import cn.quant.baa.pay.model.web.PayRequestData; import cn.quant.baa.pay.model.web.PayRequestData;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
...@@ -12,6 +13,7 @@ public interface Acquirer { ...@@ -12,6 +13,7 @@ public interface Acquirer {
JsonNode pay(PayRequestData payRequestData, PayHistoryEntity payHistoryEntity); JsonNode pay(PayRequestData payRequestData, PayHistoryEntity payHistoryEntity);
JsonNode refund(); JsonNode refund();
JsonNode check(); JsonNode checkPay(CheckPayRequestData checkPayRequestData);
JsonNode checkRefund();
JsonNode close(); JsonNode close();
} }
package cn.quant.baa.pay.acquirer; package cn.quant.baa.pay.acquirer;
import cn.quant.baa.pay.jpa.entity.PayHistoryEntity; import cn.quant.baa.pay.jpa.entity.PayHistoryEntity;
import cn.quant.baa.pay.model.web.CheckPayRequestData;
import cn.quant.baa.pay.model.web.PayRequestData; import cn.quant.baa.pay.model.web.PayRequestData;
import cn.quant.spring.NotSupportedException; import cn.quant.spring.NotSupportedException;
import cn.quant.spring.security.Base64Cipher; import cn.quant.spring.security.Base64Cipher;
...@@ -75,8 +76,13 @@ public class MerchantAcquirer implements Acquirer { ...@@ -75,8 +76,13 @@ public class MerchantAcquirer implements Acquirer {
} }
@Override @Override
public JsonNode check() { public JsonNode checkPay(CheckPayRequestData checkPayRequestData) {
throw new NotSupportedException(); return acquirers.get(checkPayRequestData.getChanId()).checkPay(checkPayRequestData);
}
@Override
public JsonNode checkRefund() {
return null;
} }
@Override @Override
......
...@@ -2,7 +2,9 @@ package cn.quant.baa.pay.acquirer.weixin; ...@@ -2,7 +2,9 @@ package cn.quant.baa.pay.acquirer.weixin;
import cn.quant.baa.pay.acquirer.AcquirerProperties; import cn.quant.baa.pay.acquirer.AcquirerProperties;
import cn.quant.baa.pay.acquirer.MerchantAcquirer; import cn.quant.baa.pay.acquirer.MerchantAcquirer;
import cn.quant.baa.pay.dict.AccessCode;
import cn.quant.baa.pay.jpa.entity.PayHistoryEntity; import cn.quant.baa.pay.jpa.entity.PayHistoryEntity;
import cn.quant.baa.pay.model.web.CheckPayRequestData;
import cn.quant.baa.pay.model.web.PayRequestData; import cn.quant.baa.pay.model.web.PayRequestData;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
...@@ -120,11 +122,23 @@ public class AlipayMerchantAcquirer extends MerchantAcquirer { ...@@ -120,11 +122,23 @@ public class AlipayMerchantAcquirer extends MerchantAcquirer {
bodyNode.put("subject", payRequestData.getSubject()); bodyNode.put("subject", payRequestData.getSubject());
bodyNode.put("body", payRequestData.getSubject()); bodyNode.put("body", payRequestData.getSubject());
bodyNode.put("product_code", properties.getProductCode()); bodyNode.put("product_code", properties.getProductCode());
switch (properties.getAccessCode()) {
case APP:
return doAppExecute(bodyNode);
case H5:
case WEB:
return doWebExecute(bodyNode); return doWebExecute(bodyNode);
default:
}
return doExecute(bodyNode);
}
@Override
public JsonNode checkPay(CheckPayRequestData checkPayRequestData) {
// String outTradeNo = "11111111218"; // String outTradeNo = "11111111218";
// bodyNode.put("out_trade_no", outTradeNo); ObjectNode bodyNode = objectMapper.createObjectNode();
// return doExecute(bodyNode); bodyNode.put("out_trade_no", checkPayRequestData.getOutTradeNo());
return doExecute(bodyNode);
} }
/** /**
...@@ -184,7 +198,7 @@ public class AlipayMerchantAcquirer extends MerchantAcquirer { ...@@ -184,7 +198,7 @@ public class AlipayMerchantAcquirer extends MerchantAcquirer {
if (response != null) { if (response != null) {
Mono<String> resultMono = response.bodyToMono(String.class); Mono<String> resultMono = response.bodyToMono(String.class);
String bodyRes = resultMono.block(); String bodyRes = resultMono.block();
Pattern pattern = Pattern.compile("[a-zA-Z_0-9]*_response"); //去掉空格符合换行符 Pattern pattern = Pattern.compile("[a-zA-Z_0-9]*_response"); //处理支付宝不同的返回格式,统一为response
Matcher matcher = pattern.matcher(bodyRes); Matcher matcher = pattern.matcher(bodyRes);
String body = matcher.replaceAll("response"); String body = matcher.replaceAll("response");
try { try {
......
...@@ -3,14 +3,17 @@ package cn.quant.baa.pay.acquirer.weixin; ...@@ -3,14 +3,17 @@ package cn.quant.baa.pay.acquirer.weixin;
import cn.quant.baa.pay.acquirer.AcquirerProperties; import cn.quant.baa.pay.acquirer.AcquirerProperties;
import cn.quant.baa.pay.acquirer.MerchantAcquirer; import cn.quant.baa.pay.acquirer.MerchantAcquirer;
import cn.quant.baa.pay.jpa.entity.PayHistoryEntity; import cn.quant.baa.pay.jpa.entity.PayHistoryEntity;
import cn.quant.baa.pay.model.web.CheckPayRequestData;
import cn.quant.baa.pay.model.web.PayRequestData; import cn.quant.baa.pay.model.web.PayRequestData;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
...@@ -85,7 +88,6 @@ public class WeiXinMerchantAcquirer extends MerchantAcquirer { ...@@ -85,7 +88,6 @@ public class WeiXinMerchantAcquirer extends MerchantAcquirer {
@Override @Override
public JsonNode pay(PayRequestData payRequestData, PayHistoryEntity payHistoryEntity) { public JsonNode pay(PayRequestData payRequestData, PayHistoryEntity payHistoryEntity) {
String outTradeNo = UUID.randomUUID().toString().replace("-", "");
ObjectNode bodyNode = objectMapper.createObjectNode(); ObjectNode bodyNode = objectMapper.createObjectNode();
// 转换金额为分 // 转换金额为分
BigInteger amount = new BigDecimal(payRequestData.getAmount()).multiply(new BigDecimal(100)).toBigInteger(); BigInteger amount = new BigDecimal(payRequestData.getAmount()).multiply(new BigDecimal(100)).toBigInteger();
...@@ -111,29 +113,50 @@ public class WeiXinMerchantAcquirer extends MerchantAcquirer { ...@@ -111,29 +113,50 @@ public class WeiXinMerchantAcquirer extends MerchantAcquirer {
default: default:
} }
bodyNode.set("scene_info", sceneInfo); bodyNode.set("scene_info", sceneInfo);
return doExecute(bodyNode); String payAccess = properties.getPayAccess();
return doExecute(payAccess, bodyNode);
}
@Override
public JsonNode checkPay(CheckPayRequestData checkPayRequestData) {
ObjectNode bodyNode = objectMapper.createObjectNode();
bodyNode.put("mchid", properties.getPayAcctId());
String payAccess = properties.getPayAccess().replace("{out_trade_no}", checkPayRequestData.getOutTradeNo());
return doExecute(payAccess, bodyNode);
} }
/** /**
* 发起请求
* *
* @param requestNode * @param payAccess
* @param bodyNode
* @return * @return
*/ */
private JsonNode doExecute(ObjectNode requestNode) { private JsonNode doExecute(String payAccess, ObjectNode bodyNode) {
String method = properties.getAccessMethod();
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(payAccess);
String requestBody = ""; String requestBody = "";
// 处理GET请求
if (HttpMethod.GET.name().equals(method)) {
bodyNode.fields().forEachRemaining((entry) -> {
uriComponentsBuilder.queryParam(entry.getKey(), entry.getValue().asText());
});
} else {
// 非GET请求的时候处理requestBody
try { try {
requestBody = objectMapper.writeValueAsString(requestNode); requestBody = objectMapper.writeValueAsString(bodyNode);
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
e.printStackTrace(); e.printStackTrace();
} }
}
String uri = uriComponentsBuilder.build().toString();
long timestamp = System.currentTimeMillis() / 1000; long timestamp = System.currentTimeMillis() / 1000;
String nonceStr = UUID.randomUUID().toString().replace("-", ""); String nonceStr = UUID.randomUUID().toString().replace("-", "");
String signText = joining("\n", "POST", properties.getPayAccess(), String.valueOf(timestamp), nonceStr, requestBody); // 代签名字符串
String signText = joining("\n", method, uri, String.valueOf(timestamp), nonceStr, requestBody);
String sign = sign(signText); String sign = sign(signText);
String token = String.format(TOKEN_PATTERN, properties.getPayAcctId(), nonceStr, timestamp, properties.getPayCertNo(), sign); String token = String.format(TOKEN_PATTERN, properties.getPayAcctId(), nonceStr, timestamp, properties.getPayCertNo(), sign);
Mono<ClientResponse> mono = webClient.post() Mono<ClientResponse> mono = webClient.method(HttpMethod.resolve(method))
.uri(properties.getPayAccess()) .uri(uri)
.header("Authorization", SCHEMA.concat(token)) .header("Authorization", SCHEMA.concat(token))
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.bodyValue(requestBody) .bodyValue(requestBody)
...@@ -160,15 +183,16 @@ public class WeiXinMerchantAcquirer extends MerchantAcquirer { ...@@ -160,15 +183,16 @@ public class WeiXinMerchantAcquirer extends MerchantAcquirer {
String signature = response.headers().asHttpHeaders().getFirst("Wechatpay-Signature"); String signature = response.headers().asHttpHeaders().getFirst("Wechatpay-Signature");
//签名信息 //签名信息
String wsSignText = joining("\n", wxTimestamp, nonce, resultMono.block()); String wsSignText = joining("\n", wxTimestamp, nonce, body);
if (verify(wsSignText, signature)) { if (verify(wsSignText, signature)) {
return bodyJsonNode; return bodyJsonNode;
} }
// TODO: 签名校验失败,做异常处理 // TODO: 签名校验失败,做异常处理
throw new RuntimeException("签名校验失败"); throw new RuntimeException("签名校验失败");
} else { } else {
return bodyJsonNode;
// TODO: 返回异常,做异常处理 // TODO: 返回异常,做异常处理
throw new RuntimeException("返回异常,做异常处理"); // throw new RuntimeException("返回异常,做异常处理");
} }
} }
return bodyJsonNode; return bodyJsonNode;
...@@ -295,9 +319,6 @@ public class WeiXinMerchantAcquirer extends MerchantAcquirer { ...@@ -295,9 +319,6 @@ public class WeiXinMerchantAcquirer extends MerchantAcquirer {
public String joining(String separator, String... str) { public String joining(String separator, String... str) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
for (String s : str) { for (String s : str) {
if (s == null || s.length() == 0) {
continue;
}
builder.append(s).append(separator); builder.append(s).append(separator);
} }
return builder.toString(); return builder.toString();
......
...@@ -6,7 +6,8 @@ package cn.quant.baa.pay.dict; ...@@ -6,7 +6,8 @@ package cn.quant.baa.pay.dict;
public enum AccessCode { public enum AccessCode {
REFUND("退款"), REFUND("退款"),
CHECK("订单查询"), CHKRFD("退款查询"),
CHKPAY("支付查询"),
CLOSE("关闭订单"), CLOSE("关闭订单"),
WEB("电脑网站支付"), WEB("电脑网站支付"),
APP("应用支付"), APP("应用支付"),
......
...@@ -5,6 +5,7 @@ import cn.quant.baa.pay.acquirer.AcquirerConfiguration; ...@@ -5,6 +5,7 @@ import cn.quant.baa.pay.acquirer.AcquirerConfiguration;
import cn.quant.baa.pay.acquirer.MerchantAcquirer; import cn.quant.baa.pay.acquirer.MerchantAcquirer;
import cn.quant.baa.pay.context.TransactionSession; import cn.quant.baa.pay.context.TransactionSession;
import cn.quant.baa.pay.jpa.entity.*; import cn.quant.baa.pay.jpa.entity.*;
import cn.quant.baa.pay.model.web.CheckPayRequestData;
import cn.quant.baa.pay.util.AssertUtils; import cn.quant.baa.pay.util.AssertUtils;
import cn.quant.baa.pay.model.web.GoodsDetail; import cn.quant.baa.pay.model.web.GoodsDetail;
import cn.quant.baa.pay.acquirer.AcquirerProperties; import cn.quant.baa.pay.acquirer.AcquirerProperties;
...@@ -114,4 +115,10 @@ public class TransactionService extends BusinessService { ...@@ -114,4 +115,10 @@ public class TransactionService extends BusinessService {
System.currentTimeMillis(); System.currentTimeMillis();
return acquirer.pay(data, payHistoryEntity); return acquirer.pay(data, payHistoryEntity);
} }
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public JsonNode checkPay(CheckPayRequestData data) {
return acquirer.checkPay(data);
}
} }
...@@ -3,6 +3,7 @@ package cn.quant.baa.pay.rest; ...@@ -3,6 +3,7 @@ package cn.quant.baa.pay.rest;
import cn.quant.baa.pay.annotation.BusinessMapping; import cn.quant.baa.pay.annotation.BusinessMapping;
import cn.quant.baa.pay.jpa.entity.PayHistoryEntity; import cn.quant.baa.pay.jpa.entity.PayHistoryEntity;
import cn.quant.baa.pay.model.BusinessRequest; import cn.quant.baa.pay.model.BusinessRequest;
import cn.quant.baa.pay.model.web.CheckPayRequestData;
import cn.quant.baa.pay.model.web.PayRequestData; import cn.quant.baa.pay.model.web.PayRequestData;
import cn.quant.baa.pay.service.TransactionService; import cn.quant.baa.pay.service.TransactionService;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
...@@ -31,4 +32,17 @@ public class TransactionController extends BusinessController { ...@@ -31,4 +32,17 @@ public class TransactionController extends BusinessController {
System.currentTimeMillis(); System.currentTimeMillis();
return res; return res;
} }
@ResponseBody
@BusinessMapping(session = 1)
@PostMapping("/checkPay")
public JsonNode checkPay(@RequestBody BusinessRequest<CheckPayRequestData> request) {
CheckPayRequestData data = request.getData();
JsonNode res = transactionService.checkPay(data);
System.currentTimeMillis();
return res;
}
} }
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