You've already forked FrameTour-BE
系统支付对接、避免返回过多数据
This commit is contained in:
@@ -1,24 +1,26 @@
|
||||
package com.ycwl.basic.service.mobile;
|
||||
|
||||
import com.ycwl.basic.model.wx.WXPayOrderReqVO;
|
||||
import com.ycwl.basic.model.wx.WxPayRespVO;
|
||||
import com.ycwl.basic.model.wx.WxchatCallbackSuccessData;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Map;
|
||||
|
||||
public interface WxPayService {
|
||||
|
||||
/**
|
||||
* 微信预支付
|
||||
*/
|
||||
WxPayRespVO createOrder(WXPayOrderReqVO req) throws Exception;
|
||||
Map<String, Object> createOrder(Long scenicId, WXPayOrderReqVO req) throws Exception;
|
||||
|
||||
/**
|
||||
* 微信支付回调
|
||||
*/
|
||||
void payNotify(HttpServletRequest xml);
|
||||
void payNotify(HttpServletRequest request);
|
||||
|
||||
void payNotify(Long scenicId, HttpServletRequest request);
|
||||
|
||||
|
||||
/**
|
||||
@@ -38,7 +40,7 @@ public interface WxPayService {
|
||||
/**
|
||||
* 微信退款回调
|
||||
*/
|
||||
boolean refundNotify(String refundResult) throws IOException, GeneralSecurityException;
|
||||
boolean refundNotify(Long scenicId, HttpServletRequest request) throws IOException;
|
||||
|
||||
/**
|
||||
* 关闭订单
|
||||
@@ -46,4 +48,5 @@ public interface WxPayService {
|
||||
* @param orderId 订单id(订单编号)
|
||||
*/
|
||||
void closeOrder(String orderId) ;
|
||||
|
||||
}
|
||||
|
@@ -3,7 +3,6 @@ package com.ycwl.basic.service.mobile.impl;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ycwl.basic.config.WechatConfig;
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
import com.ycwl.basic.constant.NumberConstant;
|
||||
import com.ycwl.basic.constant.WeiXinConstant;
|
||||
|
@@ -1,28 +1,8 @@
|
||||
package com.ycwl.basic.service.mobile.impl;
|
||||
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.aliyuncs.utils.StringUtils;
|
||||
import com.wechat.pay.java.core.Config;
|
||||
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
|
||||
import com.wechat.pay.java.core.exception.ServiceException;
|
||||
import com.wechat.pay.java.core.notification.NotificationConfig;
|
||||
import com.wechat.pay.java.core.notification.NotificationParser;
|
||||
import com.wechat.pay.java.core.notification.RequestParam;
|
||||
import com.wechat.pay.java.core.util.PemUtil;
|
||||
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
|
||||
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.*;
|
||||
import com.wechat.pay.java.service.payments.model.TransactionAmount;
|
||||
import com.wechat.pay.java.service.refund.RefundService;
|
||||
import com.wechat.pay.java.service.refund.model.AmountReq;
|
||||
import com.wechat.pay.java.service.refund.model.CreateRequest;
|
||||
import com.wechat.pay.java.service.refund.model.Refund;
|
||||
import com.ycwl.basic.biz.OrderBiz;
|
||||
import com.ycwl.basic.config.WechatConfig;
|
||||
import com.ycwl.basic.constant.HttpConstant;
|
||||
import com.ycwl.basic.constant.NumberConstant;
|
||||
import com.ycwl.basic.constant.WeiXinConstant;
|
||||
import com.ycwl.basic.enums.BizCodeEnum;
|
||||
import com.ycwl.basic.enums.OrderStateEnum;
|
||||
import com.ycwl.basic.enums.StatisticEnum;
|
||||
@@ -35,37 +15,28 @@ import com.ycwl.basic.model.pc.order.entity.OrderEntity;
|
||||
import com.ycwl.basic.model.pc.order.req.OrderUpdateReq;
|
||||
import com.ycwl.basic.model.pc.payment.entity.PaymentEntity;
|
||||
import com.ycwl.basic.model.wx.WXPayOrderReqVO;
|
||||
import com.ycwl.basic.model.wx.WxPayRespVO;
|
||||
import com.ycwl.basic.model.wx.WxchatCallbackSuccessData;
|
||||
import com.ycwl.basic.pay.adapter.IPayAdapter;
|
||||
import com.ycwl.basic.pay.entity.CancelOrderRequest;
|
||||
import com.ycwl.basic.pay.entity.CreateOrderRequest;
|
||||
import com.ycwl.basic.pay.entity.CreateOrderResponse;
|
||||
import com.ycwl.basic.pay.entity.PayResponse;
|
||||
import com.ycwl.basic.pay.entity.RefundResponse;
|
||||
import com.ycwl.basic.pay.entity.RefundOrderRequest;
|
||||
import com.ycwl.basic.pay.entity.RefundOrderResponse;
|
||||
import com.ycwl.basic.repository.OrderRepository;
|
||||
import com.ycwl.basic.service.mobile.WxPayService;
|
||||
import com.ycwl.basic.service.pc.ScenicService;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import com.ycwl.basic.utils.WXPayUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.*;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.wechat.pay.java.core.http.Constant.*;
|
||||
import static com.wechat.pay.java.service.refund.model.Status.SUCCESS;
|
||||
import static com.ycwl.basic.constant.WeiXinConstant.*;
|
||||
|
||||
/**
|
||||
* @Author: songmingsong
|
||||
@@ -77,8 +48,6 @@ import static com.ycwl.basic.constant.WeiXinConstant.*;
|
||||
@Service
|
||||
public class WxPayServiceImpl implements WxPayService {
|
||||
|
||||
@Autowired
|
||||
private WechatConfig wechatConfig;
|
||||
@Autowired
|
||||
private PaymentMapper paymentMapper;
|
||||
@Autowired
|
||||
@@ -89,116 +58,50 @@ public class WxPayServiceImpl implements WxPayService {
|
||||
private OrderBiz orderBiz;
|
||||
@Autowired
|
||||
private OrderMapper orderMapper;
|
||||
@Autowired
|
||||
private ScenicService scenicService;
|
||||
|
||||
@Override
|
||||
public WxPayRespVO createOrder(WXPayOrderReqVO req) {
|
||||
public Map<String, Object> createOrder(Long scenicId, WXPayOrderReqVO req) {
|
||||
PaymentEntity entity = new PaymentEntity();
|
||||
entity.setOrderId(req.getOrderSn());
|
||||
entity.setMemberId(req.getMemberId());
|
||||
entity.setPayPrice(new BigDecimal(BigInteger.valueOf(req.getTotalPrice()), 2));
|
||||
Long entityId = paymentMapper.addGetId(entity);
|
||||
IPayAdapter scenicPayAdapter = scenicService.getScenicPayAdapter(scenicId);
|
||||
try {
|
||||
// 使用自动更新平台证书的RSA配置
|
||||
Config config = getInstance(wechatConfig);
|
||||
// 构建service
|
||||
JsapiService service = new JsapiService.Builder().config(config).build();
|
||||
|
||||
// request.setXxx(val)设置所需参数,具体参数可见Request定义
|
||||
PrepayRequest request = new PrepayRequest();
|
||||
Amount amount = new Amount();
|
||||
amount.setTotal(req.getTotalPrice());
|
||||
request.setAmount(amount);
|
||||
request.setAppid(wechatConfig.getMiniProgramAppId());
|
||||
request.setMchid(wechatConfig.getMchId());
|
||||
request.setDescription(req.getGoodsName());
|
||||
request.setNotifyUrl(wechatConfig.getPayNotifyUrl());
|
||||
request.setOutTradeNo(req.getOrderSn().toString());
|
||||
request.setDescription(req.getDescription());
|
||||
|
||||
Payer payer = new Payer();
|
||||
payer.setOpenid(req.getOpenId());
|
||||
request.setPayer(payer);
|
||||
// SettleInfo settleInfo = new SettleInfo();
|
||||
// settleInfo.setProfitSharing(true);
|
||||
// request.setSettleInfo(settleInfo);
|
||||
|
||||
// 调用下单方法,得到应答
|
||||
PrepayResponse response = service.prepay(request);
|
||||
WxPayRespVO vo = new WxPayRespVO();
|
||||
Long timeStamp = System.currentTimeMillis() / NumberConstant.THOUSAND;
|
||||
vo.setTimeStamp(timeStamp);
|
||||
String substring = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
|
||||
vo.setNonceStr(substring);
|
||||
String signatureStr = Stream.of(wechatConfig.getMiniProgramAppId(), String.valueOf(timeStamp), substring, "prepay_id=" + response.getPrepayId())
|
||||
.collect(Collectors.joining("\n", "", "\n"));
|
||||
String sign = WXPayUtil.getSign(signatureStr, wechatConfig.getKeyPath());
|
||||
vo.setPaySign(sign);
|
||||
vo.setSignType("RSA-SHA256");
|
||||
vo.setPrepayId("prepay_id=" + response.getPrepayId());
|
||||
return vo;
|
||||
} catch (ServiceException e) {
|
||||
JSONObject parse = JSONObject.parseObject(e.getResponseBody());
|
||||
throw new AppException(BizCodeEnum.ADVANCE_PAYMENT_FAILED, parse.getString(HttpConstant.Message));
|
||||
CreateOrderRequest request = new CreateOrderRequest()
|
||||
.setOrderNo(String.valueOf(req.getOrderSn()))
|
||||
.setPriceInCents(req.getTotalPrice())
|
||||
.setDescription(req.getDescription())
|
||||
.setGoodsName(req.getGoodsName())
|
||||
.setUserIdentify(req.getOpenId())
|
||||
.setNotifyUrl("https://zhentuai.com/api/mobile/wx/pay/v1/"+scenicId+"/payNotify");
|
||||
CreateOrderResponse order = scenicPayAdapter.createOrder(request);
|
||||
Map<String, Object> paymentParams = scenicPayAdapter.getPaymentParams(order);
|
||||
paymentParams.put("needPay", !order.isSkipPay());
|
||||
return paymentParams;
|
||||
} catch (Exception e) {
|
||||
throw new AppException(BizCodeEnum.ADVANCE_PAYMENT_FAILED, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void payNotify(HttpServletRequest request) {
|
||||
public void payNotify(Long scenicId, HttpServletRequest request) {
|
||||
IPayAdapter scenicPayAdapter = scenicService.getScenicPayAdapter(scenicId);
|
||||
try {
|
||||
// 读取请求体的信息
|
||||
ServletInputStream inputStream = request.getInputStream();
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
String s;
|
||||
// 读取回调请求体
|
||||
while ((s = bufferedReader.readLine()) != null) {
|
||||
stringBuffer.append(s);
|
||||
}
|
||||
String s1 = stringBuffer.toString();
|
||||
log.warn("微信支付回调:{}", s1);
|
||||
String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
|
||||
String nonce = request.getHeader(WECHAT_PAY_NONCE);
|
||||
String signType = request.getHeader(WeiXinConstant.WECHATPAY_SIGNATURE_TYPE);
|
||||
String serialNo = request.getHeader(WECHAT_PAY_SERIAL);
|
||||
String signature = request.getHeader(WECHAT_PAY_SIGNATURE);
|
||||
|
||||
NotificationConfig config = new RSAAutoCertificateConfig.Builder()
|
||||
.merchantId(wechatConfig.getMchId())
|
||||
.privateKey(wechatConfig.getKeyPath())
|
||||
.merchantSerialNumber(wechatConfig.getMchSerialNo())
|
||||
.apiV3Key(wechatConfig.getApiV3())
|
||||
.build();
|
||||
// 初始化 NotificationParser
|
||||
NotificationParser parser = new NotificationParser(config);
|
||||
RequestParam requestParam = new RequestParam.Builder()
|
||||
.serialNumber(serialNo)
|
||||
.nonce(nonce)
|
||||
.signature(signature)
|
||||
.timestamp(timestamp)
|
||||
// 若未设置signType,默认值为 WECHATPAY2-SHA256-RSA2048
|
||||
.signType(signType)
|
||||
.body(s1)
|
||||
.build();
|
||||
Transaction parse = parser.parse(requestParam, Transaction.class);
|
||||
log.info("[微信支付]parse = {}", parse);
|
||||
PayResponse callbackResponse = scenicPayAdapter.handleCallback(request);
|
||||
log.info("[微信支付]parse = {}", callbackResponse);
|
||||
|
||||
// 更新订单信息
|
||||
new Thread(() -> {
|
||||
long orderId = Long.parseLong(parse.getOutTradeNo());
|
||||
switch (parse.getTradeState()) {
|
||||
case SUCCESS:
|
||||
orderBiz.paidOrder(orderId);
|
||||
break;
|
||||
case NOTPAY:
|
||||
case CLOSED:
|
||||
case REVOKED:
|
||||
orderBiz.cancelOrder(orderId);
|
||||
break;
|
||||
case REFUND:
|
||||
orderBiz.refundOrder(orderId);
|
||||
break;
|
||||
long orderId = Long.parseLong(callbackResponse.getOrderNo());
|
||||
if (callbackResponse.isPay()) {
|
||||
orderBiz.paidOrder(orderId);
|
||||
} else if (callbackResponse.isCancel()) {
|
||||
orderBiz.cancelOrder(orderId);
|
||||
} else if (callbackResponse.isRefund()) {
|
||||
orderBiz.refundOrder(orderId);
|
||||
}
|
||||
}).start();
|
||||
} catch (Exception e) {
|
||||
@@ -207,59 +110,29 @@ public class WxPayServiceImpl implements WxPayService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxchatCallbackSuccessData queryPay(Long orderId) {
|
||||
WxchatCallbackSuccessData wxchatCallbackSuccessData = new WxchatCallbackSuccessData();
|
||||
QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
|
||||
queryRequest.setMchid(wechatConfig.getMchId());
|
||||
queryRequest.setOutTradeNo(orderId.toString());
|
||||
Config config = getInstance(wechatConfig);
|
||||
// 构建service
|
||||
JsapiService service = new JsapiService.Builder().config(config).build();
|
||||
try {
|
||||
com.wechat.pay.java.service.payments.model.Transaction transaction = service.queryOrderByOutTradeNo(queryRequest);
|
||||
String successTime = transaction.getSuccessTime();
|
||||
public void payNotify(HttpServletRequest request) {
|
||||
payNotify(0L, request);
|
||||
}
|
||||
|
||||
wxchatCallbackSuccessData.setOrderId(orderId.toString());
|
||||
wxchatCallbackSuccessData.setSuccessTime(successTime);
|
||||
wxchatCallbackSuccessData.setTradetype(WeiXinConstant.getDescriptionType(transaction.getTradeType()));
|
||||
wxchatCallbackSuccessData.setTradestate(WeiXinConstant.getDescriptionState(transaction.getTradeState()));
|
||||
TransactionAmount amount = transaction.getAmount();
|
||||
Integer total = amount.getTotal();
|
||||
wxchatCallbackSuccessData.setTotalMoney(new BigDecimal(total).movePointLeft(2));
|
||||
} catch (ServiceException e) {
|
||||
// API返回失败, 例如ORDER_NOT_EXISTS
|
||||
log.error("[微信退款] code={}, message={}", e.getErrorCode(), e.getErrorMessage());
|
||||
log.error("[微信退款] Response_body={}", e.getResponseBody());
|
||||
}
|
||||
return wxchatCallbackSuccessData;
|
||||
@Override
|
||||
public WxchatCallbackSuccessData queryPay(Long orderId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean refundOrder(String orderId) {
|
||||
OrderEntity order = orderRepository.getOrder(Long.parseLong(orderId));
|
||||
IPayAdapter scenicPayAdapter = scenicService.getScenicPayAdapter(order.getScenicId());
|
||||
BigDecimal payPrice = order.getPayPrice();
|
||||
long priceInCents = payPrice.multiply(new BigDecimal(NumberConstant.HUNDRED)).longValue(); // 转换为分(int)
|
||||
|
||||
Config config =
|
||||
new RSAAutoCertificateConfig.Builder()
|
||||
.merchantId(wechatConfig.getMchId())
|
||||
// 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
|
||||
.privateKey(wechatConfig.getKeyPath())
|
||||
.merchantSerialNumber(wechatConfig.getMchSerialNo())
|
||||
.apiV3Key(wechatConfig.getApiV3())
|
||||
.build();
|
||||
RefundService service = new RefundService.Builder().config(config).build();
|
||||
CreateRequest request = new CreateRequest();
|
||||
request.setNotifyUrl(wechatConfig.getRefundNotifyUrl());
|
||||
AmountReq amountReq = new AmountReq();
|
||||
amountReq.setTotal(priceInCents);
|
||||
amountReq.setRefund(priceInCents);
|
||||
amountReq.setCurrency(WECHATPAY_CURRENCY_CNY);
|
||||
request.setAmount(amountReq);
|
||||
request.setOutTradeNo(orderId);
|
||||
request.setOutRefundNo(SnowFlakeUtil.getId());
|
||||
Refund refundResult = service.create(request);
|
||||
if (refundResult.getStatus() == SUCCESS) {
|
||||
int priceInCents = payPrice.multiply(new BigDecimal(NumberConstant.HUNDRED)).intValue(); // 转换为分(int)
|
||||
RefundOrderRequest request = new RefundOrderRequest()
|
||||
.setOrderNo(orderId)
|
||||
.setPrice(priceInCents)
|
||||
.setRefundNo(SnowFlakeUtil.getId())
|
||||
.setRefundPrice(priceInCents)
|
||||
.setNotifyUrl("https://zhentuai.com/api/mobile/wx/pay/v1/"+order.getScenicId()+"/refundNotify");
|
||||
RefundOrderResponse response = scenicPayAdapter.refund(request);
|
||||
if (response.isSuccess()) {
|
||||
OrderUpdateReq orderUpdateReq = new OrderUpdateReq();
|
||||
orderUpdateReq.setId(Long.parseLong(orderId));
|
||||
orderUpdateReq.setRefundStatus(OrderStateEnum.REFUNDED.getType());
|
||||
@@ -272,31 +145,14 @@ public class WxPayServiceImpl implements WxPayService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean refundNotify(String refundResult) throws IOException, GeneralSecurityException {
|
||||
// 转为map格式
|
||||
Map<String, String> jsonMap = JSONObject.parseObject(refundResult, Map.class);
|
||||
public boolean refundNotify(Long scenicId, HttpServletRequest request) throws IOException {
|
||||
IPayAdapter scenicPayAdapter = scenicService.getScenicPayAdapter(scenicId);
|
||||
try {
|
||||
RefundResponse callbackResponse = scenicPayAdapter.handleRefundCallback(request);
|
||||
log.info("[微信支付]parse = {}", callbackResponse);
|
||||
|
||||
/*
|
||||
* 退款成功后返回一个加密字段resource,以下为解密
|
||||
* 解密需要从resource参数中,获取到ciphertext,nonce,associated_data这三个参数进行解密
|
||||
*/
|
||||
String resource = JSONObject.toJSONString(jsonMap.get(REFUNDS_RESOURCE));
|
||||
JSONObject object = JSONObject.parseObject(resource);
|
||||
|
||||
String ciphertext = String.valueOf(object.get(REFUNDS_CIPHERTEXT));
|
||||
String nonce = String.valueOf(object.get(REFUNDS_NONCE));
|
||||
String associated_data = String.valueOf(object.get(REFUNDS_ASSOCIATED_DATA));
|
||||
|
||||
String resultStr = decryptToString(associated_data.getBytes(String.valueOf(StandardCharsets.UTF_8)),
|
||||
nonce.getBytes(String.valueOf(StandardCharsets.UTF_8)),
|
||||
ciphertext);
|
||||
Map<String, String> reqInfo = JSONObject.parseObject(resultStr, Map.class);
|
||||
|
||||
String refund_status = reqInfo.get(REFUNDS_REFUND_STATUS);// 退款状态
|
||||
String out_trade_no = reqInfo.get(WECHATPAY_OUT_TRADE_NO); // 订单号
|
||||
|
||||
if (!StringUtils.isEmpty(refund_status) && WECHATPAY_SUCCESS.equals(refund_status)) {
|
||||
long orderId = Long.parseLong(out_trade_no);
|
||||
// 更新订单信息
|
||||
long orderId = Long.parseLong(callbackResponse.getOrderNo());
|
||||
orderBiz.refundOrder(orderId);
|
||||
|
||||
OrderEntity order = orderRepository.getOrder(orderId);
|
||||
@@ -306,117 +162,19 @@ public class WxPayServiceImpl implements WxPayService {
|
||||
statisticsRecordAddReq.setScenicId(order.getScenicId());
|
||||
statisticsRecordAddReq.setMorphId(orderId);
|
||||
statisticsMapper.addStatisticsRecord(statisticsRecordAddReq);
|
||||
|
||||
log.info("[微信退款回调]退款成功");
|
||||
return true;
|
||||
} else {
|
||||
log.error("[微信退款回调]退款失败");
|
||||
} catch (Exception e) {
|
||||
log.error("微信退款回调失败!", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOrder(String orderId) {
|
||||
CloseOrderRequest closeOrderRequest = new CloseOrderRequest();
|
||||
closeOrderRequest.setOutTradeNo(orderId);
|
||||
closeOrderRequest.setMchid(wechatConfig.getMchId());
|
||||
Config config = getInstance(wechatConfig);
|
||||
// 构建service
|
||||
JsapiService service = new JsapiService.Builder().config(config).build();
|
||||
service.closeOrder(closeOrderRequest);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 退款回调 解密数据
|
||||
*
|
||||
* @param associatedData
|
||||
* @param nonce
|
||||
* @param ciphertext
|
||||
* @return
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext) throws GeneralSecurityException, IOException {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
||||
SecretKeySpec key = new SecretKeySpec(wechatConfig.getApiV3().getBytes(), "AES");
|
||||
GCMParameterSpec spec = new GCMParameterSpec(128, nonce);
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, spec);
|
||||
cipher.updateAAD(associatedData);
|
||||
return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), StandardCharsets.UTF_8);
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成退款请求token
|
||||
*
|
||||
* @param method
|
||||
* @param orderId
|
||||
* @param body
|
||||
* @return
|
||||
* @throws InvalidKeyException
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws UnsupportedEncodingException
|
||||
* @throws SignatureException
|
||||
*/
|
||||
public String getToken(String method, String orderId, String body) throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException, SignatureException {
|
||||
String nonceStr = WXPayUtil.generateNonceStr();
|
||||
long timestamp = System.currentTimeMillis() / NumberConstant.THOUSAND; // 生成时间戳
|
||||
|
||||
String parameter = method + "\n"
|
||||
+ REFUNDS_URi + orderId + "\n"
|
||||
+ timestamp + "\n"
|
||||
+ nonceStr + "\n"
|
||||
+ body + "\n";
|
||||
|
||||
// 对参数进行加密
|
||||
byte[] bytes = parameter.getBytes(String.valueOf(StandardCharsets.UTF_8));
|
||||
Signature sign = Signature.getInstance("SHA256withRSA");
|
||||
PrivateKey privateKey = PemUtil.loadPrivateKeyFromString(wechatConfig.getKeyPath()); // privateKeyPath是商户证书密钥的位置apiclient_key.pem
|
||||
sign.initSign(privateKey); // 商户密钥文件路径
|
||||
sign.update(bytes);
|
||||
String signature = Base64.getEncoder().encodeToString(sign.sign());
|
||||
|
||||
// 获取token
|
||||
String token = "mchid=\"" + wechatConfig.getMchId() + "\"," // 商户号
|
||||
+ "nonce_str=\"" + nonceStr + "\","
|
||||
+ "timestamp=\"" + timestamp + "\","
|
||||
+ "serial_no=\"" + wechatConfig.getMchSerialNo() + "\"," // merchantSerialNumber是微信支付中申请的证书序列号
|
||||
+ "signature=\"" + signature + "\"";
|
||||
|
||||
return REFUNDS_SCHEMA + token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
|
||||
*/
|
||||
private static class Holder {
|
||||
private static volatile Config instance;
|
||||
|
||||
static void init(WechatConfig wechatConfig) {
|
||||
instance = new RSAAutoCertificateConfig.Builder()
|
||||
.merchantId(wechatConfig.getMchId())
|
||||
.privateKey(wechatConfig.getKeyPath())
|
||||
.merchantSerialNumber(wechatConfig.getMchSerialNo())
|
||||
.apiV3Key(wechatConfig.getApiV3())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
public static Config getInstance(WechatConfig wechatConfig) {
|
||||
if (Holder.instance == null) {
|
||||
synchronized (Holder.class) {
|
||||
if (Holder.instance == null) {
|
||||
Holder.init(wechatConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Holder.instance;
|
||||
OrderEntity order = orderRepository.getOrder(Long.parseLong(orderId));
|
||||
IPayAdapter scenicPayAdapter = scenicService.getScenicPayAdapter(order.getScenicId());
|
||||
CancelOrderRequest request = new CancelOrderRequest()
|
||||
.setOrderNo(orderId);
|
||||
scenicPayAdapter.cancelOrder(request);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user