利用微信支付须要先开通做事号,然后还要开通微信支付,末了还要配置一些开拓参数,过程比较多。
申请做事号(企业)开通微信支付开拓配置 详细准备事情请参考Spring Boot入门教程(三十九):微信支付集成-申请做事号和微信支付二:支付办法刷卡支付(MICROPAY) :刷卡支付是用户展示微信钱包内的“刷卡条码/二维码”给商户系统扫描后直接完成支付的模式。紧张运用线下面对面收银的场景。相称于支付宝的条码支付扫码支付:扫码支付是商户系统按微信支付协议天生支付二维码,用户再用微信“扫一扫”完成支付的模式。该模式适用于PC网站支付、实体店单品或订单支付、媒体广告支付等场景。相称于支付宝的电脑网站支付H5支付:H5支付是指商户在微信客户端外的移动端网页展示商品或做事,用户在前述页面确认利用微信支付时,商户发起本做事呼起微信客户端进行支付。紧张用于触屏版的手机浏览器要求微信支付的场景。可以方便的从外部浏览器唤起微信支付。相称于支付宝的手机网站支付"大众年夜众号支付(JSAPI):商户已有H5商城网站,用户通过或扫描二维码在微信内打开网页时,可以调用微信支付完成下单购买的流程。App支付:APP支付又称移动端支付,是商户通过在移动端运用APP中集成开放SDK调起微信支付模块完成支付的模式。小程序支付:在小程序中利用H5支付: 是运用在微信客户端外,是一种WAP支付。 "大众年夜众号支付(JSAPI): 是运用在微信内的一种支付。 两种办法的运用处景不一样。
三:刷卡支付场景先容
1. 场景先容步骤1:用户选择刷卡支付付款并打开微信,进入“我”->“钱包”->“收付款”条码界面;步骤2:收银员在商户系统操作天生支付订单,用户确认支付金额;步骤3:商户收银员用扫码设备扫描用户的条码/二维码,商户收银系统提交支付;步骤4:微信支付后台系统收到支付要求,根据验证密码规则判断是否验证用户的支付密码,不须要验证密码的交易直接发起扣款,须要验证密码的交易会弹出密码输入框。支付成功后微信端会弹出成功页面,支付失落败会弹出错误提示。2. 验证密码规则:支付金额>1000元的交易须要验证用户支付密码用户账号每天最多有5笔交易可以免密,超过后须要验证密码微信支付后台判断用户支付行为有非常情形,符合免密规则的交易也会哀求验证密码3. 免密支付流程:
(1)收银员在商户收银台天生支付订单,向用户展示支付金额;
(2)用户打开微信客户端,点击“我的钱包”,选择“刷卡”,进入条码界面;
(3)收银员利用扫码设备读取用户手机屏幕上的条码;
(4)扫码设备将读取的信息上传给门店收银台;
(5)门店收银台得到支付信息后,向商户收银后台发起支付要求。
(6)商户后台对门店收银台的支付要求进行处理,天生署名后调用【提交刷卡支付API】向微信支付系统发起支付要求。
(7)微信支付系统得到商户侧的支付要求之后会对要求进行验证,验证通过之后会对要求数据进行处理,末了将处理后的支付结果返回给商户收银后台。如果支付成功,微信支付系统会将支付结果返回给商户,同时把支付结果关照给用户(以短信、微信的形式关照)。
(8)商户收银后台对得到的支付结果进行署名验证和处理,再将支付结果返回给门店收银台。
(9)收银员看到门店收银台的支付结果后给用户发货。
4. 验密支付流程验密支付流程文档
在商户调用【提交刷卡支付API】发起支付要求之后,微信支付后台提示用户输入密码确认支付,接口同步返回USERPAYING状态,商户系统再轮询调用查询订单接口来确认当前用户是否已经支付成功。
以下时序图解释验密支付流程:
由于在商户收银后台向微信支付系统发起支付要求之前的流程是完备一样的,以是这里只先容商户发起支付要求之后的逻辑。
(1)商户门店天生订单后,收银台向后台系统发起支付要求。
(2)后台调用微信支付【提交刷卡支付API】天生支付交易。
(3)微信支付系统对商户要求进行验证,验证通过后判断当前用户须要输入密码。
(4)微信支付系统返回USERPAYING状态,商户后台系统将应答结果返回给商户门店收银台。
(5)微信支付系统关照用户微信客户端输入密码。
(6)用户得到输入密码提示后,确认支付并输入密码。
(7)完成密码输入,提交微信支付。
(8)微信客户端在用户完成支付后提示微信支付后台系统返回的支付结果,而且微信支付系统会通过短信、微信给用户发送支付结果提醒。
(9)商户收银台得到USERPAYING状态后,经由商户后台系统调用【查询订单API】查询实际支付结果。
(10)如果支付结果仍为USERPAYING,则每隔5秒循环调用【查询订单API】判断实际支付结果,如果用户取消支付或累计30秒用户都未支付,商户收银台退出查询流程后连续调用【撤销订单API】撤销支付交易。
5. 非常处理用户碰着支付非常,请按如下解释处理
(1)用户微信端弹出系统缺点提示框,用户可在交易列表查看交易情形,如果未找到订单,须要商户重新发起支付交易;如果订单显示成功支付,商户收银系统再次调用【查询订单API】查询实际支付结果;
(2)用户微信端弹出支付失落败提示,例如:余额不敷,信用卡失落效。须要重新发起支付;
(3)当交易超时或支付交易失落败,商户收银系统必须调用【撤销订单API】,撤销今生意营业。
(4)由于银行系统非常、用户余额不敷、不支持用户卡种等缘故原由使当前支付交易失落败,商户收银系统该当把缺点提示明确展示给收银员。
(5)根据返回的缺点码,判断是否须要撤销交易,详细详见API返回缺点码列表
public Map<String, String> microPayWithPos(Map<String, String> reqData) throws Exception { return this.microPayWithPos(reqData, this.config.getHttpConnectTimeoutMs());}/ 提交刷卡支付,针对软POS,尽可能做成功 内置重试机制,最多60s @param reqData @param connectTimeoutMs @return @throws Exception /public Map<String, String> microPayWithPos(Map<String, String> reqData, int connectTimeoutMs) throws Exception { int remainingTimeMs = 601000; long startTimestampMs = 0; Map<String, String> lastResult = null; Exception lastException = null; while (true) { startTimestampMs = WXPayUtil.getCurrentTimestampMs(); int readTimeoutMs = remainingTimeMs - connectTimeoutMs; if (readTimeoutMs > 1000) { try { lastResult = this.microPay(reqData, connectTimeoutMs, readTimeoutMs); String returnCode = lastResult.get("return_code"); if (returnCode.equals("SUCCESS")) { String resultCode = lastResult.get("result_code"); String errCode = lastResult.get("err_code"); if (resultCode.equals("SUCCESS")) { break; } else { // 看缺点码,若支付结果未知,则重试提交刷卡支付 if (errCode.equals("SYSTEMERROR") || errCode.equals("BANKERROR") || errCode.equals("USERPAYING")) { remainingTimeMs = remainingTimeMs - (int)(WXPayUtil.getCurrentTimestampMs() - startTimestampMs); if (remainingTimeMs <= 100) { break; } else { WXPayUtil.getLogger().info("microPayWithPos: try micropay again"); if (remainingTimeMs > 51000) { Thread.sleep(51000); } else { Thread.sleep(11000); } continue; } } else { break; } } } else { break; } } catch (Exception ex) { lastResult = null; lastException = ex; } } else { break; } } if (lastResult == null) { throw lastException; } else { return lastResult; }}
看Demo中的方法,全体方法也没有查询订单,也没有撤销订单的操作,而是一直的重复调用microPay,这和上面文档的(9)、(10)条逻辑不一样
把稳:微信的刷卡支付并没有支付关照接口,只有退款关照接口;支付宝的条码支付是有支付关照接口的,两家是不一样的。四:开拓文档在集成之前,一定要熟习业务,熟习文档
微信支付开拓文档
刷卡文档,开拓前请详细认证的看完该文档。
刷卡支付流程图 必须看
刷卡文档中有demo,SDK与DEMO下载,须要下载下来,熟习一下项目构造,以及READEME.md
五:集成步骤1. 引入SDKwxpay-sdk 项目中的src便是要引入的sdk,可以直接将src的所有7个源文件拖入到自己项目中wxpay-sdk 的READEME.md中说可以通过maven来引入sdk现在有两种办法,选择个中一种,究竟选哪一种?
wxpay-sdk的src下面有7个java文件,通过maven引入可以看到的sdk中就4个java文件,两种办法文件个数不一致,多出来的3个文件是demo中用到的文件,并不是原始sdk中的文件,通过查看sdk中的源码可以看到,这4个文件实在便是利用httpclient来调用微信支付的支付接口,个中很多主要的逻辑并没有按照官方文档中说的那样短缺主要的逻辑实现,这个须要自己去完善一些逻辑
开拓中创造WXPay这个类和maven中的类并不完备一样,多了两个方法microPayWithPos,个中这两个方法是demo作者自己基于内部方法microPay的一个封装,完善了部分逻辑, 但是完善的逻辑和官网文档的描述不一致,有重大逻辑问题
查看demo中的test创造竟然有一个类叫test,命名不清晰,语义太笼统,而且还是小写字母开头,不符合Java的基本命名规范,关于java中的测试的命名规则一样平常类名以Test作为后缀,而该demo以Test作为前缀,一样平常测试类方法的命名以test作为前缀,但是demo中的测试并没有什么test,一样平常测试类都要利用测试框架如Junit等,但是demo中的测试并没有利用测试框架,而是利用main方法来运行的。
对wxpay-sdk的评价:wxpay-sdk只是利用httpclient来调用微信支付的接口,只管调用微信支付接口,然后解析一下相应,并不处理支付中的业务逻辑,只管一些和支付密切干系的主要逻辑也不会处理,乃至解密的工具方法都没有现成的,须要开拓者自己去处理。看demo可以知道,写的不是一样平常的烂,没想到微信那么大的厂竟然sdk写的这么
骂完了,还是要集成的,这里我选择不相信demo的源文件,利用README.md中的maven来引入sdk,一个是demo写的太烂,多出来的文件也不是不要弗成的,多出来的方法有重大逻辑毛病,万一哪天微信哪天良心创造完善sdk了,更新了maven版本,自己只须要修正一下maven的版本号就行了。
<dependency> <groupId>com.github.wxpay</groupId> <artifactId>wxpay-sdk</artifactId> <version>0.0.3</version></dependency>
2. application.yml
配置微信支付参数,个中appID、mchID、key、certPath是必须的,notifyUrl是可选的,sandboxKey和useSandbox是自己配置的,便于正式环境和沙箱环境的切换,关于参数的值去微信的开拓配置中查看
useSandbox:true表示利用沙箱环境,如果为false为正式环境sandboxKey: 沙箱环境API秘钥,须要通过下面的WXPayClient#getSignKey方法获取pay: wxpay: appID: xxx mchID: xxx key: xxx sandboxKey: xxx certPath: /var/local/cert/apiclient_cert.p12 notifyUrl: http://65ta5j.natappfree.cc/wxpay/refund/notify useSandbox: false
3. MyWXPayConfig
配置微信参数,实在便是一种Properties类,须要实现WXPayConfig中的方法 把稳:demo中的WXPayConfig是一种抽象类abstract class,可以看到maven与demo的分歧一
/ 微信支付的参数配置 @author mengday zhang /@Data@Slf4j@ConfigurationProperties(prefix = "pay.wxpay")public class MyWXPayConfig implements WXPayConfig { / "大众账号ID / private String appID; / 商户号 / private String mchID; / API 密钥 / private String key; / API 沙箱环境密钥 / private String sandboxKey; / API证书绝对路径 / private String certPath; / 退款异步关照地址 / private String notifyUrl; private Boolean useSandbox; / HTTP(S) 连接超时时间,单位毫秒 / private int httpConnectTimeoutMs = 8000; / HTTP(S) 读数据超时时间,单位毫秒 / private int httpReadTimeoutMs = 10000; / 获取商户证书内容 @return 商户证书内容 / @Override public InputStream getCertStream() { File certFile = new File(certPath); InputStream inputStream = null; try { inputStream = new FileInputStream(certFile); } catch (FileNotFoundException e) { log.error("cert file not found, path={}, exception is:{}", certPath, e); } return inputStream; } @Override public String getKey(){ if (useSandbox) { return sandboxKey; } return key; }}
WXPayClient 是对WXPay的一个封装,增加了microPayWithPOS方法,内部调用WXPay#microPay,但是sdk中的microPay并没有处理当微信支付时微信提示用户输入密码,这时sdk直接返回的缺点,这里处理的逻辑便是在指定时间内去轮询支付结果,然后将轮询的结果返回出去,而不是就直接返回缺点了,demo项目也有个microPayWithPOS实现,但是它的逻辑是当用户输入密码的情形会轮询的去下单去调用WXPay#microPay,这种做法是不符合微信的官方文档的。其余增加了获取沙箱环境API秘钥和解密退换关照的方法。
吐槽一下:觉得像这种解密方法WXPayUtil中竟然没有,这是必须的不可少的啊,怎么会没有呢,这也太烂了吧,这还称为sdk啊
/ WXPayClient <p> 对WXPay的大略封装,处理支付密切干系的逻辑. @author Mengday Zhang @version 1.0 @since 2018/6/16 /@Slf4jpublic class WXPayClient extends WXPay { / 密钥算法 / private static final String ALGORITHM = "AES"; / 加解密算法/事情模式/添补办法 / private static final String ALGORITHM_MODE_PADDING = "AES/ECB/PKCS5Padding"; / 用户支付中,须要输入密码 / private static final String ERR_CODE_USERPAYING = "USERPAYING"; private static final String ERR_CODE_AUTHCODEEXPIRE = "AUTHCODEEXPIRE"; / 交易状态: 未支付 / private static final String TRADE_STATE_NOTPAY = "NOTPAY"; / 用户输入密码,考试测验30秒内去查询支付结果 / private static Integer remainingTimeMs = 10000; private WXPayConfig config; public WXPayClient(WXPayConfig config, WXPayConstants.SignType signType, boolean useSandbox) { super(config, signType, useSandbox); this.config = config; } / 刷卡支付 对WXPay#microPay(Map)增加了当支付结果为USERPAYING时去轮询查询支付结果的逻辑处理 把稳:该方法没有处理return_code=FAIL的情形,暂时不考虑网络问题,这种情形直接返回缺点 @param reqData @return @throws Exception / public Map<String, String> microPayWithPOS(Map<String, String> reqData) throws Exception { // 开始韶光(毫秒) long startTimestampMs = System.currentTimeMillis(); Map<String, String> responseMapForPay = super.microPay(reqData); log.info(responseMapForPay.toString()); // // 先判断 协议字段返回(return_code),再判断 业务返回,末了判断 交易状态(trade_state) // 通信标识,非交易标识 String returnCode = responseMapForPay.get("return_code"); if (WXPayConstants.SUCCESS.equals(returnCode)) { String errCode = responseMapForPay.get("err_code"); // 余额不敷,信用卡失落效 if (ERR_CODE_USERPAYING.equals(errCode) || "SYSTEMERROR".equals(errCode) || "BANKERROR".equals(errCode)) { Map<String, String> orderQueryMap = null; Map<String, String> requestData = new HashMap<>(); requestData.put("out_trade_no", reqData.get("out_trade_no")); // 用户支付中,须要输入密码或系统缺点则去重新查询订单API err_code, result_code, err_code_des // 每次循环时确当前系统韶光 - 开始时记录的韶光 > 设定的30秒韶光就退出 while (System.currentTimeMillis() - startTimestampMs < remainingTimeMs) { // 商户收银台得到USERPAYING状态后,经由商户后台系统调用【查询订单API】查询实际支付结果。 orderQueryMap = super.orderQuery(requestData); String returnCodeForQuery = orderQueryMap.get("return_code"); if (WXPayConstants.SUCCESS.equals(returnCodeForQuery)) { // 通讯成功 String tradeState = orderQueryMap.get("trade_state"); if (WXPayConstants.SUCCESS.equals(tradeState)) { // 如果成功了直接将查询结果返回 return orderQueryMap; } // 如果支付结果仍为USERPAYING,则每隔5秒循环调用【查询订单API】判断实际支付结果 Thread.sleep(1000); } } // 如果用户取消支付或累计30秒用户都未支付,商户收银台退出查询流程后连续调用【撤销订单API】撤销支付交易。 String tradeState = orderQueryMap.get("trade_state"); if (TRADE_STATE_NOTPAY.equals(tradeState) || ERR_CODE_USERPAYING.equals(tradeState) || ERR_CODE_AUTHCODEEXPIRE.equals(tradeState)) { Map<String, String> reverseMap = this.reverse(requestData); String returnCodeForReverse = reverseMap.get("return_code"); String resultCode = reverseMap.get("result_code"); if (WXPayConstants.SUCCESS.equals(returnCodeForReverse) && WXPayConstants.SUCCESS.equals(resultCode)) { // 如果撤销成功,须要见告客户端已经撤销订单了 responseMapForPay.put("err_code_des", "用户取消支付或尚未支付,后台已经撤销该订单,请重新支付!
5. WXPayConfiguration
"); } } } } return responseMapForPay; } / 解密退款关照 <a href="https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_16&index=11>退款结果关照文档</a> @param reqInfo @return @throws Exception / public Map<String, String> decodeRefundNotify(String reqInfo) throws Exception { //(1)对加密串A做base64解码,得到加密串B byte[] bytes = new BASE64Decoder().decodeBuffer(reqInfo); //(2)对商户key做md5,得到32位小写key ( key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 ) Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING); SecretKeySpec key = new SecretKeySpec(WXPayUtil.MD5(config.getKey()).toLowerCase().getBytes(), ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, key); // (3)用key对加密串B做AES-256-ECB解密(PKCS7Padding) // java.security.InvalidKeyException: Illegal key size or default parameters // https://www.cnblogs.com/yaks/p/5608358.html String responseXml = new String(cipher.doFinal(bytes),"UTF-8"); Map<String, String> responseMap = WXPayUtil.xmlToMap(responseXml); return responseMap; } / 获取沙箱环境验签秘钥API <a href="https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=23_1">获取验签秘钥API文档</a> @return @throws Exception / public Map<String, String> getSignKey() throws Exception { Map<String, String> reqData = new HashMap<>(); reqData.put("appid", config.getAppID()); reqData.put("mch_id", config.getMchID()); reqData.put("nonce_str", WXPayUtil.generateNonceStr()); String sign = WXPayUtil.generateSignature(reqData, config.getKey(), WXPayConstants.SignType.MD5); reqData.put("sign", sign); String responseXml = this.requestWithoutCert("https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey", reqData, config.getHttpConnectTimeoutMs(), config.getHttpReadTimeoutMs()); Map<String, String> responseMap = WXPayUtil.xmlToMap(responseXml); return responseMap; }}
/ 微信支付配置 @author mengday zhang /@Configuration@EnableConfigurationProperties(MyWXPayConfig.class)public class WXPayConfiguration { @Autowired private MyWXPayConfig wxPayConfig; / useSandbox true为沙盒环境 @return / @Bean public WXPay wxPay() { return new WXPay(wxPayConfig, WXPayConstants.SignType.MD5, wxPayConfig.getUseSandbox() ); } @Bean public WXPayClient wxPayClient() { return new WXPayClient(wxPayConfig, WXPayConstants.SignType.MD5, wxPayConfig.getUseSandbox()); }}
6. WXPayMicroPayController
/ 微信支付-刷卡支付. <p> detailed description @author Mengday Zhang @version 1.0 @since 2018/6/18 /@Slf4j@RestController@RequestMapping("/wxpay/microPay")public class WXPayMicroPayController { @Autowired private WXPayClient wxPayClient; / 刷卡支付(类似支付宝的条码支付) 和支付宝的彷佛不一样,支付宝有支付关照,但是微信彷佛没,微信有退款关照 微信支付后台系统收到支付要求,根据验证密码规则判断是否验证用户的支付密码,不须要验证密码的交易直接发起扣款, 须要验证密码的交易会弹出密码输入框。支付成功后微信端会弹出成功页面,支付失落败会弹出错误提示 把稳该接口有可能返回缺点码为USERPAYING用户支付中 验证密码规则 ◆ 支付金额>1000元的交易须要验证用户支付密码 ◆ 用户账号每天最多有5笔交易可以免密,超过后须要验证密码 ◆ 微信支付后台判断用户支付行为有非常情形,符合免密规则的交易也会哀求验证密码 用户刷卡条形码规则:18位纯数字,以10、11、12、13、14、15开头 / @PostMapping("") public Object microPay(String authCode) throws Exception { Map<String, String> reqData = new HashMap<>(); // 商户订单号 reqData.put("out_trade_no", String.valueOf(System.nanoTime())); // 订单总金额,单位为分,只能为整数 reqData.put("total_fee", "2"); // 授权码 reqData.put("auth_code", authCode); // 商品描述 reqData.put("body", "测试"); Map<String, String> resultMap = wxPayClient.microPayWithPOS(reqData); log.info(resultMap.toString()); return resultMap; }}
7. WXPayController
/ 微信支付 - 通用API. <p> 类似支付宝中的条码支付. @author Mengday Zhang @version 1.0 @since 2018/6/15 /@Slf4j@RestController@RequestMapping("/wxpay")public class WXPayController { @Autowired private WXPay wxPay; @Autowired private WXPayClient wxPayClient; @Autowired private MyWXPayConfig wxPayConfig; / 订单查询 @param orderNo @return @throws Exception / @GetMapping("/orderQuery") public Object orderQuery(String orderNo) throws Exception { Map<String, String> data = new HashMap<>(); data.put("out_trade_no", orderNo); Map<String, String> result = wxPay.orderQuery(data); return result; } / 退款 把稳:调用申请退款、撤销订单接口须要商户证书 把稳:沙箱环境相应结果可能会是"沙箱支付金额禁绝确,请确认验收case",但是正式环境不会报这个缺点 微信支付的最小金额是0.1元,以是在测试支付时金额必须大于0.1元,否则会提示微信支付配置缺点,可以将microPay的total_fee大于1再退款 / @PostMapping("/refund") public Object refund(String orderNo) throws Exception { Map<String, String> reqData = new HashMap<>(); // 商户订单号 reqData.put("out_trade_no", orderNo); // 授权码 reqData.put("out_refund_no", orderNo); // 订单总金额,单位为分,只能为整数 reqData.put("total_fee", "2"); //退款金额 reqData.put("refund_fee", "2"); // 退款异步关照地址 reqData.put("notify_url", wxPayConfig.getNotifyUrl()); reqData.put("refund_fee_type", "CNY"); reqData.put("op_user_id", wxPayConfig.getMchID()); Map<String, String> resultMap = wxPay.refund(reqData); log.info(resultMap.toString()); return resultMap; } / 退款结果关照 特殊解释:退款结果对主要的数据进行了加密,商户须要用商户秘钥进行解密后才能得到结果关照的内容 @param request @throws Exception / @RequestMapping("/refund/notify") public String refundNotify(HttpServletRequest request) throws Exception {// Map<String, String> notifyMap = new HashMap<>();// notifyMap.put("nonce_str", "9b4e428ae262d5dca96178027e849fa9");// notifyMap.put("req_info", "VKGj8c81RwQ45LcyWEVBE9/HsNfADGbgmbIAQZ2ydcbIFhIIcJFKFQwGfcSGgFGtQlWvg6KDNsRjmCjN+PvipJ3roynJ7cME0LOFG50VGtk4EYHqdjFzUVANI7GpT+i6Ok+ZWivH0MwoGK2fsz3WG+bYs2XJBwav/K89tKjFhZGitCKKBeGqcP99fa/gAL0swNXXNQHmL806Zi+QcACzL3E89BtP9FlXM2Gi+wPQafvPr+/iE+LrPdMlNUa5LiZnenZXUF24kMdhaTafczcKL4sZjRXQHEfEyc/pIZPbIjcNIETvHsskyzKuHVr/SAFkxaM6RR1Kl9pyWZGUjkH5SOeqsT8uL7YQmTlDXrnXmno3AvZdnepTGL5w69yIOmQNPeMqsd01ES9WX36GZYOigfi2+BJ9RRXjIffmpB/MFF+zryyvLTaJE2obCwFSHrmOD8YbaJqrZXOUvWZQrn7wIQgaCypo8V57cD3w5d2RSgIHNrdnEDYlbRcLNYgKuL+T9+1HPhU/frowZgwPN9IB53OahZV3p1Yvos23kvhqPCLn3BYgUihRbey6QhEtL2QyifiQ9e8WVLzWpRZ+DOa8VrhYvSuTfjRdjoNanqHFvXGP6uEsEa+DETqnexpB7xOS9m/CdmlNCwbdUplPEVzNQQdzYT4kybi00Y8A+EdairxfVyK9A7MAYAMtAO9yxV2ht0bn3SofFyZe/YSzdJgxdtcxBf1CVYN6x+yHcSueCSgq4cM/2VCwh4J1+pUVmNpEm0OVcdKbV5USkaxJR0h7Yd+n5FTz5Q2S/qvyDo202cUzLFPI5UqQm5X+FOrWDAkmmr5yVcDQIm3dAdb31jkz0X2TPYt5g7ciQ1h9heyVxJ67FexKvEM4pKCCubtWx6nyxcOUghHMrh8DSoBtewtNjbnwGVIbLsSb6X9MIYAkWIDbqNVP1f63GiZU+cJlhBmvcb8aeQUdTTj7EX5pOTIVSVv5D6SkKmpGU4FGvV+WjufuGX4ZRZo+01p6xl0sfZVmucG1UtxhX6bMCJb06yDwxpv7tGwkwS4TCK4SQp40Xe0=");// notifyMap.put("appid", "xxx");// notifyMap.put("mch_id", "xxx");// notifyMap.put("return_code", "SUCCESS"); // 把稳:同样的关照可能会多次发送给商户系统。商户系统必须能够精确处理重复的关照。 // 推举的做法是,当收到关照进行处理时,首先检讨对应业务数据的状态,判断该关照是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。 // 在对业务数据进行状态检讨和处理之前,要采取数据锁进行并发掌握,以避免函数重入造成的数据混乱。 // TODO 处理业务 Map<String, String> requstInfoMap = wxPayClient.decodeRefundNotify(request); // 商户处理退款关照参数后同步返回给微信参数 Map<String, String> responseMap = new HashMap<>(); responseMap.put("return_code", "SUCCESS"); responseMap.put("return_msg", "OK"); String responseXml = WXPayUtil.mapToXml(responseMap); return responseXml; } / 退款查询 @param orderNo @return @throws Exception / @GetMapping("/refundQuery") public Object refundQuery(String orderNo) throws Exception { Map<String, String> reqData = new HashMap<>(); reqData.put("out_trade_no", orderNo); Map<String, String> result = wxPay.refundQuery(reqData); return result; } / 下载对账单 把稳: 微信在越日9点启动天生前一天的对账单,建议商户10点后再获取; 对账单接口只能下载三个月以内的账单。 @throws Exception / @PostMapping("/downloadBill") public Object downloadBill(String billDate) throws Exception { Map<String, String> reqData = new HashMap<>(); reqData.put("bill_date", billDate); reqData.put("bill_type", "ALL"); Map<String, String> resultMap = wxPay.downloadBill(reqData); return resultMap; } / 获取沙箱环境API秘钥, 这里只是为了获取,可以放在main方法下运行,这里作为api来运行的,实际情形下不应该暴露出来 @return @throws Exception / @GetMapping("/sandbox/getSignKey") public Object getSignKey() throws Exception { Map<String, String> signKey = wxPayClient.getSignKey(); log.info(signKey.toString()); return signKey; }}
获取源码
关注并私信“微信刷卡支付”获取源代码。