自己尝试写了一下微信公众号的demo,现将开发的流程及遇到的问题记录下来。
这篇文章可以说是小白入门的一个路标,代码是从网上搜到的一个例子稍加改动,地址http://blog.csdn.net/pamchen/article/details/38718947,感谢原作者。
在文章的开头贴上微信公众平台技术文档的地址
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432
tips:官方的文档,重要性你懂的,基本全靠它!
一般来说,我们的web项目是通过浏览器直接与用户进行交互,微信公众号的开发本质上是一样的,我们与用户的交互需要以微信为媒介,我们要做的就是通过微信收到用户的操作且将回应交给微信~~~
开发碰到的第一个问题就是既然要与微信交互,如何把我们的项目放到外网,可以让微信可以访问到。当然实际开发中是有生产环境的,但是在生产环境上测试极为不便,这里介绍一个开源的小程序——ngrok。
ngrok 是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。
我用的是windows版本,贴上链接:
https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-windows-386.zip
打开程序会弹出一个dos命令框,如图:
将红框里的内容复制下来,即ngrok.exe http 80。
tips:80指你的项目端口号,如果是8080就写ngrok.exe http 8080
tips:公众平台接口调用仅支持80端口
执行命令,如图:
启动成功后外网就可以访问到你的本地项目了,红框中是说用左边的地址等同于右边,记得后面要加项目名。
第一步需要在微信上注册公众号,这里我们可以注册一个测试号,在微信公众平台技术文档的开始开发目录下的接口测试号申请有链接,点开并登陆,如图:
tips:点击提交微信会向这个地址发送请求,接入验证时会收到echostr参数,需将它返回给微信,详情见代码
这里需要填两个信息。一个是URL,即你的项目用来接收微信端的信息并回应的地址。还有一个是Token,你的公众号的令牌。下面是Token的获取方法——微信公众平台技术文档中开始开发目录下的获取access_token,如图:
图中的地址就是获取Token的接口,我们只需要把红框中的APPID和APPSECRET替换为上一张图片我们自己的,copy到地址栏回车就可以获取token了,如图:
回到注册,填入RUL和Token点击提交就可以开始提供微信公众号的测试了!
微信公众号的信息交互是通过XML数据完成的。
总览:
public void test(HttpServletRequest request, HttpServletResponse response) throws Exception{
/** 设置编码方式 */
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
/** 参数校验,校验失败则返回 */
校验代码...(参考下文5)
if(boolean) return;
/** 判断是否是微信接入激活验证,只有首次接入验证时才会收到echostr参数,此时需要把它直接返回 */
String result ;
String echostr = request.getParameter("echostr");
if (echostr != null && echostr.length() > 1) {
/** 是初次校验 */
result = echostr;
} else {
/** 不是初次校验 */
解析接收到的xml消息... (参考下文2)
封装xml数据...(参考下文3)
result = 返回响应xml数据...(参考下文4)
}
try {
OutputStream os = response.getOutputStream();
os.write(result.getBytes("UTF-8"));
os.flush();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
1.判断是否初次接入:
String result ;
/** 判断是否是微信接入激活验证,只有首次接入验证时才会收到echostr参数,此时需要把它直接返回 */
String echostr = request.getParameter("echostr");
if (echostr != null && echostr.length() > 1) {
result = echostr;
} else {
//正常的微信处理流程
}
try {
OutputStream os = response.getOutputStream();
os.write(result.getBytes("UTF-8"));
os.flush();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
2.读取微信xml数据:
/** 读取接收到的xml消息 */
StringBuffer sb = new StringBuffer();
InputStream is = request.getInputStream();
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
BufferedReader br = new BufferedReader(isr);
String s = "";
while ((s = br.readLine()) != null) {
sb.append(s);
}
String xml = sb.toString();
3.xml数据的封装:
entity对象
public class ReceiveXmlEntity {
private String ToUserName;
private String FromUserName;
private String CreateTime;
private String MsgType;
private String MsgId;
private String Event;
private String EventKey;
private String Ticket;
private String Latitude;
private String Longitude;
private String Precision;
private String PicUrl;
private String MediaId;
private String Title;
private String Description;
private String Url;
private String Location_X;
private String Location_Y;
private String Scale;
private String Label;
private String Content;
private String Format;
private String Recognition;
/** get,set及其他方法省略 */
}
xml数据的封装
ReceiveXmlEntity msg = null;
try {
if (strXml.length() <= 0 || strXml == null) return null;
// 将字符串转化为XML文档对象
Document document = DocumentHelper.parseText(strXml);
// 获得文档的根节点
Element root = document.getRootElement();
// 遍历根节点下所有子节点
Iterator> iter = root.elementIterator();
// 遍历所有结点
msg = new ReceiveXmlEntity();
//利用反射机制,调用set方法
//获取该实体的元类型
Class> c = Class.forName("entity.ReceiveXmlEntity");
msg = (ReceiveXmlEntity)c.newInstance();
while(iter.hasNext()){
Element ele = (Element)iter.next();
//获取set方法中的参数字段(实体类的属性)
Field field = c.getDeclaredField(ele.getName());
//获取set方法,field.getType())获取它的参数数据类型
Method method = c.getDeclaredMethod("set"+ele.getName(), field.getType());
//调用set方法
method.invoke(msg, ele.getText());
}
} catch (Exception e) {
// TODO: handle exception
System.out.println("xml 格式异常: "+ strXml);
e.printStackTrace();
}
tips:需要dom4j.jar
4.返回响应xml数据
在微信公众平台技术文档中消息管理目录下的接收消息-接收普通消息中有xml数据的示例,代码以文本消息为例
public String formatXmlAnswer(String to, String from, String content) {
StringBuffer sb = new StringBuffer();
Date date = new Date();
sb.append("<xml><ToUserName>ToUserName><FromUserName>FromUserName><CreateTime>");
sb.append(date.getTime());
sb.append("CreateTime><MsgType>MsgType><Content>Content><FuncFlag>0FuncFlag>xml>");
return sb.toString();
}
5.微信消息的校验
可以校验该条消息是否确实是微信端的信息,在微信公众平台技术文档中开始开发目录下的接入指南中有验证消息的参数的介绍。java代码如下
public class CheckUtil {
private static final String token = "";
public static boolean checkSignature(String signature,String timestamp,String nonce){
String[] arr = new String[] { token, timestamp, nonce };
// 排序
Arrays.sort(arr);
// 生成字符串
StringBuilder content = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
content.append(arr[i]);
}
// sha1加密
String temp = getSHA1String(content.toString());
return temp.equals(signature); // 与微信传递过来的签名进行比较
}
private static String getSHA1String(String data){
return DigestUtils.sha1Hex(data); // 使用commons codec生成sha1字符串
}
}
自定义菜单在官方文档中有到很详细的描述和跳转到调试工具的链接,这里说一下我碰到的问题:官网上写的json例子粘上去返回错误!自己参照着写一个就Ok了。
微信公众号还有很多用法,无非就是接口地址后带上token,用post方式发送某种特定格式的数据,你需要仔细研读开发文档。