前些天帮朋友实现了一个微信扫码的接口,在之前也是不会搞这个东西,抱着试试的心态就开始看各种文档和blogs,大多数人都在吐槽微信给的java调用微信接口文档太含糊,而且网上的查到的资料也不详细,只有大概的开发流程没有太多细节上的讲解,最后还是花了一些钱买了一套视频和demo(理清了我的思路),最后完成了开发,如果有同学需要的话可以给我留言,我将免费提供帮助(可能不能及时回复)。
(在这之间我们需要申请商家号)首先我们要理清思路要怎么进行扫码接口调用开发:
图自己画的不太好,见谅。
从图中可以看出微信扫码支付的大概流程,首先是下单,我们需要拼接一个xml(包含商户平台ID,价格,随机数等信息)发送给微信接口,首先我们要知道,我们和微信接口之间的信息传递都需要使用xml,所以在开发中xml信息的拼接和解析是至关重要的。
①
发送统一下单的xml,首先我们应该知道需要将哪些信息拼接成xml信息:
这个是我们的一些必须清单:
APP_ID
这个APP_ID我就填错了(当时没找到APP_ID),一直报空指针错误。
MCH_ID这个是商家号:
就是我涂鸦的那个部分,申请过商户平台账号后会给你分配一个账号。
API_KEY:
在这个页面可以查看API_KEY,如果忘了就重置一下。
UFDODER_URL:这个是固定值,是我们统一下单的目的url:
https://api.mch.weixin.qq.com/pay/unifiedorder
NOTIFY_URL:这个是回调地址(支付成功后,微信接口返回给我们的url,一定要是公网可以访问的,不能是我们的本地localhost)。
CREATE_IP:这个东西可有可无,随便填写一个ip就行了。
//返回可生成二维码的urlCode,这里面用到了一些工具(拼接解析xml和发送http请求)
String out_trade_no = "" + System.currentTimeMillis(); //订单号
// 账号信息
String appid = PayConfigUtil.APP_ID; // appid
//String appsecret = PayConfigUtil.APP_SECRET; // appsecret
String mch_id = PayConfigUtil.MCH_ID; // 商业号
String key = PayConfigUtil.API_KEY; // key
String currTime = PayToolUtil.getCurrTime();
String strTime = currTime.substring(8, currTime.length());
String strRandom = PayToolUtil.buildRandom(4) + "";
String nonce_str = strTime + strRandom;
// 获取发起电脑 ip
String spbill_create_ip = PayConfigUtil.CREATE_IP;
// 回调接口
String notify_url = PayConfigUtil.NOTIFY_URL;
String trade_type = "NATIVE";
SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();
packageParams.put("appid", appid);
//packageParams.put("appsecret", appsecret);
packageParams.put("mch_id", mch_id);
//随机字符串
packageParams.put("nonce_str", nonce_str);
packageParams.put("body", "报名费用"); //(调整为自己的名称)
packageParams.put("out_trade_no", out_trade_no);
if(productId.equals("1")) {
packageParams.put("total_fee", "1");//一级费用240元,价格的单位为分
}else if(productId.equals("2")) {
packageParams.put("total_fee", "28000");
}else if(productId.equals("3")) {
packageParams.put("total_fee", "32000");
}else if(productId.equals("4")) {
packageParams.put("total_fee", "36000");
}else if(productId.equals("5")) {
packageParams.put("total_fee", "42000");
}else{
packageParams.put("total_fee", "48000");
}
packageParams.put("spbill_create_ip", spbill_create_ip);
packageParams.put("notify_url", notify_url);
packageParams.put("trade_type", trade_type);
String sign = PayToolUtil.createSign("UTF-8", packageParams,key);
packageParams.put("sign", sign);
String requestXML = PayToolUtil.getRequestXml(packageParams);
requestXML= requestXML.replaceAll("__", "_");
System.out.println("请求xml:"+requestXML);
//记录请求商户订单号
Map<String,String> out_map = XMLUtil4jdom.doXMLParse(requestXML);
String out_no = (String) out_map.get("out_trade_no");
System.out.println("第一次商户号:"+out_no);
//接下来存储商户订单号和用户(身份证号)对应关系
//这里执行数据库逻辑
String resXml = HttpUtil.postData(PayConfigUtil.UFDODER_URL, requestXML);
System.out.println("响应xml:"+resXml);
Map<String,String>map = XMLUtil4jdom.doXMLParse(resXml);
String urlCode = (String) map.get("code_url"); //code_url
//System.out.println(urlCode);
return urlCode;
我们需要知道首先我们应该将需要发送的信息放入map中,然后将它们拼接成xml,然后发送给微信,然后接收来自微信的xml,我们解析这个xml,获得url_code,就是生成二维码的content,然后使用谷歌的生成代码zxing进行生成二维码,最后将生成的二维码通过你想要的方式发送给前台。
——————————————————————————————
接下来就是扫码过后进行信息的回调了(例如对用户下单进行数据库操作),可以使用外部订单号来唯一标识订单和用户。
需要对微信接口回调的数据(xml)进行解析,比对result_code结果,如果是SUCCESS就是支付成功,如果是FALSE就是支付失败。
//读取参数
//System.out.println("haha");
InputStream inputStream ;
StringBuffer sb = new StringBuffer();
inputStream = request.getInputStream();
String s ;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
while ((s = in.readLine()) != null){
sb.append(s);
}
in.close();
inputStream.close();
System.out.println("回调xml:"+sb.toString());//测试
//解析xml成map
Map<String, String> m = new HashMap<String, String>();
try {
m = XMLUtil4jdom.doXMLParse(sb.toString());
} catch (JDOMException e) {
e.printStackTrace();
}
SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();
Iterator it = m.keySet().iterator();
while (it.hasNext()) {
String parameter = (String) it.next();
String parameterValue = m.get(parameter);
String v = "";
if(null != parameterValue) {
v = parameterValue.trim();
}
packageParams.put(parameter, v);
}
// 账号信息
String key = PayConfigUtil.API_KEY; // key
//判断签名是否正确
if(PayToolUtil.isTenpaySign("UTF-8", packageParams,key)) {
//------------------------------
//处理业务开始
//------------------------------
String resXml = "";
if("SUCCESS".equals((String)packageParams.get("result_code"))){
String fee = (String)packageParams.get("total_fee");
int level;
if(fee.equals("24000")) {
level = 1;
}else if(fee.equals("28000")) {
level = 2;
}else if(fee.equals("32000")) {
level = 3;
}else if(fee.equals("36000")) {
level = 4;
}else if(fee.equals("42000")) {
level = 5;
}else{
level = 6;
}
// 这里是支付成功
//接下来对数据库进行操作 ,先查询订单号对应的身份证号
String out_no = (String)packageParams.get("out_trade_no");
System.out.println("商家订单号:"+out_no);
// Connection conn = DBUtils.getConnection();
// String sql="insert into uers values(?,?)";
//
// try {
// PreparedStatement pstmt=(PreparedStatement) conn.prepareStatement(sql);
// pstmt.setInt(0, 321333);
// pstmt.setInt(1,level);
// } catch (SQLException e) {
// e.printStackTrace();
// }
//通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
} else {
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
}
//------------------------------
//处理业务完毕
//------------------------------
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
System.out.println("success");
out.flush();
out.close();
}
这些是用到的工具类:
关于工具类有点多,这里就不一一给出了,如果有需要的小伙伴可以留言你的邮箱,我会一一发给你们(可能不及时)。
这个例子是自己第一次做的,所以有很多不好的地方,所以还请包含。
限于篇幅,就讲到这里,如有错误欢迎指正。