likes
comments
collection
share

Spring Boot 对接微信公众号

作者站长头像
站长
· 阅读数 11

下面是Spring Boot 对接微信公众号开发的通用教程,包含了对接的步骤流程和示例代码。

1. 准备工作

在开始对接微信公众号之前,我们需要先准备好以下工作:

  • 一个微信公众号,可以在微信公众平台注册。
  • 一个服务器,用于接收和处理微信服务器推送的消息,同时可以响应微信用户的请求。
  • 配置服务器的域名和端口,确保可以通过公网访问。
  • 了解微信公众号开发的基本流程和要求,包括验证服务器、接收消息和响应消息等。

2. 配置微信公众号

在微信公众平台上,我们需要进行以下配置:

2.1 配置服务器地址

在开发 -> 基本配置 中,将服务器地址设置为我们的服务器地址。在设置之前,需要确保服务器已经可以通过公网访问,并且端口没有被防火墙或路由器等设备阻挡。

2.2 配置开发者模式

在开发 -> 基本配置 中,启用开发者模式,并填写服务器地址。启用开发者模式后,微信服务器会向服务器发送一个 GET 请求,用于验证服务器身份。在服务器收到请求后,需要按照微信要求返回 echostr 参数的值,用于验证服务器身份。

2.3 配置公众号菜单

在开发 -> 自定义菜单 中,设置公众号菜单。公众号菜单是用户与公众号交互的主要方式之一,需要根据实际需求设置相应的菜单项和功能。

3. 开发微信公众号

3.1 集成 Spring Boot

在开发微信公众号之前,我们需要先集成 Spring Boot 框架,用于快速构建和部署应用。在 pom.xml 文件中,添加以下依赖:

xmlCopy code
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

3.2 接收和处理微信服务器推送的消息

在接收和处理微信服务器推送的消息时,我们需要实现一个微信消息处理器,用于接收消息并处理。在 Spring Boot 中,可以使用 @RestController 和 @PostMapping 注解来实现。

javaCopy code
@RestController
public class WeChatController {

    @PostMapping("/wechat")
    public String handleRequest(HttpServletRequest request) {
        // 解析微信服务器推送的消息
        String xml = readRequestBody(request);
        Map<String, String> message = parseMessage(xml);

        // 处理消息
        String response = handleMessage(message);

        return response;
    }

    // 读取请求体
    private String readRequestBody(HttpServletRequest request) {
        try {
            BufferedReader reader = request.getReader();
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            return sb.toString();
        } catch (Exception e) {
            throw new RuntimeException("Failed to read request body", e);
        }
    }

    // 解析微信消息
    private Map<String, String> parseMessage(String xml) {
        try {
            Document doc = DocumentHelper.parseText(xml);
            Element root = doc.getRootElement();
            Map<String, String> message = new HashMap<>();
            for (Iterator<Element> it = root.elementIterator(); it.hasNext(); ) {
                Element element = it.next();
                message.put(element.getName(), element.getText());
            }
            return message;
        } catch (Exception e) {
            throw new RuntimeException("Failed to parse message", e);
        }
    }

    // 处理微信消息
    private String handleMessage(Map<String, String> message) {
        String msgType = message.get("MsgType");
        String content = message.get("Content");
        if ("text".equals(msgType)) {
            if ("hello".equals(content)) {
                return buildTextResponse(message, "Hello, world!");
            } else {
                return buildTextResponse(message, "You said: " + content);
            }
        } else if ("event".equals(msgType)) {
            String event = message.get("Event");
            if ("subscribe".equals(event)) {
                return buildTextResponse(message, "Welcome to our official account!");
            } else {
                return buildTextResponse(message, "Unknown event: " + event);
            }
        } else {
            return buildTextResponse(message, "Unknown message type: " + msgType);
        }
    }

    // 构造文本消息响应
    private String buildTextResponse(Map<String, String> message, String content) {
        String fromUserName = message.get("ToUserName");
        String toUserName = message.get("FromUserName");
        String createTime = String.valueOf(System.currentTimeMillis() / 1000);
        String msgType = "text";
        String xml = "<xml>";
        xml += "<ToUserName><![CDATA[" + toUserName + "]]></ToUserName>";
        xml += "<FromUserName><![CDATA[" + fromUserName + "]]></FromUserName>";
        xml += "<CreateTime>" + createTime + "</CreateTime>";
        xml += "<MsgType><![CDATA[" + msgType + "]]></MsgType>";
        xml += "<Content><![CDATA[" + content + "]]></Content>";
        xml += "</xml>";
        return xml;
    }
}

上述代码实现了一个简单的微信公众号消息处理器,用于接收和处理微信服务器推送的消息。当微信服务器向我们的服务器推送消息时,我们将通过 @PostMapping 注解定义的 /wechat 路径接收请求,并在 handleRequest 方法中对消息进行解析和处理,最终返回响应给微信服务器。

其中,readRequestBody 方法用于读取请求体,我们将从请求体中读取 XML 格式的消息内容,用于后续的消息解析和处理。

javaCopy code
// 读取请求体
private String readRequestBody(HttpServletRequest request) {
    try {
        BufferedReader reader = request.getReader();
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
        return sb.toString();
    } catch (Exception e) {
        throw new RuntimeException("Failed to read request body", e);
    }
}

parseMessage 方法用于解析微信服务器推送的消息,将 XML 格式的消息转换为 Map 对象。

javaCopy code
// 解析微信消息
private Map<String, String> parseMessage(String xml) {
    try {
        Document doc = DocumentHelper.parseText(xml);
        Element root = doc.getRootElement();
        Map<String, String> message = new HashMap<>();
        for (Iterator<Element> it = root.elementIterator(); it.hasNext(); ) {
            Element element = it.next();
            message.put(element.getName(), element.getText());
        }
        return message;
    } catch (Exception e) {
        throw new RuntimeException("Failed to parse message", e);
    }
}

上述代码使用了 DOM4J 解析 XML,通过解析 XML 根元素,我们将每个子元素的名称和文本内容都存储到 Map 对象中,用于后续的消息处理。

现在,我们已经完成了一个基本的微信公众号消息处理器,可以接收和处理微信服务器推送的消息,并返回响应给微信服务器。接下来,我们将进一步完善这个处理器,添加微信公众号的常用功能。

下面是一些常用的功能,可以根据需求自由添加。

自动回复

自动回复是微信公众号最基本的功能之一,可以根据用户发送的关键词或者特定事件自动回复消息。

javaCopy code
private String handleAutoReply(Map<String, String> message) {
    String content = message.get("Content");
    if ("hello".equalsIgnoreCase(content)) {
        return replyTextMessage(message, "你好,欢迎关注我的公众号!");
    } else {
        return replyTextMessage(message, "我听不懂你在说什么,请输入 hello 来和我打个招呼吧!");
    }
}

上述代码实现了一个简单的自动回复功能,如果用户发送的是 "hello",则回复 "你好,欢迎关注我的公众号!",否则回复 "我听不懂你在说什么,请输入 hello 来和我打个招呼吧!"。

图文消息

图文消息是微信公众号中常用的消息类型之一,可以在公众号中展示文章或者产品信息等。

javaCopy code
private String handleNewsMessage(Map<String, String> message) {
    List<Article> articles = new ArrayList<>();
    Article article1 = new Article();
    article1.setTitle("我是第一篇文章");
    article1.setDescription("这是第一篇文章的描述");
    article1.setPicUrl("https://picsum.photos/200");
    article1.setUrl("https://www.baidu.com");
    articles.add(article1);

    Article article2 = new Article();
    article2.setTitle("我是第二篇文章");
    article2.setDescription("这是第二篇文章的描述");
    article2.setPicUrl("https://picsum.photos/200");
    article2.setUrl("https://www.google.com");
    articles.add(article2);

    return replyNewsMessage(message, articles);
}

上述代码实现了一个简单的图文消息功能,发送两篇文章的标题、描述、图片和链接。

菜单

菜单是微信公众号中常用的功能之一,可以在公众号中设置自定义菜单,方便用户访问和使用公众号中的功能。

javaCopy code
private String handleMenuEvent(Map<String, String> message) {
    String event = message.get("Event");
    if ("CLICK".equals(event)) {
        String key = message.get("EventKey");
        if ("menu1".equals(key)) {
            return replyTextMessage(message, "你点击了菜单一");
        } else if ("menu2".equals(key)) {
            return replyTextMessage(message, "你点击了菜单二");
        }
    }
    return "";
}

上述代码实现了一个简单的菜单功能,当用户点击菜单一或菜单二时,会回复相应的文本消息。

获取用户信息

获取用户信息是微信公众号中常用的功能之一,可以通过用户授权的方式获取用户的基本信息。

首先,需要在微信公众平台中创建一个网页授权获取用户基本信息的应用,获取到 appid 和 appsecret。然后,需要在代码中添加一个获取用户授权的接口,获取用户的 openid

javaCopy code
// 获取用户授权页面
@GetMapping("/authorize")
public String authorize(@RequestParam("redirect_uri") String redirectUri,
                        @RequestParam("state") String state) {
    String url = "https://open.weixin.qq.com/connect/oauth2/authorize" +
            "?appid=" + APPID +
            "&redirect_uri=" + URLEncoder.encode(redirectUri) +
            "&response_type=code" +
            "&scope=snsapi_base" +
            "&state=" + state +
            "#wechat_redirect";
    return "redirect:" + url;
}

// 授权回调页面
@GetMapping("/callback")
public String callback(@RequestParam("code") String code,
                       @RequestParam("state") String state) {
    String url = "https://api.weixin.qq.com/sns/oauth2/access_token" +
            "?appid=" + APPID +
            "&secret=" + APPSECRET +
            "&code=" + code +
            "&grant_type=authorization_code";
    String result = restTemplate.getForObject(url, String.class);
    Map<String, String> resultMap = JsonUtils.fromJson(result, Map.class);
    String openid = resultMap.get("openid");
    // TODO: 根据 openid 获取用户信息
    return "redirect:" + state;
}

上述代码中,authorize 方法用于生成用户授权页面的链接,callback 方法用于处理用户授权后的回调页面,获取用户的 openid

接下来,可以根据用户的 openid 获取用户的基本信息。需要注意的是,需要先通过微信公众平台中的高级接口设置获取用户基本信息的权限。

javaCopy code
private String handleUserinfoEvent(Map<String, String> message) {
    String event = message.get("Event");
    if ("CLICK".equals(event)) {
        String key = message.get("EventKey");
        if ("userinfo".equals(key)) {
            String openid = message.get("FromUserName");
            String url = "https://api.weixin.qq.com/cgi-bin/user/info" +
                    "?access_token=" + accessToken +
                    "&openid=" + openid +
                    "&lang=zh_CN";
            String result = restTemplate.getForObject(url, String.class);
            // TODO: 处理用户信息
            return replyTextMessage(message, result);
        }
    }
    return "";
}

上述代码中,handleUserinfoEvent 方法用于处理点击获取用户信息菜单时的逻辑。首先,从消息中获取用户的 openid,然后调用微信公众平台的接口获取用户信息。

以上就是一些常用的微信公众号功能,可以根据需求自由添加。在这个教程中,我们使用了 Spring Boot 来开发微信公众号应用。我们学习了如何与微信服务器建立消息交互,如何对接微信公众号的常用功能,以及如何获取用户授权和用户信息。这个教程只是一个基础入门,实际的微信公众号应用开发中还有很多细节需要考虑。如果您想深入学习微信公众号的开发,可以查阅微信公众平台的开发文档,或者参考一些开源的微信公众号框架。总之,希望这个教程能对您有所帮助,祝您在微信公众号开发中取得成功!