首页 > PHP资讯 > 工具库 > 微信开发入门学习总结

微信开发入门学习总结

工具库
  上一篇《微信开发—微信开发环境搭建》我们已经完成了微信开发的准备工作,准备工作完成之后,就要开始步入正题了。

一、微信公众平台的基本原理

  在开始做之前,先简单介绍了微信公众平台的基本原理。

  微信服务器就相当于一个转发服务器,终端(手机、Pad等)发起请求至微信服务器,微信服务器然后将请求转发给我们的应用服务器。应用服务器处理完毕后,将响应数据回发给微信服务器,微信服务器再将具体响应信息回复到微信App终端。

  通信协议为:HTTP

  数据传输格式为:XML

  具体的流程如下图所示:

  

  编写一个servlevt,在其中的doGet方法中定义校验方法,具体代码如下:

package me.gacl.wx.web.servlet;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 java.io.IOException;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.util.Arrays;/** * Created by xdp on 2016/1/25. * 使用@WebServlet注解配置WxServlet,urlPatterns属性指明了WxServlet的访问路径 */@WebServlet(urlPatterns="/WxServlet")public class WxServlet extends HttpServlet {    /**     * Token可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)     * 比如这里我将Token设置为gacl     */    private final String TOKEN = "gacl";    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {    }    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        System.out.println("开始校验签名");        /**         * 接收微信服务器发送请求时传递过来的4个参数         */        String signature = request.getParameter("signature");//微信加密签名signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。        String timestamp = request.getParameter("timestamp");//时间戳        String nonce = request.getParameter("nonce");//随机数        String echostr = request.getParameter("echostr");//随机字符串        //排序        String sortString = sort(TOKEN, timestamp, nonce);        //加密        String mySignature = sha1(sortString);        //校验签名        if (mySignature != null && mySignature != "" && mySignature.equals(signature)) {            System.out.println("签名校验通过。");            //如果检验成功输出echostr,微信服务器接收到此输出,才会确认检验完成。            //response.getWriter().println(echostr);            response.getWriter().write(echostr);        } else {            System.out.println("签名校验失败.");        }    }    /**     * 排序方法     *     * @param token     * @param timestamp     * @param nonce     * @return     */    public String sort(String token, String timestamp, String nonce) {        String[] strArray = {token, timestamp, nonce};        Arrays.sort(strArray);        StringBuilder sb = new StringBuilder();        for (String str : strArray) {            sb.append(str);        }        return sb.toString();    }    /**     * 将字符串进行sha1加密     *     * @param str 需要加密的字符串     * @return 加密后的内容     */    public String sha1(String str) {        try {            MessageDigest digest = MessageDigest.getInstance("SHA-1");            digest.update(str.getBytes());            byte messageDigest[] = digest.digest();            // Create Hex String            StringBuffer hexString = new StringBuffer();            // 字节数组转换为 十六进制 数            for (int i = 0; i < messageDigest.length; i++) {                String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);                if (shaHex.length() < 2) {                    hexString.append(0);                }                hexString.append(shaHex);            }            return hexString.toString();        } catch (NoSuchAlgorithmException e) {            e.printStackTrace();        }        return "";    }}

  我这里用的Servlet3.0,使用Servlet3.0的好处就是可以直接使用@WebServlet注解映射Servlet的访问路径,不再需要在web.xml文件中进行配置.

  将WxStudy项目部署到Tomcat服务器中运行,直接启动项目,然后用ngrok将本地8080端口映射到外网(如何使用ngrok请参考博客《微信开发—微信开发环境搭建》)。如下图所示:

  

  下面正式开始在工程中实现以上思路,因为返回的数据都是json格式,这里会用到阿里的fastjson库,为构造请求和处理请求后的数据序列化和反序列化提供支持。

  1.定义一个AccessToken实体类

package me.gacl.wx.entry;/** * AccessToken的数据模型 * Created by xdp on 2016/1/25. */public class AccessToken {    //获取到的凭证    private String accessToken;    //凭证有效时间,单位:秒    private int expiresin;    public String getAccessToken() {        return accessToken;    }    public void setAccessToken(String accessToken) {        this.accessToken = accessToken;    }    public int getExpiresin() {        return expiresin;    }    public void setExpiresin(int expiresin) {        this.expiresin = expiresin;    }}

 2.定义一个AccessTokenInfo类,用于存放获取到的AccessToken,代码如下:

package me.gacl.wx.Common;import me.gacl.wx.entry.AccessToken;/** * Created by xdp on 2016/1/25. */public class AccessTokenInfo {    //注意是静态的    public static AccessToken accessToken = null;}

  3.编写一个用于发起https请求的工具类NetWorkHelper,代码如下:

package me.gacl.wx.util;import javax.net.ssl.*;import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.net.URL;import java.security.cert.CertificateException;import java.security.cert.X509Certificate;/** * 访问网络用到的工具类 */public class NetWorkHelper {    /**     * 发起Https请求     * @param reqUrl 请求的URL地址     * @param requestMethod     * @return 响应后的字符串     */    public String getHttpsResponse(String reqUrl, String requestMethod) {        URL url;        InputStream is;        String resultData = "";        try {            url = new URL(reqUrl);            HttpsURLConnection con = (HttpsURLConnection) url.openConnection();            TrustManager[] tm = {xtm};            SSLContext ctx = SSLContext.getInstance("TLS");            ctx.init(null, tm, null);            con.setSSLSocketFactory(ctx.getSocketFactory());            con.setHostnameVerifier(new HostnameVerifier() {                @Override                public boolean verify(String arg0, SSLSession arg1) {                    return true;                }            });            con.setDoInput(true); //允许输入流,即允许下载            //在android中必须将此项设置为false            con.setDoOutput(false); //允许输出流,即允许上传            con.setUseCaches(false); //不使用缓冲            if (null != requestMethod && !requestMethod.equals("")) {                con.setRequestMethod(requestMethod); //使用指定的方式            } else {                con.setRequestMethod("GET"); //使用get请求            }            is = con.getInputStream();   //获取输入流,此时才真正建立链接            InputStreamReader isr = new InputStreamReader(is);            BufferedReader bufferReader = new BufferedReader(isr);            String inputLine;            while ((inputLine = bufferReader.readLine()) != null) {                resultData += inputLine + "n";            }            System.out.println(resultData);        } catch (Exception e) {            e.printStackTrace();        }        return resultData;    }    X509TrustManager xtm = new X509TrustManager() {        @Override        public X509Certificate[] getAcceptedIssuers() {            return null;        }        @Override        public void checkServerTrusted(X509Certificate[] arg0, String arg1)                throws CertificateException {        }        @Override        public void checkClientTrusted(X509Certificate[] arg0, String arg1)                throws CertificateException {        }    };}

  getHttpsResponse方法是请求一个https地址,参数requestMethod为字符串“GET”或者“POST”,传null或者“”默认为get方式。

  4.定义一个默认启动的servlet,在init方法中启动一个新的线程去获取accessToken

package me.gacl.wx.web.servlet;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import me.gacl.wx.Common.AccessTokenInfo;import me.gacl.wx.entry.AccessToken;import me.gacl.wx.util.NetWorkHelper;import javax.servlet.ServletException;import javax.servlet.annotation.WebInitParam;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;/** * 用于获取accessToken的Servlet * Created by xdp on 2016/1/25. */@WebServlet(        name = "AccessTokenServlet",        urlPatterns = {"/AccessTokenServlet"},        loadOnStartup = 1,        initParams = {                @WebInitParam(name = "appId", value = "wxbe4d433e857e8bb1"),                @WebInitParam(name = "appSecret", value = "ccbc82d560876711027b3d43a6f2ebda")        })public class AccessTokenServlet extends HttpServlet {    @Override    public void init() throws ServletException {        System.out.println("启动WebServlet");        super.init();        final String appId = getInitParameter("appId");        final String appSecret = getInitParameter("appSecret");        //开启一个新的线程        new Thread(new Runnable() {            @Override            public void run() {                while (true) {                    try {                        //获取accessToken                        AccessTokenInfo.accessToken = getAccessToken(appId, appSecret);                        //获取成功                        if (AccessTokenInfo.accessToken != null) {                            //获取到access_token 休眠7000秒,大约2个小时左右                            Thread.sleep(7000 * 1000);                            //Thread.sleep(10 * 1000);//10秒钟获取一次                        } else {                            //获取失败                            Thread.sleep(1000 * 3); //获取的access_token为空 休眠3秒                        }                    } catch (Exception e) {                        System.out.println("发生异常:" + e.getMessage());                        e.printStackTrace();                        try {                            Thread.sleep(1000 * 10); //发生异常休眠1秒                        } catch (Exception e1) {                        }                    }                }            }        }).start();    }    /**     * 获取access_token     *     * @return AccessToken     */    private AccessToken getAccessToken(String appId, String appSecret) {        NetWorkHelper netHelper = new NetWorkHelper();        /**         * 接口地址为
可以正常与微信服务器通信

  登录到我们的测试公众号的管理后台,然后用微信扫描一下测试号的二维码,如下图所示:

   

  我们的公众号应用响应给微信用户的文本消息的XML数据如下:

      1453755900000    

  测试公众号的管理后台也可以看到关注测试号的用户列表,如下图所示:

  

  通过这个简单的入门程序,我们揭开了微信开发的神秘面纱了.

 更多微信开发入门学习总结相关文章请关注PHP中文网!

工具库

本文由欣才IT学院整理发布,未经许可,禁止转载。
支持24不支持0