微信公众平台开发好像已经火了很长一段时间,我好像有点后知后觉。但只从了解它后便有点不可收拾之势,脑袋里总想着开发一个自己的公众号,虽然不知道具体做什么。
下面就说说自己这段时间对公众号的学习。
欲善其事,必先利其器。在开发之前先要申请一个公众号,公众号有三种,个人比较容易申请的是订阅号,服务号还要审核,稍微麻烦一点,对于个人开发我建议申请服务号,
因为后面会做自定义菜单的功能。再就是我们需要有一个公网的服务器,这个可以申请sina的sae和百度的bae,个人比较喜欢sina的一点,比较容易上手。这里不讲公众号的申请
和sae服务器的申请和配置。
再做完这两件事后我们就可以开始公众号的开发了。首先我们需要了解微信公众号的工作流程,对其有个整体的把握,要不今后就会换挺多简单错误。在启用开发者模式情况下
(下面内容都是在此模式下)当用户通过微信客服端发送消息到微信服务后,微信服务器会将此消息转发给我们的公网服务器,如上面所说sae和bae(以下内容也均是在sae下完成)
。具体的业务逻辑就在sae上完成,处理完后再将结果发回微信服务器,微信服务器再发给用户。
申请到公众号后,登陆公众品台,可以看到微信已经帮我们准备好了许多功能,我们不需要编写任何代码就可以完成一个具有基本的公众号,但这不是本文的目的,我们是要
用自己的代码实现一些功能,因此我们要进入开发者中心去配置服务器接口。
下面就是本文核心内容:
试想一下让两个完全不沾边的服务器(微信服务器和sae)对接的风险,因此必须有什么验证机制的存在。具体的验证过程是
1、微信服务器会以get方式调用我们部署在sae服务器上的servlet,并传signature、timestamp、nonce、echostr四个参数。其中signature是微信加密签名;timestamp
是时间戳,防止即使有别有用心之人获得另外的参数而因时间戳的不一致无法完成验证;nonce是随机数;echostr是随机字符串,用于返回给微信服务器作比较。
2、servlet接收到以上数据后,会将token(在servlet中写好且要用公众平台上开发者中心的token相同)timestamp、nonce按字典方式排序,再拼接成字符串进行sha1加密
将加密后的字符串与signature比较,如果相同就返回echostr。
3、微信服务器接收到返回的echostr,与发过去的echostr相比较,如果相同,就接入成功,否则失败。
1 /** 2 * 核心请求处理类 3 * 4 */ 5 public class CrazyServlet extends HttpServlet { 6 7 private static final long serialVersionUID = 5021188348833856475L; 8 @Override 9 protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { 10 // 微信加密签名 11 String signature = request.getParameter("signature"); 12 // 时间戳 13 String timestamp = request.getParameter("timestamp"); 14 // 随机数 15 String nonce = request.getParameter("nonce"); 16 // 随机字符串 17 String echostr = request.getParameter("echostr"); 18 PrintWriter out = response.getWriter(); 19 // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败 20 if (SignUtil.checkSignature(signature, timestamp, nonce)) { 21 out.print(echostr); 22 } 23 out.close(); 24 out = null; 25 }
1 /** 2 * 请求校验工具类 3 */ 4 public class SignUtil { 5 // 与接口配置信息中的Token要一致 6 private static String token = "845C2550903CE6FA54CACDB82EAD4350"; 7 8 9 public static boolean checkSignature(String signature, String timestamp, 10 String nonce) { 11 //从请求中(也就是微信服务器传过来的)拿到的token, timestamp, nonce 12 String[] arr = new String[] { token, timestamp, nonce }; 13 // 将token、timestamp、nonce三个参数进行字典序排序 14 sort(arr); 15 StringBuilder content = new StringBuilder(); 16 for (int i = 0; i < arr.length; i++) { 17 content.append(arr[i]); 18 } 19 MessageDigest md = null; 20 String tmpStr = null; 21 22 try { 23 md = MessageDigest.getInstance("SHA-1"); 24 // 将三个参数字符串拼接成一个字符串进行sha1加密 25 byte[] digest = md.digest(content.toString().getBytes()); 26 //将字节数组转成字符串 27 tmpStr = byteToStr(digest); 28 } catch (NoSuchAlgorithmException e) { 29 e.printStackTrace(); 30 } 31 32 content = null; 33 // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信 34 return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false; 35 } 36 37 //将加密后的字节数组变成字符串 38 private static String byteToStr(byte[] byteArray) { 39 String strDigest = ""; 40 for (int i = 0; i < byteArray.length; i++) { 41 strDigest += byteToHexStr(byteArray[i]); 42 } 43 return strDigest; 44 } 45 46 private static String byteToHexStr(byte mByte) { 47 char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 48 'B', 'C', 'D', 'E', 'F' }; 49 char[] tempArr = new char[2]; 50 tempArr[0] = Digit[(mByte >>> 4) & 0X0F]; 51 tempArr[1] = Digit[mByte & 0X0F]; 52 53 String s = new String(tempArr); 54 return s; 55 } 56 //用于字典排序 57 public static void sort(String a[]) { 58 for (int i = 0; i < a.length - 1; i++) { 59 for (int j = i + 1; j < a.length; j++) { 60 if (a[j].compareTo(a[i]) < 0) { 61 String temp = a[i]; 62 a[i] = a[j]; 63 a[j] = temp; 64 } 65 } 66 } 67 } 68 }
再sae上配置好后,点击开发者中心,首先启用服务器配置。填写url和token(和java代码中的一样)、EncodingAESKey是随机生成,消息加解密方式选择明文模式。
这里的url就是你在sae中创建应用的地址,我们已经将写好的java代码上传到这个地址。token是微信服务器和sae服务器进行对接验证是用到的(必须保持一致),消息
加密暂时选择明文模式,如果选择加密模式需要编写加密代码,以后会再转到加密或兼容模式,这里先用明文模式。这样我们就完成了,点击提交(记得sae服务器要打开),
如果现实成功就说明接入完成,我们可以接着做下面的工作了。