大家好,我是小悟
在做微信小程序或公众号开发的有时候,难免会遇到需要在用户关注或取关公众号后处理业务逻辑的需求,只需要几步就可以搞定。
1、配置
首先我们需要在微信公众号后台进行服务器配置,登录公众号后台->开发->基本配置->服务器配置,如下:
服务器地址就是我们写的一个controller(代码在下面),用来给微信校验,和接收微信发过来的消息,如果地址错误或者token错误,提交信息的时候会报错
2、代码实现
SignUtil
/**
* @description
*/
public class SignUtil {
/**
* 验证签名
* @param token
* @param signature 签名用来核实最后的结果是否一致
* @param timestamp 时间标记
* @param nonce 随机数字标记
* @return 一个布尔值确定最后加密得到的是否与signature一致
*/
public static boolean checkSignature(String token, String signature, String timestamp, String nonce) {
//将传入参数变成一个String数组然后进行字典排序
String[] arr = new String[] { token, timestamp, nonce };
// 将token、timestamp、nonce三个参数进行字典排序
Arrays.sort(arr);
//创建一个对象储存排序后三个String的结合体
StringBuilder content = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
content.append(arr[i]);
}
MessageDigest md = null;
String tmpStr = null;
try {
md = MessageDigest.getInstance("SHA-1");
byte[] digest = md.digest(content.toString().getBytes());
tmpStr = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
content = null;
// 将sha1加密后的字符串可与signature对比
return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
}
/**
* 将字节数组转换为十六进制字符串
* @param byteArray
* @return
*/
private static String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}
return strDigest;
}
/**
* 将每一个字节转换为十六进制字符串
* @param mByte
* @return
*/
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;
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
MsgUtil
/**
* @description
*/
public class MsgUtil {
public static final String MSGTYPE_EVENT = "event";//消息类型--事件
public static final String MESSAGE_SUBSCIBE = "subscribe";//消息事件类型--订阅事件
public static final String MESSAGE_UNSUBSCIBE = "unsubscribe";//消息事件类型--取消订阅事件
public static final String MESSAGE_TEXT = "text";//消息类型--文本消息
/**
* 组装文本消息
*/
public static String textMsg(String toUserName,String fromUserName,String content){
TextMsg text = new TextMsg();
text.setFromUserName(toUserName);
text.setToUserName(fromUserName);
text.setMsgType(MESSAGE_TEXT);
text.setCreateTime(new Date().getTime());
text.setContent(content);
return XmlUtil.textMsgToxml(text);
}
/**
* 响应订阅事件--回复文本消息
*/
public static String subscribeForText(String toUserName,String fromUserName,String content){
return textMsg(toUserName, fromUserName, content);
}
/**
* 响应取消订阅事件
*/
public static String unsubscribeForText(String toUserName,String fromUserName,String content){
System.out.println("用户:"+ fromUserName +"取消关注~");
return "";
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
application.yml
WxPublicController
/**
* @description
*/
@Controller
@RequestMapping(value = "/message/weixin")
public class WxPublicController {
protected static Logger logger = LoggerFactory.getLogger(WxPublicController.class);
//填写和公众号后台配置的一样的token
private static final String TOKEN = "";
/**
* 微信公众号appId
*/
@Value("${parameter.publicAppId}")
private String publicAppId;
/**
* 微信公众号appSecret
*/
@Value("${parameter.publicAppSecret}")
private String publicAppSecret;
@RequestMapping(method = RequestMethod.GET)
public void get(HttpServletRequest request, HttpServletResponse response) {
// 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
String signature = request.getParameter("signature");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce");
// 随机字符串
String echostr = request.getParameter("echostr");
PrintWriter out = null;
try {
out = response.getWriter();
// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,否则接入失败
if (SignUtil.checkSignature(TOKEN, signature, timestamp, nonce)) {
out.print(echostr);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null ) {
out.close();
}
}
}
@RequestMapping(method = RequestMethod.POST)
public void post(HttpServletRequest request, HttpServletResponse response) {
// 响应消息
PrintWriter out = null;
String resMessage = "";
try {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
//把微信返回的xml信息转义成map
Map<String, String> map = XmlUtil.parseXml(request);
//消息来源用户标识
String fromUserName = map.get("FromUserName");
//消息目的用户标识
String toUserName = map.get("ToUserName");
//消息创建时间(整型)
String createTime = map.get("CreateTime");
//消息类型
String msgType = map.get("MsgType");
//事件类型:subscribe/unsubscribe
String eventType = map.get("Event");
//如果为事件类型
if(MsgUtil.MSGTYPE_EVENT.equals(msgType)){
//处理订阅事件
if(MsgUtil.MESSAGE_SUBSCIBE.equals(eventType)){
resMessage = MsgUtil.subscribeForText(toUserName, fromUserName, "您好,谢谢您的关注!!!");
//TODO 业务逻辑
//处理取消订阅消息
} else if(MsgUtil.MESSAGE_UNSUBSCIBE.equals(eventType)) {
//TODO 业务逻辑
}
logger.info("eventType:"+eventType+",fromUserName:"+fromUserName+",toUserName:"+toUserName+",msgType:"+msgType+",createTime:"+createTime);
}
out = response.getWriter();
out.println(resMessage);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (out != null ) {
out.close();
}
}
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
您的一键三连,是我更新的最大动力,谢谢
山水有相逢,来日皆可期,谢谢阅读,我们再会
我手中的金箍棒,上能通天,下能探海