1.查看微信官方文檔:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
2. 使用sdk獲取預訂單信息,通過預訂單信息發起支付
a.引用sdk依賴,該支付sdk文檔:https://github.com/Pay-Group/best-pay-sdk
<dependency> <groupId>cn.springboot</groupId> <artifactId>best-pay-sdk</artifactId> <version>1.1.0</version> </dependency>
b. 給sdk的bestPayService添加配置:
@Component public class WechatPayConfig { @Autowired private WechatAccountConfig wechatAccountConfig; @Bean public BestPayServiceImpl bestPayService(){ BestPayServiceImpl bestPayService=new BestPayServiceImpl(); bestPayService.setWxPayH5Config(wxPayH5Config()); return bestPayService; } private WxPayH5Config wxPayH5Config(){ WxPayH5Config wxPayH5Config = new WxPayH5Config(); //wechatAccountConfig是通過 // @ConfigurationProperties(prefix = "wechat")讀取yml文件的配置文件對象 wxPayH5Config.setAppId(wechatAccountConfig.getMpAppId()); wxPayH5Config.setAppSecret(wechatAccountConfig.getMpAppSecret()); wxPayH5Config.setMchId(wechatAccountConfig.getMchId()); wxPayH5Config.setMchKey(wechatAccountConfig.getMchKey()); wxPayH5Config.setKeyPath(wechatAccountConfig.getKeyPath()); wxPayH5Config.setNotifyUrl(wechatAccountConfig.getNotifyUrl()); return wxPayH5Config; } }
c.編寫本地的payservice
@Service public class PayServiceImpl implements PayService { private static final String ORDER_NAME = "微信點餐訂單"; @Autowired BestPayServiceImpl bestPayService; @Override public PayResponse create(OrderDTO orderDTO) { PayRequest request=new PayRequest(); //通過查詢出的order信息,設置支付的必填項 request.setOpenid("oTgZpwU8hDPxbUjXmwLXp6TiBqK4"); request.setOrderAmount(orderDTO.getOrderAmount().doubleValue()); request.setOrderId(orderDTO.getOrderId()); request.setPayTypeEnum(BestPayTypeEnum.WXPAY_H5); request.setOrderName(ORDER_NAME); PayResponse payResponse = bestPayService.pay(request); return payResponse; } }
d.編寫controller獲取payResponse,里面包含信息如下
@Controller @Slf4j @RequestMapping("/pay") public class PayController { @Autowired OrderService orderService; @Autowired PayService payService; @GetMapping("/create") public ModelAndView create(@RequestParam("orderId") String orderId, @RequestParam("returnUrl") String returnUrl) { //1. 查詢訂單 OrderDTO orderDTO = orderService.findOne(orderId); if (orderDTO == null) { throw new SellException(ResultEnum.ORDER_NOT_EXIST); } //發起支付 PayResponse payResponse = payService.create(orderDTO); //通過查詢的訂單創建支付 log.info("payResponse={}", JsonUtil.toJson(payResponse)); Map<String,Object> result=new HashMap<>(); result.put("payResponse",payResponse); result.put("returnUrl",returnUrl); return new ModelAndView("pay/create",result); //將數據傳輸至freemark文件(前端) } }
e.通過payResponse獲取的信息傳輸給前端,在前端發起支付(只有在微信才可支付)
<script> function onBridgeReady(){ WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId":"${payResponse.appId}", //公眾號名稱,由商戶傳入 "timeStamp":"${payResponse.timeStamp}", //時間戳,自1970年以來的秒數 "nonceStr":"${payResponse.nonceStr}", //隨機串 "package":"${payResponse.packAge}", "signType":"${payResponse.signType}", //微信簽名方式: "paySign":"${payResponse.paySign}" //微信簽名 }, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ){ // 使用以上方式判斷前端返回,微信團隊鄭重提示: //res.err_msg將在用戶支付成功后返回ok,但並不保證它絕對可靠。 } }); } 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>
f.支付成功,微信異步通知:
配置接收異步信息的service:
public void notify(String notifyData){ //驗證簽名 sdk已驗證 //支付的狀態 sdk已驗證 //支付金額 PayResponse payResponse = bestPayService.asyncNotify(notifyData); //解析微信返回的xml文件 OrderDTO orderDTO = orderService.findOne(payResponse.getOrderId()); if(orderDTO==null){ log.error("異步通知,訂單不存在 orderId={}",payResponse.getOrderId()); throw new SellException(ResultEnum.ORDER_NOT_EXIST); } if(!MathUtil.equals(payResponse.getOrderAmount(),orderDTO.getOrderAmount().doubleValue())){ log.error("異步通知,金額不相等 payResponse={}", JsonUtil.toJson(payResponse)); throw new SellException(ResultEnum.WXPAY_NOTIFY_MONEY_VERIFY_ERROR); } orderService.paid(orderDTO); }
配置相應的controller層
@PostMapping("/notify") public ModelAndView notify(@RequestBody String notifyData){//獲取微信服務器傳來的xml文件 payService.notify(notifyData); return new ModelAndView("pay/success"); //給微信服務器返回成功的接收的信息,不再發送通知信息 }
g.退款操作
配置相應的service層,需退款調用即可:
@Override public RefundResponse refund(OrderDTO orderDTO) { RefundRequest refundRequest = new RefundRequest(); refundRequest.setOrderAmount(orderDTO.getOrderAmount().doubleValue()); refundRequest.setOrderId(orderDTO.getOrderId()); refundRequest.setPayTypeEnum(BestPayTypeEnum.WXPAY_H5); log.info("【微信退款】request={}",JsonUtil.toJson(refundRequest)); RefundResponse refund = bestPayService.refund(refundRequest); log.info("【微信退款】response={}",JsonUtil.toJson(refund)); //收到outRefundNo表示退款成功 return refund; }