微信公众号支付开发
微信公众号支付业务流程如下:
设置授权域名
统一下单
授权登录,获取openid
下单之前,前端要先判断是否有openid,如果没有,需要首先调用后台授权接口得到openid。我们可以使用第三方SDK来做授权操作,这样比较简单。参考:微信公众号支付授权登录。
首先,项目中引入第三方SDK的依赖:
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>3.0.0</version>
</dependency>
授权登录需要商户的AppId和AppSecret,可以通过配置文件注入。首先在application.yml中配置这两个属性:
myAppSecret: 075419ce8d3f95a3b49304d84d98cee5
然后创建一个类用来存放这些属性的值:
@Component @ConfigurationProperties(prefix = "wechat") @Data public class private String myAppIdprivate String myAppSecretprivate String mchIdprivate String mchKeyprivate String keyPathprivate String notifyUrl; }
然后将AppId和AppSecret设置到WxMpService中:
@Component public class private WeChatAccountConfig weChatAccountConfigpublic new return public new weChatAccountConfigweChatAccountConfigreturn
最后调用SDK的接口进行授权:
@Controller @RequestMapping("/wechat") @Slf4j public class private WxMpService wxMpService@GetMapping("/authorize"public String authorize(@RequestParam("returnUrl""http://rc6wah.natappfree.cc/sell/wechat/userInfo"wxMpServiceSNSAPI_USERINFO, URLEncoder.encodelog.info("【微信网页授权】 获取code, result={}"return "redirect:"
("/userInfo"public String userInfo(@RequestParam("code") String code, @RequestParam("state"new try wxMpServicecatch log.error("【微信网页授权】 {}"throw new SellException(ResultEnum.WECHAT_MP_ERRORreturn "redirect:" + returnUrl + "?openid="
上面,returnUrl是前端传进来的,表示授权登陆后要跳转的页面。此时,就已经获得openid,返回给前台。
支付
支付这块为了方便使用,一样引用第三方SDK:
<dependency><groupId>cn.springboot</groupId><artifactId>best-pay-sdk</artifactId><version>1.2.0</version> </dependency>
支付完成之后微信会有一个异步通知,我将这两个接口写在同一个controller中了。代码如下:
@Controller @RequestMapping("/pay") public class private OrderMasterService orderMasterServiceprivate PayService payService@param * @param * @param * @GetMapping("/create"public ModelAndView create(@RequestParam("orderId"@RequestParam("returnUrl"//OrderMasterDto orderMasterDto = orderMasterServiceif (orderMasterDto == nullthrow new SellException(ResultEnum.ORDER_NOT_EXIST//PayResponse payResponse = payService"payResponse""returnUrl"return new ModelAndView("pay/create"@param @PostMapping("/notify"public ModelAndView notify(@RequestBody payService//return new ModelAndView("pay/success"
先说支付,两个入参:orderId表示要支付订单的订单号,returnUrl表示异步通知地址,可以在配置文件中配置,即下面的notifyUrl:
myAppSecret: notifyUrl: http://rc6wah.natappfree.cc/sell/pay/notify
支付接口中,payService的create方法为:
public new ORDER_NAMEWXPAY_H5log.info("【微信支付】 发起支付,request={}", JsonUtil.toJsonbestPayServicelog.info("【微信支付】 发起支付,response={}", JsonUtil.toJsonreturn payResponse; }
最后返回一个payResponse,这个对象为:
@Data public class private String prePayParamsprivate URI payUri/** 以下字段仅在微信h5private String appIdprivate String timeStampprivate String nonceStr@JsonProperty("package"private String packAgeprivate String signTypeprivate String paySign/** private Double orderAmountprivate String orderId//private String outTradeNo/** 以下支付是h5private String mwebUrl; }
最后把这个对象和异步通知地址通过重定向返回给create页面。create页面路径:
create.ftl内容如下:
<script>function onBridgeReady'getBrandWCPayRequest'"appId":${payResponse.appId}//"timeStamp":${payResponse.timeStamp}//时间戳,自1970"nonceStr":${payResponse.nonceStr}, //"package":${payResponse.packAge}"signType":"MD5"//"paySign":${payResponse.paySign} //functionif(res.err_msg == "get_brand_wcpay_request:ok" // 使用以上方式判断前端返回,location.href = "${returnUrl}if (typeof WeixinJSBridge == "undefined"if( document.addEventListener document.addEventListener('WeixinJSBridgeReady', onBridgeReady, falseelse if (documentdocument.attachEvent('WeixinJSBridgeReady', onBridgeReadydocument.attachEvent('onWeixinJSBridgeReady', onBridgeReadyelseonBridgeReady</script>
成功之后就会调用returnUrl,即配置文件中配置的notifyUrl地址,此处就是上面controller中的notify接口。
异步通知
Notify接口中,notify方法如下:
@param * */ @Override public //1.PayResponse payResponse = bestPayServicelog.info("【微信支付】 异步通知, payResponse={}"//orderMasterServiceif (orderMasterDto == nulllog.error("【微信支付】 异步通知,订单不存在,orderId={}"throw new SellException(ResultEnum.ORDER_NOT_EXIST//if (!MathUtil.equalslog.error("【微信支付】 异步通知,订单金额不一致, orderId={}, 微信通知金额={}, 系统金额={}"throw new SellException(ResultEnum.WXPAY_NOTIFY_MONNEY_VERIFY//orderMasterServicereturn payResponse; }
主要是修改订单支付状态,成功之后,返回success界面,通知微信已经成功,不需再调用异步通知接口了。success路径:
内容:
<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg> </xml>