当前位置: 首页 > news >正文

SpringBoot整合weixin-java-pay实现微信小程序支付

 在做完一个仿美团的应用,我将其中涉及到的一些技术点进行总结和整理,当下次遇到类似的问题就能省下不少时间,避免踩坑。

一、微信小程序支付的使用

微信支付有官方提供的SDK,但要自己处理的东西比较多。我使用的是一个别人封装过的SDK GitHub - Wechat-Group/WxJava: 微信开发 Java SDK ,支持包括微信支付,开放平台,小程序,企业微信,视频号,公众号等的后端开发微信开发 Java SDK ,支持包括微信支付,开放平台,小程序,企业微信,视频号,公众号等的后端开发 - Wechat-Group/WxJavahttps://github.com/Wechat-Group/WxJava
要如何使用呢,首先引入依赖。

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

yml配置

logging:level:org.springframework.web: infocom.github.binarywang.demo.wx.pay: debugcom.github.binarywang.wxpay: debugwx:pay:appId: wx74862e0dfcf69954mchId: 1558950191mchKey: 34345964330B66427E0D3D28826C4993C77E631F
#    subAppId: #服务商模式下的子商户公众账号ID
#    subMchId: #服务商模式下的子商户号keyPath: apiclient_key.pem
配置类
  1. 参数配置类SwaggerConfig
package com.github.binarywang.demo.wx.pay.config;import lombok.extern.slf4j.Slf4j;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.StopWatch;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;import static springfox.documentation.builders.PathSelectors.regex;/*** <pre>* Swagger配置类* Created by Binary Wang on 2018/9/27.* </pre>** @author <a href="https://github.com/binarywang">Binary Wang</a>*/
@Configuration
@EnableSwagger2
@Slf4j
public class SwaggerConfig extends WebMvcConfigurationSupport implements EnvironmentAware {private Environment environment;@Overridepublic void setEnvironment(Environment environment) {this.environment = environment;}@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");super.addResourceHandlers(registry);}@Beanpublic Docket docket() {//最重要的就是这里,定义了/test/.*开头的rest接口都分在了test分组里,可以通过/v2/api-docs?group=test得到定义的jsonlog.info("Starting Swagger");StopWatch watch = new StopWatch();watch.start();Docket docket = new Docket(DocumentationType.SWAGGER_2).groupName("pay").apiInfo(this.apiInfo()).select().apis(RequestHandlerSelectors.any()).paths(regex("/pay/.*")).build();watch.stop();log.info("Started Swagger in {} ms", watch.getTotalTimeMillis());return docket;}private ApiInfo apiInfo() {return new ApiInfoBuilder().title("微信支付Demo").description("微信支付演示接口").contact(new Contact("Binary Wang", null, null)).license("Apache 2.0").licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html").version("1.0.0").build();}}
配置类WxPayConfiguration
package com.github.binarywang.demo.wx.pay.config;import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author Binary Wang*/
@Configuration
@ConditionalOnClass(WxPayService.class)
@EnableConfigurationProperties(WxPayProperties.class)
@AllArgsConstructor
public class WxPayConfiguration {private WxPayProperties properties;@Bean@ConditionalOnMissingBeanpublic WxPayService wxService() {WxPayConfig payConfig = new WxPayConfig();payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId()));payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));payConfig.setMchKey(StringUtils.trimToNull(this.properties.getMchKey()));payConfig.setSubAppId(StringUtils.trimToNull(this.properties.getSubAppId()));payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId()));payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath()));// 可以指定是否使用沙箱环境payConfig.setUseSandboxEnv(false);WxPayService wxPayService = new WxPayServiceImpl();wxPayService.setConfig(payConfig);return wxPayService;}}
配置类WxPayProperties
package com.github.binarywang.demo.wx.pay.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;/*** wxpay pay properties.** @author Binary Wang*/
@Data
@ConfigurationProperties(prefix = "wx.pay")
public class WxPayProperties {/*** 设置微信公众号或者小程序等的appid*/private String appId;/*** 微信支付商户号*/private String mchId;/*** 微信支付商户密钥*/private String mchKey;/*** 服务商模式下的子商户公众账号ID,普通模式请不要配置,请在配置文件中将对应项删除*/private String subAppId;/*** 服务商模式下的子商户号,普通模式请不要配置,最好是请在配置文件中将对应项删除*/private String subMchId;/*** apiclient_cert.p12文件的绝对路径,或者如果放在项目中,请以classpath:开头指定*/private String keyPath;}
企业付款相关接口
package com.github.binarywang.demo.wx.pay.controller;import com.github.binarywang.wxpay.bean.entpay.*;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;/*** <pre>* 企业付款相关接口* Created by Binary Wang on 2018/9/27.* </pre>** @author <a href="https://github.com/binarywang">Binary Wang</a>*/
@Api("企业付款")
@RequestMapping("/pay")
@RestController
@AllArgsConstructor
public class EntPayController {private final WxPayService wxService;/*** <pre>* 企业付款业务是基于微信支付商户平台的资金管理能力,为了协助商户方便地实现企业向个人付款,针对部分有开发能力的商户,提供通过API完成企业付款的功能。* 比如目前的保险行业向客户退保、给付、理赔。* 企业付款将使用商户的可用余额,需确保可用余额充足。查看可用余额、充值、提现请登录商户平台“资金管理”https://pay.weixin.qq.com/进行操作。* 注意:与商户微信支付收款资金并非同一账户,需要单独充值。* 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2* 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers* </pre>** @param request 请求对象*/@ApiOperation(value = "企业付款到零钱")@PostMapping("/entPay")public EntPayResult entPay(@RequestBody EntPayRequest request) throws WxPayException {return this.wxService.getEntPayService().entPay(request);}/*** <pre>* 查询企业付款API* 用于商户的企业付款操作进行结果查询,返回付款操作详细结果。* 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3* 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo* </pre>** @param partnerTradeNo 商户订单号*/@ApiOperation(value = "查询企业付款到零钱的结果")@GetMapping("/queryEntPay/{partnerTradeNo}")public EntPayQueryResult queryEntPay(@PathVariable String partnerTradeNo) throws WxPayException {return this.wxService.getEntPayService().queryEntPay(partnerTradeNo);}/*** <pre>* 获取RSA加密公钥API.* RSA算法使用说明(非对称加密算法,算法采用RSA/ECB/OAEPPadding模式)* 1、 调用获取RSA公钥API获取RSA公钥,落地成本地文件,假设为public.pem* 2、 确定public.pem文件的存放路径,同时修改代码中文件的输入路径,加载RSA公钥* 3、 用标准的RSA加密库对敏感信息进行加密,选择RSA_PKCS1_OAEP_PADDING填充模式* (eg:Java的填充方式要选 " RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING")* 4、 得到进行rsa加密并转base64之后的密文* 5、 将密文传给微信侧相应字段,如付款接口(enc_bank_no/enc_true_name)** 接口默认输出PKCS#1格式的公钥,商户需根据自己开发的语言选择公钥格式* 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_7&index=4* 接口链接:https://fraud.mch.weixin.qq.com/risk/getpublickey* </pre>** @return the public key* @throws WxPayException the wx pay exception*/@ApiOperation(value = "获取RSA加密公钥")@GetMapping("/getPublicKey")public String getPublicKey() throws WxPayException {return this.wxService.getEntPayService().getPublicKey();}/*** 企业付款到银行卡.* <pre>* 用于企业向微信用户银行卡付款* 目前支持接口API的方式向指定微信用户的银行卡付款。* 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_2* 接口链接:https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank* </pre>** @param request 请求对象* @return the ent pay bank result* @throws WxPayException the wx pay exception*/@ApiOperation(value = "企业付款到银行卡")@PostMapping("/payBank")public EntPayBankResult payBank(EntPayBankRequest request) throws WxPayException {return this.wxService.getEntPayService().payBank(request);}/*** 企业付款到银行卡查询.* <pre>* 用于对商户企业付款到银行卡操作进行结果查询,返回付款操作详细结果。* 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_3* 接口链接:https://api.mch.weixin.qq.com/mmpaysptrans/query_bank* </pre>** @param partnerTradeNo 商户订单号* @return the ent pay bank query result* @throws WxPayException the wx pay exception*/@ApiOperation(value = "查询企业付款到银行卡的结果")@GetMapping("/queryPayBank/{partnerTradeNo}")public EntPayBankQueryResult queryPayBank(@PathVariable String partnerTradeNo) throws WxPayException {return this.wxService.getEntPayService().queryPayBank(partnerTradeNo);}}
package com.github.binarywang.demo.wx.pay.controller;import com.github.binarywang.wxpay.bean.coupon.*;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxScanPayNotifyResult;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;import java.io.File;
import java.util.Date;/*** @author Binary Wang*/
@Api("微信支付")
@RestController
@RequestMapping("/pay")
@AllArgsConstructor
public class WxPayController {private WxPayService wxService;/*** <pre>* 查询订单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2)* 该接口提供所有微信支付订单的查询,商户可以通过查询订单接口主动查询订单状态,完成下一步的业务逻辑。* 需要调用查询接口的情况:* ◆ 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知;* ◆ 调用支付接口后,返回系统错误或未知交易状态情况;* ◆ 调用被扫支付API,返回USERPAYING的状态;* ◆ 调用关单或撤销接口API之前,需确认支付状态;* 接口地址:https://api.mch.weixin.qq.com/pay/orderquery* </pre>** @param transactionId 微信订单号* @param outTradeNo    商户系统内部的订单号,当没提供transactionId时需要传这个。*/@ApiOperation(value = "查询订单")@GetMapping("/queryOrder")public WxPayOrderQueryResult queryOrder(@RequestParam(required = false) String transactionId,@RequestParam(required = false) String outTradeNo)throws WxPayException {return this.wxService.queryOrder(transactionId, outTradeNo);}@ApiOperation(value = "查询订单")@PostMapping("/queryOrder")public WxPayOrderQueryResult queryOrder(@RequestBody WxPayOrderQueryRequest wxPayOrderQueryRequest) throws WxPayException {return this.wxService.queryOrder(wxPayOrderQueryRequest);}/*** <pre>* 关闭订单* 应用场景* 以下情况需要调用关单接口:* 1. 商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;* 2. 系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。* 注意:订单生成后不能马上调用关单接口,最短调用时间间隔为5分钟。* 接口地址:https://api.mch.weixin.qq.com/pay/closeorder* 是否需要证书:   不需要。* </pre>** @param outTradeNo 商户系统内部的订单号*/@ApiOperation(value = "关闭订单")@GetMapping("/closeOrder/{outTradeNo}")public WxPayOrderCloseResult closeOrder(@PathVariable String outTradeNo) throws WxPayException {return this.wxService.closeOrder(outTradeNo);}@ApiOperation(value = "关闭订单")@PostMapping("/closeOrder")public WxPayOrderCloseResult closeOrder(@RequestBody WxPayOrderCloseRequest wxPayOrderCloseRequest) throws WxPayException {return this.wxService.closeOrder(wxPayOrderCloseRequest);}/*** 调用统一下单接口,并组装生成支付所需参数对象.** @param request 统一下单请求参数* @param <T>     请使用{@link com.github.binarywang.wxpay.bean.order}包下的类* @return 返回 {@link com.github.binarywang.wxpay.bean.order}包下的类对象*/@ApiOperation(value = "统一下单,并组装所需支付参数")@PostMapping("/createOrder")public <T> T createOrder(@RequestBody WxPayUnifiedOrderRequest request) throws WxPayException {return this.wxService.createOrder(request);}/*** 统一下单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)* 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"* 接口地址:https://api.mch.weixin.qq.com/pay/unifiedorder** @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置)*/@ApiOperation(value = "原生的统一下单接口")@PostMapping("/unifiedOrder")public WxPayUnifiedOrderResult unifiedOrder(@RequestBody WxPayUnifiedOrderRequest request) throws WxPayException {return this.wxService.unifiedOrder(request);}/*** <pre>* 微信支付-申请退款* 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4* 接口链接:https://api.mch.weixin.qq.com/secapi/pay/refund* </pre>** @param request 请求对象* @return 退款操作结果*/@ApiOperation(value = "退款")@PostMapping("/refund")public WxPayRefundResult refund(@RequestBody WxPayRefundRequest request) throws WxPayException {return this.wxService.refund(request);}/*** <pre>* 微信支付-查询退款* 应用场景:*  提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,用零钱支付的退款20分钟内到账,*  银行卡支付的退款3个工作日后重新查询退款状态。* 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5* 接口链接:https://api.mch.weixin.qq.com/pay/refundquery* </pre>* 以下四个参数四选一** @param transactionId 微信订单号* @param outTradeNo    商户订单号* @param outRefundNo   商户退款单号* @param refundId      微信退款单号* @return 退款信息*/@ApiOperation(value = "退款查询")@GetMapping("/refundQuery")public WxPayRefundQueryResult refundQuery(@RequestParam(required = false) String transactionId,@RequestParam(required = false) String outTradeNo,@RequestParam(required = false) String outRefundNo,@RequestParam(required = false) String refundId)throws WxPayException {return this.wxService.refundQuery(transactionId, outTradeNo, outRefundNo, refundId);}@ApiOperation(value = "退款查询")@PostMapping("/refundQuery")public WxPayRefundQueryResult refundQuery(@RequestBody WxPayRefundQueryRequest wxPayRefundQueryRequest) throws WxPayException {return this.wxService.refundQuery(wxPayRefundQueryRequest);}@ApiOperation(value = "支付回调通知处理")@PostMapping("/notify/order")public String parseOrderNotifyResult(@RequestBody String xmlData) throws WxPayException {final WxPayOrderNotifyResult notifyResult = this.wxService.parseOrderNotifyResult(xmlData);// TODO 根据自己业务场景需要构造返回对象return WxPayNotifyResponse.success("成功");}@ApiOperation(value = "退款回调通知处理")@PostMapping("/notify/refund")public String parseRefundNotifyResult(@RequestBody String xmlData) throws WxPayException {final WxPayRefundNotifyResult result = this.wxService.parseRefundNotifyResult(xmlData);// TODO 根据自己业务场景需要构造返回对象return WxPayNotifyResponse.success("成功");}@ApiOperation(value = "扫码支付回调通知处理")@PostMapping("/notify/scanpay")public String parseScanPayNotifyResult(String xmlData) throws WxPayException {final WxScanPayNotifyResult result = this.wxService.parseScanPayNotifyResult(xmlData);// TODO 根据自己业务场景需要构造返回对象return WxPayNotifyResponse.success("成功");}/*** 发送微信红包给个人用户* <pre>* 文档详见:* 发送普通红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3*  接口地址:https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack* 发送裂变红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5&index=4*  接口地址:https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack* </pre>** @param request 请求对象*/@ApiOperation(value = "发送红包")@PostMapping("/sendRedpack")public WxPaySendRedpackResult sendRedpack(@RequestBody WxPaySendRedpackRequest request) throws WxPayException {return this.wxService.getRedpackService().sendRedpack(request);}/*** <pre>*   查询红包记录*   用于商户对已发放的红包进行查询红包的具体信息,可支持普通红包和裂变包。*   请求Url	https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo*   是否需要证书	是(证书及使用说明详见商户证书)*   请求方式	POST* </pre>** @param mchBillNo 商户发放红包的商户订单号,比如10000098201411111234567890*/@ApiOperation(value = "查询红包")@GetMapping("/queryRedpack/{mchBillNo}")public WxPayRedpackQueryResult queryRedpack(@PathVariable String mchBillNo) throws WxPayException {return this.wxService.getRedpackService().queryRedpack(mchBillNo);}/*** <pre>* 扫码支付模式一生成二维码的方法* 二维码中的内容为链接,形式为:* weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX* 其中XXXXX为商户需要填写的内容,商户将该链接生成二维码,如需要打印发布二维码,需要采用此格式。商户可调用第三方库生成二维码图片。* 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4* </pre>** @param productId  产品Id* @param logoFile   商户logo图片的文件对象,可以为空* @param sideLength 要生成的二维码的边长,如果为空,则取默认值400* @return 生成的二维码的字节数组*/public byte[] createScanPayQrcodeMode1(String productId, File logoFile, Integer sideLength) throws Exception {return this.wxService.createScanPayQrcodeMode1(productId, logoFile, sideLength);}/*** <pre>* 扫码支付模式一生成二维码的方法* 二维码中的内容为链接,形式为:* weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX* 其中XXXXX为商户需要填写的内容,商户将该链接生成二维码,如需要打印发布二维码,需要采用此格式。商户可调用第三方库生成二维码图片。* 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4* </pre>** @param productId 产品Id* @return 生成的二维码URL连接*/public String createScanPayQrcodeMode1(String productId) {return this.wxService.createScanPayQrcodeMode1(productId);}/*** <pre>* 扫码支付模式二生成二维码的方法* 对应链接格式:weixin://wxpay/bizpayurl?sr=XXXXX。请商户调用第三方库将code_url生成二维码图片。* 该模式链接较短,生成的二维码打印到结账小票上的识别率较高。* 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5* </pre>** @param codeUrl    微信返回的交易会话的二维码链接* @param logoFile   商户logo图片的文件对象,可以为空* @param sideLength 要生成的二维码的边长,如果为空,则取默认值400* @return 生成的二维码的字节数组*/public byte[] createScanPayQrcodeMode2(String codeUrl, File logoFile, Integer sideLength) throws Exception {return this.wxService.createScanPayQrcodeMode2(codeUrl, logoFile, sideLength);}/*** <pre>* 交易保障* 应用场景:*  商户在调用微信支付提供的相关接口时,会得到微信支付返回的相关信息以及获得整个接口的响应时间。*  为提高整体的服务水平,协助商户一起提高服务质量,微信支付提供了相关接口调用耗时和返回信息的主动上报接口,*  微信支付可以根据商户侧上报的数据进一步优化网络部署,完善服务监控,和商户更好的协作为用户提供更好的业务体验。* 接口地址: https://api.mch.weixin.qq.com/payitil/report* 是否需要证书:不需要* </pre>*/@ApiOperation(value = "提交交易保障数据")@PostMapping("/report")public void report(@RequestBody WxPayReportRequest request) throws WxPayException {this.wxService.report(request);}/*** <pre>* 下载对账单* 商户可以通过该接口下载历史交易清单。比如掉单、系统错误等导致商户侧和微信侧数据不一致,通过对账单核对后可校正支付状态。* 注意:* 1、微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账单中,跟原支付单订单号一致,bill_type为REVOKED;* 2、微信在次日9点启动生成前一天的对账单,建议商户10点后再获取;* 3、对账单中涉及金额的字段单位为“元”。* 4、对账单接口只能下载三个月以内的账单。* 接口链接:https://api.mch.weixin.qq.com/pay/downloadbill* 详情请见: <a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6">下载对账单</a>* </pre>** @param billDate   对账单日期 bill_date	下载对账单的日期,格式:20140603* @param billType   账单类型	bill_type	ALL,返回当日所有订单信息,默认值,SUCCESS,返回当日成功支付的订单,REFUND,返回当日退款订单* @param tarType    压缩账单	tar_type	非必传参数,固定值:GZIP,返回格式为.gzip的压缩包账单。不传则默认为数据流形式。* @param deviceInfo 设备号	device_info	非必传参数,终端设备号* @return 保存到本地的临时文件*/@ApiOperation(value = "下载对账单")@GetMapping("/downloadBill/{billDate}/{billType}/{tarType}/{deviceInfo}")public WxPayBillResult downloadBill(@PathVariable String billDate, @PathVariable String billType,@PathVariable String tarType, @PathVariable String deviceInfo) throws WxPayException {return this.wxService.downloadBill(billDate, billType, tarType, deviceInfo);}@ApiOperation(value = "下载对账单")@PostMapping("/downloadBill")public WxPayBillResult downloadBill(WxPayDownloadBillRequest wxPayDownloadBillRequest) throws WxPayException {return this.wxService.downloadBill(wxPayDownloadBillRequest);}/*** <pre>* 提交刷卡支付* 文档地址:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1* 应用场景:* 收银员使用扫码设备读取微信用户刷卡授权码以后,二维码或条码信息传送至商户收银台,由商户收银台或者商户后台调用该接口发起支付。* 提醒1:提交支付请求后微信会同步返回支付结果。当返回结果为“系统错误”时,商户系统等待5秒后调用【查询订单API】,查询支付实际交易结果;当返回结果为“USERPAYING”时,商户系统可设置间隔时间(建议10秒)重新查询支付结果,直到支付成功或超时(建议30秒);* 提醒2:在调用查询接口返回后,如果交易状况不明晰,请调用【撤销订单API】,此时如果交易失败则关闭订单,该单不能再支付成功;如果交易成功,则将扣款退回到用户账户。当撤销无返回或错误时,请再次调用。注意:请勿扣款后立即调用【撤销订单API】,建议至少15秒后再调用。撤销订单API需要双向证书。* 接口地址:   https://api.mch.weixin.qq.com/pay/micropay* 是否需要证书:不需要。* </pre>*/@ApiOperation(value = "提交刷卡支付")@PostMapping("/micropay")public WxPayMicropayResult micropay(@RequestBody WxPayMicropayRequest request) throws WxPayException {return this.wxService.micropay(request);}/*** <pre>* 撤销订单API* 文档地址:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_11&index=3* 应用场景:*  支付交易返回失败或支付系统超时,调用该接口撤销交易。如果此订单用户支付失败,微信支付系统会将此订单关闭;如果用户支付成功,微信支付系统会将此订单资金退还给用户。*  注意:7天以内的交易单可调用撤销,其他正常支付的单如需实现相同功能请调用申请退款API。提交支付交易后调用【查询订单API】,没有明确的支付结果再调用【撤销订单API】。*  调用支付接口后请勿立即调用撤销订单API,建议支付后至少15s后再调用撤销订单接口。*  接口链接 :https://api.mch.weixin.qq.com/secapi/pay/reverse*  是否需要证书:请求需要双向证书。* </pre>*/@ApiOperation(value = "撤销订单")@PostMapping("/reverseOrder")public WxPayOrderReverseResult reverseOrder(@RequestBody WxPayOrderReverseRequest request) throws WxPayException {return this.wxService.reverseOrder(request);}@ApiOperation(value = "获取沙箱环境签名key")@GetMapping("/getSandboxSignKey")public String getSandboxSignKey() throws WxPayException {return this.wxService.getSandboxSignKey();}@ApiOperation(value = "发放代金券")@PostMapping("/sendCoupon")public WxPayCouponSendResult sendCoupon(@RequestBody WxPayCouponSendRequest request) throws WxPayException {return this.wxService.sendCoupon(request);}@ApiOperation(value = "查询代金券批次")@PostMapping("/queryCouponStock")public WxPayCouponStockQueryResult queryCouponStock(@RequestBody WxPayCouponStockQueryRequest request) throws WxPayException {return this.wxService.queryCouponStock(request);}@ApiOperation(value = "查询代金券信息")@PostMapping("/queryCouponInfo")public WxPayCouponInfoQueryResult queryCouponInfo(@RequestBody WxPayCouponInfoQueryRequest request) throws WxPayException {return this.wxService.queryCouponInfo(request);}@ApiOperation(value = "拉取订单评价数据")@PostMapping("/queryComment")public String queryComment(Date beginDate, Date endDate, Integer offset, Integer limit) throws WxPayException {return this.wxService.queryComment(beginDate, endDate, offset, limit);}}

二、唤起微信支付窗口

写一个简单的下单流程,业务逻辑代码我给他省略了

 private HttpResult order(OrderRequest orderRequest, String gkId) throws WxPayException{/** 业务代码省略*/wxPayMpOrderResult =  myWxPayService.createDdzqOrder(ddzqOrder);	//调用唤起窗口方法if(wxPayMpOrderResult == null){throw new RuntimeException("创建订单异常");}else{return HttpResult.ok(wxPayMpOrderResult);}}

唤起微信小程序支付窗口 参数可以按自己需要进行增加 https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=9_1 参考微信支付开发文档

public WxPayMpOrderResult createDdzqOrder(DdzqOrder ddzqOrder)throws WxPayException {String endPayMoney = ddzqOrder.getEndPayMoney().multiply(BigDecimal.valueOf(100)).stripTrailingZeros().toPlainString();	//将金额转换为分WxPayUnifiedOrderRequest.WxPayUnifiedOrderRequestBuilder builder = WxPayUnifiedOrderRequest.newBuilder();WxPayUnifiedOrderRequest wxOrder = builder.body("") //商品描述.openid("") //用户openid.outTradeNo(ddzqOrder.getMasterId())  //商户订单号.spbillCreateIp("0.0.0.0")  //终端IP.totalFee(endPayMoney) // 支付收款金额 100分  注意:单位(分)//.totalFee(1)  测试时可以设置一分钱.timeStart(DateTimeUtils.yyyyMMddHHmmssDateTime(0))	//交易起始时间.timeExpire(DateTimeUtils.yyyyMMddHHmmssDateTime(2))  //交易结束时间	.tradeType(WxPayConstants.TradeType.JSAPI).build();wxOrder.setSignType("MD5");//wxOrder.setNotifyUrl("https://**微信支付成功回调地址***/pay/ddzqOrder"); //不测试时需要放开注释 return wxPayService.createOrder(wxOrder);}

 当控制台打印出如下信息,则微信支付接口调用成功 

三、微信支付成功回调

https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8

 意思就是支付成功后,微信会调用我们之前设置的 微信支付成功回调地址

wxOrder.setNotifyUrl("https://**微信支付成功回调地址***/pay/ddzqOrder");

如果我们不给微信返回应答,微信会不断的请求我们接受微信回调通知的接口,所以这里就涉及到并发的问题,多次请求或者重复请求。
下面是我接收订单回调的接口,注意*需要给微信支付成功回调接口放行,不放行微信那边访问不到。

@Api("微信支付")
@RestController
@RequestMapping("/pay")
@AllArgsConstructor
public class WxPayController {
//监听到店自取下单的支付成功回调@PostMapping("/ddzqOrder")public String ddzqOrderPay(HttpServletRequest request, HttpServletResponse response) throws WxPayException {return myWxPayService.ddzqOrder(request);}
}

那微信那边重复请求我们应该怎么处理呢,其实这里有个小技巧,我们可以通过数据库锁避免同一条数据被重复操作。

update st_order set pay_status = #{payStatus } where pay_status = 0

 通过 where pay_status = 0 这个条件,那么这条订单数据只会被修改一次,以下就是我处理订单成功回调的方法

 public String ddzqOrder(HttpServletRequest request) {try {String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());WxPayOrderNotifyResult payResult = wxPayService.parseOrderNotifyResult(xmlResult);String masterOrderId = payResult.getOutTradeNo();//内部订单记录IDString wxTransactionId = payResult.getTransactionId();//商户号订单IDBigDecimal wxRealPayAmount = new BigDecimal(BaseWxPayResult.fenToYuan(payResult.getTotalFee()));//微信真实支付金额StOrder stOrder = stOrderMapper.selectByEOrderId(masterOrderId); Date nowTime = new Date();if(stOrder.getPayStatus() == 1){//下一个进程进来的时候,上一个进程已经修改了订单支付状态return WxPayNotifyResponse.success("处理成功!");}StOrder orderRequest = new StOrder();orderRequest.setPayStatus(1);//标记已支付orderRequest.setMasterOrderId(masterOrderId);orderRequest.setPaymentTime(nowTime);orderRequest.setStoreReceiveTime(nowTime);orderRequest.setOrderStatus(10);  //等待顾客取货stOrderMapper.updateByMasterOrderIdSelective(orderRequest);StOrderPay stOrderPay = new StOrderPay();stOrderPay.setMasterOrderId(masterOrderId);stOrderPay.setWxRealPayAmount(wxRealPayAmount);stOrderPay.setWxTransactionId(wxTransactionId);stOrderPay.setPayWay(1); //支付方式    微信支付:1    支付宝支付:2stOrderPayMapper.insert(stOrderPay);/*** 打印订单*/List<StPrinter> stPrinterList = stPrinterMapper.selectPrintersByStoreId(stOrder.getStoreId());for (StPrinter stPrinter:stPrinterList) {stPrinterService.printOrder(stOrder.getEOrderId(),stOrder.getStoreId(),stPrinter.getOkPrinterSn());}return WxPayNotifyResponse.success("处理成功!");} catch (Exception e) {e.printStackTrace();return WxPayNotifyResponse.fail(e.getMessage());}}


http://www.mrgr.cn/news/39780.html

相关文章:

  • 高效开发:SpringBoot网上租赁系统实现细节
  • Leetcode 981. 基于时间的键值存储
  • 随手记:ul-table表格合并方法
  • 工业交换机的RMON
  • java中有两个list列表,尽量少的去循环
  • 2024 年 25 款最佳入侵检测软件推荐 - 网络安全必备,零基础入门到精通,收藏这一篇就够了
  • 谷歌浏览器完美清除缓存
  • 一图看懂好利来老鼠接奶酪SVG交互|伸长+滑动叠加排版|E2.COOL黑科技SVG编辑器
  • 匿名管道 Linux
  • 前端css样式设置元素的绝对定位和相对定位,要注意宽度和高度的设置
  • 一条命令Docker安装常用桌面linux系统含一些系统和应用
  • 数据结构(链表的操作算法)
  • 不带头结点单链表逆置递归实现---未验证
  • 如何选择合适的量化交易策略,回测与模拟交易的实战演练
  • java-netty客户端断线重启0.9.0
  • Vim常见模式介绍,你知道哪些?
  • find()和findIndex()方法
  • Navicat 工具 下载安装
  • TE-1402/1403 简易使用说明 - Technica Engineering Media Converter
  • Spring Task 调度任务