Java微信二次开发(五)

消息加密

需要到入库:commons-io-2.4.jar,commons-codec-1.9.jar(在官网的Java微信加密demo下)

第一步:访问https://mp.weixin.qq.com/wiki,下载AES加密的示例代码

Java微信二次开发(五)

第二步:新建com.wtz.aes包,把实例代码中的8个AES加密类复制进去,将这些类的包名改为com.wtz.aes,导入库commons-codec-1.9.jar,选上面的Project下的Properties,点击Java Build Path,Libraries,Add Library,选Junit 4,Next,Finish,OK,AES加密导入完成

第三步:找到包com.wtz.util,新建类Parameter.java类,存放参数token,encodingAESKey(随机戳),corpId(AppID),这些在基本配置处可以得到

 package com.wtz.util;

 /**
* @author wangtianze QQ:864620012
* @date 2017年4月21日 下午9:27:50
* <p>version:1.0</p>
* <p>description:参数api</p>
*/
public class Parameter {
//token
public static String token = "wangtianze";
//随机戳
public static String encodingAESKey = "X78dYU3MXpijKArRbiozTRq0jZZnjxxvuB4n8KJwRH1";
//应用AppID
public static String corpId = "wx9621c31e147dfdf9";
}

第四步:找到包com.wtz.util下的MessageUtil.java类,修改parseXml方法

 package com.wtz.util;

 import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
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 com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import com.wtz.message.response.ImageMessage;
import com.wtz.message.response.MusicMessage;
import com.wtz.message.response.NewsMessage;
import com.wtz.message.response.TextMessage;
import com.wtz.message.response.VideoMessage;
import com.wtz.message.response.VoiceMessage; /**
* @author wangtianze QQ:864620012
* @date 2017年4月19日 下午3:29:58
* <p>version:1.0</p>
* <p>description:消息处理工具类</p>
*/
public class MessageUtil {
//请求消息类型:文本
public static final String REQ_MESSAGE_TYPE_TEXT = "text";
//请求消息类型:图片
public static final String REQ_MESSAGE_TYPE_IMAGE = "image";
//请求消息类型:语音
public static final String REQ_MESSAGE_TYPE_VOICE = "voice";
//请求消息类型:视频
public static final String REQ_MESSAGE_TYPE_VIDEO = "video";
//请求消息类型:地理位置
public static final String REQ_MESSAGE_TYPE_LOCATION = "location";
//请求消息类型:链接
public static final String REQ_MESSAGE_TYPE_LINK = "link";
//请求消息类型:事件推送
public static final String REQ_MESSAGE_TYPE_EVENT = "event"; //--------------------------------------------------------------- //事件类型:subscribe(订阅)
public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
//事件类型:unsubscribe(取消订阅)
public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
//事件类型:scan(用户已关注时的扫描带参数的二维码)
public static final String EVENT_TYPE_SCAN = "scan";
//事件类型:LOCATION(上报地理位置)
public static final String EVENT_TYPE_LOCATION = "LOCATION";
//事件类型:CLICK(自定义菜单)
public static final String EVENT_TYPE_CLICK = "CLICK"; //--------------------------------------------------------------- //响应消息类型:文本
public static final String RESP_MESSAGE_TYPE_TEXT = "text";
//响应详细类型:图片
public static final String RESP_MESSAGE_TYPE_IMAGE = "image";
//响应消息类型:语音
public static final String RESP_MESSAGE_TYPE_VOICE = "voice";
//响应消息类型:视频
public static final String RESP_MESSAGE_TYPE_VIDEO = "video";
//响应详细类型:音乐
public static final String RESP_MESSAGE_TYPE_MUSIC = "music";
//响应消息类型:图文
public static final String RESP_MESSAGE_TYPE_NEWS = "news"; //--------------------------------------------------------------- //-----------------------------------------老的,加密前---------------------------------------------
// //从流中解析出每个节点的内容
// public static Map<String,String> parseXml(HttpServletRequest request) throws IOException{
// Map<String,String> map = new HashMap<String,String>();
//
// //从输入流中获取流对象
// InputStream in = request.getInputStream();
//
// //构建SAX阅读器对象
// SAXReader reader = new SAXReader();
// try {
// //从流中获得文档对象
// Document doc = reader.read(in);
//
// //获得根节点
// Element root = doc.getRootElement();
//
// //获取根节点下的所有子节点
// List<Element> children = root.elements();
//
// for(Element e:children){
// //遍历每一个节点,并按照节点名--节点值放入map中
// map.put(e.getName(), e.getText());
// System.out.println("用户发送的消息XML解析为:" + e.getName() + e.getText());
// }
//
// //关闭流
// in.close();
// in = null;
// } catch (DocumentException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//
// return map;
// }
//-----------------------------------------新的,加密后--------------------------------------------
//从流中解析出每个节点的内容
public static Map<String,String> parseXml(String request) throws IOException{
Map<String,String> map = new HashMap<String,String>(); //从request中获取流对象
InputStream in = new ByteArrayInputStream(request.getBytes("UTF-8")); //构建SAX阅读器对象
SAXReader reader = new SAXReader();
try {
//从流中获得文档对象
Document doc = reader.read(in); //获得根节点
Element root = doc.getRootElement(); //获取根节点下的所有子节点
List<Element> children = root.elements(); for(Element e:children){
//遍历每一个节点,并按照节点名--节点值放入map中
map.put(e.getName(), e.getText());
System.out.println("用户发送的消息XML解析为:" + e.getName() + e.getText());
} //关闭流
in.close();
in = null;
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} return map;
}
//---------------------------------------------------------------------------------------------- /**
* 用于扩展节点数据按照<ToUserName><![CDATA[toUser]]></ToUserName>,中间加了CDATA段
*/
private static XStream xstream = new XStream(new XppDriver(){
public HierarchicalStreamWriter createWriter(Writer out){
return new PrettyPrintWriter(out){
boolean cdata = true;
public void startNode(String name,Class clazz){
super.startNode(name,clazz);
} protected void writeText(QuickWriter writer,String text){
if(cdata){
writer.write("<![CDATA[");
writer.write(text);
writer.write("]]>");
}else{
writer.write(text);
}
}
};
}
}); /**
* 将文本消息对象转换成XML格式
* params:textMessage 文本消息对象
* return:xml
*/
public static String messageToXml(TextMessage textMessage){
xstream.alias("xml",textMessage.getClass());
return xstream.toXML(textMessage);
} /**
* 将图片消息对象转换成XML格式
* params:imageMessage
* return:xml
*/
public static String messageToXml(ImageMessage imageMessage){
xstream.alias("xml", imageMessage.getClass());
return xstream.toXML(imageMessage);
} /**
* 将语音消息对象转换成XML格式
* params:voiceMessage
* return:xml
*/
public static String messageToXml(VoiceMessage voiceMessage){
xstream.alias("xml",voiceMessage.getClass());
return xstream.toXML(voiceMessage);
} /**
* 将视频消息对象转换成XML格式
* params:videoMessage
* return:xml
*/
public static String messageToXml(VideoMessage videoMessage){
xstream.alias("xml",videoMessage.getClass());
return xstream.toXML(videoMessage);
} /**
* 将音乐消息对象转换成XML格式
* params:musicMessage
* return:xml
*/
public static String messageToXml(MusicMessage musicMessage){
xstream.alias("xml",musicMessage.getClass());
return xstream.toXML(musicMessage);
} /**
* 将图文消息对象转换成XML格式
* params:newsMessage
* return:xml
*/
public static String messageToXml(NewsMessage newsMessage){
xstream.alias("xml",newsMessage.getClass());
return xstream.toXML(newsMessage);
}
}

第五步:找到包com.wtz.util下的ProcessService.java类,修改dealRequest方法

 package com.wtz.util;

 import java.io.IOException;
import java.util.Date;
import java.util.Map; import javax.servlet.http.HttpServletRequest; import com.wtz.dao.PostCodeDao;
import com.wtz.message.response.TextMessage; /**
* @author wangtianze QQ:864620012
* @date 2017年4月19日 下午8:04:14
* <p>version:1.0</p>
* <p>description:核心服务类</p>
*/
public class ProcessService {
//定义数据访问的dao
private static PostCodeDao dao = new PostCodeDao(); //-----------------------------------老的,加密前--------------------------------------------------
// public static String dealRequest(HttpServletRequest request){
// //XML格式的消息数据
// String respXml = "";
// //默认返回的文本消息内容
// String respContent = "未知的消息类型";
// //调用parseXml方法解析请求消息
// Map<String, String> requestMap;
// try {
// requestMap = MessageUtil.parseXml(request);
// //发送方账号
// String fromUserName = requestMap.get("FromUserName");
// //开发者微信号
// String toUserName = requestMap.get("ToUserName");
// //消息类型
// String MsgType = requestMap.get("MsgType");
// //消息内容
// String content = requestMap.get("Content");
//
// //回复文本消息
// TextMessage textMessage = new TextMessage();
// textMessage.setToUserName(fromUserName);
// textMessage.setFromUserName(toUserName);
// textMessage.setCreateTime(new Date().getTime());
// textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);
//
// if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)){
// respContent = "感谢您关注【王天泽的服务号】\n" + "微信号:wangtianze1\n" + "请回复序号:\n" + "1.查邮政编码\n" + "2.查电话区号\n" + "?.返回帮助菜单\n";
// if(content.equals("1")){
// respContent = "请按照格式输入地区名,例如输入 邮编:东城";
// }
// if(content.equals("2")){
// respContent = "请按照格式输入地区名,例如输入 区号:东城";
// }
// if(content.equals("?")){
// respContent = "感谢您关注【王天泽的服务号】\n" + "微信号:wangtianze1\n" + "请回复序号:\n" + "1.查邮政编码\n" + "2.查电话区号\n" + "?.返回帮助菜单\n";
// }
// if(content.startsWith("邮编:")){
// int pos = content.indexOf(":");
// String cityName = content.substring(pos + 1);
// respContent = dao.findPostCodeByCityName(cityName);
// System.out.println("邮编:respContent:" + respContent);
// }
// if(content.startsWith("区号:")){
// int pos = content.indexOf(":");
// String cityName = content.substring(pos + 1);
// respContent = dao.findTelCodeByCityName(cityName);
// System.out.println("区号:respContent:" + respContent);
// }
// }else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)){
// respContent = "您发送的是图片消息";
// }else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)){
// respContent = "您发送的是语音消息";
// }else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VIDEO)){
// respContent = "您发送的是视频消息";
// }else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)){
// respContent = "您发送的是地理位置消息";
// }else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)){
// respContent = "您发送的是链接消息";
// }else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)){
// //事件类型
// String eventType = requestMap.get("Event");
// if(eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)){
// respContent = "感谢您关注【王天泽的服务号】\n" + "微信号:wangtianze1\n" + "请回复序号:\n" + "1.查邮政编码\n" + "2.查电话区号\n" + "?.返回帮助菜单\n";
// }else if(eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)){
// //TODO 取消订阅后用户不会再收到公众号发送的消息,因此不需要回复
// }else if(eventType.equals(MessageUtil.EVENT_TYPE_SCAN)){
// //TODO 处理扫描带参数二维码事件
// }else if(eventType.equals(MessageUtil.EVENT_TYPE_LOCATION)){
// //TODO 处理上报地理位置事件
// }else if(eventType.equals(MessageUtil.EVENT_TYPE_CLICK)){
// //TODO 处理菜单点击事件
// }
// }
// //设置文本消息的内容
// textMessage.setContent(respContent);
// //将文本消息对象转换成xml
// respXml = MessageUtil.messageToXml(textMessage);
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//
// return respXml;
// } //----------------------------------------------新的,加密后---------------------------------------------
public static String dealRequest(String request){
//XML格式的消息数据
String respXml = "";
//默认返回的文本消息内容
String respContent = "未知的消息类型";
//调用parseXml方法解析请求消息
Map<String, String> requestMap;
try {
requestMap = MessageUtil.parseXml(request);
//发送方账号
String fromUserName = requestMap.get("FromUserName");
//开发者微信号
String toUserName = requestMap.get("ToUserName");
//消息类型
String MsgType = requestMap.get("MsgType");
//消息内容
String content = requestMap.get("Content"); //回复文本消息
TextMessage textMessage = new TextMessage();
textMessage.setToUserName(fromUserName);
textMessage.setFromUserName(toUserName);
textMessage.setCreateTime(new Date().getTime());
textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT); if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)){
respContent = "感谢您关注【王天泽的服务号】\n" + "微信号:wangtianze1\n" + "请回复序号:\n" + "1.查邮政编码\n" + "2.查电话区号\n" + "?.返回帮助菜单\n";
if(content.equals("1")){
respContent = "请按照格式输入地区名,例如输入 邮编:东城";
}
if(content.equals("2")){
respContent = "请按照格式输入地区名,例如输入 区号:东城";
}
if(content.equals("?")){
respContent = "感谢您关注【王天泽的服务号】\n" + "微信号:wangtianze1\n" + "请回复序号:\n" + "1.查邮政编码\n" + "2.查电话区号\n" + "?.返回帮助菜单\n";
}
if(content.startsWith("邮编:")){
int pos = content.indexOf(":");
String cityName = content.substring(pos + 1);
respContent = dao.findPostCodeByCityName(cityName);
System.out.println("邮编:respContent:" + respContent);
}
if(content.startsWith("区号:")){
int pos = content.indexOf(":");
String cityName = content.substring(pos + 1);
respContent = dao.findTelCodeByCityName(cityName);
System.out.println("区号:respContent:" + respContent);
}
}else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)){
respContent = "您发送的是图片消息";
}else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)){
respContent = "您发送的是语音消息";
}else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VIDEO)){
respContent = "您发送的是视频消息";
}else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)){
respContent = "您发送的是地理位置消息";
}else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)){
respContent = "您发送的是链接消息";
}else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)){
//事件类型
String eventType = requestMap.get("Event");
if(eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)){
respContent = "感谢您关注【王天泽的服务号】\n" + "微信号:wangtianze1\n" + "请回复序号:\n" + "1.查邮政编码\n" + "2.查电话区号\n" + "?.返回帮助菜单\n";
}else if(eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)){
//TODO 取消订阅后用户不会再收到公众号发送的消息,因此不需要回复
}else if(eventType.equals(MessageUtil.EVENT_TYPE_SCAN)){
//TODO 处理扫描带参数二维码事件
}else if(eventType.equals(MessageUtil.EVENT_TYPE_LOCATION)){
//TODO 处理上报地理位置事件
}else if(eventType.equals(MessageUtil.EVENT_TYPE_CLICK)){
//TODO 处理菜单点击事件
}
}
//设置文本消息的内容
textMessage.setContent(respContent);
//将文本消息对象转换成xml
respXml = MessageUtil.messageToXml(textMessage);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} return respXml;
}
}

第六步:找到包com.wtz.service,修改LoginServlet.java类,修改doPost方法

 package com.wtz.service;

 import java.io.IOException;
import java.io.InputStream;
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.apache.commons.io.IOUtils; import com.wtz.aes.AesException;
import com.wtz.aes.WXBizMsgCrypt;
import com.wtz.util.MessageUtil;
import com.wtz.util.Parameter;
import com.wtz.util.ProcessService;
import com.wtz.util.ValidationUtil; /**
* @author wangtianze QQ:864620012
* @date 2017年4月17日 下午8:11:32
* <p>version:1.0</p>
* <p>description:微信请求验证类</p>
*/
public class LoginServlet extends HttpServlet { @Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("get请求。。。。。。"); //1.获得微信签名的加密字符串
String signature = request.getParameter("signature"); //2.获得时间戳信息
String timestamp = request.getParameter("timestamp"); //3.获得随机数
String nonce = request.getParameter("nonce"); //4.获得随机字符串
String echostr = request.getParameter("echostr"); System.out.println("获得微信签名的加密字符串:"+signature);
System.out.println("获得时间戳信息:"+timestamp);
System.out.println("获得随机数:"+nonce);
System.out.println("获得随机字符串:"+echostr); PrintWriter out = response.getWriter(); //验证请求确认成功原样返回echostr参数内容,则接入生效,成为开发者成功,否则失败
if(ValidationUtil.checkSignature(signature, timestamp, nonce)){
out.print(echostr);
} out.close();
out = null;
} /**
* 接受微信服务器发过来的XML数据包(通过post请求发送过来的)
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//将请求响应的编码均设置为UTF-8,防止中文乱码
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8"); //------------------------老的,不加密----------------------------
// //获取微信加密的签名字符串
// String signature = request.getParameter("signature");
//
// //获取时间戳
// String timestamp = request.getParameter("timestamp");
//
// //获取随机数
// String nonce = request.getParameter("nonce");
//
// PrintWriter out = response.getWriter();
//
// if(ValidationUtil.checkSignature(signature,timestamp,nonce)){
// String respXml = "";
// try {
// respXml = ProcessService.dealRequest(request);
// } catch (Exception e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// out.print(respXml);
// }
// out.close();
// out = null;
//---------------------------新的,加密---------------------------
//获取微信加密的签名字符串
String signature = request.getParameter("msg_signature"); //获取时间戳
String timestamp = request.getParameter("timestamp"); //获取随机数
String nonce = request.getParameter("nonce"); //从请求中读取整个post数据
InputStream inputStream = request.getInputStream(); //commons.io.jar方法,直接将流转成字符串
String Post = IOUtils.toString(inputStream,"UTF-8"); System.out.println("Post:" + Post); String Msg = "";
WXBizMsgCrypt wxcpt = null;
try {
wxcpt = new WXBizMsgCrypt(Parameter.token,Parameter.encodingAESKey,Parameter.corpId);
//解密消息
Msg = wxcpt.decryptMsg(signature,timestamp,nonce,Post);
} catch (AesException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Msg打印结果
System.out.println("Msg打印结果:" + Msg); //调用核心业务类接收消息,处理消息
String respMessage = ProcessService.dealRequest(Msg); //respMessage打印结果
System.out.println("respMessage打印结果:" + respMessage); String encryptMsg = "";
try {
//加密回复消息
encryptMsg = wxcpt.encryptMsg(respMessage, timestamp, nonce);
System.out.println("encryptMsg:" + encryptMsg);
} catch (AesException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //响应消息
PrintWriter out = response.getWriter();
out.print(encryptMsg);
out.close();
}
}

消息加密完成。

上一篇:Qt for Android 打包 SQLite 数据库


下一篇:centos7的FTP服务vsftpd里建立虚拟用户不同目录分配不同权限