SpringBoot集成微信小程序创建订单&支付&退款
概要
提示:个人小程序不能进行支付等操作,因为需要在微信小程序进行商户认证等一系列操作
1,小程序支付触发如下:
实现逻辑:
1.1,点击支付首先前端传后端需要的一系列参数,调用后端生成一个未支付的订单,并返回给前端订单id
1.2,前端根据订单id调用接口生成微信小程序的订单(核心是调用微信小程序接口),重点参数有1里的订单id和回调地址(用于4回调时会在传参里传到后端,然后通过解析找到订单id查询订单并修改订单状态),返回一系列res
1.3,前端调起输入密码窗口,根据2返回的res,组装并完成支付
1.4,在2中有一个req的一个参数是负责微信支付回调的忽略token的全路径的接口地址,用于通知后端支付情况。
2,小程序退款申请触发如下:
实现逻辑:
2.1 用户点击取消预定触发退款申请操作,传入微信订单的订单id【transactionId】和退款理由,最终调用微信退款申请发起退款
2.2 根据微信接口返回结果判断是PROCESSING(处理中),SUCCESS(退款成功),ABNORMAL(异常),CLOSED(退款关闭)通过transactionId查找对应的后端订单,然后修改对应订单状态
2.3 退款回调,同理支付回调,后端通过解析回调参数判断是否退款成功
1,创建微信小程序订单
前提:小程序已经调用后端创建订单接口并返回给了前端订单id
pm.xml配置
<!-- 微信小程序支付-->
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
<version>0.2.12</version>
</dependency>
1.1 yml 配置
# 微信小程序配置
wx:
appId:
secret:
grant_type: client_credential
#商户号
merchantId:
# 私钥路径
privateKeyPath: **/apiclient_key.pem
# 商户号证书序列号
merchantSerialNumber:
# 商户apiV3秘钥
apiV3key:
#支付回调
notifyUrl: https://..../payNotify
#退款回调
refundNotifyUrl: https://..../refundNotify
1.2 WxPayConfig 配置类
@Data
@Component
@ConfigurationProperties(prefix = "wx")
public class WxPayConfig {
// appId
private String appId;
// secret
private String secret;
//
private String grant_type;
// 商户id
private String merchantId;
// 私钥地址
private String privateKeyPath;
// 商户序列号
private String merchantSerialNumber;
// apiV3key
private String apiV3key;
// 支付回调地址
private String notifyUrl;
// 退款回调地址
private String refundNotifyUrl;
}
1.3 WxPayAutoCertificateConfig 配置类
@Configuration
public class WxPayAutoCertificateConfig {
@Resource
private WxPayConfig wxPayConfig;
/**
* 初始化商户配置
* @return
*/
@Bean
public RSAAutoCertificateConfig rsaAutoCertificateConfig() {
RSAAutoCertificateConfig config = new RSAAutoCertificateConfig.Builder()
.merchantId(wxPayConfig.getMerchantId())
.privateKey(PemUtil.loadPrivateKeyFromPath(wxPayConfig.getPrivateKeyPath()))
.merchantSerialNumber(wxPayConfig.getMerchantSerialNumber())
.apiV3Key(wxPayConfig.getApiV3key())
.build();
return config;
}
}
1.4 Controller层
@GetMapping("/createOrder")
public R<PrepayWithRequestPaymentResponse> createOrder(@Validated Long orderId) {
logger.info("微信小程序创建预支付订单", orderId.toString());
try {
return weChatService.createOrder(orderId);
} catch (Exception e) {
e.printStackTrace();
return R.fail(e.getMessage());
}
}
1.5 Impl层(Service自行补充)
private final WxPayConfig wxPayConfig;
private final WxPayAutoCertificateConfig certificateConfig;
private static final String BASE_URL = "https://api.weixin.qq.com";
@Override
public R<PrepayWithRequestPaymentResponse> createOrder(Long orderId) throws Exception {
// 通过订单id获取到订单信息
R hotelOrder = hotelPcClient.detailHotelOrder(orderId);
if (!hotelOrder.isSuccess()){
throw new Exception("订单不存在,稍后重试");
}
HotelOrderVO order =JSONObject.parseObject(JSONObject.toJSONString(hotelOrder.getData()), HotelOrderVO.class);
log.info("请求微信支付相关配置");
JsapiServiceExtension service =
new JsapiServiceExtension.Builder()
.config(certificateConfig.rsaAutoCertificateConfig())
.signType("RSA") // 不填默认为RSA
.build();
PrepayWithRequestPaymentResponse response = new PrepayWithRequestPaymentResponse();
try {
PrepayRequest request = new PrepayRequest();
request.setAppid(wxPayConfig.getAppId());
request.setMchid(wxPayConfig.getMerchantId());
request.setDescription(order.getRemark());
request.setOutTradeNo(order.getSerialNumber());
request.setNotifyUrl(wxPayConfig.getNotifyUrl());
Amount amount = new Amount();
// 以分为单位
amount.setTotal(order.getPaymentAmount().multiply(new BigDecimal("100")).intValue());
request.setAmount(amount);
Payer payer = new Payer();