首先微信公众号支付分为两大部分:

1. 统一支付订单获取prepay_id;   2.前端调起微信支付页面

说一下大致流程

说白了就是打游戏,有一群小怪(参数)需要打过去,好不容易打过去了,出来了一个大boss sign(这个大boss是前面的小怪组合的),打完了这个大boss,去救公主,结果救公主需要将前面所有的怪物灵魂收集起来转换为龙珠(封装为xml字符串),然后消耗龙珠召唤神龙(用post发送请求接口),神龙(接口)给了你一个蛋(xml字符串),需要你打开(返回的xml字符串转换为map),蛋里面是钥匙(prepay_id).拿着钥匙,再去打小怪(参数),(小怪又组成了新的boss paySign,继续打完,拿着怪物灵魂去另一个世界(前端页面)用那个世界的秘术救回公主.

可以创建一个实体类:wechatPay(也可以不用,反正就是为了把那些固定的常量参数给统一放到一个地方)

public class weChatPay {
    /**
     * 公众号AppId
     */
   
public static final String APP_ID = "XXXXXXXX";
    /**
     * 微信支付商户号
     */
   
public static final String MCH_ID = "XXXXXXX";
    /**
     * 订单名称
     */
   
public  static final String BODY = "购买";
    /**
     * 通知地址(不能带参数)
     */
   
public static final String NOTIFY_URL = "http://XXXXXXXXXX";
    /**
     * 交易类型(微信公众支付)
     */
   
public static final String TRADE_TYPE = "JSAPI";
    /**
     * 设备号(微信公众支付)
     */
   
public  static final String DEVICE_INFO = "WEB";
    /**
     * 用钻石茶苑的IP地址经过MD5进行32位加密(商店统一下单KEY)

   */
   
public static final String KEY = "XXXXXXXXXX";
}

然后就是找到各种方法来获取参数了

公众号支付主要要用到这几个参数

appid  这个appid绝对是你的公众号的appid,商户也会给你一个应用appid别用那个,而且appid要在商户里面与微信公众号绑定起来,微信公众号的微信支付功能也一定要开通

body   这个就相当于标题了随便写个啥就行

mch_id 这个就是商户账号了,申请商户的时候会给的

nonce_str 这个是微信公众号支付需要的随机字符串这个在后面也会用到具体方法随便找啦(我这里是16位的)

/*** 生成16位随机编号*/public static String getNonce(){Random random = new Random();String letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";String numsLetters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";String agentCode = "";for (int i = 0; i < 16; i++) {agentCode += numsLetters.charAt(random.nextInt(letters.length()));}return agentCode;}

notify_url  回调地址,不知道做啥的反正设置一个外网可以访问的一个不带参数的地址就行,应该是接收微信返回的东西的(反正不设置不行,设置了我也不知道在哪里用到了...)

out_trade_no 商家的订单编号32位不重复随机字符串(使用UUID来创建的,本人菜狗子不考虑高并发)

/*** 获取32位商家订单号*/
public static String getUUID() {UUID uuid =UUID.randomUUID();String str = uuid.toString();// 去掉"-"符号String temp = str.substring(0, 8) +str.substring(9, 13) + str.substring(14, 18) + str.substring(19, 23) +str.substring(24);return  temp;}

spbill_create_ip:你的请求ip地址(直接获取本机ip )

total_fee:支付金额(单位:分)

trade_type: “JSAPI” 付款类型 反正只要是微信公众号支付就写这个(JSAPI)其他的得自己找哈

device_info: “WEB” 付款设备号也是固定的只要是微信公众号支付就是WEB其他的自己找

open_id:   openid就难了,可以找网上咋找的,我做的时候因为接入网站的时候就获取了code然后根据code又获取了access_token,然后又得到了json返回数据,json中就有openid,然后我就直接从进入网站的时候就将openid获取到了.

String code = request.getParameter("code");
    NetWorkHelper netHelper = new NetWorkHelper();
    String Url = String.format("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", weChatConfig.APP_ID,weChatConfig.APP_SEC,code);
    String result = netHelper.getHttpsResponse(Url,"");
    JSONObject json = JSON.parseObject(result);
    openid = json.getString("openid");//openid

这一段代码就是了.

sign : 签名

获取sign首先要把上面的所有的参数获取到

然后封装到一个sortedMap里传给生成签名的方法

生成签名的算法中需要用到MD5的算法,那个自己找,网上一大堆

生成签名的里面有一个KEY 这个key是固定的要绑定在微信公众号(还是商户我给忘了)上的秘钥(32位自己找一个固定的数字字母字符串就行,然后一定要在公众号/商户号里面绑定)

SortedMap<String, String> signParams = new TreeMap<>();signParams.put("appid", weChatPay.APP_ID);//app_idString body = new String(weChatPay.BODY.getBytes("utf-8"));signParams.put("body", body);//商品参数信息signParams.put("mch_id", weChatPay.MCH_ID);//微信商户账号signParams.put("nonce_str",nonceStr);//32位不重复的编号signParams.put("notify_url",weChatPay.NOTIFY_URL);//回调页面signParams.put("out_trade_no", orderId);//订单编号signParams.put("spbill_create_ip",SPBLING_CREATE_IP);//请求的实际ip地址signParams.put("total_fee",TOTAL_FEE);//支付金额 单位为分signParams.put("trade_type", weChatPay.TRADE_TYPE);//付款类型为APPsignParams.put("device_info",weChatPay.DEVICE_INFO);//付款设备号微信公众号支付signParams.put("openid",openid);String sign = createSign(signParams);//生成签名
/*** 微信支付签名算法sign* @param parameters* @return*/public static String createSign( SortedMap<String, String> parameters) {StringBuffer sb = new StringBuffer();Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)Iterator it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();Object v = entry.getValue();if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {sb.append(k + "=" + v + "&");}}sb.append("key=" + weChatPay.KEY);System.out.println("签名字符串:" + sb.toString());String sign = MD5Encryption.MD5(sb.toString()).toUpperCase();return sign;}

如果生成sign签名成功了

就把上面所有的参数包括sign的都给转换成xml字符串(人家要求的,具体的方法如下:)

/*** @author* @date* @Description:将请求参数转换为xml格式的string* @param parameters* @return*/public static String getRequestXml(SortedMap<String, String> parameters) throws UnsupportedEncodingException {StringBuffer sb = new StringBuffer();sb.append("<xml>");Set es = parameters.entrySet();Iterator it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();String v = (String) entry.getValue();if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");} else {sb.append("<" + k + ">" + v + "</" + k + ">");}}sb.append("</xml>");String prePayXml = sb.toString();return prePayXml;}

转换为xml后,就可以发送httppost请求去调用接口了

String orderUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";//下单接口String result = doHttpPost(requestXml,orderUrl);//以post请求的方式调用统一下单接口

具体post请求方法如下:

/*** 发送Http post请求* @param xmlInfo * xml格式的的字符串* @param URL*  请求url* @return 返回信息*/public static String doHttpPost(String xmlInfo, String URL) {System.out.println("发起的数据:" + xmlInfo);byte[] xmlData = xmlInfo.getBytes();InputStream instr = null;java.io.ByteArrayOutputStream out = null;try {URL url = new URL(URL);URLConnection urlCon = url.openConnection();urlCon.setDoOutput(true);urlCon.setDoInput(true);urlCon.setUseCaches(false);urlCon.setRequestProperty("content-Type", "application/json");urlCon.setRequestProperty("charset", "utf-8");urlCon.setRequestProperty("Content-length",String.valueOf(xmlData.length));System.out.println(String.valueOf(xmlData.length));DataOutputStream printout = new DataOutputStream(urlCon.getOutputStream());printout.write(xmlData);printout.flush();printout.close();instr = urlCon.getInputStream();byte[] bis = IOUtils.toByteArray(instr);String ResponseString = new String(bis, "UTF-8");if ((ResponseString == null) || ("".equals(ResponseString.trim()))) {System.out.println("返回空");}System.out.println("返回数据为:" + ResponseString);return ResponseString;} catch (Exception e) {e.printStackTrace();return "0";} finally {try {if(out!=null){out.close();}if(instr!=null){instr.close();}} catch (Exception ex) {return "0";}}}

我把整体的预支付封装在一个方法

/*** 微信预支付** @return*/public static String requestByWeiXinPay(String openid,String nonceStr,Long money,String orderId) throws Exception {String SPBLING_CREATE_IP="...";//访问ip//       String TOTAL_FEE = money1.toString();String TOTAL_FEE = "1";//测试用的钱String notify_url = weChatPay.NOTIFY_URL;//回调地址SortedMap<String, String> signParams = new TreeMap<>();signParams.put("appid", weChatPay.APP_ID);//app_idString body = new String(weChatPay.BODY.getBytes("utf-8"));//这一步处理是中文转码报错 body不是utf-8类型的错误,所以要将body单独转换为中文编码.signParams.put("body", body);//商品参数信息signParams.put("mch_id", weChatPay.MCH_ID);//微信商户账号signParams.put("nonce_str",nonceStr);//32位不重复的编号signParams.put("notify_url",weChatPay.NOTIFY_URL);//回调页面signParams.put("out_trade_no", orderId);//订单编号signParams.put("spbill_create_ip",SPBLING_CREATE_IP);//请求的实际ip地址signParams.put("total_fee",TOTAL_FEE);//支付金额 单位为分signParams.put("trade_type", weChatPay.TRADE_TYPE);//付款类型为APPsignParams.put("device_info",weChatPay.DEVICE_INFO);//付款设备号微信公众号支付signParams.put("openid",openid);String sign = createSign(signParams);//生成签名的方法(调用上文中的createSign方法就行)signParams.put("sign", sign);signParams.remove(weChatPay.KEY);//调用统一下单无需key(商户应用密钥)String requestXml = getRequestXml(signParams);//生成Xml格式的字符串String orderUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";//下单接口String result = doHttpPost(requestXml,orderUrl);//以post请求的方式调用统一下单接口return result;}

就是上面那些方法七七八八的合起来的总的方法

最终得到的结果result在后台打印一下就行,然后再服务器看一下返回的东西,有时候会包appid和mchid 不匹配就表示你的appid可能用的不是公众号的,或者公众号与商户没绑定.

当result获取到后,返回的也是xml的字符串所以又要转回map

/*** 将xml转换为map* @param xml* @return*/public static Map<String,String> turnString(String xml){Map<String,String >map = new HashMap<>();Document doc = null;try {doc= DocumentHelper.parseText(xml);Element rootElt = doc.getRootElement(); // 获取根节点  List<Element> list = rootElt.elements();//获取根节点下所有节点 for (Element element : list) { //遍历节点  map.put(element.getName(), element.getText()); //节点的name为map的key,text为map的value  }} catch (DocumentException e){e.printStackTrace();} catch (Exception e) {e.printStackTrace();}return map;}

然后获取到prepay_id

到现在预支付的部分就完成了

然后就开始第二部调起前端微信支付页面

第二部分差不多和第一部分

一样凑参数:

Appid

Mchid

这两个都是原来的就行

Nonce_str

这一个得重新调用方法创建新的字符串(有人说要和旧的一样,我不知道,反正众说纷纭,我自己新创建的是可以用的就行)

TimeStamp

时间戳(System.currentTimeMillis/1000就得到了当前时间的时间戳)

SignType  :“MD5” 固定的

Prepay_id  :获取到的

然后继续用前面的算法生成新的sign,当然参数要变成这几个

SortedMap<String,String> map1 = new TreeMap<>();map1.put("appId",weChatPay.APP_ID);map1.put("timeStamp",timeStamp);map1.put("nonceStr",nonceStr);map1.put("signType","MD5");map1.put("package","prepay_id="+prepayId);String sign = weChatPayConfig.createSign(map1);

注意啦,这里面的和前面不一样的有两点:

  1. 原来的是appid  现在的是appId有区分大小写,这种细节具体的看开发文档上的,那个是权威
  2. map1.put("package","prepay_id="+prepayId); 看清楚这里要经过处理的

然后要把这些参数传到你的前台去重要的事情就是必须是json格式

JSONObject json = new JSONObject();json.put("appId",weChatPay.APP_ID);json.put("timeStamp",timeStamp);json.put("nonceStr",nonceStr);json.put("signType","MD5");json.put("package","prepay_id="+prepayId);json.put("paySign",sign);

转换以后再传出去

下面这个是前端代码

获取到的东西转换为json

其他的参数按照下面的写就行了

<script>var json = eval(${resultMap}); //反正要返回的东西转换一下var appId = json.appId;var timeStamp = json.timeStamp;var nonceStr = json.nonceStr;var signType = json.signType;var package1 = json.package;var sign = json.paySign; function onBridgeReady(){WeixinJSBridge.invoke('getBrandWCPayRequest', {"appId":appId,   //公众号名称,由商户传入"timeStamp":timeStamp,  //时间戳,自1970年以来的秒数"nonceStr":nonceStr,   //随机串"package":package1,"signType":signType,    //微信签名方式:"paySign":sign    //微信签名},
            function(res){if(res.err_msg == "get_brand_wcpay_request:ok" ){//如果支付成功了//这里面就是你支付成功就得逻辑处理了,什么改数据啊,加表啊啥的就是这个了}function pay() {//这个方法是你的点击的方法,想啥时候调用这个方法就写这里面,当然只有微信浏览器有效if (typeof WeixinJSBridge == "undefined"){if( document.addEventListener ){document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);}else if (document.attachEvent){document.attachEvent('WeixinJSBridgeReady', onBridgeReady);document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);}}else{onBridgeReady();}}
</script>

差不多就这么多了,各种菜鸡儿操作乱七八糟拼凑起来的,大量的不足还请多多指教!

微信公众号支付---菜鸡儿心得相关推荐

  1. JAVA微信支付(微信公众号支付JSAPI)

    JAVA开发微信支付-公众号支付/微信浏览器支付(JSAPI) 写本篇博客其一是因为最近做的项目在用这个功能,通过本篇博客进行一个全局的梳理,其二呢,也就是想趁着思路清晰,把心得记录下来,分享给大家, ...

  2. vue 调用共众url_vue单页面,在微信公众号支付中遇到的URL未注册BUG解决方法-Go语言中文社区...

    今天在做微信公众号支付的时候,遇到一个bug,在当前支付页面点击支付,就会报错,提示当前页面的URL未注册.如下图: 但是,这个URL我们是在后台微信公众号配置了的,所以说不会出错. 但是我们刷新一次 ...

  3. yii2嵌入微信公众号支付

    序言 随着微信被越来越多的人使用,微信商城成为如今的热门.每一个商城都需要有自己的支付方式,微信商城也不例外.微信公众号支付就是微信商城的一种支付方式,微信支付随着微信的推广使用也被广泛应用.今天我主 ...

  4. 微信公众号支付调用chooseWXPay提示“errmsg choosewxpay fail”

    微信公众号支付一直提示"errmsg choosewxpay fail",也没有提示具体错误信息,签名没有问题(签名验证地址:https://pay.weixin.qq.com/w ...

  5. 微信公众号页面支付接口java,[Java教程]微信公众号支付(三):页面调用微信支付JS并完成支付...

    [Java教程]微信公众号支付(三):页面调用微信支付JS并完成支付 0 2015-09-15 15:00:30 一.调用微信的JS文件 1.首先要绑定[JS接口安全域名],"公众号设置&q ...

  6. js如何调用h5的日期控价_微信公众号支付H5调用支付解析

    最近项目需要微信支付,然后看了下微信公众号支付,虽然不难,但是细节还是需要注意的,用了大半天时间写了个demo,并且完整的测试了一下支付流程,下面分享一下微信公众号支付的经验. 一.配置公众号微信支付 ...

  7. vue 微信公众号支付接口_基于vue的h5项目之支付宝支付与微信支付

    本文仅记录基于vue开发h5项目过程中使用支付宝和微信支付过程中的重点与槽点,仅为前端部分,如有疏漏不正之处,请于文末评论探讨.注意:标红部分灰常重要,仔细阅读官方文档非常重要,耐心非常重要,细心非常 ...

  8. h5通过php微信支付宝支付,用H5调用支付微信公众号支付的解析

    这篇文章主要为大家详细介绍了微信公众号支付H5调用支付,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 最近项目需要微信支付,然后看了下微信公众号支付,虽然不难,但是细节还是需要注意的,用了大半天时 ...

  9. PHP微信公众号支付弹出“NaN:undefined”解决方法

    PHP微信公众号支付弹出"NaN:undefined"解决方法 参考文章: (1)PHP微信公众号支付弹出"NaN:undefined"解决方法 (2)http ...

最新文章

  1. 国外同行关注啥——digg.com网站Programming分类每周热点[12/17 - 12/23]
  2. mac OS Sierra支持破解程序
  3. 在Android Studio中有六种依赖
  4. webbrowser selstart selLength
  5. Py之keras-retinanet:keras-retinanet的简介、安装、使用方法之详细攻略
  6. 整理了十个Python自动化操作
  7. win10 HADOOP_HOME and hadoop.home.dir are unset
  8. mysql 事务权限_0428-mysql(事务、权限)
  9. JS setTimeout 与 setInterval
  10. Python+matplotlib自定义坐标轴位置、颜色、箭头
  11. FCPX安装插件位置及删除插件的方法
  12. HDU 4143 A Simple Problem 分解因式
  13. 关于浏览器及其内核以及什么是浏览器兼容性
  14. 2018全球高被引学者榜单出炉!中国上榜538人,计算机类排名第一
  15. 活动桌面处理和一个例子
  16. 斯坦福发布3D街景数据集:8个3D城市模型+2500万图像+1.18亿图像配对
  17. 服务器装系统bios设置方法,重装系统时BIOS的设置方法
  18. python分割pdf文档
  19. HDU-1205-吃糖果(c++的__int64!)
  20. 智能PID软件-AVEVA Diagrams 快速复制流程图【图瓦软件出品】

热门文章

  1. 解决通过vmware克隆虚拟机后,无法上网的问题
  2. 【Visual-Hull + Bregman】基于Visual-Hull + Bregman算法的三维重建算法matlab仿真
  3. Hadoop Single Node Setup(hadoop本地模式和伪分布式模式安装-官方文档翻译 2.7.3)
  4. api接口签名验证(MD5)
  5. 【手把手教你】使用Python对股价的Heikin Ashi蜡烛图进行可视化
  6. Python 算法题之 俄罗斯套娃信封
  7. 微信小程序weapp 导入calendar问题
  8. C/C++后端实习经验大礼包
  9. Python获取地震信息!能预测地震吗?
  10. 我家的网络、极路由和对小米路由器的期盼