记一次对接微信支付

场景:个人的外包项目,后台说app端自己去微信那边下单自己签名完成支付;
一脸蒙蔽啊,还有这样的操作?这里写图片描述;默默的打开微信开发文档,跟着文档一步一步集成 微信支付开发者平台

主要难点在调用微信的统一下单接口,配置与签名问题

                        // 使用该map可以自动按key排序
                        SortedMap<String, String> parameterMap = new TreeMap<>();
                        parameterMap.put("appid", weixinPay.getApp_id());  // APPID
                        parameterMap.put("mch_id", weixinPay.getPartner());  // 商户id
                        parameterMap.put("nonce_str", nonce_str);  // 随机字符串
                        parameterMap.put("body", orderNo);  // 在支付时显示的信息
                        parameterMap.put("out_trade_no", orderNo);  // 订单号,注意唯一,且一个订单号只能有一个价格,不能改价格不改订单号;已踩过的坑 :(
                        int price = (int) (Double.valueOf(receivable)*100); 
                        parameterMap.put("total_fee", String.valueOf(price)); // 支付的钱  单位是分
                        parameterMap.put("spbill_create_ip", IpGetUtil.getIPAddress(PayActivity.this));  // 自己的IP地址
                        parameterMap.put("notify_url", weixinPay.getNotify_url());  // 支付回调url
                        parameterMap.put("trade_type", "APP");  // 支付方式
                        // 获取签名 该签名是通过前面的参数来得到的签名
                        String sign = PayCommonUtil.createSign("UTF-8", parameterMap,weixinPay.getPartner_key());
                        parameterMap.put("sign", sign);

微信使用的是xml格式,所以我们还要将map数据转换为xml格式,将map转换为xml字符串

    /**
     * 将Map转换为XML格式的字符串
     *
     * @param data Map类型数据
     * @return XML格式的字符串
     */
    public static String mapToXml(Map<String, String> data) throws Exception {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
        org.w3c.dom.Document document = documentBuilder.newDocument();
        org.w3c.dom.Element root = document.createElement("xml");
        document.appendChild(root);
        for (String key: data.keySet()) {
            String value = data.get(key);
            if (value == null) {
                value = "";
            }
            value = value.trim();
            org.w3c.dom.Element filed = document.createElement(key);
            filed.appendChild(document.createTextNode(value));
            root.appendChild(filed);
        }
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
        DOMSource source = new DOMSource(document);
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        StringWriter writer = new StringWriter();
        StreamResult result = new StreamResult(writer);
        transformer.transform(source, result);
        String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
        try {
            writer.close();
        }
        catch (Exception ex) {
        }
        return output;
    }

然后就可以通过调用微信的下单接口去下单了

    /**
     * 微信下单调用
     * @param requestUrl  微信下单url
     * @param requestMethod 请求方法
     * @param outputStr 参数
     * @return 返回结果,xml格式
     */
    public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        try {

            URL url = new URL(requestUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 设置请求方式(GET/POST)
            conn.setRequestMethod(requestMethod);
            conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
            // 当outputStr不为null时向输出流写数据
            if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();
                // 注意编码格式
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }
            // 从输入流读取返回内容
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            // 释放资源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            conn.disconnect();
            return buffer.toString();
        } catch (ConnectException ce) {
            System.out.println("连接超时:{}" + ce);
        } catch (Exception e) {
            System.out.println("https请求异常:{}" + e);
        }
        return null;
    }

得到返回的结果后为了方便处理,将xml转换为map

    /**
     * XML格式字符串转换为Map
     *
     * @param strXML XML字符串
     * @return XML数据转换后的Map
     */
    public static Map<String, String> xmlToMap(String strXML) throws Exception {
        try {
            Map<String, String> data = new HashMap<>();
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
            org.w3c.dom.Document doc = documentBuilder.parse(stream);
            doc.getDocumentElement().normalize();
            NodeList nodeList = doc.getDocumentElement().getChildNodes();
            for (int idx = 0; idx < nodeList.getLength(); ++idx) {
                Node node = nodeList.item(idx);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    org.w3c.dom.Element element = (org.w3c.dom.Element) node;
                    data.put(element.getNodeName(), element.getTextContent());
                }
            }
            try {
                stream.close();
            } catch (Exception ex) {
                // do nothing
            }
            return data;
        } catch (Exception ex) {
            Log.e("WXPayUtil", "xmlToMap: ",ex );
            throw ex;
        }

    }
成功失败就看返回的结果了,如果返回成功继续,如果失败了就看下是签名的问题还是配置key的问题,微信提供了一个验证签名的工具,可以对比与自己的签名是否相同验证签名
先别激动,要再次签名

封装参数

                        // 将微信返回的xml数据再次封装到一个map中
                        SortedMap<String, String> finalParams = new TreeMap<>();
                        finalParams.put("appid", weixinPay.getApp_id());  // APPID
                        finalParams.put("partnerid", weixinPay.getPartner());  // 商户id
                        finalParams.put("prepayid", map.get("prepay_id"));  // 预支付id
                        finalParams.put("package", "Sign=WXPay");  // 签名方式
                        finalParams.put("noncestr", map.get("nonce_str"));  // 随机字符传
                        finalParams.put("timestamp", timeStamp);  // 时间戳  String.valueOf(System.currentTimeMillis() / 1000)
                        // 再次签名
                        String finalSign = PayCommonUtil.createSign("UTF-8", finalParams,weixinPay.getPartner_key());
                        finalParams.put("paySign", finalSign);

发起支付

IWXAPI mIwxapi = WXAPIFactory.createWXAPI(PayActivity.this.getApplicationContext(), weixinPay.getApp_id());
                        mIwxapi.registerApp(weixinPay.getApp_id());
                        PayReq req = new PayReq();
                        req.appId = weixinPay.getApp_id();
                        req.partnerId = weixinPay.getPartner();
                        req.prepayId =  map.get("prepay_id");
                        req.packageValue = "Sign=WXPay";
                        req.nonceStr = finalParams.get("noncestr");
                        req.timeStamp = timeStamp;
                        req.sign = finalSign;
                        req.extData = "PayActivity";  // 额外参数,可以在回调那得到该数据,可用于区分回调
                        if (req.checkArgs()) {
                            mIwxapi.sendReq(req);
                        } else {
                            mHandler.sendEmptyMessage(WX_PAY_EROR);
                        }
什么?没有回调?一闪就什么都没了?

坑啊坑
回调的activity配置要设置android:exported="true"

        <activity android:name=".wxapi.WXPayEntryActivity"
            android:exported="true"
            android:launchMode="singleTop">
        </activity>

当然还有回调处理

public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {

    private IWXAPI api;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        PayConfigBean o = Hawk.get(Define.SP_NAME_PAYCONFIG);
        if (o!=null && o.getWeixin_pay()!=null) {
            api = WXAPIFactory.createWXAPI(this, o.getWeixin_pay().getApp_id());
            api.handleIntent(getIntent(), this);
        }
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        if (api!=null) {
            api.handleIntent(intent, this);
        }
    }

    @Override
    public void onReq(BaseReq req) {
    }

    @Override
    public void onResp(final BaseResp resp) {
        if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
            if (resp.errCode == 0) {
                sendBroadcast(new Intent(Define.sendBroadcast_pay_success));
            } else {
                String errStr = resp.errStr;
                if (errStr == null) {
                    if (resp.errCode == -2) {
                        errStr = "用户取消";
                    } else {
                        errStr = "支付失败:" + resp.errCode;
                    }
                    Toast.makeText(WXPayEntryActivity.this,errStr,Toast.LENGTH_SHORT).show();
                }
            }
        }
        finish();
    }
}

到此一下午就这样在微信支付的坑中度过了,记载一下!!! 整体代码有空再贴吧,9:30啦,下班明天早上可以10点上班ok

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值