要搭建加密传输的微信公众号消息传输,首先要在开发这平台下载一下微信加密的相关jar包,并做一些准备。准备的步骤如下:

1.打开开发者文档,找到消息加减密--->接入指引,如下图所示:

2.在页面底部找到实例代码,并下载解压,下载的地方如下图所示:

3.在解压的地方找到java版本,并做如下准备:

(1)将commons-codec-1.9.jar导入到项目中。

(2)将dist下的aes-jre1.6.jar导入到项目中。

(3)打开readme.txt,按照他的指示操作。红色对勾的地方很重要。

要下载的东西就是下图标记的地方

这样准备工作就完成了,可以进入正式的代码编写了。

代码部分的解释基本都放在注释中,首先开用来核心控制的controller。内容如下:

package org.calonlan.soulpower.controller;import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.util.Map;import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.calonlan.soulpower.service.WeiInfoService;
import org.calonlan.soulpower.util.AesUtils;
import org.calonlan.soulpower.util.MessageUtil;
import org.calonlan.soulpower.util.SignUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;/*** @author Administrator*         这个controller是用来处理消息的核心controller,在这里有两个请求地址都为/sign的请求地址,一个是用get方式,用来*         做服务器和微信服务器之间的认证;一个是post方式,用来在服务器和微信服务器之间传递消息。*/
@Controller
@RequestMapping("/core")
public class CoreController {@Resourceprivate WeiInfoService weiInfoService;/** 这个service大家可以不用管,* 因为在我的项目中我是把所有的微信相关的配置信息都保存在一个weiInfo的类中了* ,这里只会用到token。*//*** @param request* @param response* @throws IOException* @throws ServletException* 用来和微信服务器之间相互认证*/@RequestMapping(method = RequestMethod.GET, value = "/sign")public void goGet(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException {String signature = request.getParameter("signature");// 获得signatureString timestamp = request.getParameter("timestamp");// 获得timestampString nonce = request.getParameter("nonce");// 获得nonceString echostr = request.getParameter("echostr");// 获得echostr/** 上面的四个参数都是微信服务器发送过来的,其中signature、timestamp、nonce是要参与服务器的验证的,* 而echostr是在我们通过验证后返回给服务器告诉服务器我们就是要通讯 的那个远程服务器*/PrintWriter out = response.getWriter();if (SignUtil.checkSignature(signature, timestamp, nonce,weiInfoService.get())) {//在SignUtil中使用checkSignature来进行验证,代码附在后面。out.print(echostr);//验证通过后就把echostr返回给微信服务器。}out.close();out = null;}@RequestMapping(method = RequestMethod.POST, value = "/sign")/*** * 用来和微信服务器通信* * */public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");/** 进行消息分发 *//* 首先定义一个空的回复消息 */String respMessage = "";try {/* 从请求中获得xml格式的信息。并转化为map类型 */Map<String, String> requestMapSecret = MessageUtil.parseXml(request);//从request中获得获得xml,并解析,代码附在后面/* 获得解密后的消息正文 */String mingwenXML = AesUtils.descMessage(//用微信官方给的jar包中的AesUtils来对消息进行解密requestMapSecret.get("Encrypt"),/* 加密的消息体 */request.getParameter("msg_signature"),/* 请求中的消息签名 */request.getParameter("timestamp"),/* 时间戳 */request.getParameter("nonce"));/* 无序数列 *//* 将明文再次进行xml解析 */Map<String, String> requestMap = MessageUtil.parseXml(new StringReader(mingwenXML));//将明文的xml再次解析后放入map中,/** 获得用户发来的消息类型,并做相应的处理 */String messageType = requestMap.get("MsgType");System.out.println(messageType);/*处理不同格式的消息类型开始-------------------------------------------------------*/// 用户发来的是文本消息if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {System.out.println(requestMap.get("Content"));}// 用户发来的是图片消息else if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {}// 用户发来地理位置信息else if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {}// 用户发来链接消息else if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) {}// 用户发来音频消息else if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) {}/** 事件推送的处理 */else if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {// 事件类型String eventType = requestMap.get("Event");// 订阅if (eventType.equals(MessageUtil.REQ_MESSAGE_TYPE_SUBSCRIBE)) {}// 取消订阅else if (eventType.equals(MessageUtil.REQ_MESSAGE_TYPE_UNSUBSCRIBE)) {}// 点击按钮事件else if (eventType.equals(MessageUtil.REQ_MESSAGE_TYPE_CLICK)) {}}/*处理不同格式的消息类型介绍-------------------------------------------------------*//*对于不同类型的消息的处理网上有很多高手已经发表了很多文章了,我自己也会总结一下,不过不是在这里---------*/// 给返回的消息加密AesUtils.aescMessage(respMessage,request.getParameter("timestamp"),request.getParameter("nonce"));} catch (Exception e) {e.printStackTrace();}/*返回消息给微信服务器,然后微信服务器把消息转发给用户···额,貌似我们聊什么,微信服务器都是可以截获的,*/PrintWriter out = response.getWriter();out.print(respMessage);out.close();}
}

SignUtil中的checkSignature代码如下:

 public static boolean checkSignature(String signature, String timestamp,String nonce, WeiInfo info) {/** 微信服务器发送过来的signature是通过某些处理然后进行SHA1加密的,我们来用它发过来的信息自己生成一个signature,* 然后两者之间进行比对,一致的话我们就是伙伴,不一致就拒绝它*/String[] arr = new String[] { info.getToken(), timestamp, nonce };/* token是我们自己填写的,具体填写位置见下图;timestamp、nonce是微信服务器发送过来的,这里我们把他们都放到数组中。*/Arrays.sort(arr);//对数组中的数据进行字典排序。。。。要不然加密出来的东西是没用的StringBuilder content = new StringBuilder();for (int i = 0; i < arr.length; i++) {content.append(arr[i]);}//把字典排序好的数组读取成字符串。MessageDigest md = null;String tmpStr = null;try {/*进行sha1加密*/md = MessageDigest.getInstance("SHA-1");byte[] digest = md.digest(content.toString().getBytes());tmpStr = byteToStr(digest);//将加密后的byte转化为16进制字符串,这就是我们自己构造的signature} catch (NoSuchAlgorithmException e) {e.printStackTrace();}content = null;return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;//进行对比,相同返回true,不同返回false}

 private static String byteToStr(byte[] byteArray) {String strDigest = "";for (int i = 0; i < byteArray.length; i++) {strDigest += byteToHexStr(byteArray[i]);//分别把没一个byte位转换成一个16进制字符,代码见下面}return strDigest;}
 private static String byteToHexStr(byte mByte) {char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A','B', 'C', 'D', 'E', 'F' };char[] tempArr = new char[2];tempArr[0] = Digit[(mByte >>> 4) & 0X0F];tempArr[1] = Digit[mByte & 0X0F];String s = new String(tempArr);return s;}

AesUtils的具体代码

package org.calonlan.soulpower.util;import org.calonlan.soulpower.dao.impl.WeiInfoDaoImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class AesUtils {private static ApplicationContext applicationContext;/** 这里我直接使用的spring来读取weiInfo对象中的加解密密钥的内容,大家可以不用这样,直接把密钥放在这里就可以了,* 也可以放在properties文件中读取更方便*/public static String descMessage(String encrypt, String msgSignature,String timestamp, String nonce) throws AesException {applicationContext = new ClassPathXmlApplicationContext("config/application-context.xml");WeiInfoDaoImpl daoImpl = (WeiInfoDaoImpl) applicationContext.getBean("weiInfoDao");String token = daoImpl.get().getToken();//获得tokenString encodingAesKey = daoImpl.get().getEncodingAesKey();//获得加解密密钥String appId = daoImpl.get().getAppId();//获得appid,这个在开发者模式下就能看到,填写你自己的。String format = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%1$s]]></Encrypt></xml>";String fromXML = String.format(format, encrypt);WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId);String result = pc.decryptMsg(msgSignature, timestamp, nonce, fromXML);return result;}/*加密和解密类似,就不做注释了*/public static String aescMessage(String replyMsg, String timestamp,String nonce) throws AesException {applicationContext = new ClassPathXmlApplicationContext("config/application-context.xml");WeiInfoDaoImpl daoImpl = (WeiInfoDaoImpl) applicationContext.getBean("weiInfoDao");String token = daoImpl.get().getToken();String encodingAesKey = daoImpl.get().getEncodingAesKey();String appId = daoImpl.get().getAppId();WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId);String mingwen = pc.encryptMsg(replyMsg, timestamp, nonce);return mingwen;}
}

MessageUtil中的parseXml代码,有两个,一个是用来直接解析request中的xml,一个是用来解析字符串类型的xml

解析request中的xml代码

 public static Map<String, String> parseXml(HttpServletRequest request)throws Exception {Map<String, String> map = new HashMap<String, String>();InputStream inputStream = request.getInputStream();SAXReader reader = new SAXReader();//我用的是SAXReaderDocument document = reader.read(inputStream);Element root = document.getRootElement();@SuppressWarnings("unchecked")List<Element> elementList = root.elements();for (Element e : elementList) {map.put(e.getName(), e.getText());}inputStream.close();inputStream = null;return map;}

解析字符串中的xml代码

 public static Map<String, String> parseXml(StringReader readers) {Map<String, String> map = new HashMap<String, String>();SAXReader reader = new SAXReader();Document document = null;try {InputSource inputSource = new InputSource(readers);document = reader.read(inputSource);} catch (DocumentException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}Element root = document.getRootElement();@SuppressWarnings("unchecked")List<Element> elementList = root.elements();for (Element e : elementList) {map.put(e.getName(), e.getText());}return map;}

到这里,构建就完成了,可以用我们的服务器来和微信服务器进行密文的消息传递了。

用spring搭建微信公众号开发者模式下服务器处理用户消息的加密传输构架(java)相关推荐

  1. java调用微信加密_用spring搭建微信公众号开发者模式下服务器处理用户消息的加密传输构架(java)...

    要搭建加密传输的微信公众号消息传输,首先要在开发这平台下载一下微信加密的相关jar包,并做一些准备.准备的步骤如下: 1.打开开发者文档,找到消息加减密--->接入指引,如下图所示: 2.在页面 ...

  2. 微信公众号基本设置服务器设置教程,最新最全的微信公众号开发者模式配置

    微信公众号的开发分为编辑模式和开发者模式,那么最新最全的微信公众号开发者模式配置是什么呢,下面是学习啦小编收集整理的最新最全的微信公众号开发者模式配置,希望对大家有帮助~~ 最新最全的微信公众号开发者 ...

  3. 微信开发者模式php,php 开启微信公众号开发者模式

    php 开启微信公众号开发者模式 /** * wechat php test */ header('Content-type:text'); //define your token //定义TOKEN ...

  4. 微信开发者模式php,PHP实现模拟微信公众号开发者模式

    本文主要和大家分享PHP实现模拟微信公众号开发者模式,主要以代码的形式和大家分享,希望能帮助到大家.$url = 'http://xxxx.com/test/aaaa/index.php';//开发者 ...

  5. 微信公众号开发者模式菜单不更新的问题

    这个问题困扰了我好几天,度娘到的都是24小时内,然而到了24小时并没有什么卵用. 开发者模式下,后台的菜单信息更新后,微信服务器并没有来拉取菜单数据,所以我们自己动手让它来拉取菜单信息. 官方debu ...

  6. 微信公众号开发者模式回复信息带表情(QQ,emoji)

    最近做微信公众号的迭代 老板非要发送消息带表情 我调研了网上的各种方法 各种开源代码和项目经验 没一个能用的- o(╥﹏╥)o emoji 下面是整个流程 首先,我自己测试,先往公众号发表情,后台去接 ...

  7. 微信服务号开发者模式下 自定义创建菜单,跳转到其他url

    首先看服务号下面配置信息,表示开发者模式已经打开. 这个时候,进入服务号查看,菜单已经消失. 接下来就是我们今天的主要内容,通过官方提供的调试工具,创建菜单. 当然,你也可以手写请求过程,第一步获取A ...

  8. 什么是php微信开发,php微信公众号开发模式详解

    这篇文章主要介绍了php微信公众号开发者模式,通过后台服务器与微信关注用户实现更多的交互作用,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 学习步骤:分四章来讲述这部分内容,下面是每章的大致内容. ...

  9. 微信公众号开发者自动回复php,微信公众平台开发者模式的启用并自动回复

    这篇文章介绍的内容是关于微信公众平台开发者模式的启用并自动回复,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 首先,什么是开发者模式? 开发者模式,就是先验证你的服务器地址,验证完成之 ...

最新文章

  1. MySQL中authorization_IdentitiServser4 + Mysql实现Authorization Server
  2. 华为鸿蒙去哪里更新,华为鸿蒙OS正式尝鲜版名单更新,升级?还是不升级?
  3. Kubernetes 笔记 01 初识 Kubernetes 新时代的领航者
  4. Word VSTO Error:Interop type 'Microsoft.Office.Interop.OneNote.Application' cannot be embedded...
  5. java 实现雷达图,如何使用y轴为0到100的chart.js创建雷达图?
  6. 大数据如何预测上市公司的业绩?
  7. java归还线程_再谈java线程
  8. 2017年会是Serverless爆发之年吗?
  9. IIS相关问题及解决方案
  10. Java学习第1天:序言,基础及配置tomcat
  11. C++primer 第 5 章语句 5.2语句作用域 5.3条件语句 5 . 4 迭代语句 5.5跳转语句 5.6 try语句块和异常处理
  12. zabbix中常用到的几个key:
  13. css如何让不确定宽度的div水平居中
  14. Error in nextTick
  15. dell服务器linux密码,Dell服务器忘记idrac密码,如何在不重启服务器的情况下重置密码?...
  16. python显示界面后1秒自动隐藏_使用Python+Qt时解决QTreeWidget中的内容超出边界后自动隐藏的问题...
  17. 将一个输入流(InputStream)写入到一个文件中
  18. 我喜欢现在的工作环境不错工资待遇一般
  19. C++ 函数模板与分离编译模式
  20. Educational Codeforces Round 39 A Partition

热门文章

  1. 学计算机的一开学叫要带电脑吗,大一新生开学需要带电脑吗?辅导员给出建议,学生需提前了解...
  2. 万年历c语言大作业实验,用C语言写的一个万年历
  3. jsp java循环读取json_JAVA JSON遍历问题,求解(内附代码)
  4. 通过stream去重_Java 8 Stream.distinct() 列表去重的操作
  5. 让8只数码管初始显示零,每隔大约1s加一显示,到数码管显示9后,再从一开始显示
  6. 西昌学院计算机,西昌学院
  7. C++ 重载new和delete运算符
  8. linux mysql 8安装教程,MySQL8系列安装与配置教程(Linux环境)
  9. ip地址自动切换器_网络IP切换器IPProviders下载_IPProviders官方版下载1.1.22
  10. java userdao,Java Web 开发基础------DAO