第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > 微信小程序支付 JSAPI v3---下单 回调

微信小程序支付 JSAPI v3---下单 回调

时间:2021-03-21 10:27:03

相关推荐

微信小程序支付 JSAPI v3---下单 回调

微信小程序支付 JSAPI v3---下单、回调

一、接入前准备

1. 微信支付文档中心

@ 接入准备: https://pay./wiki/doc/apiv3/open/pay/chapter2_8_1.shtml

@ 小程序支付API列表: https://pay./wiki/doc/apiv3/open/pay/chapter2_8_3.shtml

2. pom.xml加入依赖

<dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-pay</artifactId><version>4.3.0</version></dependency>

3. application.yml

#微信支付参数相关wx:pay:app_id: #微信公众号或者小程序等的appidmch_id: #微信支付商户号Api_V3_Key: # api v3支付秘钥 #微信支付商户密钥# subAppId: #服务商模式下的子商户公众账号ID# subMchId: #服务商模式下的子商户号private_key_path: # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)private_cert_path: # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)notify_url: # 支付成功回调

二、编码

1. 编写配置WxPayProperties读取配置

@Component@Data@ConfigurationProperties(prefix = "wx.pay")public class WxPayProperties {/*** 设置微信公众号或者小程序等的appid*/private String appId;/*** 微信支付商户号*/private String mchId;/*** 微信支付商户密钥*/private String apiV3Key;/*** 服务商模式下的子商户公众账号ID,普通模式请不要配置,请在配置文件中将对应项删除*/private String subAppId;/*** 服务商模式下的子商户号,普通模式请不要配置,最好是请在配置文件中将对应项删除*/private String subMchId;/*** apiclient_key.pem文件的绝对路径,或者如果放在项目中,请以classpath:开头指定*/private String privateKeyPath;/*** apiclient_key.pem文件的绝对路径,或者如果放在项目中,请以classpath:开头指定*/private String privateCertPath;/*** 支付成功回调地址:v3版本,必须是https*/private String notifyUrl;}

2. 初始化微信支付相关配置参数

/*** 微信支付配置*/@Configuration@ConditionalOnClass(WxPayService.class)@AllArgsConstructorpublic class AlarmWxPayConfig {@Autowiredprivate WxPayProperties properties;/*** 初始化微信支付相关配置参数* @return*/@Bean@ConditionalOnMissingBeanpublic WxPayService wxService() {WxPayConfig payConfig = new WxPayConfig();payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId()));payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));payConfig.setSubAppId(StringUtils.trimToNull(this.properties.getSubAppId()));payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId()));payConfig.setPrivateCertPath(StringUtils.trimToNull(this.properties.getPrivateCertPath()));payConfig.setPrivateKeyPath(StringUtils.trimToNull(this.properties.getPrivateKeyPath()));payConfig.setApiV3Key(StringUtils.trimToNull(this.properties.getApiV3Key()));// 可以指定是否使用沙箱环境payConfig.setUseSandboxEnv(false);WxPayService wxPayService = new WxPayServiceImpl();wxPayService.setConfig(payConfig);return wxPayService;}}

3. 下单

@ JSAPI下单

@ 请求参数(必填)

{"appid": "", //【应用ID】必填"mchid": "", //【直连商户号】必填"description ": "", //【商品描述】必填"out_trade_no": "", //【商户订单号】必填"notify_url ": "", //【通知地址】必填"amount": {//【订单金额】必填"total": "",//【总金额】必填},"payer": {//【支付者】"openid": ""//【用户标识】必填},"detail": {//【优惠功能】"invoice_id": "","goods_detail":{//【单品列表】"merchant_goods_id": "",//【商户侧商品编码】必填"quantity": "", //【商品数量】必填"unit_price": "" //【商品单价】必填}},"scene_info": {//【场景信息】"payer_client_ip": "",//【用户终端IP】必填"store_info": {//【商户门店信息】"id": "", //【门店编号】必填}},}

@ JSAPI 下单----生成预支付交易单----返回小程序调起支付API-----必要参数

/*** * JSAPI 下单----生成预支付交易单----返回小程序调起支付API-----必要参数 * * 填入必填项** @return*/public WxPayUnifiedOrderV3Result.JsapiResult prePay("传入业务数据,填充") {WxPayUnifiedOrderV3Request v3Request = new WxPayUnifiedOrderV3Request();ArrayList<WxPayUnifiedOrderV3Request.GoodsDetail> goodsDetails = new ArrayList<>();goodsDetails.add(new WxPayUnifiedOrderV3Request.GoodsDetail() {}.setMerchantGoodsId("").setUnitPrice(0).setQuantity(0));v3Request.setAppid("").setMchid("").setNotifyUrl("").setDescription("").setOutTradeNo("").setAmount(new WxPayUnifiedOrderV3Request.Amount() {}.setTotal(0)).setPayer(new WxPayUnifiedOrderV3Request.Payer() {}.setOpenid("")).setDetail(new WxPayUnifiedOrderV3Request.Discount() {}.setInvoiceId("").setGoodsDetails(goodsDetails)).setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo() {}.setStoreInfo(new WxPayUnifiedOrderV3Request.StoreInfo() {}.setId("")).setPayerClientIp(""));JsapiResult jsapiResult = null;try {jsapiResult = this.wxPayService.createOrderV3(TradeTypeEnum.valueOf("JSAPI"), v3Request);} catch (WxPayException e) {e.printStackTrace();log.info("JSAPI 下单:{}",e.getLocalizedMessage());}return jsapiResult;}

4. 页面支付成功,回调

@ 页面支付成功,查询微信后台订单状态,更新商户平台订单状态

/*** 微信查询订单,参数两者使用其一** @param orderNo 商户订单号* @param transactionId 微信交易流水号* @return Result*/public Result<?> wxQueryPay(String orderNo, String transactionId) {WxPayOrderQueryV3Result v3Result = null;try {v3Result = this.wxPayService.queryOrderV3(transactionId, orderNo);} catch (WxPayException e) {log.error("查询微信后台订单失败:{}", e.getMessage());return Result.restResult(6001, e.getMessage(), null);}// 根据业务需要,更新商户平台订单状态if(v3Result.getPayState.equels("SUCCES")){// 业务需求}return Result.ok();}

@ 页面支付成功回调问题

5. notify_url,回调

@ 解决,

页面支付成功调用API列表-----查询订单,更新生成预订单时提供的notify_url,微信后台判定订单支付成功,主动发起访问商户平台采用定时任务,轮询商户订单未支付订单,调用查询订单,更新(本文未提供)

/*** 获取回调请求头:签名相关** @param request HttpServletRequest* @return SignatureHeader*/public SignatureHeader getRequestHeader(HttpServletRequest request) {// 获取通知签名String signature = request.getHeader("wechatpay-signature");String nonce = request.getHeader("wechatpay-nonce");String serial = request.getHeader("wechatpay-serial");String timestamp = request.getHeader("wechatpay-timestamp");SignatureHeader signatureHeader = new SignatureHeader();signatureHeader.setSignature(signature);signatureHeader.setNonce(nonce);signatureHeader.setSerial(serial);signatureHeader.setTimeStamp(timestamp);return signatureHeader;}

/*** 微信支付回调** @param jsonData String* @param request HttpServletRequest* @param response HttpServletResponse* @return JSONObject*/@PostMapping("/wxNotifyUrl")public JSONObject wxNotifyUrl(@RequestBody String jsonData, HttpServletRequest request, HttpServletResponse response) {JSONObject wxPayResult = new JSONObject();if (lock.tryLock()) {// 支付成功结果通知OriginNotifyResponse notifyResponse = JSONUtil.toBean(jsonData, OriginNotifyResponse.class);WxPayOrderNotifyV3Result v3Result = null;try {v3Result=wxPayService.parseOrderNotifyV3Result(this.jsonStrSort(notifyResponse),this.getRequestHeader(request));//解密后的数据WxPayOrderNotifyV3Result.DecryptNotifyResult result = v3Result.getResult();// 注意:微信会通知多次,因此需判断此订单LambdaQueryWrapper<WxPayOrder> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(wxPayOrder::getOutTradeNo, result.getOutTradeNo());WxPayOrder wxPayOrder = this.wxPayOrderMapper.selectOne(queryWrapper);// 0:未支付,1:已支付if(wxPayOrder.getPayState == 0){//根据业务需要,更新商户平台订单状态}//通知应答:接收成功:HTTP应答状态码需返回200或204,无需返回应答报文。response.setStatus(HttpServletResponse.SC_OK);return null;} catch (WxPayException e) {e.printStackTrace();log.error("支付回调失败:{}", e.getLocalizedMessage());// 通知应答:HTTP应答状态码需返回5XX或4XX,同时需返回应答报文response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);wxPayResult.putOpt("code", "FAIL");wxPayResult.putOpt("message", "失败");return wxPayResult;} finally {lock.unlock();}}// 通知应答码:HTTP应答状态码需返回5XX或4XX,同时需返回应答报文response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);wxPayResult.putOpt("code", "FAIL");wxPayResult.putOpt("message", "失败");return wxPayResult;}

@ 从图上所说,有点模糊,翻译过来:就是需要按照API列表中所示的顺序,排序才能正确验签。,但实际body中接收到jsonData的顺序不是如下图所示,因此需重新排序。

@最简陋的方式排序。

/*** 请求报文:按官方接口示例键值 --- 排序(必须)* 官方文档:https://pay./wiki/doc/apiv3/apis/chapter3_1_5.shtml,* https://pay./wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml* 《微信支付API v3签名验证》 中注意:应答主体(response Body),需要按照接口返回的顺序进行验签,错误的顺序将导致验签失败。** @param originNotifyResponse OriginNotifyResponse* @return String*/private String jsonStrSort(OriginNotifyResponse originNotifyResponse) {Map<String, Object> jsonSort = new LinkedHashMap<>();jsonSort.put("id", originNotifyResponse.getId());jsonSort.put("create_time", originNotifyResponse.getCreateTime());jsonSort.put("resource_type", originNotifyResponse.getResourceType());jsonSort.put("event_type", originNotifyResponse.getEventType());jsonSort.put("summary", originNotifyResponse.getSummary());Map<String, Object> resource = new LinkedHashMap();resource.put("original_type", originNotifyResponse.getResource().getOriginalType());resource.put("algorithm", originNotifyResponse.getResource().getAlgorithm());resource.put("ciphertext", originNotifyResponse.getResource().getCiphertext());resource.put("associated_data", originNotifyResponse.getResource().getAssociatedData());resource.put("nonce", originNotifyResponse.getResource().getNonce());jsonSort.put("resource", resource);return JSONUtil.toJsonStr(jsonSort);}

三、随笔而已

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。