开发之前的准备工作:
APP支付申请条件
申请成为APP支付商户需要满足以下条件:
1、APP支付商户,须拥有微信开放平台(http://open.weixin.qq.com)的APPID;
2、APP应用必须通过开发者认证。
APP支付申请方法
1、 登陆开放平台(open.weixin.qq.com),选择"管理中心"=》"移动应用",选择需要申请支付的应用,点击"查看"=》 "微信支付"=》 "申请开通",申请流程与公众号支付申请流程一致。如下图:
进入管理中心,点击移动应用
选择需申请支付功能的应用,点击申请开通;
进入申请页面,开始填写资料。再依次根据页面指引操作;
温馨提示:商户申请微信认证的主体与申请开通微信支付的主体需保持一致。
全部完成后可确认提交审核,将在1-5个工作日内审核完成。
2、开户成功,登录商户平台进行金额验证
提交资料审核通过之后,微信平台会发送商户平台的帐号密码到你填写的邮箱中,并且还会打入一笔验证款项(随机金额)到你的结算银行账户中。
接下来你所需要做的就是查看银行账户的转账流水(转账方的名义是财付通),然后登录微信商户平台进行金额验证。
① 输入你在邮箱中得到的帐号密码
【!!!注意!!!】:
在输入密码的时候需要安装一个安全插件,按要求安装插件之后,关闭浏览器然后重新打开,再次输入密码的时候如果还提示需要安装插件,那么请查看一下浏览器的地址栏是什么模式。文主用的是360极速浏览器,所以必须是要在【兼容模式】下才能够正常输入密码,注意啦!是!!!兼容模式!!!
②接下来就是激动人心的时刻了
选择验证账户,输入微信支付给公司对公账户打的款项金额
【注意!!!】:只有三次验证机会哦,所以要慎重!
验证成功
③签署微信支付协议,完成微信支付申请
整个申请过程就这样完成啦,后面对应用的设计和开发,支付接口的调试就属于后台技术人员的活了。如果有什么还不清楚的地方的话,可以艾特文主,看到后能回答的都会帮你们解答。
这个时候就该技术人员上场了。
正式开发工作。
1.首先我们先来看一下微信支付的流程。
https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_3
2.看完支付流程,我们就应该去调微信[统一下单]生成预付单
发送一个支付请求 @RequestMapping("/toGetWxPay") @ResponseBody public JSONObject toGetWxPay(HttpServletRequest request) { String oid = request.getParameter("oid"); String type = request.getParameter("type"); String string = request.getRequestURL().toString(); String calBack_url = string.substring(0,string.lastIndexOf("/")); calBack_url+="/appPayNotify"; return wechatService.getWxPayAPP(oid, type, request.getRemoteAddr(), calBack_url); } public JSONObject getWxPayAPP(String oid, String type, String spbill_create_ip, String calBack_url) { // 支付map Map
order = null; if ("single".equals(type)) { // 单个订单 order = orderBillService.toPayOrder(oid, false); order.put("TYPE", "single"); } else { // 多个订单 order = orderBillService.toPayOrder(oid, true); order.put("TYPE", "many"); } order.put("OID", oid); Double ormoney = Double.valueOf(order.get("ormoney").toString()); order.put("ORMONEY", ormoney); logger.info("订单:" + order); // 调用第三方支付方法发送支付请求 return wechatInterface.getWxPayAPP( propertyUtil.getProperty("wechat.app.appid"), propertyUtil.getProperty("wechat.app.mch_id"), propertyUtil.getProperty("wechat.app.mch_key"), spbill_create_ip, order, calBack_url); } 发起预支付请求 public JSONObject getWxPayAPP(String appId, String mchId, String mchKey, String spbill_create_ip, Map order, String calBack_url) { // 支付map Map resmap = new HashMap (); resmap.put("appid", appId); resmap.put("mch_id", mchId); resmap.put("device_info", "WEB"); String nonceStr = UUID.randomUUID().toString().replaceAll("-", ""); resmap.put("nonce_str", nonceStr); resmap.put("body", "集团名称"); // 签名 resmap.put("attach", order.get("TYPE")); // 商户订单号 resmap.put("out_trade_no", order.get("OID")); // 货币类型 resmap.put("fee_type", "CNY"); // 总金额分 int order_amount = 0; try { double money = Double.parseDouble(String.valueOf(order .get("ORMONEY"))) * 100; order_amount = (int) money; } catch (Exception e) { e.printStackTrace(); } resmap.put("total_fee", order_amount); // 终端IP APP和网页支付提交用户端ip resmap.put("spbill_create_ip", spbill_create_ip); // 起始时间 resmap.put("time_start", ToolUtil.getFormatedNowDateTime()); // 结束时间 resmap.put("time_expire", ToolUtil.getFormatedTenDaysDateTime()); // 通知地址 resmap.put("notify_url", calBack_url); // 交易类型取值如下:JSAPI,NATIVE,APP resmap.put("trade_type", "APP"); // 支付签名采用md5加密2次 String sign = SignUtil.createMd5Sign(resmap, mchKey); logger.info("加密前map:" + resmap); // 生成加密签名 resmap.put("sign", sign); logger.info("sign:" + sign); return toPayAPP(resmap, appId, mchKey); } 发送支付请求并返回支付数据 private JSONObject toPayAPP(Map resmap, String appId, String mchKey) { String payInfoToXml = MessageUtil.mapToXml(resmap); logger.info("统一订单xml:" + payInfoToXml); Map pay = WeixinUtil.toPay(payInfoToXml); logger.info("支付返回map:" + pay); // 交易成功返回信息处理 if (pay != null && pay.containsKey("result_code") && "SUCCESS".equals(pay.get("result_code"))) { Map map = new HashMap (); map.put("appid", appId); map.put("noncestr", UUID.randomUUID().toString() .replaceAll("-", "")); map.put("package", "Sign=WXPay"); map.put("partnerid", pay.get("mch_id")); map.put("prepayid", pay.get("prepay_id")); map.put("timestamp", System.currentTimeMillis()/1000); String paySign = SignUtil.createMd5Sign(map, mchKey); map.put("sign", paySign); logger.info("返回给页面的map:" + map); return JSONObject.fromObject(map); } return null; } 3.接下来我们来看看支付成功后的回调。
@RequestMapping("/appPayNotify") public void appPayNotify(HttpServletRequest request, HttpServletResponse response) { try { // 将请求、响应的编码均设置为UTF-8(防止中文乱码) request.setCharacterEncoding("UTF-8"); String respMessage = wechatService.appPayNotify(MessageUtil .parseXml(request.getInputStream())); logger.info("回复内容:" + respMessage); response.setContentType("application/xml;charset=utf-8"); // 调用核心业务类接收消息、处理消息 if (respMessage != null) { // 响应消息 response.getWriter().print(respMessage); // out.close(); } } catch (Exception e) { e.printStackTrace(); } } @Override public String appPayNotify(Map
requestMap) { try { // 是否是微信发来的 if (wechatInterface.isWechatSign(requestMap, propertyUtil.getProperty ("wechat.app.mch_key"))==false) { return null; } //处理多次回调 Map callBack = transactionPayRecordService.findCallBack (requestMap.get("transaction_id")); if(callBack!=null){ return " "; } Map tMap = new HashMap (); tMap.put("is_success", "失败"); tMap.put("verifyStatus", "false"); tMap.put("transaction_type", "1"); tMap.put("notify_time", requestMap.get("time_end")); if ("SUCCESS".equals(requestMap.get("return_code"))) { if ("SUCCESS".equals(requestMap.get("result_code"))) { logger.info("验证成功!"); // 订单号 String oid = requestMap.get("out_trade_no"); String type = requestMap.get("attach"); String transaction_id = requestMap .get("transaction_id"); Map param = new HashMap (); param.put("transaction_id", transaction_id); param.put("payment_method", "3"); if ("single".equals(type)) { param.put("oid", oid); // 单个订单 tMap.put("body", "单个支付"); } else { // 多个订单oid是支付宝号 param.put("opayid", oid); tMap.put("body", "批量支付"); } // 修改订单支付时间 Integer state = orderBillService.setOrderSuccess(param); ogger.info("微信支付成功!"); //订单支付成功, 处理业务逻辑 // 记录日志 tMap.put("callback_payid", transaction_id);// 微信支付交易号 tMap.put("total_fee", requestMap.get("total_fee"));// 交易金额 tMap.put("title", "微信支付"); if (state != null && state > 0) { tMap.put("is_success", "成功"); tMap.put("trade_status", "支付成功");// 支付状态 } else { tMap.put("trade_status", "支付失败");// 支付状态 } tMap.put("verifyStatus", "true"); tMap.put("payid", requestMap.get("out_trade_no")); tMap.put("payment_method", "3"); tMap.put("remarks", JSONObject.fromObject(requestMap) .toString());// 备注 transactionPayRecordService.save(tMap); return " "; } else { logger.info("result_code不存在"); logger.info(requestMap); } transactionPayRecordService.save(tMap); } else { logger.info("return_code不存在"); logger.info(requestMap); } } catch (Exception e) { e.printStackTrace(); } return null; }
到这里差不多这个流程就算完了!!!!
说一下在开发过程当中本人遇到的问题:
1.每个微信号只能支付一次,之后就一直是error:{"code":-100,"message":"[payment微信:-1]General errors"}
解决办法是,清理了一下微信缓存。
2.微信支付成功后的回调,(支付成功后,微信会回调好几次)
解决办法,这个时候我们应该在后台做逻辑判断,回调成功修改订单状态,保存支付信息,给微信返回信息,告诉微信已经成功回调,
response.setContentType("application/xml;charset=utf-8");
我开始写的是text,微信一直回调,后来改成application,微信只调了一次。
最后给大家总结一下
1.微信支付必须apk包,本地调试支付不能成功,因为Huilder上的包名和密钥和你app申请的微信支付的包名和密钥是不一样的。所以支付失败。
2.调用微信app统一支付,生成预付订单,这时候微信会返回来success,和微信预支付唯一标示,(prepay_id)
3.注意预支付成功之后参数的顺序
{
appid=wx123......
noncestr=不长于32位的随机字符串
package=Sign=WXPay,
partnerid=商户ID,
prepayid=预支付成功返回的预支付单号,
sign=MD5签名(记得按顺序toUpperCase转换为大写),
timestamp=时间戳10位,
}
4.注意签名和密钥
5.切记记得清理微信缓存,不是微信聊天记录,是微信缓存。
6,查看appid是否配置(离线打包在AndroidManifest.xml配置,云打包在manifest.json配置)
7,申请appid时所用证书签名与apk的签名证书必须一致
8,申请appid时填写包名与打包时候所填写包名必须一致 开发平台配置的包名与签名跟apk的签名文件是否一致
9,服务生成订单时设置的appid、appkey等参数是否正确10,调统一下单是参数变量名必是小写,total_fee以分为单位,时间时间戳10位。