黔优媒体网-软文媒体自助发稿平台!
  1. 行业资讯
  2. 正文

微信公众平台开发系列

来源:黔优媒体网   时间:2024-09-19

开始微信公众平台的开发,我们首先要了解微信平台可以帮助我们做哪些事情?

使用您的公众账号登陆http://mp.weixin.qq.com/,选择菜单--高级功能-开发模式--查看文档,即能看到微信公众平台目前所能开发的功能。

一、通讯机制

公众平台的主要内容是

接受用户发送给您公众账号的消息

给您的用户回复消息

需要特别说明的是,发送消息和回复消失是一个连贯的过程,只能在一个对话中完成。也就是说您的用户不找您说话,您是不能主动发送消息给你的客户(群发是另外一种情况,有次数限制。你也可以申请付费使用微信CRM平台)。所有的发送消息和接受消息,都需要微信平台进行中转。

二、消息类型

下面介绍用户能给您发送的消息类型,也就是目前接受到的消息类型。

1.接受消息类型

1.1文本消息:

这也是我们平时碰到最多的,可以根据文本中提到的一些关键字,进行判断,判断用户的含义,并进行回复。

1.2图片消息:

目前通过图片理解用户想表达的意思,还是有较大难度,因此多数的公众账号,会选择忽略图片信息或选择由人工来处理。只能说一句:图片很美,但是我看不懂。

1.3地理位置消息:

用户把他的位置发给您,这对大多数公众账号来说,是一个重要的信息。可以提供一些基于位置信息的服务,比如酒店预订公众账号,可以给你推荐你周边的酒店。 另外一个补充是,可以在文本消息中分析出位置信息,并加以利用。比如用户输入“南京路步行街”,可以提供用户南京路步行街的相关商户。

1.4链接消息:

目前还没有看到开发模式中特别有效的使用方法。使用比较多的可能会是购物时或是咨询时,对所谈论的对象进行明确。

1.5事件推送消息:

当用户进入到和你对话的过程中,可以先和用户打招呼等。这个消息目前只支持4.5版本,且暂时还没有开发。后续可想想的空间很大,比如用户进入到会话之后,摇一摇会发生什么呢?

2.回复消息类型

  2.1文本消息
   这是我们平时发送最多的一类消息,当只需要简单的文字即可回答用户的消息时,可用文本消息。文本消息中可以带有链接地址。

 2.2图文消息
    图文消息,这是我们在推送消息中经常看到的消息格式。每项内容可以点击查看更详细信息(当然你也可以把链接设置为空,使其不能跳转)

   2.3音乐消息
   在你的答复中给用户一个语音消息或是音乐,可以获得不少用户的亲睐。
了解了公众平台的通讯机制和消息类型,接下来,我们开始准备开发环境了

1.设置成为开发者模式

登录微信工作平台,选择高级功能-进入开发模式,成为开发者。需要做如下图配置。URL配置的信息是指,微信的后台服务器把您的用户消息发送到该URL处理。Token是你和微信之间的一个密码,用来验证消息是否是从微信的服务发送而来,而不是其他来攻击你的系统。

现在你还不能设置,在设置时微信会GET请求你设置的URL,已检测接口是否可以使用。只有等你准备好GET方法之后才可以进行设置。

2.实现GET方法

从文档中知道,我们需要实现POST和GET方法,GET方法用于验证微信和你的通讯验证,POST用于消息处理。

新建Servlet HelloWeChat,先实现其中的GET方法

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
 // TODO 为了简单起见,先不对消息来源进行校验
 response.setContentType( text/html;charset=UTF-8 
 PrintWriter pw = response.getWriter(); 
 String echo = request.getParameter( echostr 
 echo = new String(echo.getBytes( ISO-8859-1 ), UTF-8 
 pw.println(echo); 
 }

可以在本地使用http://localhost:8080/QiyadengWeb/HelloWeChat?echostr=hello中文,先进行测试,如果没有问题,可以部署到服务器上,然后在微信公众平台进行设置了。

3.实现POST方法

POST方法首先接收到微信公众平台传送过来的XML,从中提取消息发送人和消息内容。更加消息发送内容,你可以增加自己的处理逻辑,最后拼装成回复消息XML,返回给微信公众平台。

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
 response.setContentType( text/html;charset=UTF-8 
 PrintWriter pw = response.getWriter(); 
 String wxMsgXml = IOUtils.toString(request.getInputStream(), utf-8 
 WeChatTextMessage textMsg = null; 
 try { 
 textMsg = getWeChatTextMessage(wxMsgXml); 
 } catch (Exception e) { 
 e.printStackTrace(); 
 StringBuffer replyMsg = new StringBuffer(); 
 if(textMsg != null){ 
 //增加你所需要的处理逻辑,这里只是简单重复消息
 replyMsg.append( 您给我的消息是: 
 replyMsg.append(textMsg.getContent()); 
 else{ 
 replyMsg.append( :)不是文本的消息,我暂时看不懂 
 String returnXml = getReplyTextMessage(replyMsg.toString(), textMsg.getFromUserName()); 
 pw.println(returnXml); 
 }

关于调试,这里推荐一个工具Fiddler,你可以模拟微信的POST消息到你的本地,而不必每次部署到服务器上进行调试。关于Fiddler的POST数据使用方法,可以参考下图标注内容。

4.部署并测试

完成第一步,并和你的公众帐号好进行对话,回复消息没有问题的话,那就恭喜你了。

5.依赖库

使用maven的同学,添加以下依赖即可。非maven用户,找到这些库添加到buider path中即可。

 dependency 
 groupId joda-time /groupId 
 artifactId joda-time /artifactId 
 version 2.2 /version 
 /dependency 
 dependency 
 groupId org.apache.commons /groupId 
 artifactId commons-io /artifactId 
 version 1.3.2 /version 
 /dependency 
 dependency 
 groupId com.thoughtworks.xstream /groupId 
 artifactId xstream /artifactId 
 version 1.4.3 /version 
 /dependency 

6.完整的代码

package com.qiyadeng.wechat; 
import java.io.IOException; 
import java.io.PrintWriter; 
import java.util.Date; 
import javax.servlet.ServletException; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import org.apache.commons.io.IOUtils; 
import com.thoughtworks.xstream.XStream; 
import com.thoughtworks.xstream.io.xml.DomDriver; 
 * Servlet implementation class HelloWeChat
public class HelloWeChat extends HttpServlet { 
 private static final long serialVersionUID = 1L; 
 * @see HttpServlet#HttpServlet()
 public HelloWeChat() { 
 super(); 
 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
 // TODO 为了简单起见,先不对消息来源进行校验
 response.setContentType( text/html;charset=UTF-8 
 PrintWriter pw = response.getWriter(); 
 String echo = request.getParameter( echostr 
 echo = new String(echo.getBytes( ISO-8859-1 ), UTF-8 
 pw.println(echo); 
 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
 response.setContentType( text/html;charset=UTF-8 
 PrintWriter pw = response.getWriter(); 
 String wxMsgXml = IOUtils.toString(request.getInputStream(), utf-8 
 WeChatTextMessage textMsg = null; 
 try { 
 textMsg = getWeChatTextMessage(wxMsgXml); 
 } catch (Exception e) { 
 e.printStackTrace(); 
 StringBuffer replyMsg = new StringBuffer(); 
 if(textMsg != null){ 
 //增加你所需要的处理逻辑,这里只是简单重复消息
 replyMsg.append( 您给我的消息是: 
 replyMsg.append(textMsg.getContent()); 
 else{ 
 replyMsg.append( :)不是文本的消息,我暂时看不懂 
 String returnXml = getReplyTextMessage(replyMsg.toString(), textMsg.getFromUserName()); 
 pw.println(returnXml); 
 private WeChatTextMessage getWeChatTextMessage(String xml){ 
 XStream xstream = new XStream(new DomDriver()); 
 xstream.alias("xml", WeChatTextMessage.class); 
 xstream.aliasField("ToUserName", WeChatTextMessage.class, "toUserName"); 
 xstream.aliasField("FromUserName", WeChatTextMessage.class, "fromUserName"); 
 xstream.aliasField("CreateTime", WeChatTextMessage.class, "createTime"); 
 xstream.aliasField("MsgType", WeChatTextMessage.class, "messageType"); 
 xstream.aliasField("Content", WeChatTextMessage.class, "content"); 
 xstream.aliasField("MsgId", WeChatTextMessage.class, "msgId"); 
 WeChatTextMessage wechatTextMessage = (WeChatTextMessage)xstream.fromXML(xml); 
 return wechatTextMessage; 
 private String getReplyTextMessage(String content, String weChatUser){ 
 WeChatReplyTextMessage we = new WeChatReplyTextMessage(); 
 we.setMessageType("text"); 
 we.setFuncFlag("0"); 
 we.setCreateTime(new Long(new Date().getTime()).toString()); 
 we.setContent(content); 
 we.setToUserName(weChatUser); 
 we.setFromUserName("shanghaiweather");//TODO 你的公众帐号微信号
 XStream xstream = new XStream(new DomDriver()); 
 xstream.alias("xml", WeChatReplyTextMessage.class); 
 xstream.aliasField("ToUserName", WeChatReplyTextMessage.class, "toUserName"); 
 xstream.aliasField("FromUserName", WeChatReplyTextMessage.class, "fromUserName"); 
 xstream.aliasField("CreateTime", WeChatReplyTextMessage.class, "createTime"); 
 xstream.aliasField("MsgType", WeChatReplyTextMessage.class, "messageType"); 
 xstream.aliasField("Content", WeChatReplyTextMessage.class, "content"); 
 xstream.aliasField("FuncFlag", WeChatReplyTextMessage.class, "funcFlag"); 
 String xml =xstream.toXML(we); 
 return xml; 
}

位置识别这是实际应用经常应用的消息,特别是很多商家,通过了解用户位置,给用户提供特别的产品或是商场的推荐。其中用户可能发送两种类型的消息:

1.微信地理位置信息

2.路名、标志性建筑或是商场名称

1.微信地理位置消息

认识一下,微信地理位置消息,包含一些什么信息

 xml 
 ToUserName ![CDATA[toUser]] /ToUserName 
 FromUserName ![CDATA[fromUser]] /FromUserName 
 CreateTime 1351776360 /CreateTime 
 MsgType ![CDATA[location]] /MsgType 
 Location_X 23.134521 /Location_X 
 Location_Y 113.358803 /Location_Y 
 Scale 20 /Scale 
 Label ![CDATA[位置信息]] /Label 
 MsgId 1234567890123456 /MsgId 
 /xml 

包含的主要信息有经度纬度和Label的位置。可以根据label中描述的位置信息,提供给用户对应的服务。也可根据用户的经度纬度信息,提供你最近的产品或是有地域性的产品。

首先根据微信的地理位置信息,定义WeChatLocationMessage类,并能把Xml转换为WeChatLocationMessage对象

public class WeChatLocationMessage { 
 private String toUserName; 
 private String fromUserName; 
 private String createTime; 
 private String msgType; 
 private String locationx; 
 private String localtiony; 
 private String scale; 
 private String label; 
 private String msgId; 
 public static WeChatLocationMessage getWeChatLocationMessage(String xml){ 
 XStream xstream = new XStream(new DomDriver()); 
 WeChatLocationMessage message = null; 
 xstream.alias( xml , WeChatLocationMessage.class); 
 xstream.aliasField( ToUserName , WeChatLocationMessage.class, toUserName 
 xstream.aliasField( FromUserName , WeChatLocationMessage.class, fromUserName 
 xstream.aliasField( CreateTime , WeChatLocationMessage.class, createTime 
 xstream.aliasField( MsgType , WeChatLocationMessage.class, msgType 
 xstream.aliasField( Location_X , WeChatLocationMessage.class, locationx 
 xstream.aliasField( Location_Y , WeChatLocationMessage.class, localtiony 
 xstream.aliasField( Scale , WeChatLocationMessage.class, scale 
 xstream.aliasField( Label , WeChatLocationMessage.class, label 
 xstream.aliasField( MsgId , WeChatLocationMessage.class, msgId 
 message = (WeChatLocationMessage)xstream.fromXML(xml); 
 return message; 
//getter and setter
}

本文利用百度的地图API,查找最近的银行做为示例。

public String getPalace(String query,String lat,String lng) throws ClientProtocolException, IOException{ 
 HttpClient httpClient = new DefaultHttpClient(); 
 String url = palceRequestUrl(query,lat,lng); 
 logger.log(Level.INFO, url); 
 HttpGet httpget = new HttpGet(url); 
 ResponseHandler String responseHandler = new BasicResponseHandler(); 
 String responseBody = httpClient.execute(httpget, responseHandler); 
 logger.log(Level.INFO, baidu response: +responseBody); 
 return responseBody; 
public String palceRequestUrl(String query,String lat,String lng) throws UnsupportedEncodingException { 
 String url = WeChatConstant.BASEURL + place/search?query= + URLEncoder.encode(query, UTF-8 ) + key= 
 + WeChatConstant.MAPKEY + location= +lat+ , +lng + radius=2000 + output= + WeChatConstant.OUTPUTFORMAT; 
 return url; 
}

输出的结果

 PlaceSearchResponse 
 status OK /status 
 results 
 result 
 name 中国工商银行东长安街支行 /name 
 location 
 lat 39.915891 /lat 
 lng 116.41867 /lng 
 /location 
 address 东城区东长安街1号东方广场西三办公楼1楼 /address 
 uid a025683c73033c35a21de987 /uid 
 detail_url http://api.map.baidu.com/place/detail?uid=a025683c73033c35a21de987 amp;output=html amp;source=placeapi
 /detail_url 
 tag 银行,王府井/东单 /tag 
 /result 
 /results 
 /PlaceSearchResponse 

接下来,把百度地图反映出来的最近位置信息,以图文消息的格式展示给微信用户

 public static String getWeChatReplyNewsMessageByBaiduPlace(List BaiduPlaceResponse placeList, double lat, double lng,String userName, int size){ 
 WeChatReplyNewsMessage newsMessage = new WeChatReplyNewsMessage(); 
 List Item items = new ArrayList Item 
 StringBuffer strBuf = new StringBuffer(); 
 logger.log(Level.INFO, placeList count= +placeList.size()); 
 newsMessage.setItems(items); 
 if(placeList.size() size){ 
 newsMessage.setArticleCount(size); 
 else{ 
 newsMessage.setArticleCount(placeList.size()); 
 logger.log(Level.INFO, article count= +newsMessage.getArticleCount()); 
 newsMessage.setCreateTime(new Date().getTime()+ 
 newsMessage.setMsgType( news 
 newsMessage.setFuncFlag( 0 
 newsMessage.setToUserName(userName); 
 newsMessage.setFromUserName(WeChatConstant.FROMUSERNAME); 
 for(int i = 0;i newsMessage.getArticleCount();i++){ 
 BaiduPlaceResponse place = placeList.get(i); 
 Double distance = GeoUtil.DistanceOfTwoPoints(Double.valueOf(place.getLng()), Double.valueOf(place.getLat()), lng, lat, GaussSphere.Beijing54); 
 Item item = new Item(); 
 item.setTitle(place.getName()+ [ +distance+ 米] + \n +place.getAddress()+ \n +place.getTelephone()); 
 item.setPicUrl( 
 item.setUrl(place.getDetailUrl()); 
 item.setDescription( 
 items.add(item); 
logger.log(Level.INFO, newMessage= +newsMessage.toString()); 
 strBuf = strBuf.append(getWeChatNewsMessage(newsMessage)); 
 return strBuf.toString(); 
 public static String getWeChatNewsMessage(WeChatReplyNewsMessage newsMessage){ 
 XStream xstream = new XStream(new DomDriver()); 
 xstream.alias( xml , WeChatReplyNewsMessage.class); 
 xstream.aliasField( ToUserName , WeChatReplyNewsMessage.class, toUserName 
 xstream.aliasField( FromUserName , WeChatReplyNewsMessage.class, fromUserName 
 xstream.aliasField( CreateTime , WeChatReplyNewsMessage.class, createTime 
 xstream.aliasField( MsgType , WeChatReplyNewsMessage.class, msgType 
 xstream.aliasField( ArticleCount , WeChatReplyNewsMessage.class, articleCount 
 xstream.aliasField( Content , WeChatReplyNewsMessage.class, content 
 xstream.aliasField( FuncFlag , WeChatReplyNewsMessage.class, funcFlag 
 xstream.aliasField( Articles , WeChatReplyNewsMessage.class, items 
 xstream.alias( item , Item.class); 
 xstream.aliasField( Title , Item.class, title 
 xstream.aliasField( Description , Item.class, description 
 xstream.aliasField( PicUrl , Item.class, picUrl 
 xstream.aliasField( Url , Item.class, url 
 return xstream.toXML(newsMessage); 
 }
2.路名、标志性建筑或是商场名称

对路名、标志性建筑等信息,方法还是通过第三方地图信息,确定输入的位置信息的经度纬度。

本文使用百度地图API,确定所查找的位置的经度和纬度。

确定了经度和纬度,问题就变成和第1种消息类型一致了,根据经度纬度去做相应处理。

public String getGeoCode(String query) throws ClientProtocolException, IOException{ 
 HttpClient httpClient = new DefaultHttpClient(); 
 String url = geoCodeRequestUrl(query); 
 logger.log(Level.INFO, url); 
 HttpGet httpget = new HttpGet(url); 
 ResponseHandler String responseHandler = new BasicResponseHandler(); 
 String responseBody = httpClient.execute(httpget, responseHandler); 
 logger.log(Level.INFO, baidu response: +responseBody); 
 return responseBody; 
 public String geoCodeRequestUrl(String query) throws UnsupportedEncodingException{ 
 String url = WeChatConstant.BASEURL + geocoder?address= + URLEncoder.encode(query, UTF-8 ) + key= 
 + WeChatConstant.MAPKEY + output= + WeChatConstant.OUTPUTFORMAT; 
 return url; 
 }

更多微信公众平台开发系列 相关文章请关注PHP中文网!

微信app下载

微信是一款手机通信软件,支持通过手机网络发送语音短信、视频、图片和文字。微信可以单聊及群聊,还能根据地理位置找到附近的人,带给大家全新的移动沟通体验,有需要的小伙伴快来保存下载体验吧!


【免责申明】黔优媒体网以上展示内容来源于用户自主上传、合作媒体、企业机构或网络收集整理,版权争议与本站无关,文章涉及见解与观点不代表黔优媒体网官方立场,请读者仅做参考,本文标题:微信公众平台开发系列;欢迎转载,转载时请说明出处。若您认为本文侵犯了您的版权信息,或您发现该内容有任何违法/违规的内容,请您立即联系我们及时修正或删除。(邮箱号: kefu@qianu.com)