微信开发工具输入特殊符号_微信小程序 微信昵称特殊符号处理 - CSDN
  • 用户输入信息,获取输入信息上传服务器存储,就是这么简单哈~~~~然而~~~ 然而~~~理想是美好的,现实却是残酷的!!! 一旦碰到特殊字符串这个强大的对手,我便在这条实现理想的道路上不能淡定如初了~~~ 好了,讲...

    用户输入信息,获取输入信息上传服务器存储,就是这么简单哈~~~~然而~~~

    然而~~~理想是美好的,现实却是残酷的!!!

     一旦碰到特殊字符串这个强大的对手,我便在这条实现理想的道路上不能淡定如初了~~~

    好了,讲重点我们要如何解决呢??

    cleanSpelChar:function (localData){    
          var noiseChar="~!@#$%^&*()_+-=`[]{};':\"\\|,./<>?\n\r";
          var goodChar ="~!@#$%^&*()_+-=`[]{};':"\|,./<>?  ";
          for(var i=0;i<noiseChar.length;i++){ 
            var oneChar = noiseChar.charAt(i);
            var towChar=goodChar.charAt(i)
            console.log('oneChar  '+oneChar + '   towChar '+towChar)
            while(localData.indexOf(oneChar) >= 0){ 
              localData=localData.replace(oneChar,towChar) 
           } 
          } 
           return localData;
    
    }

    好吧 ,解决方法就是这么简单,而我在找错以及解决路上走了挺久哭
        

    展开全文
  • 微信公众号开发技术要点 微信公众号开发技术要点 微信公众号及其接口功能介绍 基本概念 公众号开发者模式 代码验证及图示 Open ID与Union ID 基本概念 使用说明 Access_token 基本介绍 注意事项 获取流程 ...

    微信公众号开发技术要点

    前言

    本文将介绍微信公众号开发中涉及的一些技术概念,以便读者可以快速掌握公众号开发过程中的基本操作和流程。文档不涉及具体开发技术和流程的介绍,该文档作用相当于官方文档中关键点的详细注解。

    在公众号开发流程中,涉及到三种系统:

    1. 微信方面的系统,负责监听用户的操作并将相关消息和事件推送到响应系统,下称微信系统;
    2. 接收微信系统所推送的事件和消息的系统,下称响应系统;
    3. 业务逻辑系统,实现业务逻辑处理,下称业务系统。

    响应系统和业务系统需要自己开发;其中业务系统中的页面即为下文中提到的第三方页面;

    微信公众号及其接口功能介绍

    基本概念

    公众号是为微信用户提供资讯和服务的平台;公众平台开发接口则是通过后台业务系统向用户提供服务的基础;

    不同的公众号类型有不同数量的接口权限,服务号要多于订阅号;

    公众号开发者模式

    开启公众号开发模式后,微信系统将以事件推送的形式告知响应系统用户在公众号里的相关行为,包括:关注/取关事件、二维码扫描事件、自定义菜单事件、跳转链接事件时的事件、点击菜单拉取消息时的事件,从而开发者可以获取到该消息并做出响应;

    1. 开启公众号开发者模式
    2. 填写服务器配置
    3. 验证服务器地址的有效性

    这些步骤都是在微信官方公众号后台里开发->基本配置里完成的

    代码验证及图示

    配置图示:

    这里写图片描述

    服务器代码:

    public class WeChatServer extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req,resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
            PrintWriter writer=resp.getWriter();
            System.out.println(req.getParameter("echostr"));
            writer.println(req.getParameter("echostr"));
        }
    }
    //微信系统对响应系统地址的有效性验证是通过返回值(echostr)完成的,这里没有添加对微信系统身份的检查,直接输出
    

    完整代码见WeChatWebSystem

    Open ID与Union ID

    基本概念

    为识别用户,微信为每一个用户提供了针对特定公众号平台的Open ID;同一个用户在不同公众号里的有不同的Open ID;同一个公众号里不同用户有不同的Open ID;获取用户的Open ID是无需用户同意的,但是获取用户的基本信息(所在地址、昵称等)是需要用户同意的;

    为了实现在多个公众平台、移动应用之间做到用户统一管理,提供了Union ID机制。同一用户在同一开放平台账号下的所有公众号和应用里Union ID是相同的;

    使用说明

    1. Open ID的获取和使用

      获取

      1. Open ID会在微信系统向响应系统推送普通消息以及事件推送时附带于消息体内;
      2. 从公众号进入第三方页面时,业务系统需要获得该用户的Open ID;

      使用:

      1. 发送被动消息时(包括对事件的响应和消息的响应),使用Open ID来标记发送对象;
      2. 发送主动消息时(模板消息),使用Open ID来标记发送对象;
    2. Union ID的获取和使用

      从公众号进入第三方页面时,业务系统可以选择获取Union ID来实现业务逻辑,其具体流程为:

      准备阶段:

      1. 获得微信网页授权:微信公众号后台->开发->接口权限;
      2. 设置授权回调域名:一旦设置成功,该域名下的所有页面均可以进行OAuth2.0鉴权;
      3. 以snsapi_userInfo为scope发起授权以获得该用户的基本信息;

      获取阶段:

      1. 引导用户进入授权页面,用户同意后,获得code;

        https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
        
        其中APPID/REDIRECT_URI/SCOPE/STATE为变量,参数顺序不可改变;跳转回调的redirect_uri,应当使用https链接来确保授权code的安全性。以上链接需要自微信客户端里打开,如果用户同意授权,则页面跳转到:redirect_uri/?code=CODE&state=STATE
        
        参数	是否必须	说明
        appid	是	公众号的唯一标识
        redirect_uri	是	授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理
        response_type	是	返回类型,请填写code
        scope	是	应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 )
        state	否	重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
        #wechat_redirect	是	无论直接打开还是做页面302重定向时候,必须带此参数
        
      2. 使用code换取网页授权access_token(用于获取用户基本信息的token,不是微信基础服务里的access_token,在这一步里,获取access_token的同时也会获得用户的open ID);

        获取code后,请求以下链接获取access_token:  https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
        
        其中APPID/SECRET/CODE为变量
        
        正确返回的JSON数据如下:
        { "access_token":"ACCESS_TOKEN",
        "expires_in":7200,
        "refresh_token":"REFRESH_TOKEN",
        "openid":"OPENID",
        "scope":"SCOPE" }
        
      3. 如有必要,开发者刷新该access_token,避免过期;

        获取第二步的refresh_token后,请求以下链接获取access_token:
        https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
        
        access_token拥有较短的有效期,refresh_token则有30天的有效期;
        
        返回结果同上
        { "access_token":"ACCESS_TOKEN",
        "expires_in":7200,
        "refresh_token":"REFRESH_TOKEN",
        "openid":"OPENID",
        "scope":"SCOPE" }
        
      4. 通过access_token和openID获得用户基本信息;

         https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
         
         access_token为网页授权时使用的access_token,不是调用微信接口时使用的access_token;
         返回数据:
         {    "openid":" OPENID",
        " nickname": NICKNAME,
        "sex":"1",
        "province":"PROVINCE"
        "city":"CITY",
        "country":"COUNTRY",
        "headimgurl":    "http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
        "privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
        "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
        }
        
        

      从响应系统内获得Union ID是通过其他接口实现的:

       请求方式: GET
       请求地址:https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
       参数说明:access_token即为接口访问令牌,openid即为消息的发送者
    
    1. 注意事项

      使用snaapi_base为scope的网页授权对用户是静默的,用户感觉直接进入了公众号网页;

      对于已关注公众号的用户,如果用户从公众号会话或者自定义菜单进入网页授权页,即使scope为snaapi_userInfo,也是静默的;

    Access_token

    基本介绍

    access_token是公众号内全局唯一接口调用凭据;其有效期为2小时,需要定时刷新,重新获取将导致上次access_token失效;

    注意事项

    1. 建议公众号使用统一的中控服务器来获取和刷新access_token;
    2. access_token的有效期通过expire_in标志;在刷新过程中中控服务器可以继续对外输出旧的access_token,刷新完毕5分钟内新旧access_token都有效;
    3. 中控服务器应当提供被动刷新access_token的机制;
    4. 公众号和小程序均可以使用AppID和AppSecret调用本接口来获取access_token;

    获取流程

    https请求方式: GET
    https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
    
    正确返回结果
    {"access_token":"ACCESS_TOKEN","expires_in":7200}
    出粗返回结果
    {"errcode":40013,"errmsg":"invalid appid"}
    

    代码验证及图示

    下图为访问失败时的截图,因为本地开发中使用的IP地址不在公众号后台的IP访问白名单所致,正式部署后将不存在该问题:

    这里写图片描述

    下图为服务器端浏览器接口调试页面

    这里写图片描述

    自定义菜单

    开启服务模式后,将无法在微信公众号后台内实现对菜单的自定义,但是微信公众号后台内可以自定义的菜单点击类型十分有限(2/10),可以通过使用微信提供的菜单管理接口来对菜单进行管理。

    基本介绍

    1. 微信公众号内允许3个一级菜单,每个一级菜单允许5个二级子菜单;一级菜单最多4个汉字,二级菜单最多7个汉字;
    2. 菜单项共有10种类型:
      1. click:当用户点击该类子菜单时,微信系统将向响应系统推送类型为event的消息并附带该菜单项的key值,开发者可以据此对该事件做出响应;
      2. view:当用户点击该类子菜单时,微信客户端将打开开发者在该菜单项中设置的网页URL,在该URL内开发者可以配合网页授权接口获得用户的基本信息以开展业务服务;
      3. scancode_push:当用户点击此类型子菜单时,微信客户端将调起扫一扫工具,并将结果展示给用户,如果识别结果为URL,将进入该URL,同时响应系统将接收到该消息;
      4. scancode_waitmsg:当用户点击该类子菜单时,微信客户端将调起扫一扫工具,完成扫码操作后,将扫码的结果传给开发者,同时收起扫一扫工具,然后弹出“消息接收中”提示框,随后可能会收到开发者下发的消息。
      5. pic_sysphoto:当用户点击该类子菜单时,微信客户端将调起系统相机,完成拍照操作后,将拍摄的图片发送给响应系统,同时收起系统相机,等待开发者下发消息;
      6. pic_photo_or_album:基本功能同上,但是会给用户两种选择:拍照或者系统相册上传;
      7. pic_weixin:基本功能同上,但是会使用微信相册;
      8. location_select:弹出地理位置选择器,完成操作后,将选择地理信息发送给响应系统,收起地理位置选择器后,等待开发者下发消息;
      9. media_id:当用户点击该类子菜单项后,微信系统将对应永久素材id的素材下发给用户;
      10. view_limited:当用户点击该类型子菜单时,微信客户端将打开开发者在按钮中填写的永久素材id对应的图文消息URL;

    创建菜单

    接口说明:

     接口地址:https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
     访问方式:POST
     参数说明:
     ACCESS_TOKEN即为获取的access_token;
     POST的数据为JSON字符串,其中button定义了菜单,为一个JSON数组;数组中每一个元素都是一个一级菜单,其中sub_button属性为该一级菜单的二级菜单,同样也是JSON数组;每一个菜单项包含type(上面提到的10种)、name、key等信息。
     {
         "button":[
         {    
              "type":"click",
              "name":"今日歌曲",
              "key":"V1001_TODAY_MUSIC"
          },
          {
               "name":"菜单",
               "sub_button":[
               {    
                   "type":"view",
                   "name":"搜索",
                   "url":"http://www.soso.com/"
                },
                {//跳转小程序
                     "type":"miniprogram",
                     "name":"wxa",
                     "url":"http://mp.weixin.qq.com",
                     "appid":"wx286b93c14bbf93aa",
                     "pagepath":"pages/lunar/index"
                 },
                {
                   "type":"click",
                   "name":"赞一下我们",
                   "key":"V1001_GOOD"
                }]
           }]
     }
     正确返回消息:
     {"errcode":0,"errmsg":"ok"}
     出错时返回消息:
     {"errcode":40018,"errmsg":"invalid button name size"}
     
    

    这里需要注意的是,POST的内容类型(content-type)需要设置为application/json;

    查询菜单

    创建自定义菜单后,可使用该接口查询自定义菜单的结构。如果使用了个性化菜单,那么该接口将返回默认菜单和全部个性化菜单的信息;

    请求方式:GET
    https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN
    
    返回数据(无个性化菜单时):
    {
        "menu": {
            "button": [
                {
                    "type": "click", 
                    "name": "今日歌曲", 
                    "key": "V1001_TODAY_MUSIC", 
                    "sub_button": [ ]
                }, 
                {
                    "type": "click", 
                    "name": "歌手简介", 
                    "key": "V1001_TODAY_SINGER", 
                    "sub_button": [ ]
                }, 
                {
                    "name": "菜单", 
                    "sub_button": [
                        {
                            "type": "view", 
                            "name": "搜索", 
                            "url": "http://www.soso.com/", 
                            "sub_button": [ ]
                        }, 
                        {
                            "type": "view", 
                            "name": "视频", 
                            "url": "http://v.qq.com/", 
                            "sub_button": [ ]
                        }, 
                        {
                            "type": "click", 
                            "name": "赞一下我们", 
                            "key": "V1001_GOOD", 
                            "sub_button": [ ]
                        }
                    ]
                }
            ]
        }
    }
    
    返回结果(有个性化菜单时):
    {
        "menu": {
            "button": [
                {
                    "type": "click", 
                    "name": "今日歌曲", 
                    "key": "V1001_TODAY_MUSIC", 
                    "sub_button": [ ]
                }
            ], 
            "menuid": 208396938
        }, 
        "conditionalmenu": [
            {
                "button": [
                    {
                        "type": "click", 
                        "name": "今日歌曲", 
                        "key": "V1001_TODAY_MUSIC", 
                        "sub_button": [ ]
                    }, 
                    {
                        "name": "菜单", 
                        "sub_button": [
                            {
                                "type": "view", 
                                "name": "搜索", 
                                "url": "http://www.soso.com/", 
                                "sub_button": [ ]
                            }, 
                            {
                                "type": "view", 
                                "name": "视频", 
                                "url": "http://v.qq.com/", 
                                "sub_button": [ ]
                            }, 
                            {
                                "type": "click", 
                                "name": "赞一下我们", 
                                "key": "V1001_GOOD", 
                                "sub_button": [ ]
                            }
                        ]
                    }
                ], 
                "matchrule": {
                    "group_id": 2, 
                    "sex": 1, 
                    "country": "中国", 
                    "province": "广东", 
                    "city": "广州", 
                    "client_platform_type": 2
                }, 
                "menuid": 208396993
            }
        ]
    }
    

    删除菜单

    接口说明:

    http请求方式:GET
    https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
    正确返回消息:
    {"errcode":0,"errmsg":"ok"}
    错误返回消息同上
    

    这里需要注意的是,该方式将删除整个菜单。

    个性化菜单

    为了帮助公众号实现灵活的业务运营,微信公众平台新增了个性化菜单接口,开发者可以通过该接口,让公众号的不同用户群体看到不一样的自定义菜单。该接口开放给已认证订阅号和已认证服务号。

    开发者可以使用如下方式标志用户:

    1. 用户标签(开发者的业务需求可以借助用户标签来完成)
    2. 性别
    3. 手机操作系统地区(用户在微信客户端设置的地区)
    4. 语言(用户在微信客户端设置的语言)

    使用个性化菜单需要有以下几点注意:

    1. 个性化菜单要求用户的微信客户端版本在iPhone6.2.2,Android 6.2.4以上,暂时不支持其他版本微信;
    2. 菜单的刷新策略是,在用户进入公众号会话页或公众号profile页时,如果发现上一次拉取菜单的请求在5分钟以前,就会拉取一下菜单,如果菜单有更新,就会刷新客户端的菜单。测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果;
    3. 普通公众号的个性化菜单的新增接口每日限制次数为2000次,删除接口也是2000次,测试个性化菜单匹配结果接口为20000次;
    4. 出于安全考虑,一个公众号的所有个性化菜单,最多只能设置为跳转到3个域名下的链接;
    5. 创建个性化菜单之前必须先创建默认菜单(默认菜单是指使用普通自定义菜单创建接口创建的菜单)。如果删除默认菜单,个性化菜单也会全部删除;
    6. 个性化菜单接口支持用户标签,请开发者注意,当用户身上的标签超过1个时,以最后打上的标签为匹配;

    创建个性化菜单:

    请求方式:POST(请使用https协议)
    https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token=ACCESS_TOKEN
    POST数据为JSON对象;
    {
         "button":[
         {    
            "type":"click",
            "name":"今日歌曲",
             "key":"V1001_TODAY_MUSIC" },
        {     "name":"菜单",
            "sub_button":[
            {            
                "type":"view",
                "name":"搜索",
                "url":"http://www.soso.com/"},
                {
                             "type":"miniprogram",
                             "name":"wxa",
                             "url":"http://mp.weixin.qq.com",
                             "appid":"wx286b93c14bbf93aa",
                             "pagepath":"pages/lunar/index"
                },
                 {
            "type":"click",
            "name":"赞一下我们",
            "key":"V1001_GOOD"
               }]
     }],
    "matchrule":{
      "tag_id":"2",
      "sex":"1",
      "country":"中国",
      "province":"广东",
      "city":"广州",
      "client_platform_type":"2",
      "language":"zh_CN"
      }
    }
    正确返回消息:
    {"menuid":"208379533"}——menuid即为该菜单的标记;可用于以后删除使用;
    

    删除个性化菜单:

    请求方式:POST(请使用https协议)
    https://api.weixin.qq.com/cgi-bin/menu/delconditional?access_token=ACCESS_TOKEN
    参数说明:
    POST数据为JSON字符串
    {"menuid":"208379533"}
    正确返回:
    {"errcode":0,"errmsg":"ok"}
    错误返回:
    通用
    

    自定义菜单事件推送

    注意,第3个到第8个的所有事件,仅支持微信iPhone5.4.1以上版本,和Android5.4以上版本的微信用户,旧版本微信用户点击后将没有回应,开发者也不能正常接收到事件推送。

    click类型的消息推送:
    <xml>
    <ToUserName><![CDATA[toUser]]></ToUserName>
    <FromUserName><![CDATA[FromUser]]></FromUserName>
    <CreateTime>123456789</CreateTime>
    <MsgType><![CDATA[event]]></MsgType>
    <Event><![CDATA[CLICK]]></Event>
    <EventKey><![CDATA[EVENTKEY]]></EventKey>
    </xml>
    
    view类型的消息推送:
    <xml>
    <ToUserName><![CDATA[toUser]]></ToUserName>
    <FromUserName><![CDATA[FromUser]]></FromUserName>
    <CreateTime>123456789</CreateTime>
    <MsgType><![CDATA[event]]></MsgType>
    <Event><![CDATA[VIEW]]></Event>
    <EventKey><![CDATA[www.qq.com]]></EventKey>
    <MenuId>MENUID</MenuId>//指菜单ID,如果是个性化菜单,则可以通过这个字段,知道是哪个规则的菜单被点击了。
    </xml>
    
    scancode_push类型的消息推送:
    <xml><ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
    <FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
    <CreateTime>1408090502</CreateTime>
    <MsgType><![CDATA[event]]></MsgType>
    <Event><![CDATA[scancode_push]]></Event>
    <EventKey><![CDATA[6]]></EventKey>
    <ScanCodeInfo><ScanType><![CDATA[qrcode]]></ScanType>
    <ScanResult><![CDATA[1]]></ScanResult>
    </ScanCodeInfo>
    </xml>
    
    scancode_waitmsg类型的消息推送:
    <xml><ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
    <FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
    <CreateTime>1408090606</CreateTime>
    <MsgType><![CDATA[event]]></MsgType>
    <Event><![CDATA[scancode_waitmsg]]></Event>
    <EventKey><![CDATA[6]]></EventKey>
    <ScanCodeInfo><ScanType><![CDATA[qrcode]]></ScanType>
    <ScanResult><![CDATA[2]]></ScanResult>
    </ScanCodeInfo>
    </xml>
    
    pic_sysphoto类型的消息推送:
    <xml><ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
    <FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
    <CreateTime>1408090651</CreateTime>
    <MsgType><![CDATA[event]]></MsgType>
    <Event><![CDATA[pic_sysphoto]]></Event>
    <EventKey><![CDATA[6]]></EventKey>
    <SendPicsInfo><Count>1</Count>
    <PicList><item><PicMd5Sum><![CDATA[1b5f7c23b5bf75682a53e7b6d163e185]]></PicMd5Sum>
    </item>
    </PicList>
    </SendPicsInfo>
    </xml>
    
    pic_photo_or_album类型的消息推送:
    <xml><ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
    <FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
    <CreateTime>1408090816</CreateTime>
    <MsgType><![CDATA[event]]></MsgType>
    <Event><![CDATA[pic_photo_or_album]]></Event>
    <EventKey><![CDATA[6]]></EventKey>
    <SendPicsInfo><Count>1</Count>
    <PicList><item><PicMd5Sum><![CDATA[5a75aaca956d97be686719218f275c6b]]></PicMd5Sum>
    </item>
    </PicList>
    </SendPicsInfo>
    </xml>
    
    pic_weixin类型的消息推送:
    <xml><ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
    <FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
    <CreateTime>1408090816</CreateTime>
    <MsgType><![CDATA[event]]></MsgType>
    <Event><![CDATA[pic_weixin]]></Event>
    <EventKey><![CDATA[6]]></EventKey>
    <SendPicsInfo><Count>1</Count>
    <PicList><item><PicMd5Sum><![CDATA[5a75aaca956d97be686719218f275c6b]]></PicMd5Sum>
    </item>
    </PicList>
    </SendPicsInfo>
    </xml>
    
    location_select类型的消息推送:
    <xml><ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
    <FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
    <CreateTime>1408091189</CreateTime>
    <MsgType><![CDATA[event]]></MsgType>
    <Event><![CDATA[location_select]]></Event>
    <EventKey><![CDATA[6]]></EventKey>
    <SendLocationInfo><Location_X><![CDATA[23]]></Location_X>
    <Location_Y><![CDATA[113]]></Location_Y>
    <Scale><![CDATA[15]]></Scale>
    <Label><![CDATA[ 广州市海珠区客村艺苑路 106号]]></Label>
    <Poiname><![CDATA[]]></Poiname>
    </SendLocationInfo>
    </xml>
    
    
    

    用户管理

    标签管理

    开发者可以使用用户标签管理的相关接口,实现对公众号标签的管理;标签可以用于对用户的分类管理;

    每个公众号可以创建100个标签;创建方式如下:

    请求方式:POST(使用https协议);
    请求地址:https://api.weixin.qq.com/cgi-bin/tags/create?access_token=ACCESS_TOKEN
    POST数据格式:
    {   "tag":{ "name" : "广东"//标签名长度不能超过30字节}}
    返回结果:
    {   "tag":{ "id":134,id "name":"广东"   } }//包含tag-id
    

    获取公众号已创建的标签:

    请求方式:GET(使用https协议) 
    请求地址:https://api.weixin.qq.com/cgi-bin/tags/get?access_token=ACCESS_TOKEN
    返回说明:
    {   "tags":[{       "id":1,       "name":"每天一罐可乐星人",       "count":0 //此标签下粉丝数 },{   "id":2,   "name":"星标组",   "count":0 },{   "id":127,   "name":"广东",   "count":5 }   ] }
    

    编辑标签:

    请求方式:POST(请使用https协议)
    请求地址:https://api.weixin.qq.com/cgi-bin/tags/update?access_token=ACCESS_TOKEN
    POST数据:
    {   "tag" : {     "id" : 134,     "name" : "广东人"   } }
    返回说明:
    正确返回:{   "errcode":0,   "errmsg":"ok" }
    错误返回:详见错误返回码
    

    删除标签:

    请注意,当某个标签下的粉丝超过10w时,后台不可直接删除标签。此时,开发者可以对该标签下的openid列表,先进行取消标签的操作,直到粉丝数不超过10w后,才可直接删除该标签。

    请求方式:POST(使用https协议) 
    请求地址:https://api.weixin.qq.com/cgi-bin/tags/delete?access_token=ACCESS_TOKEN
    POST数据:
    {   "tag":{        "id" : 134   } }
    返回说明:
    正确返回:{   "errcode":0,   "errmsg":"ok" }
    错误返回:详见错误返回码
    

    获取标签下的粉丝列表:

    请求方式:POST(请使用https协议) 
    请求地址:https://api.weixin.qq.com/cgi-bin/user/tag/get?access_token=ACCESS_TOKEN
    POST数据格式:JSON
    {   "tagid" : 134,   "next_openid":""//第一个拉取的OPENID,不填默认从头开始拉取 }
    返回说明:
    { 
    	"count":2,//这次获取的粉丝数量   
    	"data":{//粉丝列表
    		"openid":[  
    			"ocYxcuAEy30bX0NXmGn4ypqx3tI0",    
    			"ocYxcuBt0mRugKZ7tGAHPnUaOW7Y"
    		]  
    	},  
    	"next_openid":"ocYxcuBt0mRugKZ7tGAHPnUaOW7Y"//拉取列表最后一个用户的openid 
    }
    

    用户标签管理

    标签功能支持为公众号用户进行打标签、取消标签等操作;该功能可以实现个性化菜单定制

    批量为用户打标签

    请求方式:POST(请使用https协议)
    请求地址:https://api.weixin.qq.com/cgi-bin/tags/members/batchtagging?access_token=ACCESS_TOKEN
    POST数据:
    {   
    	"openid_list" : [//粉丝列表    
    		"ocYxcuAEy30bX0NXmGn4ypqx3tI0",    
    		"ocYxcuBt0mRugKZ7tGAHPnUaOW7Y"],   
    	"tagid" : 134 
    }
    返回说明:
    {   
    	"errcode":0,   
    	"errmsg":"ok"
    }
    

    批量为用户取消标签

    请求方式:POST(请使用https协议) 
    请求地址:https://api.weixin.qq.com/cgi-bin/tags/members/batchuntagging?access_token=ACCESS_TOKEN
    POST数据格式:JSON
    {
    	"openid_list" : [//粉丝列表     
    		"ocYxcuAEy30bX0NXmGn4ypqx3tI0",     
    		"ocYxcuBt0mRugKZ7tGAHPnUaOW7Y"],   
    	"tagid" : 134
    }
    返回说明:{"errcode":0, "errmsg":"ok"}
    

    获取用户的标签列表

    请求方式:POST(请使用https协议)
    请求地址:https://api.weixin.qq.com/cgi-bin/tags/getidlist?access_token=ACCESS_TOKEN
    POST数据格式:JSON
    {   "openid" : "ocYxcuBt0mRugKZ7tGAHPnUaOW7Y" }
    返回说明:{   "tagid_list":[//被置上的标签列表 134, 2   ] }
    

    设置用户备注名

    请求方式: POST(请使用https协议)
    请求地址:https://api.weixin.qq.com/cgi-bin/user/info/updateremark?access_token=ACCESS_TOKEN
    POST数据格式:JSON
    POST数据例子:
    {
        "openid":"oDF3iY9ffA-hqb2vVvbr7qxf6A0Q",
        "remark":"pangzi"//标签名
    }
    返回说明:{"errcode":0,"errmsg":"ok"}
    

    获取用户基本信息

    注意,这里获的用户基本信息是在关注者和公众号产生消息交互后,公众号可获得该用户的Open ID,之后在响应系统中,通过Open ID获的Union ID以及基本信息

    请求方式: GET
    请求地址:https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
    返回说明:正常情况下,微信会返回下述JSON数据包给公众号
    {
        "subscribe": 1, 
        "openid": "o6_bmjrPTlm6_2sgVt7hMZOPfL2M", 
        "nickname": "Band", 
        "sex": 1, 
        "language": "zh_CN", 
        "city": "广州", 
        "province": "广东", 
        "country": "中国", 
        "headimgurl":"http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
        "subscribe_time": 1382694957,
        "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
        "remark": "",
        "groupid": 0,
        "tagid_list":[128,2],
        "subscribe_scene": "ADD_SCENE_QR_CODE",
        "qr_scene": 98765,
        "qr_scene_str": ""
    }
    

    批量获得用户基本信息

    请求方式: POST
    请求地址:https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=ACCESS_TOKEN
    POST:JSON
    {
        "user_list": [
            {
                "openid": "otvxTs4dckWG7imySrJd6jSi0CWE", 
                "lang": "zh_CN"
            }, 
            {
                "openid": "otvxTs_JZ6SEiP0imdhpi50fuSZg", 
                "lang": "zh_CN"
            }
        ]
    }
    返回说明:
    {
       "user_info_list": [
           {
               "subscribe": 1, 
               "openid": "otvxTs4dckWG7imySrJd6jSi0CWE", 
               "nickname": "iWithery", 
               "sex": 1, 
               "language": "zh_CN", 
               "city": "揭阳", 
               "province": "广东", 
               "country": "中国", 
    
               "headimgurl": "http://thirdwx.qlogo.cn/mmopen/xbIQx1GRqdvyqkMMhEaGOX802l1CyqMJNgUzKP8MeAeHFicRDSnZH7FY4XB7p8XHXIf6uJA2SCunTPicGKezDC4saKISzRj3nz/0",
    
              "subscribe_time": 1434093047, 
               "unionid": "oR5GjjgEhCMJFyzaVZdrxZ2zRRF4", 
               "remark": "", 
    
               "groupid": 0,
               "tagid_list":[128,2],
               "subscribe_scene": "ADD_SCENE_QR_CODE",
               "qr_scene": 98765,
               "qr_scene_str": ""
    
          }, 
           {
               "subscribe": 0, 
               "openid": "otvxTs_JZ6SEiP0imdhpi50fuSZg"
           }
       ]
    }
    

    获取用户列表

    公众号可通过本接口来获取帐号的关注者列表,关注者列表由一串OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的)组成。一次拉取调用最多拉取10000个关注者的OpenID,可以通过多次拉取的方式来满足需求。

    请求方式: GET(请使用https协议)
    请求地址:https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID
    返回说明:
    {
    	"total":2,
    	"count":2,
    	"data":{
    		"openid":["OPENID1","OPENID2"]
    	},
    	"next_openid":"NEXT_OPENID"
    }
    

    当公众号关注者数量超过10000时,可通过填写next_openid的值,从而多次拉取列表的方式来满足需求。

    具体而言,就是在调用接口时,将上一次调用得到的返回中的next_openid值,作为下一次调用中的next_openid值。

    消息管理

    接收普通消息

    当普通用户向公众号发送消息时,微信系统将POST消息的XML数据包到开发者填写的URL上;

    注意事项:

    1. 微信服务器在5s内收不到响应并不会断掉连接,并且重新发起请求,总共重试3次;如果服务器无法保证在5s内做出响应,应当回复空串。
    2. 如果开发者需要在5s内对用户发送的消息做出回应,即使用发送消息->被回复消息接口向用户被动回复消息,那么需要选择对消息的加密方式,详情见 消息加密;

    各种消息体结构(XML格式组织,可使用输入流的方式读取):

    注意,首次出现的XML标签将给出注释,第二次出现则不再注释,该规则同样适用于后面的接收事件消息

    1. 文本消息

      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>	//开发者微信号
      	<FromUserName>< ![CDATA[fromUser] ]></FromUserName>		//用户的openid
      	<CreateTime>1348831860</CreateTime>
      	<MsgType>< ![CDATA[text] ]></MsgType>	//文本为text
      	<Content>< ![CDATA[this is a test] ]></Content>
      	<MsgId>1234567890123456</MsgId>		//64位整型
      </xml>
      
    2. 图片消息

      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>
      	<FromUserName>< ![CDATA[fromUser] ]></FromUserName>
      	<CreateTime>1348831860</CreateTime>
      	<MsgType>< ![CDATA[image] ]></MsgType>	//图片为image
      	<PicUrl>< ![CDATA[this is a url] ]></PicUrl>
      	<MediaId>< ![CDATA[media_id] ]></MediaId>	//可使用图片消息媒体id,可以调用多媒体文件下载接口拉取数据。
      	<MsgId>1234567890123456</MsgId>
      </xml>
      
    3. 语音消息

      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>
      	<FromUserName>< ![CDATA[fromUser] ]></FromUserName>
      	<CreateTime>1357290913</CreateTime>
      	<MsgType>< ![CDATA[voice] ]></MsgType>	//语音为voice
      	<MediaId>< ![CDATA[media_id] ]></MediaId>
      	<Format>< ![CDATA[Format] ]></Format>	//语音格式,如amr,speex等
      	<MsgId>1234567890123456</MsgId>
      	<Recognition>< ![CDATA[腾讯微信团队] ]></Recognition>
      </xml>
      

      这里需要注意的是,如果开启了语音识别,用户每次发送语音给公众号时,微信会在推送的语音消息XML数据包中,增加一个Recongnition字段标志识别结果;

    4. 视频消息

      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>
      	<FromUserName>< ![CDATA[fromUser] ]></FromUserName>
      	<CreateTime>1357290913</CreateTime>
      	<MsgType>< ![CDATA[video] ]></MsgType>	//视频为video
      	<MediaId>< ![CDATA[media_id] ]></MediaId>	//可使用图片消息媒体id,可以调用多媒体文件下载接口拉取数据。
      	<ThumbMediaId>< ![CDATA[thumb_media_id] ]></ThumbMediaId>	//视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。
      	<MsgId>1234567890123456</MsgId></xml>
      
    5. 小视频消息

      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>
      	<FromUserName>< ![CDATA[fromUser] ]></FromUserName>
      	<CreateTime>1357290913</CreateTime>
      	<MsgType>< ![CDATA[shortvideo] ]></MsgType>		//小视频为shortvideo
      	<MediaId>< ![CDATA[media_id] ]></MediaId>
      	<ThumbMediaId>< ![CDATA[thumb_media_id] ]></ThumbMediaId>
      	<MsgId>1234567890123456</MsgId>
      </xml>
      
    6. 地理位置消息

      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>
      	<FromUserName>< ![CDATA[fromUser] ]></FromUserName>
      	<CreateTime>1351776360</CreateTime>
      	<MsgType>< ![CDATA[location] ]></MsgType>	//地理位置为	location
      	<Location_X>23.134521</Location_X>	// 地理纬度
      	<Location_Y>113.358803</Location_Y>	// 地理经度
      	<Scale>20</Scale>	//地图缩放大小
      	<Label>< ![CDATA[位置信息] ]></Label>	//地理位置信息
      	<MsgId>1234567890123456</MsgId>
      </xml>
      
      
    7. 链接消息

      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>
      	<FromUserName>< ![CDATA[fromUser] ]></FromUserName>
      	<CreateTime>1351776360</CreateTime>
      	<MsgType>< ![CDATA[link] ]></MsgType>	//链接消息为 link
      	<Title>< ![CDATA[公众平台官网链接] ]></Title>	//标题
      	<Description>< ![CDATA[公众平台官网链接] ]></Description>	//描述
      	<Url>< ![CDATA[url] ]></Url>	//消息链接
      	<MsgId>1234567890123456</MsgId>
      </xml>
      
      

    接收事件消息

    在微信用户和公众号产生交互的过程中,用户的某些操作会使得微信系统通过事件推送的形式通知响应系统,从而开发者可以获取到该信息。其中,某些事件推送在发生后,是允许开发者回复用户的,某些则不允许,详细内容如下:

    1. 关注/取消关注事件
    2. 扫描带参数二维码事件
    3. 上报地理位置事件
    4. 自定义菜单事件
    5. 点击菜单拉取消息的事件
    6. 点击菜单跳转链接时的事件

    各种事件介绍:

    1. 关注/取消关注事件

      用户在关注与取消关注公众号时,微信系统会把这个事件推送到响应系统,方便开发者给用户下发欢迎消息或者做帐号的解绑。为保护用户数据隐私,开发者收到用户取消关注事件时需要删除该用户的所有信息。

      推送XML数据包示例:

      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>	//开发者微信号
      	<FromUserName>< ![CDATA[FromUser] ]></FromUserName>		//用户的OennID
      	<CreateTime>123456789</CreateTime>	//创建时间,int整型
      	<MsgType>< ![CDATA[event] ]></MsgType>
      	<Event>	//消息类型为event< ![CDATA[subscribe] ]></Event>	//事件类型,subscribe(订阅)、unsubscribe(取消订阅)
      </xml>
      
      
    2. 扫描带参数二维码事件:

      用户扫描带场景值二维码时,可能推送以下两种事件:

      1. 如果用户还未关注公众号,则用户可以关注公众号,关注后微信系统会将带场景值关注事件推送给响应系统。
      2. 如果用户已经关注公众号,则微信系统会将带场景值的扫描事件推送响应系统。

      推送XML数据包示例:

      用户未关注时,进行关注后的事件推送
      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>
      	<FromUserName>< ![CDATA[FromUser] ]></FromUserName>
      	<CreateTime>123456789</CreateTime>
      	<MsgType>< ![CDATA[event] ]></MsgType>		//消息类型为event
      	<Event>< ![CDATA[subscribe] ]></Event>	//事件类型,subscribe
      	<EventKey>< ![CDATA[qrscene_123123] ]></EventKey>	//事件KEY值,qrscene_为前缀,后面为二维码的参数值
      	<Ticket>< ![CDATA[TICKET] ]></Ticket>	//二维码的ticket,可用来换取二维码图片
      </xml>
      
      用户已关注时的事件推送
      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName> 
      	<FromUserName>< ![CDATA[FromUser] ]></FromUserName> 
      	<CreateTime>123456789</CreateTime> 
      	<MsgType>< ![CDATA[event] ]></MsgType>
          <Event>< ![CDATA[SCAN] ]></Event>
          <EventKey>< ![CDATA[SCENE_VALUE] ]></EventKey>	//创建二维码是的scene_id
          <Ticket>< ![CDATA[TICKET] ]></Ticket>	//二维码的ticket,可用来换取图片
      </xml>
      
      
    3. 上报地理位置事件

      用户同意上报地理位置后,每次进入公众号会话时,都会进入上报地理位置,或在进入会话后每5秒报一次地理位置。上报地理位置时,微信系统将上报地理位置事件推送到响应系统;

      推送XML数据包示例:

      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>
      	<FromUserName>< ![CDATA[fromUser] ]></FromUserName>
      	<CreateTime>123456789</CreateTime>
      	<MsgType>< ![CDATA[event] ]></MsgType>
      	<Event>< ![CDATA[LOCATION] ]></Event>
      	<Latitude>23.137466</Latitude>	//维度
      	<Longitude>113.352425</Longitude>	//经度
      	<Precision>119.385040</Precision>	//地理位置精度
      </xml>
      
      
    4. 自定义菜单事件

      用户点击自定义菜单后,微信系统会把点击事件推送给响应系统,点击菜单弹出子菜单,不会产生上报。

      推送XML数据包示例:

      点击菜单拉取消息时的事件推送
      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>
      	<FromUserName>< ![CDATA[FromUser] ]></FromUserName>
      	<CreateTime>123456789</CreateTime>
      	<MsgType>< ![CDATA[event] ]></MsgType>
      	<Event>< ![CDATA[CLICK] ]></Event>	//事件类型为CLICK
      	<EventKey>< ![CDATA[EVENTKEY] ]></EventKey>	//事件KEY值,与自定义菜单接口中KEY值对应
      </xml>
      
      点击菜单跳转链接时的事件推送
      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>
      	<FromUserName>< ![CDATA[FromUser] ]></FromUserName>
      	<CreateTime>123456789</CreateTime>
      	<MsgType>< ![CDATA[event] ]></MsgType>	
      	<Event>< ![CDATA[VIEW] ]></Event>	//事件类型为 VIEW
      	<EventKey>< ![CDATA[www.qq.com] ]></EventKey>	//事件的KEY值,设置的跳转URL
      </xml>
      
      

    被动回复用户消息

    当用户发送消息给公众号时,或某些特定的用户操作引发的事件推送时,微信系统会将一个POST请求发送到响应系统,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应,这种方式称为被动回复用户消息。

    现支持回复文本、图片、图文、语音、视频、音乐。

    发送被动响应消息其实并不是一种接口,而是对微信系统发过来消息的一次回复,只是这次回复将发送到用户。

    被动回复消息的数据格式:

    注意:

    1. 回复图片(不支持gif动图)等多媒体消息时需要预先通过素材管理接口上传临时素材到微信服务器,可以使用素材管理中的临时素材,也可以使用永久素材。

    2. 一旦遇到以下情况,微信都会在公众号会话中,向用户下发系统提示“该公众号暂时无法提供服务,请稍后再试”:

      1. 开发者在5秒内未回复任何内容;
      2. 开发者回复了异常数据,比如JSON数据等;
    3. 回复文本消息

      XML格式数据:

      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>	//用户Open id
      	<FromUserName>< ![CDATA[fromUser] ]></FromUserName>	//开发者 微信号;这两者都可以从响应系统收到的消息里获得
          <CreateTime>12345678</CreateTime>
          <MsgType>< ![CDATA[text] ]></MsgType>	//消息类型为:text
          <Content>< ![CDATA[你好] ]></Content>
      </xml>
      
      
    4. 回复图片消息

      XML格式数据:

      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>
      	<FromUserName>< ![CDATA[fromUser] ]></FromUserName>
      	<CreateTime>12345678</CreateTime>
      	<MsgType>< ![CDATA[image] ]></MsgType>	//消息类型为:image
      	<Image>
      		<MediaId>< ![CDATA[media_id] ]></MediaId>//通过素材管理中的接口上传多媒体文件,得到的id。
      	</Image>
      </xml>
      
      
    5. 回复语音消息

      XML格式数据:

      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>
      	<FromUserName>< ![CDATA[fromUser] ]></FromUserName>
      	<CreateTime>12345678</CreateTime>
      	<MsgType>< ![CDATA[voice] ]></MsgType>	//消息类型为:voice
      	<Voice>
      		<MediaId>< ![CDATA[media_id] ]></MediaId>
      	</Voice>
      </xml>
      
      
    6. 回复视频消息

      XML格式数据:

      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>
      	<FromUserName>< ![CDATA[fromUser] ]></FromUserName>
      	<CreateTime>12345678</CreateTime>
      	<MsgType>< ![CDATA[video] ]></MsgType>	//消息类型为:video
      	<Video>
      		<MediaId>< ![CDATA[media_id] ]></MediaId>
      		<Title>< ![CDATA[title] ]></Title>	//视频的标题
      		<Description>< ![CDATA[description] ]></Description>	//视频的描述
      	</Video>
      </xml>
      
      
    7. 回复音乐消息

      XML格式数据:

      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>
      	<FromUserName>< ![CDATA[fromUser] ]></FromUserName>
      	<CreateTime>12345678</CreateTime>
      	<MsgType>< ![CDATA[music] ]></MsgType>
      	<Music>
      		<Title>< ![CDATA[TITLE] ]></Title>
      		<Description>< ![CDATA[DESCRIPTION] ]></Description>
      		<MusicUrl>< ![CDATA[MUSIC_Url] ]></MusicUrl>
      		<HQMusicUrl>< ![CDATA[HQ_MUSIC_Url] ]></HQMusicUrl>
      		<ThumbMediaId>< ![CDATA[media_id] ]></ThumbMediaId>
      	</Music>
      </xml>
      
      
    8. 回复图文消息

      XML格式数据:

      <xml>
      	<ToUserName>< ![CDATA[toUser] ]></ToUserName>
      	<FromUserName>< ![CDATA[fromUser] ]></FromUserName>
      	<CreateTime>12345678</CreateTime>
      	<MsgType>< ![CDATA[news] ]></MsgType>
      	<ArticleCount>2</ArticleCount>
      	<Articles>
      		<item>
      			<Title>< ![CDATA[title1] ]></Title>
      			<Description>< ![CDATA[description1] ]></Description>
      			<PicUrl>< ![CDATA[picurl] ]></PicUrl>
      			<Url>< ![CDATA[url] ]></Url>
      		</item>
      		<item>
      			<Title>< ![CDATA[title] ]></Title>
      			<Description>< ![CDATA[description] ]></Description>
      			<PicUrl>< ![CDATA[picurl] ]></PicUrl>
      			<Url>< ![CDATA[url] ]></Url>
      		</item>
      	</Articles>
      </xml>
      
      

    主动发送消息

    主动发送消息是通过模板消息实现的,模板消息仅用于公众号向用户发送重要的服务通知,只能用于符合其要求的服务场景中,如信用卡刷卡通知,商品购买成功通知等。

    为了发送模板消息,需要首先设置公众号所属的行业,之后公众号则只能使用该行业内的模板来发送模板消息;设置行业可以通过微信公众平台后台来完成,每月可修改一次;也可以通过接口调用的方式来修改所属行业;

    定义模板消息时需要注意的地方:

    1. 模板消息调用时主要需要模板ID和模板中各参数的赋值内容;
    2. 模板中参数内容必须以".DATA"结尾,否则视为保留字;
    3. 模板保留符号"{{ }}";
    4. 详情见:获得已添加到微信公众号里的所有模板列表;

    设置所属行业:

    请求方式: POST
    请求地址:https://api.weixin.qq.com/cgi-bin/template/api_set_industry?access_token=ACCESS_TOKEN
    POST数据格式:
    {"industry_id1":"1","industry_id2":"4"}
     
    
    

    获得模板ID:

    该过程可在公众号后台完成,同时提供接口:

    请求方式: POST
    请求地址:https://api.weixin.qq.com/cgi-bin/template/api_add_template?access_token=ACCESS_TOKEN
    POST数据格式:
    {"template_id_short":"TM00015"}
    正确返回消息说明:JSON
    {"errcode":0,"errmsg":"ok","template_id":"Doclyl5uP7Aciu-qZ7mJNPtWkbkYnWBWVja26EGbNyk"}
    错误返回消息说明:
    错误码通用。
    
    

    获取已添加到微信公众号里的所有模板列表:

    请求方式:GET
    请求地址:https//api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=ACCESS_TOKEN
    返回结果说明:
    {    
     "template_list": [{
          "template_id": "iPk5sOIt5X_flOVKn5GrTFpncEYTojx6ddbt8WYoV5s",
          "title": "领取奖金提醒",
          "primary_industry": "IT科技",
          "deputy_industry": "互联网|电子商务",
          "content": "{ {result.DATA} }\n\n领奖金额:{ {withdrawMoney.DATA} }\n领奖  时间:{ {withdrawTime.DATA} }\n银行信息:{ {cardInfo.DATA} }\n到账时间:  { {arrivedTime.DATA} }\n{ {remark.DATA} }",
          "example": "您已提交领奖申请\n\n领奖金额:xxxx元\n领奖时间:2013-10-10 12:22:22\n银行信息:xx银行(尾号xxxx)\n到账时间:预计xxxxxxx\n\n预计将于xxxx到达您的银行卡"
       }]
    }
    
    

    删除模板:

    该过程可在公众号后台完成,同时提供接口:

    请求方式:POST
    请求地址:https://api.weixin.qq.com/cgi-bin/template/del_private_template?access_token=ACCESS_TOKEN
    POST数据格式:
    {"template_id" : "Dyvp3-Ff0cnail_CDSzk1fIc6-9lOkxsQE7exTJbwUE"}
    正确返回消息说明:JSON
    错误返回消息说明:
    {"errcode" : 0,"errmsg" : "ok"}
    错误码通用。
    
    

    发送模板消息:

    请求方式: POST
    请求地址:https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
    POST数据格式:
    {
    	"touser":"OPENID",
    	"template_id":"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY",
    	"url":"http://weixin.qq.com/download",  
         "miniprogram":{
         	"appid":"xiaochengxuappid12345",
         	"pagepath":"index?foo=bar"
         },
         "data":{
         	"first": {
         		"value":"恭喜你购买成功!",
         		"color":"#173177"
         	},
         	"keyword1":{
         		"value":"巧克力",
         		"color":"#173177"
         	},
         	"keyword2": {
            	"value":"39.8元",
            	"color":"#173177"
            },
            "keyword3": {
            	"value":"2014年9月22日",
            	"color":"#173177"
            },
            "remark":{
            	"value":"欢迎再次购买!",
            	"color":"#173177"
            }
        }
    }
    正确返回消息格式:
    {"errcode":0,"errmsg":"ok","msgid":200228332}
    
    

    事件推送:

    在模版消息发送任务完成后,微信系统会将是否送达成功作为通知,发送到响应系统。

    送达成功时,推送的XML如下:
    <xml>
    	<ToUserName>< ![CDATA[gh_7f083739789a] ]></ToUserName>
    	<FromUserName>< ![CDATA[oia2TjuEGTNoeX76QEjQNrcURxG8] ]></FromUserName>
    	<CreateTime>1395658920</CreateTime>
    	<MsgType>< ![CDATA[event] ]></MsgType>
    	<Event>< ![CDATA[TEMPLATESENDJOBFINISH] ]></Event>
    	<MsgID>200163836</MsgID>
    	<Status>< ![CDATA[success] ]></Status>
    </xml>
    
    没有送达时,推送的XML如下:
    <xml>
    	<ToUserName>< ![CDATA[gh_7f083739789a] ]></ToUserName>
    	<FromUserName>< ![CDATA[oia2TjuEGTNoeX76QEjQNrcURxG8] ]></FromUserName>
    	<CreateTime>1395658984</CreateTime>
    	<MsgType>< ![CDATA[event] ]></MsgType>
    	<Event>< ![CDATA[TEMPLATESENDJOBFINISH] ]></Event>
    	<MsgID>200163840</MsgID>
    	<Status>< ![CDATA[failed:user block] ]></Status>	//failed: system failed——其他原因;failed:user block——用户拒绝接收该公众号的消息
    </xml>
    
    

    消息加密

    公众号消息加解密是为了进一步加强公众号安全保障,提供的新机制。公众账号主动调用API的情况不受影响。只有被动回复用户的消息时,才需要进行消息加解密。消息加解密方式:

    1. 明文模式:维持现有模式,没有适配加解密新特性,消息体明文收发,默认设置为明文模式;
    2. 兼容模式:公众平台发送消息内容将同时包括明文和密文,消息包长度增加到原来的3倍左右;公众号回复明文或密文均可,不影响现有消息收发;开发者可在此模式下进行调试;
    3. 安全模式(推荐):公众平台发送消息体的内容只含有密文,公众账号回复的消息体也为密文,建议开发者在调试成功后使用此模式收发消息

    启用加解密功能(即选择兼容模式或安全模式)后,微信系统在向响应系统推送消息时,URL将新增加两个参数(加密类型和消息体签名),并以此来体现新功能。加密算法采用AES。具体方案见该模块代码实现。

    获取微信系统服务器地址

    出于安全等考虑,如需要获知微信服务器的IP地址列表,可以通过该接口获得微信服务器IP地址列表或者IP网段信息。

    请求方式: GET
    请求地址:https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=ACCESS_TOKEN
    返回消息:JSON格式
    {"ip_list":["127.0.0.1","127.0.0.2","101.226.103.0/25"]}
    
    

    客服消息及管理

    当用户和公众号产生特定动作的交互时(具体动作列表请见下方说明),微信系统将会把消息数据推送给响应系统,响应系统可以在一段时间内(目前修改为48小时)调用客服接口,通过POST一个JSON数据包来发送消息给普通用户。此接口主要用于客服等有人工消息处理环节的功能,方便开发者为用户提供更加优质的服务。

    目前允许的动作列表如下(公众平台会根据运营情况更新该列表,不同动作触发后,允许的客服接口下发消息条数不同,下发条数达到上限后,会遇到错误返回码,具体请见返回码说明页):

    1. 用户发送信息
    2. 点击自定义菜单(仅有点击推事件、扫码推事件、扫码推事件且弹出“消息接收中”提示框这3种菜单类型将会触发客服接口)
    3. 关注公众号
    4. 扫描二维码
    5. 支付成功
    6. 用户维权

    客服账号管理:

    请注意,必须先在公众平台官网为公众号设置微信号后才能使用该能力。

    1. 添加客服账号

      请求方式: POST
      请求地址:https://api.weixin.qq.com/customservice/kfaccount/add?access_token=ACCESS_TOKEN
      POST数据示例如下:
      {
           "kf_account" : "test1@test",
           "nickname" : "客服1",
           "password" : "pswmd5",
      }
      返回说明(正确时的JSON返回结果):
      {"errcode" : 0,"errmsg" : "ok"}
      返回错误码是通用的
      
      
    2. 删除客服账号

      请求方式: GET
      请求地址:https://api.weixin.qq.com/customservice/kfaccount/del?access_token=ACCESS_TOKEN
      POST数据示例如下:
      {
           "kf_account" : "test1@test",
           "nickname" : "客服1",
           "password" : "pswmd5",
      }
      返回说明(正确时的JSON返回结果):
      {"errcode" : 0,"errmsg" : "ok"}
      返回错误码是通用的
      
      
    3. 修改客服账号

      请求方式: POST
      请求地址:https://api.weixin.qq.com/customservice/kfaccount/update?access_token=ACCESS_TOKEN
      POST数据示例如下:
      {
           "kf_account" : "test1@test",
           "nickname" : "客服1",
           "password" : "pswmd5",
      }
      返回说明(正确时的JSON返回结果):
      {"errcode" : 0,"errmsg" : "ok"}
      返回错误码是通用的
      
      

    设置客服账号头像

    开发者可调用该接口来上传图片作为客服人员的头像,头像图片文件必须是jpg格式,推荐使用640*640大小的图片以达到最佳效果。该接口调用请求如下:

    请求方式: POST/FORM
    请求地址:http://api.weixin.qq.com/customservice/kfaccount/uploadheadimg?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT
    这里需要注意的是,官方文档中提到的是使用curl工具POST一个多媒体文件;这里我想只要通过代码将文件提交到上述地址就OK,因为curl是一个命令行工具,网上有在php中使用curl的,但是对Java的支持很惨淡,这一部分详见代码验证及图示。
    
    

    获取所有客服账号

    请求方式: GET
    请求地址:https://api.weixin.qq.com/cgi-bin/customservice/getkflist?access_token=ACCESS_TOKEN
    返回数据:
    {
        "kf_list": [
            {
                "kf_account": "test1@test", 
                "kf_nick": "ntest1", 
                "kf_id": "1001"	//这里需要注意的是,kf_id是第一次在这里出现,创建的时候并没有返回该字段;
                "kf_headimgurl": " http://mmbiz.qpic.cn/mmbiz/4whpV1VZl2iccsvYbHvnphkyGtnvjfUS8Ym0GSaLic0FD3vN0V8PILcibEGb2fPfEOmw/0"
            }, 
            {
                "kf_account": "test2@test", 
                "kf_nick": "ntest2", 
                "kf_id": "1002"
                "kf_headimgurl": " http://mmbiz.qpic.cn/mmbiz/4whpV1VZl2iccsvYbHvnphkyGtnvjfUS8Ym0GSaLic0FD3vN0V8PILcibEGb2fPfEOmw /0"
            }
        ]
    }
    
    

    客服接口-发送消息

    请求方式: POST
    请求地址:https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
    各消息类型所需的JSON数据包如下:
    文本消息:
    {
        "touser":"OPENID",
        "msgtype":"text",
        "text":
        {
             "content":"Hello World"
        }
    }
    发送文本消息时,文本内容中可以携带跳转小程序的文字链:<a href="http://www.qq.com" data-miniprogram-appid="appid" data-miniprogram-path="pages/index/index">点击跳小程序</a>
    参数说明:
    1.data-miniprogram-appid 项,填写小程序appid,则表示该链接跳小程序;
    2.data-miniprogram-path项,填写小程序路径,路径与app.json中保持一致,可带参数;
    3.对于不支持data-miniprogram-appid 项的客户端版本,如果有herf项,则仍然保持跳href中的网页链接;
    
    注意,data-miniprogram-appid对应的小程序必须与公众号有绑定关系。
    
    发送图片消息:
    {
        "touser":"OPENID",
        "msgtype":"image",
        "image":
        {
          "media_id":"MEDIA_ID"
        }
    }
    
    发送语音消息:
    {
        "touser":"OPENID",
        "msgtype":"voice",
        "voice":
        {
          "media_id":"MEDIA_ID"
        }
    }
    
    发送视频消息:
    {
        "touser":"OPENID",
        "msgtype":"video",
        "video":
        {
          "media_id":"MEDIA_ID",
          "thumb_media_id":"MEDIA_ID",
          "title":"TITLE",
          "description":"DESCRIPTION"
        }
    }
    
    发送音乐消息:
    {
        "touser":"OPENID",
        "msgtype":"music",
        "music":
        {
          "title":"MUSIC_TITLE",
          "description":"MUSIC_DESCRIPTION",
          "musicurl":"MUSIC_URL",
          "hqmusicurl":"HQ_MUSIC_URL",
          "thumb_media_id":"THUMB_MEDIA_ID" 
        }
    }
    
    发送图文消息(点击跳转到外链) 图文消息条数限制在8条以内,注意,如果图文数超过8,则将会无响应。
    {
        "touser":"OPENID",
        "msgtype":"news",
        "news":{
            "articles": [
             {
                 "title":"Happy Day",
                 "description":"Is Really A Happy Day",
                 "url":"URL",
                 "picurl":"PIC_URL"
             },
             {
                 "title":"Happy Day",
                 "description":"Is Really A Happy Day",
                 "url":"URL",
                 "picurl":"PIC_URL"
             }
             ]
        }
    }
    
    发送图文消息:
    {
        "touser":"OPENID",
        "msgtype":"mpnews",
        "mpnews":
        {
             "media_id":"MEDIA_ID"
        }
    }
    
    发送卡券:
    {
      "touser":"OPENID", 
      "msgtype":"wxcard",
      "wxcard":{              
           "card_id":"123dsdajkasd231jhksad"        
       },
    }
    发送小程序卡片:
    {
        "touser":"OPENID",
        "msgtype":"miniprogrampage",
        "miniprogrampage":
        {
            "title":"title",
            "appid":"appid",
            "pagepath":"pagepath",
            "thumb_media_id":"thumb_media_id"
        }
    }
    
    

    微信网页开发

    网页授权获取用户基本信息

    用户在微信客户端中访问第三方网页,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑。

    这里需要注意的是同用户管理中的获取用户基本信息的区别:用户管理是在响应系统的完成的;而用户授权是在业务系统中完成的;两者工作的环境也是不同的,所以请求接口是不同的:第三方授权是在公众号内通过微信客户端进入网页时发生,而用户管理是公众号内部的管理行为;

    使用流程:

    1. 在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。
    2. 授权回调域名配置规范为全域名。配置后,该域名下的所有网页都可以进行OAuth2.0鉴权。

    两种请求模式:

    1. 以snsapi_base为scope发起的网页授权,用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务系统的入口);

    2. 以snsapi_userinfo为scope发起的网页授权,用来获取用户的基本信息的。这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。

      注意:用户管理类接口中的“获取用户基本信息接口”,是在用户和公众号产生消息交互或关注后事件推送后,才能根据用户OpenID来获取用户基本信息。该接口以及包括其他微信接口,都是需要该用户(即openid)关注了公众号后,才能调用成功的。

    在OAuth2.0用户授权机制下,存在一个反应用户是否同意授权的标记,该标记在OAuth2.0的环境下称为:access_token。这和响应系统用于请求微信接口时使用的access_token是不一样的,但是它们的性质是相同的;

    特殊环境下的静默授权:

    1. 上面已经提到,对于以snsapi_base为scope的网页授权,就静默授权的,用户无感知;
    2. 对于已关注公众号的用户,如果用户从公众号的会话或者自定义菜单进入本公众号的网页授权页,即使是scope为snsapi_userinfo,也是静默授权,用户无感知。

    具体而言,网页授权流程分为四步:

    1. 引导用户进入授权页面同意授权,获取code

       请求地址:https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
       参数说明:APPID/REDIRECT_URI/SCOPE/StATE等为变量,其余为常量;参数顺序不可变;
      
      

      如果用户同意授权,页面将跳转至 REDIRECT_URI/?code=CODE&state=STATE。 code说明 : code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。

    2. 通过code换取网页授权access_token(与基础支持中的access_token不同)

      请求地址:https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
      参数说明:APPID/SECRET/CODE等为变量,其余为常量;参数顺序可变;
      返回数据:JSON
      { 
      	"access_token":"ACCESS_TOKEN",//	网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
      	"expires_in":7200,
      	"refresh_token":"REFRESH_TOKEN",//用户刷新access_token
      	"openid":"OPENID",
      	"scope":"SCOPE"
      }
      
      

      注意:由于公众号的secret和获取到的access_token安全级别都非常高,必须只保存在服务器,不允许传给客户端。后续刷新access_token、通过access_token获取用户信息等步骤,也必须从服务器发起。即当前请求是可以通过客户端进行的。

      另外,此时已经获得open id,即如果不需要使用union id 的话,网页授权到此结束;

    3. 如果需要,开发者可以刷新网页授权access_token,避免过期

      请求地址:https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
      参数说明:APPID/REFRESH_TOKEN为变量,REFRESH_TOKEN即为第二步获得数据
      
      
    4. 通过网页授权access_token和openid获取用户基本信息(支持UnionID机制)

      请求方式:GET
      请求地址:https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
      参数说明:ACCESS_TOKEN即为第二步获得网页授权数据;OPENID一样;
      返回数据说明:JSON
      {
      	"openid":" OPENID",
      	" nickname": NICKNAME,
      	"sex":"1",
      	"province":"PROVINCE"
      	"city":"CITY",
      	"country":"COUNTRY",
      	"headimgurl": "http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
      	"privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
      	"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
      }
      
      

      整体来看,App Secret作为秘密数据,其获取也应该通过业务系统的验证以检查正在请求App Secret的网页是不是友军;

    微信JS-SDK的功能

    JS-SDK为第三方网页在微信客户端内使用本地资源提供JS封装的接口;这里不涉及具体API的使用,仅介绍JS-SDK的引入、调用接口权限的验证配置。

    引入JS文件:

    同普通JS文件。

    权限验证:

    所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用,同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复。

    wx.config({
        debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
        appId: '', // 必填,公众号的唯一标识
        timestamp: , // 必填,生成签名的时间戳
        nonceStr: '', // 必填,生成签名的随机串
        signature: '',// 必填,签名,签名算法见后专门模块
        jsApiList: [] // 必填,需要使用的JS接口列表
    });
    
    wx.ready(function(){
        // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
    });
    
    wx.error(function(res){
        // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
    });
    
    

    所有接口通过wx对象(也可使用jWeixin对象)来调用,参数是一个对象,除了每个接口本身需要传的参数之外,还有以下通用参数:

    1. success:执行成功时的回调函数;
    2. fail:调用接口失败时执行的回调函数;
    3. complete:接口调用完成时执行的回调函数,无论成功或失败都会执行。
    4. cancel:用户点击取消时的回调函数,仅部分有用户取消操作的api才会用到。
    5. trigger: 监听Menu中的按钮点击时触发的方法,该方法仅支持Menu中的相关接口。

    以上几个函数都带有一个参数,类型为对象,其中除了每个接口本身返回的数据之外,还有一个通用属性errMsg,其值格式如下:

    1. 调用成功时:“xxx:ok” ,其中xxx为调用的接口名
    2. 用户取消时:“xxx:cancel”,其中xxx为调用的接口名
    3. 调用失败时:其值为具体错误信息

    签名算法

    生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。 开发者必须在自己的服务全局缓存jsapi_ticket 。

    生成签名的流程:

    1. 获得access_token:具体见上文目录;

    2. 用第一步拿到的access_token获得jsapi_ticket

      请求方法:GET
      请求地址:https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
      返回数据说明:JSON
      {
      	"errcode":0,
      	"errmsg":"ok",
      	"ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
      	"expires_in":7200
      }
      
      
    3. 签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。 sha1加密后的结果即为signature;

    展开全文
  • 最近在做微信小程序的时候,需要实现在搜索框的输入内容的时候实现全局匹配实现高亮效果,目前的思路是,递归后台来返回的数据,并将对象的value值替换为需要的dom节点,并且通过rich-text来实现,高亮效果。...

    需求

    最近在做微信小程序的时候,需要实现在搜索框的输入内容的时候实现全局匹配实现高亮效果,目前的思路是,递归后台来返回的数据,并将对象的value值替换为需要的dom节点,并且通过rich-text来实现,高亮效果。

    思路

    在实现的过程中主要考虑,不同类型的数据结构,过滤掉特殊符号,url这些基本需求;同时在实现的过程中每次都要去处理最原始的数据,这就需要考虑到对象的深拷贝问题,目前所采用的方法是通过JSON.parse(JSON.stringify(str))来处理,因为在这个全局搜索的项目中不太会用到函数这些对象。最后通过replace方法来处理这些目标字符串。

    截图

    代码

    wxml:

    
    <view class='homePage'>
        <input bindinput="bindKeyInput"></input>
        <view wx:for="{{newJson}}" wx:for-item='item' wx:key>
            <rich-text nodes="{{item.name}}"></rich-text>   
            <rich-text nodes="{{item.address}}"></rich-text>   
            <rich-text nodes="{{item.age}}"></rich-text>
            <view wx:if="{{item.aihao}}" wx:for="{{item.aihao}}" wx:for-item='sitem' wx:key>
                <rich-text nodes="{{sitem}}"></rich-text>   
            </view>
        </view>
    </view>
    复制代码

    js:

    //index.js
    //index.js
    const app = getApp()
    
    Page({
        data: {
            homeUrl: '../index/index',
            mineUrl: '../mine/mine',
            newFillUrl: '../newFill/newFill',
            historyUrl: '../historyData/historyData',
            json: [{ name: '你是谁', age: 'awdqww\\k', address: 'auemnkjkifwh{\\efwfheffoewjowef', aihao: ['sdsd', 'sdfsd', 'sdsf'] }, { name: '98797', age: '6544656', address: 'https://www.baidu.com/' }],
            newJson: '',
            tempText: '',
            showShadow: false,
            chartNumber: 0,
            newStr:''
        },
        /**
         * 生命周期函数--监听页面加载
         */
        onLoad: function (options) {
            this.setData({
                newJson: this.data.json
            })
        },
        haha: function () {
            console.log('haha');
            wx.navigateTo({
                url: '../mine/mine',
            })
        },
        digui: function (newJson, obj, key) {
            var urlReg = new RegExp('(https ?|ftp | file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]')
            var that = this;
            var reg = that.data.tempText;
            if (that.data.tempText == '.' || that.data.tempText == '\\' || that.data.tempText == '\?' || that.data.tempText == '\[' || that.data.tempText == '\]') {
                reg = '\\' + that.data.tempText
            }
            var reg = new RegExp(reg, 'ig');
            if (newJson.constructor == Array) {
                newJson.forEach(function (item, index) {
                    if (item.constructor == String && !urlReg.test(item)) {
                        obj[key].splice(index, 1, item.replace(reg, function (index) {
                            if (that.data.newStr != ''){
                                that.setData({
                                    chartNumber: (that.data.chartNumber + 1)
                                })
                            }
                            return "<span style='color:red'>" + that.data.tempText + "</span>"
                        }))
                    } else {
                        that.digui(item, newJson);
                    }
                });
            } else if (newJson.constructor == Object) {
                var json = {};
                for (var key in newJson) {
                    json[key] = newJson;
                    that.digui(newJson[key], newJson, key);
                }
            } else if (newJson.constructor == String && !urlReg.test(newJson)) { // 这里做全局替换
                if (key) {
                    obj[key] = newJson.replace(reg, function () {
                        if (that.data.newStr != '') {
                            that.setData({
                                chartNumber: (that.data.chartNumber + 1)
                            })
                        }
                        return "<span style='color:red'>" + that.data.tempText + "</span>"
                    })
                }
            }
        },
        showBgShadow: function (e) {
            this.setData({
                showShadow: e.detail.showBgShadow
            })
        },
        bindKeyInput: function (e) {
            var regChart = this.data.regChart;
            var text = e.detail.value;
            var newStr = '';
            newStr = text.replace(/[\@\#\$\%\^\&\*\{\}\:\"\L\<\>\?\\\.]/, '')
            this.setData({
                tempText: newStr,
                chartNumber: 0,
                newStr: newStr
            })
            var newJson = JSON.parse(JSON.stringify(this.data.json));
    
            this.digui(newJson);
            this.setData({
                newJson: newJson
            })
        }
    
    })
    
    
    复制代码

    转载于:https://juejin.im/post/5abc9bad5188255c272202d2

    展开全文
  • 最近在做微信小程序的时候,需要实现在搜索框的输入内容的时候实现全局匹配实现高亮效果,目前的思路是,递归后台来返回的数据,并将对象的value值替换为需要的dom节点,并且通过rich-text来实现,高亮效果。...
        

    需求

    最近在做微信小程序的时候,需要实现在搜索框的输入内容的时候实现全局匹配实现高亮效果,目前的思路是,递归后台来返回的数据,并将对象的value值替换为需要的dom节点,并且通过rich-text来实现,高亮效果。

    思路

    在实现的过程中主要考虑,不同类型的数据结构,过滤掉特殊符号,url这些基本需求;同时在实现的过程中每次都要去处理最原始的数据,这就需要考虑到对象的深拷贝问题,目前所采用的方法是通过JSON.parse(JSON.stringify(str))来处理,因为在这个全局搜索的项目中不太会用到函数这些对象。最后通过replace方法来处理这些目标字符串。

    截图

    代码

    wxml:

    
    <view class='homePage'>
        <input bindinput="bindKeyInput"></input>
        <view wx:for="{{newJson}}" wx:for-item='item' wx:key>
            <rich-text nodes="{{item.name}}"></rich-text>   
            <rich-text nodes="{{item.address}}"></rich-text>   
            <rich-text nodes="{{item.age}}"></rich-text>
            <view wx:if="{{item.aihao}}" wx:for="{{item.aihao}}" wx:for-item='sitem' wx:key>
                <rich-text nodes="{{sitem}}"></rich-text>   
            </view>
        </view>
    </view>

    js:

    //index.js
    //index.js
    const app = getApp()
    
    Page({
        data: {
            homeUrl: '../index/index',
            mineUrl: '../mine/mine',
            newFillUrl: '../newFill/newFill',
            historyUrl: '../historyData/historyData',
            json: [{ name: '你是谁', age: 'awdqww\\k', address: 'auemnkjkifwh{\\efwfheffoewjowef', aihao: ['sdsd', 'sdfsd', 'sdsf'] }, { name: '98797', age: '6544656', address: 'https://www.baidu.com/' }],
            newJson: '',
            tempText: '',
            showShadow: false,
            chartNumber: 0,
            newStr:''
        },
        /**
         * 生命周期函数--监听页面加载
         */
        onLoad: function (options) {
            this.setData({
                newJson: this.data.json
            })
        },
        haha: function () {
            console.log('haha');
            wx.navigateTo({
                url: '../mine/mine',
            })
        },
        digui: function (newJson, obj, key) {
            var urlReg = new RegExp('(https ?|ftp | file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]')
            var that = this;
            var reg = that.data.tempText;
            if (that.data.tempText == '.' || that.data.tempText == '\\' || that.data.tempText == '\?' || that.data.tempText == '\[' || that.data.tempText == '\]') {
                reg = '\\' + that.data.tempText
            }
            var reg = new RegExp(reg, 'ig');
            if (newJson.constructor == Array) {
                newJson.forEach(function (item, index) {
                    if (item.constructor == String && !urlReg.test(item)) {
                        obj[key].splice(index, 1, item.replace(reg, function (index) {
                            if (that.data.newStr != ''){
                                that.setData({
                                    chartNumber: (that.data.chartNumber + 1)
                                })
                            }
                            return "<span style='color:red'>" + that.data.tempText + "</span>"
                        }))
                    } else {
                        that.digui(item, newJson);
                    }
                });
            } else if (newJson.constructor == Object) {
                var json = {};
                for (var key in newJson) {
                    json[key] = newJson;
                    that.digui(newJson[key], newJson, key);
                }
            } else if (newJson.constructor == String && !urlReg.test(newJson)) { // 这里做全局替换
                if (key) {
                    obj[key] = newJson.replace(reg, function () {
                        if (that.data.newStr != '') {
                            that.setData({
                                chartNumber: (that.data.chartNumber + 1)
                            })
                        }
                        return "<span style='color:red'>" + that.data.tempText + "</span>"
                    })
                }
            }
        },
        showBgShadow: function (e) {
            this.setData({
                showShadow: e.detail.showBgShadow
            })
        },
        bindKeyInput: function (e) {
            var regChart = this.data.regChart;
            var text = e.detail.value;
            var newStr = '';
            newStr = text.replace(/[\@\#\$\%\^\&\*\{\}\:\"\L\<\>\?\\\.]/, '')
            this.setData({
                tempText: newStr,
                chartNumber: 0,
                newStr: newStr
            })
            var newJson = JSON.parse(JSON.stringify(this.data.json));
    
            this.digui(newJson);
            this.setData({
                newJson: newJson
            })
        }
    
    })
    
    
    展开全文
  • 在做微信高级接口开发中,或许总会碰到很多神奇的错误码,而这些错误码在官方文档中还是找不到原因,因此贴出自己开发过程中用的一些demo,希望能够给一些小伙伴指点迷津。{"errcode":45028,"errmsg":"has no ...

    在做微信高级接口开发中,或许总会碰到很多神奇的错误码,而这些错误码在官方文档中还是找不到原因,因此贴出自己开发过程中用的一些demo,希望能够给一些小伙伴指点迷津。{"errcode":45028,"errmsg":"has no masssend quota hint: [c3ZjkA0323age9]"}如遇到这个错误码,官方文档是没有查询的,这个是因为测试号没有大型数据群发配额导致,解决办法申请一个认证的订阅号或者公众号,或者测试号模式下通过openid来测试群发,最后在公众号上更换成正确的post地址,就可以实现了,只是测试号无法用分组的那个post接口而已。


    群发的步骤:


    第一步,获取access_token,这部分就不写代码了,可以参照柳峰的博客专栏
    http://blog.csdn.net/lyq8479/article/details/25076223点击打开链接
    获取到的ACCESS_TOKEN

    第二部,发送消息

    首先是准备post接口地址:

    String groupUrl = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token=ACCESS_TOKEN"; //这个地址是根据分组id来群发消息
    
    String groupUrl1 = "https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=ACCESS_TOKEN"; //这个地址是根据openid来群发消息
    由于接口调用有次数限制,测试号是200次一天,请珍惜。

    再是准备post数据:

    ①文本消息

    String group1data = "{\"filter\":{\"is_to_all\":false,\"group_id\":\"2\"},\"text\":{\"content\":\"群发消息测试\"},\"msgtype\":\"text\"}\";"; //这个是通过分组id发送的普通文本消息
    
    String openid1data = "{\"touser\":[\"obGXiwHTGN_4HkR2WToFj_3ua\",\"obGXiwNu0z2o_RRWaODvaZctd\"],\"msgtype\": \"text\",\"text\": {\"content\": \"测试文本消息\"}}";//这个是通过openid发送的普通文本消息//发送给  OPENID   为obGXiwHTGN_4HkR2WToFj_3ua和obGXiwNu0z2o_RRWaODvaZctd的两位关注公众号的微信用户,可替换成开发测试号中任意的一个用户或多个用户均可。如下图的json格式就可以,分组群发的数据格式可以查看官方文档,自己拼成java字符串就好了

    消息格式严格如上,可以参照官方文档微信官方文档,可以用JSONObject.from(Objec obj)这个来进行对象转json字符串,具体可以百度,红色字(由于颜色会影响代码美观,所以删除了)是关注当前微信公众号用户的openid

    至于如何获取用户openid这里就不赘述,参照官方文档,或者参照博主其他文章。

    ②图片消息图片消息数据准备又要分两步,关键在于     获取图片     或者说    获取media_id

    博主采用模拟表单上传方式来先上传一个临时素材文件并获取其id,代码如下:

    import java.io.BufferedReader;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    public class FileUpload {
    
    	/**
    	 * 模拟form表单的形式 ,上传文件 以输出流的形式把文件写入到url中,然后用输入流来获取url的响应
    	 * @param url
    	 *            请求地址 form表单url地址
    	 * @param filePath
    	 *            文件在服务器保存路径
    	 * @return String url的响应信息返回值
    	 * @throws IOException
    	 */
    	public String send(String url, String filePath) throws IOException {
    		String result = null;
    		File file = new File(filePath);
    		if (!file.exists() || !file.isFile()) {
    			throw new IOException("文件不存在");
    		}
    		/**
    		 * 第一部分
    		 */
    		URL urlObj = new URL(url);
    		// 连接
    		HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();
    		/**
    		 * 设置关键值
    		 */
    		con.setRequestMethod("POST"); // 以Post方式提交表单,默认get方式
    		con.setDoInput(true);
    		con.setDoOutput(true);
    		con.setUseCaches(false); // post方式不能使用缓存
    		// 设置请求头信息
    		con.setRequestProperty("Connection", "Keep-Alive");
    		con.setRequestProperty("Charset", "UTF-8");
    		// 设置边界
    		String BOUNDARY = "---------------------------" + System.currentTimeMillis();
    		con.setRequestProperty("Content-Type", "multipart/form-data; boundary="
    				+ BOUNDARY);
    		// 请求正文信息
    		// 第一部分:
    		StringBuilder sb = new StringBuilder();
    		sb.append("--"); // 必须多两道线
    		sb.append(BOUNDARY);
    		sb.append("\r\n");
    		sb.append("Content-Disposition: form-data;name=\"media\";filename=\""
    				+ file.getName() + "\"\r\n");
    		sb.append("Content-Type:application/octet-stream\r\n\r\n");
    		byte[] head = sb.toString().getBytes("utf-8");
    		// 获得输出流
    		OutputStream out = new DataOutputStream(con.getOutputStream());
    		// 输出表头
    		out.write(head);
    		// 文件正文部分
    		// 把文件以 流文件 的方式 推入到url中
    		DataInputStream in = new DataInputStream(new FileInputStream(file));
    		int bytes = 0;
    		byte[] bufferOut = new byte[1024];
    		while ((bytes = in.read(bufferOut)) != -1) {
    			out.write(bufferOut, 0, bytes);
    		}
    		in.close();
    		// 结尾部分
    		byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 最数据分隔线
    		out.write(foot);
    
    		out.flush();
    		out.close();
    
    		StringBuffer buffer = new StringBuffer();
    		BufferedReader reader = null;
    		try {
    			// 定义BufferedReader输入流来读取URL的响应
    			reader = new BufferedReader(new InputStreamReader(
    					con.getInputStream()));
    			String line = null;
    			while ((line = reader.readLine()) != null) {
    				buffer.append(line);
    			}
    			if (result == null) {
    				result = buffer.toString();
    			}
    		} catch (IOException e) {
    			System.out.println("发送POST请求出现异常!" + e);
    			e.printStackTrace();
    			throw new IOException("数据读取异常");
    		} finally {
    			if (reader != null) {
    				reader.close();
    			}
    		}
    		return result;
    	}
    
    	public static void main(String[] args) throws IOException {
    		String filePath = "C:/Users/Administrator/Desktop/1.jpg";//本地或服务器文件路径
    		String sendUrl = "http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=image";//ACCESS_TOKEN是获取到的access_token
    		String result = null;
    		FileUpload fileUpload = new FileUpload();
    		result = fileUpload.send(sendUrl, filePath);
    		System.out.println(result);
    
    	}
    }
    输出如下

    {"type":"image","media_id":"1Le_MCBJShdaL1nLirSFRkYYiEXtPTUD_uOk0D9QtNLchWiQ2MHOtkT4Rm6T9Ciy","created_at":1447392539}

    通过获取media_id,这个值也是就是后续的图文素材上传中的 thumb_media_id,这是后话。上传的图片素材是临时素材不占用永久素材容量。

    数据格式如下:

    String openid3data = "{\"touser\":[\"obGXiwHTGN_4HkR2WToFj_3ua\",\"obGXiwNu0z2o_RRWaODvaZctd\"], \"image\": {\"media_id\":\"1Le_MCBJShdaL1nLirSFRkYYiEXtPTUD_uOk0D9QtNLchWiQ2MHOtkT4Rm6T9Ciy\"},\"msgtype\":\"image\"}";
    
    
    消息格式严格如上,可以参照官方文档微信官方文档,可以用JSONObject.from(Objec obj)这个来进行对象转json字符串,具体可以百度,红色字(由于颜色会影响代码美观,所以删除了,字符串中["obGXiwHTGN_4HkR2WToFj_3ua\",\"obGXiwNu0z2o_RRWaODvaZctd\"]是关注当前微信公众号用户的openid
    ③图文消息

    图文消息需要先上传图文消息素材,

    (一)上传素材

    Post接口地址:https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token=ACCESS_TOKEN

    post数据data格式:如是java编写需要注意特殊符号转义,这个就不多讲了,用\这个转义应该都知道。
    {
       "articles": [
    		 {
                            "thumb_media_id":"qI6_Ze_6PtV7svjolgs-rN6stStuHIjs9_DidOHaj0Q-mwvBelOXCFZiq2OsIU-p",
                            "author":"xxx",
    			 "title":"Happy Day",
    			 "content_source_url":"www.qq.com",
    			 "content":"content",
    			 "digest":"digest",
                            "show_cover_pic":"1"
    		 },
    		 {
                            "thumb_media_id":"qI6_Ze_6PtV7svjolgs-rN6stStuHIjs9_DidOHaj0Q-mwvBelOXCFZiq2OsIU-p",
                            "author":"xxx",
    			 "title":"Happy Day",
    			 "content_source_url":"www.qq.com",
    			 "content":"content",
    			 "digest":"digest",
                            "show_cover_pic":"0"
    		 }
       ]
    }
    thumb_media_id是上一步中图片消息上传的临时素材media_id,这一部分代码如下:
    import net.sf.json.JSONObject;
    
    public class ImageArticleUpload {
    	public String upload(){
    		String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token=NkwaEYtrewLfkgMphjwUmnZ0l6vguB794RBhstvHUT58nLk2HMrQ3Ji9EJTD8aOyViteTyV6H1xrVLx2Myee1MUdwz0xEcw0gmlBpf6VkFoMQRfAAAQUV";//ACCESS_TOKEN是获取到的access_token
    		//上传的图文消息数据,其中thumb_media_id是文件上传图片上传的id
    		String data = "{\"articles\": [{\"thumb_media_id\":\"BW4eDIdYSvO7AFjfsZKsQ9ujNma_TkCj3VSo3JNTQkYmk_iPuhpUKm48oZ4umHED\",\"author\":\"xxx\",\"title\":\"Happy Day\",\"content_source_url\":\"www.qq.com\",\"content\":\"content\",\"digest\":\"digest\",\"show_cover_pic\":\"0\"}]}";
    		String data1 = "{\"articles\":[{\"author\":\"王传清|毕强|Wang Chuanqing|Bi Qiang\",\"content\":\"基于关联关系维度的数字资源聚合是数字资源知识发现的重要基础和工具。超网络是由多个类型的同质和异质子网络组成的网络,通过多种关联维度聚合的数字资源即形成了拥有相同以及不同性质的结点和关系的数字资源超网络,这些不同性质的关联与链接是知识关联、挖掘、发现与创新的脉络线索。结合超网络理论,构建和描述数字资源超网络,并分析超网络中不同性质的关系类型,如引用关系、共现关系、耦合关系等,从关联维度探讨数字资源深度聚合的模式,进而分析利用数字资源超网络进行知识发现的具体应用方法,最后构建数字资源超网络聚合系统模型。\",\"content_source_url\":\"http://d.g.wanfangdata.com.cn/Periodical_qbxb201501002.aspx\",\"digest\":\"测试\",\"show_cover_pic\":1,\"thumb_media_id\":\"BW4eDIdYSvO7AFjfsZKsQ9ujNma_TkCj3VSo3JNTQkYmk_iPuhpUKm48oZ4umHED\",\"title\":\"超网络视域下的数字资源深度聚合研究\"}]}";
    		JSONObject json = CommUtil.httpRequest(url, "POST", data1);
    		return json.toString();
    	}
    	public static void main(String[] args) {
    		System.out.println(new ImageArticleUpload().upload());
    	}
    }
    输出如下:

    {"type":"news","media_id":"Sf3S9D8mCM7T5TIwphe3CSAgWnXQzaDnuA7mdgX6SV1JKRGRv9Je3e7AXB8St7yy","created_at":1447394345}

    这个时候获取到的media_id就是我们要进行图文消息群发的media_id

    (二)组装数据:

    数据格式如下:

    String openid4data = "{\"touser\":[\"obGXiwHTGN_4HkR2WToFj_3ua\",\"obGXiwNu0z2o_RRWaODvaZctd\"], \"mpnews\": {\"media_id\":\"Sf3S9D8mCM7T5TIwphe3CSAgWnXQzaDnuA7mdgX6SV1JKRGRv9Je3e7AXB8St7yy\"},\"msgtype\":\"mpnews\"}";

    详情参照官方文档。微信官方文档


    接下来是voice群发,视频群发,操作差不多,官方文档比较垃圾简单的说明了如何处理数据,我就不过多介绍了。


    准备好数据后就是进行群发操作了。

    代码如下:直接拷贝的注意更改token和media_id

    import net.sf.json.JSONObject;
    
    public class SendGroupMessage {
    	public String sendGroupMessage(){
    		String groupUrl = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token=ACCESS_TOKEN";//ACCESS_TOKEN是获取到的access_token,根据分组id发群发消息地址
    		String groupUrl1 = "https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=NkwaEYtrewLfkgMphjwUmnZ0l6vguB794RBhstvHUT58nLk2HMrQ3Ji9EJTD8aOyViteTyV6H1xrVLx2Myee1MUdwz0xEcw0gmlBpf6VkFoMQRfAAAQUV";//根据openid发群发消息地址
    		String group1data = "{\"filter\":{\"is_to_all\":false,\"group_id\":\"2\"},\"text\":{\"content\":\"群发消息测试\"},\"msgtype\":\"text\"}\";";
    		String openid1data = "{\"touser\":[\"obGXiwHTGN_4HkR2WToFj_3uaEKY\",\"obGXiwNu0z2o_RRWaODvaZctdWEM\"],\"msgtype\": \"text\",\"text\": {\"content\": \"测试文本消息\"}}";
    		String openid2data = "{\"touser\":[\"obGXiwHTGN_4HkR2WToFj_3uaEKY\",\"obGXiwNu0z2o_RRWaODvaZctdWEM\"], \"voice\": {\"media_id\":\"UfMRvSiXAD5_iUS8u0Gc3JrKGWOABE9ivQbgrX6i-mVrKGBRL9KnKlioK1BxTPc3\"},\"msgtype\":\"voice\"}";
    		String openid3data = "{\"touser\":[\"obGXiwHTGN_4HkR2WToFj_3uaEKY\",\"obGXiwNu0z2o_RRWaODvaZctdWEM\"], \"image\": {\"media_id\":\"fNUzGbYzTRui4N7-eyx9e3viP8uJuzztAvA32lIdjX4Cucj7mGN_1jpWjn7O80c8\"},\"msgtype\":\"image\"}";
    		String openid4data = "{\"touser\":[\"obGXiwHTGN_4HkR2WToFj_3uaEKY\",\"obGXiwNu0z2o_RRWaODvaZctdWEM\"], \"mpnews\": {\"media_id\":\"6I8DOB-7rJsY_zdOCe6YJKJ59MwXWPb2iYBKVqb22cBHPtECYdRgiWIULfCW-hcF\"},\"msgtype\":\"mpnews\"}";
    		JSONObject json = CommUtil.httpRequest(groupUrl1, "POST", openid4data);
    		return json.toString();
    	}
    	public static void main(String[] args) {
    		System.out.println(new SendGroupMessage().sendGroupMessage());
    	}
    }
    运行代码如下:

    {"errcode":0,"errmsg":"send job submission success","msg_id":2548581905,"msg_data_id":401097527}

    这个时候表示群发成功,大功告成。

    当然,博主不会漏掉那个工具类的代码的,代码如下:

    import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.ConnectException;
    import java.net.URL;
    
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSocketFactory;
    import javax.net.ssl.TrustManager;
    
    import net.sf.json.JSONException;
    import net.sf.json.JSONObject;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.pojo.AccessToken;
    import com.pojo.BindPhone;
    import com.pojo.JsapiTicket;
    import com.pojo.Menu;
    import com.thread.TokenThread;
    
    /**
     * 
     * @Description: 公众平台通用接口工具类
     * @Package Name: com.util
     * @ClassName: CommUtil
     * @author heboy
     * @date 2015年9月8日 下午2:21:56
     */
    public class CommUtil {
    	private static Logger log = LoggerFactory.getLogger(CommUtil.class);
    	// 获取access_token的接口地址(GET) 限200(次/天)
    	public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    	public final static String jsapi_ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
    	
    	/**
    	 * 发起https请求并获取结果
    	 * 
    	 * @param requestUrl 请求地址
    	 * @param requestMethod 请求方式(GET、POST)
    	 * @param outputStr 提交的数据
    	 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
    	 */
    	public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
    		JSONObject jsonObject = null;
    		StringBuffer buffer = new StringBuffer();
    		try {
    			// 创建SSLContext对象,并使用我们指定的信任管理器初始化
    			TrustManager[] tm = { new MyX509TrustManager() };
    			SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
    			sslContext.init(null, tm, new java.security.SecureRandom());
    			// 从上述SSLContext对象中得到SSLSocketFactory对象
    			SSLSocketFactory ssf = sslContext.getSocketFactory();
    
    			URL url = new URL(requestUrl);
    			HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
    			httpUrlConn.setSSLSocketFactory(ssf);
    
    			httpUrlConn.setDoOutput(true);
    			httpUrlConn.setDoInput(true);
    			httpUrlConn.setUseCaches(false);
    			// 设置请求方式(GET/POST)
    			httpUrlConn.setRequestMethod(requestMethod);
    
    			if ("GET".equalsIgnoreCase(requestMethod))
    				httpUrlConn.connect();
    
    			// 当有数据需要提交时
    			if (null != outputStr) {
    				OutputStream outputStream = httpUrlConn.getOutputStream();
    				// 注意编码格式,防止中文乱码
    				outputStream.write(outputStr.getBytes("UTF-8"));
    				outputStream.close();
    			}
    
    			// 将返回的输入流转换成字符串
    			InputStream inputStream = httpUrlConn.getInputStream();
    			InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
    			BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
    
    			String str = null;
    			while ((str = bufferedReader.readLine()) != null) {
    				buffer.append(str);
    			}
    			bufferedReader.close();
    			inputStreamReader.close();
    			// 释放资源
    			inputStream.close();
    			inputStream = null;
    			httpUrlConn.disconnect();
    			jsonObject = JSONObject.fromObject(buffer.toString());
    		} catch (ConnectException ce) {
    			log.error("Weixin server connection timed out.");
    		} catch (Exception e) {
    			log.error("https request error:{}", e);
    		}
    		return jsonObject;
    	}
    
    	/**
    	 * 
    	 * @Description: 获取access_token
    	 * @param appid 
    	 * @param appsecret 
    	 * @Title: getAccessToken
    	 * @return AccessToken    
    	 * @date: 2015年9月8日 下午2:23:01
    	 * @author heboy
    	 */
    	public static AccessToken getAccessToken(String appid, String appsecret) {
    		AccessToken accessToken = null;
    
    		String requestUrl = access_token_url.replace("APPID", appid).replace("APPSECRET", appsecret);
    		JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
    		// 如果请求成功
    		if (null != jsonObject) {
    			try {
    				accessToken = new AccessToken();
    				accessToken.setToken(jsonObject.getString("access_token"));
    				accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
    			} catch (JSONException e) {
    				accessToken = null;
    				// 获取token失败
    				log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
    			}
    		}
    		return accessToken;
    	}
    	
    	// 菜单创建(POST) 限100(次/天)
    	public static String menu_create_url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
    
    	/**
    	 * 创建菜单
    	 * 
    	 * @param menu 菜单实例
    	 * @param accessToken 有效的access_token
    	 * @return 0表示成功,其他值表示失败
    	 */
    	public static int createMenu(Menu menu, String accessToken) {
    		int result = 0;
    
    		// 拼装创建菜单的url
    		String url = menu_create_url.replace("ACCESS_TOKEN", accessToken);
    		// 将菜单对象转换成json字符串
    		String jsonMenu = JSONObject.fromObject(menu).toString();
    		// 调用接口创建菜单
    		JSONObject jsonObject = httpRequest(url, "POST", jsonMenu);
    
    		if (null != jsonObject) {
    			if (0 != jsonObject.getInt("errcode")) {
    				result = jsonObject.getInt("errcode");
    				log.error("创建菜单失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
    			}
    		}
    
    		return result;
    	}
    	/**
    	 * 
    	 * @Description: 获取js票据
    	 * @Title: getJsapiTicket
    	 * @return JsapiTicket    
    	 * @date: 2015年9月11日 上午10:48:07
    	 * @author heboy
    	 */
    	public static JsapiTicket getJsapiTicket(String tocken){
    		JsapiTicket jsapiTicket = null;
    		String requestUrl = jsapi_ticket_url.replace("ACCESS_TOKEN", tocken);
    		JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
    		// 如果请求成功
    		if (null != jsonObject) {
    			try {
    				jsapiTicket = new JsapiTicket();
    				jsapiTicket.setTicket(jsonObject.getString("ticket"));
    				jsapiTicket.setExpiresIn(jsonObject.getInt("expires_in"));
    			} catch (JSONException e) {
    				jsapiTicket = null;
    				// 获取token失败
    				log.error("获取jsapi_ticket失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
    			}
    		}
    		return jsapiTicket;
    	}
    }


    展开全文
  • 同时欢迎大家加入微信商城开发QQ群:364072602,共同探讨进步。   为什么叫不写代码玩转微信公众号呢? 我们大家都知道,微信公众号有两种模式,一种是编辑模式,一种是开发模式。所谓的不写代码玩转微信...
  • 本文就是用这个小工具完成的哦。 操作过公众号后台的朋友肯定知道,微信的编辑器是很简易的,这也不叫缺陷吧,毕竟微信团队的主张一直就是简洁。但是这个编辑器是可以粘贴带格式的html的,所以就给我们留下...
  • 微信公众账号开发

    2014-02-27 15:00:52
    微信开发 微信公众平台开发(82) 天气预报 摘要: 在这篇教程中,我们将介绍如何在微信公众平台上开发天气预报功能。我们将使用中国天气网的气象数据接口来获取天气信息。这篇教程将介绍以下内容:获取...
  • Java开发微信公众号

    2017-12-14 22:25:35
    1.首先需要注册,https://mp.weixin.qq.com/,...比较方便,如果是比较复杂的,就需要接入自己的服务器,自己后台连上微信服务器获取数据,处理得到结果后再返回给微信服务器,微信服务器再发给手机2.注册后,在开发 -
  • 一、注册微信公众平台 微信公众平台官网 https://mp.weixin.qq.com/,点击注册 ... ... 如果对公众号没特别要求直接操作公众平台就可以了,这里主要介绍java后台开发者调用微信接口的操作。 ...
  • 微信公众平台开发

    2014-01-18 11:18:26
    微信公众平台开发(80) 上传下载多媒体文件 摘要: 微信公众账号在回复图片、语音、视频的时候,将使用media_id来调用相关文件,很多朋友咨询这个如何开发实现。本文将介绍在微信公众平台开发过程中,如何上传...
  • 转自:http://blog.csdn.net/gueter/archive/2007/03/08/1524447.aspx Author :Jeffrey引言HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速...它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。...
  • 考虑到歌曲名称有重复的情况,用户还可以同时指定歌曲名称、演唱者搜索歌曲。下面就为读者详细介绍歌曲点播功能的实现过程。 音乐消息说明 在微信公众平台开发者文档中提到,向... ToUserName>ToUserNa
  • 微信公众平台消息接口 微信公众平台开发 微信公众平台开发模式 快递查询 作者:方倍工作室原文:http://www.cnblogs.com/txw1958/archive/2013/03/12/weixin-if7-express.html   一、请求数据 快递100提供快递...
  • ylbtech-微信-小程序-开发文档-开发开发 1. 开发指南返回顶部 1.1、 小程序提供了一个简单、高效的应用开发框架和丰富的组件及API,帮助开发者在微信开发具有原生 APP 体验的服务。 ...
  • 开发工具: Spring Tool Suite JS框架:jQuery Mobile 下载必要的资源: Spring Tool Suite; jQuery Mobile脚本库; 在STS中运行实例: 新建Maven项目; 配置pom.xml以便加载S...
  • 在前几节文章中我们讲述了微信公众号环境的搭建、如何接入微信公众平台、以及微信服务器请求消息,响应消息,事件消息以及工具处理类的封装;接下来我们重点说一下-微信服务器post消息体的接收及消息的处理,这个...
  • 在这里可以通过微信渠道将品牌推广给上亿的微信用户,减少宣传成本,提高品牌知名度,打造更具影响力的品牌形象。 初始微信公众平台 官方网址 https://mp.weixin.qq.com/cgi-bin/loginpage?t=wxm2-login&amp...
1 2 3 4 5 ... 20
收藏数 2,172
精华内容 868
关键字:

微信开发工具输入特殊符号