【JAVA版】微信支付方案一详解

举报
星汉网络 发表于 2019/04/18 15:32:49 2019/04/18
【摘要】 在接入微信支付插件时,如果使用方案一完成,难点还是在getOrderId。这个方法的服务器端实现,还要多参考微信提供的接口文档。对接起来还是有很多小坑的,希望以下经验,能给您提供帮助。参考接入接口 : https://pay.weixin.qq.com/wiki/doc/api/index.html管理端后台的Java主体代码如下:/** * 微信支付获取预支付订单号 ...

在接入微信支付插件时,如果使用方案一完成,难点还是在getOrderId。这个方法的服务器端实现,还要多参考微信提供的接口文档。对接起来还是有很多小坑的,希望以下经验,能给您提供帮助。
参考接入接口 : https://pay.weixin.qq.com/wiki/doc/api/index.html

管理端后台的Java主体代码如下:

/**
         * 微信支付获取预支付订单号
         * <ul>
         * <li>1、封装数据,进行预支付,获取统一下单的prepay_id</li>
         * <li>2、验证是否下单成功,成功后,将签名数据返回</li>
         * </ul>
         * @param request
         * @param response
         * @return
         * @author JiangZhongyan
         * @throws NoSuchAlgorithmException
         */
        @SuppressWarnings("unchecked")
        @ResponseBody
        @RequestMapping(value = "wxpay-order-info")
        public String getPayOrderInfo(HttpServletRequest request, HttpServletResponse response)
                        throws NoSuchAlgorithmException
        {
                String payType = request.getParameter("type");

                String tradeNo = request.getParameter("tradeNo");
                String totalFee = request.getParameter("totalFee");

                // 封装微信支付申请参数对象,注意APP支付和微信公众号支付的参数差异
                WxpayPreConfig preConfig = new WxpayPreConfig(tradeNo, totalFee, WxpayHelper.TRADE_TYPE_APP);
                preConfig.setNotify_url(prop.getWxNotifyUrl());
                String secretKey = prop.getWxAppSecret();
                preConfig.setTrade_type(WxpayHelper.TRADE_TYPE_APP);
                preConfig.setAppid(prop.getWxAppId());
                preConfig.setMch_id(prop.getWxMchId());

                // 预支付信息
                Map<String, String> preInfo = new HashMap<>(BeanMap.create(preConfig));
                preInfo.put("sign", WxpayHelper.getMD5Sign(preInfo, secretKey));

                String resultStr = ClientUtils.sendPost(prop.getWxSendUri(),
                                WxpayHelper.getRequestXml(preInfo), StringUtils.UTF8);
                
                // 统一下单结果,主要为了获取prepay_id
                JSONObject result = XmlUtils.getJSONFromXml(resultStr);

                // 检测是否下单成功以及签名是否正确
                if (result.getString("return_code").equals("SUCCESS")
                                && WxpayHelper.checkSign(result, secretKey))
                {
                        // 解析下单结果,并返回前台使用
                        WxpayConfig retConfig = new WxpayConfig(result.getString("prepay_id"));
                        retConfig.setAppid(prop.getWxAppId());
                        retConfig.setPartnerid(prop.getWxMchId());

                        Map<String, String> info = new HashMap<>(BeanMap.create(retConfig));
                        info.put("package", "Sign=WXPay");

                        // 二次签名
                        info.put("sign", WxpayHelper.getMD5Sign(info, secretKey));
                        // 拼装返回前台信息
                        return JSONObject.fromObject(info).toString();
                }

                return JSONObject.fromObject(new ErrorMsgBean(resultStr)).toString();
        }

说明:
1)其中,WxpayPreConfig类的内容,参考接口文档,自己拼凑即可。
2)prop.getWxSendUri() = https://api.mch.weixin.qq.com/pay/unifiedorder
3)附上MD5签名方法,注意map的排序。

public static String getMD5Sign(Map<String, String> map, String key)
                        throws NoSuchAlgorithmException
        {
                StringBuffer info = new StringBuffer(StringUtils.getSortedParam(map));
                // 若有key
                if (!StringUtils.isNullOrEmpty(key))
                {
                        info.append("&key=" + key);
                }
                return StringUtils.MD5(info.toString()).toUpperCase();
        }

说明:这里附上的代码,仅提供开发思路。可能不全。如果需要源代码者,再线下联系。可以提供相关代码。
如下为,正确统一下单之后,返回的结果数据:

【微信统一下单参数结果】 <xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg><appid><![CDATA[<你自己的>]]></appid><mch_id><![CDATA[<你自己的>]]></mch_id><nonce_str><![CDATA[LMvSZOBztoQzz13g]]></nonce_str><sign><![CDATA[<你自己的>]]></sign><result_code><![CDATA[SUCCESS]]></result_code><prepay_id><![CDATA[<你自己的>]]></prepay_id><trade_type><![CDATA[APP]]></trade_type></xml>

在APP一侧的JS代码中,对接如下:

/**
                 * 微信支付
                 * 微信支付的最小单位是分
                 * 注意Number(price) * 100的冗余错误,加上parseInt修正
                 * parseInt(Number(price) * 100)
                 * @param  tradeNo 商户系统内部的订单号
                 * @param price 订单总金额,只能为整数,单位:分(¥)
                 */
                function execWxpay(tradeNo, price, desc) {
                        var data = {
                                tradeNo : tradeNo,
                                totalFee : price,
                                description : '支付订单'
                        }
                        ajax.post('app/wxpay-order-info.action', data, function(data) {
                                if (!extApi.isNullObj(data)) {
                                        var wxPay = api.require('wxPay');
                                        wxPay.payOrder({
                                                apiKey : data.appid,
                                                orderId : data.prepayid,
                                                mchId : data.partnerid,
                                                nonceStr : data.noncestr,
                                                timeStamp : data.timestamp,
                                                package : 'Sign=WXPay',
                                                sign : data.sign
                                        }, function(ret, err) {
                                                if (!ret.status) {
                                                        var msg = getWxRetErrorCodeMsg(err.code);
                                                        extApi.alert(msg, '支付结果');
                                                }
                                                
                                                if (ret.status) {
                                                        closePayWin();
                                                }
                                        });
                                }
                        });
                }

                /**
                 * 微信支付失败时返回的错误码
                 * -2:用户取消
                 * -1:未知错误,可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等
                 * 1:apiKey值非法
                 */
                function getWxRetErrorCodeMsg(code) {
                        switch(code) {
                                case '-2':
                                        return '用户取消';
                                case '1':
                                        return 'apiKey值非法';
                                default:
                                        return '未知错误';
                        }
                }

正确提交支付后,微信返回的支付成功数据串,示例如下:

【微信支付回调时的String参数】<xml><appid><![CDATA[<你自己的>]]></appid><bank_type><![CDATA[CFT]]></bank_type><cash_fee><![CDATA[1]]></cash_fee><fee_type><![CDATA[CNY]]></fee_type><is_subscribe><![CDATA[N]]></is_subscribe><mch_id><![CDATA[<你自己的>]]></mch_id><nonce_str><![CDATA[ps6Opmjk]]></nonce_str><openid><![CDATA[<你自己的>]]></openid><out_trade_no><![CDATA[20170904182528806]]></out_trade_no><result_code><![CDATA[SUCCESS]]></result_code><return_code><![CDATA[SUCCESS]]></return_code><sign><![CDATA[<你自己的>]]></sign><time_end><![CDATA[20170904182539]]></time_end><total_fee>1</total_fee><trade_type><![CDATA[APP]]></trade_type><transaction_id><![CDATA[4009082001201709040196726483]]></transaction_id></xml>

特别注意:
1)尤其是APP和微信公众号都有接入的项目,一定要注意二者之间的差异。主要在账号上,不能混用,否则支付会一直不成功。
2)在附件中,会携带主要的Java类方法。但可能还是会不全。

以上内容,希望对您有用。

    附件下载

  • wxpay.zip 3.87KB 下载次数:2
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。