• 微信开发服务器配置

    2019-04-01 11:23:01
    * 微信接口验证与接收 * * @param signature * @param timestamp * @param nonce * @return * @throws IOException */ @RequestMapping(value = "/wsc") public void check(HttpServletRequest request, ...

    /**
    * 微信接口验证与接收
    * 
    * @param signature
    * @param timestamp
    * @param nonce
    * @return
    * @throws IOException
    */
    @RequestMapping(value = "/wsc")
    public void check(HttpServletRequest request, HttpServletResponse response) throws IOException {
    boolean isGet = request.getMethod().toLowerCase().equals("get");
    PrintWriter out;
    if (isGet) {
    
    
    String signature = request.getParameter("signature");
    String timestamp = request.getParameter("timestamp");
    String nonce = request.getParameter("nonce");
    String echostr = request.getParameter("echostr");
    
    
    // PrintWriter out = null;
    
    
    if (CheckUtil.checkSignature(signature, timestamp, nonce)) {
    try {
    
    
    out = response.getWriter();
    out.write(echostr);
    out.flush();
    
    
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    } else {
    
    
    response.setCharacterEncoding("UTF-8");
    out = response.getWriter();
    // 接收消息并返回消息
    // 调用核心服务类接收处理请求
    String respXml = CoreService.processRequest(request);
    out.print(respXml); 
    out.flush();
    out.close();
    }
    
    
    
    }
    
    

    --------分隔符

    public static String processRequest(HttpServletRequest request) {
    
    
    // xml格式的消息数据
    String respXml = null;
    // 默认返回的文本消息内容
    String respContent = "未知的消息类型";
    try {
    request.setCharacterEncoding("UTF-8");
    
    
    // 调用parseXml方法解析请求消息
    Map requestMap = MessageUtil.parseXml(request);
    // 发送方帐号
    String fromUserName = (String) requestMap.get("FromUserName");
    // 开发者微信号
    String toUserName = (String) requestMap.get("ToUserName");
    // 消息类型
    String msgType = (String) requestMap.get("MsgType");
    // 回复文本消息
    TextMessage textMessage = new TextMessage();
    textMessage.setToUserName(fromUserName);
    textMessage.setFromUserName(toUserName);
    textMessage.setCreateTime(new Date().getTime());
    textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);// 回复的类型
    // textMessage.setFuncFlag(0);
    
    
    // 图文消息
    
    
    NewsMessage newsMessage = new NewsMessage();
    newsMessage.setToUserName(fromUserName);
    newsMessage.setFromUserName(toUserName);
    newsMessage.setCreateTime(new Date().getTime());
    newsMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_NEWS);
    newsMessage.setFuncFlag(0);
    
    
    // 获取文本消息
    // String content = (String) requestMap.get("Content");
    List<Article> articleList = new ArrayList<Article>();
    
    
    if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
    
    
    // respContent = "你好啊!!!!";
    // StringBuffer buffer = new StringBuffer();
    // buffer.append("您好,我是Target,请回复数字选择服务:").append("\n\n");
    // buffer.append("1 可查看测试单图文").append("\n");
    // buffer.append("2 可测试多图文发送").append("\n");
    // respContent = String.valueOf(buffer);
    // textMessage.setContent(respContent);
    
    
    // 测试单图文回复
    Article article = new Article();
    article.setTitle("巴洛伊铲射破门");
    // 图文消息中可以使用QQ表情、符号表情
    article.setDescription("这是测试有没有换行\n\n如果有空行就代表换行成功\n\n点击图文可以跳转到百度首页");
    // 将图片置为空
    article.setPicUrl(
    "http://n.sinaimg.cn/sports/99_img/upload/cf0d0fdd/294/w1700h994/20180624/dx4W-heirxyf2696267.jpg");
    article.setUrl("http://slide.2018.sina.com.cn/eng/slide_82_89646_439637.html#p=1");
    articleList.add(article);
    newsMessage.setArticleCount(articleList.size());
    newsMessage.setArticles(articleList);
    
    
    respXml = MessageUtil.newsMessageToXml(newsMessage);
    
    
    }
    // 图片消息
    else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {
    // respContent = "您发送的是图片消息!";
    return "";
    }
    // 语音消息
    else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) {
    // respContent = "您发送的是语音消息!";
    return "";
    }
    // 视频消息
    else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VIDEO)) {
    //respContent = "您发送的是视频消息!";
    return "";
    }
    // 地理位置消息
    else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {
    //respContent = "您发送的是地理位置消息!";
    return "";
    }
    // 链接消息
    else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) {
    //respContent = "您发送的是链接消息!";
    return "";
    }
    // 事件推送
    else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {
    // 事件类型
    String eventType = (String) requestMap.get("Event");
    // 关注
    if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) {
    respContent = "谢谢关注Target公众号";
    textMessage.setContent(respContent);
    respXml = MessageUtil.textMessageToXml(textMessage);
    }
    // 取消关注
    else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) {
    // TODO 取消订阅后用户不会再收到公众账号发送的消息,因此不需要回复
    }
    // 扫描带参数二维码
    else if (eventType.equals(MessageUtil.EVENT_TYPE_SCAN)) {
    // TODO 处理扫描带参数二维码事件
    }
    // 上报地理位置
    else if (eventType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {
    // TODO 处理上报地理位置事件
    return "";
    }
    // 自定义菜单
    else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) {
    // TODO 处理菜单点击事件
    }
    }
    
    
    
    
    
    return respXml;
    } catch (Exception e) {
    e.printStackTrace();
    }
    return "";
    }
    
    
    
    
    
    
    
    
    
    

    MessageUtil 工具类

    // public static final String RESP_MESSAGE_TYPE_TEXT = "text";
    // public static final Object REQ_MESSAGE_TYPE_TEXT = "text";
    // public static final Object REQ_MESSAGE_TYPE_IMAGE = "image";
    // public static final Object REQ_MESSAGE_TYPE_VOICE = "voice";
    // public static final Object REQ_MESSAGE_TYPE_VIDEO = "video";
    // public static final Object REQ_MESSAGE_TYPE_LOCATION = "location";
    // public static final Object REQ_MESSAGE_TYPE_LINK = "link";
    // public static final Object REQ_MESSAGE_TYPE_EVENT = "event";
    // public static final Object EVENT_TYPE_SUBSCRIBE = "SUBSCRIBE";
    // public static final Object EVENT_TYPE_UNSUBSCRIBE = "UNSUBSCRIBE";
    // public static final Object EVENT_TYPE_SCAN = "SCAN";
    // public static final Object EVENT_TYPE_LOCATION = "LOCATION";
    // public static final Object EVENT_TYPE_CLICK = "CLICK";
    
    
    /**
    * 返回消息类型:文本
    */
    public static final String RESP_MESSAGE_TYPE_TEXT = "text";
    
    
    /**
    * 返回消息类型:音乐
    */
    public static final String RESP_MESSAGE_TYPE_MUSIC = "music";
    
    
    /**
    * 返回消息类型:图文
    */
    public static final String RESP_MESSAGE_TYPE_NEWS = "news";
    
    
    /**
    * 请求消息类型:视频
    */
    public static final Object REQ_MESSAGE_TYPE_VIDEO = "video";
    /**
    * 请求消息类型:文本
    */
    public static final String REQ_MESSAGE_TYPE_TEXT = "text";
    
    
    /**
    * 请求消息类型:图片
    */
    public static final String REQ_MESSAGE_TYPE_IMAGE = "image";
    
    
    /**
    * 请求消息类型:链接
    */
    public static final String REQ_MESSAGE_TYPE_LINK = "link";
    
    
    /**
    * 请求消息类型:地理位置
    */
    public static final String REQ_MESSAGE_TYPE_LOCATION = "location";
    
    
    /**
    * 请求消息类型:音频
    */
    public static final String REQ_MESSAGE_TYPE_VOICE = "voice";
    
    
    /**
    * 请求消息类型:推送
    */
    public static final String REQ_MESSAGE_TYPE_EVENT = "event";
    
    
    /**
    * 事件类型:subscribe(订阅)and 未关注群体扫描二维码
    */
    public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
    
    
    /**
    * 事件类型:已关注群体扫描二维码
    */
    public static final String EVENT_TYPE_SCAN = "SCAN";
    /**
    * 事件类型:unsubscribe(取消订阅)
    */
    public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
    
    
    /**
    * 事件类型:CLICK(自定义菜单点击事件)
    */
    public static final String EVENT_TYPE_CLICK = "CLICK";
    /**
    * 事件类型:VIEW(点击自定义菜单跳转链接时的事件)
    */
    public static final String EVENT_TYPE_VIEW = "VIEW";
    
    
    /**
    * 事件类型:transfer_customer_service(把消息推送给客服)
    */
    public static final String EVENT_TYPE_TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service";
    public static String PREFIX_CDATA = "<![CDATA[";
    public static String SUFFIX_CDATA = "]]>";
    
    
    /**
    * 扩展xstream,使其支持CDATA块 CDATA[不解析块内容]
    */
    private static XStream xstream = new XStream(new XppDriver() {
    public HierarchicalStreamWriter createWriter(Writer out) {
    return new PrettyPrintWriter(out) {
    // 对所有xml节点的转换都增加CDATA标记
    boolean cdata = true;
    
    
    @SuppressWarnings("unchecked")
    public void startNode(String name, Class clazz) {
    super.startNode(name, clazz);
    }
    
    
    protected void writeText(QuickWriter writer, String text) {
    if (cdata) {
    writer.write(PREFIX_CDATA);
    writer.write(text);
    writer.write(SUFFIX_CDATA);
    } else {
    super.writeText(writer, text);
    }
    }
    };
    }
    });
    
    
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static Map parseXml(HttpServletRequest request) throws Exception {
    // 将解析结果存储在HashMap中
    Map map = new HashMap();
    
    
    // 从request中取得输入流
    InputStream inputStream = request.getInputStream();
    // 读取输入流
    SAXReader reader = new SAXReader();
    Document document = reader.read(inputStream);
    // 得到xml根元素
    Element root = document.getRootElement();
    // 得到根元素的所有子节点
    List<Element> elementList = root.elements();
    // 遍历所有子节点
    for (Element e : elementList)
    map.put(e.getName(), e.getText());
    
    
    // 释放资源
    inputStream.close();
    inputStream = null;
    return map;
    }
    
    
    /**
    * 文本消息转为xml
    * 
    * @param textMessage
    * @return
    */
    public static String textMessageToXml(BaseMessage textMessage) {
    xstream.alias("xml", textMessage.getClass());
    
    
    return xstream.toXML(textMessage);
    }
    
    
    /**
    * 图文消息对象转换成xml
    *
    * @param newsMessage
    *            图文消息对象
    * @return xml
    */
    public static String newsMessageToXml(BaseMessage newsMessage) {
    xstream.alias("xml", newsMessage.getClass());
    xstream.alias("item", new Article().getClass());
    return xstream.toXML(newsMessage);
    }
    
    
    
    
    
    
    
    private static final String token = "***";//微信里自己的设置
    
    
    
    
    public static boolean checkSignature(String signature, String timestamp, String nonce) {
    String[] str = new String[] { token, timestamp, nonce };
    // 排序
    Arrays.sort(str);
    // 拼接字符串
    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < str.length; i++) {
    buffer.append(str[i]);
    }
    // 进行sha1加密
    String temp = encode(buffer.toString());
    // 与微信提供的signature进行匹对
    return signature.equals(temp);
    }
    
    
    private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
    'e', 'f' };
    
    
    private static String getFormattedText(byte[] bytes) {
    int len = bytes.length;
    StringBuilder buf = new StringBuilder(len * 2);
    // 把密文转换成十六进制的字符串形式
    for (int j = 0; j < len; j++) {
    buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
    buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
    }
    return buf.toString();
    }
    
    
    public static String encode(String str) {
    if (str == null) {
    return null;
    }
    try {
    MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
    messageDigest.update(str.getBytes());
    return getFormattedText(messageDigest.digest());
    } catch (Exception e) {
    throw new RuntimeException(e);
    }
    }

     

    展开全文
  • http://www.weixinyunduan.com/reg.html?tj=210965 一键绑定微信公众号 转载于:https://www.cnblogs.com/ZHONGZHENHUA/p/6248235.html

    http://www.weixinyunduan.com/reg.html?tj=210965

    一键绑定微信公众号

     

     

    转载于:https://www.cnblogs.com/ZHONGZHENHUA/p/6248235.html

    展开全文
  • 微信公众号开发(一)服务器及接口的配置 关于微信公众号中的订阅号和服务的区别这里不多加讨论,网上有很多资源可以搜到,这里直接进入正题,如果是个人开发者,这里建议使用测试号进行开发学习,测试号的权限要比...

    微信公众号开发(一)服务器及接口的配置

    关于微信公众号中的订阅号和服务的区别这里不多加讨论,网上有很多资源可以搜到,这里直接进入正题,如果是个人开发者,这里建议使用测试号进行开发学习,测试号的权限要比个人订阅号要多的多,而本篇博客也是基于测试号进行开发的。

     

    在开始微信号开发之前需要准备好两样东西,1、需要一个测试号,2、需要一个拥有域名的服务器,下面将分别介绍怎样获取这两样东西。

    1、测试号

    点击此链接测试号登录可直接用微信扫一扫注册一个测试号,相应的界面如下所示

     

    进入测试号界面之后可以获得一些开发所需要的东西,以及关注者列表和开发权限等,如下所示

     

    2、服务器

    微信号开发需要一个第三方服务器来和微信服务器沟通,这里我使用的是一个百度云的BAE虚拟主机,理由有以下几点:

    1、性价比高,该主机一天只需要2毛钱,而且不限制充值金额,如果你只是用来学习微信公众号开发,而且预计一个月学会的话,那么你只需要充值6元钱就可以,相比其他最低充值一年的平台相比,要划算的多。

    2、可以免去购买域名的费用,该BAE可免费设置一个二级域名,可用于微信公众号开发,并且数据库的使用也是免费的。

    3、该BAE的代码可以使用git或svn管理,我们在本地写好代码之后,直接push上去就可以了,相当方便,而且可以设置快捷发布,提交代码当即发布。

    缺点就是它的日志系统不够完善,不过这个缺点很容易解决,我们可以自己打印信息到文件里,然后读取出来,下面将会介绍到。

     

    百度云网址是:https://login.bce.baidu.com/?account=,登录之后,点击BAE后如图

     

    好了,这样我们就准备好了微信开发的两个必备的东西。接下来就要配置接口了。

     

    3、配置接口

    上面进入测试号界面的时候我们可以看到有一个接口配置信息的模块,如下所示

     

     

    这里的URL就是填写以上BAE中的域名就好了,当然了要注意加上http://前缀,以后用户发送的消息都会经过微信服务器转发到该接口。Token可以随便填写一些东西,这里填写了weixin。关于Token的用途下面会讲到。

    好了,现在先别急着点击提交,因为我们还没有在URL指向的服务器里编写任何的代码,还不能正确响应微信服务器的请求。

     

    在编写任何的代码之前,我先说一下本博客的一些习惯,为了便于理解,我会先将文件的结构和代码先贴出来,然后才解释具体代码的含义,这样如果熟悉的人就可以直接跳过该部分了。

     

    文件结构如下

     

    index.php用于处理消息。

    output_log.php和output_query.php分别用来输出post过来的数据和请求的查询字符串,Utils.php主要用来将数据输出到文件中,看了下面的代码你就明白了,其实相当简单,这三个东西是我用来调试用的,相比起微信公众号提供的在线调试接口而言(需要设置一堆的信息),我觉得这样更加简单。

     

    Utils.php,提供了两个函数,traceHttp()将请求的时间、远程主机地址和查询字符串输出到query.xml文件中。logger()将类型、时间和post数据输出到log.xml中。

    <?php
    class Utils
    {
        public static function traceHttp()
        {
            $content = date('Y-m-d H:i:s')."\n\rremote_ip:".$_SERVER["REMOTE_ADDR"].
                "\n\r".$_SERVER["QUERY_STRING"]."\n\r\n\r";
            $max_size = 1000;
            $log_filename = "./query.xml";
            if (file_exists($log_filename) and (abs(filesize($log_filename))) > $max_size){
                unlink($log_filename);
            }else {
    
            }
            file_put_contents($log_filename, $content, FILE_APPEND);
        }
    
        public static function logger($log_content, $type = '用户')
        {
            $max_size = 3000;
            $log_filename = "./log.xml";
            if (file_exists($log_filename) and (abs(filesize($log_filename)) >
                    $max_size)) {
                unlink($log_filename);
            }
            file_put_contents($log_filename, "$type  ".date('Y-m-d H:i:s')."\n\r".$log_content."\n\r",
                FILE_APPEND);
        }
    }

     

    output_query.php,输出query.xml的内容

    <?php
    @header('Content-type: text/plain;charset=UTF-8');
    $filepath = './query.xml';
    readfile($filepath);


    output_log.php,输出log.xml的内容。

    <?php
    @header('Content-type: text/plain;charset=UTF-8');
    $filepath = './log.xml';
    readfile($filepath);


    是不是非常简单,然后我们开始写处理消息index.php

    <?php
    //设置时区
    date_default_timezone_set("Asia/Shanghai");
    //定义TOKEN常量,这里的"weixin"就是在公众号里配置的TOKEN
    define("TOKEN", "weixin");
    
    require_once("Utils.php");
    //打印请求的URL查询字符串到query.xml
    Utils::traceHttp();
    
    $wechatObj = new wechatCallBackapiTest();
    /**
     * 如果有"echostr"字段,说明是一个URL验证请求,
     * 否则是微信用户发过来的信息
     */
    if (isset($_GET["echostr"])){
        $wechatObj->valid();
    }else {
        $wechatObj->responseMsg();
    }
    
    class wechatCallBackapiTest
    {
        /**
         * 用于微信公众号里填写的URL的验证,
         * 如果合格则直接将"echostr"字段原样返回
         */
        public function valid()
        {
            $echoStr = $_GET["echostr"];
            if ($this->checkSignature()){
                echo $echoStr;
                exit;
            }
        }
    
        /**
         * 用于验证是否是微信服务器发来的消息
         * @return bool
         */
        private function checkSignature()
        {
            $signature = $_GET["signature"];
            $timestamp = $_GET["timestamp"];
            $nonce = $_GET["nonce"];
    
            $token = TOKEN;
            $tmpArr = array($token, $timestamp, $nonce);
            sort($tmpArr);
            $tmpStr = implode($tmpArr);
            $tmpStr = sha1($tmpStr);
    
            if ($tmpStr == $signature){
                return true;
            }else {
                return false;
            }
        }
    
        /**
         * 响应用户发来的消息
         */
        public function responseMsg()
        {
            //获取post过来的数据,它一个XML格式的数据
            $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
            //将数据打印到log.xml
            Utils::logger($postStr);
            if (!empty($postStr)){
                //将XML数据解析为一个对象
                $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
                $RX_TYPE = trim($postObj->MsgType);
                //消息类型分离
                switch($RX_TYPE){
                    case "event":
                        $result = $this->receiveEvent($postObj);
                        break;
                    default:
                        $result = "unknow msg type:".$RX_TYPE;
                        break;
                }
                //打印输出的数据到log.xml
                Utils::logger($result, '公众号');
                echo $result;
            }else{
                echo "";
                exit;
            }
        }
    
        /**
         * 接收事件消息
         */
        private function receiveEvent($object)
        {
            switch ($object->Event){
                //关注公众号事件
                case "subscribe":
                    $content = "欢迎关注微微一笑很倾城";
                    break;
                default:
                    $content = "";
                    break;
            }
            $result = $this->transmitText($object, $content);
            return $result;
        }
    
        /**
         * 回复文本消息
         */
        private function transmitText($object, $content)
        {
            $xmlTpl = "<xml>
        <ToUserName><![CDATA[%s]]></ToUserName>
        <FromUserName><![CDATA[%s]]></FromUserName>
        <CreateTime><![CDATA[%s]]></CreateTime>
        <MsgType><![CDATA[text]]></MsgType>
        <Content><![CDATA[%s]]></Content>
    </xml>";
            $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time(), $content);
            return $result;
        }
    }


    这几个文件写好之后,直接通过git push到BAE上,如果设置了快捷发布,过1、2秒钟就会自动发布了,状态里面会显示绿色的"正常",如果没有设置快捷发布,上传代码后需要手动点击右边的快捷发布按钮。

     

    这时我们就可以点击测试号界面里面的那个提交按钮了。

     

     

    如果配置正确,则会提示配置成功。

     

    4、调试

    在浏览器地址栏上输入,xxx/output_query.php,xxx是你的域名。则会出现你点击提交后发送过来的请求,类似如下

     

     

    可以看到该查询字符串有4个字段

    • signature:微信加密签名
    • echostr:随机字符串
    • timestamp:时间戳
    • nonce:随机数

    只有在验证URL的时候查询字符串中才会有“echostr”这个字段,验证的方法是

    1. 将token、timestamp、nonce三个参数进行字典序排序
    2. 将三个参数字符串拼接成一个字符串进行sha1加密
    3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信

     

    验证通过之后,我们可以用微信扫一扫,扫描测试号里面的公众号二维码,关注该公众号,关注之后,公众号列表会显示出关注者的列表。

     

    此时微信应该会回复一条文本消息,也就是以上在index.php中设置的“欢迎关注XXX”。

     

    这时我们重新刷新一下xxx/output_query.php,发现没有“echostr”这个字段了,因为这个是用户发来的消息,而不是验证URL的消息。多出来的openid字段是用户的微信号,如果采用的是加密模式,还会有encrypt_type和msg_signature等字段。测试号只有明文模式。

    接着我们重新打开一个标签,访问XXX/log.xml,查看发送的post数据,下面是一个关注公众号的事件,和我们返回给微信的XML数据。

     

    现在不比纠结这些数据格式的问题,以后我们会提到,这样我们的微信公众号开发就准备好了,记得把这两个日志URL保存为浏览器的标签方便下次访问,以后调试只要F5一下就可以了,是不是比微信提供的在线调试容易多了。

    注意:必须在5秒内响应微信的服务器,否则会导致重传或者报错

     

    下一章我们将会尝试微信的基本消息接口,那时候就会理解这些数据结构了。

    相关博客

    微信公众号开发(一)服务器及接口的配置

    微信公众号开发(二)基础接口

    微信公众号开发(三)获取access_token

    微信公众号开发(四)自定义菜单

    微信公众号开发(五)个性化菜单

    微信公众号开发(六)素材管理

    微信公众号开发(七)发送客服消息

    微信公众号开发(八)用户管理

    微信公众号开发(九)群发消息接口

    微信公众号开发(十)模板消息

    微信公众号开发(十一)生成带参数二维码

    微信公众号开发(十二)OAuth2.0网页授权

    展开全文
  • 初学微信二次开发首先我们要接入微信公众平台。我们首先要有一个开发微信的第三方平台。...(暂时忽略)填写服务器配置:我们登录微信公众平台之后,找到开发者工具,打开公众平台测试账号。测试账号有一个...
    初学微信二次开发首先我们要接入微信公众平台。

    我们首先要有一个开发微信的第三方平台。这个平台可以是自己写的代码,也可以使用已经发布的一些平台。我们选择用自己的域名和虚拟主机,来自己开发。

    在域名和虚拟主机可以使用的情况下我们要完成三步:

    1. 填写服务器配置。
    2. 验证服务器地址的有效性。
    3. 依据接口实现业务逻辑。(暂时忽略)

    填写服务器配置:

    我们登录微信公众平台之后,找到开发者工具,打开公众平台测试账号。测试账号有一个接口配置信息。我们需要完全正确的填写才能配置成功。首先URL:此处的URL为开发者用来接收微信消息和事件的接口URL。Token:这是一个很重要的,由开发者任意填写,用作生成签名(该Token会和接口URL中包含的Token进行对比,从而验证安全性)。

    验证消息是否来自微信:

    微信服务器将发送GET请求到填写的服务器地址URL上。会携带4个参数,分别是signature,timestamp,nonce,echostr.将token,timestamp,nonce三个参数进行排序,将三个参数字符串拼接成一个字符串进行sha1加密,开发者获得加密后的字符串可与Signature对比。开发者通过检验signature对请求进行校验若确认此次请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者否则接入失败。

    <?php
    /**
      * wechat php test
      */
    
    //define your token
    define("TOKEN", "weixin");//必须与微信公众号里的相同
    $wechatObj = new wechatCallbackapiTest();
    $wechatObj->valid();
    
    class wechatCallbackapiTest
    {
    	public function valid()
        {
            $echoStr = $_GET["echostr"];
    
            //valid signature , option
            if($this->checkSignature()){
            	echo $echoStr;
            	exit;
            }
        }
    
      
    	private function checkSignature()
    	{
            $signature = $_GET["signature"];
            $timestamp = $_GET["timestamp"];
            $nonce = $_GET["nonce"];	
            		
    		$token = TOKEN;
    		$tmpArr = array($token, $timestamp, $nonce);
    		sort($tmpArr);
    		$tmpStr = implode( $tmpArr );
    		$tmpStr = sha1( $tmpStr );
    		
    		if( $tmpStr == $signature ){
    			return true;
    		}else{
    			return false;
    		}
    	}
    }
    
    ?>

    我的域名是cjiele.top将上边的php文件放到了wx文件夹下名字为wx_sample.php。

    这样我们就可以配置成功了。我们就走出了开发者的第一步。

    我们可以在代码中加入自动回复功能这样我们就可以在公众号中收到回复了,这是一个自动回复代码。回复中的内容是xml类型的。

     public function responseMsg()
        {
    		//get post data, May be due to the different environments
    		// $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
            $postStr=file_get_contents("php://input");
          	//extract post data
    		if (!empty($postStr)){
                    
                  	$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
                    $fromUsername = $postObj->FromUserName;
                    $toUsername = $postObj->ToUserName;
                    $keyword = trim($postObj->Content);
                    $time = time();
                    $textTpl = "<xml>
    							<ToUserName><![CDATA[%s]]></ToUserName>
    							<FromUserName><![CDATA[%s]]></FromUserName>
    							<CreateTime>%s</CreateTime>
    							<MsgType><![CDATA[%s]]></MsgType>
    							<Content><![CDATA[%s]]></Content>
    							<FuncFlag>0</FuncFlag>
    							</xml>";             
    				if(!empty( $keyword ))
                    {
                  		$msgType = "text";
                    	// $contentStr = "Welcome to wechat world!";
                         $contentStr =$this->gjz($keyword);
                    	$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
                    	echo $resultStr;
                    }else{
                    	echo "Input something...";
                    }
    
            }else {
            	echo "";
            	exit;
            }
        }
    	public function gjz($keyword){
            if ($keyword==="天气") {
                $contentStr = "今天有雨!";
                return $contentStr;
            }else if($keyword==="你好"){
                $contentStr = "你好呀!";
                return $contentStr;
            }else{
                $contentStr = "对不起暂时不识别!";
                return $contentStr;
    
            }
            
        }
    接下来我们就可以扫描测试号二维码,试着发一句自动回复吧。


    展开全文
  • 登录进微信公众号平台,首页最下面有个基本配置:进入基本配置后,会看到两个栏目,一个是公众号开发信息,一个是服务器配置。这里主要讲如何进行服务器配置,公众号开发信息配置比较简单,就自己去操因为我已经配置...

    由于项目需要微信公众号的开发,弄了老半天,发现也不是那么难弄。

    对于微信公众号开发,首先要有开发者权限然后进行基本的配置。

    登录进微信公众号平台,首页最下面有个基本配置:

    进入基本配置后,会看到两个栏目,一个是公众号开发信息,一个是服务器配置。

    这里主要讲如何进行服务器配置,公众号开发信息配置比较简单,就自己去操作。

    要配置服务器,要将自己的IP添加到IP白名单,否则微信会将你的消息过滤掉。

    因为我已经配置过了服务器,所以页面有点不同,点击修改配置

    接下来按照图里面步骤

    因为服务器需要公网可以访问的域名并且要80和443端口,可以使用nat映射软件进行内网穿透(花生壳不能固定80端口,已经不能使用)

    然后进行服务器校验

    看一下官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319

    我摘取比较重要的信息:

     

    开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示:

    参数描述
    signature微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
    timestamp时间戳
    nonce随机数
    echostr随机字符串

    开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。加密/校验流程如下:

    1)将token、timestamp、nonce三个参数进行字典序排序 2)将三个参数字符串拼接成一个字符串进行sha1加密 3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信

     

    意思是说:对微信服务器发过来消息忠token、timestamp、nonce三个参数进行加密处理,然后加密得到的字符串与signature微信加密签名相比较,如果相等则返回echostr随机字符串。


    先下载微信官方的示例:https://wximg.gtimg.com/shake_tv/mpwiki/cryptoDemo.zip

    下面进行服务器环境搭建:

    在刚才下载的微信官方的示例将

    SampleCode\SampleCode\Java\src\com\qq\weixin\mp\aes\SHA1.java该类与其依赖类导入项目中,为方便操作可以直接将SampleCode\Java\src下的com包导入进去,后面根据哪些不需要用到的类删除。

     并且将SHA1类改为public,(有可能导入会是中文乱码,重新复制粘贴文字进去即可)

     

    新建一个servlet类(get方法用来给微信验证服务器,post用来业务逻辑):

    import java.io.IOException;
    import java.io.PrintWriter;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashMap;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import com.qq.weixin.mp.aes.AesException;
    import com.qq.weixin.mp.aes.SHA1;
    
    
    /**
     * Servlet implementation class test
     */
    @WebServlet("/test")
    public class test extends HttpServlet {
        private static final long serialVersionUID = 1L;
           
        /**
         * @see HttpServlet#HttpServlet()
         */
        public test() {
            super();
            // TODO Auto-generated constructor stub
        }
    
        /**
         * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
         */
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // TODO Auto-generated method stub
            
            String signature=request.getParameter("signature");
            String timestamp=request.getParameter("timestamp");
            String nonce=request.getParameter("nonce");
            String echostr=request.getParameter("echostr");
            String token="somelog";//这里填基本配置中的token
            String jiami="";
             try {
                 jiami=SHA1.getSHA1(token, timestamp, nonce,"");//这里是对三个参数进行加密
            } catch (AesException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
             System.out.println("加密"+jiami);
             System.out.println("本身"+signature);
                PrintWriter out=response.getWriter();
                if(jiami.equals(signature))
                out.print(echostr);
            
        }
    
        /**
         * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
         */
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // TODO Auto-generated method stub
            
        }
    
    }

    因为官方给的示例,SHA1类中getSHA1方法有四个参数token,  timestamp, nonce, encrypt,但是我们只有三个参数,根据观察代码可知,将第四个参数设置为“”不会影响操作。

    所以在调用getSHA1方法时,传入参数是token, timestamp, nonce,""

    最后将加密的字符串与signature进行比较,如果相等就返回echostr。

    服务器环境即搭建完毕。

    点击提交即可,显示提交成功即可

    这里需要强调一下,eclipse在自动创建servlet时会给get方法加上

    response.getWriter().append("Served at: ").append(request.getContextPath());

    这一句一定要删除,否则会一直验证失败。

    并且不能自己去结束response的输入流:out.flush()和out.close();会出现超时提示。

    展开全文
  • 1.首先可以自行购买获取服务器,也可以在本地主机中设置虚拟机搭建服务器(这个方法没试过,但在设想中我认为是可行的,后续会自己尝试一下再发布),这里我购买的是腾讯云服务器Ubuntu16.04 64位版本。 2.推荐使用...
  • 原因是:利用springboot进行操作,Controller上的注解应该是@RestController,让其返回一个字符串,结果自己写成了@Controller,使用浏览器进行测试的时候发现返回404,才找到了这个错误。 其实在指定的方法上加上@...
  • 微信之所以验证开发者服务器,是为了绑定公众号用户与其开发服务器,以完成公众号的用户与公众号之间交互信息的推送。 举个例子来说,比如用户领取了公众号的会员卡,微信就会往这个公众号绑定的服务器地址发送一个...
  • 打开微信开发者工具 创建第一个小程序 步骤: 打开微信开发者工具 使用微信扫码登录 点击小程序-创建小程序 项目名 项目路径 appid 不使用云服务器 语言: javascript...
  • 微信开发者模式配置

    2018-03-09 14:14:03
    1. 点击打开链接 找到第二步的位置2. 3. 3.1 获取appsecret 3.2 根据要求填写服务器的ip地址 4. 打开修改配置看第五步5. 根据要求修改下面的内容(注:通过url必选能读取待文件才能成功 )...
  • 上一篇文章中https://blog.csdn.net/u014650759/article/details/90701866,我们已经安装好了微信开发者工具,并导入了一个Demo项目,这篇文章,将就开发者工具进行简单的介绍,方便你开发实用编译器,更好的开发小...
  • 呐,第一次接触微信的开发,搞vue也搞了好久,页面框架和后台框架和我一点关系都...下面是第一次为了用开发者工具测试需要配置的内容。首先,登录微信公众平台,看到自己的appID,appsecret,如下图:然后在下图中...
  • 微信开发者工具1.02.1905151 配置 File—settings或者快捷键Ctrl+Alt+S,点击出来如下页面: 1.FileType下Cascading Style Sheet 添加*.wxss 2.FileType下HTML 添加*.wxml 3.将其中的wecharCode.jar下载...
  • 安装微信开发者工具 --》https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html?t=201716 新建项目 安装Node.js --》https://nodejs.org/en/ 点击–》 注册 右键选择环境 然后将node.js–》cmd 安...
  • 开发者工具配置:在开发者工具右侧的详情中的项目设置,将不校验合法域名打上勾index.js:Page({ //对应的index.wxml页面绑定的数据 data: { json : '' }, //index.wxml页面加载时调用的函数 onLoad: function...
  • 相关文章微信小程序开发(二)开发之日历打卡小程序发现页微信小程序开发(三)入门之创建打卡活动前言一直不温不火的微信小程序2018年迎来了第二春,在我的记忆中随着跳一跳小游戏的出现,一时间数千万的微信小程序...
  • 进入微信开发工具后,发现需要使用新的版本工具 - “工蜂”,在这之前公司用的 GitLab 搭建的服务器,本以为有什么不同,但是忘记了是 TX 的!!!咳咳,不难发现,这是微信开发工具有意推广 TX ...
  • 微信开发者工具可以获取地址而手机上不能获取地址 原因: 未进行 wx.config 的配置; 解决方法: 传入对应的签名信息,对 wx.config 进行配置 参考文档 ...
  • 微信开发者基本配置

    2017-05-05 14:44:33
    服务器配置(未启用)修改配置 启用启用并设置服务器配置后,用户发给公众号的消息以及开发者需要的事件 推送,将被微信转发到该URL中URL(服务器地址) http://www.xxx.com/wx_sample.php Token(令牌) token ...
  • 微信开发者工具无法使用本地E:\*************** 这种地址, 如果需要本地测试的话, 可以使用laya开启的服务 可以使用这个相对的地址本地调试 ...
1 2 3 4 5 ... 20
收藏数 22,671
精华内容 9,068