杰瑞科技汇

Java微信公众台开发怎么入门?

Java微信公众平台开发全教程

准备工作:开发者资质与工具

在开始编码之前,你需要完成以下准备工作:

Java微信公众台开发怎么入门?-图1
(图片来源网络,侵删)
  1. 一个公众号

    • 订阅号:适合个人或媒体,主要用于信息传播和用户互动,接口权限较少,但认证后可以获得高级接口。
    • 服务号:适合企业和组织,能提供更多高级接口(如微信支付、模板消息等),每月可群发4次消息。
    • 测试号:微信官方提供的测试环境,拥有大部分接口权限,非常适合开发者进行学习和测试。推荐新手从测试号开始,地址:微信公众平台测试号申请入口
  2. 开发环境

    • JDK: 建议使用 JDK 8 或更高版本。
    • IDE: IntelliJ IDEA 或 Eclipse。
    • Web服务器: Tomcat (推荐) 或 Jetty。
    • 项目管理工具: Maven 或 Gradle。
    • API调试工具: Postman 或 Apifox。
    • 抓包工具: Fiddler 或 Charles (用于调试网络请求)。
  3. 获取开发者凭证

    • 登录你的公众号(或测试号)后台,在“开发” -> “基本配置”中,你可以看到:
      • AppID (开发者ID): 公众号的唯一标识。
      • AppSecret (开发者密码): 与AppID配对使用,用于获取access_token,务必保密

核心概念与原理

理解微信的通信原理是开发的第一步。

Java微信公众台开发怎么入门?-图2
(图片来源网络,侵删)
  1. 服务器配置 你需要将你的公网服务器地址(http://yourdomain.com/wechat)配置到公众号后台,微信服务器会向这个地址发送请求,你的Java应用需要在这个地址上提供一个接口来接收和响应。

  2. 接入验证 (Token验证) 当你首次提交服务器配置时,微信服务器会向你配置的URL发送一个GET请求,以验证你服务器的所有权,请求包含以下参数:

    • signature: 微信加密签名
    • timestamp: 时间戳
    • nonce: 随机数
    • echostr: 随机字符串

    你的服务器需要做三件事来响应这个请求:

    1. 获取你自己在公众号后台填写的 Token (这个Token可以任意填写,如 MyWechatToken)。
    2. Tokentimestampnonce 三个参数进行字典序排序。
    3. 将排序后的三个参数字符串拼接成一个字符串,并进行 SHA1 加密。
    4. 将加密后的字符串与 signature 进行对比。
    5. 如果一致,则说明请求来自微信,原样返回 echostr 参数内容;如果不一致,则返回错误。
  3. 消息交互流程 用户在公众号中发送消息后,微信服务器会将该消息以XML格式POST到你配置的服务器URL上,你的Java应用解析XML,根据消息类型(文本、图片、事件等)进行处理,然后将处理结果以XML格式返回给微信服务器,最后由微信服务器将结果推送给用户。

    Java微信公众台开发怎么入门?-图3
    (图片来源网络,侵删)

第一个Java程序:接入验证

我们将使用 Spring Boot 来快速搭建项目,因为它极大地简化了Web应用的开发。

创建Spring Boot项目

使用 Spring Initializr 创建一个新项目,添加以下依赖:

  • Spring Web: 用于创建Web接口。
  • Lombok: 简化Java代码。

编写Controller

创建一个 WeChatController 类来处理来自微信服务器的请求。

package com.example.wechatdemo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@RestController
@RequestMapping("/wechat")
public class WeChatController {
    // 在公众号后台配置的Token
    private static final String TOKEN = "MyWechatToken";
    /**
     * 处理微信服务器的GET请求(接入验证)
     * @param signature 微信加密签名
     * @param timestamp 时间戳
     * @param nonce 随机数
     * @param echostr 随机字符串
     * @return echostr
     */
    @GetMapping
    public String verify(
            @RequestParam("signature") String signature,
            @RequestParam("timestamp") String timestamp,
            @RequestParam("nonce") String nonce,
            @RequestParam("echostr") String echostr) {
        // 1. 将token, timestamp, nonce三个参数进行字典序排序
        List<String> params = Arrays.asList(TOKEN, timestamp, nonce);
        Collections.sort(params);
        // 2. 将三个参数字符串拼接成一个字符串进行sha1加密
        StringBuilder sb = new StringBuilder();
        for (String param : params) {
            sb.append(param);
        }
        String plain = sb.toString();
        String encrypted = sha1(plain);
        // 3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
        if (encrypted.equals(signature)) {
            return echostr; // 验证成功,返回echostr
        } else {
            return "fail"; // 验证失败
        }
    }
    /**
     * SHA1加密方法
     */
    private String sha1(String str) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] digest = md.digest(str.getBytes());
            StringBuilder hexStr = new StringBuilder();
            for (byte b : digest) {
                String shaHex = Integer.toHexString(b & 0xFF);
                if (shaHex.length() < 2) {
                    hexStr.append(0);
                }
                hexStr.append(shaHex);
            }
            return hexStr.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }
}

运行与配置

  • 运行你的Spring Boot应用。
  • 在本地,使用工具(如ngrok)将你的本地服务器端口(如8080)映射到公网。ngrok http 8080,它会给你一个类似 https://xxx.ngrok.io 的公网地址。
  • 登录微信测试号后台,在“接口配置信息”中填写:
    • URL: https://xxx.ngrok.io/wechat (你ngrok的地址 + 项目路径)
    • Token: MyWechatToken (与代码中定义的TOKEN一致)
    • 消息加解密方式: 明文模式(推荐新手使用)
  • 点击“提交”,如果提示“成功”,恭喜你,服务器已经成功接入!

接收和回复用户消息

现在我们来处理用户发送的消息。

接收消息

修改 WeChatController,添加一个 @PostMapping 方法来接收微信服务器POST过来的XML消息。

// ... (前面的代码保持不变)
import org.springframework.web.bind.annotation.PostMapping;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.io.StringBufferInputStream;
import java.io.IOException;
@RestController
@RequestMapping("/wechat")
public class WeChatController {
    // ... (前面的 verify 方法保持不变)
    /**
     * 处理微信服务器的POST请求(接收用户消息)
     * @param requestBody 微信服务器发来的XML格式的消息体
     * @return 回复给用户的XML字符串
     */
    @PostMapping(produces = "application/xml;charset=UTF-8")
    public String handleWeChatMessage(@RequestBody String requestBody) {
        System.out.println("收到消息: " + requestBody);
        try {
            // 解析XML
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(new StringBufferInputStream(requestBody));
            Element root = doc.getDocumentElement();
            String fromUserName = getElementText(root, "FromUserName"); // 发送者OpenID
            String toUserName = getElementText(root, "ToUserName");     // 公众号原始ID
            String msgType = getElementText(root, "MsgType");           // 消息类型
            String content = getElementText(root, "Content");           // 文本消息内容
            // 根据消息类型处理
            if ("text".equals(msgType)) {
                // 回复用户发送的内容
                String replyContent = "你发送的是: " + content;
                return buildTextReplyXml(fromUserName, toUserName, replyContent);
            } else if ("event".equals(msgType)) {
                // 处理事件推送,如关注、点击菜单等
                String event = getElementText(root, "Event");
                if ("subscribe".equals(event)) {
                    // 用户关注事件
                    return buildTextReplyXml(fromUserName, toUserName, "感谢关注!");
                }
            }
            // 其他消息类型暂不处理
            return "";
        } catch (ParserConfigurationException | SAXException | IOException e) {
            e.printStackTrace();
            return ""; // 发生错误,返回空
        }
    }
    // 辅助方法:从XML元素中获取标签文本内容
    private String getElementText(Element parent, String tagName) {
        NodeList nodes = parent.getElementsByTagName(tagName);
        if (nodes.getLength() > 0) {
            Node node = nodes.item(0);
            return node.getTextContent();
        }
        return "";
    }
    /**
     * 构造回复文本消息的XML
     * @param toUser 接收者用户名
     * @param fromUser 发送者公众号
     * @param content 回复内容
     * @return XML字符串
     */
    private String buildTextReplyXml(String toUser, String fromUser, String content) {
        return "<xml>" +
                "<ToUserName><![CDATA[" + toUser + "]]></ToUserName>" +
                "<FromUserName><![CDATA[" + fromUser + "]]></FromUserName>" +
                "<CreateTime>" + System.currentTimeMillis() / 1000 + "</CreateTime>" +
                "<MsgType><![CDATA[text]]></MsgType>" +
                "<Content><![CDATA[" + content + "]]></Content>" +
                "</xml>";
    }
}

测试消息回复

重新启动你的应用,在微信测试号界面给你的测试号发送一条文本消息,如果一切正常,你的服务器控制台会打印出收到的XML消息,并且你的微信会收到自动回复。


使用SDK简化开发

手动解析XML和构建响应非常繁琐,社区中有很多成熟的Java SDK可以帮助我们简化开发,Weixin Java MP (WeixinMP)

添加依赖

在你的 pom.xml 中添加:

<dependency>
    <groupId>me.chanjar</groupId>
    <artifactId>weixin-java-mp</artifactId>
    <version>4.4.0</version> <!-- 请使用最新版本 -->
</dependency>

重构代码使用SDK

使用SDK后,代码会简洁很多。

package com.example.wechatdemo.controller;
import me.chanjar.weixin.mp.api.WxMpMessageHandler;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@RestController
@RequestMapping("/wechat")
public class WeChatControllerWithSDK {
    private static final String TOKEN = "MyWechatToken";
    private final WxMpService wxMpService = new WxMpServiceImpl();
    // 初始化消息路由器
    public WeChatControllerWithSDK() {
        WxMpMessageRouter router = new WxMpMessageRouter(wxMpService);
        // 文本消息处理器
        router.rule()
                .async(false)
                .msgType("text")
                .handler(new WxMpMessageHandler() {
                    @Override
                    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage) throws Exception {
                        String content = wxMessage.getContent();
                        return WxMpXmlOutMessage.TEXT()
                                .content("你发送的是: " + content)
                                .fromUser(wxMessage.getToUser())
                                .toUser(wxMessage.getFromUser())
                                .build();
                    }
                })
                .end();
        // 关注事件处理器
        router.rule()
                .async(false)
                .msgType("event")
                .event("subscribe")
                .handler(new WxMpMessageHandler() {
                    @Override
                    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage) throws Exception {
                        return WxMpXmlOutMessage.TEXT()
                                .content("感谢关注!")
                                .fromUser(wxMessage.getToUser())
                                .toUser(wxMessage.getFromUser())
                                .build();
                    }
                })
                .end();
        // 将配置好的路由器设置到Service中
        wxMpService.setWxMpMessageRouter(router);
    }
    @GetMapping
    public String verify(
            @RequestParam("signature") String signature,
            @RequestParam("timestamp") String timestamp,
            @RequestParam("nonce") String nonce,
            @RequestParam("echostr") String echostr) {
        // SDK提供了校验方法
        if (!wxMpService.checkSignature(timestamp, nonce, signature)) {
            return "fail";
        }
        return echostr;
    }
    @PostMapping(produces = "application/xml;charset=UTF-8")
    public String handleWeChatMessage(@RequestBody String requestBody) {
        // SDK提供了消息解析和路由处理方法
        return wxMpService.getWxMpMessageRouter().route(requestBody);
    }
}

对比一下,使用SDK后,我们只需要关注具体的业务逻辑(如何回复),而底层的XML解析、路由分发、签名校验等都由SDK帮我们完成了。


高级功能介绍

完成基础交互后,你可以探索更多高级功能:

  1. 获取Access Token

    • 作用: 调用绝大多数微信接口的“通行证”,有效期为2小时,需要定时刷新并缓存。
    • 方法: 使用SDK提供的 WxMpService.getAccessToken() 方法,它会自动处理获取和刷新逻辑。
  2. 自定义菜单

    • 作用: 在公众号界面底部创建自定义按钮,点击可触发事件或跳转链接。
    • 实现: 调用 menu_create 接口,使用SDK可以很方便地构建菜单JSON并提交。
  3. 模板消息

    • 作用: 服务号在特定场景下(如订单支付成功)向用户发送重要的服务通知。
    • 实现: 需要先在公众号后台设计模板,然后调用 template_send 接口,将用户数据和模板ID一起发送。
  4. 网页授权 (OAuth2.0)

    • 作用: 获取用户的 OpenID 和基本信息(需用户同意),用于实现微信登录、获取用户地理位置等功能。
    • 流程:
      1. 用户点击链接,重定向到微信授权页面。
      2. 用户同意授权。
      3. 微信重定向回你指定的回调URL,并携带 code
      4. 你的服务用 code 去换取 access_tokenopenid
  5. 微信支付

    • 作用: 在公众号内发起支付。
    • 实现: 这是一个非常复杂的功能,涉及证书、签名、回调处理等,强烈建议仔细阅读官方文档,并使用SDK中的支付相关模块。

部署与最佳实践

  1. 服务器: 部署到云服务器(如阿里云、腾讯云),确保公网IP和域名解析正常。
  2. HTTPS: 微信所有接口都要求使用 https,你需要为你的域名申请并安装SSL证书。
  3. 代码安全: 绝对不要AppSecret 硬编码在代码中,应该使用配置文件(如 application.yml)或环境变量来管理。
  4. 日志: 记录详细的请求和响应日志,对于排查问题至关重要。
  5. 性能: Access Token需要缓存,避免频繁请求微信服务器导致限频,可以使用Redis等缓存工具。
  6. 异常处理: 做好健壮的异常处理,防止因网络抖动或微信服务器问题导致应用崩溃。

总结与资源

  • 官方文档: 微信公众平台开发者文档,这是最重要的参考资料,没有之一。
  • Weixin Java MP SDK: GitHub仓库,文档和示例非常丰富。
  • 持续学习: 微信的接口和规则在不断更新,要养成经常查看官方文档和更新SDK的习惯。

这份教程为你铺开了一条Java微信开发的清晰路径,从最基础的接入验证,到消息的收发,再到使用SDK简化开发,最后介绍了高级功能和最佳实践,动手实践是掌握技术的最快方式,祝你开发顺利!

分享:
扫描分享到社交APP
上一篇
下一篇