首先需要多些网上的大神
链接:https://bbs.csdn.net/topics/390991193 ;
https://blog.csdn.net/sinat_22878395/article/details/69258165 ;
https://blog.csdn.net/hanghangde/article/details/51028755 ;
https://bbs.csdn.net/topics/391878796
本文只是将这几个大神的攻略进行排列组合。
Controller类
/**
*@author TEDYYAN
* @throws DocumentException
* @throws IOException
* @throws AesException
*@注释:公众号用户互动
*/
@RequestMapping(value="/extensionInsurance/weiXinInteraction",produces = {"text/plain;charset=UTF-8"})
@ResponseBody
public String weiXinInteraction(HttpServletRequest request) throws IOException, DocumentException, AesException{
String msgSignature = request.getParameter("signature");
String msgTimestamp = request.getParameter("timestamp");
String msgNonce = request.getParameter("nonce");
String echostr = request.getParameter("echostr");
if (WXPublicUtils.verifyUrl(msgSignature, msgTimestamp, msgNonce,sysConfigService.getValue("sacon.app.token"))) {
LOG.info("---------------------------------------------公众号成功连接!");
LOG.info("msgNonce"+msgNonce+" msgTimestamp"+msgTimestamp+" msgNonce"+msgNonce+" echostr"+echostr);
return echostr;
}
LOG.info("msgNonce"+msgNonce+" msgTimestamp"+msgTimestamp+" msgNonce"+msgNonce+" echostr"+echostr+"公众号成功失败!");
return null;
}
WXPublicUtils 类
package com.dido.common.util;
import com.dido.common.payment.weixin.WeiXinConfig;
public class WXPublicUtils {
/**
* 验证Token
* @param msgSignature 签名串,对应URL参数的signature
* @param timeStamp 时间戳,对应URL参数的timestamp
* @param nonce 随机串,对应URL参数的nonce
*
* @return 是否为安全签名
* @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
*/
public static boolean verifyUrl(String msgSignature, String timeStamp, String nonce,String token)
throws AesException {
// 这里的 WXPublicConstants.TOKEN 填写你自己设置的Token就可以了
String signature = SHA1.getSHA1(token, timeStamp, nonce);
if (!signature.equals(msgSignature)) {
throw new AesException(AesException.ValidateSignatureError);
}
return true;
}
}
AesException 类
package com.dido.common.util;
@SuppressWarnings("serial")
public class AesException extends Exception {
public final static int OK = 0;
public final static int ValidateSignatureError = -40001;
public final static int ParseXmlError = -40002;
public final static int ComputeSignatureError = -40003;
public final static int IllegalAesKey = -40004;
public final static int ValidateAppidError = -40005;
public final static int EncryptAESError = -40006;
public final static int DecryptAESError = -40007;
public final static int IllegalBuffer = -40008;
//public final static int EncodeBase64Error = -40009;
//public final static int DecodeBase64Error = -40010;
//public final static int GenReturnXmlError = -40011;
private int code;
private static String getMessage(int code) {
switch (code) {
case ValidateSignatureError:
return "签名验证错误";
case ParseXmlError:
return "xml解析失败";
case ComputeSignatureError:
return "sha加密生成签名失败";
case IllegalAesKey:
return "SymmetricKey非法";
case ValidateAppidError:
return "appid校验失败";
case EncryptAESError:
return "aes加密失败";
case DecryptAESError:
return "aes解密失败";
case IllegalBuffer:
return "解密后得到的buffer非法";
// case EncodeBase64Error:
// return "base64加密错误";
// case DecodeBase64Error:
// return "base64解密错误";
// case GenReturnXmlError:
// return "xml生成失败";
default:
return null; // cannot be
}
}
public int getCode() {
return code;
}
AesException(int code) {
super(getMessage(code));
this.code = code;
}
}
SHA1 类
/**
* 对公众平台发送给公众账号的消息加解密示例代码.
*
* @copyright Copyright (c) 1998-2014 Tencent Inc.
*/
// ------------------------------------------------------------------------
package com.dido.common.util;
import java.security.MessageDigest;
import java.util.Arrays;
/**
* SHA1 class
*
* 计算公众平台的消息签名接口.
*/
class SHA1 {
/**
* 用SHA1算法生成安全签名
*
* @param token
* 票据
* @param timestamp
* 时间戳
* @param nonce
* 随机字符串
* @param encrypt
* 密文
* @return 安全签名
* @throws AesException
*/
public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws AesException {
try {
String[] array = new String[] { token, timestamp, nonce, encrypt };
StringBuffer sb = new StringBuffer();
// 字符串排序
Arrays.sort(array);
for (int i = 0; i < 4; i++) {
sb.append(array[i]);
}
String str = sb.toString();
// SHA1签名生成
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(str.getBytes());
byte[] digest = md.digest();
StringBuffer hexstr = new StringBuffer();
String shaHex = "";
for (int i = 0; i < digest.length; i++) {
shaHex = Integer.toHexString(digest[i] & 0xFF);
if (shaHex.length() < 2) {
hexstr.append(0);
}
hexstr.append(shaHex);
}
return hexstr.toString();
} catch (Exception e) {
e.printStackTrace();
throw new AesException(AesException.ComputeSignatureError);
}
}
/**
* 用SHA1算法验证Token
*
* @param token
* 票据
* @param timestamp
* 时间戳
* @param nonce
* 随机字符串
* @return 安全签名
* @throws AesException
*/
public static String getSHA1(String token, String timestamp, String nonce) throws AesException {
try {
String[] array = new String[] { token, timestamp, nonce };
StringBuffer sb = new StringBuffer();
// 字符串排序
Arrays.sort(array);
for (int i = 0; i < 3; i++) {
sb.append(array[i]);
}
String str = sb.toString();
// SHA1签名生成
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(str.getBytes());
byte[] digest = md.digest();
StringBuffer hexstr = new StringBuffer();
String shaHex = "";
for (int i = 0; i < digest.length; i++) {
shaHex = Integer.toHexString(digest[i] & 0xFF);
if (shaHex.length() < 2) {
hexstr.append(0);
}
hexstr.append(shaHex);
}
return hexstr.toString();
} catch (Exception e) {
e.printStackTrace();
throw new AesException(AesException.ComputeSignatureError);
}
}
}
接收xml变为map
/**
* 根据request将XML流解析成MAP
*
* @param request
* @return
* @throws IOException
* @throws DocumentException
*/
public static Map xmlToMap(HttpServletRequest request) throws IOException, DocumentException {
// 将解析结果存储在HashMap中
Map map = new HashMap();
// 从request中取得输入流
InputStream inputStream = request.getInputStream();
// 一定要utf-8
InputStreamReader inputReader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader buffer = new BufferedReader(inputReader);
String message = "";
String s = "";
while ((s = buffer.readLine()) != null) {
message += s;
}
System.out.println(message);
LOG.info("WechatSendMessage---------------------------------------------" + message);
System.out.println("获取输入流");
// // 读取输入流
SAXReader reader = new SAXReader();
// Document document = reader.read(inputStream);
// 将字符串转化为XML文档对象
Document document = DocumentHelper.parseText(message);
Element root = document.getRootElement();
List elements = root.elements();
// 遍历根节点下所有子节点
Iterator> iter = root.elementIterator();
// // 遍历所有子节点
// for (Element e : elementList) {
// System.out.println(e.getName() + "|" + e.getText());
// map.put(e.getName(), e.getText());
// }
while (iter.hasNext()) {
Element ele = (Element) iter.next();
map.put(ele.getName(), ele.getText());
}
// 释放资源
inputStream.close();
return map;
}
处理事件代码
LOG.info("---------------------------------------------进入扫码事件!");
com.alibaba.fastjson.JSONObject jsonObject = HttpClientUtils.httpGet("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + sysConfigService.getValue("sacon.app.id") + "&secret=" + sysConfigService.getValue("sacon.app.secret"));
String access_token = jsonObject.getString("access_token");
Map receivedMap = xmlToMap(request);
String msgType = receivedMap.get("MsgType").replaceAll("\\s*", "");
// 普通消息
if ("text".equals(msgType)) { // 文本消息
// todo 处理文本消息
} else if ("image".equals(msgType)) { // 图片消息
// todo 处理图片消息
} else if ("voice".equals(msgType)) { // 语音消息
// todo 处理语音消息
} else if ("video".equals(msgType)) { // 视频消息
// todo 处理视频消息
} else if ("shortvideo".equals(msgType)) { // 小视频消息
// todo 处理小视频消息
} else if ("location".equals(msgType)) { // 地理位置消息
// todo 处理地理位置消息
} else if ("link".equals(msgType)) { // 链接消息
// todo 处理链接消息
} else if ("event".equals(msgType)) { // 事件消息
String event = receivedMap.get("Event").replaceAll("\\s*", "");
if ("subscribe".equals(event)) { // 订阅事件 或 未关注扫描二维码事件
// 获取消息模板ID
String template_id = sysConfigService.getValue("weixin.sendMessage.model.first");
// 获取用户数据中的openid、unionid、nickname和headimgurl放入wx_user数据库
String openid = receivedMap.get("FromUserName").replaceAll("\\s*", "");
String userInfoURL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + access_token + "&openid=" + openid;
com.alibaba.fastjson.JSONObject userInfo = HttpClientUtils.httpGet(userInfoURL);
String unionid = userInfo.getString("unionid");
String nickname = userInfo.getString("nickname");
String headimgurl = userInfo.getString("headimgurl");
WXUser wxUser = wxUserService.findUserByOpenid(openid);
if (wxUser == null) {
wxUser = new WXUser();
wxUser.setNickname(nickname);
wxUser.setOpenid(openid);
wxUser.setHeadimgurl(headimgurl);
wxUser.setUnionid(unionid);
wxUser.setAppid(sysConfigService.getValue("sacon.app.id"));
wxUserService.saveOrUpdate(wxUser);
}
// 获取二维码中的参数进行解密
String receivedMessage = receivedMap.get("EventKey").replaceAll("\\s*", "");
String orderNumber = "";
if (receivedMessage != null) {
String[] reciveMessages = receivedMessage.split("_");
if (reciveMessages.length > 0) {
String temp = AESUtils.decrypt(reciveMessages[1]);
orderNumber = temp;
}
}
// 获取订单详情
AcppOrder acppOrder = acppOrderService.findAcppOrderId(orderNumber);
// 绑定订单,参数创建时间、unionid和价格
if (acppOrder != null) {
acppOrder.setObeyWxOpenId(unionid);
acppOrder.setOrderCreationTime(new Date());
acppOrderService.saveOrUpdate(acppOrder);
AcppProduct product = acppProductService.selectByPrimaryKey(acppOrder.getProductId());
if (product != null) {
if (sysConfigService.isOpen("weixin.sendMessage.model.flag")) {
// 初始化返回消息模板
WeChatSendTemplateMessageModel weChatSendTemplateMessageModel = new WeChatSendTemplateMessageModel();
weChatSendTemplateMessageModel.setTouser(openid);
weChatSendTemplateMessageModel.setTemplate_id(template_id);
weChatSendTemplateMessageModel.setUrl(product.getWeimengUrl());
// 模板赋值
Map dataMap = initCreateModel(acppOrder, product);
weChatSendTemplateMessageModel.setData(dataMap);
// 转换模板格式
String json = com.alibaba.fastjson.JSONObject.toJSONString(weChatSendTemplateMessageModel);
com.alibaba.fastjson.JSONObject resultObject = com.alibaba.fastjson.JSONObject.parseObject(json);
// 发送模板信息
String sendURL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + access_token;
com.alibaba.fastjson.JSONObject sendObject = HttpClientUtils.httpPost(sendURL, resultObject);
String errmsg = sendObject.getString("errmsg");
if (!errmsg.equals("ok")) {
LOG.error("errmsg" + errmsg + " errcode" + sendObject.getString("errcode") + " msgid" + sendObject.getString("msgid"));
}
}
} else {
LOG.error("Query product failure");
}
} else {
LOG.error("Extension does not exist");
}
LOG.info("---------------------------------------------微信公众号扫码收到的订单号" + orderNumber);
//
return "success";
} else if ("unsubscribe".equals(event)) { // 取消订阅事件
// todo 处理取消订阅事件
} else if ("SCAN".equals(event)) { // 已关注扫描二维码事件
String openid = receivedMap.get("FromUserName").replaceAll("\\s*", "");
// 检测是否已经记录到wxUser数据库
WXUser wxUser = wxUserService.findUserByOpenid(openid);
if (wxUser == null) {
String userInfoURL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + access_token + "&openid=" + openid;
com.alibaba.fastjson.JSONObject userInfo = HttpClientUtils.httpGet(userInfoURL);
String unionid = userInfo.getString("unionid");
String nickname = userInfo.getString("nickname");
String headimgurl = userInfo.getString("headimgurl");
wxUser = new WXUser();
wxUser.setNickname(nickname);
wxUser.setOpenid(openid);
wxUser.setHeadimgurl(headimgurl);
wxUser.setUnionid(unionid);
wxUser.setAppid(sysConfigService.getValue("sacon.app.id"));
wxUserService.saveOrUpdate(wxUser);
}
// 获取消息模板ID
String template_id = sysConfigService.getValue("weixin.sendMessage.model.first");
//
// 获取二维码中的参数进行解密
String orderNumber = "";
String receivedMessage = receivedMap.get("EventKey").replaceAll("\\s*", "");
if (receivedMessage != null) {
orderNumber = AESUtils.decrypt(receivedMessage);
}
LOG.info("---------------------------------------------微信公众号扫码收到的订单号" + orderNumber);
//
// 获取订单详情
AcppOrder acppOrder = acppOrderService.findAcppOrderId(orderNumber);
if (acppOrder != null) {
// 绑定订单,参数创建时间、unionid和价格
if (wxUser != null) {
acppOrder.setObeyWxOpenId(wxUser.getUnionid());
acppOrder.setOrderCreationTime(new Date());
acppOrderService.saveOrUpdate(acppOrder);
} else {
WXUser wxUser1 = wxUserService.findUserByOpenid(openid);
acppOrder.setObeyWxOpenId(wxUser1.getUnionid());
acppOrder.setOrderCreationTime(new Date());
acppOrderService.saveOrUpdate(acppOrder);
}
AcppProduct product = acppProductService.selectByPrimaryKey(acppOrder.getProductId());
if (product != null) {
if (sysConfigService.isOpen("weixin.sendMessage.model.flag")) {
// 初始化返回消息模板
WeChatSendTemplateMessageModel weChatSendTemplateMessageModel = new WeChatSendTemplateMessageModel();
weChatSendTemplateMessageModel.setTouser(openid);
weChatSendTemplateMessageModel.setTemplate_id(template_id);
weChatSendTemplateMessageModel.setUrl(product.getWeimengUrl());
// 模板赋值
Map dataMap = initCreateModel(acppOrder, product);
weChatSendTemplateMessageModel.setData(dataMap);
// 转换模板格式
String json = com.alibaba.fastjson.JSONObject.toJSONString(weChatSendTemplateMessageModel);
com.alibaba.fastjson.JSONObject resultObject = com.alibaba.fastjson.JSONObject.parseObject(json);
// 发送模板信息
String sendURL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + access_token;
com.alibaba.fastjson.JSONObject sendObject = HttpClientUtils.httpPost(sendURL, resultObject);
String errmsg = sendObject.getString("errmsg");
if (!errmsg.equals("ok")) {
LOG.error("errmsg" + errmsg + " errcode" + sendObject.getString("errcode") + " msgid" + sendObject.getString("msgid"));
}
}
} else {
LOG.error("Query product failure");
}
} else {
LOG.error("Extension does not exist");
}
return "success";
} else if ("LOCATION".equals(event)) { // 上报地理位置事件
// todo 处理上报地理位置事件
} else if ("CLICK".equals(event)) { // 点击菜单拉取消息时的事件推送事件
// todo 处理点击菜单拉取消息时的事件推送事件
} else if ("VIEW".equals(event)) { // 点击菜单跳转链接时的事件推送
// todo 处理点击菜单跳转链接时的事件推送
} else if ("TEMPLATESENDJOBFINISH".equals(event)) {
String status = receivedMap.get("Status").replaceAll("\\s*", "");
String fromUserName = receivedMap.get("FromUserName").replaceAll("\\s*", "");
String createTime = receivedMap.get("CreateTime").replaceAll("\\s*", "");
String msgID = receivedMap.get("MsgID").replaceAll("\\s*", "");
if (status.equals("success")) {
LOG.info("用户Openid为" + fromUserName + "消息ID" + msgID + "创建时间为" + createTime + "成功!");
} else if (status.equals("failed:user block")) {
LOG.warn("用户Openid为" + fromUserName + "消息ID" + msgID + "创建时间为" + createTime + "用户拒收!");
} else if (status.equals("failed: system failed")) {
LOG.error("用户Openid为" + fromUserName + "消息ID" + msgID + "创建时间为" + createTime + "发送失败!");
}
}
}
return "success";