一直想尝试一下微信公众号开发,上上周开始弄的,碰到很多坑,现在把经验分析一下
一、注册微信公众平台
微信开发有公众平台和开放平台两种,公众平台是给关注用户推送信息用的,提供一些接口给开发者,开放平台是给成熟的app或网站提供接入、支付、分享的功能
在公众平台上注册的账号有三种:订阅号、服务号、企业号,一般个人只能申请订阅号,而且不能认证,遗憾的是公众平台的一些高级接口和开发者自定义菜单功能只开放给认证的用户
我申请的是未认证的订阅号,很快就通过了,几乎没有什么门槛,不过开启开发者模式以后,就失去了自定义菜单的功能
微信开放平台地址:https://mp.weixin.qq.com
微信开放平台开发文档:https://mp.weixin.qq.com/wiki
二、服务器接入认证
要开启开发者模式,需要对服务器url进行接入认证
在接入认证的时候,微信会对URL发送get请求(之后接收用户消息时,微信会改为对URL发送post请求)
在基本配置页面,URL是服务器的地址,Token是约定好的一串字符串,EncodingAESKey是用于验证的字符串
验证方法里面需要对三个参数做一定规则的运算,得到结果和echostr一样,然后返回,就能通过微信接入认证
示例代码:
/**
* 接入验证
*/
@ResponseBody
@RequestMapping(method = {RequestMethod.GET }, produces = "application/json;charset=UTF-8")
public String verifyAccess(VerifyAccessReq req) {
try {
if(!StringUtils.isEmpty(req.getEchostr())) {
String token = Global.getConfig("wx.token");
String[] ArrTmp = {token, req.getTimestamp(), req.getNonce()};
//进行字典序排序
Arrays.sort(ArrTmp);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < ArrTmp.length; i++) {
sb.append(ArrTmp[i]);
}
//进行sha1加密
String pwd = Encodes.Encrypt(sb.toString());
//如果相同就返回
if(!StringUtils.isEmpty(pwd) && pwd.equals(req.getSignature())) {
log.info("认证通过");
return req.getEchostr();
}
}
} catch (Exception e) {
log.debug("认证失败");
e.printStackTrace();
}
log.info("认证失败");
return "";
}
接入指南:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319
三、接收用户消息
用户消息是通过post在xml流里传过来的,先要解析成map对象:
/**
* 解析微信发来的xml请求
* @param request
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
//将解析结果存储在HashMap中
Map<String, String> map = new HashMap<String, String>();
//从request中取得输入流
InputStream inputStream = request.getInputStream();
//读取输入流
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
//得到xml根元素
Element root = document.getRootElement();
//得到根元素的所有子节点
List<Element> elementList = root.elements();
//遍历所有子节点
for (Element e : elementList) {
map.put(e.getName(), e.getText());
}
//释放资源
inputStream.close();
inputStream = null;
return map;
}
消息类型有文本消息、图片消息、语音消息、视频消息、地理位置消息、链接消息
目前我只用到文本消息:
//从流中获取xml数据转入map
Map<String, String> reqMap = MessageUtil.parseXml(request);
//得到接收消息实体
BaseMsgReq msgReq = new BaseMsgReq();
msgReq.setToUserName(reqMap.get("ToUserName"));
msgReq.setFromUserName(reqMap.get("FromUserName"));
msgReq.setCreateTime(reqMap.get("CreateTime"));
msgReq.setMsgType(reqMap.get("MsgType"));
msgReq.setMsgId(reqMap.get("MsgId"));
msgReq.setContent(reqMap.get("Content"));
msgReq.setEvent(reqMap.get("Event"));
四、回复用户消息
收到用户消息,进过处理以后,公众号需要返回信息给用户,微信的回复消息是xml结构的,有约定的格式要求,比如文本消息:
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[你好]]></Content>
</xml>
转换xml的示例代码:
/**
* 文本消息对象转换成xml
* @param textMsgRes
* @return
*/
public static String textMessageToXml(TextMsgRes textMsgRes) {
xstream.alias("xml", textMsgRes.getClass());
return xstream.toXML(textMsgRes);
}
/**
* 接收消息对象转换成xml
* @param msgReq
* @return
*/
public static String msgReqToXml(BaseMsgReq msgReq, String content) {
TextMsgRes textMsgRes = new TextMsgRes();
textMsgRes.setToUserName(msgReq.getFromUserName());
textMsgRes.setFromUserName(msgReq.getToUserName());
textMsgRes.setCreateTime(new Date().getTime());
textMsgRes.setMsgType("text");
textMsgRes.setContent(content);
return textMessageToXml(textMsgRes);
}
参考的教程:
五、24点游戏
这两周做的,欢迎来玩
源码地址:https://github.com/ctxsdhy/dntown