准备工作(需要提前获取的内容)
- APPID
- 商户号
- API密钥(去微信商户中心去自定义设置,格式:32位大小写字符串)
在开始编码前,先了解微信支付的分类,以便于准确的接入响应的场景
产品类型 | 产品能力 | 场景描述 |
---|---|---|
基础支付 |
JSAPI支付(产品介绍 | API接口) | 商户通过调用微信支付提供的JSAPI接口,在支付场景中调起微信支付模块完成收款 |
APP支付(产品介绍 | API接口) | 商户通过在移动端应用APP中集成开放SDK调起微信支付模块来完成支付 | |
Native支付(产品介绍 | API接口) | 商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模式 | |
小程序支付(产品介绍 | API接口) | 通过好友分享或扫描二维码在微信内打开小程序时,可以调用微信支付完成下单购买的流程 | |
合单支付(产品介绍 | API接口) | 一次支付行为可以同时进行票证、保险的付款,且两笔付款分别对应两个不同的商户 | |
付款码支付V2 | 用户出示微信钱包中的条码、二维码,商家通过扫描用户条码即可完成收款 | |
刷脸支付 | 用户在集成微信刷脸支付SDK的线下机具上"刷脸"即可完成支付 |
点击 产品介绍快速了解自己需要对接的场景!
同时去商户号,产品中心-我的产品 查看自己的时候开通相关服务
正式编码
Maven依赖
<!-- 微信支付第三方包,官方因为Bug下架了-->
<dependency>
<groupId>com.github.javen205</groupId>
<artifactId>IJPay-All</artifactId>
<version>2.7.4</version>
</dependency>
<!-- 用于微信支付时候验证 如:StrKit.isBlank("hello") 只是一个String检验,我觉得完全可以按照自己的方式判断-->
<dependency>
<groupId>com.jfinal</groupId>
<artifactId>enjoy</artifactId>
<version>4.9.16</version>
</dependency>
注入一个SpringBean,相当于SDK(请勿忽略)
@Bean
public WxPayApiConfig getWxPayApiConfig(){
WxPayApiConfig apiConfig;
try {
apiConfig = WxPayApiConfigKit.getApiConfig(appId);
} catch (Exception e) {
apiConfig = com.ijpay.wxpay.WxPayApiConfig.builder()
.appId("你的APPID")
.mchId("商户号")
.partnerKey("API密钥 是32位的大小写数字组合")
.certPath(null)
.domain(null)
.build();
}
// notifyUrl = wxPayApiConfig.getDomain().concat("/wxPay/payNotify");
//refundNotifyUrl = wxPayApiConfig.getDomain().concat("/wxPay/refundNotify");
return apiConfig;
}
微信APP支付接口
@Autowired
WxPayApiConfig wxPayApiConfig;
/**
* 唤起APP支付,注意需要的 APPID、 mchId(商户号) 、partnerKey(API密钥 微信开放平台获取)
* @param request
* @return
*/
@GetMapping("doAppPay")
@ResponseBody
public String doAppPay(HttpServletRequest request) {
// 获取真实IP 微信要求必须穿,就借用这个工具来测试
String ip = IpKit.getRealIp(request);
if (StrKit.isBlank(ip)) {
ip = "127.0.0.1";
}
// 构建请求参数 具体参数含义,请访问:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1; 如果需要其他参数请自己加
Map<String, String> params = UnifiedOrderModel
.builder()
// 固定参数 依次是:APPID、商户号、随机字符串(必填,但是没啥用)
.appid(wxPayApiConfig.getAppId())
.mch_id(wxPayApiConfig.getMchId())
.nonce_str(WxPayKit.generateStr())
// 动态参数依次是:商品描述、附加数据、商户订单号、总金额(单位是分 1块钱就是100分)、终端IP(用户IP)、通知地址、交易类型
.body("商品描述")
.attach("我是附加数据")
.out_trade_no(WxPayKit.generateStr())
.total_fee("1")
.spbill_create_ip(ip)
.notify_url("http://740969606.vaiwan.com/emailclock/wechatPay/payNotify")
.trade_type(TradeType.APP.getTradeType())
.build()
.createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
// 向微信发送订单,并获取微信的结果
String xmlResult = WxPayApi.pushOrder(false, params);
log.info(xmlResult);
// 由于微信返回的结果是xml,我们要处理成map,方便我们使用
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
// 从结果中获取返回码与返回信息
String returnCode = result.get("return_code");
String returnMsg = result.get("return_msg");
// 如果下单失败,请不要返回给用户微信给的提示
if (!WxPayKit.codeIsOk(returnCode)) {
// 打印微信给的失败的结果
System.out.println(returnMsg);
return "下单失败,请联系管理员";
}
// 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回
String prepayId = result.get("prepay_id");
// 返回给前端的签名,这个可以自己定义或者代替
Map<String, String> packageParams = WxPayKit.appPrepayIdCreateSign(wxPayApiConfig.getAppId(), wxPayApiConfig.getMchId(), prepayId,
wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
// 将返回给前端的结果处理成Json 返回
String jsonStr = JSON.toJSONString(packageParams);
log.info("返回apk的参数:" + jsonStr);
return jsonStr;
}
下单后 需要根据前端需要的参数,自己动态追加即可!
微信支付回调
@Autowired
WxPayApiConfig wxPayApiConfig;
/**
* 异步通知
* 当下单的时候指定了回调地址,且在用户成功支付后,会调用本接口。如果本接口执行成功了,需要给微信返回一个消息,这样微信就不会再给我们发了
* @param request
* @return 返回给微信的消息,指定xml格式
*/
@RequestMapping(value = "/payNotify", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public String payNotify(HttpServletRequest request) {
//读取xml的信息
String xmlMsg = HttpKit.readData(request);
log.info("微信支付的通知:\n" + xmlMsg);
// 将XML转成我们方便处理的Map即可
Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
String returnCode = params.get("return_code");
// TODO 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态
// 注意此处签名方式需与统一下单的签名类型一致
if (WxPayKit.verifyNotify(params, wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256)) {
if (WxPayKit.codeIsOk(returnCode)) {
// TODO 更新订单信息
// 封装返回数据,给微信应答,微信要XML的格式,就处理返回给微信吧
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;
}
微信回调返回的结果!仅供参考,方便快速提取需要自己的参数
具体含义:https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/open/chapter6_8.shtml
# 说明 <![CDATA[]> 包含的内容是xml格式,具体数据 就是包含的数据!
这个是我格式化后的结果,xml格式化网站:https://c.runoob.com/front-end/710/
<xml>
<appid>
<![CDATA[wx04c70dfc32bcf80c]]>
</appid>
<attach>
<![CDATA[我是附加数据]]>
</attach>
<bank_type>
<![CDATA[OTHERS]]>
</bank_type>
<cash_fee>
<![CDATA[1]]>
</cash_fee>
<fee_type>
<![CDATA[CNY]]>
</fee_type>
<is_subscribe>
<![CDATA[N]]>
</is_subscribe>
<mch_id>
<![CDATA[1613480964]]>
</mch_id>
<nonce_str>
<![CDATA[ccc94fef62b04cc6bbc06a069594d6a1]]>
</nonce_str>
<openid>
<![CDATA[ovKlt6fJWaf2J32k9xwecUgaigR4]]>
</openid>
<out_trade_no>
<![CDATA[cf2cb7cd909b462b9f307c253ae772f9]]>
</out_trade_no>
<result_code>
<![CDATA[SUCCESS]]>
</result_code>
<return_code>
<![CDATA[SUCCESS]]>
</return_code>
<sign>
<![CDATA[46F2750404B79B851200E851A3BF27C644C8F2C012CC34E73285DE3FEBE384A2]]>
</sign>
<time_end>
<![CDATA[20210901172005]]>
</time_end>
<total_fee>1</total_fee>
<trade_type>
<![CDATA[APP]]>
</trade_type>
<transaction_id>
<![CDATA[4200001221202109016245020614]]>
</transaction_id>
</xml>
特殊说明:
上述文章均是作者实际操作后产出。烦请各位,请勿直接盗用!转载记得标注原文链接:www.zanglikun.com
第三方平台不会及时更新本文最新内容。如果发现本文资料不全,可访问本人的Java博客搜索:标题关键字。以获取最新全部资料 ❤
第三方平台不会及时更新本文最新内容。如果发现本文资料不全,可访问本人的Java博客搜索:标题关键字。以获取最新全部资料 ❤
评论(0)