微信公众号开发-公众号被动回复用户消息

专栏简介
💒个人主页
📰专栏目录
📖心灵鸡汤📖
没有人能改变你,别人只能影响你,能改变你的只有你自己。
✍相关博文✍
微信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.指令演示
在这里插入图片描述

### PHP 实现微信公众号被动回复图片的方法 为了通过PHP实现微信公众号被动回复图片功能,需遵循特定的消息结构和接口调用方式。当接收到用户的请求时,应解析XML格式的数据包并构建相应的响应。 #### 解析接收消息 在处理来自微信服务器的消息前,先要对接收的信息进行解码: ```php $postStr = file_get_contents('php://input'); if (!empty($postStr)){ libxml_disable_entity_loader(true); $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); } ``` 此段代码读取POST过来的内容,并将其转换成可操作的对象形式[^2]。 #### 构建图像回复消息体 对于发送图片类型的回复,需要按照指定的XML模板来创建回应内容。以下是用于构造此类响应的具体方法: ```php function responseImageMsg($toUser, $fromUser, $mediaId){ $time = time(); $msgType = "image"; $template = "<xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%d</CreateTime> <MsgType><![CDATA[%s]]></MsgType> <Image> <MediaId><![CDATA[%s]]></MediaId> </Image> </xml>"; return sprintf($template, $toUser, $fromUser, $time, $msgType, $mediaId); } ``` 上述函数接受三个参数:目标用户ID (`$toUser`)、源用户ID(`$fromUser`), 和媒体文件标识符(`$mediaId`). 它们共同组成了完整的XML字符串表示形式. #### 设置Access Token 值得注意的是,在实际应用过程中可能还需要定期更新 `access_token`, 以便能够正常使用微信公众平台所提供的API服务。通常来说,这一步骤涉及向官方提供的URL发起HTTP GET请求以换取最新的访问令牌[^3]: ```php $appid = 'YOUR_APP_ID'; $secret = 'YOUR_APP_SECRET'; $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appid}&secret={$secret}"; $response = json_decode(file_get_contents($url)); $accessToken = $response->access_token; ``` 不过请注意,这里的 `$mediaId` 需要在上传多媒体素材之后由微信端返回获得,而不仅仅是简单的字符串替换。 最后,确保已正确设置了回调验证中的Token值以及URL路径指向自己的服务器地址[^4]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不要喷香水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值