Java微信公众号开发

开发环境的准备

转载地址:http://www.2cto.com/weixin/201505/401807.html
  • 微信公众号
  • 外网映射工具(开发调试)

  与微信的对接的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
package org.gpf.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.gpf.util.CheckUtil;
/**
  * 接收微信服务器发送的4个参数并返回echostr
  */
public class WeixinServlet extends HttpServlet {
 
     public void doGet(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, 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参数内容
         }
     }
 
     public void doPost(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, 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
package org.gpf.util;
 
import java.util.Arrays;
 
import org.apache.commons.codec.digest.DigestUtils;
 
/**
  * 校验的工具类
  */
public class CheckUtil {
 
     private static final String token = "weixin" ;
     public static boolean checkSignature(String signature,String timestamp,String nonce){
         
         String[] arr = new String[] { token, timestamp, nonce };
         
         // 排序
         Arrays.sort(arr);
         // 生成字符串
         StringBuilder content = new StringBuilder();
         for ( int i = 0 ; i < arr.length; i++) {
             content.append(arr[i]);
         }
         
         // sha1加密
         String temp = getSHA1String(content.toString());
         
         return temp.equals(signature); // 与微信传递过来的签名进行比较
     }
     
     private static String getSHA1String(String data){
         return DigestUtils.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
package org.gpf.servlet;
 
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Map;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.dom4j.DocumentException;
import org.gpf.po.TextMeaasge;
import org.gpf.util.CheckUtil;
import org.gpf.util.MessageUtil;
/**
  * 微信消息的接收和响应
  */
public class WeixinServlet extends HttpServlet {
 
     /**
      * 接收微信服务器发送的4个参数并返回echostr
      */
     public void doGet(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, 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参数内容
         }
     }
 
     /**
      * 接收并处理微信客户端发送的请求
      */
     public void doPost(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, 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 = new TextMeaasge();
                 text.setFromUserName(toUserName);         // 发送和回复是反向的
                 text.setToUserName(fromUserName);
                 text.setMsgType( "text" );
                 text.setCreateTime( new Date().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
package org.gpf.util;
 
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import javax.servlet.http.HttpServletRequest;
 
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.gpf.po.TextMeaasge;
 
import com.thoughtworks.xstream.XStream;
 
/**
  * 实现消息的格式转换(Map类型和XML的互转)
  */
public class MessageUtil {
 
     /**
      * 将XML转换成Map集合
      */
     public static Map<String, String>xmlToMap(HttpServletRequest request) throws IOException, DocumentException{
         
         Map<String, String> map = new HashMap<String, String>();
         SAXReader reader = new SAXReader();            // 使用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();
         return map;
     }
     
     /**
      * 将文本消息对象转换成XML
      */
     public static String textMessageToXML(TextMeaasge textMessage){
         
         XStream xstream = new XStream();              // 使用XStream将实体类的实例转换成xml格式   
         xstream.alias( "xml" , textMessage.getClass()); // 将xml的默认根节点替换成“xml”
         return xstream.toXML(textMessage);
         
     }
     
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值