基于《wechat——微信公众号开发前准备(腾讯云服务器)》和《Wechat——微信公众号开发前准备(外网映射)》两篇文章,微信开发调试环境已搭建好,接下来进行微信公众平台的开发工作。
微信公众平台实际只是起到一个桥梁作用,实际处理业务、提供服务的代码,需要我们在服务器上面编写后台代码。目前,腾讯推荐的编码语言有PHP、Java、Python、Go,本文主要以外网映射为例,使用Java进行微信公众平台开发。
1 开发环境搭建
JDK、Tomcat、Eclipse、Mysql
1.1 JDK
下载&安装:
https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
环境变量配置:
“JAVA_HOME”:“D:…\jdk1.8.0_112”(jdk的安装路径)
“Path”:“;%JAVA_HOME%\bin;”
CLASSPATH”:“.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;”
验证:cmd,分别输入“java”和“javac”回车,都正常运行即配置成功
1.2 Tomcat服务器
Apache Tomcat是一个开源软件,可作为独立的服务器来运行JSP和Servlets,也可以集成在 Apache Web Server中。
(1)下载(zip):
(2)测试:
解压之后,运行bin目录下的startup.bat,启动服务。
在浏览器端:http://localhost/, 显示Apache界面表示成功。
(可在conf/server.xml中设置端口,默认端口80)
(3)部署web应用
通过复制web应用到Tomcat安装目录下面的“webapps”文件夹下的“ROOT”文件夹中
然后启动Tomcat服务器,再打开浏览器,输入“http://localhost/项目名称” (例如:“http://localhost/NewFile.jsp” ),访问成功。
(4)建立虚拟目录
在Tomcat安装目录下的“conf”文件夹下找到“server.xml”文件打开,在节点中间添加
(path指的是访问的路径,docBase指的是存放路径)
然后保存并重启Tomcat服务器,在浏览器输入地址“http://localhost:8080/my/NewFile.jsp”访问页面
1.3 Eclipse
(1)下载&解压,设置工作空间
(2)配置Tomcat
- eclipse中在“菜单栏 — 窗口 — 首选项”选项,打开首选项
- 选择“Sever — Runtime Environments — Add”,选择相对应的Tomcat版本,输入Tomcat的安装路径,使用默认的JRE,点击“完成”
- Eclipse工作态,选择“Server”,点击“蓝色字体”,选择相对应的Tomcat版本,然后点击“完成”,配置完成
(3)验证配置是否成功
- 启动eclipse,在“菜单栏”选择“File — new — Dynamic Web Project”,创建一个JSP项目
- 在“Project name”输入项目名称,“Target runtime”选择相对应版本的Tomcat服务器,其他选项默认,点击“完成”即创建成功
- 点击“菜单栏”的绿色“启动”按钮,在弹出来的页面点击“完成”,跳出相应页面即配置成功
1.4 mysql数据库(暂时用不到,可稍后装)
如有数据库需求,需安装mysql和navicat
下载:
https://dev.mysql.com/downloads/mysql/
https://dev.mysql.com/downloads/connector/j/
安装:
1.5 JavaWeb项目的工程目录
- Java Resource
- src:存放Java源代码的目录。
- Libraries:存放的是Tomcat及JRE中的jar包。
- build:自动编译.java文件的目录
- WebContent(WebRoot):存放的是需要部署到服务器的文件
-
MEAT-INF:是存放工程自身相关的一些信息,元文件信息,通常由开发工具和环境自动生成。
- MANIFEST.MF:配置清单文件
-
WEB-INF:这个目录下的文件,是不能被客户端直接访问的。
- classes:存放Java字节码文件的目录。
- lib:用于存放该工程用到的库。
- web.xml:web工程的配置文件,完成用户请求的逻辑名称到真正的servlet类的映射。
-
凡是客户端能访问的资源(html或.jpg)必须跟WEB-INF在同一目录,即放在Web根目录下的资源,从客户端是可以通过URL地址直接访问的。
-
2 微信公众号接入(校验签名)
该部分参照接入指南,进行实际操作。
第一步:填写服务器配置
微信公众平台,开发–>基本配置–>服务器配置
(1)URL:服务器地址即公众号后台提供业务逻辑的入口地址,目前只支持80端口,之后包括接入验证以及任何其它的操作的请求(例如消息的发送、菜单管理、素材管理等)都要从这个地址进入。接入验证和其它请求的区别就是,接入验证时是get请求,其它时候是post请求;
(2)Token:可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性);
(3)EncodingAESKey:由开发者手动填写或随机生成,将用作消息体加解密密钥。本例中全部以未加密的明文消息方式,不涉及此配置项。
第二步:验证消息的确来自微信服务器
开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示:
参数 | 描述 |
---|---|
signature | 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 |
timestamp | 时间戳 |
nonce | 随机数 |
echostr | 随机字符串 |
开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。加密/校验流程如下:
1)将token、timestamp、nonce三个参数进行字典序排序
2)将三个参数字符串拼接成一个字符串进行sha1加密
3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
下面我们用Java代码来演示一下这个验证过程:
(1)创建一个JavaWeb项目,新建servlet–weChatAccounts,代码如下:
package weChatServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Properties;
public class weChatAccounts extends HttpServlet {
static Logger logger = LoggerFactory.getLogger(weChatAccounts.class);
/*
* 自定义token, 用作生成签名,从而验证安全性
* */
private final String TOKEN ="weixin";
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("-----开始校验签名-----");
/**
* 接收微信服务器发送请求时传递过来的参数
*/
String signature = req.getParameter("signature");
String timestamp = req.getParameter("timestamp");
String nonce = req.getParameter("nonce"); //随机数
String echostr = req.getParameter("echostr");//随机字符串
/**
* 将token、timestamp、nonce三个参数进行字典序排序
* 并拼接为一个字符串
*/
String sortStr = sort(TOKEN,timestamp,nonce);
/**
* 字符串进行shal加密
*/
String mySignature = shal(sortStr);
/**
* 校验微信服务器传递过来的签名 和 加密后的字符串是否一致, 若一致则签名通过
*/
if(!"".equals(signature) && !"".equals(mySignature) && signature.equals(mySignature)){
System.out.println("-----签名校验通过-----");
resp.getWriter().write(echostr);
}else {
System.out.println("-----校验签名失败-----");
}
}
/**
* 参数排序
* @param token
* @param timestamp
* @param nonce
* @return
*/
public 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();
}
/**
* 字符串进行shal加密
* @param str
* @return
*/
public String shal(String str){
try {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update(str.getBytes());
byte messageDigest[] = digest.digest();
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 "";
}
}
(2)在web.xml中配置 servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app 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_3_1.xsd"
version="3.1">
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>weChatServlet</servlet-name>
<servlet-class>weChatServlet.weChatAccounts</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>weChatServlet</servlet-name>
<url-pattern>/weChatServlet</url-pattern> <!--url-pattern必须与servlet-name一致-->
</servlet-mapping>
</web-app>
(3)然后在index.jsp中写hello world 测试:
<%-- Created by IntelliJ IDEA. --%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
<title></title>
</head>
<body>
<h3>微信公众号测试!</h3>
</body>
</html>
(4)启动项目结果如下:
(5)启动natapp,进行内网透传 natapp -authtoken yourtoken
(6)根据动态生成的ip地址访问.,得到如下效果,则表示外网可以成功访问:
(7)进入微信测试公众号管理界面,在接口配置信息中填入映射的外网地址和代码中声明的token,如下图所示:
点击提交,会显示配置成功, 控制台就会打印信息, 显示签名校验通过.(注意: URL是 外网的ip地址加上 web.xml中配置的servlet名称)
(8)总结
(撒花~)
项目启动后,通过微信公众号测试的全过程:
- 开启外网访问 : CMD进入natapp目录下, 运行命令natapp -authtoken yourauthtoken , 得到外网访问的域名
- Tomcat启动项目
- 进入微信公众号测试管理平台, 修改接口配置信息URL为: 新域名/weChatServlet , 待签名校验通过,就可以测试
- 进入测试公众号, 发送消息进行测试
到此,我们的公众号应用已经能够和微信服务器正常通信了,也就是说我们的公众号已经接入到微信公众平台了。
第三步:依据接口文档实现业务逻辑(此步即为接下来的开发,come on~)
验证URL有效性成功后即接入生效,成为开发者。你可以在公众平台网站中申请微信认证,认证成功后,将获得更多接口权限,满足更多业务需求。
成为开发者后,用户每次向公众号发送消息、或者产生自定义菜单、或产生微信支付订单等情况时,开发者填写的服务器配置URL将得到微信服务器推送过来的消息和事件,开发者可以依据自身业务逻辑进行响应,如回复消息。
公众号调用各接口时,一般会获得正确的结果,具体结果可见对应接口的说明。返回错误时,可根据返回码来查询错误原因。全局返回码说明
3 access_token管理
我们的公众号和微信服务器对接成功之后,接下来要做的就是根据我们的业务需求调用微信公众号提供的接口来实现相应的逻辑了。在使用微信公众号接口中都需要一个access_token。
3.1 access_token介绍
access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。详见获取access_token。
总结来说,access_token需要做到以下两点:
- 因为access_token有2个小时的时效性,要有一个机制保证最长2个小时重新获取一次。
- 因为接口调用上限每天2000次,所以不能调用太频繁。
3.2 获取access_token步骤
3.3 代码实现获取access_token
定义一个默认启动的servlet,在init方法中启动一个Thread,这个进程中定义一个无限循环的方法,用来获取access_token,当获取成功后,此进程休眠7000秒(7000秒=1.944444444444444小时),否则休眠3秒钟继续获取。流程图如下:
未完待续。。。。