微信开发学习总结(二)——微信开发环境准备(2)

上一节内容:
微信开发学习总结(二)——微信开发环境准备(1)
https://blog.csdn.net/qq_29914837/article/details/82891095


三、access_token管理

3.1、介绍access_token
我们的公众号和微信服务器对接成功之后,接下来要做的就是根据我们的业务需求调用微信公众号提供的接口来实现相应的逻辑了。在使用微信公众号接口中都需要一个access_token。
access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token,开发者需要妥善保存access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。并且每天调用获取access_token接口的上限是2000次。
  总结以上说明,access_token需要做到以下两点:
  ①因为access_token有2个小时的时效性,要有一个机制保证最长2个小时重新获取一次。
  ②因为接口调用上限每天2000次,所以不能调用太频繁。
  
3.2、通过微信公众平台提供的接口获取access_token

接口调用请求说明

https请求方式: GET
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
参数 是否必须 说明
grant_type 获取access_token填写client_credential
appid 第三方用户唯一凭证
secret 第三方用户唯一凭证密钥,即appsecret

返回说明
正常情况下,微信会返回下述JSON数据包给公众号:

{"access_token":"ACCESS_TOKEN","expires_in":7200}
参数 说明
access_token 获取到的凭证
expires_in 凭证有效时间,单位:秒

错误时微信会返回错误码等信息,JSON数据包示例如下(该示例为AppID无效错误):

{"errcode":40013,"errmsg":"invalid appid"}

返回码说明

返回码 说明
-1 系统繁忙,此时请开发者稍候再试
0 请求成功
40001 AppSecret错误或者AppSecret不属于这个公众号,请开发者确认AppSecret的正确性
40002 请确保grant_type字段值为client_credential
40164 调用接口的IP地址不在白名单中,请在接口IP白名单中进行设置。(小程序及小游戏调用不要求IP地址在白名单内。)

在这里插入图片描述
这是我申请公众号测试帐号时分配到的AppID和AppSecret。

3.3、获取access_token方案以及具体实现

这里采用的方案是这样的,定义一个默认启动的servlet,在init方法中启动一个Thread,这个进程中定义一个无限循环的方法,用来获取access_token,当获取成功后,此进程休眠7000秒(7000秒=1.944444444444444小时),否则休眠3秒钟继续获取。流程图如下:
在这里插入图片描述

完整的项目结构
在这里插入图片描述

①定义一个AccessToken实体类

package weixin.entity.accesstoken;

/**
 * @所属类别:实体类
 * @用途:微信公众号开发中AccessToken实体类
 * @author yilei
 * @version:1.0
 */
public class AccessToken {

    //获取到的凭证
    private String accessToken;
    //凭证有效时间,单位:秒
    private int expiresin;

    public String getAccessToken() {
        return accessToken;
    }

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }

    public int getExpiresin() {
        return expiresin;
    }

    public void setExpiresin(int expiresin) {
        this.expiresin = expiresin;
    }
}

②定义一个WeiXin类,静态变量,代码如下:

package weixin.util;

/**
 * @所属类别:工具类
 * @用途:存放微信公众号开发中全部静态变量(微信开发服务器配置-token-access_token等)
 * @author yilei
 * @version:1.0
 */
public class WeiXin {
	/**
	 * Token可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)
	 * 这里和你服务器配置-令牌(token)一致
	 */
	public static final String TOKEN  ="yilei";
	
	
	/**
	 * 第三方用户唯一凭证
	 */
	public static String APPID="wxc931e30eb7da614b";
	
	/**
	 * 第三方用户唯一凭证密钥,即appsecret
	 */
	public static String APPSECRET="ae68f7583fda08460e116fc02780aab8";
	
	/**
	 * 获取access_token的调用接口
	 */
	public static String ACCESS_TOKEN_URL="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

}

③WeiXinCheck 工具类,存在共用方法

package weixin.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
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.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import net.sf.json.JSONObject;
import weixin.entity.accesstoken.AccessToken;

/**
 * @所属类别:工具类
 * @用途:微信开发校验方法、sha1加密算法等
 * @author yilei
 * @version:1.0
 */
public class WeiXinCheck {

	/**
	 * @method 将token、timestamp、nonce三个参数进行字典序排序
	 * @param token
	 * @param timestamp
	 * @param nonce
	 * @return 排序后的字符串
	 */
	public static String sort(String token, String timestamp, String nonce) {
		String[] strArray = { token, timestamp, nonce };
		Arrays.sort(strArray);
		StringBuilder sb = new StringBuilder();
		for (String str : strArray) {
			sb.append(str);
		}
		return sb.toString();
	}

	/**
	 * @method 将三个参数字符串拼接成一个字符串进行sha1加密
	 * @param str,需要加密的字符串(排序后的字符串)
	 * @return 加密后的内容
	 */
	public static String sha1(String str) {
		try {
			MessageDigest digest = MessageDigest.getInstance("SHA-1");
			digest.update(str.getBytes());
			byte messageDigest[] = digest.digest();
			// Create Hex String
			StringBuffer hexString = new StringBuffer();
			// 字节数组转换为 十六进制 数
			for (int i = 0; i < messageDigest.length; i++) {
				String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
				if (shaHex.length() < 2) {
					hexString.append(0);
				}
				hexString.append(shaHex);
			}
			return hexString.toString();

		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return "";
	}

	/**
	 * @method 开发者获得加密后的字符串可与signature对比
	 * @param str ,需要加密的字符串(排序后的字符串)
	 * @return 加密后的内容
	 */
	public static boolean equalSignature(String str, String signature) {
		boolean falg = false;
		if (str != null && str != "") {
			if (str.equals(signature)) {
				falg = true;
			}
		}
		return falg;

	}

	/**
	 * 发起Http请求, 通过GET方式访问网络用到的方法
	 * @param url,请求的URL地址
	 * @return 响应后的字符串
	 */
	public static JSONObject doGetStr(String url){
		DefaultHttpClient httpClient = new DefaultHttpClient();
		HttpGet httpGet = new HttpGet(url);
		JSONObject jsonObject = null;
		try {
			HttpResponse response =  httpClient.execute(httpGet);
			HttpEntity entity = response.getEntity();
			if(entity!=null){
				String result=EntityUtils.toString(entity);
				jsonObject = JSONObject.fromObject(result);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return jsonObject;
	}
	
	/**
	 * 发起Http请求, 通过POST方式访问网络用到的方法
	 * @param url,请求的URL地址
	 * @return 响应后的字符串
	 */
	public static JSONObject doPostStr(String url,String outstr){
		DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);
        JSONObject jsonObject = null;
		try {
			httpPost.setEntity(new StringEntity(outstr, "UTF-8"));
			HttpResponse response = httpClient.execute(httpPost);
			HttpEntity entity = response.getEntity();
			String result=EntityUtils.toString(entity,"UTF-8");
			jsonObject = JSONObject.fromObject(result);
		
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		return jsonObject;
		
	}

	/**
	 * 获取access_token
	 * @return AccessToken对象
	 */
	public static AccessToken getAccessToken() {
		AccessToken accessToken = new AccessToken();
		String url = WeiXin.ACCESS_TOKEN_URL.replace("APPID", WeiXin.APPID).replace("APPSECRET", WeiXin.APPSECRET);
		JSONObject jsonObject = WeiXinCheck.doGetStr(url);
		if (jsonObject != null) {
			accessToken.setAccessToken(jsonObject.getString("access_token"));
			accessToken.setExpiresin(jsonObject.getInt("expires_in"));
		}
		return accessToken;
	}
}

④AccessTokenServlet类(当服务器启动时会自动获取获取AccessToken,设置每隔7000s重新获取一次AccessToken)

package weixin.controller.accesstoken;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import weixin.entity.accesstoken.AccessToken;
import weixin.util.WeiXinCheck;
/**
 * @所属类别:servlet类
 * @用途:当服务器启动时会自动获取获取AccessToken,设置每隔7000s重新获取一次AccessToken
 * @author yilei
 * @version:1.0
 */
public class AccessTokenServlet extends HttpServlet {

	  @Override
	    public void init() throws ServletException {
	        System.out.println("默认启动AccessTokenServlet");
	        super.init();

	        //开启一个新的线程
	        new Thread(new Runnable() {
	            @Override
	            public void run() {
	                while (true) {
	                    try {
	                        //获取accessToken
	                    	AccessToken accessToken = WeiXinCheck.getAccessToken();
	                        //获取成功
	                        if (accessToken != null) {
	                        	System.out.println("access_token获取成功");
	                            //获取到access_token 休眠7000秒,大约2个小时左右
	                            Thread.sleep(7000 * 1000);
	                            //Thread.sleep(10 * 1000);//10秒钟获取一次
	                        } else {
	                            //获取失败
	                            Thread.sleep(1000 * 3); //获取的access_token为空 休眠3秒
	                        }
	                    } catch (Exception e) {
	                        System.out.println("发生异常:" + e.getMessage());
	                        e.printStackTrace();
	                        try {
	                            Thread.sleep(1000 * 10); //发生异常休眠1秒
	                        } catch (Exception e1) {

	                        }
	                    }
	                }

	            }
	        }).start();
	    }
}

⑤MainApplication微信开发接口入口

package weixin;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import weixin.util.WeiXin;
import weixin.util.WeiXinCheck;
/**
 * @所属类别:servlet类
 * @用途:微信开发接口入口
 * @author yilei
 * @version:1.0
 */
public class MainApplication extends HttpServlet{

	/**
	 * 开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上
	 * @param request
	 * @param response
	 * @throws IOException 
	 */
	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		 // TODO Auto-generated method stub
		 System.out.println("开始校验签名");
		 //接收微信服务器发送请求时传递过来的4个参数
		 String signature = request.getParameter("signature");//微信加密签名signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
		 String timestamp = request.getParameter("timestamp");//时间戳
		 String nonce = request.getParameter("nonce");//随机数
		 String echostr = request.getParameter("echostr");//随机字符串
		 //排序
		 String sortString = WeiXinCheck.sort(WeiXin.TOKEN, timestamp, nonce);
		 //sha1加密
		 String mySignature = WeiXinCheck.sha1(sortString);
		 //校验签名
		 if (WeiXinCheck.equalSignature(mySignature, signature)) {
	            System.out.println("签名校验通过。");
	            //如果检验成功输出echostr,微信服务器接收到此输出,才会确认检验完成。
	            //response.getWriter().println(echostr);
	            response.getWriter().println(echostr);
	        } else {
	            System.out.println("签名校验失败.");
	        }
	}
    @Override
	public void doPost(HttpServletRequest request, HttpServletResponse response){
	
    }
	
}

⑥web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
	xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <display-name></display-name>
  <servlet>
    <servlet-name>MainApplication</servlet-name>
    <servlet-class>weixin.MainApplication</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>MainApplication</servlet-name>
    <url-pattern>/main.do</url-pattern>
  </servlet-mapping>
  
    <servlet>
    <servlet-name>AccessTokenServlet</servlet-name>
    <servlet-class>weixin.controller.accesstoken.AccessTokenServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>AccessTokenServlet</servlet-name>
    <url-pattern>/AccessTokenServlet.do</url-pattern>
  </servlet-mapping>	
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

启动服务器,控制台输入:
在这里插入图片描述


微信开发学习总结(二)——微信开发环境准备(2)项目源码
下载地址:

https://download.csdn.net/download/qq_29914837/10696721


下一节内容:
微信开发学习总结(三)——消息管理—接收普通消息—(1)文本消息
https://blog.csdn.net/qq_29914837/article/details/82903594

发布了168 篇原创文章 · 获赞 214 · 访问量 20万+
展开阅读全文

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

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览