• 发送消息,是指用户公众号向用户发送相应形式的消息。根据微信开发文档,由以下四种形式:被动回复,群发接口,客服消息接口以及模板消息接口。...这一部分较为简单,正式进行微信开发的第一步就是,在公众号中基本

    发送消息,是指用户公众号向用户发送相应形式的消息。根据微信开发文档,由以下四种形式:被动回复,群发接口,客服消息接口以及模板消息接口。本文将基于Java语言以及个人微信测试号,说明被动回复、客服消息接口以及模板消息接口的使用实现,群发接口并未涉及。
    1. 被动回复
    被动回复只能应用于在接收到用户的互动数据之后,才能向用户发送消息。这一部分较为简单,正式进行微信开发的第一步就是,在公众号中基本配置->服务器配置中设置URL(服务器地址)时,这时该URL链接指定的地址就是对应着Java Web下的一个Servlet,配置好对应的Token及相关参数之后,则微信服务器将会将所有的用户与公众号的互动信息都转发到该Servlet,然后开发者根据接收到的用户互动数据,再进行处理。所谓的被动回复,就是在该Servlet中判断接收到你指定的消息时(例如某个字眼),则直接将想要回复的消息打包成官方指定的XML数据格式,写回到输出流中即可。在这里不过过多解释,如下示例代码:

    response.getWriter().write( MessageUtil.MessageToXML(new TextMessage.Builder(fromUserName,toUserName,new Date().getTime(),"最新资讯请查看下方微信菜单栏,谢谢您的关注").build()));

    2.客服消息接口
    客服消息接口,应用于公众号主动向特定用户(必须满足该用户在48小时内与公众号有交互)发送特定格式的消息,应用场景例如:用户在微页面上完成了抽奖,而这时候公众号主动向用户推送中奖信息。所回复的不同消息的格式,参见开发者文档,下面以回复文本消息作为示例,需要注意的是推送的消息data必须满足json格式,请求类型为post。返回的json数据中,若errorcode为0,则代表推送成功。

     //推送中奖消息
            String data = "{"+
                    "\"touser\":\""+openid+"\","+
                    "\"msgtype\":\"text\","+
                    "\"text\":"+
                    "{"+
                    "\"content\":\""+content+"\""+
                    "}"+
                    "}";
            System.out.println(data);
            String reMsg0 = UrlReqUtil.post("https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token="+access_token,data);
            JSONObject jsonObject = JSONObject.fromObject(reMsg0);
            if(0 != (Integer) jsonObject.get("errcode")) throw new RuntimeException("通知用户失败");

    3.模板消息接口
    模板消息接口的使用场景大体与客服消息接口一致,只是不需要证明对象用户“在线”,即48小时内与当前公众号有交互记录,因而应用范围更为广泛。在具有权限的服务号中使用该接口时,需要向系统申请对应模板,并得到模板号,作为调用凭据。在测试号环境下,则需要自定义模板。例如:
    这里写图片描述
    其中模板内容需要严格遵循指定的格式,即在需要调用才填入的变量值的定义方式为:{{xxxx.DATA}},其中“xxxx”为调用时对应的字段名。
    以下是调用代码:jsonData数据部分遵循json数据格式。
    其中touser:为用户在该公众号下的openid
    template_id:为模板id
    对于每个字段,包含两个值,一是value,即填入模板的具体值;二是color,即对应的字体颜色。
    请求方式为post,判断是否成功同样是依据errcode字段,为0则成功。

            //推送模板消息
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            String jsonData = "{" +
                    "\"touser\":\""+openid+"\"," +
                    "\"template_id\":\"maD2W1yaTvkXmh1dRjXEsMHUc9dDP8Xh1eANP***ig\"," +
                    "\"topcolor\":\"#FF0000\"," +
                    "\"data\":{" +
                    "\"title\":{\"value\":\"恭喜您中奖啦\",\"color\":\"#173177\"}," +
                    "\"nickname\":{\"value\":\""+nickname+"\",\"color\":\"#173177\"}," +
                    "\"prizeLevel\":{\"value\":\""+rewardLevel+"\",\"color\":\"#173177\"}," +
                    "\"prizeContent\":{\"value\":\""+ ConfigParamUtil.PRIZE_CONTENT.split(",")[rewardLevel]+"\",\"color\":\"#173177\"}," +
                    "\"time\":{\"value\":\""+dateFormat.format(new Date())+"\",\"color\":\"#173177\"}," +
                    "\"bonus\":{\"value\":\"10积分\",\"color\":\"#173177\"}}}";
            String reMsg1 = UrlReqUtil.post("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+access_token,jsonData);
            JSONObject jsonObject = JSONObject.fromObject(reMsg1);
            if(0 != (Integer) jsonObject.get("errcode")) throw new RuntimeException("通知用户失败");
    展开全文
  • 微信提供的api,对于针对用户openid发消息的话,没有向所有关注者群发消息的接口,但提供了向单一用户和多用户发文本消息的接口,我们可以基于此开发向所有用户群发消息的接口。 补充:后面我发现其实可以有更好的...

    本文目录 :

    1. 给单一用户发文本消息
    2. 给多个用户发文本消息
    3. 给所有用户发文本消息
    4. 有更好的方案吗?
    5. 遇到的问题
    6. 小结


    微信提供的api,对于针对用户openid发消息的话,没有向所有关注者群发消息的接口,但提供了向单一用户和多用户发文本消息的接口,我们可以基于此开发向所有用户群发消息的接口。
    补充:后面我发现其实可以有更好的实现方案,详看 ‘有更好的方案吗?‘。

    文中遇到部分的接口请查看上一文:

    微信开发之获取用户详细列表


    1、 给单一用户发文本消息

    微信开发文档入口:

    客服接口-发消息

    我的代码接口:

    /**
     * 向一个粉丝发送消息
     */
    public function sendMsgToOne($openid, $content)
    {
        $access_token = $this->getAccessToken();
        if (!$access_token) {
            return false;
        }
    
        $url ="https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={$access_token}";
        $post_arr = [
                        'touser' => $openid,
                        'msgtype' => 'text',
                        'text' => ['content'=>$content]
                    ];
        $post_str = json_encode($post_arr, JSON_UNESCAPED_UNICODE);
        $return = httpRequest($url, 'POST', $post_str);
        $wxdata = json_decode($return, true);
        if (isset($wxdata['errcode']) && $wxdata['errcode'] != 0) {
            $this->setError('微信错误码:'.$wxdata['errcode'].',错误信息:'.$wxdata['errmsg']);
            return false;
        }
    
        return true;
    }


    2、 给多个用户发文本消息

    微信开发文档入口:

    根据OpenID列表群发【订阅号不可用,服务号认证后可用】

    我的代码接口:

    /**
     * 指定一部分人群发消息
     * @param array $openids
     * @param string $content
     * @return boolean
     */
    public function sendMsgToMass($openids, $content)
    {
        $access_token = $this->getAccessToken();
        if (!$access_token) {
            return false;
        }
    
        $url ="https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token={$access_token}";
        $post_arr = [
                        'touser' => $openids,
                        'msgtype' => 'text',
                        'text' => ['content'=>$content]
                    ];
        $post_str = json_encode($post_arr, JSON_UNESCAPED_UNICODE);
        $return = httpRequest($url, 'POST', $post_str);
        $wxdata = json_decode($return, true);
        if (isset($wxdata['errcode']) && $wxdata['errcode'] != 0) {
            $this->setError('微信错误码:'.$wxdata['errcode'].',错误信息:'.$wxdata['errmsg']);
            return false;
        }
    
        return true;
    }


    3、 给所有用户发文本消息

    利用上面的两个接口,实现一个统一的接口,如下:
    下面接口入参$openids支持数组和字符串,字符串支持多个openid用连接,具体请看代码吧。

    /**
     * 发送消息,自动识别id数
     * @param string or array $openids
     * @param string $content
     * @return boolean
     */
    public function sendMsg($openids, $content)
    {
        if (empty(openids)) {
            return true;
        }
        if (is_string($openids)) {
            $openids = explode(',', $openids);
        }
    
        if (count($openids) > 1) {
            $result = $this->sendMsgToMass($openids, $content);
        } else {
            $result = $this->sendMsgToOne($openids[0], $content);
        }
    
        if ($result === false) {
            return false;
        }
    
        return true;
    }

    下面实现向所有用户群发消息, 使用的时候请判断接口返回是否为false,若是,可用getError()获取详细错误信息,具体可参考上一文 微信开发之获取用户详细列表

    /**
     * 给所有粉丝发消息
     * @param string $content
     * @return boolean
     */
    public function sendMsgToAll($content)
    {
        $next_openid = '';
        do {
            $id_list = $this->getFanIdList($next_openid);
            if ($id_list === false) {
                return false;
            }
    
            $result = $this->sendMsg($id_list['data']['openid'], $content);
            if ($result === false) {
                return false;
            }
    
            $next_openid = $id_list['next_openid'];
        } while($id_list['count']);
    
        return true;
    }


    4、 有更好的方案吗?

    微信开发文档入口:

    根据标签进行群发【订阅号与服务号认证后均可用】

    我一直以为微信没有提供直接向所有用户群发的接口,其实是有的!
    在上面的微信文档中,我发现,这个接口竟然被归类在根据标签进行群发里面。不过不需要用标签这个概念,里面有个关键的变量是is_to_all,把它置为 true 即可。
    这样子可以节省上一接口中的相关api的调用次数,更能提高web响应的性能!

    我的代码接口:

    /**
     * 给所有粉丝发消息
     * @param string $content
     * @return boolean
     */
    public function sendMsgToAll($content)
    {
        $access_token = $this->getAccessToken();
        if (!$access_token) {
            return false;
        }
    
        $url ="https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token={$access_token}"; 
        $post_arr = [
                        'filter' => ['is_to_all'=>true, 'tag_id'=>0],
                        'msgtype' => 'text',
                        'text' => ['content'=>$content]
                    ];
        $post_str = json_encode($post_arr, JSON_UNESCAPED_UNICODE);
        $return = httpRequest($url, 'POST', $post_str);
        $wxdata = json_decode($return, true);
        if ($this->checkError($wxdata, $url)) {
             return false;
        }
    
        return true;
    }


    5、 遇到的问题

    在向单一用户发消息的时候,遇到报45015错误的接收报文:

    {
        "errcode":45015,
        "errmsg":"response out of time limit or subscription is canceled hint: [***]"
    }

    原因是当用户微信不活跃时间超过48小时,不会将信息推送到用户微信公众号。

    : 上面说法来源于腾讯官方,评论区园友实际测试也是,谢谢这位朋友指出。
    为了验证这个说法的正确性,我试着先向公众号发个信息,果然公众号可以向单一用户推送消息了。


    小结

    简单利用微信向单一用户和多用户的发消息接口,实现向所有用户群发消息,但利用标签接口群发效率回更好哦。其他的语音、图文等消息发送也是类似的。


    主要参考文档

    微信开发文档:https://mp.weixin.qq.com/wiki

    -end-

    展开全文
  • 收到很多童鞋的咨询,利用微信公众号的接口能不能某个用户发送消息呢,如果说直接发送呢那还真有些限制,一个是客服消息接口,但是这个需要用户在48小时内和公众号有互动才可以发送。另外一个就是微信的模板消息,...

    收到很多童鞋的咨询,利用微信公众号的接口能不能给某个用户发送消息呢,如果说直接发送呢那还真有些限制,一个是客服消息接口,但是这个需要用户在48小时内和公众号有互动才可以发送。另外一个就是微信的模板消息,这个没有发送时间限制,但是微信为了防止一些垃圾数据需要使用模板才可以发送。相信我们平时也收到很多模板消息,实际效果如下:

     这种微信模板消息的效果如何实现呢?

    首先需要在微信公众平台后台的"功能"菜单中选择模板消息,如果菜单中没有模板消息,需要点击功能插件进行添加,如下图:

    添加插件之后可以在模板库中选择模板使用,当然也可以创建模板,一般来说模板库中已经够用了,选择模板后一定要记住模板ID,这在后续的PHP程序中要用到。

    接下来说一下接口的调用规则:

    http请求方式: POST
    https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN

    发送什么格式的数据呢?发送的数据为json格式,以如下模板为例:

    JSON格式如下:

    {
    	"touser": "这里是接收用户的OPENID",
    	"template_id": "这里是模板ID",
    	"url": "这里是点击详情后跳转的网址",
    	"data": {
    		"first": {
    			"value": "您好!有访客访给您留言了。",
    			"color": "#173177"
    		},
    		"user": {
    			"value": "张三",
    			"color": "#FF0000"
    		},
    		"ask": {
    			"value": "您好,非常关注黎明互联,有没有关于支付宝的视频教程?",
    			"color": "#173177"
    		},
    		"remark": {
    			"value": "该用户已注册12天",
    			"color": "blue"
    		}
    	}
    }

    数据格式现在我们明白了,那么如何使用PHP发送到服务器呢,另外在代码里面JSON只能定义成数据拼接完成的字符串吗?如果不熟悉字符串或者不喜欢用字符串可以用数组转换,下面以数组为例给出PHP代码片段实现微信模板消息:

    class WxTmp
    {
        //请求模板消息的地址
        const TEMP_URL = 'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=';
        public function getAccessToken(){
            //这里获取accesstoken  请根据自己的程序进行修改
            return $access_token;
        }
        /**
        * 微信模板消息发送
        * @param $openid 接收用户的openid
        * return 发送结果
        */
        public function send($openid){
            $tokens = $this->getAccessToken();
            $url = self::TEMP_URL . $tokens;
            $params = [
                'touser' => $openid,
                'template_id' => 'Oblr5uXH_fS79gMC8E0mYz0CpUAHnJtdvAC3PWABrsk',//模板ID
                'url' => 'https://www.liminghulian.com/course/3/lesson/list', //点击详情后的URL可以动态定义
                'data' => 
                        [
                          'first' => 
                             [
                                'value' => '您好!有访客访给您留言了。',
                                'color' => '#173177'
                             ],
                          'user' => 
                             [
                                'value' => '张三',
                                'color' => '#FF0000'
                             ],
    
                          'ask' => 
                             [
                                    'value' => '您好,非常关注黎明互联,有没有关于支付宝的视频教程?',
                                    'color' => '#173177'
                             ],
                           'remark' => 
                             [
                                    'value' => '该用户已注册12天',
                                    'color' => 'blue'
                             ] 
                          ]
            ]; 
            $json = json_encode($params,JSON_UNESCAPED_UNICODE);
            return $this->curlPost($url, $json);
        }
        /**
        * 通过CURL发送数据
        * @param $url 请求的URL地址
        * @param $data 发送的数据
        * return 请求结果
        */
        protected function curlPost($url,$data)
        {
            $ch = curl_init();
            $params[CURLOPT_URL] = $url;    //请求url地址
            $params[CURLOPT_HEADER] = FALSE; //是否返回响应头信息
            $params[CURLOPT_SSL_VERIFYPEER] = false;
    	    $params[CURLOPT_SSL_VERIFYHOST] = false;
            $params[CURLOPT_RETURNTRANSFER] = true; //是否将结果返回
            $params[CURLOPT_POST] = true;
            $params[CURLOPT_POSTFIELDS] = $data;
            curl_setopt_array($ch, $params); //传入curl参数
            $content = curl_exec($ch); //执行
            curl_close($ch); //关闭连接
            return $content;
        }
    }
    
    $obj = new WxTmp();
    $openid = '接收模板信息的用户的openid';
    echo $obj->send($openid);

     

    展开全文
  • 微信开发文档:   客服接口-发消息   接口调用请求说明 http请求方式: POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN 各消息类型所需的JSON数据包如下: 发送...

    微信开发文档:

     

    客服接口-发消息

     

    接口调用请求说明

    http请求方式: POST
    https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
    

    各消息类型所需的JSON数据包如下:

    发送文本消息

    {
        "touser":"OPENID",
        "msgtype":"text",
        "text":
        {
             "content":"Hello World"
        }
    }

    创建封装实体类:

    
    import java.util.Map;
    
    /**
     * 客户接口消息发送实体
     *
     * @author 
     * @date 2018-2-6 11:00:30
     */
    public class TestMessage {
    
        //openid
        private String touser;
    
        //消息类型
         private String msgtype;
    
         //消息内容
         private Map<String,Object> text ;
    
    
        public String getTouser() {
            return touser;
        }
    
        public void setTouser(String touser) {
            this.touser = touser;
        }
    
        public String getMsgtype() {
            return msgtype;
        }
    
        public void setMsgtype(String msgtype) {
            this.msgtype = msgtype;
        }
    
        public Map<String, Object> getText() {
            return text;
        }
    
        public void setText(Map<String, Object> text) {
            this.text = text;
        }
    }
    

     

     

     

    后台controller代码:

     

    
     
    
     
    /**
     * 状态修改为测试中
     *
     * @param id 要测试的ID
     * @param request
     * @return 内容展示页面
     */
    @ResponseBody
    @RequestMapping(value = "/service/test", method = RequestMethod.PUT)
    public ResponseVO ContentTest(Long id, HttpServletRequest request) {
    
        ResponseVO vo=new ResponseVO();
        if(id!=null){
            //根据接收的ID查询相应的内容实体
            WeixinContent weixinContent = weixinContentService.selectById(id);
         //判断查询到的对象的合法性
        if (weixinContent!=null&&(weixinContent.getState() == 1||weixinContent.getState()==4)) {
            //修改内容实体状态为测试中
            weixinContent.setState(2);
    
            //将内容实体进行保存操作
            weixinContentService.updateById(weixinContent);
            //获得内容静态页面的访问路径
           String templatesUrl= weixinContent.getTemplatesUrl();
            //拼接访问的完整路径
            String saveUrl =fileuploadPrefix + "/" + templatesUrl;
            //获得内容信息标题
            String title = weixinContent.getTitle();
            //拼接发送的消息内容
            String content="你好!标题("+title+")<a href='"+saveUrl+"'>点我测试</a>";
            //创建微信用户查询条件
            Wrapper<WeixinUser> wrapper=new EntityWrapper<>();
            wrapper.where("tagid_list={0}","[101]");
            //获得满足条件的集合
            List<WeixinUser> weixinUsers = weixinUserService.selectList(wrapper);
            //遍历用户集合调用业务层进行消息发送
            for (WeixinUser weixinUser : weixinUsers) {
                String openid = weixinUser.getOpenid();
                //调用业务层进行发送消息
                wxContentTextService.contentTest(openid,content);
            }
    
            vo.setSuccess(true);
        } else {
            //不是未测试状态所以不能进行状态修改
            vo.setSuccess(false);
        }
    
        }
        return vo;
    }
    

    后台service代码:

    
     
    /**
     * <p>
     * 菜单信息 服务实现类
     * </p>
     *
     * @author 
     * @date 2018/01/15
     */
    @Service
    public class WxContentTextService {
    
        private static Logger log = LoggerFactory.getLogger(WxContentTextService.class);
    
        /**
         * 客服接口给用户发送消息接口
         */
        public static String  content_openid="https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN";
    
        @Autowired
        private TokenFeignService tokenFeignService;
    
        @Autowired
        private WeixinPortalService weixinPortalService;
    
        /**
         *
         * @param openid   openid
         * @param saveUrl   静态页面访问地址
         * @return
         */
        public ResponseVO contentTest(String openid,String saveUrl){
            //获得令牌
            String accessToken = tokenFeignService.getToken();
    
            //创建返回实体对象
            ResponseVO vo = new ResponseVO();
            //替换token
            String url=content_openid.replace("ACCESS_TOKEN", accessToken);
    
            TestMessage testMessage=new TestMessage();
            //设置消息的类型
            testMessage.setMsgtype("text");
            //设置要发送的openid集合
            testMessage.setTouser(openid);
            //创建集合
            Map<String,Object> map=new HashMap<>();
            //设置发送内容
            map.put("content",saveUrl);
            testMessage.setText(map);
            //将测试消息对象转成json
            String jsonTestMessage = JSONObject.toJSONString(testMessage);
            //调用接口进行发送
            JSONObject jsonObject = httpRequest(url, "POST", jsonTestMessage);
    
            log.error("分组群发消息失败 errcode:{" + jsonObject.getInteger("errcode")+"} " +
                    "errmsg:{"+jsonObject.getString("errmsg")+"} ");
            Integer errcode = jsonObject.getInteger("errcode");
            String errorCodeText = ErrorCodeText.errorMsg(errcode);
    
            if (errcode == 0){
                vo.setSuccess(true);
            }else{
                vo.setSuccess(false);
            }
            vo.setCode(errcode);
            vo.setText(errorCodeText);
            return vo;
    
        }
    }
    

    获取token的业务层:

    import org.springframework.cloud.netflix.feign.FeignClient;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    /**
     * 进行请求分发
     *
     */
    @FeignClient(value = "weixin-2")
    public interface TokenFeignService {
    
        /**
         * 进行token请求
         * @param
         * @return
         */
        @RequestMapping(value = "/getToken",method = RequestMethod.GET)
        String getToken();
    }
    

    微信请求工具类utils

    
     
    public class WeixinHttpUtil {
    
        private static Logger log = LoggerFactory.getLogger(WeixinHttpUtil.class);
    
        /**
         * 描述:  发起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.parseObject(buffer.toString());
            } catch (ConnectException ce) {
                log.error("Weixin server connection timed out.");
            } catch (Exception e) {
                log.error("https request error:{}", e);
            }
            return jsonObject;
        }
    }
    
    
     

    应网友要求贴出获取token部分代码,首先要配置公众号相关配置

    1.IP白名单

    2.配置开发模式

    3.在自己配置的白名单服务器就可以获取token,根据自己配置的服务器接口就可以监听所有公众号的操作,从而得到操作用户信息和具体操作内容

    3.1这个就是通过springCloud远程调用获取token接口

    @Controller
    @RequestMapping("")
    public class WeixinTokenController {
    
        @Autowired
        private WeixinAccessTokenTask weixinAccessTokenTask;
    
        @RequestMapping("getToken")
        @ResponseBody
        public String getToken(){
            AccessToken token = weixinAccessTokenTask.getLastAccessToken();
            return token.getAccessToken();
        }
    
    }

    3.2具体获取token业务

    @Component
    public class WeixinAccessTokenTask implements ApplicationListener {
    
        protected final static Logger logger = LoggerFactory.getLogger(WeixinAccessTokenTask.class);
    
        private static boolean isStart = false;
    
        /**
         * 微信Access_Token刷新地址
         */
        private String uri = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
        /**
         * 存放Access_Token的标识符
         */
        private String tokenKey = "WEIXIN_ACCESS_TOKEN";
        /**
         *  最近一次的Access_Token
         */
        private AccessToken lastAccessToken;
    
        /**
         * 微信分配的appID
         */
        @Value("${app.id}")
        private String appID;
        /**
         * 微信分配的appsecret
         */
        @Value("${app.secrect}")
        private String appsecrect;
    
        private long lastRunTime;
    
        /**
         * 刷新Access_Token
         * @return boolean 刷新是否成功
         */
        @Scheduled(cron="0 0/5 * * * ?")
        public boolean refresh(){
            boolean refresh = this.refresh(false);
            //重置最后一次定时器运行时间
            lastRunTime = System.currentTimeMillis();
            return refresh;
        }
    
    
        /**
         * 刷新Access_Token
         * @param forced 是否强制
         * @return boolean 刷新是否成功
         */
        public boolean refresh(boolean forced){
            if(!(forced || this.isNeedRefresh())){
                return false;
            }
    
            try {
                AccessToken token = this.getWeixinAccessToken();
                //把token存入lastAccessToken,便于下次检验token是否有效
                lastAccessToken = token;
                return true;
            } catch (IOException e){
                e.printStackTrace();
            }
            return false;
        }
        /**
         * 请求微信接口获取最新的access_token信息
         * @return AccessToken
         */
        public AccessToken getWeixinAccessToken() throws IOException{
            String uri = this.uri.replace("APPID",
                    this.getAppID()).replace("APPSECRET",
                    this.getAppsecrect());
            URL url = new URL(uri);
    
            HttpURLConnection conn = null;
            BufferedReader reader = null;
            StringBuffer buffer = new StringBuffer();
            try{
                conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.connect();
                reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    
                String line;
                while ((line = reader.readLine()) != null) {
                    buffer.append(line);
                }
            }finally {
                if(reader != null){
                    reader.close();
                }
    
                if(conn != null){
                    conn.disconnect();
                }
            }
            //返回的参数是json格式
            JSONObject jsonObject = JSONObject.parseObject(buffer.toString());
            AccessToken token = new AccessToken();
            if (!jsonObject.containsKey("access_token")) {//如果没拿到token,肯定发生了问题,打印错误日志
                logger.info(jsonObject.toJSONString());
            }
            String accessToken = jsonObject.getString("access_token");
            String expiresInStr = jsonObject.getString("expires_in");
            int expiresIn = Integer.parseInt(expiresInStr);
            token.setAccessToken(accessToken);
            token.setExpiresIn(expiresIn);
            //设置token的更新时间
            token.setUpdateTime(new Date());
            logger.info("最新的token>>>> "+ AesUtil.aesEncrypt(accessToken));
            return token;
        }
    
        /**
         *  是否需要刷新
         *
         *  @return boolean 判断是否需要刷新
         */
        private boolean isNeedRefresh(){
            AccessToken token = this.getLastAccessToken();
            /*如果上次会话不存在,肯定是需要刷新缓存的*/
            if(null == token){
                return true;
            }
            //当前系统时间
            long now = System.currentTimeMillis();
            //此次运行和上次运行的时间间隔,5min
            long interval = now - this.lastRunTime;
            //上次token的更新时间
            long lastTimeMillis = this.getLastTimeMillis();
            //此处在微信规定7200秒的基础上减去1800秒,即度过1h30m的时间,就认为token已失效,以此保证token的有效性
            int expiresIn = 5400*1000;
            /*如果时间间隔不足以支撑到下次运算时的超时时间,则会话会在本次被刷新*/
    //        logger.info("判断是否需要刷新开始---------");
    //        logger.info("                   此时此刻 now            ---------" + now);
    //        logger.info("此次运行和上次运行的时间间隔 interval       ---------" + interval);
    //        logger.info("        上次token的更新时间 lastTimeMillis ---------" + lastTimeMillis);
    //        logger.info("               token有效期  expiresIn      ---------" + expiresIn);
    //        logger.info("计算表达式(lastTimeMillis + expiresIn) <= (now + interval)---------" + ((lastTimeMillis + expiresIn) <= (now + interval)));
            if((lastTimeMillis + expiresIn) <= (now + interval)){
                return true;
            }
            return false;
        }
    
        private String getAppID() {
            return appID;
        }
    
        public void setAppID(String appID) {
            this.appID = appID;
        }
    
        private String getAppsecrect() {
            return appsecrect;
        }
    
        public void setAppsecrect(String appsecrect) {
            this.appsecrect = appsecrect;
        }
    
        public AccessToken getLastAccessToken(){
            if(this.lastAccessToken == null){
                return null;
            }
            return this.lastAccessToken;
        }
    
        //获得token有效期的时间戳
        private long getLastTimeMillis(){
            AccessToken token = this.getLastAccessToken();
            Date updateTime = token.getUpdateTime();
            if(updateTime == null){
                return 0L;
            }
            long millis = updateTime.getTime();
            return millis;
        }
    
        @Override
        public void onApplicationEvent(ApplicationEvent applicationEvent) {
            if (!isStart) {
                isStart = true;
                logger.info("启动token刷新服务..........");
                this.refresh();
            }
        }
    }
    

     

    展开全文
  •  各位肯定都知道,做微信开发,我们的开发服务器需要和微信服务器做交互,我们需要准备一台放置在公网的服务器,能够使得我们的服务器可以正常访问微信服务器,并且微信服务器也需要可以正常访问我们的开发服务器。...

    一,为什么要用到ngrok?

           各位肯定都知道,做微信开发,我们的开发服务器需要和微信服务器做交互,我们需要准备一台放置在公网的服务器,能够使得我们的服务器可以正常访问微信服务器,并且微信服务器也需要可以正常访问我们的开发服务器。并且我们做开发时的服务器都是放在内网中的,只能通过内网来访问。然而微信服务器无法和我们的内网服务器做交互,这就导致我们做微信开发在本地调试出现了一定的困难!

         今天就向大家介绍一个非常强大的外网映射工具:ngrok.它可以把你的本地ip(127.0.0.1|localhost)映射成一个公网域名,这样所有人都可以通过这个域名来访问你的项目,这个功能对本地调试,特别是微信公众号开发带来了极大的便利.

    示例:
    http://localhost:8080/项目名/ -> http://**.ngrok.cc/项目名

    提醒:微信接口服务只支持80端口,并不支持其他的端口

    ,准备开发工具

         1.tomcat

         2.ngrok客户端(可以访问官网进行下载,官网地址是:http://www.ngrok.cc)

    三,ngrok版本说明

        

    此处要介绍三个ngrok版本:ngrok,tunnel,sunny-ngrok.

    第一个版本是国外开发的原生ngrok版本,这个版本将我们的本地ip映射到一个二级域名上,这个域名有两种形式:自定义主机名和系统分配主机名(主机名为最左边的部分,比如我们平时经常看到的www).这个版本有两个缺陷:
    1.系统分配的主机名是动态分配的,即每一次开启都会不一样,所以每次访问的时候都要记住不一样的域名,这很蛋疼.
    2.这个域名是在国外的,所以访问速度会相当慢

    第二个版本是国内基于ngrok开发的一个改良版,由于域名在国内,所以解决了访问慢的问题,但是这个版本现在已经无法使用

    第三个版本也是国内开发出的一个版本,可以自定义主机名,还可以自定义域名(前提是你有一条域名),很好的解决了原生ngrok的那两条缺陷.

    ,环境搭建步骤

             我们这里主要来介绍sunny-ngrok版本的搭建方法;

            1、访问ngrok授权管理系统(http://www.ngrok.cc/login),点击注册,注册帐号。

           

            2,注册一个新的账号,如下如所示:

            

     

             3,注册成功以后点击登录进入ngrok授权管理系统的主界面,然后点击左侧菜单栏中的隧道管理----》开通隧道,进入下面的界面,


              

         进入界面以后提供隧道的两种购买方式,一种是付费的,一种是免费(其实两者的区别就是带宽的不同,如果只是做测试用,10M带宽肯定够用)

         然后点击立即购买;将会出现下面的界面

     

          注意:1.隧道协议选择http协议;

                    2.填写隧道名称以及前置域名

                    3.把上面本地端口改成127.0.0.1:8080

        然后点击确定添加

        4.确定添加成功后跳转到新的界面下,继续点击左侧菜单中的隧道管理,出现下面的界面,并且要复制隧道id

      


      5.下载ngrok的客户端

         访问下面的网址http://www.ngrok.cc就可以下载客户端,如下图所示:


             下载到本地的D盘中,然后解压,如下图所示:





    6.输入上文的隧道id,然后回车。如下图所示:



    到此ngrok的环境搭建已经完成,下面就是测试,测试的时候在项目中启动tomcat,用http://127.0.0.1:8080/访问能访问到

    同时用http://****.ngrok.cc/也能访问到;


    7.最后一步就是把该域名配置到微信公众平台上就ok了,大功告成。。。。。。


    展开全文
  • 这里需要明确的是消息其实是由用户发给你的公众帐号的,消息先被微信平台接收到,然后微信平台会将该消息你在开发模式接口配置中指定的URL地址。 微信公众平台消息接口 要接收微信平台发送的消息,我们...
  • 在我们做微信公众号开发时,发送模板消息往往是必不可少的功能。今天我们就来说说吧! 1、申请模板消息 首先我们应该知道,模板消息是需要申请的。这个申请就其本身来说是很easy的(我前一天晚上申请的,显示需要2...
  • 微信开发之架构设计

    2014-10-30 11:45:32
     本文将讲解微信开发的前期准备,包括微信开发上的一些坑、架构上的设计、接口上需要注意的地方,全部来自自己的开发经验,如有不对,请指正。   微信开发的坑   1、微信授权  微信...
  • 一定要先看下官方文档微信消息管理分为接收普通消息、接收事件推送、发送消息(被动回复)、客服消息、群发消息、模板消息这几部分一、接收普通消息当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML...
  • 本课程是一个系列入门教程,目标是从 0 开始带领读者上手实战,课程以微信小程序的核心概念作为主线,介绍配置文件、页面样式文件、JavaScript 的基本知识并以指南针为例对基本知识进行扩展,另外加上开发工具的安装...
  • 在上一篇文章写了如何配置服务器:...要实现消息获取和自动回复,需要了解微信是怎么实现这个过程:接收普通消息当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。文本消息...
  • 微信开发注意事项

    2018-07-11 15:55:40
    刚接触微信开发踩坑无数,现将踩过的坑作整理,适合刚接触微信开发的程序猿。 1:长期运营人员绑定 大部分情况下微信公众号的管理员不是自己,这时候开发的时候会遇到很多麻烦,很多操作都需要管理员或长期运维人员...
  • 在公司微信项目开发中,我主要负责消息中心的模板消息接口设计实现。主要是将微信公众号的推送模板消息功能放到公司的消息中心系统中,微信后台项目通过RMI调用接口,实现推送功能。在这里记录总结下当时的设计实现...
  • 随着腾讯微信公众平台号的开放,围绕着微信的各种开发和营销如火如荼。很多商家也开始在微信上做文章,想充分利用微信平台4亿多的粉丝群体来进行各种营销和推广。这直接带来了很多公司开始做微信第3方营销平台,而...
  • 微信开发视频教程-深入浅出微信公众平台实战开发(微网站、LBS云、Api接口调用、服务号高级接口) 一、微信开发实例视频教程总目录: 微信开发实例视频教程 讲师介绍: 易伟,现广东合桓律师事务所专职律师。...
  • 基于 laravel框架的微信公众号的自动回复功能。主要是图文消息和文本类型
  • 微信公众号开发
  • 思路描述,用户在前段操作了部分数据,后台在更新数据库的成功之后,会发送一个请求我们的微信服务号服务,通过微信公众号的服务再调用相关接口给用户进行推送。 思路如下图所示: 新增接口代码如下(只是...
  • 我需要用户接收微信分享的链接后,点击进入参加活动的用户【点赞】,然后需要后台获取该微信用户的 openid 作为唯一的标记信息,以便保证该用户下次进入后进行数据库的比对,直接提取其对应的操作信息...
1 2 3 4 5 ... 20
收藏数 90,153
精华内容 36,061