微信公众号支付 js api java版本

说起来.微信支付真是一堆坑. 居然官网都没有java版本的完整代码. 就算是php版本的.还都有错误.且前后各种版本.各种文档一大堆....不停的误导开发人员.

花了一天半时间.总算实现了微信公众号支付.和pc端的微信扫码支付.其他不说了.直接给思路

本人做的是微信V3版本的微信支付.微信的官方文档中.提供的demo 只有一些工具类.这些类还是很有作用的.

https://mp.weixin.qq.com/paymch/readtemplate?t=mp/business/course3_tmpl&lang=zh_CN  可以在这个连接中找到相应的java类.

这里一定要注意.在官网填写的授权目录一定要写到三级目录.如:

我的回调地址是:http://111.111.111.111:1111/control/weixinPay_notify

那么,官网填写都授权目录就是:http://111.111.111.111:1111/control/

我试过.授权目录写到2级.是没用的.此处差评,第一个坑.

首先,定义各种微信支付所需要的参数

GzhConfig.java

public static String APPID = "XXXXXXXXXXXX";
//受理商ID,身份标识
public static String MCHID = "XXXXXXXXXXXXxx";
//商户支付密钥Key。审核通过后,在微信发送的邮件中查看
public static String KEY = "XXXXXXXXXXXXXXXXX";
//JSAPI接口中获取openid,审核后在公众平台开启开发模式后可查看
public static String APPSECRET = "xxxxxxxxxxxxxx";
//重定向地址
public static String REDIRECT_URL = "http://XXXXXXXXXXXXXXXXXXX/callWeiXinPay";
//异步回调地址
public static String NOTIFY_URL = "http://XXXXXXXXXXXXXXXXXXXXXX/weixinPay_notify";
//web回调地址
public static String WEB_NOTIFY_URL = "http://XXXXXXXXXXXXXXXXXXXXXXXXX/weixinPay_notify";

然后.就是正式的开始代码了:

1.使用Oauth2.0授权.进行页面跳转,获取code .(code关系着后面获取openid.)

https://open.weixin.qq.com/connect/oauth2/authorize?appid=123456789&redirect_uri=http://111.111.111.111:1111/control/orderPay&response_type=code&scope=snsapi_base&state=456123456#wechat_redirect

此处.appid 这个在微信官网可以获取. 重定向地址. 就是获取code 后.跳转指向你的地址.这里可以是你的订单结算页面.response_type=code和scope=snsapi_base 都是固定格式.   state 是传入传出.这个参数用户自定义为任何都可以,比如说订单id. 然后会和code 一起传递到你的重定向地址,如我上面写的重定向地址就是 orderPay链接.

2.在重定向到页面(http://111.111.111.111:1111/control/orderPay)的时候中间执行java方法(如获取openid 如执行微信统一下单接口,获取预支付ID.).处理各种参数.下面贴具体代码做说明.

GzhService.java

String code = request.getParameter("code");
String state = request.getParameter("state");
Debug.log("code-======"+code+"===========state======"+state);
String noncestr = Sha1Util.getNonceStr();//生成随机字符串
String timestamp = Sha1Util.getTimeStamp();//生成1970年到现在的秒数.
//state 可以传递你的订单号.然后根据订单号 查询付款金额.我就不详细写了.
                                
String out_trade_no = state;//订单号
GenericValue orderHeader = delegator.findOne("OrderHeader", UtilMisc.toMap("orderId", out_trade_no),false);
String total_fee = String.valueOf(orderHeader.getBigDecimal("grandTotal").doubleValue()*100);
String order_price = total_fee.substring(0, total_fee.indexOf("."));//订单金额
//微信金额 以分为单位.这是第二坑.如果不注意.页面的报错.你基本看不出来.因为他提示系统升级,正在维护.扯淡.....
String product_name=out_trade_no;//订单名称
//获取jsapi_ticket.此参数是为了生成 js api  加载时候的签名用.必须.jsapi_ticket只会存在7200秒.并且有时间限制,(好像一年还只能调用两万次.所以一定要缓存.)这是第三坑.
//可以在java中模拟url请求.就能获取access_token 然后根据access_token 取得 jsapi_ticket,但一定要缓存起来..这个代码.我只提供获取.缓存你们自己处理.
//SendGET方法我会在后面放出
String tokenParam = "grant_type=client_credential&appid="+GzhConfig.APPID+"&secret="+GzhConfig.APPSECRET;
String tokenJsonStr = SendGET("https://api.weixin.qq.com/cgi-bin/token", tokenParam);
Map tokenMap = JSON.parseObject(tokenJsonStr);
//获取access_token
String access_token = (String)tokenMap.get("access_token");
String ticketParam = "access_token="+access_token+"&type=jsapi";
String ticketJsonStr = SendGET("https://api.weixin.qq.com/cgi-bin/ticket/getticket", ticketParam);
Map ticketMap = JSON.parseObject(ticketJsonStr);
//获取jsapi_ticket
String ticket = (String)ticketMap.get("ticket");
 //下面就到了获取openid,这个代表用户id.
//获取openID
String openParam = "appid="+GzhConfig.APPID+"&secret="+GzhConfig.APPSECRET+"&code="+code+"&grant_type=authorization_code";
String openJsonStr = SendGET("https://api.weixin.qq.com/sns/oauth2/access_token", openParam);
Map openMap = JSON.parseObject(openJsonStr);
String openid = (String) openMap.get("openid");
RequestHandler reqHandler = new RequestHandler(request, response);
 //初始化     RequestHandler  类可以在微信的文档中找到.还有相关工具类    
reqHandler.init();
reqHandler.init(GzhConfig.APPID, GzhConfig.APPSECRET, GzhConfig.KEY, "");
//执行统一下单接口 获得预支付id
reqHandler.setParameter("appid",GzhConfig.APPID);
reqHandler.setParameter("mch_id", GzhConfig.MCHID);                //商户号
reqHandler.setParameter("nonce_str", noncestr);            //随机字符串
reqHandler.setParameter("body", product_name);                        //商品描述(必填.如果不填.也会提示系统升级.正在维护我艹.)
reqHandler.setParameter("out_trade_no", out_trade_no);        //商家订单号
reqHandler.setParameter("total_fee", order_price);                    //商品金额,以分为单位
reqHandler.setParameter("spbill_create_ip",request.getRemoteAddr());   //用户的公网ip  IpAddressUtil.getIpAddr(request)
//下面的notify_url是用户支付成功后为微信调用的action  异步回调.
reqHandler.setParameter("notify_url", GzhConfig.NOTIFY_URL);
reqHandler.setParameter("trade_type", "JSAPI");
//------------需要进行用户授权获取用户openid-------------
reqHandler.setParameter("openid", openid);   //这个必填.
//这里只是在组装数据.还没到执行到统一下单接口.因为统一下单接口的数据传递格式是xml的.所以才需要组装.
String requestUrl = reqHandler.getRequestURL();
                                requestUrl 例子:
 /*
<xml><appid>wx2421b1c4370ec43b</appid><attach>支付测试</attach><body>JSAPI支付测试</body><mch_id>10000100</mch_id><nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str><notify_url>http://wxpay.weixin.qq.com/pub_v2/pay/notify.v2.php</notify_url><openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid><out_trade_no>1415659990</out_trade_no><spbill_create_ip>14.23.150.211</spbill_create_ip><total_fee>1</total_fee><trade_type>JSAPI</trade_type><sign>0CB01533B8C1EF103065174F50BCA001</sign></xml>
*/
                                
Debug.log("requestUrl==================="+requestUrl);
//统一下单接口提交  xml格式
URL orderUrl = new URL("https://api.mch.weixin.qq.com/pay/unifiedorder");
HttpURLConnection conn = (HttpURLConnection) orderUrl.openConnection();
conn.setConnectTimeout(30000); // 设置连接主机超时(单位:毫秒)
conn.setReadTimeout(30000); // 设置从主机读取数据超时(单位:毫秒)
conn.setDoOutput(true); // post请求参数要放在http正文内,顾设置成true,默认是false
conn.setDoInput(true); // 设置是否从httpUrlConnection读入,默认情况下是true
conn.setUseCaches(false); // Post 请求不能使用缓存
// 设定传送的内容类型是可序列化的java对象(如果不设此项,在传送序列化对象时,当WEB服务默认的不是这种类型时可能抛java.io.EOFException)
conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
conn.setRequestMethod("POST");// 设定请求的方法为"POST",默认是GET
conn.setRequestProperty("Content-Length",requestUrl.length()+"");
String encode = "utf-8";
OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream(), encode);
out.write(requestUrl.toString());
out.flush();
out.close();
String result = getOut(conn);
Debug.log("result=========返回的xml============="+result);
Map<String, String> orderMap = XMLUtil.doXMLParse(result);
Debug.log("orderMap==========================="+orderMap);
//得到的预支付id
String prepay_id = orderMap.get("prepay_id");
SortedMap<String,String> params = new TreeMap<String,String>();
params.put("appId", GzhConfig.APPID);
params.put("timeStamp",timestamp);
params.put("nonceStr", noncestr);
params.put("package", "prepay_id="+prepay_id);
params.put("signType", "MD5");
        
//生成支付签名,这个签名 给 微信支付的调用使用
String paySign =  reqHandler.createSign(params);        
request.setAttribute("paySign", paySign);
request.setAttribute("appId", GzhConfig.APPID);
request.setAttribute("timeStamp", timestamp);        //时间戳
request.setAttribute("nonceStr", noncestr);            //随机字符串
request.setAttribute("signType", "MD5");        //加密格式
request.setAttribute("out_trade_no", out_trade_no);          //订单号
request.setAttribute("package", "prepay_id="+prepay_id);//预支付id ,就这样的格式.
String url = "http://xxxxxxxxxx/control/wxPayment";
String signValue = "jsapi_ticket="+ticket+"&noncestr="+noncestr+"&timestamp="+timestamp+"&url="+url;
Debug.log("url====="+signValue);
//这个签名.主要是给加载微信js使用.别和上面的搞混了.
String signature = Sha1Util.getSha1((signValue));
request.setAttribute("signature", signature);

//此页面的一些其他方法

public static String getOut(HttpURLConnection conn) throws IOException{
        if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
            return null;
        }
        // 获取响应内容体
        BufferedReader in = new BufferedReader(new InputStreamReader(
                conn.getInputStream(), "UTF-8"));
        String line = "";
        StringBuffer strBuf = new StringBuffer();
        while ((line = in.readLine()) != null) {
            strBuf.append(line).append("\n");
        }
        in.close();
        return  strBuf.toString().trim();
}
public static String SendGET(String url,String param){
   String result="";//访问返回结果
   BufferedReader read=null;//读取访问结果
    
   try {
    //创建url
    URL realurl=new URL(url+"?"+param);
    //打开连接
    URLConnection connection=realurl.openConnection();
     // 设置通用的请求属性
             connection.setRequestProperty("accept", "*/*");
             connection.setRequestProperty("connection", "Keep-Alive");
             connection.setRequestProperty("user-agent",
                     "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
             //建立连接
             connection.connect();
          // 获取所有响应头字段
//             Map<String, List<String>> map = connection.getHeaderFields();
             // 遍历所有的响应头字段,获取到cookies等
//             for (String key : map.keySet()) {
//                 System.out.println(key + "--->" + map.get(key));
//             }
             // 定义 BufferedReader输入流来读取URL的响应
             read = new BufferedReader(new InputStreamReader(
                     connection.getInputStream(),"UTF-8"));
             String line;//循环读取
             while ((line = read.readLine()) != null) {
                 result += line;
             }
   } catch (IOException e) {
    e.printStackTrace();
   }finally{
    if(read!=null){//关闭流
     try {
      read.close();
     } catch (IOException e) {
      e.printStackTrace();
     }
    }
   }
     
   return result; 
 }

其他相关类的方法:

/*

‘============================================================================

‘api说明:

‘createSHA1Sign创建签名SHA1

‘getSha1()Sha1签名

‘============================================================================

‘*/

public class Sha1Util {
public static String getNonceStr() {
Random random = new Random();
return MD5Util.MD5Encode(String.valueOf(random.nextInt(10000)), "UTF-8");
}
public static String getTimeStamp() {
return String.valueOf(System.currentTimeMillis() / 1000);
}
   //创建签名SHA1
public static String createSHA1Sign(SortedMap<String, String> signParams) throws Exception {
StringBuffer sb = new StringBuffer();
Set es = signParams.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();
sb.append(k + "=" + v + "&");
//要采用URLENCODER的原始值!
}
String params = sb.substring(0, sb.lastIndexOf("&"));
System.out.println("sha1 sb:" + params);
return getSha1(params);
}
//Sha1签名
public static String getSha1(String str) {
if (str == null || str.length() == 0) {
return null;
}
char hexDigits[] = { ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘, ‘f‘ };
try {
MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
mdTemp.update(str.getBytes("GBK"));
byte[] md = mdTemp.digest();
int j = md.length;
char buf[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
buf[k++] = hexDigits[byte0 & 0xf];
}
return new String(buf);
} catch (Exception e) {
return null;
}
}
}

/**

* xml工具类

* @author  miklchen

*

*/

public class XMLUtil {
/**
 * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
 * @param  strxml
 * @return 
 * @throws  JDOMException
 * @throws  IOException
 */
public static Map<String,String> doXMLParse(String strxml) throws JDOMException, IOException {
if(null == strxml || "".equals(strxml)) {
return null;
}
Map<String,String> m = new HashMap<String,String>();
InputStream in = HttpClientUtil.String2Inputstream(strxml);
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(in);
Element root = doc.getRootElement();
List list = root.getChildren();
Iterator it = list.iterator();
while(it.hasNext()) {
Element e = (Element) it.next();
String k = e.getName();
String v = "";
List children = e.getChildren();
if(children.isEmpty()) {
v = e.getTextNormalize();
} else {
v = XMLUtil.getChildrenText(children);
}
m.put(k, v);
}
//关闭流
in.close();
return m;
}
/**
 * 获取子结点的xml
 * @param children
 * @return String
 */
public static String getChildrenText(List children) {
StringBuffer sb = new StringBuffer();
if(!children.isEmpty()) {
Iterator it = children.iterator();
while(it.hasNext()) {
Element e = (Element) it.next();
String name = e.getName();
String value = e.getTextNormalize();
List list = e.getChildren();
sb.append("<" + name + ">");
if(!list.isEmpty()) {
sb.append(XMLUtil.getChildrenText(list));
}
sb.append(value);
sb.append("</" + name + ">");
}
}
return sb.toString();
}
/**
 * 获取xml编码字符集
 * @param strxml
 * @return
 * @throws IOException 
 * @throws JDOMException 
 */
public static String getXMLEncoding(String strxml) throws JDOMException, IOException {
InputStream in = HttpClientUtil.String2Inputstream(strxml);
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(in);
in.close();
return (String)doc.getProperty("encoding");
}
}
public class MD5Util {
private static String byteArrayToHexString(byte b[]) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++)
resultSb.append(byteToHexString(b[i]));
return resultSb.toString();
}
private static String byteToHexString(byte b) {
int n = b;
if (n < 0)
n += 256;
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
}
public static String MD5Encode(String origin, String charsetname) {
String resultString = null;
try {
resultString = new String(origin);
MessageDigest md = MessageDigest.getInstance("MD5");
if (charsetname == null || "".equals(charsetname))
resultString = byteArrayToHexString(md.digest(resultString
.getBytes()));
else
resultString = byteArrayToHexString(md.digest(resultString
.getBytes(charsetname)));
} catch (Exception exception) {
}
return resultString;
}
private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
}

下面才到了页面代码:jsp 页面

<script type="text/javascript" src="/xxxx/jquery-1.6.2.min.js"></script>
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<script language="javascript">
//加载
wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: ‘${StringUtil.wrapString(requestAttributes.appId)!}‘, // 必填,公众号的唯一标识
    timestamp: ${StringUtil.wrapString(requestAttributes.timeStamp)?default(0)!}, // 必填,生成签名的时间戳
    nonceStr: ‘${StringUtil.wrapString(requestAttributes.nonceStr)!}‘, // 必填,生成签名的随机串
    signature: ‘${StringUtil.wrapString(requestAttributes.signature)!}‘,// 必填,签名,见附录1
    jsApiList: [
    ‘checkJsApi‘,
            ‘chooseWXPay‘] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
wx.ready(function(){
//支付
wx.chooseWXPay({
    timestamp: ${StringUtil.wrapString(requestAttributes.timeStamp)?default(0)!}, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
    nonceStr: ‘${StringUtil.wrapString(requestAttributes.nonceStr)!}‘, // 支付签名随机串,不长于 32 位
    package: ‘${StringUtil.wrapString(requestAttributes.package)!}‘, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
    signType: ‘${StringUtil.wrapString(requestAttributes.signType)!}‘, // 签名方式,默认为‘SHA1‘,使用新版支付需传入‘MD5‘
    paySign: ‘${StringUtil.wrapString(requestAttributes.paySign)!}‘, // 支付签名
    success: function (res) {
        // 支付成功后的回调函数
        WeixinJSBridge.log(res.err_msg);
        //alert("支付接口:"+res.err_code + res.err_desc + res.err_msg);
        if(!res.err_msg){
                    //支付完后.跳转到成功页面.
        location.href="orderconfirm?orderId=${StringUtil.wrapString(requestAttributes.out_trade_no)!}";
        }
    }
});
    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
});
wx.error(function(res){
    // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
});
wx.checkJsApi({
    jsApiList: [‘chooseWXPay‘], // 需要检测的JS接口列表,所有JS接口列表见附录2,
    success: function(res) {
    //alert("检测接口:"+res.err_msg);
    }
    });
</script>

下面是后台异步回调代码:

/**
 * 异步返回
 */
@SuppressWarnings("deprecation")
public static String weixinNotify(HttpServletRequest request, HttpServletResponse response){
        try {
        
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);
}
outSteam.close();
inStream.close();
String resultStr  = new String(outSteam.toByteArray(),"utf-8");
Map<String, String> resultMap = XMLUtil.doXMLParse(resultStr);
String result_code = resultMap.get("result_code");
String is_subscribe = resultMap.get("is_subscribe");
String out_trade_no = resultMap.get("out_trade_no");
String transaction_id = resultMap.get("transaction_id");
String sign = resultMap.get("sign");
String time_end = resultMap.get("time_end");
String bank_type = resultMap.get("bank_type");
String return_code = resultMap.get("return_code");
//签名验证
GenericValue userLogin =delegator.findOne("UserLogin", UtilMisc.toMap("userLoginId","admin"),false);
if(return_code.equals("SUCCESS")){
    //此处就是你的逻辑代码
        }
 request.setAttribute("out_trade_no", out_trade_no);
//通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
response.getWriter().write(RequestHandler.setXML("SUCCESS", ""));
} catch (UnsupportedEncodingException e) { 
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JDOMException e) {
e.printStackTrace();
} 
return "success";
}

代码中,删除了一些和公司相关的代码.所以如果直接复制进去.肯定是要做大量修改的.见谅.

时间: 2024-10-10 22:31:17

微信公众号支付 js api java版本的相关文章

微信公众号支付开发全过程 --JAVA

按照惯例,开头总得写点感想 ------------------------------------------------------------------ 业务流程 这个微信官网说的还是很详细的,还配了图.我还要再说一遍. 用户点击一个支付按钮-->{后台一大推处理}-->用户看到了一个输入密码的界面,包含金额等一些信息-->用户输入密码后出来一个支付成功的页面(这部分流程都是微信自己完成的,我们什么都不用做)-->返回系统自己的页面(总不能让用户一直看着一个支付完成的页面吧

微信公众号支付(提供MVC版本)

一:获取微信支付 MCHID,KEY,APPID,APPSecret 四个支付关键值.      微信支付商户平台 https://pay.weixin.qq.com/index.php/core/home/login?return_url=%2F  1.登录微信支付商户平台获取到商户号(MCHID),  2.在"账号中心"栏目下"API安全"栏目里设置API密钥(KEY)   微信公众号: https://mp.weixin.qq.com/     1.登录微信公

微信公众号的开发教程Java版本

1.首先,去官网注册一个微信公众号 2.点击开发者中心,填写服务器配置信息 3.通过ngrok来映射本地的请求到服务器端 4.通过代码来验证请求,并给出相应的回复,不多说,贴代码 package com.weixin.action; import java.io.IOException; /* * 第一次请求的时候是get请求,用户验证 * 第二次请求就是Post请求,传递消息和返回消息 */ import java.io.PrintWriter; import java.util.Map; i

2017-9月微信公众号支付-Java详解

微信支付源代码 在此之前,先C麻瓜藤N遍,MD官方文档一半正确一半错误.言归正传, 微信支付整体流程:微信授权登录商户的公众号--微信支付的公众号配置--统一下单--微信js调起支付页面--输入密码支付--支付成功,异步回调URL处理商户的相应业务 一.业务场景: 先看一下支付的业务场景:用户使用微信登录商户页面,点击支付按钮,调起微信支付,选择付款卡号,输入密码,完成支付,如图: 场景十分简单,不过步骤比较多,稍不注意就掉坑里了. 二.微信公众号支付的配置准备: 1)调用公众号支付,首先你得有

微信公众号支付H5调用支付详解

最近项目需要微信支付,然后看了下微信公众号支付,,虽然不难,但是细节还是需要注意的,用了大半天时间写了个demo,并且完整的测试了一下支付流程,下面分享一下微信公众号支付的经验. 一.配置公众号微信支付 需要我们配置微信公众号支付地址和测试白名单. 比如:支付JS页面的地址为 http://www.xxx.com/shop/pay/ 那此处配置www.xxx.com/shop/pay/ 二.开发流程 借用微信公众号支付api(地址 http://pay.weixin.qq.com/wiki/do

微信公众号支付总结

微信公众号支付总结大致可以分为三步, 第一步获取用户授权,第二步调用统一下单接口获取预支付id,第三步H5调起微信支付的内置JS进行支付. 注意: 不得不提的是,每个公众号(公众平台),每一个APP(开放平台), 如果要进行微信支付得单独进行开通微信支付功能.开通成功后会为每一个公众号,APP 分配一个商户号.最开始没有搞清楚这层关系,导致出现类似"appid与商户号没有关联",授权时没有"scope 权限"这样的问题. 获取用户授权 String wxaccess

使用开源库MAGICODES.WECHAT.SDK进行微信公众号支付开发

概要 博客使用Word发博,发布后,排版会出现很多问题,敬请谅解.可加群获取原始文档. 本篇主要讲解微信支付的开发流程,相关业务基于MAGICODES.WECHAT.SDK实现.通过本篇教程,您可以很方便的快速完成微信公众号支付的开发. 关于Magicodes.WeChat.SDK MAGICODES.WECHAT.SDK为心莱团队封装的轻量级微信SDK,现已全部开源,开源库地址为:https://github.com/xin-lai/Magicodes.WeChat.SDK 更多介绍,请关注后

thinkphp整合系列之微信公众号支付

thinkphp整合系列之微信公众号支付 白俊遥 2016-07-17 11:26:52 PHP thinkphp 公众号支付是指在微信app中访问的页面通过js直接调起微信支付:因此页面必须是在微信中打开的:示例项目:https://github.com/baijunyao/thinkphp-bjyadmin一:设置域名登录微信公众平台:微信支付中设置支付授权目录:把域名改为自己的:注意最后是有一个斜线的 / 设置授权域名:二:导入sdk/ThinkPHP/Library/Vendor/Wei

微信公众号支付踩坑记

前两周做微信H5支付,在浏览器端用的,天真地以为app挂到公众号中也能用,结果不行>"<|||| ,只好再对接一次公众号支付,微信的支付对接下来总体感觉就是封装地不如支付宝,文档不完善,坑贼多.本文会主要关注对接过程中所遇到的问题,以及部分实现代码. 1.介绍 公众号支付(JSAPI支付)是指用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块来完成支付,适用于在公众号.朋友圈.聊天窗口等微信内完成支付的场景.注意公众号支付必须在微信环境