Java微信公众平台开发全教程
准备工作:开发者资质与工具
在开始编码之前,你需要完成以下准备工作:

-
一个公众号
- 订阅号:适合个人或媒体,主要用于信息传播和用户互动,接口权限较少,但认证后可以获得高级接口。
- 服务号:适合企业和组织,能提供更多高级接口(如微信支付、模板消息等),每月可群发4次消息。
- 测试号:微信官方提供的测试环境,拥有大部分接口权限,非常适合开发者进行学习和测试。推荐新手从测试号开始,地址:微信公众平台测试号申请入口
-
开发环境
- JDK: 建议使用 JDK 8 或更高版本。
- IDE: IntelliJ IDEA 或 Eclipse。
- Web服务器: Tomcat (推荐) 或 Jetty。
- 项目管理工具: Maven 或 Gradle。
- API调试工具: Postman 或 Apifox。
- 抓包工具: Fiddler 或 Charles (用于调试网络请求)。
-
获取开发者凭证
- 登录你的公众号(或测试号)后台,在“开发” -> “基本配置”中,你可以看到:
- AppID (开发者ID): 公众号的唯一标识。
- AppSecret (开发者密码): 与AppID配对使用,用于获取access_token,务必保密。
- 登录你的公众号(或测试号)后台,在“开发” -> “基本配置”中,你可以看到:
核心概念与原理
理解微信的通信原理是开发的第一步。

-
服务器配置 你需要将你的公网服务器地址(
http://yourdomain.com/wechat)配置到公众号后台,微信服务器会向这个地址发送请求,你的Java应用需要在这个地址上提供一个接口来接收和响应。 -
接入验证 (Token验证) 当你首次提交服务器配置时,微信服务器会向你配置的URL发送一个GET请求,以验证你服务器的所有权,请求包含以下参数:
signature: 微信加密签名timestamp: 时间戳nonce: 随机数echostr: 随机字符串
你的服务器需要做三件事来响应这个请求:
- 获取你自己在公众号后台填写的
Token(这个Token可以任意填写,如MyWechatToken)。 - 将
Token、timestamp、nonce三个参数进行字典序排序。 - 将排序后的三个参数字符串拼接成一个字符串,并进行 SHA1 加密。
- 将加密后的字符串与
signature进行对比。 - 如果一致,则说明请求来自微信,原样返回
echostr参数内容;如果不一致,则返回错误。
-
消息交互流程 用户在公众号中发送消息后,微信服务器会将该消息以XML格式POST到你配置的服务器URL上,你的Java应用解析XML,根据消息类型(文本、图片、事件等)进行处理,然后将处理结果以XML格式返回给微信服务器,最后由微信服务器将结果推送给用户。
(图片来源网络,侵删)
第一个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一致) - 消息加解密方式: 明文模式(推荐新手使用)
- URL:
- 点击“提交”,如果提示“成功”,恭喜你,服务器已经成功接入!
接收和回复用户消息
现在我们来处理用户发送的消息。
接收消息
修改 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帮我们完成了。
高级功能介绍
完成基础交互后,你可以探索更多高级功能:
-
获取Access Token
- 作用: 调用绝大多数微信接口的“通行证”,有效期为2小时,需要定时刷新并缓存。
- 方法: 使用SDK提供的
WxMpService.getAccessToken()方法,它会自动处理获取和刷新逻辑。
-
自定义菜单
- 作用: 在公众号界面底部创建自定义按钮,点击可触发事件或跳转链接。
- 实现: 调用
menu_create接口,使用SDK可以很方便地构建菜单JSON并提交。
-
模板消息
- 作用: 服务号在特定场景下(如订单支付成功)向用户发送重要的服务通知。
- 实现: 需要先在公众号后台设计模板,然后调用
template_send接口,将用户数据和模板ID一起发送。
-
网页授权 (OAuth2.0)
- 作用: 获取用户的
OpenID和基本信息(需用户同意),用于实现微信登录、获取用户地理位置等功能。 - 流程:
- 用户点击链接,重定向到微信授权页面。
- 用户同意授权。
- 微信重定向回你指定的回调URL,并携带
code。 - 你的服务用
code去换取access_token和openid。
- 作用: 获取用户的
-
微信支付
- 作用: 在公众号内发起支付。
- 实现: 这是一个非常复杂的功能,涉及证书、签名、回调处理等,强烈建议仔细阅读官方文档,并使用SDK中的支付相关模块。
部署与最佳实践
- 服务器: 部署到云服务器(如阿里云、腾讯云),确保公网IP和域名解析正常。
- HTTPS: 微信所有接口都要求使用
https,你需要为你的域名申请并安装SSL证书。 - 代码安全: 绝对不要将
AppSecret硬编码在代码中,应该使用配置文件(如application.yml)或环境变量来管理。 - 日志: 记录详细的请求和响应日志,对于排查问题至关重要。
- 性能: Access Token需要缓存,避免频繁请求微信服务器导致限频,可以使用Redis等缓存工具。
- 异常处理: 做好健壮的异常处理,防止因网络抖动或微信服务器问题导致应用崩溃。
总结与资源
- 官方文档: 微信公众平台开发者文档,这是最重要的参考资料,没有之一。
- Weixin Java MP SDK: GitHub仓库,文档和示例非常丰富。
- 持续学习: 微信的接口和规则在不断更新,要养成经常查看官方文档和更新SDK的习惯。
这份教程为你铺开了一条Java微信开发的清晰路径,从最基础的接入验证,到消息的收发,再到使用SDK简化开发,最后介绍了高级功能和最佳实践,动手实践是掌握技术的最快方式,祝你开发顺利!
