微信公众号开发学习笔记(一)

时间:2022-06-06 10:43:59

微信公众号开发入门(一) -- 接入

测试号申请

由于项目还处在演示版和研发初期, 客户并没有提供正式的公众号, 所以暂时使用测试号进行研发.
测试号申请地址
http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
开发者扫码即可申请成功, 申请成功后如下图:
微信公众号开发学习笔记(一)

测试号信息:
appID和appsecret相当于公众号的一把钥匙, 可以用来获取全局唯一票据access_token.

接口配置信息:
URL: 开发者用来接收微信消息和事件的接口URL
Token: 由开发者可以任意填写, 用作生成签名(该Token会和接口URL中包含的Token进行比对, 从而验证安全性)

准备外网环境

我们需要有一台能被互联网所访问的服务器, 没有也没有关系, 市面上各种云服务器还是比较好用的.
可以将我们的发布包部署在上面. ngrok也可以

微信公众号接口只支持80端口

编写接入程序(Java)

这里用的是Servlet, 用其他技术也是可以的比如spring mvc.

新建一个Servlet, 命名为CoreController, 作为核心控制器
get方法作为接入微信服务的接口
post方法预留, 用于接收用户请求

package com.thunisoft.wechat.connect;

import java.io.IOException;
import java.util.Arrays;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.thunisoft.wechat.util.PropertiesLoader;
import com.thunisoft.wechat.util.Sha1Util;

public class CoreController extends HttpServlet {

/** 日志 */
private final Logger LOGGER = LoggerFactory.getLogger(CoreController.class);

/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 微信加密签名, signature结合了开发者填写的token参数和请求中的timestamp参数, nonce参数。
String signature = request.getParameter("signature");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce");
// 随机字符串
String echostr = request.getParameter("echostr");
String token = PropertiesLoader.getProperty("token");

/*
* 加密/校验流程如下:
* 1. 将token、timestamp、nonce三个参数进行字典序排序
* 2. 将三个参数字符串拼接成一个字符串进行sha1加密
* 3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
* 4. 返回echostr
*/
String[] tmpStrArr = {token, timestamp, nonce};
Arrays.sort(tmpStrArr);

StringBuilder tmpStr = new StringBuilder();
for(int i=0; i<tmpStrArr.length; i++) {
String temp = tmpStrArr[i];
tmpStr.append(temp);
}

if(Sha1Util.checkSignature(signature, tmpStr.toString())) {
response.getWriter().print(echostr);
LOGGER.info("------接入成功------");
} else {
LOGGER.info("------接入失败------");
}

}

/**
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to post.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}

}

其中, token就是公众号配置页面中所填写的token, 这里把它写在了配置文件wechat.properties中.

#Token
token=wechat



CoreController在web.xml中的配置:

<!-- 微信接入 -->
<servlet>
<servlet-name>CoreController</servlet-name>
<servlet-class>com.thunisoft.wechat.connect.CoreController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CoreController</servlet-name>
<url-pattern>/connect</url-pattern>
</servlet-mapping>

url-pattern/connect, 要与公众号配置页面中所填写的URL一致.

CoreController中用到了PropertiesLoader和Sha1Util两个类,
PropertiesLoader用于加载配置文件wechat.properties, 并提供配置项的值, 代码如下:

package com.thunisoft.wechat.util;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PropertiesLoader {

private static final Logger logger = LoggerFactory.getLogger(PropertiesLoader.class);

private static final String CONFIG_PROPERTIES = "/props/wechat.properties";

private static Properties properties = new Properties();

static {

// load wechat.properties
InputStream in = PropertiesLoader.class.getResourceAsStream(CONFIG_PROPERTIES);

if (in == null) {
logger.error("{} not found", CONFIG_PROPERTIES);
throw new RuntimeException(CONFIG_PROPERTIES + " not found");
} else {
if (!(in instanceof BufferedInputStream)) {
in = new BufferedInputStream(in);
}
try {
properties.load(in);
in.close();
logger.debug("{} loaded", CONFIG_PROPERTIES);
} catch (Exception e) {
logger.error("Error while processing {}", CONFIG_PROPERTIES);
throw new RuntimeException("Error while processing " + CONFIG_PROPERTIES, e);
}
}

}

public static String getProperty(final String key) {
return properties.getProperty(key);
}

}



Sha1Util用于sha1加密以及验证sha1加密票据, 代码如下:

package com.thunisoft.wechat.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Sha1Util
* @author 第七狙击手
* @version 1.0
*
*/
public class Sha1Util {

/** 字符数组 */
private static char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

/** 日志 */
private static final Logger LOGGER = LoggerFactory.getLogger(Sha1Util.class);

/**
* sha1加密
* @param src 待加密字符串
* @return 加密字符串
*/
public static String encrypt(String src) {
String sha1Dest = null;
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-1");
byte[] digest = md.digest(src.getBytes());
sha1Dest = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
LOGGER.error("加密失败!", e);
}
return sha1Dest;
}

/**
* 验证sha1签名
* @param signature sha1签名
* @param src 待加密串
* @return 通过是否验证
*/
public static boolean checkSignature(String signature, String src) {
String sha1Dest = encrypt(src);
return sha1Dest != null ? sha1Dest.equals(signature.toUpperCase()) : false;
}

/**
* 将字节数组转换为十六进制字符串
* @param byteArray 字节数组
* @return 十六进制字符串
*/
private static String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}
return strDigest;
}

/**
* 字节转为十六进制字符串
* @param mByte 字节
* @return 十六进制字符串
*/
private static String byteToHexStr(byte mByte) {
char[] tempArr = new char[2];
tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
tempArr[1] = Digit[mByte & 0X0F];

String s = new String(tempArr);
return s;
}
}

示例源码:
https://github.com/lizujia/wechat_demo.git

如有错误, 请随时指正, 谢谢!



如需转载, 请注明作者及出处.

作者:第七狙击手

出处:http://www.cnblogs.com/lzj0616/