[Java project] SpringBoot project completed WeChat official account received user message automatic reply function with video (super detailed)

Video explanation

Video explanation

basic registration

First of all, you need to register your WeChat public account
WeChat public account platform
and then open the automatic reply function below,
insert image description here
insert image description here
then enter your developer center
developer center basic configuration
insert image description here
and generate your developer password, developer id, and set your IP whitelist.
The IP in the IP whitelist here must be a public network IP, because WeChat officials will send their requests to the public network, and then you need to respond to the request after receiving the request to realize the function of message exchange.
insert image description here
Then start to configure your server information
insert image description here
. The first is the URL. The URL here needs to be filled with
http://ip:80/path (the path here can meet the format of the request path)
or
https://ip:443/path
insert image description here
After that, you need to use these configurations in your SpringBoot project

Java part code

We first configure the pom file, because the data format of WeChat is xml,
so we need to introduce dependencies that can parse xml and convert xml, as follows,
here my springboot version is 2.7.7, but this effect should not be great, if there are some The problem can try to change the dependency version

      <!-- 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.19</version>
        </dependency>
        <dependency>
            <groupId>com.github.liyiorg</groupId>
            <artifactId>weixin-popular</artifactId>
            <version>2.8.30</version>
        </dependency>
        <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-mp</artifactId>
            <version>3.7.0</version>
        </dependency>

After that, just configure your WeChat official information in the project. Then as
insert image description here
I said just now, WeChat will send a request to the address you just entered on the public network. It is a get request and will carry some parameters. We have to do The only thing is to parse these parameters, the code is as follows
The following is the code of the Controller layer

import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Log
@RestController
@RequestMapping("/wx")
public class TokenCheckController {
    
    
    @Value("${wechat.mp.token}")
    private String token;
	@GetMapping("/")
    public String index(HttpServletResponse response, HttpServletRequest request) throws Exception {
    
    
        String echostr = TokenCheckUtil.checkToken(request, token);
        return echostr;
    }
}
   @PostMapping("/")
    public String chatGPTproxy(
            HttpServletResponse response,
            HttpServletRequest request,
            @RequestBody String requestBody, @RequestParam("signature") String signature,
            @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce,
            @RequestParam(name = "encrypt_type", required = false) String encType,
            @RequestParam(name = "msg_signature", required = false) String msgSignature) {
    
    

        System.out.println("requestbody:----"+requestBody);
        return requestBody;
}

Below is the code for the TokenCheckUtil toolkit

import javax.servlet.http.HttpServletRequest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import static cn.hutool.crypto.SecureUtil.sha1;

/**
 * @author: 张锦标
 * @date: 2023/4/2 15:10
 * TokenCheckUtil类
 */
public class TokenCheckUtil {
    
    
    public static String checkToken(HttpServletRequest request, String token) throws NoSuchAlgorithmException {
    
    
        String method = request.getMethod();
        //微信token验证get请求
        if ("GET".equals(method)) {
    
    
            //微信加密签名
            String echostr = request.getParameter("echostr");//时阅鲛
            String signature = request.getParameter("signature");//随机宁符串
            String timestamp = request.getParameter("timestamp");//随机数
            String nonce = request.getParameter("nonce");
            String[] str = {
    
    token, timestamp, nonce};
            //字典排序
            Arrays.sort(str);
            String bigStr = str[0] + str[1] + str[2];// SHA1加密
            String digest = sha1(bigStr);//对比签名
            if (digest.equals(signature)) {
    
    
                return echostr;
            } else {
    
    
                return "";
            }
        }
        return "";
    }
}

After the above two are completed, as long as you click Test, WeChat will send a Get request to this interface, and its request parameters are as the above code, you need to check and compare these parameters and return an echostr, the code just needs to be copied directly according to the above That's it.
Then continue to look at the code of the controller layer. There is a post request. Wechat will send the received user message to this post request. You only need to change the get request to post, and the path will not change.
The request data is in the request body, so the @RequestBody annotation needs to be used

test

Here we do a simple test first, package the project with maven, and then deploy it to your cloud server to
manage the WeChat public account test account.
Since we only did a test first, we use the test account management. Here is It is not necessary to set the port to 80, but when it is really online, then you need to use port 80. However, you can perform a proxy, for example, after using nginx, you can click submit, and then if you follow the
insert image description here
above If there is no problem with the steps, the following situation will appear.
insert image description here
After the above URL configuration is successful, you can ask your friends to scan the QR code of your test number and let them follow and send you a message.
insert image description here
After they send you a message, you will receive the following message, which is in XML format.
First, you will receive a message to subscribe to the official account. You can see that there is an Event tag. Then when the user sends you a message, You will also receive a Content tag, the content of which is the content sent to you by the user
insert image description here
, then all you need to do at this point is to parse the XML and get the data you need

Parse XML and get the required data

Java entity class for accepting requests and encapsulating


import lombok.Data;


/**
 * @author: 张锦标
 * @date: 2023/4/2 15:03
 * ReceiveMessage类
 */
@Data
public class ReceiveMessage {
    
    
    /**
     * 开发者微信号
     */
    private String ToUserName;
    /**
     * 发送方账号(一个openid)
     */
    private String FromUserName;
    /**
     * 消息创建时间(整形)
     */
    private String CreateTime;
    /**
     * 消息类型
     */
    private String MsgType;
    /**
     * 文本消息内容
     */
    private String Content;
    /**
     * 消息ID 64位
     */
    String MsgId;
    /**
     * 消息的数据ID 消息来自文章才有
     */
    private String MsgDataId;
    /**
     * 多图文时第几篇文章,从1开始 消息如果来自文章才有
     */
    private String Idx;
    /**
     * 订阅事件 subscribe订阅 unsbscribe取消订阅
     */
    private String Event;
}

XML Toolkit

import com.towelove.file.domain.wechat.ReceiveMessage;
import com.towelove.file.domain.wechat.ReplyMessage;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.io.StringWriter;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.XMLWriter;
/**
 * @author: 张锦标
 * @date: 2023/4/2 15:13
 * XMLUtil类
 */
public class XMLUtil {
    
    
    public static void main(String[] args) {
    
    
        String str = "" +
                "<xml><ToUserName><![CDATA[gh_71a0837d69a6]]></ToUserName>\n" +
                "<FromUserName><![CDATA[oy__X6O4BjH9QyyOcQaj55-O5Awo]]></FromUserName>\n" +
                "<CreateTime>1680533388</CreateTime>\n" +
                "<MsgType><![CDATA[text]]></MsgType>\n" +
                "<Content><![CDATA[123]]></Content>\n" +
                "<MsgId>24059451823534879</MsgId>\n" +
                "</xml>";
        System.out.println(XMLUtil.XMLTOModel(str));
    }
    public  static ReceiveMessage XMLTOModel(String str) {
    
    
        ReceiveMessage receiveMessage = new ReceiveMessage();
        try {
    
    
            Document document = DocumentHelper.parseText(String.valueOf(str));
            Element root = document.getRootElement();
            receiveMessage.setToUserName(root.elementText("ToUserName"));
            receiveMessage.setFromUserName(root.elementText("FromUserName"));
            receiveMessage.setMsgType(root.elementText("MsgType"));
            receiveMessage.setContent(root.elementText("Content"));
            receiveMessage.setCreateTime(root.elementText("CreateTime"));
            receiveMessage.setMsgId(root.elementText("MsgId"));
            //receiveMessage.setMsgDataId(root.elementText("MsgDataId"));
            //receiveMessage.setIdx(root.elementText("Idx"));
            关注
            //receiveMessage.setEvent(root.elementText("Event"));
        } catch (Exception e) {
    
    
            System.out.println(e);
        }
        return receiveMessage;
    }

    public static String ObjToXml(ReplyMessage obj) throws Exception {
    
    
        Document document = DocumentHelper.createDocument();
        Element root = document.addElement(obj.getClass().getSimpleName());
        convertObjectToXml(obj, root);
        StringWriter stringWriter = new StringWriter();
        XMLWriter writer = new XMLWriter(stringWriter);
        writer.write(document);
        writer.close();
        return stringWriter.toString();
    }
    private static void convertObjectToXml(Object obj, Element element) throws Exception {
    
    
        Class<?> clazz = obj.getClass();
        for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {
    
    
            field.setAccessible(true);
            Element child = element.addElement(field.getName());
            Object value = field.get(obj);
            if (value != null) {
    
    
                if (value.getClass().isPrimitive() || value.getClass() == java.lang.String.class) {
    
    
                    child.setText(value.toString());
                } else {
    
    
                    convertObjectToXml(value, child);
                }
            }
        }
    }
}

Then we use the test method to test whether this parsing code is valid
insert image description here
insert image description here

Implement message auto-reply

Then according to the above logic, we already know roughly what kind of data WeChat sends us. Then we just need to return the request in the post method according to the official definition of WeChat. Let’s take a look at the official Documentation
Official Documentation
insert image description here
The key is needed here, and the ToUserName and FromUserName have to be changed at this time.
Because in the above xml, ToUserName is ourselves, FromUserName is the user, and what we need to do at this time is to return data to the user, so at this time ToUserName is the user, and FromUserName is ourselves.
So first modify the code
insert image description here
and then let's use a main function to do a test

 public static void main(String[] args) {
    
    
        try {
    
    
            // 创建document对象
            Document document = DocumentHelper.createDocument();
            // 创建根节点bookRoot
            Element xml = document.addElement("xml");
            // 向根节点中添加第一个节点
            Element toUserName = xml.addElement("ToUserName");
            // 向子节点中添加属性
            toUserName.addCDATA("oy__X6JbTiLxEVG85ABtAawsc_qw");
            Element fromUserName = xml.addElement("FromUserName");
            fromUserName.addCDATA("gh_71a0837d69a6");
            Element createTime = xml.addElement("CreateTime");
            createTime.addCDATA(String.valueOf(System.currentTimeMillis()));
            Element msgType = xml.addElement("MsgType");
            msgType.addCDATA("text");
            Element content = xml.addElement("Content");
            content.addCDATA("hello呀,我是张锦标");


            System.out.println(document.getRootElement().asXML());

            // 设置生成xml的格式
            OutputFormat of = OutputFormat.createPrettyPrint();
            // 设置编码格式
            of.setEncoding("UTF-8");
            // 生成xml文件
            File file = new File("D:\\desktop\\student.xml");
            if (file.exists()){
    
    
                file.delete();
            }
            //创建一个xml文档编辑器
            XMLWriter writer = new XMLWriter(new FileOutputStream(file), of);
            //把刚刚创建的document放到文档编辑器中
            writer.write(document);
            writer.close();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }

The final format is as follows
insert image description here
Now that it’s ready, let’s start modifying the code in the post
So the code in the post request body is modified as follows

  @PostMapping("/")
    public String chatGPTproxy(
            HttpServletResponse response,
            HttpServletRequest request,
            @RequestBody String requestBody, @RequestParam("signature") String signature,
            @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce,
            @RequestParam(name = "encrypt_type", required = false) String encType,
            @RequestParam(name = "msg_signature", required = false) String msgSignature) {
    
    

        System.out.println("requestbody:----"+requestBody);
        ReceiveMessage receiveMessage = XMLUtil.XMLTOModel(requestBody);
        return parseMsgToXML(receiveMessage);
    }

The final result is as
insert image description here
insert image description here
follows. By the way, pay special attention, if your message reply time will exceed 5s, then the automatic reply will fail this time, so if your message query is very long, then you need to use customer service to reply, and then I will continue complete this function.

Measured

The above test function has been successful, so let’s change the port of the project to 80, and then try again.
Remember that the project should be placed on the cloud server.
insert image description here
insert image description here

insert image description here
insert image description here
insert image description here
insert image description here

Guess you like

Origin blog.csdn.net/Zhangsama1/article/details/129944565