微信开发手册(1)
1、个人号与服务号(企业号先不谈):
微信公众帐号注册的第 3 步是选择“类型”,它有3个值可供选择“订阅号”,“服务号”,“企业号”。开发微信推荐选择“服务号”可获取菜单接口等权限,“订阅号”接口权限极低,账号类型选择后无法修改,请慎重。
2、微信公众帐号注册的第 4 步是信息登记,一般选择“企业”。填入相关信息,完成注册。
1、微信公众帐号申请成功后,要想接收处理用户的请求,就必须要在“开发者中心”里进行配置,点击“开发者中心”,将看到如下界面:
2、这里需要填写URL和Token两个值,EncodingAESKey(消息加解密密钥),加解密方式的默认状态为明文模式,选择兼容模式和安全模式需要提前配置好相关加解密代码。为了降低开发难度,请选择明文方式。
URL指的是能够接收处理微信服务器发送的GET/POST请求的地址,并且是已经存在的,现在就能够在浏览器访问到的地址,这就要求我们先把公众帐号后台处理程序开发好(至少应该完成了对GET请求的处理)并部署在公网服务器上。Token后面会详细说明。
也就是说要完成接口配置,只需要先完成微信服务器的GET请求处理就可以?是的。 那这是为什么呢?因为这是微信公众平台接口中定义的。具体请参考API文档-新手接入-接入指南的网址接入部分。
3、上面写的很清楚,其实你只要能理解上面在说什么就OK了,至于怎么编写相关代码,我已经帮你完成了,请继续往下看。
4、创建公众帐号后台接口程序:
创建一个Java Web工程,并新建一个能够处理请求的Action,命名任意,我在这里将其命名为edu.siso.action.WeiXinAction,代码如下:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import com.opensymphony.xwork2.ActionSupport;
import edu.siso.service.CoreService;
import edu.siso.util.SignUtil;
public class WeiXinAction extends ActionSupport implements ServletRequestAware,
ServletResponseAware {
private static final String GET = "GET";
private static final String POST = "POST";
private HttpServletRequest request;
private HttpServletResponse response;
private String signature;
private String timestamp;
private String nonce;
private String echostr;
private static final long serialVersionUID = 1L;
@Override
public String execute() throws Exception {
if (request.getMethod().equals(GET)) {
// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
if (SignUtil.checkSignature(signature, timestamp, nonce)) {
response.getWriter().write(echostr);
}
}
return null;
}
@Override
public void setServletResponse(HttpServletResponse response) {
// TODO Auto-generated method stub
this.response = response;
}
@Override
public void setServletRequest(HttpServletRequest request) {
// TODO Auto-generated method stub
this.request = request;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public String getNonce() {
return nonce;
}
public void setNonce(String nonce) {
this.nonce = nonce;
}
public String getEchostr() {
return echostr;
}
public void setEchostr(String echostr) {
this.echostr = echostr;
}
}
5、可以看到,代码中处理Get请求的方法,它的作用正是确认请求是否来自于微信服务器;而处理Post请求不是我们这次要讲的内容,并且完成接口配置也不需要管Post请求,就先空在那里。
在处理Get请求中调用了edu.siso.util.SignUtil方法,SignUtil.java的实现如下:
package edu.siso.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
public class SignUtil {
// 与接口配置信息中的Token要一致 ,我设置成了自己的名字
private static String token = "zhongren";
/**
* 验证签名
*
* @param signature
* @param timestamp
* @param nonce
* @return
*/
public static boolean checkSignature(String signature, String timestamp, String nonce) {
String[] arr = new String[] { token, timestamp, nonce };
// 将token、timestamp、nonce三个参数进行字典序排序
Arrays.sort(arr);
StringBuilder content = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
content.append(arr[i]);
}
MessageDigest md = null;
String tmpStr = null;
try {
md = MessageDigest.getInstance("SHA-1");
// 将三个参数字符串拼接成一个字符串进行sha1加密
byte[] digest = md.digest(content.toString().getBytes());
tmpStr = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
content = null;
// 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
return tmpStr != null ? tmpStr.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[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
char[] tempArr = new char[2];
tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
tempArr[1] = Digit[mByte & 0X0F];
String s = new String(tempArr);
return s;
}
}
6、这里唯一需要注意的就是SignUtil类中的成员变量token,这里赋予什么值,在接口配置信息中的Token就要填写什么值,两边保持一致即可,没有其他要求,建议用项目名称、公司名称缩写等,我在这里用的是我的名字zhongren。
最后再来看一下struts.xml中,WeiXinAction是怎么配置的,struts.xml中的配置代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
<constant name="struts.action.extension" value="do,action,," />
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<constant name="struts.ognl.allowStaticMethodAccess" value="true" />
<constant name="struts.multipart.maxSize" value="2073741824" />
<package name="weixin" extends="struts-default">
<action name="weixinSign" class="edu.siso.action.WeiXinAction">
<result name="sign"></result>
</action>
</package>
</struts>
7、到这里,所有编码都完成了,就是这么简单。接下来就是将工程发布到公网服务器上,如果没有公网服务器环境,可以去了解下BAE、SAE或阿里云(貌似都是收费的 - -)。发布到服务器上后,我们在浏览器里访问WeiXinAction,如果看到如下界面就表示我们的代码没有问题:
8、啊~~~,代码都报空指针异常了还说证明没问题?那当然了,因为直接在地址栏访问WeiXinAction,就相当于提交的是GET请求,而我们什么参数都没有传,在验证的时候当然会报空指针异常。
最后简单说一下为什么action返回的是null而不是一个String.
大家都之后默认写struts2的时候需要指定返回路径,通常使用String来做.Struts会根据你所返回的值去查找对应的页面.返回null就是因为微信接口协议,协议中说了echostr参数要原样返回,如果是使用浏览器来看的话页面只有echostr的值,没有其他的字符.所以直接返回response,到页面就输出print了。
9、到这里,接口配置、开发模式的开启就都完成了,本章节的内容也就讲到这里。接下来要章节要讲的就是如何接收、处理、响应由微信服务器转发的用户发送给公众帐号的消息,也就是完成对Post请求处理的编写。