很久之前做了微信支付,其中也趟过很多坑,现在有时间就做个自我梳理吧算是。

公众号开发的基本配置(不明白的可以参考https://blog.csdn.net/TOP__ONE/article/details/78183209),这里不再继续阐述。

如果以下代码涉及到微信工具类方法,而我没有提到的,请到链接下载:https://download.csdn.net/download/top__one/10875681

实现微信页面的分享自定义接口功能,需要先配置js-sdk以下数据项,所以需要先获取这些数据项。详细配置可以参考上一篇文章https://blog.csdn.net/TOP__ONE/article/details/85247401中的第一步后台参数准备配置,这里就不重复写了。

在页面配置好以下参数,同样是引用的js-1.2.0版本

<script type="text/javascript">$(document).ready(function(){var appId = $("#appId").val();var timestamp = $("#timestamp").val();var nonceStr = $("#nonceStr").val();var signature = $("#signature").val();//var jsonObj = eval('('+t+')');wx.config({debug: false,appId: appId,timestamp: timestamp,nonceStr: nonceStr,signature: signature,jsApiList: ['chooseWXPay','checkJsApi','closeWindow']});wx.error(function(res){//alert(JSON.stringify(res));// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
});wx.checkJsApi({jsApiList: ['checkJsApi'], // 需要检测的JS接口列表,所有JS接口列表见附录2,success: function(res) {//alert(res);// 以键值对的形式返回,可用的api值true,不可用为false// 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}}});}); 

准备好页面参数配置好以后就可以进行下面程序了,进行 统一下单 微信统一下单操作:

$(function(){     //此方法就是为了获取统一订单id之类的信息,与后台配套$("#paybt").click(function(){$.ajax({type: "POST",url: "*/payGetPreId.action",data:,dataType : "html",success : function(msg) {msg=eval('(' + msg + ')'); if("fail"==msg.info){alert(mgs.content);return false;}wx.chooseWXPay({timestamp : msg.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符nonceStr : msg.nonceStr, // 支付签名随机串,不长于 32 位package : msg.prep, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)signType : 'MD5', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'paySign : msg.paySign, // 支付签名success : function(res) {$.ajax({type: "POST",async: false,url: pay/success/",data:,dataType : "html",success : function(msg) {//alert(msg);}}); a();},cancel: function(res) {//支付取消alert('支付取消');}});}});});});

后台对应的payGetPreId方法

/*** 获取统一下单的id* * @author wang* @dateTime 上午10:17:51* @param RenewalController*            .java* @return* @throws ServiceException* */@ResponseBody@RequestMapping(value = "/payGetPreId", produces = { "application/json;charset=UTF-8" })public String payGetPreId(Model model, @RequestParam Map<String, String> map) {String buy_time = StringUtils.getNowTime();// 生成订单号String rStr = TokenGenerator.getPwd(6);String id = buy_time.replace("-", "").replace(" ", "").replace(":", "")+ rStr;WxPaySendData data = new WxPaySendData();String nonce_str = Sign.create_nonce_str();String timep = Sign.create_timestamp();String ip = GetIp.getLocalIp(this.getRequest());data.setAppid(PropertieSingle.getInstance().getProperty("APPID"));data.setMch_id(PropertieSingle.getInstance().getProperty("APP_MCH"));data.setBody("IncallOrderPay");data.setNonce_str(nonce_str);// 支付回调url需要重新设置
data.setNotify_url("http://*/payBack.action");logger.info("微信支付回调url地址======"+data.getNotify_url());data.setOut_trade_no(id);data.setTotal_fee((int) (Double.parseDouble(map.get("combo_price")) * 100));// 单位:分//data.setTotal_fee(1);// 单位:分data.setTrade_type("JSAPI");data.setSpbill_create_ip(ip);// 获取本地ipString openid = (String) this.getSession().getAttribute("openid");data.setOpenid(openid);logger.info("微信支付中的openid参数========"+data.getOpenid());String sign = UnifiedorderService.unifiedOrder(data, PropertieSingle.getInstance().getProperty("APP_SECRET"));Map<String, String> m = new DOMXML().parse(sign);String pre1 = m.get("prepay_id");String prep = "prepay_id=" + pre1;// 加 sessionSortedMap<Object, Object> parameters = new TreeMap<Object, Object>();parameters.put("appId",PropertieSingle.getInstance().getProperty("APPID"));parameters.put("timeStamp", timep);parameters.put("nonceStr", nonce_str);parameters.put("package", prep);parameters.put("signType", "MD5");this.getSession().setAttribute("p", parameters);// FIXME 再获取一次singture  查看下文档String signAgain = Sign.createSign(parameters, PropertieSingle.getInstance().getProperty("APP_SECRET"));String paySign = signAgain;String nonceStr = (String) parameters.get("nonceStr");String timeStamp = (String) parameters.get("timeStamp");JSONObject json = new JSONObject();json.put("info", "ok");json.put("timeStamp", timeStamp);json.put("nonceStr", nonceStr);json.put("prep", prep);json.put("paySign", paySign);map.put("wxhost", PropertieSingle.getInstance().getProperty("WXNOTIFYHOST"));json.put("map", map);return json.toString();}/*** 微信支付回调方法,用于验证微信发来的请求* * @param model* @param map*/@ResponseBody@RequestMapping(value = "/payBack", produces = { "application/json;charset=UTF-8" })public void payBack(Model model, @RequestParam Map<String, String> map) {InputStream inStream = null;ByteArrayOutputStream outSteam = null;String result = "";try {inStream = this.getRequest().getInputStream();outSteam = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len = 0;while ((len = inStream.read(buffer)) != -1) {outSteam.write(buffer, 0, len);}result = new String(outSteam.toByteArray(), "utf-8");} catch (Exception e) {e.printStackTrace();} finally {if (outSteam != null) {try {outSteam.close();} catch (IOException e) {e.printStackTrace();}}if (inStream != null) {try {inStream.close();} catch (IOException e) {e.printStackTrace();}}}// 解析微信发过来回调内容Map<String, String> m = XMLUtil.doXMLParse(result);if (m.get("result_code").equalsIgnoreCase("success")) {//成功回调,可以进行自己的业务操作,参数可以从m中取System.out.println(m.get("out_trade_no"));//m.get("out_trade_no").substring(0,m.get("out_trade_no").length()-1));try {this.getResponse().getWriter().write(PayCommonUtil.setXML("SUCCESS", ""));} catch (IOException e) {e.printStackTrace();}// 告诉微信服务器,我收到信息了,不要在调用回调action了       System.out.println("-------------"+ PayCommonUtil.setXML("SUCCESS", ""));} else {System.out.println("11111111111111111");}}

其中涉及到的工具类sign

package com.chinatsp.wechat.util;import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.UUID;public class Sign {public static void main(String[] args) {String jsapi_ticket = "jsapi_ticket";// 注意 URL 一定要动态获取,不能 hardcodeString url = "http://example.com";Map<String, String> ret = sign(jsapi_ticket, url);for (Map.Entry entry : ret.entrySet()) {System.out.println(entry.getKey() + ", " + entry.getValue());}};/*** 这是jssdk中需要的那个singture签名* @param jsapi_ticket* @param url* @return*/public static Map<String, String> sign(String jsapi_ticket, String url) {Map<String, String> ret = new HashMap<String, String>();String nonce_str = create_nonce_str();//定义的字符串String timestamp = create_timestamp();//同上String string1;String signature = "";System.out.println(nonce_str);System.out.println(timestamp);System.out.println(jsapi_ticket);System.out.println(url);//注意这里参数名必须全部小写,且必须有序string1 = "jsapi_ticket=" + jsapi_ticket +"&noncestr=" + nonce_str +"&timestamp=" + timestamp +"&url=" + url;System.out.println(string1);try{MessageDigest crypt = MessageDigest.getInstance("SHA-1");//加密方法crypt.reset();crypt.update(string1.getBytes("UTF-8"));signature = byteToHex(crypt.digest());}catch (NoSuchAlgorithmException e){e.printStackTrace();}catch (UnsupportedEncodingException e){e.printStackTrace();}ret.put("url", url);ret.put("jsapi_ticket", jsapi_ticket);ret.put("nonceStr", nonce_str);ret.put("timestamp", timestamp);ret.put("signature", signature);return ret;}/*** 这是微信支付里面需要哪个签名* @param parameters* @param key* @return*/private static String characterEncoding = "UTF-8";@SuppressWarnings("rawtypes")public static String createSign(SortedMap<Object,Object> parameters,String key){ 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=" + key);String signature = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();return signature; }//加密方法private static String byteToHex(final byte[] hash) {Formatter formatter = new Formatter();for (byte b : hash){formatter.format("%02x", b);}String result = formatter.toString();formatter.close();return result;}public static String create_nonce_str() {return UUID.randomUUID().toString().replaceAll("-", "");}public static String create_timestamp() {return Long.toString(System.currentTimeMillis() / 1000);}
}

工具类DOMXML

package com.chinatsp.wechat.util;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;   public class DOMXML {public  Map<String,String> parse(String protocolXML) {   Map<String,String> m = new HashMap<String, String>();try {   DocumentBuilderFactory factory = DocumentBuilderFactory   .newInstance();   DocumentBuilder builder = factory.newDocumentBuilder();   Document doc = builder   .parse(new InputSource(new StringReader(protocolXML)));   Element root = doc.getDocumentElement();   NodeList books = root.getChildNodes();   if (books != null) {   for (int i = 0; i < books.getLength(); i++) {   Node book = books.item(i);
//                     System.out.println("节点=" + book.getNodeName() + "\ttext="
//                             + book.getFirstChild().getNodeValue());   m.put(book.getNodeName(), book.getFirstChild().getNodeValue());}   }   } catch (Exception e) {   e.printStackTrace();   }return m;}   }

GetIp工具类

package com.chinatsp.wechat.util;import javax.servlet.http.HttpServletRequest;public class GetIp{/*** 从Request对象中获得客户端IP,处理了HTTP代理服务器和Nginx的反向代理截取了ip* @param request* @return ip*/public static String getLocalIp(HttpServletRequest request) {String remoteAddr = request.getRemoteAddr();String forwarded = request.getHeader("X-Forwarded-For");String realIp = request.getHeader("X-Real-IP");String ip = null;if (realIp == null) {if (forwarded == null) {ip = remoteAddr;} else {ip =  forwarded.split(",")[0];}} else {if (realIp.equals(forwarded)) {ip = realIp;} else {if(forwarded != null){forwarded = forwarded.split(",")[0];}ip =  forwarded;}}return ip;}
} 

UnifiedorderService.unifiedOrder工具类方法 重点

package com.chinatsp.wechat.util;import java.io.IOException;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import weixin.util.HttpUtils;import com.alibaba.fastjson.JSONObject;
import com.chinatsp.wechat.bean.WxPaySendData;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;public class UnifiedorderService {private final static Logger logger = LoggerFactory.getLogger(UnifiedorderService.class);public static String unifiedOrder(WxPaySendData data,String key){//统一下单支付String returnXml = null;try {//生成sign签名SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();parameters.put("appid", data.getAppid()); parameters.put("body", data.getBody());parameters.put("mch_id", data.getMch_id());parameters.put("nonce_str", data.getNonce_str());parameters.put("notify_url", data.getNotify_url());parameters.put("out_trade_no", data.getOut_trade_no());parameters.put("total_fee", data.getTotal_fee()+"");parameters.put("trade_type", data.getTrade_type());parameters.put("spbill_create_ip", data.getSpbill_create_ip());parameters.put("openid", data.getOpenid());
//        parameters.put("time_start", data.getTime_start());
//        parameters.put("time_expire", data.getTime_expire());logger.info("SIGN:"+Sign.createSign(parameters,key));data.setSign(Sign.createSign(parameters,key));XStream xs = new XStream(new DomDriver("UTF-8",new XmlFriendlyNameCoder("-_", "_")));xs.alias("xml", WxPaySendData.class);String xml = xs.toXML(data);logger.info("统一下单xml为:\n" + xml);returnXml = HttpUtils.doRequest("https://api.mch.weixin.qq.com/pay/unifiedorder","POST", xml);logger.info("返回结果:" + returnXml);System.out.println(returnXml); } catch (Exception e) {e.printStackTrace();} return returnXml;}public static void main(String[] args) {WxPaySendData data = new WxPaySendData();data.setAppid("wx1b");data.setBody("wxgzzgzgufy");data.setMch_id("13901");data.setNonce_str("12345678");data.setNonce_str(Sign.create_nonce_str());data.setNotify_url("yy/testindex.action");data.setOut_trade_no("122125112");data.setTotal_fee(1);//单位:分data.setTrade_type("JSAPI");data.setSpbill_create_ip("192.16.");data.setOpenid("oogDE");String sign = UnifiedorderService.unifiedOrder(data, "pq19L**SwY5EB");//        String s = "<xml><appid><![CDATA[wx2c43b]]></appid><attach><![CDATA[支付测试]]></attach><bank_type><![CDATA[CFT]]></bank_type>  <fee_type><![CDATA[CNY]]></fee_type>  <is_subscribe><![CDATA[Y]]></is_subscribe>  <mch_id><![CDATA[10000100]]></mch_id>  <nonce_str><![CDATA[5d2b6c46e531c]]></nonce_str>  <openid><![CDATA[oUpFkE]]></openid>  <out_trade_no><![CDATA[14653]]></out_trade_no>  <result_code><![CDATA[SUCCESS]]></result_code>  <return_code><![CDATA[SUCCESS]]></return_code>  <sign><![CDATA[B552ED6B278AB241]]></sign>  <sub_mch_id><![CDATA[10000]]></sub_mch_id>  <time_end><![CDATA[20140903131540]]></time_end>  <total_fee>1</total_fee>  <trade_type><![CDATA[JSAPI]]></trade_type>  <transaction_id><![CDATA[100440079030005092168]]></transaction_id>                </xml>";
//      String xmlToJSON = XmlUtils.xmlToJSON(s);
//      Map<String,String> map = (Map)JSONObject.toJSON(xmlToJSON);
//      System.out.println(map.get("prepay_id"));Map<String,String> m=XMLUtil.doXMLParse(sign);System.out.println(m.size());}
}

至此,微信公众号的支付功能就开发完毕了·、留此备忘一下~

具体的jsapi支付功能请参考详细文档https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1

微信公众号开发笔记(三):微信JSAPI支付功能开发相关推荐

  1. Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理

    在前几节文章中我们讲述了微信公众号环境的搭建.如何接入微信公众平台.以及微信服务器请求消息,响应消息,事件消息以及工具处理类的封装:接下来我们重点说一下-微信服务器post消息体的接收及消息的处理,这 ...

  2. 关于开发微信公众号获取手机用户运动数据的功能实现思路

    一.前沿研究 微信公众号开发文档,浏览后没有任何关于获取微信运动数据的接口 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp144 ...

  3. 如何开发微信公众号以及如何运营微信公众号

    微信公众号已经成为了企业.个人和组织进行品牌推广.宣传和营销的重要平台.但是,如何开发和运营微信公众号并不是一件容易的事情.本文将从以下几个方面来介绍如何开发和运营微信公众号. 一.微信公众号的开发 ...

  4. ngrok内网穿透工具搭建,方便微信公众号,小程序、钉钉等开发【已投入使用】

    前言:微信公众号,小程序.钉钉等开发需要内网穿透工具. 1.经过不断的摸索和调试,完成ngrok内网穿透的工具的搭建,对于微信公众号,小程序.钉钉等开发提供便利性. 2.搭建环境Linux cento ...

  5. 微信小程序使用微信公众号的模板消息进行消息推送开发流程

    微信小程序使用微信公众号的模板消息进行消息推送开发流程 微信公众号服务号,微信公众号订阅号,微信公众号开发者平台,微信小程序 这些的账号都是独立的不能共用 微信开放平台开发者资质认证审核费用为300元 ...

  6. 微信公众号数据2019_历史微信公众号排名,微信公众号新榜排名

    历史微信公众号排名,微信公众号新榜排名 公众号排名优化的注意事项及细节今天给大家分享一下,作为微信公众号的排名优化对于大多数人来说都已经知道了有这个渠道的事情,其实很多的新产品及渠道出来以后有不少的人 ...

  7. 利用微信公众号实现商品的展示和支付(2)

    在前面随笔<利用微信公众号实现商品的展示和支付(1)>介绍了商品的列表和明细信息的处理,本篇随笔接着上一篇,继续介绍关于商品的微信支付和购物车处理方面,其中微信支付里面,也涉及到了获取微信 ...

  8. 微信公众号开发者自动回复php,微信公众平台开发者模式的启用并自动回复

    这篇文章介绍的内容是关于微信公众平台开发者模式的启用并自动回复,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 首先,什么是开发者模式? 开发者模式,就是先验证你的服务器地址,验证完成之 ...

  9. php 向公众号发送消息,微信公众号之主动给用户发送消息功能

    前一段时间项目中遇到一个稍微麻烦一点的问题. 即客户要求,他在后台编辑好文章后要主动给每个用户都发送消息,并可以让用户点击直接进入文章页面. 于是乎,当时脑子一热,想着没什么大的问题,so easy. ...

  10. 微信公众号页面模版怎么添加文章推荐功能

    微信公众号中发布的文章可以添加推荐的文章,该怎么添加文章推荐功能呢?下面我们就来看看详细的教程. 微信公众号页面模版怎么添加文章推荐功能? 1.登录微信公众平台,选择"功能"--& ...

最新文章

  1. 遥遥无期还是近在咫尺?长文展望「大模型」商业化前景
  2. iframe内容 固定比例_允知研习|浅析固定总价合同的结算问题
  3. 实现table鼠标移动改变table行背景色
  4. python Intel Realsense udp协议 局域网传输实时视频流并通过窗口显示 (opencv压缩解码)
  5. js自动触发onclick_每日一题JS中最基本的this情况分析
  6. python中的函数修饰器
  7. 【spring boot】注解@ApiParam @PathVariable @RequestParam三者区别
  8. jsp mysql环境_MySQL在JSP环境下的操作应用
  9. c语言中因式分解的题目,因式分解相关练习题
  10. pytorch 关于显存增长原因以及显存占用优化
  11. Python 爬取分析全国 12 个城市 4 万条房价信息,告诉你该怎样买房?
  12. java求sin函数咋写_5类“隐含条件”,题干不写但是你要会用(解三角形知识整合,建议收藏)| 真题精讲-16...
  13. Sublime Text2.0.2注册码,添加python编译系统:
  14. JS写的简单的图片播放器
  15. uniapp文件路径转base64格式
  16. centos7 中彻底卸载mysql
  17. 计算机网络 故障处理,浅析计算机网络常见故障处理及维护方法
  18. 聊聊图标和MBE图标
  19. 回归中的相关系数以及R平方值和Python应用举例
  20. 如何获取dgv中所显示的全部数据

热门文章

  1. Docker 18.09.0更换阿里镜像加速器
  2. 服务器进pe后找不到硬盘,进入PE后找不到硬盘的原因及解决方法
  3. 服务器升级微信公告,【更新公告】8月6日先锋服务器停服更新公告
  4. 「镁客·请讲」移康智能朱鹏程:做产品就要直击痛点,多余的功能只会是噱头...
  5. longitudinal models | 纵向研究 | mixed model
  6. electron+vue3+vite2 如何使用打印
  7. mybatis中count(*)与count (*)的区别
  8. 软件工程——结构化分析方法
  9. 路由器的配置,IP,NAT、DHCP
  10. 学习自旋电子学的笔记00:杂谈(闲话) OOMMF软件的安装