专栏简介 | ||
💒个人主页 📰专栏目录 | 📖心灵鸡汤📖 没有人能改变你,别人只能影响你,能改变你的只有你自己。 | ✍相关博文✍ 微信API封装 token验证 |
本栏以基础的订阅号为例进行模拟实现,服务号通用
需求模拟
1️⃣.客户关注公众号时,自动回复消息给客户
2️⃣.根据客户发送的文字,进行相应的回复
需求分析
在订阅号上面实现相关功能。用的是【对话服务】中的接收消息和发送消息的相关接口服务
环境配置
需要先在公众平台配置token,相关配置步骤可参考: token验证
软件设计
1.采用SpringBoot工程进行开发
2.数据库采用MongoDB存储(当然你可以选择其它数据库),目前设计三个表分别为
receive_msg | 接收信息表,用于存储客户发送的信息 |
reply_msg | 回复消息表,用于存储回复客户的消息 |
my_order | 指令 表,用于存储设置指令对应的回复信息 |
代码实现
🔈本文仅以回复文本内容进行演示
🔈消息的接收和回复都是通过微信服务器实现
实现流程:
1.通过微信服务器接收客户发送的消息,并将xml转换成对象存储起来
2.根据发送的消息内容,获取指令对应的回复内容
3.回复消息至微信服务器,通过微信服务器将消息告知客户
1.接收消息
1.引入依赖
<!--xml解析-->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.0.0</version>
</dependency>
<!--Java对象转换为xml-->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.9</version>
</dependency>
2.创建TokenCheckController
import com.lvyq.model.receive.ReceiveMsg;
import com.lvyq.service.OrderService;
import com.lvyq.util.TokenCheckUtils;
import com.lvyq.util.XMLUtils;
import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @program: weg
* @description: 微信公众号平台token验证
* @author: lvyq
* @create: 2023-03-07 14:49
**/
@RequestMapping
@Controller
@CrossOrigin
@Log
public class TokenCheckController {
@Value("${wechat.token}")
public String token;
@Resource
private MongoTemplate mongoTemplate;
@Resource
private OrderService orderService;
@RequestMapping("/")
public void index(HttpServletResponse response, HttpServletRequest request) throws Exception{
boolean state=TokenCheckUtils.checkToken(response,request,token);
if (state){
ReceiveMsg receiveMsg = XMLUtils.XMLTOModel(request);
mongoTemplate.save(receiveMsg);
//指令回复
orderService.orderReply(response,receiveMsg);
}else {
log.info("请求无效");
}
}
}
3.TokenCheckUtils.java
import javax.servlet.http.HttpServletRequest;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
/**
* @program: weg
* @description: token验证工具
* @author: lvyq
* @create: 2023-03-07 14:55
**/
public class TokenCheckUtils {
public static boolean checkToken(HttpServletResponse response, HttpServletRequest request, String token) throws NoSuchAlgorithmException, IOException {
String method = request.getMethod();
String signature = request.getParameter("signature");
String echostr = request.getParameter("echostr");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String[] str = new String[]{token, timestamp, nonce};
Arrays.sort(str);
String bigStr = str[0] + str[1] + str[2];
String digest = sha1(bigStr);
if (digest.equals(signature)) {
if ("GET".equals(method)) {
response.getWriter().print(echostr);
}
return true;
} else {
return false;
}
}
/**
* @description: sha1
* @author: lvyq
* @date: 2022/7/8 15:18
* @version 1.0
*/
public static String sha1(String data) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA1");
//把字符串转为字节数组
byte[] b = data.getBytes();
//使用指定的字节来更新我们的摘要
md.update(b);
//获取密文 (完成摘要计算)
byte[] b2 = md.digest();
//获取计算的长度
int len = b2.length;
//16进制字符串
String str = "0123456789abcdef";
//把字符串转为字符串数组
char[] ch = str.toCharArray();
//创建一个40位长度的字节数组
char[] chs = new char[len*2];
//循环20次
for(int i=0,k=0;i<len;i++) {
//获取摘要计算后的字节数组中的每个字节
byte b3 = b2[i];
// >>>:无符号右移
// &:按位与
//0xf:0-15的数字
chs[k++] = ch[b3 >>> 4 & 0xf];
chs[k++] = ch[b3 & 0xf];
}
//字符数组转为字符串
return new String(chs);
}
}
4.XMLUtils.java (解析xml
)
/**
* @Description: 接收的xml格式转换为model实体
* @params: * @param
* @Author: lvyq
* @Date: 2023/3/7 15:38
*/
public static ReceiveMsg XMLTOModel(HttpServletRequest request){
ReceiveMsg receiveMsg= new ReceiveMsg();
try {
InputStream inputStream;
StringBuffer sb = new StringBuffer();
inputStream = request.getInputStream();
String s;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
while ((s = in.readLine()) != null) {
sb.append(s);
}
Document document = DocumentHelper.parseText(String.valueOf(sb));
Element root = document.getRootElement();
receiveMsg.setToUserName(root.elementText("ToUserName"));
receiveMsg.setFromUserName(root.elementText("FromUserName"));
receiveMsg.setMsgType(root.elementText("MsgType"));
receiveMsg.setContent(root.elementText("Content"));
receiveMsg.setCreateTime(root.elementText("CreateTime"));
receiveMsg.setMsgId(root.elementText("MsgId"));
receiveMsg.setMsgDataId(root.elementText("MsgDataId"));
receiveMsg.setIdx(root.elementText("Idx"));
receiveMsg.setEvent(root.elementText("Event"));
in.close();
inputStream.close();
}catch (Exception e){
System.out.println(e.getMessage());
}
return receiveMsg;
}
/**
* @Description: 对象转xml
* @params: * @param data
* @return: {@link java.lang.String}
* @Author: lvyq
* @Date: 2023/3/7 21:37
*/
public static String ObjToXml(ReplyMsg data){
JAXBContext context = null;
Marshaller marshaller=null;
String xmlObj="";
try {
context = JAXBContext.newInstance(ReplyMsg.class);
marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
marshaller.marshal(data, baos);
xmlObj= new String(baos.toByteArray());
}catch(Exception e){
e.printStackTrace();
}
return xmlObj;
}
2.发送消息
1.orderReply方法
public JSONObject orderReply(HttpServletResponse response, ReceiveMsg receiveMsg) throws IOException {
JSONObject mav = new JSONObject();
if (receiveMsg.getMsgType().equals(MsgTypeConstant.EVENT) && receiveMsg.getEvent().equals("subscribe")){
//关注
receiveMsg.setContent("关注");
}
Order order = orderRepository.findByOrderName(receiveMsg.getContent());
ReplyMsg replyMsg = new ReplyMsg();
replyMsg.setMsgType(MsgTypeConstant.TEXT);
replyMsg.setFromUserName(receiveMsg.getToUserName());
replyMsg.setToUserName(receiveMsg.getFromUserName());
replyMsg.setCreateTime(System.currentTimeMillis());
if (order!=null){
replyMsg.setContent(order.getMovementContent());
}else {
//指令未存在于指令库中
replyMsg.setContent("☹对不起,您说的话,小窝还没听懂,小窝正在努力学习中\uD83D\uDE2D");
}
String msg= XMLUtils.ObjToXml(replyMsg);
response.setCharacterEncoding("UTF-8");
response.getWriter().print(msg);
mongoTemplate.save(replyMsg);
mav.put("msg","操作成功");
return mav;
}
效果演示
1关注演示
2.指令演示