Java 扫码关注公众号获取openId,以及关注和取消动作

目录

一:微信端配置

二:准备接受服务器信息,进行地址验签

三:公众号关注、取消、输入文本等指令信息

3-1:代码解析公众号请求信息,将信息内容都放在request里,所以需要对request进行解析

3-2:用户如果发送文本信息则进行回复


一:微信端配置

在设置与开发——>基本配置中,设置服务器配置,token可以随便输入,填写之后,记录下来,马上代码中需要用到。key点击随机生成

 如果此时点击提交,就会报错,token验证失败,因为上面很清楚说明了“此信息需要你拥有自己的服务器资源”,也就是说这个接口将会掉用我们自己服务上的接口,进行验证,所以准备JAVA项目

二:准备接受服务器信息,进行地址验签

/**
     * 微信服务器发送信息,进行验签
     * @param request
     * @param response
     * @return
     */
    @GetMapping("/checkToken")
    public String checkToken2(HttpServletRequest request, HttpServletResponse response) {
        try {
            if (StringUtils.isNotBlank(request.getParameter("signature"))) {
                String signature = request.getParameter("signature");
                String timestamp = request.getParameter("timestamp");
                String nonce = request.getParameter("nonce");
                String echostr = request.getParameter("echostr");
                log.info("signature[{}], timestamp[{}], nonce[{}], echostr[{}]", signature, timestamp, nonce, echostr);
                if (SignUtil.checkSignature(signature, timestamp, nonce)) {
                    log.info("数据源为微信后台,将echostr[{}]返回!", echostr);
                    return echostr;
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return "";
    }

 

 

该方法必须是get请求, 且每次修改配置点击提交之前都会进行验签,验签成功直接返回echostr,启动服务再次点击提交,服务器配置就可以保存了。

三:公众号关注、取消、输入文本等指令信息

公众号的关注和取消请求的地址都是和上面的地址相同,只不过上面的是get请求,所有的动作指令都是POST请求,请注意!

/**
     * 关注公众号验签
     */
    @PostMapping("/checkToken")
    public void checkTokenPost(HttpServletRequest request, HttpServletResponse response) {
        try {
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");

            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);
                if (eventType.equals(WxEeventType.SUBSCRIBE.getCode())) {
                    log.info("公众号====>新用户关注");
                    // 获取接口调用凭证
                    String accessTokenStr = "https://api.weixin.qq.com/cgi-bin/token?" +
                            "grant_type=client_credential" + "&appid=" + "wxXXXXXXXX" + "&secret=" + "f97XXXXXXXX";
                    String tokenStr = HttpUtil.get(accessTokenStr);
                    JSONObject object = JSONUtil.parseObj(tokenStr);
                    String accessToken = object.get("access_token").toString();

                    // 构建获取用户的基本信息
                    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);
                    JSONObject jsonObject = JSONUtil.parseObj(wxUserString);
                } else if (eventType.equals(WxEeventType.UNSUBSCRIBE.getCode())) {
                    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();
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

3-1:代码解析公众号请求信息,将信息内容都放在request里,所以需要对request进行解析

3-1-1:引用Maven,编写WxMessageUtil工具类

<dependency>
    <groupId>dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>1.6</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>
package com.dx.common.utils;

import com.dx.common.domain.TextMessage;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * WxMessageUtil
 *
 * @Description: 解析微信关注后的xml信息
 * @Author: bb
 * @Date: 2022-08-18
 * @Version: V1.0.0
 */
public class WxMessageUtil {
    /**
     * 解析微信发来的请求(XML)
     *
     * @param request
     * @return
     * @throws Exception
     */
    public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
        // 将解析结果存储在HashMap中
        Map<String, String> map = new HashMap<String, String>();

        // 从request中取得输入流
        InputStream inputStream = request.getInputStream();
        // 读取输入流
        SAXReader reader = new SAXReader();
        Document document = reader.read(inputStream);
        // 得到xml根元素
        Element root = document.getRootElement();
        // 得到根元素的所有子节点

        @SuppressWarnings("unchecked")
        List<Element> elementList = root.elements();

        // 遍历所有子节点
        for (Element e : elementList) {
            map.put(e.getName(), e.getText());
        }
        // 释放资源
        inputStream.close();
        inputStream = null;
        return map;
    }

    /**
     * 文本消息对象转换成xml
     *
     * @param textMessage 文本消息对象
     * @return xml
     */
    public static String textMessageToXml(TextMessage textMessage) {
        xstream.alias("xml", textMessage.getClass());
        return xstream.toXML(textMessage);
    }

    /**
     * 扩展xstream,使其支持CDATA块
     *
     */
    private static XStream xstream = new XStream(new XppDriver() {

        @Override
        public HierarchicalStreamWriter createWriter(Writer out) {
            return new PrettyPrintWriter(out) {
                // 对所有xml节点的转换都增加CDATA标记
                boolean cdata = true;
                @Override
                protected void writeText(QuickWriter writer, String text) {
                    if (cdata) {
                        writer.write("<![CDATA[");
                        writer.write(text);
                        writer.write("]]>");
                    } else {
                        writer.write(text);
                    }
                }
            };
        }
    });


}

3-1-2:判断用户操作指令,是动作事情节点还是文本信息

package com.dx.common.enums;


import lombok.Getter;

@Getter
public enum WxMessageType {
    /**
     * 事件类型,比如订阅与取消订阅
     */
    EVENT("event"),
    /**
     * 向公众号发送的文字消息
     */
    TEXT("text");
    private String code;

    WxMessageType(String code) {
        this.code = code;
    }

}
package com.dx.common.enums;

import lombok.Getter;

@Getter
public enum WxEeventType {
    /**
     * 关注公众号
     */
    SUBSCRIBE("subscribe"),
    /**
     * 取消关注公众号
     */
    UNSUBSCRIBE("unsubscribe");

    private String code;

    WxEeventType(String code) {
        this.code = code;
    }
}

3-1-3:如果是关注指定,我们就去获取用户信息,获取用户的基本信息,又需要access_token参数和openId参数,上面已经获取到openId参数,

// 发送方帐号(open_id)
String openid = requestMap.get("FromUserName");

所以我们只需要准备 access_token,这里我就简单获取一下参数,实际业务中需要定时去获取一下然后放在缓存里比较好,这样可以有效的保证access_token

// 获取接口调用凭证
String accessTokenStr = "https://api.weixin.qq.com/cgi-bin/token?" +
         "grant_type=client_credential" + "&appid=" + "wxXXXX" + "&secret=" + "f977af825f980dc13XXXXXXXXXXX";
String tokenStr = HttpUtil.get(accessTokenStr);
JSONObject object = JSONUtil.parseObj(tokenStr);
String accessToken = object.get("access_token").toString();

 1、需要参数appid和secret,同时设置IP白名单,即可调用获取

 2、HttpUtil使用的是hutool

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.5.9</version>
</dependency>

3、构建获取用户的基本信息 

// 构建获取用户的基本信息
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);
JSONObject jsonObject = JSONUtil.parseObj(wxUserString);

JSONObject就是用户的基本信息了包括昵称,头像,地址等

3-2:用户如果发送文本信息则进行回复

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();
}

3-2-1:准备TextMessage实体类,注意实体类首字母大写

package com.dx.common.domain;

import lombok.Data;

/**
 * TextMessage
 *
 * @Description:
 * @Author: bb
 * @Date: 2022-08-19
 * @Version: V1.0.0
 */
@Data
public class TextMessage {
    /**
     * 开发者微信号
     */
    private String ToUserName;
    /**
     * 发送方账号
     */
    private String FromUserName;
    /**
     * 创建时间
     */
    private Long CreateTime;

    /**
     * 消息类型
     */
    private String MsgType;

    /**
     * 消息文本
     */
    private String Content;




}

3-2-2:根据用户输入的内容进行自定义回复

 

  • 0
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
根据提供的引用内容,Java代码中的getopenid方法是用于获取微信公众号openid的。该方法接收一个名为code的参数,通过调用微信API来获取openid。具体的步骤如下: 1. 首先,需要设置公众号的appid和secret。 2. 然后,设置响应头,允许跨域请求。 3. 构建微信登录的URL,包括appid、secret、code和授权类型等参数。 4. 发送GET请求到微信登录URL,获取返回的JSON字符串。 5. 解析JSON字符串,提取其中的openid字段作为结果。 6. 最后,将openid返回。 根据提供的代码,无法确定具体的错误原因。但是根据错误代码40029,这可能是由于code参数无效或过期导致的。建议检查传递给getopenid方法的code参数是否正确,并确保它是最新的。 请注意,以上回答是基于提供的引用内容,可能不完整或有遗漏。如果需要更详细的帮助,请提供更多相关的代码或信息。 #### 引用[.reference_title] - *1* *2* [微信公众号获取openidjava后端+html实现)](https://blog.csdn.net/weixin_43767744/article/details/121747536)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [微信公众号根据openid获取unionid](https://blog.csdn.net/qq_39418742/article/details/126197895)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值