• 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>

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

    微信平台提示接入成功。

  • 相关阅读:
    新式类、经典类与多继承
    实现抽象类之方式二
    实现抽象类之方式一
    re模块
    28个高频Linux命令
    Git使用教程
    编程语言介绍
    编码
    进制
    操作系统简史
  • 原文地址:https://www.cnblogs.com/haojiahong/p/4564891.html
Copyright © 2020-2023  润新知