zoukankan      html  css  js  c++  java
  • Java与微信不得不说的故事——实现微信公众平台与sae服务器的对接

      又颓废了些日子,说好认真来半年的,那就接着来啊,公司的easyUI平台慢慢开始明白了,可是最近bug太多了,只能找时间在研究了,平时无聊看见了了java微信平台开发,感觉有点意思呀,自己也来试试,不过又得求教博客园里面的大神们了,现在开始研究。

      一开始无聊的时候,自己在新浪云服务器注册了一个账号,可以建立一些应用在上面,微信平台也是可以的。于是自己照着微信官方的例子,建立了微信公众平台与新浪云服务器的接口,成功了。不过官方是用PHP语言写的(也许PHP是世界上最好的语言)。可是作为一个Javaer,当然要学会怎么写Java了。先贴把这个例子贴一下吧。

      

    <?php
    /**
      * wechat php test
      */
    
    //define your token
    define("TOKEN", "haojiahongxihuanliyuan");
    $wechatObj = new wechatCallbackapiTest();
    $wechatObj->valid();
    
    class wechatCallbackapiTest
    {
        public function valid()
        {
            $echoStr = $_GET["echostr"];
    
            //valid signature , option
            if($this->checkSignature()){
                echo $echoStr;
                exit;
             }
        }
    
        public function responseMsg()
        {
            //get post data, May be due to the different environments
            $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
    
              //extract post data
            if (!empty($postStr)){
                    /* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
                       the best way is to check the validity of xml by yourself */
                    libxml_disable_entity_loader(true);
                      $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!";
                        $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
                        echo $resultStr;
                    }else{
                        echo "Input something...";
                    }
    
            }else {
                echo "";
                exit;
            }
        }
            
        private function checkSignature()
        {
            // you must define TOKEN by yourself
            if (!defined("TOKEN")) {
                throw new Exception('TOKEN is not defined!');
            }
            
            $signature = $_GET["signature"];
            $timestamp = $_GET["timestamp"];
            $nonce = $_GET["nonce"];
                    
            $token = TOKEN;
            $tmpArr = array($token, $timestamp, $nonce);
            // use SORT_STRING rule
            sort($tmpArr, SORT_STRING);
            $tmpStr = implode( $tmpArr );
            $tmpStr = sha1( $tmpStr );
            
            if( $tmpStr == $signature ){
                return true;
            }else{
                return false;
            }
        }
    }
    
    ?>

      这个是官方提过的接口程序。

      下面开始研究Java接口程序。

      当用户通过微信客服端发送消息到微信服务后,微信服务器会将此消息转发给我们的公网服务器,也就是上面所说sae新浪云服务器。具体的业务逻辑就在sae上完成,处理完后再将结果发回微信服务器,微信服务器再发给用户。

      让两个完全不沾边的服务器(微信服务器和sae)对接是有风险,因此必须有验证机制的存在。具体的验证过程是

    代码如下:

    微信公众平台去请求sae中的coreServlet。

    package org.liufeng.course.servlet;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.liufeng.course.service.CoreService;
    import org.liufeng.course.util.SignUtil;
    
    /**
     * 请求处理的核心类
     * 
     * @author liufeng
     * @date 2013-09-29
     */
    public class CoreServlet extends HttpServlet {
        private static final long serialVersionUID = 4440739483644821986L;
    
        /**
         * 请求校验(确认请求来自微信服务器)
         */
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 微信加密签名
            String signature = request.getParameter("signature");
            // 时间戳
            String timestamp = request.getParameter("timestamp");
            // 随机数
            String nonce = request.getParameter("nonce");
            // 随机字符串
            String echostr = request.getParameter("echostr");
    
            PrintWriter out = response.getWriter();
            // 请求校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
            if (SignUtil.checkSignature(signature, timestamp, nonce)) {
                out.print(echostr);
            }
            out.close();
            out = null;
        }
    
        /**
         * 处理微信服务器发来的消息
         */
        public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 将请求、响应的编码均设置为UTF-8(防止中文乱码)
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");
    
            // 调用核心业务类接收消息、处理消息
            String respXml = CoreService.processRequest(request);
    
            // 响应消息
            PrintWriter out = response.getWriter();
            out.print(respXml);
            out.close();
        }
    }

    消息处理类:

    package org.liufeng.course.util;
    
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.Arrays;
    
    /**
     * 请求校验工具类
     * 
     * @author liufeng
     * @date 2013-09-01
     */
    public class SignUtil {
        // 与开发模式接口配置信息中的Token保持一致
        private static String token = "weixinCourse";
    
        /**
         * 校验签名
         * 
         * @param signature 微信加密签名
         * @param timestamp 时间戳
         * @param nonce 随机数
         * @return
         */
        public static boolean checkSignature(String signature, String timestamp, String nonce) {
            // 对token、timestamp和nonce按字典排序
            String[] paramArr = new String[] { token, timestamp, nonce };
            Arrays.sort(paramArr);
    
            // 将排序后的结果拼接成一个字符串
            String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]);
    
            String ciphertext = null;
            try {
                MessageDigest md = MessageDigest.getInstance("SHA-1");
                // 对接后的字符串进行sha1加密
                byte[] digest = md.digest(content.toString().getBytes());
                ciphertext = byteToStr(digest);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            
            // 将sha1加密后的字符串与signature进行对比
            return ciphertext != null ? ciphertext.equals(signature.toUpperCase()) : false;
        }
    
        /**
         * 将字节数组转换为十六进制字符串
         * 
         * @param byteArray
         * @return
         */
        private static String byteToStr(byte[] byteArray) {
            String strDigest = "";
            for (int i = 0; i < byteArray.length; i++) {
                strDigest += byteToHexStr(byteArray[i]);
            }
            return strDigest;
        }
    
        /**
         * 将字节转换为十六进制字符串
         * 
         * @param mByte
         * @return
         */
        private static String byteToHexStr(byte mByte) {
            char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
            char[] tempArr = new char[2];
            tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
            tempArr[1] = Digit[mByte & 0X0F];
    
            String s = new String(tempArr);
            return s;
        }
    }

    web.xml中配置了coreServlet:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
        http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
        <servlet>
            <servlet-name>coreServlet</servlet-name>
            <servlet-class>
                org.liufeng.course.servlet.CoreServlet
            </servlet-class>
        </servlet>
    
        <!-- /coreServlet用于指定该Servlet的访问路径 -->
        <servlet-mapping>
            <servlet-name>coreServlet</servlet-name>
            <url-pattern>/coreServlet</url-pattern>
        </servlet-mapping>
    
        <welcome-file-list>
            <welcome-file>index.jsp</welcome-file>
        </welcome-file-list>
    </web-app>

    微信公众平台的配置截图:

    微信平台提示接入成功。

  • 相关阅读:
    Java实现 蓝桥杯VIP 算法提高 排队打水问题
    Java实现 蓝桥杯VIP 算法提高 排队打水问题
    Java实现 蓝桥杯VIP 算法提高 排队打水问题
    Java实现 蓝桥杯VIP 算法提高 特殊的质数肋骨
    Java实现 蓝桥杯VIP 算法提高 特殊的质数肋骨
    Java实现 蓝桥杯VIP 算法提高 特殊的质数肋骨
    Java实现 蓝桥杯VIP 算法提高 特殊的质数肋骨
    现在使用控件, 更喜欢继承(覆盖控件已有的函数,很奇怪的一种使用方式)
    Controls 属性与继承 TShape 类的小练习(使用TShape可以解决很多图形问题)
    QT创建窗口程序、消息循环和WinMain函数(为主线程建立了一个QEventLoop,并执行exec函数)
  • 原文地址:https://www.cnblogs.com/haojiahong/p/4564891.html
Copyright © 2011-2022 走看看