首先 这个微信支付 官网的demo 是有bug的 研究了好几天 吸取了一些大神的指点才成功,还有csdn一些人发的代码都不全太坑,资源还少,今天我就整合一下,
把我的一些心得分享给大家 。
之前遇到的一些问题:
预支付id获取失败,签名失败,您没有JSAPI支付权
预支付id获取失败的原因是: 交易类型这是成默认APP ,一些 随机数位数 都要跟api 对应上,加密的时候api的那些字段都要排序好按照(a-b),获取的时候 需要传递两个参数 (统一下单接口地址,拼接成的xml)。
签名失败的原因是:预支付id获取失败,加密的时候排序的顺序,加密用MD5 32位转换大写!
您没有JSAPI支付权: 商户的一些id 一些号 都要对应上
以上就是大致的错误! 现在上代码 !
首先 这个微信支付 官网的demo 是有bug的 研究了好几天 吸取了一些大神的指点才成功,还有csdn一些人发的代码都不全太坑,资源还少,今天我就整合一下,
把我的一些心得分享给大家 。
实体层代码
- package com.model;
- /**
- * 微信支付实体
- * @author 裴广庭
- *
- */
- public class WxPay {
- private String orderId;//订单号
- private String totalFee;//金额
- //private String spbillCreateIp;//订单生成的机器 IP
- private String notifyUrl;//这里notify_url是 支付完成后微信发给该链接信息,可以判断会员是否支付成功,改变订单状态等
- private String body;// 商品描述根据情况修改
- private String openId;//微信用户对一个公众号唯一
- public String getOrderId() {
- return orderId;
- }
- public void setOrderId(String orderId) {
- this.orderId = orderId;
- }
- public String getTotalFee() {
- return totalFee;
- }
- public void setTotalFee(String totalFee) {
- this.totalFee = totalFee;
- }
- // public String getSpbillCreateIp() {
- // return spbillCreateIp;
- // }
- // public void setSpbillCreateIp(String spbillCreateIp) {
- // this.spbillCreateIp = spbillCreateIp;
- // }
- public String getNotifyUrl() {
- return notifyUrl;
- }
- public void setNotifyUrl(String notifyUrl) {
- this.notifyUrl = notifyUrl;
- }
- public String getBody() {
- return body;
- }
- public void setBody(String body) {
- this.body = body;
- }
- public String getOpenId() {
- return openId;
- }
- public void setOpenId(String openId) {
- this.openId = openId;
- }
- }
单独写的微信商户平台信息的类
- package com.util.weixin;
- public class WeixinPayConstants {
- //微信支付商户开通后 微信会提供appid和appsecret和商户号partner
- public static final String appid = "****";//在微信开发平台登记的app应用
- public static final String appsecret = "****";
- public static final String partner = "****";//商户号
- //这个参数partnerkey是在商户后台配置的一个32位的key,微信商户平台-账户设置-安全设置-api安全
- public static final String partnerkey = "****";
- public static final String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
- //openId 是微信用户针对公众号的标识,授权的部分这里不解释
- public static final String openId = "";
- //微信支付成功后通知地址 必须要求80端口并且地址不能带参数
- public static final String notifyurl = "http://**.**.**.**:8080/zhihuishe/weixin/notify";
- }
- // 商户相关资料
- private static String appid = WeixinPayConstants.appid;
- private static String appsecret = WeixinPayConstants.appsecret;
- private static String partner = WeixinPayConstants.partner;
- private static String partnerkey = WeixinPayConstants.partnerkey;
- private static String notifyurl = WeixinPayConstants.notifyurl;
- @RequestMapping(value = "/wxPay", method = RequestMethod.GET)
- public void wxPay(HttpServletRequest request, HttpSession session,
- HttpServletResponse response) throws IOException {
- Tool tool = new Tool();
- String totalFee = request.getParameter("totalFee");
- String body = request.getParameter("body");
- WxPay tpWxPay = new WxPay();
- tpWxPay.setTotalFee(totalFee);
- tpWxPay.setBody(body);
- tpWxPay.setOrderId(tool.orderNo());
- Object obj = getPackage(request,response, tpWxPay);
- JSONArray json = JSONArray.fromObject(obj);
- response.setCharacterEncoding(Constants.ENCODING_UTF8);
- response.getWriter().print(json.toString());
- }
- /**
- * 获取请求预支付id报文
- * @return
- * @throws IOException
- */
- public static Object getPackage(HttpServletRequest request,HttpServletResponse response,WxPay tpWxPay)
- throws IOException {
- JSONObject retMsgJson = new JSONObject();
- String openId = WeixinPayConstants.openId;
- // 订单号
- String orderId = tpWxPay.getOrderId();
- // 附加数据 原样返回
- String attach = "";
- // 总金额以分为单位,不带小数点
- String totalFee = getMoney(tpWxPay.getTotalFee());
- // 订单生成的机器 IP
- //String spbill_create_ip = tpWxPay.getSpbillCreateIp();
- // 这里notify_url是 支付完成后微信发给该链接信息,可以判断会员是否支付成功,改变订单状态等。
- String notify_url = notifyurl;
- //交易类型
- String trade_type = "APP";
- // ---必须参数
- // 商户号
- String mch_id = partner;
- // 随机字符串
- String nonce_str = Tool.getRandom();
- // 商品描述根据情况修改
- String body = tpWxPay.getBody();
- // 商户订单号
- String out_trade_no = orderId;
- SortedMap<String, String> packageParams = new TreeMap<String, String>();
- packageParams.put("appid", appid);//应用ID ---微信开放平台审核通过的应用APPID
- packageParams.put("attach", attach);//附加数 ---附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
- packageParams.put("body", body);//商品描述
- packageParams.put("mch_id", mch_id);//商户号
- packageParams.put("nonce_str", nonce_str);//随机字符串
- packageParams.put("notify_url", notify_url);//通知地址 ---微信给发的回调地址,要放在公网
- packageParams.put("openid", openId);////用户标识
- packageParams.put("out_trade_no", out_trade_no);//商户订单号
- //packageParams.put("spbill_create_ip", spbill_create_ip);//手机端ip
- packageParams.put("total_fee", totalFee);//总金额
- packageParams.put("trade_type", trade_type);//交易类型
- RequestHandler reqHandler = new RequestHandler(request, response);
- reqHandler.init(appid, appsecret, partnerkey);
- //MD5加密
- String sign = reqHandler.createSign(packageParams);
- //拼接成xml 形式 生成预支付id---prepay_id
- String xml = "<xml>" + "<appid><![CDATA[" + appid + "]]></appid>"
- + "<attach><![CDATA[" + attach + "]]></attach>"
- + "<body><![CDATA[" + body + "]]></body>"
- + "<mch_id><![CDATA[" +mch_id + "]]></mch_id>"
- + "<nonce_str><![CDATA[" + nonce_str + "]]></nonce_str>"
- + "<notify_url><![CDATA[" + notify_url + "]]></notify_url>"
- + "<out_trade_no><![CDATA[" + out_trade_no + "]]></out_trade_no>"
- //+ "<spbill_create_ip><![CDATA[" + spbill_create_ip + "]]></spbill_create_ip>"
- + "<total_fee><![CDATA[" + totalFee + "]]></total_fee>"
- + "<trade_type><![CDATA[" + trade_type + "]]></trade_type>"
- + "<sign><![CDATA[" + sign + "]]></sign>" + "</xml>";
- String prepay_id = "";
- //统一下单接口地址
- String createOrderURL = WeixinPayConstants.createOrderURL;
- //获取预支付id
- prepay_id = new GetWxOrderno().getPayNo(createOrderURL, xml);
- System.out.println("获取到的预支付ID:" + prepay_id);
- // 获取到prepayid后对以下字段进行签名最终发送给app
- SortedMap<String, String> finalpackage = new TreeMap<String, String>();
- String timestamp = Sha1Util.getTimeStamp();
- finalpackage.put("appid", appid);
- finalpackage.put("timestamp", timestamp);
- finalpackage.put("noncestr", nonce_str);
- finalpackage.put("package", "Sign=WXPay");
- finalpackage.put("partnerid", mch_id);
- finalpackage.put("prepayid", prepay_id);
- //MD5签名
- String finalsign = reqHandler.createSign(finalpackage);
- System.out.println("签名" + finalsign);
- //打印方便看
- String finaPackage = "appid=" + appid + "&partnerid=" + mch_id
- + "&prepayid=" + prepay_id + "&package=" + "Sign=WXPay"
- + "&noncestr=" + nonce_str + "×tamp=" + timestamp
- + "&sign=" + finalsign;
- System.out.println("V3 jsApi package:" + finaPackage);
- //最后发给发给手机端
- retMsgJson.put("msg", "ok");
- retMsgJson.put("appid", appid);
- retMsgJson.put("prepayid", prepay_id);
- retMsgJson.put("partnerid", mch_id);
- retMsgJson.put("package", "Sign=WXPay");
- retMsgJson.put("noncestr", nonce_str);
- retMsgJson.put("timestamp", timestamp);
- retMsgJson.put("sign", finalsign);
- retMsgJson.put("sendUrl", notify_url);
- return retMsgJson;
- }
以上是 微信支付 , 支付完成后 微信会回调一些服务器 首先这里 项目一定要放在公网上面 因为 方便 微信访问! 下面是回调代码!
方便在服务器上排除错 我用最笨的方法 就是加打印 都打印到日志上了。。 shell 没有研究明白
在声明一下 !! 这个回调地址 必须放在公网上 言外之意 你想测试项目 必须把项目放在公网上 注意 端口号必须是8080!!!!!!!!!!!
public static final String notifyurl = "http://123.**.**.**:8080/zhihuishe/weixin/notify";
微信异步通知
- // 微信异步通知
- @RequestMapping(value = "/notify")
- @ResponseBody
- public String notify(HttpServletRequest request, HttpServletResponse response)
- throws Exception {
- String result;//返回给微信的处理结果
- String inputLine;
- String notityXml = "";
- request.setCharacterEncoding("UTF-8");
- response.setCharacterEncoding("UTF-8");
- response.setContentType("text/html;charset=UTF-8");
- response.setHeader("Access-Control-Allow-Origin", "*");
- //微信给返回的东西
- try {
- while ((inputLine = request.getReader().readLine()) != null) {
- notityXml += inputLine;
- }
- request.getReader().close();
- } catch (Exception e) {
- e.printStackTrace();
- result = setXml("fail","xml获取失败");
- }
- if (StringUtils.isEmpty(notityXml)) {
- result = setXml("fail","xml为空");
- }
- Map map = new GetWxOrderno().doXMLParse(notityXml);
- // 解析各种数据
- String appid = (String) map.get("appid");//应用ID
- String attach = (String) map.get("attach");//商家数据包
- String bank_type = (String) map.get("bank_type");//付款银行
- String cash_fee = (String) map.get("cash_fee");//现金支付金额
- String fee_type = (String) map.get("fee_type");//货币种类
- String is_subscribe = (String) map.get("is_subscribe");//是否关注公众账号
- String mch_id = (String) map.get("mch_id");//商户号
- String nonce_str = (String) map.get("nonce_str");//随机字符串
- String openid = (String) map.get("openid");//用户标识
- String out_trade_no = (String) map.get("out_trade_no");// 获取商户订单号
- String result_code = (String) map.get("result_code");// 业务结果
- String return_code = (String) map.get("return_code");// SUCCESS/FAIL
- String sign = (String) map.get("sign");// 获取签名
- String time_end = (String) map.get("time_end");//支付完成时间
- String total_fee = (String) map.get("total_fee");// 获取订单金额
- String trade_type = (String) map.get("trade_type");//交易类型
- String transaction_id = (String) map.get("transaction_id");//微信支付订单号
- SortedMap<String, String> parameters = new TreeMap<String, String>();
- // 数据加密
- parameters.put("appid", appid);//应用ID
- parameters.put("attach", attach);//商家数据包
- parameters.put("bank_type", bank_type);//付款银行
- parameters.put("cash_fee", cash_fee);//现金支付金额
- parameters.put("fee_type", fee_type);//货币种类
- parameters.put("is_subscribe", is_subscribe);//是否关注公众账号
- parameters.put("mch_id", mch_id);//商户号
- parameters.put("nonce_str", nonce_str);//随机字符串
- parameters.put("openid", openid);//用户标识
- parameters.put("out_trade_no", out_trade_no);// 商户订单号
- parameters.put("result_code", result_code);// 业务结果
- parameters.put("return_code", return_code);// SUCCESS/FAIL
- parameters.put("time_end", time_end);// 支付完成时间
- parameters.put("total_fee", total_fee);// 获取订单金额
- parameters.put("trade_type", trade_type);//交易类型
- parameters.put("transaction_id", trade_type);//微信支付订单号
- //加密前验证notify支付订单网关---https://gw.tenpay.com/gateway/simpleverifynotifyid.xml
- RequestHandler reqHandler = new RequestHandler(request, response);
- reqHandler.init(appid, appsecret, partnerkey);
- //MD5加密
- String endsign = reqHandler.createSign(parameters);
- System.out.println("**************************************************************************************************");
- System.out.println(appid+"-------------------应用ID");
- System.out.println(attach+"-------------------商家数据包");
- System.out.println(bank_type+"-------------------付款银行");
- System.out.println(cash_fee+"-------------------现金支付金额");
- System.out.println(fee_type+"-------------------货币种类");
- System.out.println(is_subscribe+"-------------------是否关注公众账号");
- System.out.println(mch_id+"-------------------商户号");
- System.out.println(nonce_str+"-------------------随机字符串");
- System.out.println(openid+"-------------------用户标识");
- System.out.println(out_trade_no+"-------------------获取商户订单号");
- System.out.println(result_code+"-------------------业务结果");
- System.out.println(return_code+"------------------- SUCCESS/FAIL");
- System.out.println(sign+"-------------------获取签名-微信回调的签名");
- System.out.println(time_end+"-------------------支付完成时间");
- System.out.println(total_fee+"-------------------获取订单金额");
- System.out.println(trade_type+"-------------------交易类型");
- System.out.println(transaction_id+"-------------------微信支付订单号");
- System.out.println(endsign+"-------------------第二次加密sign");
- System.out.println("**************************************************************************************************");
- // 验证签名
- if (sign.equals(endsign)) {
- result = setXml("SUCCESS", "OK");
- } else {
- System.err.println("签名不一致!");
- result = setXml("fail", "签名不一致!");
- }
- if (!"SUCCESS".equals("SUCCESS")) {
- System.err.println("微信返回的交易状态不正确(result_code=" + "SUCCESS" + ")");
- result = setXml("fail", "微信返回的交易状态不正确(result_code=" + "SUCCESS" + ")");
- }
- //如果成功写入数据库
- if ("SUCCESS".equals("SUCCESS")) {// 如果微信返回的结果是success,则修改订单状态
- //判断订单号是否重复
- List<CapitalTable> userList = cpitalTableService.queryOrder(out_trade_no);
- if (userList.size() > 0) {
- result = setXml("fail", "订单号重复");
- }else{
- CapitalTable capitalTable = new CapitalTable();
- UserAdmin userAdmin = new UserAdmin();
- userAdmin.setId(6);
- capitalTable.setCapital(total_fee);//金币
- capitalTable.setState("1");//类型:1充值2提问3回答
- capitalTable.setDatetime(new Date());//流入时间
- capitalTable.setOrderNo(out_trade_no);
- capitalTable.setUserAdmin(userAdmin);
- cpitalTableService.insertCapital(capitalTable);
- }
- }
- System.out.println("回调成功");
- System.out.println("----返回给微信的xml:" + result);
- return result;
- }
- //通过xml 发给微信消息
- public static String setXml(String return_code, String return_msg) {
- SortedMap<String, String> parameters = new TreeMap<String, String>();
- parameters.put("return_code", return_code);
- parameters.put("return_msg", return_msg);
- return "<xml><return_code><![CDATA[" + return_code + "]]>" +
- "</return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>";
- }
有的需求需要将元转成分
- /**
- * 元转换成分
- * @param money
- * @return
- */
- public static String getMoney(String amount) {
- if(amount==null){
- return "";
- }
- // 金额转化为分为单位
- String currency = amount.replaceAll("\\$|\\¥|\\,", ""); //处理包含, ¥ 或者$的金额
- int index = currency.indexOf(".");
- int length = currency.length();
- Long amLong = 0l;
- if(index == -1){
- amLong = Long.valueOf(currency+"00");
- }else if(length - index >= 3){
- amLong = Long.valueOf((currency.substring(0, index+3)).replace(".", ""));
- }else if(length - index == 2){
- amLong = Long.valueOf((currency.substring(0, index+2)).replace(".", "")+0);
- }else{
- amLong = Long.valueOf((currency.substring(0, index+1)).replace(".", "")+"00");
- }
- return amLong.toString();
- }
以上就是 微信支付的全过程 需要用到的工具包 我已经发布在csdn了 地址是 http://download.csdn.net/detail/qq_29739821/9702230