进入公众账号的后台https://mp.weixin.qq.com/,
微信公众平台的通讯机制
开发流程
从上图中可以看到,高级功能包含两种模式:编辑模式和开发模式,并且这两种模式是互斥关系,即两种模式不能同时开启。那两种模式有什么区别呢?作为开发人员到底要开启哪一种呢?
编辑模式:主要针对非编程人员及信息发布类公众帐号使用。开启该模式后,可以方便地通过界面配置“自定义菜单”和“自动回复的消息”。
开发模式:主要针对具备开发能力的人使用。开启该模式后,能够使用微信公众平台开放的接口,通过编程方式实现自定义菜单的创建、用户消息的接收/处理/响应。这种模式更加灵活,建议有开发能力的公司或个人都采用该模式。
在这里就只介绍开发模式了, 编辑没有就不用讲了,都是动手操作的事情太简单了。 嘿嘿。
开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,否则接入失败。
signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
加密/校验流程: 1. 将token、timestamp、nonce三个参数进行字典序排序 2. 将三个参数字符串拼接成一个字符串进行sha1加密 3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
备注 :URL必须是公网地址
后台代码
/**
* User: zhanglin
* Date: 13-10-23
* Time: 下午5:31
* Desc: 微信控制电器
*/
@Controller
@RequestMapping("/")
public class WeiXinControllerTest {
private static Logger log = LogManager.getLogger(WeiXinControllerTest.class);
@Resource
private ServiceConfig serviceConfig;
@Resource
private IWeiXinTextService weiXinTextService;
//get请求方式,可以做测试用。
@ResponseBody
@RequestMapping(method = RequestMethod.GET)
public String get(ModelMap model, String signature, String timestamp, String nonce, String echostr) {
boolean bChecked = check(signature, timestamp, nonce);
if (bChecked) {
return echostr;
}
return "hello";
} //微信进来的请求就通过POST方式进来
@RequestMapping(method = RequestMethod.POST)
public void post(String signature, String timestamp, String nonce, HttpServletRequest request, HttpServletResponse response) {
boolean bChecked = check(signature, timestamp, nonce);
if (bChecked) {
response.setCharacterEncoding("UTF-8");
PrintWriter out = null;
Document doc;
SAXReader reader = new SAXReader();
InputStream in = null;
try {
out = response.getWriter();
in = request.getInputStream();
doc = reader.read(in);
Element root = doc.getRootElement();
//根据消息类型执行不同的方法
checkMsgType(out, root,response);
} catch (Exception e) {
log.debug(e.getMessage());
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
log.debug(e.getMessage());
}
}
if (out != null) {
out.flush();
out.close();
}
}
}
}
/**
* 检测是否为微信发送的请求
*
* @param signature
* @param timestamp
* @param nonce
* @return
*/
private boolean check(String signature, String timestamp, String nonce) {
List strList = new ArrayList(); //这里的token 就是网站填的值, 建议用配置文件读取,根据环境不同读取不同的数据。
strList.add(serviceConfig.getToken());
strList.add(timestamp);
strList.add(nonce);
Collections.sort(strList);
String str = "";
for (String s : strList) {
str += s;
}
String strSha = DigestUtils.shaHex(str);
return strSha.equals(signature);
}
}
微信向公众号发送一个地理位置,然后公众号读取坐标 ,查询这个坐标附近的数据。
当用户向公众号发送请求, 微信服务器再向公众号发送的是XML的数据, 所以不了解解析XML,封装XML的童鞋可以先去补一下这方面的知识。
后台代码
//把抽象的东西抽取成java对象
/**
* User: zhanglin
* Date: 13-10-23
* Time: 下午4:26
*/
public enum MsgType {
text("文本"),image("图片"),location("地理位置"),link("连接"),event("事件"),news("图文信息") ;
private String value;
public String getValue() {
return value;
}
private MsgType(String value) {
this.value = value;
}
}
封装图文消息类,在这里笔者是用xml提供的标签来创建xml
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* User: zhanglin
* Date: 13-10-24
* Time: 下午1:37
* desc: 图片文消息
*/
@XmlRootElement(name="item")
public class Item {
private String title;
private String description;
private String picUrl;
private String url;
public Item() {
}
public Item(String title, String description, String picUrl, String url) {
this.title = title;
this.description = description;
this.picUrl = picUrl;
this.url = url;
}
@XmlElement(name = "Title")
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@XmlElement(name = "Description")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@XmlElement(name = "PicUrl")
public String getPicUrl() {
return picUrl;
}
public void setPicUrl(String picUrl) {
this.picUrl = picUrl;
}
@XmlElement(name = "Url")
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
//查询坐标附近的数据
/**
* 根据不同的类型执行不同的方法
*
* @param out 输出流
* @param root 从请求中获得的有关xml对象
*/
private void checkMsgType(PrintWriter out, Element root) {
try {
String value = root.element("MsgType").getTextTrim();
//查询坐标附近的数据
if (MsgType.location.toString().equals(value)) {
findNearCommunity(out, root);
}
//做其他的逻辑
} catch (Exception e) {
log.debug(e.getMessage());
}
}
/**
*
* @param out
* @param root
*/
private void findNearCommunity(PrintWriter out, Element root) throws Exception {
NearCoordinate nearCoordinate = param(root);
Integer count ="..." ;//调用接口查询条数
List
/**
* 图文信息xml
* @param list 结果集
* @param root
* @param count 总条数
* @return
*/
public static String getImgNewsXml(List list,Element root,Integer count) {
try { //接收方帐号(收到的OpenID)
String toUserName = root.element("ToUserName").getTextTrim(); // 开发者微信号
String fromUserName = root.element("FromUserName").getTextTrim();
Marshaller m = getMarshaller(new WeiXinImg());
ArrayList- items = new ArrayList
- ();
Articles articles = new Articles();
Item item ;
int next=0;
for (CommunityDto communityDto:list){
//封装 Item对象
items.add(item);
next++;
}
//总条数大于列表条数
if(WeiXinConfig.COMMUNITY_LIST_SIZE
count ,articles);
StringWriter fw = new StringWriter();
m.marshal(weiXinImg, fw);
return fw.toString();
}catch (Exception e){
log.debug(e.getMessage());
}
return null;
}
//创建一个< tt >Marshaller< / tt >对象,可以用来转换成一个Java内容树转换成XML数据。
private static Marshaller getMarshaller(Object o)throws Exception{
JAXBContext context = JAXBContext.newInstance(o.getClass());
// 下面代码演示将对象转变为xml
Marshaller m = context.createMarshaller();
//是否格式化生成的xml串
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, false);
//是否省略xml头信息
m.setProperty(Marshaller.JAXB_FRAGMENT, true);
return m;
}
/**
* 图文信息xml
* @param list 结果集
* @param root
* @param count 总条数
* @return
*/
public static String getImgNewsXml(List list,Element root,Integer count) {
try {
String toUserName = root.element("ToUserName").getTextTrim();
String fromUserName = root.element("FromUserName").getTextTrim();
Marshaller m = getMarshaller(new WeiXinImg());
ArrayList- items = new ArrayList
- ();
Articles articles = new Articles();
Item item ;
int next=0;
for (CommunityDto communityDto:list){
//组装Item对象
items.add(item);
next++;
}
//总条数大于列表条数
if(WeiXinConfig.COMMUNITY_LIST_SIZE