最近公司项目不太紧张,领导让研究一下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微信集成就完成了。。。在此记录一下