# IJPay 中的微信支付

## 官方参考文档

- [普通商户模式接入](https://pay.weixin.qq.com/wiki/doc/api/index.html)
- [服务商模式接入](https://pay.weixin.qq.com/wiki/doc/api/sl.html)
- [微信委托扣款相关 API-服务商模式](https://pay.weixin.qq.com/wiki/doc/api/pap_sl.php?chapter=17_1)
- [微信委托扣款相关 API-普通商户模式](https://pay.weixin.qq.com/wiki/doc/api/pap.php?chapter=17_1)
- [微信刷脸支付 API](https://pay.weixin.qq.com/wiki/doc/wxfacepay/develop/backend.html)
- [微信酒店押金相关 API](https://pay.weixin.qq.com/wiki/doc/api/deposit_sl.php?chapter=26_1)

##  支付方式与支付工具

::: tip
IJPay 中支持的支付方式以及支付工具
:::

1. 付款码支付【[商户模式](https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=5_1)】【[服务商模式](https://pay.weixin.qq.com/wiki/doc/api/micropay_sl.php?chapter=5_1)】
2. 公众号支付(JSAPI 支付)【[商户模式](https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1)】【[服务商模式](https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=7_1)】
3. 扫码支付(Native 支付)【[商户模式](https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1)】【[服务商模式](https://pay.weixin.qq.com/wiki/doc/api/native_sl.php?chapter=6_1)】
4. APP支付【[商户模式](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_1)】【[服务商模式](https://pay.weixin.qq.com/wiki/doc/api/app/app_sl.php?chapter=8_1)】
5. H5 支付【[商户模式](https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_1)】【[服务商模式](https://pay.weixin.qq.com/wiki/doc/api/H5_sl.php?chapter=15_1)】
6. 小程序支付【[商户模式](https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3&index=1)】【[服务商模式](https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_sl_api.php?chapter=7_3&index=1)】
7. 人脸支付   【[服务商模式](https://pay.weixin.qq.com/wiki/doc/wxfacepay/)】
8. 企业付款到零钱/银行卡 【[商户模式](https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_1)】
9. 现金红包  【[商户模式](https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_1)】【[服务商模式](https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon_sl.php?chapter=13_1)】

## 使用步骤

1. [添加相关依赖](../maven.md)
2. 找到相关支付方式的接口文档。构建请求参数 Model，并使用 https 执行请求
3. 调用支付接口唤起支付并完成支付逻辑


## 微信支付 Model

IJPay 中常用支付方式涉及到的 [Model](https://gitee.com/javen205/IJPay/blob/master/IJPay-WxPay/src/main/java/com/ijpay/wxpay/model)
都是使用 `builder` 模式来构建，**其中 Model 每个字段与官方接口文档保持一致**，同时支持商户模式、服务商模式。

 ::: warning
 为什么要使用 Lombok 来构建接口的请求参数？

1、使用 Lombok 来构建请求参数是为了方便，不用写太多的冗余 get set。

2、避免手动设置误写参数导致的低级错误。

外界对 Lombok 的评价也不太一致，喜欢的非常喜欢不喜欢的就使劲吐槽，那么 IJPay 中有其他的替代方案吗？

当然是有的，最简单粗暴的方法使用 Map 来构建请求参数，再使用 `WxPayKit.buildSign` 来构建签名即可。 IJPay 1.x 版本就是这么做的  
 :::

## 扩展 Model

由于支付方式的不同涉及到的接口非常多，如果某些接口的 Model 在 IJPay 没有提供封装，大家可以继承 [BaseModel](https://gitee.com/javen205/IJPay/blob/master/IJPay-Core/src/main/java/com/ijpay/core/model/BaseModel.java) 
**所有属性字段名称与接口参数保持一致且必须为 `String` 类型**，最后添加如下注解来实现 `builder` 模式。

```java{5}
@Builder
@AllArgsConstructor
@Getter
@Setter
public class CloseOrderModel extends BaseModel {
    // 属性字段名称与接口参数保持一致 
    private String appid;
    // 省略接口中的其他参数...
}
```  

::: warning 前方高能
1. 扩展 Model 必须继承  BaseModel
2. 所有属性字段名称与接口参数保持一致且必须为 `String` 类型
3. 必须添加 [Lombok](https://projectlombok.org) 注解 
`@Builder`  
`@AllArgsConstructor(access = AccessLevel.PRIVATE)` 
`@Getter`
4. IDEA 必须安装 [Lombok](https://projectlombok.org) 插件
:::


## 构建参数并执行请求

1. 根据接口需要的参数，使用 Model 构建除 `sign` 以外的参数
2. `build` 后根据接口的签名方式创建签名 `creatSign`
3. 使用 [WxPayApi](https://gitee.com/javen205/IJPay/blob/master/IJPay-WxPay/src/main/java/com/ijpay/wxpay/WxPayApi.java) 提供的接口执行 https 请求
4. 构建支付参数唤起支付 

例如公众号支付(JSAPI 支付)的统一下单

```java{2,3,15,17,19,21,36,37} 
// 统一下单构建请求参数
Map<String, String> params = UnifiedOrderModel
    .builder()
    .appid(wxPayBean.getAppId())
    .mch_id(wxPayBean.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(wxPayBean.getDomain().concat("/wxpay/pay_notify"))
    .trade_type(TradeType.JSAPI.getTradeType())
    .openid(openId)
    .build()
    // 同时支持 SignType.MD5、SignType.HMACSHA256
    .creatSign(wxPayBean.getPartnerKey(), SignType.HMACSHA256);  
// 发送请求
String xmlResult = WxPayApi.pushOrder(false,params); 
// 将请求返回的 xml 数据转为 Map，方便后面逻辑获取数据
Map<String, String> resultMap = WxPayKit.xmlToMap(xmlResult);
// 判断返回的结果
String returnCode = resultMap.get("return_code");
String returnMsg = resultMap.get("return_msg");
if (!WxPayKit.codeIsOk(returnCode)) {
    return new AjaxResult().addError(returnMsg);
}
String resultCode = resultMap.get("result_code");
if (!WxPayKit.codeIsOk(resultCode)) {
    return new AjaxResult().addError(returnMsg);
}

// 以下字段在return_code 和result_code都为SUCCESS的时候有返回
String prepayId = resultMap.get("prepay_id");
// 二次签名，构建公众号唤起支付的参数,这里的签名方式要与上面统一下单请求签名方式保持一致
Map<String, String> packageParams = WxPayKit.prepayIdCreateSign(prepayId, 
    wxPayBean.getAppId(),wxPayBean.getPartnerKey(),SignType.HMACSHA256);
// 将二次签名构建的数据返回给前端并唤起公众号支付
String jsonStr = JSON.toJSONString(packageParams);
return new AjaxResult().success(jsonStr);
``` 

::: tip 完整示例
公众号[如何唤起支付](https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6)，完整示例请参考 [IJPay-Demo](https://gitee.com/javen205/IJPay/blob/master/IJPay-Demo-SpringBoot/src/main/java/com/ijpay/demo/controller/wxpay/WxPayController.java)
:::

## 多应用支持

微信支付的多应用支持方式与支付宝的多应用无缝切换一致，请参考 [支付宝初始化](../alipay/init.md)


## 完整示例

 ::: tip
 IJPay 2.x 版本示例
 :::
 
- [IJPay-Demo-SpringBoot](https://gitee.com/javen205/IJPay/tree/master/IJPay-Demo-SpringBoot)
- [IJPay-Demo-JFinal](https://gitee.com/javen205/IJPay/tree/master/IJPay-Demo-JFinal)

 ::: tip
 IJPay 1.x 版本示例
 :::
 
- [IJPay-Demo](https://gitee.com/javen205/IJPay-Demo)

<Q url="tencent://message/?uin=572839485&Site=%E5%AE%A2%E6%9C%8D&Menu=yes" />

