1、注册小程序
拿到App_idAppSecret 小程序密钥
取得商户的微信支付商户号 MCHID 和 微信支付密钥 APIKEY

2、流程 微信用户在微信端选商品下单-------》后台响应下单生成单号,产生第一次签名数据,提交微信统一支付接口,得到返回数据,支付单号,二次签名-----返参微信端----》微信端发起支付--------支付成功失败,微信支付平台发送消息给提供的地址返回数据。
2.1.1 小程序中用户选择商品下单。
【小程序】中,用户选中商品,数量,下单------提交-----》【后台】接收下单数据。验证数据,成功入库后,
**后台对微信支付接口发起支付请求。**后台进行第一次签名验算。
必须参数如下:

 SortedMap<String,String> resultmap  = new TreeMap<String,String>();//sortedMap 是有序排列 接口是TreeMap不是HashMapresultmap.put("appid" , app_id);                             //APP应用ID       必须resultmap.put("attach", "test");                              //订单附加信息  resultmap.put("mch_id" , mch_id);                               //直连商户号     必须resultmap.put("body", order.getOrder_no());                     //产品信息。     必须resultmap.put("nonce_str" , nonce_str);                         // 随机字符串不大于32位   必须resultmap.put("notify_url", "https://www......./notify");    //通知地址 接收2.1.4步骤微信端支付后,微信支付平台给来的消息,需要提供的后台处理地址,   必须resultmap.put("openid", open_id);   //发起支付用户的open_id 。必须resultmap.put("out_trade_no" , order.getOrder_no());  //商户订单号  必须resultmap.put("spbill_create_ip", requestIp(request));   //客户ip地址记录resultmap.put("total_fee",String.valueOf(order.getPay_price()*100).substring(0, String.valueOf(order.getPay_price()*100).lastIndexOf(".")));   //支付金额按分计算。必须resultmap.put("trade_type" , "JSAPI");   //支付接口选择,这里选择统一支付接口。必须

这个map文件。需排序。所以用SortedMap格式存储,因为转url字符串 后。再加密验算时候 key需要按ask码排序,再进行MD5加密验算。
String url = mapToUrl(resultmap); //这里用了一个map转str的工具类。

private static String  makeSign(String str){//生成签名return DigestUtils.md5DigestAsHex(str.getBytes());}    //map转url。private static String  mapToUrl(SortedMap<String,String> map){//生成url map.entrySet()String buffer ="";Set<Map.Entry<String,String>> map2 = map.entrySet();for(Map.Entry<String, String> s: map2){buffer+=s.getKey()+"="+s.getValue()+"&";}return buffer;}
         String signstr = url + "key="+  wxapp.getApikey();   //这个就比较关键了。这个字符串是从上面一系列参数转换成字符串后,本地加密验算的字符串。转化为字符串   “appid=*********&attach=*******............&“  + 最尾后再加上      **key=微信支付密钥APIKEY**String sign = makeSign(signstr).toUpperCase() ;   //MD5加密后,再转换成大写。这个sign。可以用微信开发平台提供的工具进行核算,验证。sign和上面signstr在平台算出来的结果是否一致。

(签名校验工具)
2.1.2 后台算签名,及把签名加入到xml中去。对统一支付接口https://api.mch.weixin.qq.com/pay/unifiedorder发起提交。xml post提交得到返回数据xml格式的。requestmap.put("sign", sign );
//好了。上面第一次签名加密串有了。在这里加入到map中去。才组合成了完整的提交到微信支付接口的参数。这个格式肯定不接受。需要转换为xml格式。

 String xml = "";xml = MapToXml.mapToXml(resultmap);     //这里用了一个工具类,转换为了xml格式的串。后台这里就要对微信支付接口进行一个访问提交,同时把参数,用xml的格式进行提交。CloseableHttpClient **httpClient** = HttpClientBuilder.create().build();// 创建Post请求HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder");  //微信小程序的开发文档坑爹,v3和统一支付,初始根本分布清楚。乱套了。一直提交给的的是v3的地址。总是验证错误。StringEntity entity = new StringEntity(xml, null, "UTF-8", false);// post请求是将参数放在请求体里面传过去的;这里将entity放入post请求体中httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36");httpPost.setHeader("Content-Type", "application/json;charset=utf8");httpPost.setHeader("Accept", "application/json;charset=utf8");httpPost.setEntity(**entity**);

这样后台提交就完成了。
2.1.3接收微信接口返回的xml,取值,本地时间戳,不大于32位的随机串。再次md5加密签名。
接收返回的参数。
CloseableHttpResponse response = null; Map<String, String> remap = new HashMap<String,String>(); // 由客户端执行(发送)Post请求 response = httpClient.execute(httpPost); // 从响应模型中获取响应实体 HttpEntity responseEntity = response.getEntity(); if (responseEntity != null) { System.out.println("响应内容长度为:" + responseEntity.getContentLength()); remap = XmlToMap.getXmlBodyContext(EntityUtils.toString(responseEntity)); } //这里就是接收到的微信返回数据。返回的格式一样是xml格式的。这里用了一个工具类。对数据进行整理到map中。这个map中有几个关键key-value。这个是需要后台返回给小程序中给用户的。
paysignMap.put(“appId”, app_id); //小程序的app_id
paysignMap.put(“nonceStr”, nonce_str); //随机字符串。第二次签名需要加入的。这个可以重新再生成一个。也可以拿之前的。
paysignMap.put(“package”, “prepay_id=” + prepay_id); //支付订单号
paysignMap.put(“signType”, “MD5”); //验算加密的方式
paysignMap.put(“timeStamp”, time2); //时间戳
把这个再次传换成url的 appid=&nonceStr=&package=… + 再加上 key=微信支付密钥APIKEY
String paysignurl = mapToUrl(paysignMap);
paysignurl += “key=”+ wxapp.getApikey();
String paysign = makeSign(paysignurl).toUpperCase();
再次md5验算。可以去微信平台工具那里验算。但有个巨坑。微信网站平台的验算。在package=parepay_id=wx
**订单号。他会过滤掉后面的订单号。验算不会相等自己平台后面的MD5加密串。 这里可以把自己的urlstr 转xml 。再把xml提供到网站验算平台,进行验算。看是不是能够一样。后台还是按url方式进行加密算。但去网站上检验时,用XML的格式去复制粘贴。就能能看到一样了。这个困扰了大天半。这样第二次签名验算的加密串就拿到了。
把下面四个必要参数返回给微信用户。以及下单成功,发起支付的消息一并发给微信端。
towxmap.put(“timeStamp”, time); //时间戳
towxmap.put(“nonceStr”, nonce_str); //随机串
towxmap.put(“prepay_id”, prepay_id); //在微信支付返回来的支付订单号
towxmap.put(“paySign”, paysign); //后台二次签名
2.1.4小程序接收到必要参数,调用wx.requestPayment.发起支付。提供下面正确的参数。即可正常支付。
小程序调用wx.requestPayment 发起支付 发送必须参数如下:

 timeStamp: result.data.payment.timeStamp,                               //后台二次签名时,用的时间戳,返回过来的。nonceStr: result.data.payment.nonceStr,                                 //后台二次签名时候。用到的随机串package: 'prepay_id=' + result.data.payment.prepay_id,         //注意这里和后台返回的不同。前面加了'prepay_id='支付订单号signType: 'MD5',                                                                          //加密方式paySign: result.data.payment.paySign,

2.1.5 前面提到notify。后台接收微信支付成功失败的网址。接收的数据一样是xml格式。必须要给微信接口返回消息。不然会一直发。
再根据微信发过来的支付结果消息,进行订单更新处理,改变订单状态,和给用户发送消息。因为各方面数据通讯不知道正常否,不方便调试的话,可以自己模拟一个发送接收页面。xml传递数据。数据处理完全正常了。再转微信支付接口。这样就能很快的测试好。

@RequestMapping(value="wxclient/notify")@ResponseBodypublic void notify(HttpServletRequest request,HttpServletResponse response) throws Exception{//request.setCharacterEncoding("utf-8"); // 接收格式指定//String path = request.getServletContext().getRealPath("/WEB-INF/temple/default/");String result = "";BufferedReader in = null;request.setCharacterEncoding("UTF-8");//InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "UTF-8");in = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));String line;while ((line = in.readLine()) != null) {result += line;}//ObjectMapper MAPPER = new ObjectMapper();//Map<String, Object> jsonmap = MAPPER.readValue(result, HashMap.class);SortedMap<String,String> map2 = new TreeMap<String,String>();map2 = XmlToMap.getXmlBodyContext(result);  //获得的result来的格式为xml,这里xml转mapString signurl = mapToUrlQuSign(map2);          //map再转url后,加key。再md5算sign验证码。WxApp wxapp = *****.SelectWxApp(10001);   //暂时直接用的wxapp_id没有查询。signurl += "key="+  wxapp.getApikey();map2.put("signurl", signurl);System.out.println(signurl);String sign2 = makeSign(signurl).toUpperCase();   //对本站内的数据验算。map2.put("sign2", sign2);System.out.println(map2);Constants.map = map2;    //得到返回值,给到一个全局变量供查看。SortedMap<String,String> map = new TreeMap<String,String>();if(sign2!=null && sign2.equals(map2.get("sign"))){  //比较本站内的数据加密 和 返回的加密串  是否一致。一致则证明是一个订单发起的消息回应。再根据消息内容对订单做出正确的处理。Order order = new Order();int update_time = Integer.parseInt(String.valueOf(System.currentTimeMillis()/1000));//order.setUser_id(Integer.parseInt((String)redisUtil.get(token)));order.setWxapp_id(10001);order.setOrder_no(map2.get("out_trade_no"));order.setUpdate_time(update_time);        order.setPay_time(StampToData.dateToStamp(map2.get("time_end")));order.setTransaction_id(map2.get("transaction_id"));Service.OrderPayUpdateByOrderId(order);System.out.println(order);map.put("result_code","SUCCESS");     }else{map.put("result_code", "FAIL");}String xml = "";xml = MapToXml.mapToXml(map);             //返回给支付平台成功消息。map转xml。response.setCharacterEncoding("UTF-8");response.getWriter().println(xml);}

XmlToMap

public class XmlToMap{public static Document parseXmlString(String xmlStr){try{InputSource is = new InputSource(new StringReader(xmlStr));DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();DocumentBuilder builder=factory.newDocumentBuilder();Document doc = builder.parse(is);return doc;}catch(Exception e){e.printStackTrace();}return null;}public static SortedMap<String, String> getXmlBodyContext(String bodyXml){SortedMap<String, String> dataMap = new TreeMap<String,String>();Document doc = parseXmlString(bodyXml);if(null != doc){NodeList rootNode = doc.getElementsByTagName("xml");if(rootNode != null){Node root = rootNode.item(0);NodeList nodes = root.getChildNodes();for(int i = 0;i < nodes.getLength(); i++){Node node = nodes.item(i);dataMap.put(node.getNodeName(), node.getTextContent());}}}return dataMap;}}

MapToXml 两个方式,都可以用。

public class MapToXml {public static boolean isNumeric(String str){for(int i=str.length();--i>=0;){int chr=str.charAt(i);if(chr<48 || chr>57)return false;}return true;}public static String mapToXml(SortedMap<String, String> map) throws Exception {/*  if (map.size()==0) {return "fail";}String xml = "<xml>";for(Entry<String,String> s : map.entrySet()) {if(isNumeric(s.getValue())){ xml += "<" + s.getKey() + "><![CDATA[" + s.getValue() + "]]></" + s.getKey() + ">"; }else{             xml += "<" + s.getKey() + ">" + s.getValue() + "</" + s.getKey() + ">";}}xml += "</xml>";return xml;}*/DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();//防止XXE攻击documentBuilderFactory.setXIncludeAware(false);documentBuilderFactory.setExpandEntityReferences(false);DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();org.w3c.dom.Document document = documentBuilder.newDocument();org.w3c.dom.Element root = document.createElement("xml");document.appendChild(root);for (String key: map.keySet()) {String value = map.get(key);if (value == null) {value = "";}value = value.trim();org.w3c.dom.Element filed = document.createElement(key);filed.appendChild(document.createTextNode(value));root.appendChild(filed);}TransformerFactory tf = TransformerFactory.newInstance();Transformer transformer = tf.newTransformer();DOMSource source = new DOMSource(document);transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");transformer.setOutputProperty(OutputKeys.INDENT, "yes");StringWriter writer = new StringWriter();StreamResult result = new StreamResult(writer);transformer.transform(source, result);String output = writer.getBuffer().toString();try {writer.close();}catch (Exception ex) {}return output;}}

HttpClient 需要 httpcomponents-client-5.1-bin 支持。https://dlcdn.apache.org//httpcomponents/httpclient/binary/httpcomponents-client-5.1-bin.zip

小程序支付完整过程。足够详细!相关推荐

  1. 微信小程序支付完整流程

    1.注册微信支付商户号(由上级或法人注册) 注册链接:https://pay.weixin.qq.com/index.php/apply/applyment_home/guide_normal#non ...

  2. uniapp快速搭建小程序项目 完整过程

    先看看效果! 1. 注册小程序开发者(已注册的可以跳过) 进入官网 点击注册 -> 选择小程序 -> 填写注册信息 2. 开发工具准备 使用uniapp开发就需要用到两个工具,HBuild ...

  3. 小程序支付 PHP

    小程序支付完整demo 拿去直接可以用 须准备好小程序appid 和商户mch_id 回调地址你们随意,想用的话就用不想用填个业务域名就行了 /****小程序支付/ public function w ...

  4. 小程序支付,详细过程

    1.小程序注册,要以公司的以身份去注册一个小程序,才有微信支付权限: 2.绑定商户号. 3.在小程序填写合法域 二.完成以上条件,你可以得到 "小程序appid 小程序秘钥 " 这 ...

  5. thinkphp5微信小程序支付的接口详细过程

    控制器: class Pay extends BaseController {protected $beforeActionList = ['checkExclusiveScope' => [' ...

  6. android简单小程序完整代码_10行代码实现小程序支付功能!丨实战

    " 纯干货!本文教你用云开发轻松实现强大的小程序支付功能! " 导语 前面给大家讲过如何借助小程序云开发实现微信支付,但是这种开发方式相对繁琐,并且具有不稳定性,今天就给大家讲一下 ...

  7. 微信小程序支付的整个流程和在这个过程中遇到的问题

    前言:这几天公司要做微信的支付功能,花了一天时间写了一个dome,单文档上有太多的坑,有些地方写的不清不楚,所以写了这个文档记录一下过程. 环境 一.后台:微信的sdk <!--微信支付SDK- ...

  8. 完整的微信小程序支付开发记录(亲测)

    这次呢是开发小程序的支付功能.因为没有做过,特此记录,做一个小总结,以便以后使用以及给小伙伴们提供一个像我一样的小白一个参考,我也是一点一点摸索过来的,此文只针对开发支付流程而言以及出现的问题,其它则 ...

  9. 微信小程序支付以及退款功能(超详细)

    Springboot整合微信小程序支付 第一步: 第二步:导入微信支付的依赖 第三步:在springboot核心配置文件中配置参数 第四步:创建配置类WxPayAppConfig 第五步:支付方法 s ...

  10. Java--微信支付--小程序支付--v3版--完整的代码例子

    微信官方文档–小程序支付:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_1.shtml 微信官方文档–支付接入前准备https:// ...

最新文章

  1. android 4.4 禁止下拉,Android开发中禁止下拉式的实现技巧
  2. Linux tree命令
  3. 列名无效怎么解决_电脑win键失效怎么办? 键盘win键无效的解决办法
  4. 【转】Asp.net页面的生命周期
  5. 同感,C#对JSON序列化和反序列化有点蹩脚
  6. laravel 任务队列_Laravel 队列的简单使用例子
  7. 【设计模式】第七章 享元模式
  8. 牛客国庆集训派对Day3: G. Stones(博弈+SG)
  9. 一个dsp最小系统至少要有_DSP原理及应用(2812)试卷_附答案卷B2(2015城南)
  10. antdvue 表格插入自定义行
  11. 【云存储】IOPS概念及测试方法
  12. 支付宝php sdk如何使用,支付宝SDK怎么用啊?
  13. python turtle笛卡尔心形线_用MATLAB实现心形线
  14. 万能数据库查询分析器使用技巧之(十一)
  15. 联想0xc000007b蓝屏怎么修复
  16. 【单片机】辉光管时钟系列<一>--单片机最小系统
  17. 免费的视频转换器有哪些?推荐3款好用免费视频格式转换软件
  18. Ubuntu 上使用qcad将dwg转 pdf
  19. ML之FE:机器学习算法/数据挖掘中特征选取(变量筛选)的简介、常用方法(单变量分析并筛选—Filter/Wrapper/Embedded、多变量间相关性分析并筛选—PCC/MIC/IV)之详细攻略
  20. iapp教程从入门到精通全部,小白用的iapp教程手册

热门文章

  1. Redis基础6(Redis6管道)
  2. java两个数的最大公约数和最小公倍数
  3. 一个关于finally和return的面试题
  4. bzoj4009: [HNOI2015]接水果
  5. Python Project Euler 013:100个50位数和
  6. IRF之LACP-MAD检测
  7. 东北三省计算机专业好的学校,东北地区哪个大学比较好 各自的王牌专业是什么...
  8. 游戏筑基开发之利用文件函数取出配置文件(ini文件)的数据实体(C语言)
  9. KVM详解(二)——KVM安装部署
  10. ansible 第二次练习