JAVA开发微信支付-公众号支付/微信浏览器支付(JSAPI)

写本篇博客其一是因为最近做的项目在用这个功能,通过本篇博客进行一个全局的梳理,其二呢,也就是想趁着思路清晰,把心得记录下来,分享给大家,也方便日后自己再用。再此之前,在网上搜索了很多关于微信公众号支付的博文,真正思路清晰,适合第一次接触微信支付的人去用的博文更是少之又少,所以,打算详细的记录一下,希望可以帮助到初次接触微信支付的人吧。

接下来进入正题:

步骤一:前提条件

进行微信公众号支付开发,就需要公众号和商户号两个账号,公众号比较好弄,商户号的话申请就比较麻烦了,一般情况下都是由客户之间提供好以上两个账号,提供这两个账号也是为了给我们提供微信支付的其中四个比较重要的参数:

微信公众号:1. APPID:wx455***********54532. APPSECRET:35502926************0c20e87b7fb8
微信商户号1. MCH_ID(商户ID):14******422. API_KEY(API秘钥):2NEJNeXbTdy********q77fPKQIDAQAB

其中比较不好找的是商户的API密钥:在商户平台的账户中心下:需要用户自行下载证书及安装,(略)

步骤二:平台配置

公众号配置网页域名授权,在下图部分修改为域名

步骤三:开发流程

简单来说,就是调用微信支付的统一下单的接口,简单的步骤如下

  1. 凑足参数,请求统一下单接口
  2. 编写回调接口,进行业务处理
  3. 给微信返回信息
参数
携带支付结果,请求回调接口
客户端
统一下单接口
微信
客户端
回调接口中返回信息给微信
微信

接下来看一下请求统一下单接口需要的参数

官方文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

先看一遍所有的参数:



在这些参数里,其中有11个参数是必填的:

  1. appid:公众账号ID
  2. mch_id:商户号
  3. nonce_str:随机字符串
  4. sign:签名(重点)
  5. body:商品描述
  6. out_trade_no:商户订单号
  7. total_fee:金额
  8. spbill_create_ip:终端IP
  9. notify_url:回调接口地址
  10. trade_type:交易类型(本次为JSAPI)
  11. openid :支付人的微信公众号对应的唯一标识

接下来开始凑这十一个参数

  1. appid:√
  2. mch_id:√
  3. nonce_str:随机字符串用WXPayUtil中的generateNonceStr()即可√
  4. sign:签名 用WXPayUtil中的generateSignature(finalMap<String, String> data, String key)方法,data是将除了sign外,其他10个参数放到map中,key是四大配置参数中的API秘钥(paternerKey)(这里不要着急管它,最后处理它);
  5. body:√
  6. out_trade_no:商户订单号(自主生成)√
  7. total_fee:金额(需要支付的金额)√
  8. spbill_create_ip:终端IP(测试用127.0.0.1即可,获取IP也很简单)√
  9. notify_url:回调地址,这是微信支付成功后,微信那边会带着一大堆XML格式的参数请求这个地址多次,在这个回调接口里我们要处理我们的业务逻辑,订单,流水,用户信息等,最终给微信返回一个XML格式的result_code
  10. trade_type:交易类型(本次为JSAPI) √
  11. openid :支付人的微信公众号对应的唯一标识

这样的话还有openid、sign签名、回调接口(回调地址直接写接口地址就可以,只不过我们现在还没写接口里的内容)未凑齐。

步骤四:代码部分

1:获取openid

这部分在我的代码中其实用户信息里就已经存过用户的openid了,所以我直接获取了支付用户的用户信息拿到的openid,不过如果没有openid的话,下面我描述一下获取openid的方法,其实也就是微信授权的部分,有想详细了解的可以看我写过的另一篇博文JAVA实现微信授权登录(详解),简单说一下:
第一步:用户同意授权,获取code
我是在前台请求的这个自己写的接口,然后在后台此接口中调用微信授权接口,调用此接口需要有三个注意的地方

  1. APPID:公众号的appid
  2. REDIRECT_URI:这个地址是调用微信授权后的回调接口,在回调接口中我们可以拿到用户的信息,特别注意:redirect_uri地址需要使用 urlEncode 对链接进行处理
  3. SCOPE:此处填snsapi_userinfo,需要用户点授权
    /*** Tea微信登录* @throws IOException */@ApiOperation(value = "微信登录接口")@IgnoreAuth@RequestMapping("wx_login")public void wxLogin(HttpServletResponse response) throws IOException{//域名String sym = WxConstant.DOMAINNAME;//这里是回调的urlString redirect_uri = URLEncoder.encode(sym+"/front/auth/callBack", "UTF-8");String url = "https://open.weixin.qq.com/connect/oauth2/authorize?" +"appid=APPID" +"&redirect_uri=REDIRECT_URI"+"&response_type=code" +"&scope=SCOPE" +"&state=123#wechat_redirect";response.sendRedirect(url.replace("APPID",WxConstant.APPID).replace("REDIRECT_URI",redirect_uri).replace("SCOPE","snsapi_userinfo"));}

接下来就是微信授权的回调接口
1、获取code
2、根据code获取openid和access_token
3、根据access_token和openid获取用户的微信信息(昵称,性别,地址等)

 /*** Tea微信授权成功的回调函数* * @param request* @param response* @throws ClientProtocolException* @throws IOException* @throws ServletException*/@ApiOperation(value = "微信授权回调接口")@IgnoreAuth@RequestMapping("/callBack")protected void deGet(HttpServletRequest request, HttpServletResponse response)throws Exception {//获取回调地址中的codeString code = request.getParameter("code");//拼接URLString url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + WxConstant.APPID + "&secret="+ WxConstant.APPSECRET + "&code=" + code + "&grant_type=authorization_code";JSONObject jsonObject = AuthUtil.doGetJson(url);//获取openIdString openid = jsonObject.getString("openid");//获取tokenString access_token = jsonObject.getString("access_token");String infoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + access_token + "&openid=" + openid+ "&lang=zh_CN";//获取用户信息JSONObject userInfo = AuthUtil.doGetJson(infoUrl);}

补上刚刚用的工具类AuthUtil

package com.platform.util;import java.io.IOException;import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;import net.sf.json.JSONObject;public class AuthUtil {public static JSONObject doGetJson(String url) throws ClientProtocolException, IOException {JSONObject jsonObject = null;DefaultHttpClient client = new DefaultHttpClient();HttpGet httpGet = new HttpGet(url);HttpResponse response = client.execute(httpGet);HttpEntity entity = response.getEntity();if (entity != null) {String result = EntityUtils.toString(entity, "UTF-8");jsonObject = JSONObject.fromObject(result);}httpGet.releaseConnection();return jsonObject;}
}
这样我们就拿到openId了

接下来就只剩下签名sign还没有了,不过这个时候其他参数我们都已经凑完了,开始生成签名

用WXPayUtil中的generateSignature(final Map<String, String> data, Stringkey)方法,
data是将除了sign外,其他10个参数放到map中,key是四大配置参数中的API秘钥(paternerKey)

拿到sign后需要将上面我们凑的这十一个参数放到一个map里,参数凑齐了,我们开始请求统一下单接口吧

如果不出意外的话,你将会拿到如下所述的一个XML返回


<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg><appid><![CDATA[wx2421b1c4370ec43b]]></appid><mch_id><![CDATA[10000100]]></mch_id><nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str><openid><![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]></openid><sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign><result_code><![CDATA[SUCCESS]]></result_code><prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id><trade_type><![CDATA[JSAPI]]></trade_type>
</xml>

官方文档如下:

到此为止,我们千辛万苦费劲拿到的范围值,仅仅是为了一个prepay_id。
看看前台都需要接收哪些值吧

这次是要将6个参数返回给前台,逐个分析一下

  1. appId:四大参数之一的APPID;
  2. timestamp:时间戳(newDate()即可)
  3. nonceStr:随机字符串,再次用WXPayUtil中的generateNonceStr()即可;
  4. package:就tm是它用到了prepay_id,但是还不是直接取值,还非要固定格式的,值的格式例如:”prepay_id= wx2018…250…9981…666”
  5. signType:写MD5就好、
  6. paySign:又来了还是签名算法 ,按照上面的方法,用WXPayUtil中的publicstatic String generateSignature(final Map<String, String> data, Stringkey)方法,data是将除了paySign外,其他5个参数放到map中,key是四大配置参数中的API秘钥(paternerKey),得到了paySign后,不要忘记再将paySign put到只有5个参数的map中,这样才能凑齐最后的第6个参数。);

下面贴一下我自己可以运行的代码吧,大家参考一下

一:前台的VUE的js代码(支付部分用到的是goldMember方法,其他的无用)
var vm = new Vue({el: '#rrapp',data: {user: getLocalUserInfo()},methods: {getInfo: function () {ApiAjax.request({url: "/api/user/detail",type: "POST",async: true,successCallback: function (r) {vm.user = r.data;console.log(vm.user);}});},goldMember: function () {var totalAmount = '0.01';//充值金额var description = '充值:xxx元'//充值描述ApiAjax.request({url: '/api/weixin/goldMember/'+totalAmount+'/'+description,type: "get",async: true,successCallback: function (date) {WeixinJSBridge.invoke('getBrandWCPayRequest',{  "appId" : date.appId,          //公众号名称,由商户传入  "timeStamp":date.timeStamp,    //时间戳,自 1970 年以来的秒数  "nonceStr" : date.nonceStr,    //随机串  "package" : date.package,      //商品包信息"signType" : date.signType,    //微信签名方式"paySign" : date.paySign       //微信签名  },function(res){if(res.err_msg == "get_brand_wcpay_request:ok" ) {  $.toast('支付成功');window.location.href = '/front/my.index.html';}else{$.toast('支付失败');ApiAjax.request({url: '/api/goldMember/weixinPay/fail',type: "POST",async: true,params: {trade_no: date.trade_no,},successCallback: function (r) {}});}});}});}},mounted: function() {if(this.user == null)window.location.href = '/front/login.html';this.getInfo();}
});
二:刚刚前台请求的接口
    /*** @param totalAmount    支付金额* @param description    描述* @param openId         微信公众号openId   (可以前端传code,然后后台再通过微信对应接口换取openId)* @param request -* @return -*/@RequestMapping(value = "/weixin/goldMember/{totalAmount}/{description}",produces = MediaType.APPLICATION_JSON_VALUE)@ResponseBodypublic SortedMap<String, String> ToPay(@LoginUser UserVo loginUser, @PathVariable BigDecimal totalAmount, @PathVariable String description, HttpServletRequest request) {/*** 业务逻辑部分*///------------------//拼接回调地址,private static String wxnotify = "/api/json/money/goldMember/succ";String sym = request.getRequestURL().toString().split("/api/")[0];String notifyUrl = sym + wxnotify;String attach = null;String openId = (String) request.getSession().getAttribute("openid");//返回预支付参数到前台(此方法中凑齐了十一个参数请求统一下单接口并将6个值返回给了前台,代码在后面工具类中贴出来)return PayCommonUtil.WxPublicPay(tradeNo, totalAmount, description, attach, notifyUrl ,loginUser.getWeixin_openid(), request);}
三:支付成功回调接口

此接口中处理支付成功的业务逻辑,一定要判断该次订单或者支付是否已经处理过防止微信重复回调接口导致我们重复处理业务逻辑

    /*** 支付成功回调地址* @param request* @return* @throws Exception */@IgnoreAuth@Transactional@RequestMapping(value = "/json/money/goldMember/succ",produces = MediaType.APPLICATION_JSON_VALUE)public String wxpaySucc(@LoginUser UserVo loginUser,HttpServletRequest request) throws Exception {System.out.println("微信支付回调");InputStream inStream = request.getInputStream();ByteArrayOutputStream outSteam = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len = 0;while ((len = inStream.read(buffer)) != -1) {outSteam.write(buffer, 0, len);}String resultxml = new String(outSteam.toByteArray(), "utf-8");System.out.println("微信支付返回结果集:"+resultxml);Map<String, String> params = null;try {params = PayCommonUtil.doXMLParse(resultxml);System.out.println(params);} catch (JDOMException e) {e.printStackTrace();}//获取订单号(可以围绕订单号处理业务)String orderNo = params.get("out_trade_no");outSteam.close();inStream.close();try {if (PayCommonUtil.isTenpaySign(params)){if("SUCCESS".equals(params.get("return_code"))){Map map = new HashMap<String,String>();map.put("return_code", "SUCCESS");map.put("return_msg", "ok");String resultCode = params.get("result_code");if("SUCCESS".equals(resultCode)) {// --- 处理支付成功逻辑 ---//判断该业务逻辑是否已经处理过,防止微信重复回调//判断该业务逻辑是否已经处理过,防止微信重复回调//判断该业务逻辑是否已经处理过,防止微信重复回调return WXPayUtil.mapToXml(map);}else {// 充值失败业务逻辑↓return WXPayUtil.mapToXml(map);}}else{Map map = new HashMap<String,String>();map.put("return_code", "FILE");map.put("return_msg", "ok");// 充值失败业务逻辑↓return WXPayUtil.mapToXml(map);}}}catch(Exception e) {e.printStackTrace();TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();throw new RuntimeException();}return null;}/*** 支付失败回调地址* @param request* @return* @throws Exception */@RequestMapping(value = "/goldMember/weixinPay/fail",method = RequestMethod.POST)@ResponseBodypublic String wxpayFail(HttpServletRequest request,String trade_no) throws Exception {/**** 充值失败业务逻辑↓*/return null;}
四:补上刚刚请求统一下单的那个工具类
package com.platform.config.wxpay;import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;import com.platform.utils.HttpClientUtil;public class PayCommonUtil {//微信参数配置(就用到前三个)public static String API_KEY = "2NEJNeXbTdy8u5p35ARq77fPKQIDAQAB";public static String APPID = "wxb29f520d09a81ed9";public static String MCH_ID = "1560164811";public static String APP_NAME = "APP_NAME ";public static String BUNDLE_ID = "bundle_id";//bundle_idpublic static String PACKAGE_NAME = "包名";//包名public static String WAP_NAME = "WAP 网站名";//WAP 网站名public static String WAP_URL = "https://www.baidu.com";//WAP网站URL地址public static String SUCCESS = "SUCCESS";/*** 微信公众号支付* @param trade_no      订单号* @param totalAmount   支付金额* @param description   文字内容说明* @param attach        自定义参数 length=127* @param openId        微信公众号openId* @param wxnotify      回调地址* @param request       -* @return              -*/public static SortedMap<String, String> WxPublicPay(String trade_no, BigDecimal totalAmount, String description, String attach,String wxnotify, String openid, HttpServletRequest request) {Map<String, String> map = weixinAppPrePay(trade_no,totalAmount,description,attach,wxnotify,openid,request);SortedMap<String, String> finalpackage = new TreeMap<>();finalpackage.put("appId", PayCommonUtil.APPID);finalpackage.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));finalpackage.put("nonceStr", getRandomString(32));finalpackage.put("package", "prepay_id=" + map.get("prepay_id"));finalpackage.put("signType", "MD5");String sign = PayCommonUtil.createSign2(finalpackage);finalpackage.put("paySign", sign);finalpackage.put("trade_no", trade_no);return finalpackage;}/***                      -* @param trade_no      订单号* @param totalAmount   支付金额* @param description   文字内容说明* @param attach        自定义参数 length=127* @param openid        微信公众号openId* @param wxnotify      回调地址* @param request       -* @return              -*/public static Map<String, String> weixinAppPrePay(String trade_no, BigDecimal totalAmount, String description, String attach, String wxnotify, String openid ,HttpServletRequest request) {SortedMap<String, String> parameterMap = new TreeMap<>();parameterMap.put("appid", PayCommonUtil.APPID);parameterMap.put("mch_id", PayCommonUtil.MCH_ID);parameterMap.put("nonce_str", getRandomString(32));parameterMap.put("body", description);parameterMap.put("out_trade_no", trade_no);parameterMap.put("fee_type", "CNY");BigDecimal total = totalAmount.multiply(new BigDecimal(100));java.text.DecimalFormat df = new java.text.DecimalFormat("0");parameterMap.put("total_fee", df.format(total).toString());parameterMap.put("spbill_create_ip", request.getRemoteAddr());parameterMap.put("notify_url", wxnotify);parameterMap.put("trade_type", "JSAPI");//trade_type为JSAPI是 openid为必填项parameterMap.put("openid", openid);String sign = PayCommonUtil.createSign2(parameterMap);parameterMap.put("sign", sign);Map<String, String> map = null;try {//此部分就是生成签名请求参数。可以不用这个工具类String requestXML = WXPayUtil.generateSignedXml(parameterMap, PayCommonUtil.API_KEY);String result = PayCommonUtil.httpsRequest("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST", requestXML);System.out.println(result);      map = PayCommonUtil.doXMLParse(result);} catch (Exception e) {e.printStackTrace();}return map;}//随机字符串生成public static String getRandomString(int length) { //length表示生成字符串的长度String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";Random random = new Random();StringBuilder sb = new StringBuilder();for (int i = 0; i < length; i++) {int number = random.nextInt(base.length());sb.append(base.charAt(number));}return sb.toString();}//请求xml组装public static String getRequestXml(SortedMap<String, String> parameterMap){StringBuilder sb = new StringBuilder();sb.append("<xml>");Set es = parameterMap.entrySet();for (Object e : es) {Map.Entry entry = (Map.Entry) e;String key = (String) entry.getKey();String value = (String) entry.getValue();if ("attach".equalsIgnoreCase(key) || "body".equalsIgnoreCase(key) || "sign".equalsIgnoreCase(key)) {sb.append("<").append(key).append(">").append("<![CDATA[").append(value).append("]]></").append(key).append(">");} else {sb.append("<").append(key).append(">").append(value).append("</").append(key).append(">");}}sb.append("</xml>");return sb.toString();}//生成签名public static String createSign2(SortedMap<String, String> parameters){StringBuilder sb = new StringBuilder();Set es = parameters.entrySet();for (Object e : es) {Map.Entry entry = (Map.Entry) e;String k = (String) entry.getKey();Object v = entry.getValue();if (null != v && !"".equals(v)&& !"sign".equals(k) && !"key".equals(k)) {sb.append(k).append("=").append(v).append("&");}}sb.append("key=").append(API_KEY);System.out.println(sb.toString());return MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();}/*** 验证回调签名* @param map* @return*/public static boolean isTenpaySign(Map<String, String> map) {String charset = "utf-8";String signFromAPIResponse = map.get("sign");if (signFromAPIResponse == null || signFromAPIResponse.equals("")) {System.out.println("API返回的数据签名数据不存在,有可能被第三方篡改!!!");return false;}System.out.println("服务器回包里面的签名是:" + signFromAPIResponse);//过滤空 设置 TreeMapSortedMap<String,String> packageParams = new TreeMap<>();for (String parameter : map.keySet()) {String parameterValue = map.get(parameter);String v = "";if (null != parameterValue) {v = parameterValue.trim();}packageParams.put(parameter, v);}StringBuilder sb = new StringBuilder();Set es = packageParams.entrySet();for (Object e : es) {Map.Entry entry = (Map.Entry) e;String k = (String) entry.getKey();String v = (String) entry.getValue();if (!"sign".equals(k) && null != v && !"".equals(v)) {sb.append(k).append("=").append(v).append("&");}}sb.append("key=").append(API_KEY);//将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较//算出签名String tobesign = sb.toString();String resultSign = MD5Util.MD5Encode(tobesign, "utf-8").toUpperCase();String tenpaySign = packageParams.get("sign").toUpperCase();return tenpaySign.equals(resultSign);}//请求方法public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {try {URL url = new URL(requestUrl);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setDoOutput(true);conn.setDoInput(true);conn.setUseCaches(false);// 设置请求方式(GET/POST)conn.setRequestMethod(requestMethod);conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");// 当outputStr不为null时向输出流写数据if (null != outputStr) {OutputStream outputStream = conn.getOutputStream();// 注意编码格式outputStream.write(outputStr.getBytes("UTF-8"));outputStream.close();}// 从输入流读取返回内容InputStream inputStream = conn.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String str = null;StringBuilder buffer = new StringBuilder();while ((str = bufferedReader.readLine()) != null) {buffer.append(str);}// 释放资源bufferedReader.close();inputStreamReader.close();inputStream.close();conn.disconnect();return buffer.toString();} catch (ConnectException ce) {System.out.println("连接超时:{}"+ ce);} catch (Exception e) {System.out.println("https请求异常:{}"+ e);}return null;}//xml解析public static Map doXMLParse(String strxml) throws JDOMException, IOException {strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");if(null == strxml || "".equals(strxml)) {return null;}Map m = new HashMap();InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));SAXBuilder builder = new SAXBuilder();Document doc = builder.build(in);Element root = doc.getRootElement();List list = root.getChildren();for (Object aList : list) {Element e = (Element) aList;String k = e.getName();String v = "";List children = e.getChildren();if (children.isEmpty()) {v = e.getTextNormalize();} else {v = getChildrenText(children);}m.put(k, v);}//关闭流in.close();return m;}private static String getChildrenText(List children) {StringBuilder sb = new StringBuilder();if(!children.isEmpty()) {for (Object aChildren : children) {Element e = (Element) aChildren;String name = e.getName();String value = e.getTextNormalize();List list = e.getChildren();sb.append("<").append(name).append(">");if (!list.isEmpty()) {sb.append(getChildrenText(list));}sb.append(value);sb.append("</").append(name).append(">");}}return sb.toString();}}

JAVA微信支付(微信公众号支付JSAPI)相关推荐

  1. php微信公众号支付实例教程,php微信支付之公众号支付功能

    这篇文章主要为大家详细介绍了php微信支付之公众号支付功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 网上的很多PHP微信扫码支付接入教程都颇为复杂,且需要配置和引入较多的文件,本人通过整理后 ...

  2. 微信支付 php详解,微信支付之公众号支付详解

    本文主要和大家分享微信支付之公众号支付详解,随着微信支付的流行,大多产品都开发了自己的公众号.小程序等,产品的营销需要支付的支撑,最近做了个微信公号号支付,采坑无数,今天给大家分享一下,希望能帮助到大 ...

  3. 微信支付、公众号支付、微信APP支付教程

    这两天有朋友问我微信支付的一些事情,我就抽了点时间整理了一下微信支付相关的一些东西,在这里分享给大家,希望能帮助大家少走弯路. 微信支付分为APP支付和公众号支付两大类,其中公众号支付又分为(公众号支 ...

  4. APP支付和公众号支付区别在哪?

    PP支付与公众号支付容易搞混淆,尤其对于一些半专业的外行人来说,傻傻分不清. 随着移动支付的盛行,或者说随着微信社交产品的全民普及,再加上消费者被一轮又一轮的支付大战烧脑,再不懂支付的也都了解那么丁点 ...

  5. 什么是APP支付和公众号支付

    APP支付与公众号支付容易搞混淆,尤其对于一些半专业的外行人来说,傻傻分不清. 随着移动支付的盛行,或者说随着微信社交产品的全民普及,再加上消费者被一轮又一轮的支付大战烧脑,再不懂支付的也都了解那么丁 ...

  6. 微信支付之公众号支付

    经过近一周的敲代码,终于把公众号支付和H5支付实现完成并测试通过,特此分享一些流程,一方面自己记录另一方面给新入门的一点思路 [本文介绍普通商户的公众号支付] 一.基本信息和配置 公众号支付的前提是要 ...

  7. 微信支付(公众号支付)微信公众平台开发教程(5)

    简介 Senparc.Weixin SDK 是由盛派网络(Senparc)团队自主研发的针对微信各模块的 开发套件(C#SDK), 已全面支持微信公众号.微信支付.企业号.开放平台.JSSDK.摇一摇 ...

  8. 【微信开发】---- 公众号支付

    公众号支付就是在微信里面的H5页面唤起微信支付,不用扫码即可付款的功能.做这个功能首先要明确的就是,只有和商户号mch_id匹配的appid才能成功支付.商户号在注册成功的时候就会将相关信息发送到邮箱 ...

  9. 微信h5支付和公众号支付、支付宝h5支付

    1.微信h5支付: 首先是支付参数的构建,这个需要通过后台进行组装,后台会跟微信进行数据的交互,而你所需要做的是拿到返回的数据,然后传递给微信的JSSDK,由微信的JSSDK进行后续操作,比如说先跳转 ...

  10. 微信H5支付、非微信H5支付、公众号支付、小程序支付

    文章目录 前言 一.微信H5支付和非微信H5支付 二.公众号支付 三.小程序支付 总结 前言 最近公司又要搞微信支付,大体上就是把app上VIP那一套内容但做成网页版,更方便用户去购买vip,老板就让 ...

最新文章

  1. 喜马拉雅自研网关架构实践
  2. 安卓如何调出软键盘_如何系统学习手机摄影?这张思维导图告诉你
  3. 升级 | Fastjson 1.2.68 发布,支持 GEOJSON
  4. ios app上架App Store需要多少费用?
  5. Notification大图标修改问题种种
  6. 10 i lt shell的if_shell脚本----if(数字条件,字符串条件,字符串为空)
  7. PHP网站开启gzip压缩,php中开启gzip压缩的2种方法代码
  8. Javascript基础回顾 之(二) 作用域
  9. 两条边延长角会有什么变化_《认识角》教学设计
  10. c语言发牌小游戏,大家想想怎么用c实现我们经常玩的斗地主游戏的发牌过程呢?...
  11. NET上传大文件出现网页无法显示的问题 默认的上传文件大小是4M
  12. android ios 下载地址,Ios/Android h5 唤起本地APP
  13. VISA/MasterCard/AE/DC/JCB卡号结构
  14. 常见的统计图表及其应用
  15. Java 服务接入 OpenTracing(1)--从 Tracing 到 OpenTracing
  16. 23岁IT男与女友分手,扔下200万元分手费走了。。。
  17. 安装Phoenix时,执行./splline.py报错File “./sqlline.py“, line 25, in <module> import phoenix_utils File
  18. Word如何添加标题
  19. android实现mysql数据库存储_一个简单的Android端对象代理数据库系统的实现(二、执行+存储)...
  20. NancyFx系列之 Hello World

热门文章

  1. html 圆圈图表插件,10款强大的JavaScript图表图形插件
  2. 【Visual C++】游戏开发笔记三十四 浅墨DirectX提高班之三 起承转合的艺术:Direct3D渲染五步曲
  3. 基于51单片机的太阳能风能路灯控制器设计(毕设课设资料)
  4. 文件传输协议FTP和开源FTP软件FileZilla
  5. CMU-15112课程笔记
  6. Multi-tissue transcriptome analyses identify genetic mechanisms underlying neuropsychiatric traits
  7. CentOS7设置定时任务 每隔30秒执行一次命令详解
  8. FutureTask 概览
  9. 汽车诊断中常说的DTC是什么?
  10. 电子商务购物管理系统