Java微信公众平台开发(一)--接入微信公众平台
今天正式开始微信公众平台的二次开发。网上有很多的及射入微信公众平台的教程。总的来说都差不多,当了解了接入流程解析,什么都显得理所当然。
所以我们还是先看微信给出的官网文档吧:
地址:http://mp.weixin.qq.com/wiki/8/f9a0b8382e0b77d87b3bcc1ce6fbc104.html
通过文档我们可以看出其中接入微信公众平台开发,开发者需要按照如下步骤完成:
- 填写服务器配置
- 验证服务器地址的有效性
- 依据接口文档实现业务逻辑
一、验证服务器代码编写。
按照开发文档我们知道我们的应用服务器需要接受微信服务器的get请求,其中包含四个参数(signature、timestamp、nonce、echostr)然后通过校验方式校验服务器的可靠性,校验方式如下:
-
将token、timestamp、nonce三个参数进行字典序排序
-
将三个参数字符串拼接成一个字符串进行sha1加密
-
开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
①我在这里写了一个工具类去实现其中的前两步,将三个参数排序并返回sha1加密后的字符串,代码如下:
1 package com.gede.wechat.util; 2 3 import java.security.MessageDigest; 4 import java.security.NoSuchAlgorithmException; 5 import java.util.Arrays; 6 7 /** 8 * @author gede 9 * @version date:2019年5月22日 下午2:50:43 10 * @description : 11 */ 12 public class SignUtil { 13 // 与接口配置信息中的 Token 要一致 14 private static String token = "gede"; 15 /** 16 * 验证签名 17 * @param signature 18 * @param timestamp 19 * @param nonce 20 * @return 21 */ 22 public static boolean checkSignature(String signature, String timestamp, String nonce) { 23 String[] arr = new String[] { token, timestamp, nonce }; 24 // 将 token、timestamp、nonce 三个参数进行字典序排序 25 Arrays.sort(arr); 26 StringBuilder content = new StringBuilder(); 27 for (int i = 0; i < arr.length; i++) { 28 content.append(arr[i]); 29 } 30 MessageDigest md = null; 31 String tmpStr = null; 32 33 try { 34 md = MessageDigest.getInstance("SHA-1"); 35 // 将三个参数字符串拼接成一个字符串进行 sha1 加密 36 byte[] digest = md.digest(content.toString().getBytes()); 37 tmpStr = byteToStr(digest); 38 } catch (NoSuchAlgorithmException e) { 39 e.printStackTrace(); 40 } 41 42 content = null; 43 // 将 sha1 加密后的字符串可与 signature 对比,标识该请求来源于微信 44 return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false; 45 } 46 47 /** 48 * 将字节数组转换为十六进制字符串 49 * @param byteArray 50 * @return 51 */ 52 private static String byteToStr(byte[] byteArray) { 53 String strDigest = ""; 54 for (int i = 0; i < byteArray.length; i++) { 55 strDigest += byteToHexStr(byteArray[i]); 56 } 57 return strDigest; 58 } 59 60 /** 61 * 将字节转换为十六进制字符串 62 * @param mByte 63 * @return 64 */ 65 private static String byteToHexStr(byte mByte) { 66 char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 67 char[] tempArr = new char[2]; 68 tempArr[0] = Digit[(mByte >>> 4) & 0X0F]; 69 tempArr[1] = Digit[mByte & 0X0F]; 70 String s = new String(tempArr); 71 return s; 72 } 73 }
②将我们的工具类应用到我们的服务器验证过程中,这里我新建一个controller为WechatSecurity,实现同一个get用于接收参数和返回验证参数,简单代码如下:
1 package com.gede.wechat.controller; 2 3 import java.io.PrintWriter; 4 5 import javax.servlet.http.HttpServletRequest; 6 import javax.servlet.http.HttpServletResponse; 7 8 import org.apache.log4j.Logger; 9 import org.springframework.stereotype.Controller; 10 import org.springframework.web.bind.annotation.RequestMapping; 11 import org.springframework.web.bind.annotation.RequestMethod; 12 import org.springframework.web.bind.annotation.RequestParam; 13 14 import com.gede.wechat.util.SignUtil; 15 16 /** 17 * @author gede 18 * @version date:2019年5月22日 下午2:53:46 19 * @description : 20 */ 21 @Controller 22 @RequestMapping("/wechat") 23 public class WechatSecurity { 24 private static Logger logger = Logger.getLogger(WechatSecurity.class); 25 26 @RequestMapping(value = "security", method = RequestMethod.GET) 27 public void doGet( 28 HttpServletRequest request, 29 HttpServletResponse response, 30 @RequestParam(value = "signature", required = true) String signature, 31 @RequestParam(value = "timestamp", required = true) String timestamp, 32 @RequestParam(value = "nonce", required = true) String nonce, 33 @RequestParam(value = "echostr", required = true) String echostr) { 34 try { 35 if (SignUtil.checkSignature(signature, timestamp, nonce)) { 36 PrintWriter out = response.getWriter(); 37 out.print(echostr); 38 out.close(); 39 } else { 40 logger.info("这里存在非法请求!"); 41 } 42 } catch (Exception e) { 43 logger.error(e, e); 44 } 45 } 46 47 @RequestMapping(value = "security", method = RequestMethod.POST) 48 // post方法用于接收微信服务端消息 49 public void DoPost() { 50 System.out.println("这是post方法!"); 51 } 52 }
那么到这里我们的服务器验证的代码就基本完成了,下面我们就进入验证过程!
二、服务器端验证。
1、首先要将我们的内网穿透工具运行起来,然后再本地服务器上运行我们的项目。
2.、在这里我用的是测试号,其他的大家对号入座。测试号登录网址 https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
3、当我们点击提交时,发现提交失败。原因是之前忘记配置springMVC ,在准备工作中我们只是开启了spring功能,现在我们开始配置springMVC
在我们项目的src 下,新增appServlet.xml配置文件。开启mvc,并指明mvc扫描包,代码如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"> <mvc:annotation-driven></mvc:annotation-driven> <mvc:default-servlet-handler/> <context:component-scan base-package="com.gede.wechat.controller"></context:component-scan> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/"></property> <property name="suffix" value=".jsp"></property> </bean> </beans>
4、再打开我们的web.xml,添加appServlet.xml的扫描。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <display-name>mychat</display-name> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:appServlet.xml </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
5、这个时候我们再次重启本地服务器,然后提交接口配置信息就大功告成了。