前言
使用IJpay进行支付接口的开发,主要包括下面几个步骤,这里主要是使用的是 API V2 版本的接口进行的调试。
1.引入依赖
主要通过pom引入依赖
1 2 3 4 5 6
| <dependency> <groupId>com.github.javen205</groupId> <artifactId>IJPay-All</artifactId> <version>2.9.4</version> </dependency>
|
2.编写配置
主要appId、appSecret还有证书路径等
1 2 3 4 5 6 7 8 9 10 11 12 13
| wxpay: appId: appSecret: mchId: partnerKey: certPath: domain:
|
其中的秘钥和证书,需要到微信支付->商户平台->API安全进行配置,这里需要配置一个证书的路径。可以配置系统的绝对路径,但是程序使用的是docker部署,那么这个路径该如何配置呢?
解决方法就是使用目录映射的方法,比如我在docker-compose.yml中,使用volumes进行了目录映射
3.编写配置类
有了配置文件,需要进行读取配置文件内容,生成一个bean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| @Component @ConfigurationProperties(prefix = "wxpay") public class WxPayProperties { private String appId; private String appSecret; private String mchId; private String partnerKey; private String certPath; private String domain;
public String getAppId() { return appId; }
public void setAppId(String appId) { this.appId = appId; }
public String getAppSecret() { return appSecret; }
public void setAppSecret(String appSecret) { this.appSecret = appSecret; }
public String getMchId() { return mchId; }
public void setMchId(String mchId) { this.mchId = mchId; }
public String getPartnerKey() { return partnerKey; }
public void setPartnerKey(String partnerKey) { this.partnerKey = partnerKey; }
public String getCertPath() { return certPath; }
public void setCertPath(String certPath) { this.certPath = certPath; }
public String getDomain() { return domain; }
public void setDomain(String domain) { this.domain = domain; }
@Override public String toString() { return "WxPayBean [appId=" + appId + ", appSecret=" + appSecret + ", mchId=" + mchId + ", partnerKey=" + partnerKey + ", certPath=" + certPath + ", domain=" + domain + "]"; } }
|
4.编写接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
| @RestController @RequestMapping("/wxPay") public class PayController { private final static Logger logger= LoggerFactory.getLogger(PayController.class);
@Autowired private WxPayProperties wxPayBean;
private String notifyUrl; private String refundNotifyUrl; private static final String USER_PAYING = "USERPAYING";
public WxPayApiConfig getApiConfig() { WxPayApiConfig apiConfig; try { apiConfig = WxPayApiConfigKit.getApiConfig(wxPayBean.getAppId()); } catch (Exception e) { apiConfig = WxPayApiConfig.builder() .appId(wxPayBean.getAppId()) .mchId(wxPayBean.getMchId()) .partnerKey(wxPayBean.getPartnerKey()) .certPath(wxPayBean.getCertPath()) .domain(wxPayBean.getDomain()) .build(); WxPayApiConfigKit.setThreadLocalWxPayApiConfig(apiConfig); } notifyUrl = apiConfig.getDomain().concat("/wxPay/payNotify"); refundNotifyUrl = apiConfig.getDomain().concat("/wxPay/refundNotify"); return apiConfig; }
@RequestMapping(value = "/webPay", method = {RequestMethod.POST, RequestMethod.GET}) public AjaxResult webPay(HttpServletRequest request, @RequestParam("total_fee") String totalFee) { String openId = (String) request.getSession().getAttribute("openId"); if (openId == null) { openId = "11111111"; }
if (StrUtil.isEmpty(openId)) { return AjaxResult.error("openId is null"); } if (StrUtil.isEmpty(totalFee)) { return AjaxResult.error("请输入数字金额"); } String ip = IpKit.getRealIp(request); if (StrUtil.isEmpty(ip)) { ip = "127.0.0.1"; } WxPayApiConfig wxPayApiConfig = getApiConfig(); Map<String, String> params = UnifiedOrderModel .builder() .appid(wxPayApiConfig.getAppId()) .mch_id(wxPayApiConfig.getMchId()) .nonce_str(WxPayKit.generateStr()) .body("IJPay 让支付触手可及-公众号支付") .attach("Node.js 版:https://gitee.com/javen205/TNWX") .out_trade_no(WxPayKit.generateStr()) .total_fee("1000") .spbill_create_ip(ip) .notify_url(notifyUrl) .trade_type(TradeType.JSAPI.getTradeType()) .openid(openId) .build() .createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256); String xmlResult = WxPayApi.pushOrder(false, params); logger.info(xmlResult); Map<String, String> resultMap = WxPayKit.xmlToMap(xmlResult); String returnCode = resultMap.get("return_code"); String returnMsg = resultMap.get("return_msg"); if (!WxPayKit.codeIsOk(returnCode)) { return AjaxResult.error(returnMsg); } String resultCode = resultMap.get("result_code"); if (!WxPayKit.codeIsOk(resultCode)) { return AjaxResult.error(returnMsg); }
String prepayId = resultMap.get("prepay_id"); Map<String, String> packageParams = WxPayKit.prepayIdCreateSign(prepayId, wxPayApiConfig.getAppId(), wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
return AjaxResult.success(packageParams); }
@RequestMapping(value = "/refundNotify", method = {RequestMethod.POST, RequestMethod.GET}) public String refundNotify(HttpServletRequest request) { String xmlMsg = HttpKit.readData(request); logger.info("退款通知=" + xmlMsg); Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
String returnCode = params.get("return_code"); if (WxPayKit.codeIsOk(returnCode)) { String reqInfo = params.get("req_info"); String decryptData = WxPayKit.decryptData(reqInfo, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey()); logger.info("退款通知解密后的数据=" + decryptData); Map<String, String> xml = new HashMap<String, String>(2); xml.put("return_code", "SUCCESS"); xml.put("return_msg", "OK"); return WxPayKit.toXml(xml); } return null; }
@RequestMapping(value = "/payNotify", method = {RequestMethod.POST, RequestMethod.GET}) public String payNotify(HttpServletRequest request) { String xmlMsg = HttpKit.readData(request); logger.info("支付通知=" + xmlMsg); Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
String returnCode = params.get("return_code");
if (WxPayKit.verifyNotify(params, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey(), SignType.HMACSHA256)) { if (WxPayKit.codeIsOk(returnCode)) { Map<String, String> xml = new HashMap<String, String>(2); xml.put("return_code", "SUCCESS"); xml.put("return_msg", "OK"); return WxPayKit.toXml(xml); } } return null; } }
|
参考文章:
1.
微信支付 API v3 使用v2接口还是v3接口,这两种方式是不一样的。
2.
统一下单 这是微信统一下单接口,无论是微信小程序,Native支付,还是其他的支付方式,都需要使用这个后端接口实现统一下单。body:商品简单描述;attach:附加数据,在查询 API 和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据;
3.
Native支付接入前准备 这是Native支付模式,API v3版本的接口说明
4.
Native支付 这个也是微信支付的开发文档,不过这里是API v2版本的。商户支付回调URL设置指引:进入商户平台–>产品中心–>开发配置,进行配置和修改,如图6.6所示。
问题
(1) 无法将输入源“/body/xml/total_fee”映射到目标字段“标价金额”中,此字段需要一个合法的 64 位有符号整数
【解决方法】
这个total_fee的单位是分,不能包括小数点。
(2) 签名错误,请检查后再试
这个问题我以为是因为使用了错误的证书引起的,后来我专门重新申请了一个证书,最后还是不行。
【解决方法】
这个错误的原因很多,我的问题主要就是我使用了 API v2 的支付,但是我的partnerKey填入了 API v3 的秘钥。
(4) 此商家的收款功能已被限制,暂无法支付。商家可以登录微信商户平台/微信支付商家助手小程序查看原因和解决方案。
这个没啥说的,主要就是登录商户管理平台,查看消息通知,按要求进行整改。