参考于:https://javen205.gitee.io/ijpay/

准备工作

  • APPID
  • 商户号
  • API密钥(去微信商户中心去设置,格式:32位大小写字符串)

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>