频道栏目
首页 > 资讯 > 微信公众平台开发 > 正文

大齐玩转微信公众账号系列(七): 微信公众账号开发:消息设计、源码

14-08-10        来源:[db:作者]  
收藏   我要投稿

 此系列博文目录:

如何申请微信公众帐号

微信公众账号消息那些事儿

服务号实现自定义菜单

微信公众账号开发入门(原理)

微信公众账号开发:URL 和 Tocken

微信公众账号开发:消息原理

微信公众账号开发:消息设计、源码

微信公众账号开发:菜单原理、设计、源码

微信公众账号开发:JS接口

微信公众账号开发:Auth2.0认证原理、设计、源码

 

上篇博文主要介绍了微信公众账号消息的原理,如果你已经详细阅读了上篇博文,我想对于公众账号开发者的消息设计,你心中已经有个大概了;

所以不啰嗦了,直奔主题吧,我用的开发语言是python(是我使用众多语言中最棒的,没有之一),下面是逻辑流程图以及源码(源码只贴主要的部分);

 

消息设计流程图

这个流程图是很简单的了,微信公众账号的消息本身就不复杂,说的简单点就是:输入、处理、输出;

 

源码

 

 

@csrf_exempt
def wx_valid(request):#提供给微信公众平台的url,微信公众平台请求url时,会执行此方法

    '''微信开发者验证,是GET请求;GET 和 POST 区分是认证还是发送消息(发送消息的时候是POST)'''
    if request.method == 'GET':
        tocken='zainanjing6tocken'#提供给微信公众平台的tocken,可以保持在数据库、文件或者直接硬编码到代码中;
        if tocken:
            timestamp = request.GET['timestamp']
            nonce = request.GET['nonce']
            signature = request.GET['signature']
            echostr = request.GET['echostr']
            
            arr = [tocken,timestamp,nonce]
            arr.sort()
            data = ''
            for s in arr :
                data += s
            sha1 = hashlib.sha1() #或hashlib.md5()  
            sha1.update(data)
            _signature = sha1.hexdigest() #生成40位(sha1)或32位(md5)的十六进制字符串  
            if _signature == signature :
                return HttpResponse(echostr)#返回 echostr
        return HttpResponse('error')#返回 error
    else:#POST请求,也就是微信公众平台转发用户消息给开发者服务器
        '''
    如果是POST 请求,那么表示的是用户发送消息,或者点击菜单发送事件消息;
    通过同一个URL进行处理;只是请求的方法不一样,
    '''
        xml = request.POST.keys()[0]#post的数据,其他语言取法可能有不同,django是这么取的,也可能有其他方法?有朋友知道的可以分享下
        if xml:
            q_obj = get_request_obj(xml.encode('UTF-8'))#获取请求对象dict
            rep_xml = get_response_obj(q_obj)#根据account分发处理业务
            if rep_xml:
                return HttpResponse(rep_xml)  
        return HttpResponse('error')
    

'''
转换请求的xml数据成 req_obj (dict类型)
XmlUtil类,没有贴出源代码,很简单,就是解析xml对象
'''
def get_request_obj(xml):
    q_obj = {}
    root = XmlUtil.getRootNode(xml)
    msgType = XmlUtil.getSingleNodeValue(root,'MsgType')
    
    if msgType == MsgType.TEXT:
        q_obj['Content'] = XmlUtil.getSingleNodeValue(root,'Content')
    elif msgType == MsgType.IMAGE:
        q_obj['PicUrl'] = XmlUtil.getSingleNodeValue(root,'PicUrl')
    elif msgType == MsgType.LOCATION:
        q_obj['Location_X'] = XmlUtil.getSingleNodeValue(root,'Location_X')
        q_obj['Location_Y'] = XmlUtil.getSingleNodeValue(root,'Location_Y')
        q_obj['Scale'] = XmlUtil.getSingleNodeValue(root,'Scale')
        q_obj['Label'] = XmlUtil.getSingleNodeValue(root,'Label')
    else:
        q_obj['Event'] = XmlUtil.getSingleNodeValue(root,'Event')
        q_obj['EventKey'] = XmlUtil.getSingleNodeValue(root,'EventKey')
    
    q_obj['ToUserName'] = XmlUtil.getSingleNodeValue(root,'ToUserName')
    q_obj['FromUserName'] = XmlUtil.getSingleNodeValue(root,'FromUserName')
    q_obj['CreateTime'] = XmlUtil.getSingleNodeValue(root,'CreateTime')
    q_obj['MsgType'] = XmlUtil.getSingleNodeValue(root,'MsgType')
    q_obj['MsgId'] = XmlUtil.getSingleNodeValue(root,'MsgId')
    
    return q_obj

'''
转换rep_obj 成发送的xml的形式
'''
def get_response_obj(q_obj):
    msg_type = q_obj['MsgType']
    p_obj = None
    '''
    根据自己的业务处理,获取对象   msg_obj ,
  封装的 msg_obj 
  如果是文本消息,需要有  content,createTime 等;
 如果是图文消息,我们使用的是list,如果size=1,单图文消息;如果size>1 ,多图文消息 
 其他类型,不多做解释,和文本类似
    '''
    if msg_obj:
        if msg_obj['MsgType'] == 'text':#文本消息
            return get_response_text(q_obj,p_obj)
        elif msg_obj['MsgType'] == 'news':#图文消息
            return get_response_news(q_obj,p_obj)
    return None


'''
获取response_text
''' 
def get_response_text(q_obj,text):
    rep_xml = u'''<xml>
    <ToUserName><![CDATA[%s]]></ToUserName>
    <FromUserName><![CDATA[%s]]></FromUserName>
    <CreateTime>%s</CreateTime>
    <MsgType><![CDATA[text]]></MsgType>
    <Content><![CDATA[%s]]></Content>
    </xml>''' %(q_obj['FromUserName'],q_obj['ToUserName'],TimeUtil.getIntTime(),text.content)
    return rep_xml.encode('UTF-8')


'''
回复新闻消息
'''
def get_response_news(q_obj,news_list):
    rep_xml = u'''<xml>
    <ToUserName><![CDATA[%s]]></ToUserName>
    <FromUserName><![CDATA[%s]]></FromUserName>
    <CreateTime>%s</CreateTime>
    <MsgType><![CDATA[news]]></MsgType>
    <ArticleCount>%d</ArticleCount>
    <Articles>''' %(q_obj['FromUserName'],q_obj['ToUserName'],TimeUtil.getIntTime(),len(news_list))

    for new in news_list:
        rep_xml += u'''<item>
        <Title><![CDATA[%s]]></Title>
        <Description><![CDATA[%s]]></Description>
        <PicUrl><![CDATA[%s]]></PicUrl>
        <Url><![CDATA[%s]]></Url>
        </item>''' %(new.title,new.brief,new.picUrl,new.url)#这里使用简介

    rep_xml += '</Articles></xml>' 
    return rep_xml.encode('UTF-8')



 

代码中:

@csrf_exempt
def wx_valid(request):

和URL 、Tocken 设计那篇博文中用的是同一个方法,也就是提供给微信公众平台服务器的URL 对应的方法,只是请求的方式不一样,URL验证的时候是 GET 方法,发送消息的时候是POST 方法;详细情况请看代码注释;

 

这篇博文就到此结束了,文字不多,对应开发人员来说,有图、有源码就足矣...

我们下篇就说说菜单设计了...

相关TAG标签
上一篇:大齐玩转微信公众账号系列(八):微信公众账号开发:菜单原理、设计、源码
下一篇:大齐玩转微信公众账号系列(六): 微信公众账号开发 :消息原理
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站