🆕 #2022 【微信支付】增加智慧商圈相关接口和解析支付营销代金券核销回调消息的方法

* 增加解析支付营销代金券核销回调消息解析

* 增加微信支付智慧商圈接口和回调解析

Co-authored-by: 黄星 <huang.xing@aquilaflycloud.com>
This commit is contained in:
thinsstar
2021-03-09 16:12:11 +08:00
committed by GitHub
parent e46c6c1995
commit 30155b316b
25 changed files with 1226 additions and 56 deletions

View File

@@ -0,0 +1,35 @@
package com.github.binarywang.wxpay.service;
import com.github.binarywang.wxpay.bean.businesscircle.BusinessCircleNotifyData;
import com.github.binarywang.wxpay.bean.businesscircle.PaidResult;
import com.github.binarywang.wxpay.bean.businesscircle.PointsNotifyRequest;
import com.github.binarywang.wxpay.bean.businesscircle.RefundResult;
import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader;
import com.github.binarywang.wxpay.exception.WxPayException;
/**
* <pre>
* 微信支付智慧商圈API
* </pre>
*
* @author thinsstar
*/
public interface BusinessCircleService {
/**
* <pre>
* 智慧商圈接口-商圈积分同步API
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/businesscircle/chapter3_2.shtml
* 接口链接https://api.mch.weixin.qq.com/v3/businesscircle/points/notify
* </pre>
*
* @param request 请求对象
* @throws WxPayException the wx pay exception
*/
void notifyPoints(PointsNotifyRequest request) throws WxPayException;
BusinessCircleNotifyData parseNotifyData(String data, SignatureHeader header) throws WxPayException;
PaidResult decryptPaidNotifyDataResource(BusinessCircleNotifyData data) throws WxPayException;
RefundResult decryptRefundNotifyDataResource(BusinessCircleNotifyData data) throws WxPayException;
}

View File

@@ -1,5 +1,6 @@
package com.github.binarywang.wxpay.service;
import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader;
import com.github.binarywang.wxpay.bean.marketing.*;
import com.github.binarywang.wxpay.exception.WxPayException;
@@ -172,13 +173,39 @@ public interface MarketingFavorService {
* 接口链接https://api.mch.weixin.qq.com/v3/marketing/favor/callbacks
* </pre>
*
* @param request 批次号
* @param request 请求对象
* @return FavorCallbacksSaveResult 微信返回的结果信息。
* @throws WxPayException the wx pay exception
*/
FavorCallbacksSaveResult saveFavorCallbacksV3(FavorCallbacksSaveRequest request) throws WxPayException;
/**
* <pre>
* 代金券接口-暂停代金券批次API
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_13.shtml
* 接口链接https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/{stock_id}/pause
* </pre>
*
* @param request 请求对象
* @return FavorCallbacksSaveResult 微信返回的结果信息。
* @throws WxPayException the wx pay exception
*/
FavorStocksStartResult pauseFavorStocksV3(String stockId, FavorStocksSetRequest request) throws WxPayException;
/**
* <pre>
* 代金券接口-重启代金券批次API
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_14.shtml
* 接口链接https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/{stock_id}/restart
* </pre>
*
* @param request 请求对象
* @return FavorCallbacksSaveResult 微信返回的结果信息。
* @throws WxPayException the wx pay exception
*/
FavorStocksStartResult restartFavorStocksV3(String stockId, FavorStocksSetRequest request) throws WxPayException;
UseNotifyData parseNotifyData(String data, SignatureHeader header) throws WxPayException;
FavorCouponsUseResult decryptNotifyDataResource(UseNotifyData data) throws WxPayException;
}

View File

@@ -153,6 +153,13 @@ public interface WxPayService {
*/
EcommerceService getEcommerceService();
/**
* 获取微信支付智慧商圈服务类
*
* @return the business circle service
*/
BusinessCircleService getBusinessCircleService();
/**
* 获取微信支付通用媒体服务类
*

View File

@@ -60,6 +60,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
private final RedpackService redpackService = new RedpackServiceImpl(this);
private final PayScoreService payScoreService = new PayScoreServiceImpl(this);
private final EcommerceService ecommerceService = new EcommerceServiceImpl(this);
private final BusinessCircleService businessCircleService = new BusinessCircleServiceImpl(this);
private final MerchantMediaService merchantMediaService = new MerchantMediaServiceImpl(this);
private final MarketingMediaService marketingMediaService = new MarketingMediaServiceImpl(this);
private final MarketingFavorService marketingFavorService = new MarketingFavorServiceImpl(this);
@@ -91,6 +92,11 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
return ecommerceService;
}
@Override
public BusinessCircleService getBusinessCircleService() {
return this.businessCircleService;
}
@Override
public MerchantMediaService getMerchantMediaService() {
return this.merchantMediaService;

View File

@@ -0,0 +1,89 @@
package com.github.binarywang.wxpay.service.impl;
import com.github.binarywang.wxpay.bean.businesscircle.BusinessCircleNotifyData;
import com.github.binarywang.wxpay.bean.businesscircle.PaidResult;
import com.github.binarywang.wxpay.bean.businesscircle.PointsNotifyRequest;
import com.github.binarywang.wxpay.bean.businesscircle.RefundResult;
import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.BusinessCircleService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.v3.util.AesUtils;
import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Objects;
/**
* 微信支付-微信支付智慧商圈service
*
* @author thinsstar
*/
@Slf4j
@RequiredArgsConstructor
public class BusinessCircleServiceImpl implements BusinessCircleService {
private static final Gson GSON = new GsonBuilder().create();
private final WxPayService payService;
@Override
public void notifyPoints(PointsNotifyRequest request) throws WxPayException {
String url = String.format("%s/v3/businesscircle/points/notify", this.payService.getPayBaseUrl());
RsaCryptoUtil.encryptFields(request, this.payService.getConfig().getVerifier().getValidCertificate());
this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request));
}
/**
* 校验通知签名
*
* @param header 通知头信息
* @param data 通知数据
* @return true:校验通过 false:校验不通过
*/
private boolean verifyNotifySign(SignatureHeader header, String data) {
String beforeSign = String.format("%s%n%s%n%s%n", header.getTimeStamp(), header.getNonce(), data);
return payService.getConfig().getVerifier().verify(header.getSerialNo(),
beforeSign.getBytes(StandardCharsets.UTF_8), header.getSigned());
}
@Override
public BusinessCircleNotifyData parseNotifyData(String data, SignatureHeader header) throws WxPayException {
if (Objects.nonNull(header) && !this.verifyNotifySign(header, data)) {
throw new WxPayException("非法请求,头部信息验证失败");
}
return GSON.fromJson(data, BusinessCircleNotifyData.class);
}
@Override
public PaidResult decryptPaidNotifyDataResource(BusinessCircleNotifyData data) throws WxPayException {
BusinessCircleNotifyData.Resource resource = data.getResource();
String cipherText = resource.getCipherText();
String associatedData = resource.getAssociatedData();
String nonce = resource.getNonce();
String apiV3Key = this.payService.getConfig().getApiV3Key();
try {
return GSON.fromJson(AesUtils.decryptToString(associatedData, nonce, cipherText, apiV3Key), PaidResult.class);
} catch (GeneralSecurityException | IOException e) {
throw new WxPayException("解析报文异常!", e);
}
}
@Override
public RefundResult decryptRefundNotifyDataResource(BusinessCircleNotifyData data) throws WxPayException {
BusinessCircleNotifyData.Resource resource = data.getResource();
String cipherText = resource.getCipherText();
String associatedData = resource.getAssociatedData();
String nonce = resource.getNonce();
String apiV3Key = this.payService.getConfig().getApiV3Key();
try {
return GSON.fromJson(AesUtils.decryptToString(associatedData, nonce, cipherText, apiV3Key), RefundResult.class);
} catch (GeneralSecurityException | IOException e) {
throw new WxPayException("解析报文异常!", e);
}
}
}

View File

@@ -1,9 +1,11 @@
package com.github.binarywang.wxpay.service.impl;
import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader;
import com.github.binarywang.wxpay.bean.marketing.*;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.MarketingFavorService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.v3.util.AesUtils;
import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -11,6 +13,11 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Objects;
/**
* 微信支付-营销代金券接口
*
@@ -161,4 +168,39 @@ public class MarketingFavorServiceImpl implements MarketingFavorService {
String result = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request));
return GSON.fromJson(result, FavorStocksStartResult.class);
}
/**
* 校验通知签名
*
* @param header 通知头信息
* @param data 通知数据
* @return true:校验通过 false:校验不通过
*/
private boolean verifyNotifySign(SignatureHeader header, String data) {
String beforeSign = String.format("%s%n%s%n%s%n", header.getTimeStamp(), header.getNonce(), data);
return payService.getConfig().getVerifier().verify(header.getSerialNo(),
beforeSign.getBytes(StandardCharsets.UTF_8), header.getSigned());
}
@Override
public UseNotifyData parseNotifyData(String data, SignatureHeader header) throws WxPayException {
if (Objects.nonNull(header) && !this.verifyNotifySign(header, data)) {
throw new WxPayException("非法请求,头部信息验证失败");
}
return GSON.fromJson(data, UseNotifyData.class);
}
@Override
public FavorCouponsUseResult decryptNotifyDataResource(UseNotifyData data) throws WxPayException {
UseNotifyData.Resource resource = data.getResource();
String cipherText = resource.getCipherText();
String associatedData = resource.getAssociatedData();
String nonce = resource.getNonce();
String apiV3Key = this.payService.getConfig().getApiV3Key();
try {
return GSON.fromJson(AesUtils.decryptToString(associatedData, nonce, cipherText, apiV3Key), FavorCouponsUseResult.class);
} catch (GeneralSecurityException | IOException e) {
throw new WxPayException("解析报文异常!", e);
}
}
}