0
点赞
收藏
分享

微信扫一扫

微信支付 & 退款 - 快速入门(第三方SDK)


微信支付 & 退款 - 快速入门(第三方SDK)_SpringBoot

微信支付 & 退款 - 快速入门(第三方SDK)_SpringBoot_02

<dependency>
<groupId>cn.springboot</groupId>
<artifactId>best-pay-sdk</artifactId>
<version>1.1.0</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
wechat:
# 公众账号, 授权
mpAppId: wxd898fcb01713c658
mpAppSecret:

# 开放平台, 卖家扫码登录用
openAppId: wx6ad144e54af67d87
openAppSecret: 91a2ff6d38a2bbccfb7e9xxxxxx

# 支付/商户号
mchId: 1483469312
mchKey: 06C56A89949D617xxxxxxxxxxx
# 发起支付不需要证书, 退款需要
keyPath:
notifyUrl: http://sell.natapp4.cc/sell/pay/notify
templateId:
orderStatus: e-Cqq67QxD6YNI41iRiqawEYdFavW_7pc7LyEMb-yeQ
package com.imooc.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Map;

@Data
@Component
@ConfigurationProperties(prefix = "wechat")
public class WechatAccountConfig {

/**
* 公众平台id
*/
private String mpAppId;

/**
* 公众平台密钥
*/
private String mpAppSecret;

/**
* 开放平台id
*/
private String openAppId;

/**
* 开放平台密钥
*/
private String openAppSecret;

/**
* 商户号
*/
private String mchId;

/**
* 商户密钥
*/
private String mchKey;

/**
* 商户证书路径
*/
private String keyPath;

/**
* 微信支付异步通知地址
*/
private String notifyUrl;

/**
* 微信模版id
*/
private Map<String, String> templateId;
}
package com.imooc.config;

import com.lly835.bestpay.config.WxPayH5Config;
import com.lly835.bestpay.service.impl.BestPayServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class WechatPayConfig {

@Autowired
private WechatAccountConfig accountConfig;

@Bean
public BestPayServiceImpl bestPayService() {
BestPayServiceImpl bestPayService = new BestPayServiceImpl();
bestPayService.setWxPayH5Config(wxPayH5Config());
return bestPayService;
}

@Bean
public WxPayH5Config wxPayH5Config() {
WxPayH5Config wxPayH5Config = new WxPayH5Config();
wxPayH5Config.setAppId(accountConfig.getMpAppId());
wxPayH5Config.setAppSecret(accountConfig.getMpAppSecret());
wxPayH5Config.setMchId(accountConfig.getMchId());
wxPayH5Config.setMchKey(accountConfig.getMchKey());
wxPayH5Config.setKeyPath(accountConfig.getKeyPath());
wxPayH5Config.setNotifyUrl(accountConfig.getNotifyUrl());
return wxPayH5Config;
}
}
package com.imooc.service;

import com.imooc.dto.OrderDTO;
import com.lly835.bestpay.model.PayResponse;
import com.lly835.bestpay.model.RefundResponse;

public interface PayService {

PayResponse create(OrderDTO orderDTO);

PayResponse notify(String notifyData);

RefundResponse refund(OrderDTO orderDTO);
}
package com.imooc.service.impl;

import com.imooc.dto.OrderDTO;
import com.imooc.enums.ResultEnum;
import com.imooc.exception.SellException;
import com.imooc.service.OrderService;
import com.imooc.service.PayService;
import com.imooc.utils.JsonUtil;
import com.imooc.utils.MathUtil;
import com.lly835.bestpay.enums.BestPayTypeEnum;
import com.lly835.bestpay.model.PayRequest;
import com.lly835.bestpay.model.PayResponse;
import com.lly835.bestpay.model.RefundRequest;
import com.lly835.bestpay.model.RefundResponse;
import com.lly835.bestpay.service.impl.BestPayServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class PayServiceImpl implements PayService {

private static final String ORDER_NAME = "微信点餐订单";

@Autowired
private BestPayServiceImpl bestPayService;

@Autowired
private OrderService orderService;

@Override
public PayResponse create(OrderDTO orderDTO) {
PayRequest payRequest = new PayRequest();
payRequest.setOpenid(orderDTO.getBuyerOpenid());
payRequest.setOrderAmount(orderDTO.getOrderAmount().doubleValue());
payRequest.setOrderId(orderDTO.getOrderId());
payRequest.setOrderName(ORDER_NAME);
payRequest.setPayTypeEnum(BestPayTypeEnum.WXPAY_H5);
log.info("【微信支付】发起支付, request={}", JsonUtil.toJson(payRequest));

PayResponse payResponse = bestPayService.pay(payRequest);
log.info("【微信支付】发起支付, response={}", JsonUtil.toJson(payResponse));
return payResponse;
}

@Override
public PayResponse notify(String notifyData) {
//1. 验证签名
//2. 支付的状态
//3. 支付金额
//4. 支付人(下单人 == 支付人)

// bestPayService.asyncNotify 已经验证了签名和支付状态
PayResponse payResponse = bestPayService.asyncNotify(notifyData);
log.info("【微信支付】异步通知, payResponse={}", JsonUtil.toJson(payResponse));

//查询订单
OrderDTO orderDTO = orderService.findOne(payResponse.getOrderId());

//判断订单是否存在
if (orderDTO == null) {
log.error("【微信支付】异步通知, 订单不存在, orderId={}", payResponse.getOrderId());
throw new SellException(ResultEnum.ORDER_NOT_EXIST);
}

//判断金额是否一致(0.10 0.1)
if (!MathUtil.equals(payResponse.getOrderAmount(), orderDTO.getOrderAmount().doubleValue())) {
log.error("【微信支付】异步通知, 订单金额不一致, orderId={}, 微信通知金额={}, 系统金额={}",
payResponse.getOrderId(),
payResponse.getOrderAmount(),
orderDTO.getOrderAmount());
throw new SellException(ResultEnum.WXPAY_NOTIFY_MONEY_VERIFY_ERROR);
}

//修改订单的支付状态
orderService.paid(orderDTO);

return payResponse;
}

/**
* 退款
* @param orderDTO
*/
@Override
public RefundResponse refund(OrderDTO orderDTO) {
RefundRequest refundRequest = new RefundRequest();
refundRequest.setOrderId(orderDTO.getOrderId());
refundRequest.setOrderAmount(orderDTO.getOrderAmount().doubleValue());
refundRequest.setPayTypeEnum(BestPayTypeEnum.WXPAY_H5);
log.info("【微信退款】request={}", JsonUtil.toJson(refundRequest));

RefundResponse refundResponse = bestPayService.refund(refundRequest);
log.info("【微信退款】response={}", JsonUtil.toJson(refundResponse));

return refundResponse;
}
}
package com.imooc.controller;

import com.imooc.dto.OrderDTO;
import com.imooc.enums.ResultEnum;
import com.imooc.exception.SellException;
import com.imooc.service.OrderService;
import com.imooc.service.PayService;
import com.lly835.bestpay.model.PayResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.Map;

@Controller
@RequestMapping("/pay")
public class PayController {

@Autowired
private OrderService orderService;

@Autowired
private PayService payService;

@GetMapping("/create")
public ModelAndView create(@RequestParam("orderId") String orderId,
@RequestParam("returnUrl") String returnUrl,
Map<String, Object> map) {
//1. 查询订单
OrderDTO orderDTO = orderService.findOne(orderId);
if (orderDTO == null) {
throw new SellException(ResultEnum.ORDER_NOT_EXIST);
}

//2. 发起支付
PayResponse payResponse = payService.create(orderDTO);

map.put("payResponse", payResponse);
map.put("returnUrl", returnUrl);

return new ModelAndView("pay/create", map);
}

/**
* 微信异步通知
* @param notifyData
*/
@PostMapping("/notify")
public ModelAndView notify(@RequestBody String notifyData) {
payService.notify(notifyData);

//返回给微信处理结果
return new ModelAndView("pay/success");
}
}

Freemarker 目录结构

微信支付 & 退款 - 快速入门(第三方SDK)_回调_03

// create

<script>
function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":"${payResponse.appId}", //公众号名称,由商户传入
"timeStamp":"${payResponse.timeStamp}", //时间戳,自1970年以来的秒数
"nonceStr":"${payResponse.nonceStr}", //随机串
"package":"${payResponse.packAge}",
"signType":"MD5", //微信签名方式:
"paySign":"${payResponse.paySign}" //微信签名
},
function(res){
// if(res.err_msg == "get_brand_wcpay_request:ok" ) {

// } // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
location.href = "${returnUrl}";
}
);
}
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
}else{
onBridgeReady();
}
</script>
// success

<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
</xml>

  • 微信一旦成功发起了支付,这时,你在数据库改价格,发现再一次调用接口,还是原先未改的价格。这是因为一旦成功发起,微信服务器就会记录该订单信息,所以需要重新修改订单号等相关信息。 
  • 订单状态业务处理后需要返回给微信处理结果,否则微信会定时调用异步回调方法。
  • 模板引擎:Freemarker,之所以要用这个,没有前后端分离,是因为前端可能反复需要写这么一段JSSDK,当然前端也可以去封装,这里只不过也可以在后端封装中间这个过程。


举报

相关推荐

0 条评论