• 微信小程序:引导用户关注微信公众号-用户关注/取消关注事件,特别详细,已成功


    前言

    相信来此的兄嘚都是看不懂官网,官方文档中有一些无从下手啊,或者已经尝试了其他的文章,但按照他们那个配置不成功,来这里就对了,因为我也是这么过来的,互相帮助。
    希望这篇文章解决了您的问题后,能给小弟一个三连,帮小弟把这篇文章顶上去,拯救更多的好兄弟于水火之中。

    业务背景

    项目需求
    微信小程序项目上想和微信公众号做关联互相引流,所以想在微信小程序上引导用户关注绑定的微信公众号;
    如何做一个好产品?
    从用户的需求来看,如果我没有关注微信公众号,你给我弹出,可以;
    我已经关注了微信公众号,你还让我去关注,oh No,不喜欢的!所以需要知道用户到底有么有关注我滴公众号呢?

    方案

    我们还是先要仰仗官方大大的,站在巨人的肩膀上,更省力更高效;

    微信公众号文档

    说明
    这里给大家解释一下,如果你想做引导用户关注微信公众号-用户关注/取消关注事件;在文档中直接搜索关注/取消关注事件;
    这里直接提供网址:微信公众号:用户关注/取消关注事件

    前提

    1、微信公众号的AppId和AppSecret需要拥有,开发者密码如果没有记录的话只能重置了。下面需要使用到这两个信息。
    在这里插入图片描述
    2、**注意:**这个是验证token的,调用微信公众号的api都需要拥有token验证哦,下面的代码里你会看见;
    在这里插入图片描述
    3、拥有一个服务器,且需要使用你服务器的80(对应http)或443(对应https)端口;可以不使用域名直接配置为IP

    实操步骤

    了解完前提之后,我们进行实操,跟着我配置,一次成功,如有问题随时评论交流

    第一步:后端代码编写(需要在配置文件里修改一些你自己的东西)

    创建一个被maven管理的项目

    这里和上文的前提中2对应,需要写两个接口:1、验证token接口(GET请求);2、关注/取消关注事件接口(POST请求)
    首先给大家看一下目录结构
    在这里插入图片描述

    在这里插入图片描述

    注意注意:这两个接口对外的名字要一样

    验证token接口(GET请求)和 关注/取消关注事件接口(POST请求)

    在这里插入图片描述
    其中验证token接口做了两件事
    Main类

    package com.example;
    
    import lombok.extern.log4j.Log4j2;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.core.env.Environment;
    import org.springframework.web.bind.annotation.CrossOrigin;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    
    /**
     * @BelongsProject: BigK
     * @BelongsPackage: com.example
     * @Description: TODO
     * @Version: 1.0
     */
    @Log4j2
    @EnableSwagger2
    @SpringBootApplication//开启自动配置
    @MapperScan("com.example.mapper")
    public class Main {
        public static void main(String[] args) throws UnknownHostException {
            System.out.println("启动了");
    
            ConfigurableApplicationContext application = SpringApplication.run(Main.class, args);
    
            Environment env = application.getEnvironment();
            String ip = InetAddress.getLocalHost().getHostAddress();
            String port = env.getProperty("server.port");
            String path = env.getProperty("server.servlet.context-path");
            // 未配置默认空白
            if (path == null) {
                path = "";
            }
            log.info("\n----------------------------------------------------------\n\t" +
                    "公众号微服务启动成功,访问路径如下:\n\t" +
                    "本地路径: http://localhost:" + port + path + "/\n\t" +
                    "网络地址: http://" + ip + ":" + port + path + "/\n\t" +
                    "接口地址: http://" + ip + ":" + port + path + "/swagger-ui.html\n\t"  +
                    "API文档: http://" + ip + ":" + port + path + "/doc.html\n" +
                    "----------------------------------------------------------");
        }
    
    }
    
    • 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

    Entity实体层
    实体:UserInfoEntity

    package com.example.pojo;
    
    import lombok.Data;
    
    import java.util.List;
    
    /**
     * @BelongsPackage: com.tfjybj.entity.wxgzh
     * @Description: 微信公众号用户信息集合
     * @Version: 1.0
     */
    @Data
    public class UserInfoEntity {
        //关注公众号的用户列表
        private List<UserInfoList> user_info_list;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    实体:UserInfoList

    package com.example.pojo;
    
    import lombok.Data;
    
    import java.util.List;
    
    /**
     * @BelongsPackage: com.tfjybj.entity
     * @Description: 微信公众号用户信息
     * @Version: 1.0
     */
    @Data
    public class UserInfoList {
        //用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息
        private int subscribe;
    
        //用户的标识,对当前公众号唯一
        private String openid;
    
        //用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间
        private int subscribe_time;
    
        //只有在用户将公众号绑定到微信开放平台账号后,才会出现该字段。
        private String unionid;
    
        //公众号运营者对粉丝的备注,公众号运营者可在微信公众平台用户管理界面对粉丝添加备注
        private String remark;
    
        //用户所在的分组ID(兼容旧的用户分组接口)
        private int groupid;
    
        //用户被打上的标签ID列表
        private List<String> tagid_list;
    
        //返回用户关注的渠道来源
        //返回用户关注的渠道来源,ADD_SCENE_SEARCH 公众号搜索,ADD_SCENE_ACCOUNT_MIGRATION 公众号迁移,ADD_SCENE_PROFILE_CARD 名片分享,ADD_SCENE_QR_CODE 扫描二维码,ADD_SCENE_PROFILE_LINK 图文页内名称点击,ADD_SCENE_PROFILE_ITEM 图文页右上角菜单,ADD_SCENE_PAID 支付后关注,ADD_SCENE_WECHAT_ADVERTISEMENT 微信广告,ADD_SCENE_REPRINT 他人转载 ,ADD_SCENE_LIVESTREAM 视频号直播,ADD_SCENE_CHANNELS 视频号 , ADD_SCENE_OTHERS 其他
        private String subscribe_scene;
    
        //二维码扫码场景(开发者自定义)
        private int qr_scene;
    
        //二维码扫码场景描述(开发者自定义)
        private String qr_scene_str;
    
    
        //微信公众号调整之后以下信息将按照默认规则返回
        //性别:0-未知,1-男性,2-女性(强制返回0)
        private int sex;
    
        //用户所在城市
        private String city;
    
        //用户所在省份
        private String province;
    
        //用户所在国家
        private String country;
    
        //头像
        private String headimgurl;
    
        //昵称
        private String nickname;
    
        //用户的语言,简体中文为zh_CN(强制返回“xh_CN”)
        private String language;
    }
    
    
    • 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

    controller层
    代码中的令牌要和公众号后台配置的一致哦
    在这里插入图片描述

    package com.example.controller;
    
    
    import com.example.service.GzhService;
    import io.swagger.annotations.Api;
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.security.NoSuchAlgorithmException;
    
    
    import org.apache.commons.lang3.StringUtils;
    
    /**
     * @BelongsProject: BigK
     * @BelongsPackage: com.example
     * @Description: TODO
     * @Version: 1.0
     */
    @RestController
    @Api("公众号")
    public class Controller {
    
        @Autowired
        private GzhService gzhService;
    
        private static final Logger log = LogManager.getLogger(Controller.class);
        private static final String TOKEN = "dmsd";
    
        public Controller() {
        }
    
        @GetMapping(value="/serverCheck")
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, NoSuchAlgorithmException {
            String signature = request.getParameter("signature");
            String timestamp = request.getParameter("timestamp");
            String nonce = request.getParameter("nonce");
            String echostr = request.getParameter("echostr");
            log.info("\n接收到来自微信服务器的认证消息:[{}, {}, {}, {}]", signature, timestamp, nonce, echostr);
            if (StringUtils.isAnyBlank(new CharSequence[]{signature, timestamp, nonce, echostr})) {
                throw new IllegalArgumentException("请求参数非法,请核实!");
            } else {
                String signatureCheck =gzhService.getSHA1(TOKEN, timestamp, nonce);
                log.info("\n加密后的signatureCheck = {}", signatureCheck);
                if (signatureCheck.equals(signature)) {
                    log.info("\n接入成功");
                    PrintWriter out = response.getWriter();
                    out.print(echostr);
                    out.flush();
                    out.close();
                }
    
            }
        }
    
    
        @PostMapping(value = "/serverCheck")
        public void checkTokenPost(HttpServletRequest request, HttpServletResponse response) {
            try{
                gzhService.checkTokenPost(request,response);
            }catch (Exception e){
                log.error(e.getMessage());
            }
    
        }
    }
    
    
    • 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

    service接口

    package com.example.service;
    
    import com.example.TextMessage;
    import com.example.mapper.GzhOfficialMapper;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.security.NoSuchAlgorithmException;
    import java.util.Map;
    
    /**
     * @BelongsProject: BigK
     * @BelongsPackage: com.example.service
     * @Description: TODO
     * @Version: 1.0
     */
    
    public interface GzhService {
    
        /**
         * @Description:微信服务器校验
         * @param token:
         * @param timestamp:
         * @param nonce:
         * @return: java.lang.String
         **/
        String getSHA1(String token, String timestamp, String nonce) throws NoSuchAlgorithmException;
    
        /*
         * @description:关注/取消关注事件
         * @param: [request, response]
         * @return: void
         **/
        void checkTokenPost(HttpServletRequest request, HttpServletResponse response) throws Exception;
    
    }
    
    
    • 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

    service实现层

    package com.example.service.impl;
    
    import cn.hutool.http.HttpUtil;
    import cn.hutool.json.JSONNull;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import cn.hutool.json.JSONUtil;
    import com.alibaba.fastjson.JSONObject;
    import com.example.TextMessage;
    import com.example.WxEeventType;
    import com.example.WxMessageType;
    import com.example.WxMessageUtil;
    import com.example.entity.GzhOfficialEntity;
    import com.example.mapper.GzhOfficialMapper;
    import com.example.pojo.UserInfoEntity;
    import com.example.service.GzhService;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.util.StringUtils;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.PrintWriter;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.Map;
    
    
    /**
     * @BelongsProject: BigK
     * @BelongsPackage: com.example.service.impl
     * @Description: TODO
     * @Version: 1.0
     */
    @Slf4j
    @Service
    public class GzhServiceImpl implements GzhService {
        @Autowired
        private GzhOfficialMapper gzhUserMapper;
    
    
        /**
         * @Description:微信服务器校验
         * @param token:
         * @param timestamp:
         * @param nonce:
         * @return: java.lang.String
         **/
        public String getSHA1(String token, String timestamp, String nonce) throws NoSuchAlgorithmException {
            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();
            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] & 255);
                if (shaHex.length() < 2) {
                    hexstr.append(0);
                }
    
                hexstr.append(shaHex);
            }
    
            return hexstr.toString();
        }
    
        /**
         * @Description:关注/取消关注事件
         * @param request:
         * @param response:
         * @return: void
         **/
        @Override
        public void checkTokenPost(HttpServletRequest request, HttpServletResponse response) throws Exception {
            Map<String, String> requestMap = WxMessageUtil.parseXml(request);
            log.info("解析====>{}", request);
    
            String messageType = requestMap.get("MsgType");
            log.info("微信类型===>{}", messageType);
            String eventType = requestMap.get("Event");
            // 发送方帐号(open_id)
            String openid = requestMap.get("FromUserName");
            // 公众帐号
            String toUserName = requestMap.get("ToUserName");
            // 消息类型
            String msgType = requestMap.get("MsgType");
    
            if (messageType.equals(WxMessageType.EVENT.getCode())) {
                //判断消息类型是否是事件消息类型
                log.info("公众号====>事件消息");
                log.info("openid:" + openid);
                log.info("Event:" + eventType);
    
                //新用户关注:
                //查询prosper_user_official表指定openid&&subscribe=1 的用户信息
                GzhOfficialEntity gzhOfficialEntity = gzhUserMapper.selectInfoByOpenid(openid, 1);
    
                if (eventType.equals(WxEeventType.SUBSCRIBE.getCode())) {
                    log.info("公众号====>新用户关注");
                    //获取accesstoken
                    String accessToken = getAccessToken();
    
    
                    // 构建获取用户的基本信息
                    String buffer = "https://api.weixin.qq.com/cgi-bin/user/info?" +
                            "access_token=" + accessToken +
                            "&openid=" + openid + "&lang=zh_CN";
                    String wxUserString = HttpUtil.get(buffer);
                    log.info("获取用户信息===>{}", wxUserString);
                    cn.hutool.json.JSONObject jsonObject1 = JSONUtil.parseObj(wxUserString);
    
                    //返回条数>0,有此新用户关注信息;
                    //返回条数<=0,没有此用户信息,插入信息
                    if(!StringUtils.isEmpty(gzhOfficialEntity)){
                        UserInfoEntity userInfo = getUserInfo(openid);
    
                        GzhOfficialEntity gzhUserInfo = new GzhOfficialEntity();
                        gzhUserInfo.setOpenid(openid);
                        gzhUserInfo.setUnionid(userInfo.getUser_info_list().get(0).getUnionid());
                        gzhUserInfo.setIsSubscribe(1);
    
                        int insertResult = gzhUserMapper.insertUserInfo(gzhUserInfo);
                        if(insertResult<=0){
                            log.error("查询新关注用户失败",gzhUserInfo);
                        }
                    }
    
    
                } else if (eventType.equals(WxEeventType.UNSUBSCRIBE.getCode())) {
                    //取消关注:
                    //更新prosper_user_official表指定openid && subscribe=1 的用户,设置 subscribe=0
                    int updateResult = gzhUserMapper.updateStatus(openid, 0);
                    if(updateResult<=0){
                        log.error("更新取关用户信息失败",updateResult);
                    }
    
                    log.info("公众号====>用户取消关注");
                } else {
                    log.info("微信类型===>{}", messageType);
                    log.info("公众号===>其他");
                }
            } else if (messageType.equals(WxMessageType.TEXT.getCode())) {
                log.info("用户输入文本信息");
                // 响应消息
                PrintWriter out = response.getWriter();
                TextMessage textMessage = new TextMessage();
                textMessage.setFromUserName(openid);
                textMessage.setToUserName(toUserName);
                textMessage.setMsgType(msgType);
                textMessage.setCreateTime(System.currentTimeMillis());
                textMessage.setContent("欢迎您");
                String message = WxMessageUtil.textMessageToXml(textMessage);
                log.info("message==>{}",message);
                out.println(message);
                // 关闭流
                out.close();
            }
        }
    
    
        /**
         * @Description:获取微信公众号token
         * @return: java.lang.String
         **/
        public String getAccessToken(){
            // 获取接口调用凭证
            String accessTokenStr = "https://api.weixin.qq.com/cgi-bin/token?" +
                    "grant_type=client_credential" + "&appid=" + "wx2b9d806c89ac57dc" + "&secret=" + "c93c372ecdf9d343054431d3257ae8af";
            String tokenStr = HttpUtil.get(accessTokenStr);
            cn.hutool.json.JSONObject object = JSONUtil.parseObj(tokenStr);
            String accessToken = object.get("access_token").toString();
            return accessToken;
        }
    
        /**
         * @Description:通过openid获取微信公众号用户信息
         * @return: void
         **/
        public UserInfoEntity getUserInfo(String openId) throws JsonProcessingException {
            // 获取AccessToken的值
            String accessToken = getAccessToken();
    
            Map<String, String> openIdMap = new HashMap<>();
            openIdMap.put("openid", openId);
            openIdMap.put("lang", "zh-CN");
    
            //创建最外层的包含用户列表的对象
            Map<String,Object> requestMap= new HashMap<>();
            requestMap.put("user_list",openIdMap);
    
            // 将对象转换为JSON字符串
            ObjectMapper objectMapper = new ObjectMapper();
            String json = objectMapper.writeValueAsString(requestMap);
    
            String url = "https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token="+accessToken;
            //调用接口并传入json字符串
            String dataStr = HttpUtil.post(url, json);
    
            // 将JSON字符串解析为JSONObject对象
            JSONObject jsonObject1 = JSON.parseObject(dataStr);
    
            // 将JSONObject对象转换为指定的实体类对象
            UserInfoEntity gzhUserExtity= new UserInfoEntity();
            gzhUserExtity = jsonObject1.toJavaObject(UserInfoEntity.class);
    
            return gzhUserExtity;
        }
    }
    
    
    • 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
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224

    mapper接口层

    package com.example.mapper;
    
    import com.example.entity.GzhOfficialEntity;
    import org.apache.ibatis.annotations.Mapper;
    
    
    /**
     * @BelongsProject: BigK
     * @BelongsPackage: com.example.mapper
     * @Description: TODO
     * @Version: 1.0
     */
    
    @Mapper
    public interface GzhOfficialMapper {
    
        /**
         * @Description:指定openid&&subscribe=1 的用户信息
         * @param openId:
         * @param subscribe:
         * @return: com.example.entity.GzhOfficialEntity
         **/
        GzhOfficialEntity selectInfoByOpenid(String openId,int subscribe);
    
        /**
         * @Description:更新用户关注状态
         * @Author: denglimei
         * @Date: 2023/8/20 19:55
         * @param openId:
         * @param subscribe:
         * @return: int
         **/
        int updateStatus(String openId,int subscribe);
    
        /**
         * @Description:插入新关注用户信息
         * @param officialEntity:
         * @return: int
         **/
        int insertUserInfo(GzhOfficialEntity officialEntity);
    }
    
    
    • 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

    mapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!-- namespace="com.b0.mybatis.mapper.UserMapper" -->
    <mapper namespace="com.example.mapper.GzhOfficialMapper">
    
        <select id="selectInfoByOpenid" resultType="com.example.entity.GzhOfficialEntity">
            SELECT open_id ,union_id FROM `prosper_user_official` where open_id=#{openId} and is_subscribe=#{isSubscribe}
        </select>
    
        <update id="updateStatus" parameterType="com.example.entity.GzhOfficialEntity">
            update prosper_user_official set is_subscribe =#{isSubscribe} where open_id=#{openId}
        </update>
    
    
        <insert id="insertUserInfo" parameterType="com.example.entity.GzhOfficialEntity">
            insert prosper_user_official (open_id,union_id,is_subscribe) VALUES(#{openId},#{unionid},#{isSubscribe})
        </insert>
    </mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    pom.xml(有一些没有用到)

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.3.12.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>org.example</groupId>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>WxGzh</artifactId>
        <dependencies>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.13</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-autoconfigure</artifactId>
            </dependency>
    
            <dependency>
                <groupId>dom4j</groupId>
                <artifactId>dom4j</artifactId>
                <version>1.6.1</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>3.12.0</version>
            </dependency>
    
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version> 5.7.17</version>
            </dependency>
    
            <dependency>
                <groupId>xmlpull</groupId>
                <artifactId>xmlpull</artifactId>
                <version>1.1.3.1</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream -->
            <dependency>
                <groupId>com.thoughtworks.xstream</groupId>
                <artifactId>xstream</artifactId>
                <version> 1.4.19</version>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.73</version>
                <scope>compile</scope>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version> 8.0.30</version>
            </dependency>
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>2.9.2</version>
            </dependency>
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger-ui</artifactId>
                <version>2.9.2</version>
            </dependency>
            <dependency>
                <groupId>javax.xml.bind</groupId>
                <artifactId>jaxb-api</artifactId>
                <version> 2.3.1</version>
            </dependency>
            <dependency>
                <groupId>jakarta.xml.bind</groupId>
                <artifactId>jakarta.xml.bind-api</artifactId>
                <version>2.3.3</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version> 2.2.2</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>2.7.10</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.kafka</groupId>
                <artifactId>spring-kafka</artifactId>
                <version>2.8.1</version>
            </dependency>
        </dependencies>
    
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
        </properties>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>
    
    • 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
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141

    application.yml
    注意:需要配置自己的端口、微信公众号的开发信息、数据库地址

    server:
      port: 80 #设置好自己的端口,必须为80或443
      servlet:
        context-path: /user
    
    wechat:
      appId: "你的AppID" #在公众号后台的设置与开发里面的基本配置里
      appSecret: "开发者密码(AppSecret)"
      token: "dmsd"
    
    mybatis:
      mapper-locations: classpath*:mapper/*.xml
    
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://
        你的数据库地址/哪个数据库?autoReconnect=true&useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&rewriteBatchedStatements=true
        username: 用户名
        password: 密码
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    数据库表结构

    我的表名为prosper_user_official,如果你要修改表名的话,需要修改mapper.xml中的表名

    类型长度小数点不是Null虚拟注释
    open_idvarchar25501
    union_idvarchar2550
    is_subscribeint10是否关注公众号(0:没有关注该公众号:1:已关注)

    第二步:打包部署

    maven打包

    在这里插入图片描述
    在这里插入图片描述

    部署到服务器上

    1、先将jar包上传到服务器上
    2、启动jar包
    (要先安装jdk哈)启动jar包命令:

    nohup java -jar WxGzh-2.3.12.RELEASE.jar > gzh.log 2>&1 &
    
    • 1

    这条命令主要是运行一个 Java 应用程序,具体解释如下:

    • nohup 表示不挂断地运行命令,即使终端退出,命令也能够继续运行。
    • java -jar WxGzh-2.3.12.RELEASE.jar 表示运行 Java 应用程序 WxGzh-2.3.12.RELEASE.jar,-jar 参数用于指定运行 jar 包。
    • > 表示将标准输出重定向到 gzh.log 文件中。即将程序的标准输出(包括 System.out.println() 打印的内容)输出到 gzh.log 文件中。
    • 2>&1 表示将标准错误重定向到标准输出。即将程序的标准错误(包括 System.err.println() 打印的内容)也输出到 gzh.log 文件中。
    • & 表示将命令放入后台运行。

    综合起来,这条命令的作用是在后台运行一个 Java 应用程序,将程序的标准输出和标准错误输出到 gzh.log 文件中。
    所以根据你配置的名字去更改吧。
    3、查看防火墙端口是否开启
    firewall-cmd --list-all
    开放端口命令:firewall-cmd --zone=public --add-port=80/tcp --permanent
    如果是https,则将80改为443

    第三步:测试一下

    微信公众号给我们提供了接口调试工具
    微信公众平台接口调试工具
    选择这两个
    下面的按照他提示的填写就好,填写整型的可以随便写几个数字;
    在这里插入图片描述

    效果展示

    因为在代码里配置了日志,并且启动jar包时配置了log文件,所以我们可以查看日志来验证是否成功;
    如果报错,可以针对报错去解决问题。
    在这里插入图片描述

    测试通过后配置后台

    在这里插入图片描述
    点击提交,如果显示成功则说明验证通过,微信就是实时监听微信公众号用户关注/取消关注的操作,并且将结果转发到我们刚才配置的服务器地址上

    总结

    帮助别人就是帮助自己
    总的来说,引导用户关注微信公众号可以为开发者提供更多的渠道,让用户更好地了解和使用产品。同时,处理用户关注/取消关注事件的相关逻辑也可以为开发者提供更多的互动和营销机会。

    小弟创作不易,如果文章符合您的心意,辛苦大佬给小弟个一键三连,让这篇文章可以帮助到更多的人

  • 相关阅读:
    「Python实用秘技06」逐行监听Python程序的内存消耗
    css和js放置的位置
    【PAT甲级】1122 Hamiltonian Cycle
    ASP.NET WebApi 极简依赖注入
    对于html和css初学者,你有什么值得推荐的简单的网页适合练习?
    adb命令汇总
    Mybatis的关系关联配置
    【python基础】python类的成员变量与成员函数的一些疑问
    RK3568 + YT 9215交换机芯片,MAC TO MAC 调试记录
    day01 spring
  • 原文地址:https://blog.csdn.net/aqiuisme/article/details/132665686