最近公司项目不太紧张,领导让研究一下react.js方面的东西,其中有用到微信支付,app项目也准备想要集成微信支付的功能,之前有做过微信支付,基本都是复制之前的demo进行集成,没太深入去了解过,最近没事就把之前的demo给整理一下,在这里做一下记录。
首先需要在 微信的开放平台注册一个账号,注册流程详见。注意注册填写的邮箱,以后申请支付成功后,商户号、登录密码、API密钥等信息会发送到该邮箱,当有了微信的开放平台的账号后,就可以在管理中心创建应用,应用创建后需要七个工作日的审核,审核成功后,就可以申请该应用的微信支付了,设置android和ios的签名。(开通微信支付需要缴纳300元)。
**微信支付申请成功后,就可以调用微信支付的统一下单接口,统一下单接口接口请求参数是xml方式请求,返回的参数也是xml,这个需要注意,具体实现如下:

* 首先是统一下单的参数设置(参数添加是按照ASCII码从小到大排序(字典序),因为在签名时候需要这个顺序)*

/**
*这里说一下为什么用LinkedHashMap,没有用HashMap。因为HashMap存储兼*键值对是无序的,LinkedHashMap输出的顺序和输入的相同,在签名的时候,需要map中储存的顺序。
*/
private String setPlaceOrderParameter(String tradeType) {
        Map<String, String> map = new LinkedHashMap<>();
        map.put("appid", "wx2c3865766f57ccb0");// 微信支付分配的公众账号ID(企业号corpid即为此appId)
        map.put("attach", "支付测试");// 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。
        map.put("body", "JSAPI支付测试");// 商品简单描述,该字段请按照规范传递
        map.put("mch_id", "1344819501");// 微信支付分配的商户号
        map.put("nonce_str", genNonceStr());// 随机字符串,长度要求在32位以内。推荐随机数生成算法
                                            // 1add1a30ac87aa2db72f57a2375d8fec
        map.put("notify_url", "http://wxpay.wxutil.com/pub_v2/pay/notify.v2.php");// 异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。
//      map.put("openid", "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o");// trade_type=JSAPI时(即公众号支付),此参数必传,此参数为微信用户在商户对应appid下的唯一标识https://pay.weixin.qq.com/wiki/doc/api/wap.php?chapter=4_4
                                                            // 获取的地址
        map.put("out_trade_no", genOutTradNo());// 商户系统内部订单号,要求32个字符内、且在同一个商户号下唯一
        map.put("spbill_create_ip", "127.0.0.1");// APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP
        map.put("total_fee", "100");// 订单总金额,单位为分
        map.put("trade_type", tradeType);// 取值如下:JSAPI,NATIVE,APP,MWEB等

        String sign = getSign(map);
        map.put("sign", sign);// 通过签名算法计算得出的签名值

        String xmlstring = toXml(map);
        return xmlstring;
    }

* 代码注解很详细就不多记录了,下面是签名算法*

/**
     * 通过签名算法计算得出的签名值
     */
    private String getSign(Map<String, String> map) {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            sb.append(entry.getKey());
            sb.append('=');
            sb.append(entry.getValue());
            sb.append('&');
        }
        // 拼接API密钥
        sb.append("key=");
        sb.append("UrS7zXfUTf5Pq7s8l0WpP7MvQyQRIhPN");
        System.out.println(">>>>>>signsb>" + sb.toString());
        String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase(Locale.CHINA);
        System.out.println(">>>>>>sign>" + packageSign);
        return packageSign;
    }

*下面代码是吧参数变成xml格式的字符串*

/**
     * 拼接成xml形式的字符串,以供统一下单使用
     */
    private String toXml(Map<String, String> map) {
        StringBuilder sb = new StringBuilder();
        sb.append("<xml>");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            sb.append("<" + entry.getKey() + ">");
            sb.append(entry.getValue());
            sb.append("</" + entry.getKey() + ">");
        }
        sb.append("</xml>");
        System.out.println(">>>>>>xml>" + sb.toString());
        return sb.toString();
    }

*统一下单网络请求,用的HttpURLConnection请求,放在异步线程(官方给的demo用的是httpclient)*

private Map<String, String> placeArder() {
        try {
            // 创建url资源
            URL url = new URL("https://api.mch.weixin.qq.com/pay/unifiedorder");// 统一下单接口
                                                                                // 微信的
            // 建立http连接
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            // 设置允许输出
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 设置不用缓存
            conn.setUseCaches(false);
            // 设置传递方式
            conn.setRequestMethod("POST");
            // 设置维持长连接
            conn.setRequestProperty("Connection", "Keep-Alive");
            // 设置文件字符集:
            conn.setRequestProperty("Charset", "UTF-8");
            // 转换为字节数组
            byte[] data = xmlString.getBytes();
            // 设置文件长度
            conn.setRequestProperty("Content-Length", String.valueOf(data.length));
            // 设置文件类型:
            conn.setRequestProperty("contentType", "text/xml");
            // 开始连接请求
            conn.connect();
            OutputStream out = conn.getOutputStream();
            // 写入请求的字符串
            out.write(data);
            out.flush();
            out.close();
            System.out.println(conn.getResponseCode());
            // 请求返回的状态
            if (conn.getResponseCode() == 200) {
                System.out.println(">>>>>>>>连接成功");
                // 请求返回的数据
                InputStream in = conn.getInputStream();
                String a = null;
                try {
                    byte[] data1 = new byte[in.available()];
                    in.read(data1);
                    // 转成字符串
                    a = new String(data1);
                    System.out.println(">>>>a>" + a);
                    return decodeXml(a);//把返回的xml字符串转化成map对象
                } catch (Exception e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                    return null;
                }
            } else {
                System.out.println("no++");
                return null;
            }

        } catch (Exception e) {
            return null;
        }
    }

*下面是统一下单接口返回的xml参数转化成map储存*

public Map<String, String> decodeXml(String content) {

        try {
            Map<String, String> xml = new HashMap<String, String>();
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(new StringReader(content));
            int event = parser.getEventType();
            while (event != XmlPullParser.END_DOCUMENT) {

                String nodeName = parser.getName();
                switch (event) {
                case XmlPullParser.START_DOCUMENT:

                    break;
                case XmlPullParser.START_TAG:

                    if ("xml".equals(nodeName) == false) {
                        // 实例化student对象
                        xml.put(nodeName, parser.nextText());
                    }
                    break;
                case XmlPullParser.END_TAG:
                    break;
                }
                event = parser.next();
            }

            return xml;
        } catch (Exception e) {
            Log.e("orion-e--->", e.toString());
        }
        return null;
    }

*下面随机数生成代码*

/**
     * 获取OutTradNo可根据用户自行更改 商户系统内部订单号,要求32个字符内、且在同一个商户号下唯一
     * 
     * @return
     */
    private String genOutTradNo() {
        Random random = new Random();
        int time = (int) System.currentTimeMillis();
        return MD5.getMessageDigest(String.valueOf(random.nextInt(10000) + time).getBytes());
    }

*最后贴出MD5的类*

public class MD5 {

    private MD5() {}

    public final static String getMessageDigest(byte[] buffer) {
        char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("MD5");
            mdTemp.update(buffer);
            byte[] md = mdTemp.digest();
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            return null;
        }
    }
}

**至此微信支付的统一下单接口已近完成,具体的中间出现的错误码查看微信统一下单返回错误码,页面最下面。android如果统一下单成功后,项目集成了微信支付的SDK,开放平台设置的签名和包名正确的话,用如下代码就可以调起微信支付了
**

/**
*调起微信支付还需要的重新签名
*/
msgApi = WXAPIFactory.createWXAPI(context, null);
        req = new PayReq();
        req.appId = "APP_ID";
        req.partnerId = "MCH_ID";
        req.prepayId = placeArder().get("prepay_id");
        req.packageValue = "Sign=WXPay";
        req.nonceStr = genOutTradNo();
        req.timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
        Map<String, String> map = new LinkedHashMap<>();
        map.put("appid", req.appId));
        map.put("noncestr", req.nonceStr));
        map.put("package", req.packageValue));
        map.put("partnerid", req.partnerId));
        map.put("prepayid", req.prepayId));
        map.put("timestamp", req.timeStamp));
        req.sign = getSign(map);
        msgApi.registerApp("APP_ID");
        msgApi.sendReq(req);

到此android微信集成就完成了。。。在此记录一下