Java 开发微信公众平台完整教程
微信公众平台为开发者提供了丰富的接口,让我们可以构建强大的自定义服务,如自动回复、菜单管理、用户管理、模板消息等,本教程将手把手教你如何使用 Java (Spring Boot) 来开发一个微信公众号。

目录
-
第一部分:准备工作
- 1 注册并配置公众号
- 2 获取开发者凭证
- 3 配置服务器信息(服务器地址 & Token)
- 4 开发环境准备
-
第二部分:核心代码实现
- 1 创建 Spring Boot 项目
- 2 实现服务器验证(Token 验证)
- 3 接收和解析用户消息
- 4 实现自动回复
- 5 创建自定义菜单
- 6 发送模板消息
-
第三部分:部署与上线
- 1 准备服务器
- 2 使用 Nginx 反向代理
- 3 使用 HTTPS (必备)
- 4 部署应用
-
第四部分:进阶与总结
(图片来源网络,侵删)- 1 获取用户 OpenID
- 2 推荐使用成熟的 SDK
- 3 学习资源
第一部分:准备工作
在开始编码之前,我们必须完成微信官方的配置工作。
1 注册并配置公众号
- 访问 微信公众平台。
- 使用你的个人身份证号或企业资质进行注册,对于学习和开发,推荐注册 订阅号,流程相对简单。
- 登录后,在后台找到 “设置与开发” -> “基本配置”。
2 获取开发者凭证
在“基本配置”页面,你会看到:
- AppID (应用ID): 公众号的唯一标识。
- AppSecret (应用密钥): 用于获取 Access Token 的密钥,请务必保密。
3 配置服务器信息(服务器地址 & Token)
这是最关键的一步,它将你的公众号和你的后端服务连接起来。
-
在“基本配置”页面,点击 “配置” 按钮。
(图片来源网络,侵删) -
填写以下信息:
- URL (服务器地址): 你的 Java Web 应用对外访问的地址。
https://yourdomain.com/wechat。 - Token (令牌): 可以任意填写,如
myWechatToken123,这个 Token 将用于微信服务器验证你的身份。 - EncodingAESKey (消息加解密密钥): 可以随机生成,用于消息的安全传输,如果暂时不需要,可以留空。
- 消息加解密方式: 选择 “安全模式” 或 “兼容模式”,开发阶段可以选择“明文模式”,但生产环境务必选择安全模式。
- URL (服务器地址): 你的 Java Web 应用对外访问的地址。
-
点击 “提交”,微信服务器会向你的
URL发送一个GET请求,你需要编写代码来响应这个请求以完成验证,如果验证成功,配置才会生效。
4 开发环境准备
- JDK: 推荐 JDK 8 或更高版本。
- IDE: IntelliJ IDEA 或 Eclipse。
- 构建工具: Maven 或 Gradle。
- Web 框架: Spring Boot (强烈推荐,可以极大简化开发)。
- HTTP 客户端: 用于调用微信 API,如
OkHttp或Apache HttpClient。 - JSON 库: 如
Jackson或Gson。
第二部分:核心代码实现
我们将使用 Spring Boot 来快速搭建项目。
1 创建 Spring Boot 项目
- 访问 Spring Initializr。
- 填写项目信息:
- Project: Maven
- Language: Java
- Spring Boot: 选择一个稳定版本 (如 2.7.x 或 3.x.x)
- Project Metadata: Group, Artifact, Name 等。
- Dependencies: 添加
Spring Web。
- 点击 "Generate" 下载项目压缩包,并用 IDE 打开。
2 实现服务器验证(Token 验证)
当你在公众号后台提交 URL 时,微信服务器会发送如下格式的 GET 请求:
https://yourdomain.com/wechat?signature=ASDFGHJKL×tamp=1234567890&nonce=987654321&echostr=hello_world
你需要根据 signature, timestamp, nonce 和你在后台配置的 Token 来进行验证,验证逻辑如下:
- 将
Token,timestamp,nonce三个参数进行字典序排序。 - 将三个参数字符串拼接成一个字符串进行
SHA1加密。 - 将加密后的字符串与
signature对比,如果相同,则请求来自微信,返回echostr即可。
代码实现:
创建一个 Controller 来处理 /wechat 路径的请求。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
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 = "myWechatToken123";
@GetMapping
public void validate(HttpServletRequest request, HttpServletResponse response) throws IOException {
String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String echostr = request.getParameter("echostr");
if (isWeChatRequest(signature, timestamp, nonce)) {
// 验证成功,返回 echostr
response.getWriter().print(echostr);
} else {
// 验证失败
response.getWriter().print("Invalid request");
}
}
private boolean isWeChatRequest(String signature, String timestamp, String nonce) {
// 1. 将 token, timestamp, nonce 三个参数进行字典序排序
List<String> params = Arrays.asList(TOKEN, timestamp, nonce);
Collections.sort(params);
// 2. 将三个参数字符串拼接成一个字符串
String paramStr = String.join("", params);
// 3. 进行 SHA1 加密
String encryptedStr = sha1(paramStr);
// 4. 开发者获得加密后的字符串可与 signature 对比
return encryptedStr != null && encryptedStr.equals(signature);
}
private String sha1(String str) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
byte[] digestBytes = digest.digest(str.getBytes());
StringBuilder sb = new StringBuilder();
for (byte b : digestBytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
}
测试:
将你的项目运行起来,确保外网可以访问 https://yourdomain.com/wechat,然后在公众号后台点击“提交”,如果成功,说明服务器验证已经完成。
3 接收和解析用户消息
当用户与公众号互动时,微信服务器会向你的 URL 发送一个 POST 请求,请求体是 XML 格式的消息,我们需要创建一个接口来处理 POST 请求。
用户发送文本消息的 XML 示例:
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[this is a test]]></Content> <MsgId>1234567890123456</MsgId> </xml>
代码实现:
-
创建消息实体类:
import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class WeChatMessage { private String ToUserName; private String FromUserName; private long CreateTime; private String MsgType; private String Content; private long MsgId; // Getters and Setters... } -
修改 Controller 处理 POST 请求:
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; // ... imports ... @RestController @RequestMapping("/wechat") public class WeChatController { // ... GET 方法 ... @PostMapping public String handlePost(HttpServletRequest request) throws Exception { // 1. 获取请求体中的 XML 数据 String xmlData = IOUtils.toString(request.getInputStream(), "UTF-8"); // 2. 解析 XML Document document = DocumentHelper.parseText(xmlData); Element root = document.getRootElement(); String fromUser = root.element("FromUserName").getStringValue(); String toUser = root.element("ToUserName").getStringValue(); String msgType = root.element("MsgType").getStringValue(); String content = root.element("Content").getStringValue(); // 3. 根据消息类型处理 if ("text".equals(msgType)) { // 用户发送的是文本,进行回复 String replyContent = "你发送的是: " + content; return buildTextReply(toUser, fromUser, replyContent); } // 其他消息类型... return "success"; // 返回 success 表示微信服务器不再重发 } private String buildTextReply(String toUser, String fromUser, String content) { // 构造回复消息的 XML return String.format( "<xml>" + "<ToUserName><![CDATA[%s]]></ToUserName>" + "<FromUserName><![CDATA[%s]]></FromUserName>" + "<CreateTime>%d</CreateTime>" + "<MsgType><![CDATA[text]]></MsgType>" + "<Content><![CDATA[%s]]></Content>" + "</xml>", toUser, fromUser, System.currentTimeMillis() / 1000, content ); } }注意:这里使用了
dom4j或jackson来解析 XML 会更方便。
4 实现自动回复
上面的 handlePost 方法已经实现了最简单的文本自动回复,你可以根据 content 的内容,实现更复杂的逻辑,比如关键词回复、菜单点击回复等。
5 创建自定义菜单
自定义菜单不是通过接收消息来触发的,而是需要你主动调用微信的 API 来创建。
步骤:
- 获取
access_token。 - 调用创建菜单的 API。
获取 Access Token
access_token 是调用所有接口的凭证,有效期 2 小时,需要缓存起来。
import org.springframework.web.client.RestTemplate;
public class WeChatApiService {
private static final String APPID = "你的AppID";
private static final String APPSECRET = "你的AppSecret";
private static final String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
private RestTemplate restTemplate;
// 使用缓存存储 token,例如用 Caffeine 或 Guava Cache
// private Cache<String, String> tokenCache;
public String getAccessToken() {
// 1. 先从缓存中获取
// String token = tokenCache.getIfPresent("access_token");
// if (token != null) {
// return token;
// }
// 2. 缓存中没有,则调用接口获取
String url = String.format(TOKEN_URL, APPID, APPSECRET);
AccessTokenResponse response = restTemplate.getForObject(url, AccessTokenResponse.class);
// 3. 存入缓存
// tokenCache.put("access_token", response.getAccessToken());
return response.getAccessToken();
}
// 响应实体
public static class AccessTokenResponse {
private String access_token;
private int expires_in;
// getters and setters...
}
}
调用创建菜单 API
菜单的配置是一个复杂的 JSON 对象,你可以先在微信公众平台“自定义菜单”工具里生成好 JSON。
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
public void createMenu() {
String accessToken = getAccessToken();
String menuUrl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + accessToken;
// 菜单的 JSON 配置
String menuJson = "{...}"; // 你的菜单 JSON
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(menuJson, headers);
restTemplate.postForEntity(menuUrl, entity, String.class);
}
6 发送模板消息
模板消息用于在特定场景下向用户发送重要通知,如订单确认、物流更新等。
步骤:
- 在公众号后台“模板消息”中找到并选用模板。
- 获取用户的
openid。 - 调用发送模板消息 API。
API 调用示例:
public void sendTemplateMessage(String openid) {
String accessToken = getAccessToken();
String templateUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken;
// 构造请求体 JSON
String requestJson = String.format(
"{\"touser\":\"%s\",\"template_id\":\"你的模板ID\",\"data\":{\"first\":{\"value\":\"恭喜你购买成功!\"},\"keyword1\":{\"value\":\"20251228\"},\"keyword2\":{\"value\":\"88.88\"},\"remark\":{\"value\":\"欢迎再次购买!\"}}}",
openid
);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(requestJson, headers);
restTemplate.postForEntity(templateUrl, entity, String.class);
}
第三部分:部署与上线
你的应用需要部署在一个有公网 IP 的服务器上,并且支持 HTTPS。
1 准备服务器
- 云服务器: 阿里云、腾讯云、华为云等,选择一个你熟悉的。
- 系统: CentOS 或 Ubuntu。
- 环境: 安装 JDK, Maven, Git。
2 使用 Nginx 反向代理
直接将 Spring Boot 应用(默认 8080 端口)暴露给公网不安全,使用 Nginx 作为反向代理,可以隐藏后端端口,并实现负载均衡。
Nginx 配置示例 (/etc/nginx/conf.d/wechat.conf):
server {
listen 80;
server_name yourdomain.com; # 你的域名
location /wechat {
proxy_pass http://127.0.0.1:8080; # 代理到你的 Spring Boot 应用
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
3 使用 HTTPS (必备)
微信服务器要求你的回调 URL 必须是 https 开头的。
- 域名备案: 如果你的服务器在国内,域名必须先备案。
- 购买/申请 SSL 证书:
- 免费: Let's Encrypt (推荐)。
- 付费: 各大云服务商都提供。
- 配置 Nginx:
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /path/to/your/cert.pem; # 证书文件
ssl_certificate_key /path/to/your/cert.key; # 私钥文件
location /wechat {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
# 将 HTTP 请求重定向到 HTTPS
server {
listen 80;
server_name yourdomain.com;
return 301 https://$host$request_uri;
}
4 部署应用
- 将你的 Spring Boot 项目打包成 JAR 包:
mvn clean package。 - 将 JAR 文件上传到服务器。
- 使用
nohup命令让它在后台运行:nohup java -jar your-app.jar > app.log 2>&1 &
- 可以使用
supervisor或systemd来管理进程,实现开机自启和自动重启。
第四部分:进阶与总结
1 获取用户 OpenID
当用户关注公众号或与公众号交互时,消息中会包含 FromUserName,这个值就是用户的 OpenID,是用户在公众号下的唯一标识。请务必妥善保存,有了 OpenID,你才能给特定用户发送模板消息。
2 推荐使用成熟的 SDK
手动处理 XML、调用 API、管理 access_token 等过程非常繁琐,容易出错,强烈建议使用成熟的第三方 SDK,它们封装了所有细节。
- me.chanjar:weixin-java: (推荐) 功能非常全面,文档和社区都很好。
- WxJava: 另一个流行的 Java 微信开发 SDK。
使用 weixin-java 的示例:
<!-- Maven 依赖 -->
<dependency>
<groupId>me.chanjar</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>最新版本号</version>
</dependency>
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.WxMpMessageHandler;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
// 初始化 WxMpService
WxMpService wxMpService = new WxMpServiceImpl();
wxMpService.setWxMpConfigStorage(new WxMpInMemoryConfigStorage());
wxMpService.getWxMpConfigStorage().setAppid("yourAppId");
wxMpService.getWxMpConfigStorage().setSecret("yourAppSecret");
// 设置消息路由
WxMpMessageRouter router = new WxMpMessageRouter(wxMpService);
router.rule()
.msgType("text")
.content("你好")
.handler(new WxMpMessageHandler() {
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, WxMpService wxMpService) {
return WxMpXmlOutMessage.TEXT()
.content("你好,世界!")
.fromUser(wxMessage.getToUser())
.toUser(wxMessage.getFromUser())
.build();
}
})
.end();
// 在 Controller 中使用
@PostMapping("/wechat")
public String handlePost(@RequestBody String requestBody,
@RequestParam("signature") String signature,
@RequestParam("timestamp") String timestamp,
@RequestParam("nonce") String nonce,
@RequestParam("openid") String openid,
@RequestParam("encrypt_type") String encryptType) {
// WxMpMessageRouter 会自动处理验证和消息解密
return router.route(requestBody, signature, timestamp, nonce);
}
可以看到,使用 SDK 后,代码变得极其简洁和健壮。
3 学习资源
- 微信公众平台官方文档: 必看! 所有接口和规范的最终来源。
- WxJava 官方文档
- me.chanjar/weixin-java GitHub
开发微信公众号 Java 应用,核心流程是:
- 配置:在公众号后台配置服务器地址和 Token。
- 验证:编写代码响应微信的 GET 请求,完成服务器身份验证。
- 交互:编写代码处理微信的 POST 请求(用户消息),并构造 XML 格式的回复。
- 调用:通过获取
access_token,调用微信 API 实现菜单、模板消息等功能。 - 部署:将应用部署到公网服务器,并配置 HTTPS 和反向代理。
从手动实现开始,有助于理解底层原理,但在实际项目中,强烈推荐使用 WxJava 这样的 SDK 来提高开发效率和代码质量,祝你开发顺利!
