微信公众号开发
在进行学习微信公众号开发时,首先我们需要做好一些必须的准备。
1.具有一个自己的公众号平台,方便进行学习。
2.在网上找一款内网穿透器,进行内网穿透,接入微信开发。
3.有一个已经搭建好的Web项目。
1.申请微信公众号
进行微信公众号申请时,在下方地址进行申请即可,我们申请时可以根据自己的不同需求进行申请,选择订阅号或者服务号。企业号的开发模式和微信公众号类似,但是必须由企业才能进行申请。
https://mp.weixin.qq.com/cgi-bin/registermidpage?action=index&lang=zh_CN
这里不对申请做过多描述,按照表单填写即可,很简单。
2.使用内网穿透器进行内网穿透
免费的内网穿透器有很多,博主使用过的有花生壳和Ngrok,这里推荐使用Ngrok,花生壳速度很慢,而且自身网站也有很多BUG。Ngrok的网站地址如下:
https://www.ngrok.cc/#down-client
申请注册完成后,选择登录按钮进行登录,在左侧选择开通隧道,进入如下界面,选择免费的版本。
选择后进行隧道开通,可以将表单设置为如下信息:
前置域名可以写一个自己喜欢的域名,端口号要与本地服务器的端口号一致。隧道名称可以随便起,方便自己识别。
然后我们要去下载区进行下载windows版本的客户端。下载完成后进行解压,可以获得到两个文件夹,这里我们只保留下面一个文件夹即可。
运行该文件夹下的脚本文件 Sunny-Ngrok启动工具.bat之后,可以看到如下界面
在这里我们可以输入隧道Id,隧道Id可以在穿透器的管理界面获得,即下方的隧道Id
随后将隧道Id填写脚本中,如果需要启动多个隧道,则以逗号进行分割,启动内网穿透器,不要关闭。
3.测试项目内网穿透
在项目的隧道编辑页面可以找到如下前置域名
该域名为与我们平时项目运行时的域名localhost:8080相同,后跟项目路径即可。
我的项目访问名直接配置的/,可以获得如下界面:
测试接口访问成功后,我们的准备工作就已经完成了。
4.连接微信公众号
我们可以进入开发者工具---开发者文档 进行查看如何进行URL的接入
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432
在开始开发--接入指南 中可以看到,在进行接入时,微信公众号会向定义好的接口URL发送get请求,参数为
signature | 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 |
timestamp | 时间戳 |
nonce | 随机数 |
echostr | 随机字符串 |
根据微信开发文档所指出,我们可以通过对所获得的参数进行加密处理进行校验,如果成功则返回echostr参数,表示接入成功。这里我们将直接返回该参数,不进行验证。
然后进入项目,进行代码编写,创建一个SpringMVC的Servlet接口:
@RequestMapping("check.do")
@ResponseBody
public String checkInterface(String signature, String timestamp, String nonce,
String echostr, HttpServletResponse response) throws IOException {
// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
System.out.println(echostr);
return echostr;
}
接口编写完成以后,我们可以在微信管理界面中,进行接入接口的配置。
我们登录进入自己所申请的微信公众号,在最下方的开发中,有一个 基本配置 按钮,进入页面,进行配置我们公众号的一系列信息。
这里为了便于学习,采用了明文模式,即不对来往的消息进行加密处理。URL需要填写我们进行接入微信公众号的URL,token可以随意填写,识别验证进行使用。EncodingAESKey使用随机生成即可。
5.Access_token的获取
Access_token是在微信开发中,常用的一个token参数,这个参数每天最多获取2000次,且参数的有效期默认为7200秒。我们可以通过以下接口进行获取:
https://api.weixin.qq.com/cgi-bin/token
grant_type | 是 | 获取access_token填写client_credential |
appid | 是 | 第三方用户唯一凭证 |
secret | 是 | 第三方用户唯一凭证密钥,即appsecret |
该接口中,具有以上三个参数,其中grant_type直接填写client_credential即可,后两个参数可以在开发者配置中找到,如下图所示
开发者密码需要进行重置以后才能看到。看完开发者密码以后,要注意保存,否则无法再次查看。我们在进行对微信公众平台的访问时,需要通过httpClient进行。在添加httpClient的jar包到项目中以后,添加一个工具类:
package com.mender.mdoa.weixin.util;
import org.apache.http.HttpEntity;
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.client.methods.HttpUriRequest;
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 java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class HttpUtil {
/**
* 发送get请求到指定的URl
* @param url Url地址
* @param params 参数列表
* @return 返回的信息
*/
public String sendGet(String url, Map<String, String> params){
StringBuffer sbUrl = new StringBuffer(url);
//1.使用默认的配置的httpclient
CloseableHttpClient client = HttpClients.createDefault();
//2.使用get方法
if(params != null && params.size() != 0){
Set<String> keys = params.keySet();
sbUrl.append("?");
for(String key : keys){
sbUrl.append(key).append("=").append(params.get(key)).append("&");
}
sbUrl.substring(0,sbUrl.length() - 1);
}
System.out.println(sbUrl.toString());
HttpGet httpGet = new HttpGet(sbUrl.toString());
InputStream inputStream = null;
CloseableHttpResponse response = null;
return this.excute(httpGet);
}
/**
* 发送post请求到指定的URl
* @param url Url地址
* @param params 参数列表
* @return 返回的信息
*/
public String sendPost(String url, Map<String, String> params) throws UnsupportedEncodingException {
StringBuffer sbUrl = new StringBuffer(url);
//1.使用默认的配置的httpclient
CloseableHttpClient client = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(sbUrl.toString());
if(params != null && params.size() > 0){
List<BasicNameValuePair> paramList = new LinkedList<BasicNameValuePair>();
Set<Map.Entry<String, String>> entrySet = params.entrySet();
for(Map.Entry<String, String> entry : entrySet){
paramList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList,"UTF-8");
httpPost.setEntity(entity);
}
return this.excute(httpPost);
}
/**
* 发送信息
* @param request
* @return
*/
private String excute(HttpUriRequest request){
InputStream inputStream = null;
CloseableHttpResponse response = null;
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
response = httpClient.execute(request);
HttpEntity entity = response.getEntity();
return EntityUtils.toString(entity, "utf-8");
} catch (IOException e) {
e.printStackTrace();
return null;
}finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (response != null) {
try {
response.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
然后使用该工具类发送请求到微信的access_token获取接口即可。
如下方代码所示:
public static String getToken(){
String url="https://api.weixin.qq.com/cgi-bin/token";
Map<String, String> params = new HashMap<String, String>();
params.put("grant_type","client_credential");
params.put("appid","wx128a89fa44624819");
params.put("secret","a6ac12b17e8ce4b611f50c0e99571855");
HttpUtil httpUtil = new HttpUtil();
String response = httpUtil.sendGet(url, params);
System.out.println(response);
return response;
}
该方法所返回的response字符串,就是一个包含了access_token的json串,从字符串中提取即可。
在这里可能会出现一下异常提示
{"errcode":40164,"errmsg":"invalid ip XXX.10.XXX.XXX, not in whitelist hint: [.L7cCA0682nfo1]"}
这里是因为我们没有将自己的ip地址设置到公众号的ip地址白名单中,我们只需要将报错信息中的ip复制,然后添加到 微信管理中心---开发配置---白名单 中即可。
6.Access_token过期?
Access_token过期以后会跑出一个异常编码,编码的信息可以在微信开发文档中进行查看。因为Access_token具有有效期,因此我们需要每隔一段时间进行一次获取,Access_token在获取到下一个以后,前一个仍然是有效的,可以使用的,因此在这里建议使用Spring的定时任务进行获取,时间周期设定在小于两小时即可。
我们也可以通过如下代码进行有效性的测试:
public static void main(String args[]) throws UnsupportedEncodingException {
String token1 = getToken();
String token2 = getToken();
Gson gson = new Gson();
Map<String, String> map = gson.fromJson(token1, HashMap.class);
token1 = map.get("access_token");
map = gson.fromJson(token2, HashMap.class);
token2 = map.get("access_token");
String address1 = getServerAddress(token1);
String address2 = getServerAddress(token2);
System.out.println(address1);
System.out.println(address2);
}
public static String getToken(){
String url="https://api.weixin.qq.com/cgi-bin/token";
Map<String, String> params = new HashMap<String, String>();
params.put("grant_type","client_credential");
params.put("appid","wx128a89fa44624819");
params.put("secret","a6ac12b17e8ce4b611f50c0e99571855");
HttpUtil httpUtil = new HttpUtil();
String response = httpUtil.sendGet(url, params);
System.out.println(response);
return response;
}
public static String getServerAddress(String token){
String url="https://api.weixin.qq.com/cgi-bin/getcallbackip";
Map<String, String> params = new HashMap<String, String>();
params.put("access_token",token);
HttpUtil httpUtil = new HttpUtil();
String response = httpUtil.sendGet(url, params);
System.out.println(response);
return response;
}
先获取了两个access_token然后使用这两个access_token来获取微信的服务地址,最后我们就可以得到这个结果。这样可以证明access_token是可以多次获取,且在后一次获取后,前一次依然有效的。