Java微信公众号开发

来源:互联网 发布:ubuntu打开怎么用 编辑:程序博客网 时间:2024/06/06 09:25

微信公众平台是腾讯为了让用户申请和管理微信公众账号而推出的一个web平台。微信公众账号的种类可以分为3种,并且一旦选定不可更改。按照功能的限制从小到大依次为:订阅号、服务号、企业号。个人只能注册订阅号。注册地址:https://mp.weixin.qq.com/。

开发环境的准备

  • 微信公众号
  • 外网映射工具(开发调试)

  与微信的对接的URL应该满足以下的条件:

  • 在公网上能够访问
  • 只支持80端口

  映射工具有很多,例如花生壳,ngrok可以将内网映射到公网上面,这样就可以使用公网访问本机的网络服务。下载链接: http://pan.baidu.com/s/1i3u26St 密码: v4e8(里面有简明的教程)。

微信公众号的数据交互原理

\\

  我们的主要开发就是微信公众号服务器的开发。

开发模式的接入

  进入微信公众号平台之后进入开发者中心,在开发者中心中找到开发者文档,在新手指南中有接入的相关步骤。依据接入文档有以下的实现:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
packageorg.gpf.servlet;
 
importjava.io.IOException;
importjava.io.PrintWriter;
 
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
 
importorg.gpf.util.CheckUtil;
/**
 * 接收微信服务器发送的4个参数并返回echostr
 */
publicclass WeixinServlet extendsHttpServlet {
 
    publicvoid doGet(HttpServletRequest request, HttpServletResponse response)
            throwsServletException, IOException {
 
        // 接收微信服务器以Get请求发送的4个参数
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
         
        PrintWriter out = response.getWriter();
        if(CheckUtil.checkSignature(signature, timestamp, nonce)) {
            out.print(echostr);       // 校验通过,原样返回echostr参数内容
        }
    }
 
    publicvoid doPost(HttpServletRequest request, HttpServletResponse response)
            throwsServletException, IOException {
 
        doGet(request, response);
    }
 
}

  校验工具类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
packageorg.gpf.util;
 
importjava.util.Arrays;
 
importorg.apache.commons.codec.digest.DigestUtils;
 
/**
 * 校验的工具类
 */
publicclass CheckUtil {
 
    privatestatic final String token = "weixin";
    publicstatic boolean checkSignature(String signature,String timestamp,String nonce){
         
        String[] arr = newString[] { token, timestamp, nonce };
         
        // 排序
        Arrays.sort(arr);
        // 生成字符串
        StringBuilder content = newStringBuilder();
        for(inti = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
         
        // sha1加密
        String temp = getSHA1String(content.toString());
         
        returntemp.equals(signature); // 与微信传递过来的签名进行比较
    }
     
    privatestatic String getSHA1String(String data){
        returnDigestUtils.sha1Hex(data);    // 使用commons codec生成sha1字符串
    }
}

  Servlet配置:

?
1
2
3
4
5
6
7
8
9
servlet>
<servlet-name>WeixinServlet</servlet-name>
<servlet-class>org.gpf.servlet.WeixinServlet</servlet-class>
</servlet>
 
<servlet-mapping>
<servlet-name>WeixinServlet</servlet-name>
<url-pattern>/wx.do</url-pattern>
</servlet-mapping>

  接下来通过映射工具将本地的服务器映射到公网,从公网访问Servlet。

\

  开发模式和编辑模式是互斥的,如果启动了开发模式,则自定义菜单和自动回复将失效!

消息的接收和响应

  参照文档,当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。所以我们需要更改我们的Servlet中的doPost方法,因为微信服务器与我们的服务器之间是通过XML传递数据的,因此我们需要实现消息实体与XML之间的互相转换。可以采用第三方jar包XStream完成。

  处理微信服务器与本机服务器进行交互的Servlet:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
packageorg.gpf.servlet;
 
importjava.io.IOException;
importjava.io.PrintWriter;
importjava.util.Date;
importjava.util.Map;
 
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
 
importorg.dom4j.DocumentException;
importorg.gpf.po.TextMeaasge;
importorg.gpf.util.CheckUtil;
importorg.gpf.util.MessageUtil;
/**
 * 微信消息的接收和响应
 */
publicclass WeixinServlet extendsHttpServlet {
 
    /**
     * 接收微信服务器发送的4个参数并返回echostr
     */
    publicvoid doGet(HttpServletRequest request, HttpServletResponse response)
            throwsServletException, IOException {
 
        // 接收微信服务器以Get请求发送的4个参数
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
         
        PrintWriter out = response.getWriter();
        if(CheckUtil.checkSignature(signature, timestamp, nonce)) {
            out.print(echostr);       // 校验通过,原样返回echostr参数内容
        }
    }
 
    /**
     * 接收并处理微信客户端发送的请求
     */
    publicvoid doPost(HttpServletRequest request, HttpServletResponse response)
            throwsServletException, IOException {
 
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/xml;charset=utf-8");
        PrintWriter out = response.getWriter();
        try{
            Map<String, String> map = MessageUtil.xmlToMap(request);
            String toUserName = map.get("ToUserName");
            String fromUserName = map.get("FromUserName");
            String msgType = map.get("MsgType");
            String content = map.get("Content");
             
            String message = null;
            if("text".equals(msgType)) {                // 对文本消息进行处理
                TextMeaasge text = newTextMeaasge();
                text.setFromUserName(toUserName);        // 发送和回复是反向的
                text.setToUserName(fromUserName);
                text.setMsgType("text");
                text.setCreateTime(newDate().getTime());
                text.setContent("你发送的消息是:"+ content);
                message = MessageUtil.textMessageToXML(text);
                System.out.println(message);           
            }
            out.print(message);                           // 将回应发送给微信服务器
        }catch(DocumentException e) {
            e.printStackTrace();
        }finally{
            out.close();
        }
    }
 
}

  按照微信的接口文档编写的文本消息实体类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
packageorg.gpf.util;
 
importjava.io.IOException;
importjava.io.InputStream;
importjava.util.HashMap;
importjava.util.List;
importjava.util.Map;
 
importjavax.servlet.http.HttpServletRequest;
 
importorg.dom4j.Document;
importorg.dom4j.DocumentException;
importorg.dom4j.Element;
importorg.dom4j.io.SAXReader;
importorg.gpf.po.TextMeaasge;
 
importcom.thoughtworks.xstream.XStream;
 
/**
 * 实现消息的格式转换(Map类型和XML的互转)
 */
publicclass MessageUtil {
 
    /**
     * 将XML转换成Map集合
     */
    publicstatic Map<String, String>xmlToMap(HttpServletRequest request) throwsIOException, DocumentException{
         
        Map<String, String> map = newHashMap<String, String>();
        SAXReader reader = newSAXReader();            // 使用dom4j解析xml
        InputStream ins = request.getInputStream(); // 从request中获取输入流
        Document doc = reader.read(ins);
         
        Element root = doc.getRootElement();         // 获取根元素
        List<Element> list = root.elements();        // 获取所有节点
         
        for(Element e : list) {
            map.put(e.getName(), e.getText());
            System.out.println(e.getName() + "--->"+ e.getText());
        }
        ins.close();
        returnmap;
    }
     
    /**
     * 将文本消息对象转换成XML
     */
    publicstatic String textMessageToXML(TextMeaasge textMessage){
         
        XStream xstream = newXStream();              // 使用XStream将实体类的实例转换成xml格式   
        xstream.alias("xml", textMessage.getClass()); // 将xml的默认根节点替换成“xml”
        returnxstream.toXML(textMessage);
         
    }
     
}
0 0
原创粉丝点击