2018-09-21 11:40:30 zds12345sdfs 阅读数 188
  • 微信公众号开发9-公众号JSSDK开发-微信开发php

    微信公众平台开发之公众号JSSDK开发是子恒老师《微信公众平台开发》视频教程的第9部。详细讲解了用php开发微信公众号,对微信公众平台中的JSSDK开发。内容包含用JSSDK获取网络状态,地理位置,分享到朋友圈,QQ,空间设置等等。欢迎反馈,微信/QQ:68183131

    14972 人正在学习 去看看 秦子恒

微信支付分为好几种,我要记录的是微信公众号支付网页微信扫码支付这两种:

现在来讲一讲微信公众号支付,(网页微信扫码支付会在下一篇博客讲,这篇博客讲的是微信公众号支付):

无论是微信公众号支付还是网页微信扫码支付都要准备好以下条件,接下来的调用接口需要用到:

1.已成功认证的微信公众号(服务号),拿到公众号的AppID,AppSecret;订阅号无论是否认证很多接口都调用不了建议不要用。

看图说话:

 

2.在公众号上开通 商户平台,拿到商户号app商户秘钥;

3.一个公网可以访问到的服务器和一个公网可以访问到的域名,这里不管你是买服务器买域名还是用内网穿透软件都行,只要能让公网访问到自己写的后台程序就ok。注意:公网访问不能带端口号

以上这些准备妥当之后就可以进行微信公众号支付开发了

微信支付这块第一步问题很多,走出了之后就不怎么难了;

第一步获取用户信息之后然后再跳转到支付页面:关键词openid

           点击进入到支付页面的同时需要获取用户的当前基本信息其中包括openid(微信用户唯一标识,名词解释自己去微信官网了解);

当用户点击支付时让用户直接进入以下方法中,获取到用户信息后然后再重定向到页面(注意:我这里用的是ssh框架);

所以我的进入支付的链接就是进入后台方法的链接:http://域名/WeChat/WxPaycode.action?biao=1

这个biao的参数是我个人的业务需求,是为了后续跳转用的,不需要就不加!

// 获取code 微信支付第一步
public String code() {
		String redirect_uri="";
		try {
        //redirect_uri 是访问微信接口之后的回调地址,我这边是回调到action WxPay的openid方法去
			if(biao==1){
				redirect_uri = URLEncoder.encode(WeiXinUtil.ip + "WxPayopenid.action?biao=1", "utf-8");
			}else if(biao==2){
				redirect_uri = URLEncoder.encode(WeiXinUtil.ip + "WxPayopenid.action?biao=2", "utf-8");
			}
			String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="
					+ WeiXinUtil.appid
					+ "&redirect_uri="
					+ redirect_uri
					+ "&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
			//scope作用域,这里是获取基本信息snsapi_base,如果要获取详细信息就不一样,不同之处对照微信官方文档
//基本信息就获取openid,详细信息是获取包括openid、用户头像等等的信息
			ServletActionContext.getResponse().sendRedirect(url);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

 代码中的WeiXinUtil是一个实体类,主要是放一下调用微信接口常用的数据,例如公众号的appid:

WeiXinUtil.java

/**
 * 微信支付用到的商家数据
 * @author QT-666
 *
 */
public class WeiXinUtil {
	public static String appid ="*********************";//公众号应用id
	
	public static String secret ="***********************";//应用秘钥
	
	public static String APIid ="*****************************";//商户支付api秘钥
	
	public static String ip = "http://域名/WeChat/";//域名或IP地址
	
//	public static String ip = "http://域名/WeChat/";//域名或IP地址
	
	public static String account = "******";//微信商户支付号
 

       
}

 把上面的 “ * ” 号替换为自己的真实数据

紧跟第一个方法的 回调地址中的openid方法:

// 获取open_id; 第二步:由第一步自动回调到这个方法,然后在这个方法里自动重定向到支付页面
	public String openid() {
		HttpSession session = request.getSession();

		String code = request.getParameter("code");

		try {
			String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="
					+ WeiXinUtil.appid
					+ "&secret="
					+ WeiXinUtil.secret
					+ "&code=" + code + "&grant_type=authorization_code";
			if (code != null) {
				String json = HttpUtils.get(requestUrl);//HttpUtils是远程访问工具类,代码后面提供
                //new Gson().fromJson不知道就去百度
				WechatResult result = new Gson().fromJson(json,
						WechatResult.class);//WechatResult返回值接收实体类,其中就有openid属性,代码后面提供
				String OPEN_ID = result.getOpenid();
				String access_token = result.getAccess_token();
				session.setAttribute("token", access_token);
				session.setAttribute("open_id", OPEN_ID); // 存入open_id
                //因为我这要保存一下支付记录,所以我这里需要保存用户信息的业务逻辑
				UserInfo u = userService.findUserByOpenId(OPEN_ID);
				int id=0;
				if (u == null) {
					UserInfo user = new UserInfo();
					user.setFake(0); 
					user.setUser_score(200);
					user.setUser_name("");
					user.setUser_phone("1");
					user.setOpen_id(OPEN_ID);
					id = userService.addUser(user);// 添加后的主键
					session.setAttribute("user", user);
				}
				session.setAttribute("user", u);
				if(biao==1){//重定向到支付页面
					ServletActionContext.getResponse().sendRedirect(
							WeiXinUtil.ip + "wxpay/pay.html");
					return null;
				}else if(biao==2){
					ServletActionContext.getResponse().sendRedirect(
							WeiXinUtil.ip + "wxpay/info.jsp");
					return null;
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

 到这里就已经获取到用户的信息了,接下来就到支付页面去了;openid已拿到!第一步完成了!!

WechatResult.java,省略了get set方法

/**
 * 用户授权信息类
 * @author QT-666
 *
 */
public class WechatResult {
	private String access_token;	//网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
	private int expires_in;	//access_token接口调用凭证超时时间,单位(秒)
	private String refresh_token;	//用户刷新access_token
	private String openid;	//用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
	private String scope;	//用户授权的作用域,使用逗号(,)分隔

HttpUtils.java一般这种访问接口都会用到这种工具类,可以根据自己需求修改,网上很多,各色各样。不过我还是在这里提供一份我用的吧!

package com.game.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.Key;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;

import org.apache.http.NameValuePair;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import com.game.model.Find_university;
import com.game.model.Select_info;
import com.google.gson.JsonArray;

/**
 * http post 提交 和 get请求
 * @author QT-666
 *
 */
public class HttpUtils {
 private static RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(15000).setConnectTimeout(15000)
   .setConnectionRequestTimeout(15000).build();

 public static void get(String url, Map<String, String> params){
	    CloseableHttpClient httpClient = null;
	    HttpGet httpGet = null;
	    try {
	        httpClient = HttpClients.createDefault();
	        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(20000).setConnectTimeout(20000).build();
	        String ps = "";
	        for (String pKey : params.keySet()) {
	            if(!"".equals(ps)){
	                ps = ps + "&";
	            }
	            ps = pKey+"="+params.get(pKey);
	        }
	        if(!"".equals(ps)){
	            url = url + "?" + ps;
	        }
	        httpGet = new HttpGet(url);
	        httpGet.setConfig(requestConfig);
	        CloseableHttpResponse response = httpClient.execute(httpGet);
	        HttpEntity httpEntity = response.getEntity();
	        System.out.println(EntityUtils.toString(httpEntity,"utf-8"));
	    } catch (ClientProtocolException e) {
	        e.printStackTrace();
	    } catch (IOException e) {
	        e.printStackTrace();
	    }finally{
	        try {
	            if(httpGet!=null){
	                httpGet.releaseConnection();
	            }
	            if(httpClient!=null){
	                httpClient.close();
	            }
	        } catch (IOException e) {
	            e.printStackTrace();
	        }
	    }
	}
 /** 
     * 发送 post请求 
     * @param httpUrl 地址 
     * @param maps 参数 
     */  
 public static void post(String url, Map<String, String> params){
	    CloseableHttpClient httpClient = null;
	    HttpPost httpPost = null;
	    try {
	        httpClient = HttpClients.createDefault();
	        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(20000).setConnectTimeout(20000).build();
	        httpPost = new HttpPost(url);
	        httpPost.setConfig(requestConfig);
	        List<NameValuePair> ps = new ArrayList<NameValuePair>();
	        for (String pKey : params.keySet()) {
	            ps.add(new BasicNameValuePair(pKey, params.get(pKey)));
	        }
	        httpPost.setEntity(new UrlEncodedFormEntity(ps));
	        CloseableHttpResponse response = httpClient.execute(httpPost);
	        HttpEntity httpEntity = response.getEntity();
	        System.out.println(EntityUtils.toString(httpEntity,"utf-8"));
	    } catch (ClientProtocolException e) {
	        e.printStackTrace();
	    } catch (IOException e) {
	        e.printStackTrace();
	    }finally{
	        try {
	            if(httpPost!=null){
	                httpPost.releaseConnection();
	            }
	            if(httpClient!=null){
	                httpClient.close();
	            }
	        } catch (IOException e) {
	            e.printStackTrace();
	        }
	    }
	}
 /** 
     * 发送post请求Https,参数是字符串 
     * @param httpPost 
     * @return 
     */  
 public static String post(String url, String body) throws Exception{
	    String str="";
	    CloseableHttpClient httpClient = null;
	    HttpPost httpPost = null;
	    try {
	        httpClient = HttpClients.createDefault();
	        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(20000).setConnectTimeout(20000).build();
	        httpPost = new HttpPost(url);
	        httpPost.setConfig(requestConfig);
	        httpPost.setEntity(new StringEntity(body,"utf-8"));
	        CloseableHttpResponse response = httpClient.execute(httpPost);
	        HttpEntity httpEntity = response.getEntity();
	        str = EntityUtils.toString(httpEntity,"utf-8");
	       
	      
	  
	    } catch (ClientProtocolException e) {
	        e.printStackTrace();
	    } catch (IOException e) {
	        e.printStackTrace();
	    }finally{
	        try {
	            if(httpPost!=null){
	                httpPost.releaseConnection();
	            }
	            if(httpClient!=null){
	                httpClient.close();
	            }
	        } catch (IOException e) {
	            e.printStackTrace();
	        }
	    }
	    return new String(str.getBytes("iso-8859-1"));
	}
 public static String get(String strURL) throws Exception{
	
	 URL url = new URL(strURL);  
	 HttpURLConnection httpConn = (HttpURLConnection)  
	         url.openConnection();  
	 httpConn.setRequestMethod("GET");  
	 httpConn.connect();  
	   
	 BufferedReader reader = new BufferedReader(new InputStreamReader(  
	         httpConn.getInputStream(),"utf-8"));  
	 String line;  
	 StringBuffer buffer = new StringBuffer();  
	 while ((line = reader.readLine()) != null) {  
	     buffer.append(line);  
	 }  
	 reader.close();  
	 httpConn.disconnect();  

	 return buffer.toString();
	}
 
 //url表示请求链接,param表示json格式的请求参数		//自定义菜单创建访问方式
 public static String sendPost(String url, Object param) {
     PrintWriter out = null;
     BufferedReader in = null;
     String result = "";
     try {
         URL realUrl = new URL(url);
         // 打开和URL之间的连接
         URLConnection conn = realUrl.openConnection();
         // 设置通用的请求属性 注意Authorization生成
         // conn.setRequestProperty("Content-Type",
         // "application/x-www-form-urlencoded");
         // 发送POST请求必须设置如下两行
         conn.setDoOutput(true);
         conn.setDoInput(true);
         // 获取URLConnection对象对应的输出流
         out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(),"utf-8"));
         // 发送请求参数
         out.print(param);
         // flush输出流的缓冲
         out.flush();
         // 定义BufferedReader输入流来读取URL的响应
         in = new BufferedReader(
                 new InputStreamReader(conn.getInputStream(),"utf-8"));
         String line;
         while ((line = in.readLine()) != null) {
             result += line;
         }
         System.out.println(result);
     } catch (Exception e) {
         System.out.println("发送 POST 请求出现异常!" + e);
         e.printStackTrace();
     }
     // 使用finally块来关闭输出流、输入流
     finally {
         try {
             if (out != null) {
                 out.close();
             }
             if (in != null) {
                 in.close();
             }
         } catch (IOException ex) {
             ex.printStackTrace();
         }
     }
     return result;
 }
 public List<Select_info> PostUrl(String url) throws Exception{
		 //获取查询信息URLEncoder.encode(q, "UTF-8")
		 //String msg = ht.get("http://域名/api/GetCollegeResult/GetRecommendResult?localAreas=陕西&score_rank=1123&areas=河北,江西,陕西&majors=预防医学(五年)&ftype=2&f_type=236");
		 //请求获取返回字符(中文转16进制)
	     String ur="http://域名/api/GetCollegeResult/GetRecommendResult?localAreas="+URLEncoder.encode("陕西","UTF-8")+"&score_rank=1123&areas="+URLEncoder.encode("河北,江西,陕西","UTF-8")+"&majors="+URLEncoder.encode("预防医学(五年)","UTF-8")+"&ftype=2&f_type=236";
	     //String msg = get("http://域名/api/GetCollegeResult/GetRecommendResult?localAreas=%E9%99%95%E8%A5%BF&score_rank=1123&areas=%E6%B2%B3%E5%8C%97,%E6%B1%9F%E8%A5%BF,%E9%99%95%E8%A5%BF&majors=%E9%A2%84%E9%98%B2%E5%8C%BB%E5%AD%A6(%E4%BA%94%E5%B9%B4)&ftype=2&f_type=236");
	     String msg = get(ur);
		 //信息分段截取
		 //1.去掉字符串第一个和最后一个
		 String str = msg.substring(0,msg.length()-1);
		 str=str.substring(1);
		 //数据为["3823d737-d9ed-4556-a0f5-c7a52af8bf50","XITKSTIT","南昌大学","康复治疗学","3","0","",0,"2018-06-14T23:30:49","2018-06-14T23:30:49","1","101005",null,null,545.0,14402.0],[....
		 //2.对以上数据进行分段,通过‘[’,']'进行分段
		//过滤其他[
		 //使用List集合保存对象
		 List<Select_info>list=new ArrayList<Select_info>();
		 //创建对象
		 Select_info info=new Select_info();
		 String s="";
		 String st= str.replace("[","");
		 st= str.replace("\"","");
		 String[]split =st.split("],");
		 for(int i=0;i<split.length;i++){
			 if(i>split.length){
				 break;
			 }
			 
			 for(int j=0;j<16;j++){
				 s=split[i].toString();
				 String[]spli =s.split(",");
				 //对象拼接
				 info.setId(spli[0]);
				 info.setF_query_termId(spli[1]);
				 info.setColleges(spli[2]);
				 info.setMajors(spli[3]);
				 info.setF_type(spli[4]);
				 info.setIsPay(spli[5]);
				 info.setRemark(spli[6]);
				 //info.setStatus(spli[7]);
				 info.setModified(spli[8]);
				 info.setCreated(spli[9]);
				 info.setF_typeD(spli[10]);
				 info.setMajors_code(spli[11]);
				 info.setMajors_advantage(spli[12]);
				 info.setMajors_evaluation(spli[13]);
				//info.setMajors_score(spli[14]);
				 //info.setMajors_rank(spli[15]);
				 list.add(i, info);
				 if(spli[j]==null){
					 break;
				 }
			 }
				 System.out.println("获取"+list.size());
		 }
		return list;
	}
 public  String getUrl(String url) throws Exception{
	 
	 String msg = get(url);
	 
	 return msg;
	 
 }
 
 
 public static void main(String[] args) throws Exception {
	 String code="";
	 String url ="http://域名/api/getcollegeresult/GetMajors?key="
				+URLEncoder.encode("软件技术","UTF-8");
	 HttpUtils du =new HttpUtils();
	 code = du.getUrl(url);
	 System.out.println(code);
	 /*//获取查询信息
	 String msg = get("http://域名/api/GetCollegeResult/GetRecommendResult?localAreas=陕西&score_rank=1123&areas=河北,江西,陕西&majors=预防医学(五年)&ftype=2&f_type=236");
	 //信息分段截取
	 //1.去掉字符串第一个和最后一个
	 String str = msg.substring(0,msg.length()-1);
	 str=str.substring(1);
	 //数据为["3823d737-d9ed-4556-a0f5-c7a52af8bf50","XITKSTIT","南昌大学","康复治疗学","3","0","",0,"2018-06-14T23:30:49","2018-06-14T23:30:49","1","101005",null,null,545.0,14402.0],[....
	 //2.对以上数据进行分段,通过‘[’,']'进行分段
	//过滤其他[
	 //使用List集合保存对象
	 List<Select_info>list=new ArrayList<Select_info>();
	 //List<Select_info>list2=new ArrayList<Select_info>();
	 int ids=3;
	 Select_info info=new Select_info();
	 String s="";
	 String st= str.replace("[","");
	 st= str.replace("\"","");
	 String[]split =st.split("],");
	 for(int i=0;i<split.length;i++){
		 if(i>split.length){
			 break;
		 }
		 
		 for(int j=0;j<16;j++){
			 s=split[i].toString();
			 String[]spli =s.split(",");
			 info.setId(spli[0]);
			 info.setF_query_termId(spli[1]);
			 info.setColleges(spli[2]);
			 info.setMajors(spli[3]);
			 info.setF_type(spli[4]);
			 info.setIsPay(spli[5]);
			 info.setRemark(spli[6]);
			 info.setStatus(spli[7]);
			 info.setModified(spli[8]);
			 info.setCreated(spli[9]);
			 info.setF_typeD(spli[10]);
			 info.setMajors_code(spli[11]);
			 info.setMajors_advantage(spli[12]);
			 info.setMajors_evaluation(spli[13]);
			 info.setMajors_score(spli[14]);
			 info.setMajors_rank(spli[15]);
			 list.add(i, info);
			 if(spli[j]==null){
				 break;
			 }
			 //info.setId(spli[j]);
			 //System.out.println(spli[j]);
		 }
		 //
			 System.out.println(list.get(i).getMajors());
		 
	 }
	 */
	 //分段数据序列成数组
	 //String[]split =str.split(",");
	 
       
	 
	 
	 //创建自定义菜单
	 /*String url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=7__Q8qY7aZYK13ASiiEzidF4W87d4arKZXJApUHAEsQRyrDDb8iGrtuMKIX809fikh7u1H8x-_VW0OTsIm2Ha3YsbfX4SppMPsN5kBJ10EJdqU35e7bAbJUgNLYZoIBTgAIALEW";
	 JSONObject menu = JSONObject.fromObject(demo.initMenu());
	 String msg = sendPost(url,menu);*/
	 //获取自定义菜单配置接口
	 /*String url = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=7__Q8qY7aZYK13ASiiEzidF4W87d4arKZXJApUHAEsQRyrDDb8iGrtuMKIX809fikh7u1H8x-_VW0OTsIm2Ha3YsbfX4SppMPsN5kBJ10EJdqU35e7bAbJUgNLYZoIBTgAIALEW";
     String msg = get(url);*/
	 //System.out.println(msg);
 }
}

 工具类的话没什么可说的,会用就行;

第二步,支付页面上的花里胡哨环境配置!

         这一步也繁琐,一点错都不能有,因为要真正开始调用微信js开放接口了,页面环境要配置完美ok才能调用微信js开放接口中的微信支付方法

这里所说的支付页面环境配置就是wx.config里面的配置,要返回config:ok 了就万事大吉了!这里推荐个可以在电脑端就可以看到wx.config是否ok的工具,就是微信官方推出的微信web开发者工具,需要的话自己去微信官网上下载!因为这种微信接口方面的报错在微信手机端是看不到的,只有这工具能显示支付页面出到底是哪里错了!

直接上支付页面代码吧,不废话!

<!doctype html>
<html>
  <head>
    <title>充值</title>
    <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<link rel="stylesheet" href="css/jquery-weui.min.css">
<link rel="stylesheet" href="css/weui.min.css">
<script src="https://res.wx.qq.com/open/js/jweixin-1.0.0.js "></script>
<script src="http://pv.sohu.com/cityjson?ie=utf-8"></script>
<script src="js/jquery-2.1.4.js"></script>
<style>
        .pay{ width:100%; height:150px;}
        ul {  
            margin-left:10px;  
            margin-right:10px;  
            margin-top:10px;  
            padding: 0;  
        }  
        li {  
            width: 32%;  
            float: left;  
            margin: 0px;  
            margin-left:1%;  
            padding: 0px;  
            height: 60px;  
            display: inline;  
            line-height:60px;  
            color: #fff;  
            font-size:16px;  
            word-break:break-all;  
            word-wrap : break-word;  
            margin-bottom: 5px;  
        }  
        a {  
            -webkit-tap-highlight-color: rgba(0,0,0,0);
			background:rgba(204,204,204,0.3)
			width: 48%;
			height: 60px;  
            text-decoration:none;  
            color:#000;  
        }  
        a:link{  
            -webkit-tap-highlight-color: rgba(0,0,0,0);  
            text-decoration:none;  
            color:#000;  
        }  
        a:visited{  
            -webkit-tap-highlight-color: rgba(0,0,0,0);  
            text-decoration:none;  
            color:#000;  
        }  
        a:hover{  
            -webkit-tap-highlight-color:rgba(0,0,0,0);
            text-decoration:none;
            color:#fff;  
        }  
        a:active{  
            -webkit-tap-highlight-color:rgba(0,0,0,0);  
            text-decoration:none;
             
        }  
.dan{width:90%; height:auto; margin-left:5%;}
.option-input {
 -webkit-appearance: none;
 width: 30px;
 height: 30px;
 
 float:right;
 background: #cbd1d8;
 border: none;
 color: #fff;
 cursor: pointer;
 display: inline-block;
 outline: none;
 margin-right: 0.5rem;
 z-index: 1000;
}
.option-input:checked {
 background:#F00;
}
.option-input:checked::before {
 width: 30px;
 height: 30px;
 position: absolute;
 content: '\2714';
 display: inline-block;
 font-size: 26.66667px;
 text-align: center;
 line-height: 30px;
}
.option-input.radio {
 border-radius: 50%;
}
.option-input.radio::after {
 border-radius: 50%;
}
body label {
 display: block;
 line-height: 30px;
 margin-top:20px;
}
.reminder{width:90%; height:60px; text-align:center; margin-top:100px; margin-left:5%; font-size:14px;}
.btn{ width:90%; height:40px; background:#F00; margin-left:5%; border:0; font-size:16px; color:#FFF;margin-top:40px;}
</style>
<script src="js/jquery-2.1.4.js"></script>
<script>
$(document).ready(function(){
	 $.ajax({
			url:"WxPaygetAccess.action",
			type:"post",
			dataType:"json",
			data:null,
			async : false,//同步方式 
			success:function(data){
				$("#a").val(data.s.timeStamp);
				$("#b").val(data.s.nonceStr);
				$("#c").val(data.s.signature);
				
			}
	 });
});  

 wx.config({
	    debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
	    appId: '************', // 必填,公众号的唯一标识,这里填写自己的公众号appid
	    timestamp:$("#a").val(), // 必填,生成签名的时间戳
	    nonceStr: $("#b").val(), // 必填,生成签名的随机串
	    signature: $("#c").val(),// 必填,签名,见附录1
	    jsApiList: ['wx.chooseWXPay'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
	});
 wx.ready(function(){
       	    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
	}); 
 
  </script>
  <script>
   $(document).ready(function(){
   $(".ss1").click(function(){
    $(".t1").css({"background":"#F00","display":"block","color":"#fff"});
	$(".t2").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t3").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t4").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t5").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t6").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	payMoney(8);
     });

   $(".ss2").click(function(){
    $(".t1").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t2").css({"background":"#F00","display":"block","color":"#fff"});
	$(".t3").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t4").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t5").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t6").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	payMoney(88);
     });

   $(".ss3").click(function(){
    $(".t1").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t2").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t3").css({"background":"#F00","display":"block","color":"#fff"});
	$(".t4").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t5").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t6").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	payMoney(188);
     });

   $(".ss4").click(function(){
    $(".t1").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t2").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t3").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t4").css({"background":"#F00","display":"block","color":"#fff"});
	$(".t5").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t6").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	payMoney(288);
     });
	 $(".ss5").click(function(){
    $(".t1").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t2").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t3").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t5").css({"background":"#F00","display":"block","color":"#fff"});
	$(".t4").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t6").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	payMoney(388);
     });
	 $(".ss6").click(function(){
    $(".t1").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t2").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t3").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t6").css({"background":"#F00","display":"block","color":"#fff"});
	$(".t5").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	$(".t4").css({"background":"rgba(204,204,204,0.3)","display":"block","color":"#000"});
	payMoney(488);
     });
   });
   function payMoney(money){
	
	  $("#money").val(money); 
	 
	   }
   function cleanMsg(){
	   $("#msg").html("");
	   
   }
   //跳转后台支付
   function pay(){  
	   var money=$("#money").val();
	  
	   var tel = $("#tel").val();
	   
	   var type=  $("input[name='example']:checked").val();
	   
	   if(money!=""&&money!='0'&&tel!=""&&type!=""){
		   if(!(/^1[34578]\d{9}$/.test(tel))){ //验证手机号格式
               $("#msg").html("手机号格式不正确!");         
           }
		   else{  //判断是哪种充值方式
			   var ip = returnCitySN["cip"];
		       
			   if(type==2){//微信
				   $.ajax({
						url:"WxPayweixinPay.action",
						type:"post",
						dataType:"json",
						data:{num:money,ip:ip,tel:tel},
						async : false,//同步方式 
						success:function(data){
						     if(data.pay==1){
						     $("#msg").text("请先注册会员再来充值!");
						     }
							 else if(data!=null){
								 
							      var obj=data.pay;
							      var appId = obj.appId;
							      //timeStamp = new Date().getTime();
							      var timeStamp = obj.timeStamp;
							      var nonceStr = obj.nonceStr;
							      var prepay_id = obj.prepay_id;
							      var signType = obj.signType;
							     var  paySign = obj.paySign;
							      wx.chooseWXPay({
							    	    timestamp: timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
							    	    nonceStr: nonceStr, // 支付签名随机串,不长于 32 位
							    	    package: "prepay_id="+prepay_id, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
							    	    signType: signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
							    	    paySign: paySign, // 支付签名
							    	    success: function (res) {
							    	        // 支付成功后的回调函数
							    	   
							    	        window.location.href="pay_succ.html?num="+num;
							    	    }
							          
							    	});
							 }
							     
							    
							 else{
								 alert("支付失败");
							 };
							
						},
					 
					 });
		
			   }
				   else if(type==1){//支付宝
					   $.ajax({
							url:"alipay_checkUser.action",
							type:"post",
							dataType:"json",
							data:{num:money,ip:ip,tel:tel},
							async : false,//同步方式 
							success:function(data){
							     if(data.pay==0){
							     	$("#msg").text("请先注册会员再来充值!");
							     	return false;
							     }
								 else{
								 	var btn = document.querySelector("#pay_btn");
								    btn.addEventListener("click", function (e) {
								   		//alert(type);
								        e.preventDefault();
								        e.stopPropagation();
								        e.stopImmediatePropagation();
								
										//订单号
										var vNow = new Date();
										var sNow = "";
										sNow += String(vNow.getFullYear());
										sNow += String(vNow.getMonth() + 1);
										sNow += String(vNow.getDate());
										sNow += String(vNow.getHours());
										sNow += String(vNow.getMinutes());
										sNow += String(vNow.getSeconds());
										sNow += String(vNow.getMilliseconds());
										var out_trade_no = sNow;
										//订单名称,必填
										//var subject = "农庄游戏支付";
										//表单参数
								        var queryParam = '';
								
										//订单号
								        queryParam += "out_trade_no" + "=" + encodeURIComponent(out_trade_no) + '&';
								        //支付金额
								        queryParam += "total_amount" + "=" + encodeURIComponent(money) + '&';
								        //电话号码
								        queryParam += "tel" + "=" + encodeURIComponent(tel) + '&';
								        //订单名称
								        //queryParam += "subject" + "=" + encodeURIComponent(subject) + '&';
								        
								        var gotoUrl = "alipay_pay.action" + '?' + queryParam;
								        _AP.pay(gotoUrl);
								        return false;
									    }, false);
											btn.click();
											return true;
											}
										}
										});
				   
				   
				   
			   }
		   }
		   }
	   }   
  </script>
  <script type="text/javascript" src="alipay/ap.js"></script>
  </head>

  <body ontouchstart="">
   <input type="hidden" id="a">
 <input type="hidden" id="b">
 <input type="hidden" id="c">
  <form action="#" method="post">
    <h4>充值金额</h4> 
    <div class="pay" align="center">
        <ul>    
            <li class="ss1" style="background:rgba(204,204,204,0.3)"><a class="t1" href="javascript:" >充¥8</a></li>  
            <li class="ss2" style="background:rgba(204,204,204,0.3)"><a class="t2" href="javascript:">充¥88</a></li>  
            <li class="ss3" style="background:rgba(204,204,204,0.3)"><a class="t3"href="javascript:">充¥188</a></li>  
            <li class="ss4" style="background:rgba(204,204,204,0.3)"><a class="t4"href="javascript:">充¥288</a></li>   
            <li class="ss5" style="background:rgba(204,204,204,0.3)"><a class="t5"href="javascript:">充¥388</a></li>  
            <li class="ss6" style="background:rgba(204,204,204,0.3)"><a class="t6"href="javascript:">充¥488</a></li>  
        </ul>
        <input type="hidden" id="money">
     </div>
     
     <div class="dan">
     <label><img src="image/pay_logo.png" />
     <input type="radio" class="option-input radio" name="example" value="1">
     </label>
     <label><img src="image/watchar.jpg" width="114" height="40"/>
     <input type="radio" class="option-input radio" name="example" value="2">
     </label>
 
      <!-- <div class="weui-cell" style="margin-top:5px;">
        <div class="weui-cell__hd"><label class="weui-label" style="font-size:18px;margin-top:-1px;">手机号:</label></div>
        <div class="weui-cell__bd">
          <input class="weui-input" style="font-size:18px; margin-left:-30px;"  type="number"  id="tel" onfocus="cleanMsg()">
        </div>
      </div> -->
       <div class="weui-cell" >
       </div>
     </div>
    <!-- <div class="reminder">
     <p style="ccc">点击充值,即表示已阅读并同意<span style=" color:#F00;">充值协议</span></p>
     <p style="">王博士农庄不会以任何形势要求您输入银行账户和密码</p>
     </div>  -->
     <label id="msg" style="color:red;text-align:center;"></label>
    <input type="button" id="pay_btn" class="btn" onclick="pay()" value="去充值">
    </form>
  </body>
</html>

这个页面目前是我自己用的支付页面,懒得删减凑合着用吧!这里在页面上重申几个重点:

1.页面的js导入,这个在官方文档上也有说,<script src="https://res.wx.qq.com/open/js/jweixin-1.0.0.js "></script>必须导入这个js,和一些需要的jquery。

2.大家可以看到我在页面的初始化方法中就进入了获取wx.config需要用到的参数的后台方法中,要注意的是ajax必须同步;

$(document).ready(function(){
	 $.ajax({
			url:"WxPaygetAccess.action",
			type:"post",
			dataType:"json",
			data:null,
			async : false,//同步方式 
			success:function(data){
				$("#a").val(data.s.timeStamp);
				$("#b").val(data.s.nonceStr);
				$("#c").val(data.s.signature);
				
			}
	 });
});  

 wx.config({
	    debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
	    appId: '*********', // 必填,公众号的唯一标识
	    timestamp:$("#a").val(), // 必填,生成签名的时间戳
	    nonceStr: $("#b").val(), // 必填,生成签名的随机串
	    signature: $("#c").val(),// 必填,签名,见附录1
	    jsApiList: ['wx.chooseWXPay'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
	});
 wx.ready(function(){
       	    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
	}); 

 WxPaygetAccess.action方法后面提供,先说一下页面注意点,在wx.config({})中的参数属性名是固定写法,敲黑板!!是属性名不是属性值;着重注意timestamp:生成签名的时间戳;nonceStr:生成签名的随机串;signature:签名;看清楚这三个舒心名,“驼峰”都知道吧,不能错,有驼峰的给驼峰,没有的就别瞎加!不然错都不知道怎么错的。至于这三个属性的值是哪来的,这个是在页面初始化方法中生成好的,也就是后台WxPaygetAccess.action方法生成的,怎么生成的我会在后面给到代码。

点击支付按钮就调用支付方法,支付按钮方法在页面上找的到,我是经过一定的业务逻辑的,没业务需求的话可以直接就调用wx.chooseWXPay({})支付接口就好了,同样里面属性名不能错,如果一切ok的话就会弹出一个梦寐以求思念良久的微信输入支付密码弹出框了。

第三步,支付页面初始化时进来这里,获取access_token,然后根据它调用接口获取参数来配置页面支付时的环境!

接下来就是说说如何生成签名啊,随机字符串啊这些东西了,不废话,代码在哪里?

就在下面  ↓↓↓↓↓

// 第三步 支付页面初始化时进来这里,获取access_token,然后根据它调用接口获取参数来配置页面支付时的环境
	public String getAccess() throws Exception {
		// HttpSession session = request.getSession();
		List<ToKen> list = tokenService.findToken();
		Gson gson = new Gson();
		Signature s = new Signature();
		String ticket = "";
		String access_token = "";
		ToKen token = new ToKen();
		if (list.size() > 0) { // 数据库有token和ticket
			token = list.get(0);
			long end_time = Long.parseLong(token.getEnd_time());
			Date date = new Date();
			long nowTime = date.getTime() / 1000;
			if ((nowTime - end_time) > 6900) { // 快过期 重新获取token和ticket 并删除原来的
				String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
						+ WeiXinUtil.appid + "&secret=" + WeiXinUtil.secret;
				access_token = HttpUtils.get(url);
				access_token = gson.fromJson(access_token, AccessToken.class)
						.getAccess_token();

				String url1 = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="
						+ access_token + "&type=jsapi";
				ticket = HttpUtils.get(url1);
				ticket = gson.fromJson(ticket, Ticket.class).getTicket();
				token.setAccess_token(access_token);
				token.setTicket(ticket);
				token.setEnd_time((new Date().getTime() / 1000 + 6900) + "");
				tokenService.updateToken(token);
			} else {// 使用原来的
				access_token = token.getAccess_token();
				ticket = token.getTicket();
			}

		} else {// 第一次获取

			String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
					+ WeiXinUtil.appid + "&secret=" + WeiXinUtil.secret;
			access_token = HttpUtils.get(url);
			access_token = gson.fromJson(access_token, AccessToken.class)
					.getAccess_token();

			String url1 = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="
					+ access_token + "&type=jsapi";
			ticket = HttpUtils.get(url1);
			ticket = gson.fromJson(ticket, Ticket.class).getTicket();
			token = new ToKen();
			token.setAccess_token(access_token);
			token.setTicket(ticket);
			token.setEnd_time((new Date().getTime() / 1000 + 6900) + "");
			tokenService.addToken(token);

		}
		s.setJsapi_ticket(ticket);
		s.setNoncestr(PayWxUtil.getNonceStr());//PayWxUtil.getNonceStr()工具类生成随机字符串,这个随机字符串生成有特定规则
		s.setTimeStamp(new Date().getTime() / 1000 + "");//时间戳
		s.setUrl(WeiXinUtil.ip + "wxpay/pay.html");//把项目中支付页面的全路劲也需要放进去
		Map<String, String> map = new HashMap<String, String>();
		map.put("noncestr", s.getNoncestr());
		map.put("jsapi_ticket", s.getJsapi_ticket());
		map.put("timestamp", s.getTimeStamp());
		map.put("url", s.getUrl());
		String str = "jsapi_ticket=" + s.getJsapi_ticket() + "&noncestr="
				+ s.getNoncestr() + "&timestamp=" + s.getTimeStamp() + "&url="
				+ s.getUrl();
		s.setSignature(PayWxUtil.getSha1(str));//PayWxUtil.getSha1(str)工具类真正生成签名,这里面很严格,一点都不能含糊,不然生成的签名在config中就是错的
		JSONObject json = new JSONObject();
		json.put("s", s);
		ResUtil.write(json, ServletActionContext.getResponse());

		return null;
	}

token:微信关键字,理解为调用接口的凭证吧;解释在微信官方文档;通过appid和秘钥获取,规定两个小时时效性,过了两个小时需的重新调用接口获取,但是又不能一直获取,有获取次数限制。所以获取了之后会存在数据库中,并且记录该次获取之间,以便下次用时判断是否有两小时了,有的话重新获取一下,在删除数据库的存入新的token,每次重复如此。

上面这个方法是前端支付页面初始化获取签名和随机字符串以及时间戳的接口方法,所以生成好了会返回值给前端ajax的请求!

凭证token问题解决了之后就是调用工具类正式生成前端支付页面 wx.config需要的签名和随机字符串了,这里贴一下相关代码:

Token.java(凭证实体类,get set方法省略)

/**
 * token 和
 * @author QT-666
 *
 */
public class ToKen {
	 private int token_id;
     private String access_token;
     private String ticket;
     private String end_time;//生成时间

Signature.java(生成签名需要以下参数,定义好了,传入工具类中)

/**
 * 生成签名实体类
 * @author QT-666
 *
 */
public class Signature {
    private String noncestr;//随机字符串
    private String jsapi_ticket;//调用js凭证
    private String timeStamp;//时间戳
    private String url;//支付页面地址
    private String signature;//签名

最最重要的生成签名PayWxUtil.java工具类代码,没特殊情况一般不要改:

package com.game.util;

import java.security.MessageDigest;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import org.apache.commons.codec.digest.DigestUtils;

/**
* Created by Song on 2016/11/8.
* mail: 1147649695@qq.com
* 微信支付相关工具类
*/
public class PayWxUtil {
   //上一次订单请求日期
   private static Date preDay = new Date();
   //当前订单日期
   private static Date curDay = new Date();
   //用于记录已产生的订单号
   private static Set<Long> numPoul = new HashSet<Long>();
   /**
    * 获得签名
    * @param params 待编码参数,参数值为空不传入
    * @param key key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
    * @return
    */
   public static String getSign(Map<String,String> params,String key) throws Exception{
       List<String> list = new ArrayList<String>(params.keySet());
       Collections.sort(list,new DictionaryCompare());
       StringBuffer sb = new StringBuffer();
       for(String keyVal:list){
    	   if(params.get(keyVal)!=null){
           sb.append(keyVal+"="+params.get(keyVal)+"&");
    	   }
       }
       sb.append("key="+key);
       return DigestUtils.md5Hex(new String(sb.toString().getBytes(),"utf-8")).toUpperCase();
   }

   /**
    * 获得随机字符串
    * @return
    */
   public static String getNonceStr(){
       Random random = new Random();
       long val = random.nextLong();
       String res = DigestUtils.md5Hex(val+"yzx").toUpperCase();
       if(32<res.length()) return res.substring(0,32);
       else return res;
   }

   /**
    * 获取订单号
    * 商户订单号(每个订单号必须唯一)
    * 组成:mch_id+yyyymmdd+10位一天内不能重复的数字。
    * @param mchId
    * @return
    */
   public static String getMchBillno(String mchId){
       Random random = new Random();
       long val = random.nextLong()%10000000000L;//获得0-9999999999内的数字
       curDay = new Date();
       //隔天清空
       if(curDay.after(preDay)) numPoul.clear();
       while(numPoul.contains(val)){
           val = random.nextLong()%10000000000L;
       }
       numPoul.add(val);
       preDay = curDay;
       //按要求,日期格式化输出
       DateFormat df = new SimpleDateFormat("yyyymmdd");
       return mchId+df.format(curDay)+format(val+"",10);
   }

   /**
    * 将字符串str按长度在前面添0补齐
    * @param str
    * @param length
    * @return
    */
   private static String format(String str,int length){
       String pre = "0000000000";
       int len = str.length();
       if(10<=len) return str.substring(0,10);
       else return pre.substring(0,10-len).concat(str);
   }
   
   //SHA1加密方法,jssdk签名算法
   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("UTF-8"));

           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) {
           // TODO: handle exception
           return null;
       }
   }

}

/**
* 按字典序排序
*/
class DictionaryCompare implements Comparator<String>{
   public int compare(String o1, String o2) {
       return o1.compareTo(o2);
   }
}

工具类没什么说的,知道怎么用就ok!

后台生成好了这几个参数就给前端用了,如果config报错了,多有是签名错误,也是在这一步上出了问题,仔细检查你生成签名传的值对不对!还有就前端属性名的“驼峰”问题。config:ok了就会弹出微信支付密码输入框了,到了这一步,那恭喜你!这时就已经成功了大半;接下来就是一些支付成功或者支付失败的业务逻辑处理了,可以松一口气了!!!

第四步 统一下单生成 ,页面传入用户输入金额,ip,生成预支付订单,把微信回调的参数传递给页面,页面就可以调起支付

大家可以翻上去看看,我在支付页面上的点击按钮时,会通过ajax进入到后台方法WxPayweixinPay.action中生成调用wx.chooseWXPay({})微信支付接口的参数值;别看这里个wx.chooseWXPay({})接口里面的属性名和wx.config({})接口的差不多,但是就是不同,需要后台方法WxPayweixinPay.action重新生成给前端用,直接上WxPayweixinPay.action的方法吧:

// 统一下单生成 第四步,页面传入用户输入金额,ip,生成预支付订单,把微信回调的参数传递给页面,页面就可以调起支付
	public String weixinPay() throws Exception {

		HttpSession session = request.getSession();
		String open_id = (String) session.getAttribute("open_id");
		UserInfo u = userService.findUserByOpenId(open_id);// 查找是不是会员,不是会员不能充值
		 if (u != null&&u.getFake()=='T') {
		String ip = request.getParameter("ip");
		String token = (String) session.getAttribute("token");

		String nickname = token;

		double money = Double.parseDouble(request.getParameter("num"));
		int a = (int) (money * 100);
		WechatUnifiedOrder w = new WechatUnifiedOrder();
		w.setAppid(WeiXinUtil.appid);
		String str = "0791游戏-充值";
		byte[] jiema = str.getBytes("utf-8"); // 解码
		String bianma = new String(jiema);// 编码 如果上面的解码不对 可能出现问题
		URLEncoder.encode(bianma, "UTF-8");
		byte[] jiema1 = nickname.getBytes("utf-8"); // 解码
		String bianma1 = new String(jiema1);// 编码 如果上面的解码不对 可能出现问题
		URLEncoder.encode(bianma1, "UTF-8");
		w.setAttach(bianma1);
		w.setBody(bianma);
		w.setMch_id(WeiXinUtil.account);
		w.setNonce_str(PayWxUtil.getNonceStr());// 随机支付串
		w.setNotify_url(WeiXinUtil.ip + "WxPaypayResulet.action");// 支付结果回调地址
		w.setOpenid(open_id);
		w.setOut_trade_no("" + new Date().getTime());
		w.setSpbill_create_ip(ip);
		w.setTotal_fee(a);
		w.setTrade_type("JSAPI");
		Map<String, String> params = new HashMap<String, String>();
		params.put("attach", w.getAttach());
		params.put("appid", w.getAppid());
		params.put("mch_id", w.getMch_id());
		params.put("nonce_str", w.getNonce_str());
		params.put("body", w.getBody());
		params.put("out_trade_no", w.getOut_trade_no());
		params.put("total_fee", w.getTotal_fee() + "");
		params.put("spbill_create_ip", w.getSpbill_create_ip());
		params.put("notify_url", w.getNotify_url());
		params.put("trade_type", w.getTrade_type());
		params.put("openid", w.getOpenid());
		w.setSign(PayWxUtil.getSign(params, WeiXinUtil.APIid));
		params.put("sign", w.getSign());
		// /System.out.println(w.getSign());
		// 将java对象转换为XML字符串
		// JaxbUtil requestBinder = new JaxbUtil(WechatUnifiedOrder.class,
		// CollectionWrapper.class);
		// String retXml = requestBinder.toXml(w, "utf-8");
		// retXml = retXml.substring(56);
		String retXml = JaxbUtil.getRequestXml(params);

		String msg = HttpUtils.post(
				"https://api.mch.weixin.qq.com/pay/unifiedorder", retXml);
		if (msg.indexOf("FAIL") > -1) {
			return null;
			// JSONObject json = new JSONObject();
			// json.put("pay", "error");
			// ResponseUtil.write(json, ServletActionContext.getResponse());
		} else {
			JaxbUtil requestBinder = new JaxbUtil(TongYiReturn.class,
					CollectionWrapper.class);
			TongYiReturn to = requestBinder.fromXml(msg);
			if (to.getReturn_code().equals("SUCCESS")
					&& to.getResult_code().equals("SUCCESS")) {
				EndPay pay = new EndPay();
				pay.setAppId(WeiXinUtil.appid);
				pay.setSignType("MD5");

				pay.setTimeStamp(System.currentTimeMillis() / 1000 + "");

				pay.setPrepay_id(to.getPrepay_id());
				pay.setNonceStr(PayWxUtil.getNonceStr());
				Map<String, String> requestMap = new HashMap<String, String>();
				requestMap.put("appId", pay.getAppId());
				requestMap.put("timeStamp", pay.getTimeStamp());
				requestMap.put("nonceStr", pay.getNonceStr());
				requestMap.put("package", "prepay_id=" + pay.getPrepay_id());
				requestMap.put("signType", "MD5");
				pay.setPaySign(PayWxUtil.getSign(requestMap, WeiXinUtil.APIid));
				// requestMap.put("sign",pay.getPaySign());
				// String ret = JaxbUtil.getRequestXml(requestMap);
				// System.out.println(ret);
				JSONObject json = new JSONObject();
				json.put("pay", pay);
				if (session.getAttribute("p_biao") != null) { // 说明时从打转盘页面进来的,支付完成后继续调到转盘页面
					json.put("p_biao", 1);
					session.removeAttribute("p_biao");
				} else {
					json.put("p_biao", 0);
				}
				ResUtil.write(json, ServletActionContext.getResponse());
			}
		}
		 } else { // 说明不是会员
		 JSONObject json = new JSONObject();
		 json.put("pay", 1);
		 ResUtil.write(json, ServletActionContext.getResponse());
		 }

		return null;
	}

这其中,前端页面传进来的支付金额money要乘以100,因为支付接口传进去的金额是按分算的,不要出现小数点;

我这里定义了支付后的回调地址,也就是告诉微信方支付之后把支付结果返回到哪里的地址,我这里写的是:

w.setNotify_url(WeiXinUtil.ip + "WxPaypayResulet.action");// 支付结果回调地址

也就是所谓的第五步了,接收支付结果并处理支付结果!第五步后面献上!!

没什么可多说的,按照格式写代码!奉上相关代码:

WechatUnifiedOrder.java

/**
 * 统一下单实体类
 * @author QT-666
 *
 */
@XmlRootElement(name="xml")
public class WechatUnifiedOrder implements Serializable{
	private String appid;   //微信支付分配的公众账号ID(企业号corpid即为此appId)
	private String mch_id;  //微信支付分配的商户号
	private String nonce_str;   //随机字符串,长度要求在32位以内。推荐随机数生成算法
	private String sign;  //通过签名算法计算得出的签名值,详见签名生成算法
	private String body;   //商品简单描述,该字段请按照规范传递,具体请见参数规定
	private String out_trade_no;  //	商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。详见商户订单号
	private int total_fee;   //订单总金额,单位为分,详见支付金额
	private String spbill_create_ip;  //APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。
	private String notify_url;   //异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。
	private String trade_type;  //取值如下:JSAPI,NATIVE,APP等,说明详见参数规定
	private String openid;   //trade_type=JSAPI时(即公众号支付),此参数必传,此参数为微信用户在商户对应appid下的唯一标识
	private String attach;//数据包

同样,此方法生成好调用wx.chooseWXPay({})接口需要的参数是,返回前端支付页面使用就ok了;

支付页面上的 wx.chooseWXPay({})接口方法中也有支付回调函数,那可以作为支付成功后的跳转相应的成功或者失败页面中去;只要的还是后台接收支付结果的方法里处理并验证支付结果的后台方法;

第五步:支付页面用户输完密码后微信会把支付结果回调到这里,我们根据需要存储支付记录,和执行不同的方法

// 第五步:支付页面用户输完密码后微信会把支付结果回调到这里,我们根据需要存储支付记录,和执行不同的方法
	public String payResulet() throws Exception { // 微信支付结果通知
		BufferedReader reader = null;

		reader = request.getReader();
		String line = "";
		String xmlString = null;
		StringBuffer inputString = new StringBuffer();

		while ((line = reader.readLine()) != null) {
			inputString.append(line);
		}
		xmlString = inputString.toString();
		request.getReader().close();

		JaxbUtil requestBinder = new JaxbUtil(PayResult.class, PayResult.class);
		PayResult result = requestBinder.fromXml(xmlString);

		if (result.getResult_code().equals("SUCCESS")) { // 交易成功,支付结果转换为对象
			String account = result.getTransaction_id();

			Pay pay = payService.findPayByNo(account);

			if (pay != null) { // 有交易记录 发送成功消息给商家
				String returnMsg = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
				HttpServletResponse response = ServletActionContext
						.getResponse();
				response.setContentType("text/html;charset=utf-8");
				PrintWriter out = response.getWriter();
				out.println(returnMsg);
				out.flush();
				out.close();
			} else { // 交易记录开始记录
				Map<String, String> params = new HashMap<String, String>();
				byte[] jiema1 = result.getAttach().getBytes("utf-8"); // 解码
				String bianma1 = new String(jiema1);// 编码 如果上面的解码不对 可能出现问题
				URLEncoder.encode(bianma1, "UTF-8");
				params.put("appid", result.getAppid());
				params.put("attach", bianma1);
				params.put("bank_type", result.getBank_type());
				params.put("fee_type", result.getFee_type());
				params.put("is_subscribe", result.getIs_subscribe());
				params.put("mch_id", result.getMch_id());
				params.put("nonce_str", result.getNonce_str());
				params.put("openid", result.getOpenid());
				params.put("out_trade_no", result.getOut_trade_no());
				params.put("result_code", result.getResult_code());
				params.put("return_code", result.getReturn_code());
				params.put("sub_mch_id", result.getSub_mch_id());
				params.put("time_end", result.getTime_end());
				params.put("total_fee", result.getTotal_fee() + "");
				params.put("trade_type", result.getTrade_type());
				params.put("transaction_id", result.getTransaction_id());
				params.put("cash_fee", result.getCash_fee() + "");

				params.put("device_info", result.getDevice_info());
				params.put("sign_type", result.getSign_type());
				params.put("settlement_total_fee",
						result.getSettlement_total_fee());
				params.put("cash_fee_type", result.getCash_fee_type());
				params.put("coupon_fee", result.getCoupon_fee());
				params.put("coupon_count", result.getCoupon_count());
				params.put("coupon_type_$n", result.getCoupon_type_$n());
				params.put("coupon_id_$n", result.getCoupon_id_$n());
				params.put("coupon_fee_$n", result.getCoupon_fee_$n());

				String sign = PayWxUtil.getSign(params, WeiXinUtil.APIid);
				params.put("sign", sign);

				if (sign.equals(result.getSign())) { // 两次签名一样,说明没有第三方修改,交易真实

					// String token = result.getAttach();

					// String[] l = msg.split(",");

					// String token = l[0];// 获取用户信息凭证

					// String url =
					// "https://api.weixin.qq.com/sns/userinfo?access_token="
					// + token
					// + "&openid="
					// + result.getOpenid()
					// + "&lang=zh_CN";
					// String json1 = HttpUtils.get(url);
					// UserMsg user = new Gson().fromJson(json1, UserMsg.class);
					// // 获得交易支付成功用户的信息

					Pay pay1 = new Pay();
					UserInfo u = userService.findUserByOpenId(result
							.getOpenid()); // 查找充值的会员信息
					pay1.setPay_money((double) result.getTotal_fee() / 100);

					pay1.setUser_name(u.getUser_name());
					pay1.setPay_no(new String(account.getBytes("utf-8")));
					SimpleDateFormat simp = new SimpleDateFormat(
							"yyyyMMddHHmmss");
					SimpleDateFormat simp1 = new SimpleDateFormat(
							"yyyy-MM-dd HH:mm:ss");

					Date date = simp.parse(result.getTime_end());
					String time = simp1.format(date);
					pay1.setPay_time(time); // 支付结束时间
					pay1.setPay_type(1);

					pay1.setUser_id(u.getUser_id());
					pay1.setOpen_id(result.getOpenid());
					payService.addPay(pay1); // 添加交易信息

					userService.update((double) result.getTotal_fee() / 10,
							u.getUser_id());
					String returnMsg = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
					HttpServletResponse response = ServletActionContext
							.getResponse();
					response.setContentType("text/html;charset=utf-8");
					PrintWriter out = response.getWriter();
					out.println(returnMsg);
					out.flush();
					out.close(); // 发送成功消息给商家
				}
			}

		}

		return null;
	}

 相关代码:

PayResult.java

/**
 * 微信支付结果返回
 * 
 * @author QT-666
 * 
 */
@XmlRootElement(name="xml")
public class PayResult {
	private String appid;// 微信分配的公众账号ID(企业号corpid即为此appId)
	private String attach;//
	private String bank_type;// 银行类型,采用字符串类型的银行标识,银行类型见银行列表
	private String fee_type;// 货币类型,符合ISO4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
	private String is_subscribe;// 用户是否关注公众账号,Y-关注,N-未关注,仅在公众账号类型支付有效
	private String mch_id;// 微信支付分配的商户号
	private String nonce_str;// 随机字符串,不长于32位
	private String openid;// 用户在商户appid下的唯一标识
	private String out_trade_no;// 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@
								// ,且在同一个商户号下唯一。
	private String result_code;// SUCCESS/FAIL
	private String return_code;// 此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断
	private String sign;// 签名,详见签名算法
	private String sub_mch_id;//
	private String time_end;// 支付完成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
	private int total_fee;// 订单总金额,单位为分
	private String trade_type;// JSAPI、NATIVE、APP
	private String transaction_id;// 微信支付订单号
	private int cash_fee;// 现金金额
	
	private String device_info; //微信支付分配的终端设备号,
    private String sign_type;//签名类型,目前支持HMAC-SHA256和MD5,默认为MD5
    private String settlement_total_fee ;//应结订单金额=订单金额-非充值代金券金额,应结订单金额<=订单金额。 
    private String cash_fee_type;//货币类型,符合ISO4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
    private String  coupon_fee;//代金券金额<=订单金额,订单金额-代金券金额=现金支付金额,详见支付金额
    private String coupon_count;//代金券使用数量
    private String coupon_type_$n;// CASH--充值代金券 NO_CASH---非充值代金券 仅在使用了免充值代金券时有返回(取值:CASH、NO_CASH)。$n为下标,从0开始编号,举例:coupon_type_0
    private String coupon_id_$n;//代金券ID,$n为下标,从0开始编号
    private String coupon_fee_$n;//单个代金券支付金额,$n为下标,从0开始编号

 我这边是执行了相应的业务需求,保存了支付记录!保存支付记录的时候注意,因为在微信那边会多次回调这个接口,所以要判断后台存不存在这条支付记录,如果存在了就不保存支付记录了,防止保存多条一样的支付记录;

我这里时做了最简单的支付安全验证,就是校验我们生成的签名和微信给我们的签名是否一样,一样就表示没问题的支付,反之则就是有问题(可能被人串改的支付结果)。这个检验有个漏洞:就是在 微信现金红包,在用户输入金额后,点击支付时输入的金额会自动减去微信现金红包的金额,这样就可能造成两次的金额不一样,生成的签名就不同了,支付是支付了,就是后台校验的时候过不去;目前这个问题我还没解决,所以如果没什么安全要求的话可以去掉这一步的检验。

做微信支付开发,还是用内网穿透软件比较好,因为一路走下来可能会遇到各种各样的问题,都能在本地上找到并修复!比直接在服务器上开发测试好不知道多少;内网穿透软件有花生壳,还有些别的在网上可以找到;

我的框架是java三大框架ssh,struts+spring+hibernate,所以在一些接口的写法都是类似WxPayweixinPay.action,WxPay是action名字,weixinPay是这个action中的方法名;这个都应该看得懂!!

到这里就完成微信公众号的整个支付流程了,你走下来了吗!!!走下来的同学恭喜了,没走下来的同学加油,不要气馁不要急躁慢慢来会成功的!!!

学会了微信支付,相对于一些微信其他的开发也就差不多都会了,微信的很多js开放接口都是基于wx.config({})上的,只要你这个config:ok了,那别的微信开发那都不是事,恭喜你掌握了微信二次开发!

看着这篇博客写的也蛮长的,其实也就代码多,我也没废话多少;就到这里吧,有空再献上微信网页支付的博客吧;
 

 

 

 

 

2018-01-15 22:14:46 MYTLJP 阅读数 4952
  • 微信公众号开发9-公众号JSSDK开发-微信开发php

    微信公众平台开发之公众号JSSDK开发是子恒老师《微信公众平台开发》视频教程的第9部。详细讲解了用php开发微信公众号,对微信公众平台中的JSSDK开发。内容包含用JSSDK获取网络状态,地理位置,分享到朋友圈,QQ,空间设置等等。欢迎反馈,微信/QQ:68183131

    14972 人正在学习 去看看 秦子恒

用了好几个小时的时间,整理了一下关于公众号的思维导图,由于CSDN不能上传相对应的文件,所以萍子一一的分解开的截图附上来,希望对大家有所帮助哦~
因为是电脑设备自动截图,又鉴于内容比较多,可能不是太清楚,需要的小伙伴们,可以联系我,我可以随时发给你。

学习微信公众号需要的配置

这里写图片描述


微信开发的主体、请求方式、数据类型和环境

主体

这里写图片描述

请求方式

这里写图片描述
这里写图片描述

数据类型和环境

这里写图片描述


开始开发

获取access_token值并存储

这里写图片描述
这里写图片描述


账号管理

生成带参数的二维码

这里写图片描述

长链接转短链接

这里写图片描述


消息管理

获取微信服务器的IP地址

接收普通消息

接收事件推送

被动回复用户消息

这里写图片描述


微信网页授权

微信网页授权步骤

第一步:跳转页面,用户同意授权,获取code

这里写图片描述

第二步:通过code换取网页授权access_token(与普通的access_token不一样,具体见下方)
第三步:如果需要,刷新access_token值

这里写图片描述

第四步:拉取用户信息(需要scope为snsapi_userinfo)
第五步:附,检验授权凭证access_token是否有效,一般用不到

这里写图片描述


微信JS-SDK

说明

这里写图片描述

JS-SDK使用步骤

这里写图片描述

上传图片素材

这里写图片描述


微信公众号

握手协议

这里写图片描述

自定义菜单

自定义菜单类型

这里写图片描述

自定义菜单的设置

这里写图片描述

自定义菜单参数说明

这里写图片描述

获取自定义菜单

这里写图片描述


自定义菜单事件推送/被动回复用户信息

自定义事件推送

这里写图片描述

被动回复用户信息

这里写图片描述

根据菜单类型的点击,被动回复

点击按钮事件

这里写图片描述

公众号首次被某个用户关注的推送

这里写图片描述

微信扫一扫,并展示扫的内容

这里写图片描述

推送图文消息

这里写图片描述

回复图片消息
没有点击按钮

这里写图片描述

2019-06-19 21:05:29 weixin_44356485 阅读数 3626
  • 微信公众号开发9-公众号JSSDK开发-微信开发php

    微信公众平台开发之公众号JSSDK开发是子恒老师《微信公众平台开发》视频教程的第9部。详细讲解了用php开发微信公众号,对微信公众平台中的JSSDK开发。内容包含用JSSDK获取网络状态,地理位置,分享到朋友圈,QQ,空间设置等等。欢迎反馈,微信/QQ:68183131

    14972 人正在学习 去看看 秦子恒

首先说一下code的获得,一般只需要读微信这公众号开发文档就OK,但是也有一个坑。

本人是用vue开发的

https://mp.weixin.qq.com/wiki     微信公众号开发文档

 拿code是要在配置了appID,redirect_uri之后页面跳转回来的页面url上携带着code,需要截取。

本人在开发是将公众号代码让后端小哥哥布到了服务器上  所以可以看效果,微信开发者工具很不方便,

getUrl() {
      let appID = "公众号的appId";
      let redirectUri = encodeURIComponent("这里是f跳转回来的页面");
      let strUrl =
        "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" +
        appID +
        "&redirect_uri=" +
        redirectUri +
        "%2Foauth_response.php&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";

      this.$nextTick(() => {
        window.location.href = strUrl;
      });
    },

appId和response_type 是自己定义的参数

跳回的页面的url 需要加encodeURIComponent()方法来处理 否知不好使

这是截code的方法

//截取code
    getCode() {
      let url = window.location.search;
      let start = window.location.search.indexOf("=");
      let end = window.location.search.indexOf("&");
      let code = url.substring(start + 1, end);
      return code;
    },

拿到code之后去请求后端,后端会给你返回openId 也可以拿到用户的昵称 头像

 

如果需求有绑定手机号 那就自己另起页面 开通手机验证码服务

前端拿到数据发送给后端验证

getCode(formName){
            this.msg = '';
            const TIME_COUNT = 60;
            if (this.inputPhone) {
                 this.$http.post('这里是调取的后端接口名?phone='+ this.inputPhone, this.inputPhone)
                    .then(({ data }) => {
                        if(data.succeed) {
                            this.count = TIME_COUNT;
                            this.show = false;
                            this.btnShow = true;
                            this.timer = setInterval(() => {
                            if (this.count > 0 && this.count <= TIME_COUNT) {
                                this.count--;
                                } else {
                                this.btnShow = false;
                                this.show = true;
                                clearInterval(this.timer);
                                this.timer = null;
                                }
                            }, 1000)
                        } else {
                            //展示错误信息给用户
                            let errINFO = document.getElementById('errInfo')
                            this.msg = data.msg
                            this.changeMsg()
                        }
                    })
                
            } else {
                this.msg = '请输入手机号'
                this.changeMsg();
            }
        },
        //提交绑定
        submitInfo() {
           this.$http.post('这里是调取的后端接口名?phone='+ this.inputPhone +'&code='+ this.inputCode +'&openId='+ localStorage.getItem('openId'))
            .then(({ data }) => {
                if(data.succeed) {
                    this.$router.push('/production?userOK')
                } else {
                    this.msg = data.msg
                }
            })
        }

总结: 

开发时需后端把项目上线自动布项目,之后拿到域名跳域名测试,前端push代码,服务器自动布项目。这也是开发的不便。

 

2018-04-27 19:08:53 jklkjz 阅读数 89
  • 微信公众号开发9-公众号JSSDK开发-微信开发php

    微信公众平台开发之公众号JSSDK开发是子恒老师《微信公众平台开发》视频教程的第9部。详细讲解了用php开发微信公众号,对微信公众平台中的JSSDK开发。内容包含用JSSDK获取网络状态,地理位置,分享到朋友圈,QQ,空间设置等等。欢迎反馈,微信/QQ:68183131

    14972 人正在学习 去看看 秦子恒

1、只有在公众号的开发者微信号绑定了,才可以用web开发者工具进行调试

2、对于同一个微信用户,不同公众号的openid是不一样的,所以要调用其他接口,前提就是要用户授权,拿到他的openid

3、微信接口分两类,一类用普通的access_token,另一类需要经过用户授权后拿到的access_token(多为用户信息的接口)

4、微信普通接口请求步骤:

1)先用appid、Secret请求接口获取token
2)使用token再请求所需要的接口

5、微信用户授权类接口请求步骤:

1)页面重定向到微信授权页面(https://open.weixin.qq.com/connect/oauth2/authorize?appid=XXXXX&redirect_uri=XXXXX&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect)
2)用户同意,提交给微信
3)微信把访问页面重定向到自身服务器的地址、并带有openid和code
4)通过code,请求微信接口,重新获取access_token(https://api.weixin.qq.com/sns/oauth2/access_token?appid=XXXXX&secret=XXXXX&code=XXXXX&grant_type=authorization_code)
5)使用token再请求所需要的接口(https://api.weixin.qq.com/sns/userinfo?access_token=XXXXX&openid=XXXXX&lang=zh_CN)

6、合理做法:首次访问用非静默授权,获取用户信息,并存数据库,第二次访问不可以通过session获取(由于回调页面的请求客户端是微信服务器,并发用户手机,所以session根本没法保存在用户手机),需要用静默授权获取openid然后查询数据库来获取用户信息。

7、网页授权获取用户基本信息是有一个专门的授权回调页面域名设置
8、自定义菜单类型有很多,其中包括调用摄像头的扫一扫功能
9、接口配置信息除了验证以外,还是用接收推送事件

2019-07-18 17:04:09 glei20 阅读数 1118
  • 微信公众号开发9-公众号JSSDK开发-微信开发php

    微信公众平台开发之公众号JSSDK开发是子恒老师《微信公众平台开发》视频教程的第9部。详细讲解了用php开发微信公众号,对微信公众平台中的JSSDK开发。内容包含用JSSDK获取网络状态,地理位置,分享到朋友圈,QQ,空间设置等等。欢迎反馈,微信/QQ:68183131

    14972 人正在学习 去看看 秦子恒

记录下最近在做项目的时候遇到的一个问题,就是用户未关注该公众号的情况下打开了h5页面,在授权的时候获取到用户的Subscribe=0,本来是直接打算给个提示,但是觉得对于用户有点繁琐,还得手动去查找公众号并关注,后来又想了一套方案就是直接返回公众号二维码,但是总感觉不太美观,然后闲的蛋疼弄了个下面的方式。

首先第一步将该公众号内的任意一篇文章分享到qq ,这个时候我们拿到了一个连接,下面就需要对这个连接进行操作

原连接如下

http://mp.weixin.qq.com/s?__biz=MzU5MzIxMTg3OA==&mid=2247484047&idx=1&sn=6ff186c31a3fbc2129e5dc8ce29dd682&chksm=fe12ba06c96533108c5cda4b4a63c99cc510e68abe9af368e3f85aa3b805baf6459768f0e9b4&mpshare=1&scene=23&srcid=#rd
替换后如下:
http://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=MzU5MzIxMTg3OA==&scene=110#wechat_redirect

按照这个连接来就行。保留原链接里面的__biz=这串字符就行

 之后微信点开链接就能看到第一张图片上的内容了

微信开发

阅读数 56

没有更多推荐了,返回首页