🧑 博主简介:CSDN博客专家 ,历代文学网 (PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可微信小程序搜索"历代文学 ")总架构师,
15年
工作经验,精通Java编程
,高并发设计
,Springboot和微服务
,熟悉Linux
,ESXI虚拟化
以及云原生Docker和K8s
,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。
技术合作 请加本人wx(注明来自csdn ):foreast_sea


在Java中对接微信公众号并向指定关注用户发送消息,主要依赖微信公众号的消息模板功能。以下是关键步骤和代码实现:
⚙️ 一、核心前提条件
- 公众号类型 :需服务号或认证后的订阅号(个人可用测试号)。
- 用户关注:目标用户必须已关注公众号。
- 获取用户OpenID:每个用户有唯一OpenID(通过网页授权或后台接口获取)。
- 消息模板 :在公众号后台申请模板消息,获取
template_id
。
🔧 二、开发步骤与Java代码实现
1. 服务器URL验证(首次配置必做)
微信通过GET请求验证服务器有效性,需实现校验逻辑:
java
@WebServlet("/wx")
public class WxServlet extends HttpServlet {
private static final String TOKEN = "your_token"; // 与公众号配置的Token一致
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String echostr = request.getParameter("echostr");
// 1. 排序并拼接Token、timestamp、nonce
String[] arr = {TOKEN, timestamp, nonce};
Arrays.sort(arr);
String concatStr = String.join("", arr);
// 2. SHA1加密
String sha1 = DigestUtils.sha1Hex(concatStr); // Apache Commons Codec
// 3. 校验签名
if (sha1.equals(signature)) {
response.getWriter().print(echostr); // 返回echostr表示验证成功
}
}
}
注意:需使用内网穿透工具(如cpolar、natapp)将本地服务暴露为公网URL,供微信访问。
2. 获取Access Token
调用微信API获取接口凭证(有效期2小时,需缓存):
java
public String getAccessToken() throws IOException {
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential"
+ "&appid=APPID&secret=APPSECRET"; // 替换为实际AppID和AppSecret
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(url)).build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
JSONObject json = new JSONObject(response.body());
return json.getString("access_token"); // 返回Token
}
优化:使用Redis缓存Token,避免频繁调用。
3. 发送模板消息
构造JSON请求体,调用微信消息接口:
java
public void sendTemplateMessage(String openid, String templateId) throws IOException {
// 1. 准备消息数据
Map<String, Object> data = new HashMap<>();
data.put("first", Map.of("value", "订单通知", "color", "#173177"));
data.put("orderNo", Map.of("value", "202408051234"));
data.put("status", Map.of("value", "已发货"));
// 2. 构造完整请求体
JSONObject body = new JSONObject();
body.put("touser", openid);
body.put("template_id", templateId);
body.put("url", "https://yourdomain.com/order"); // 用户点击跳转链接
body.put("data", data);
// 3. 调用接口
String apiUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + getAccessToken();
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body.toString()))
.build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
System.out.println("发送结果:" + response.body()); // 解析errcode判断成功与否
}
表:模板消息参数说明
参数 | 必填 | 说明 |
---|---|---|
touser |
是 | 用户OpenID(如oOM-e52ersdi7a4wZTOQHUQOwGuw ) |
template_id |
是 | 模板ID(如AYZc280-hh7QeO5eM8Usl7SlD5wzQ_I8tQq1e9HlmhQ ) |
data |
是 | 模板内容,需与申请模板时的关键词匹配(如first 、orderNo 等) |
url |
否 | 用户点击消息后跳转的链接 |
⚠️ 三、注意事项与常见问题
-
消息类型限制:
-
模板消息:适用于业务通知(如订单状态),需用户触发交互后7天内发送。
-
客服消息:用户主动发送消息后48小时内可任意回复(无需模板)。
-
表:消息类型对比
特性 模板消息 客服消息 发送条件 需用户触发交互 用户主动发消息后 时效性 7天内 48小时内 内容格式 固定模板 自由文本/图文
-
-
调试工具:
- 测试号申请:微信公众平台测试账号。
- 内网穿透工具:cpolar(稳定)或natapp(免费)。
-
错误码处理:
40001
:Access Token无效 → 重新获取。41028
:FormID失效 → 检查用户交互是否超期。- 完整错误码:微信全局错误码文档。
🚀 四、进阶优化建议
-
使用SDK简化开发
推荐WxJava封装底层请求:
java// 示例:WxJava发送模板消息 WxMpService wxService = new WxMpServiceImpl(); wxService.setWxMpConfigStorage(new WxMpInMemoryConfigStorage()); // 设置AppID/Secret WxMpTemplateMessage message = WxMpTemplateMessage.builder() .toUser(openid) .templateId(templateId) .build(); message.addData(new WxMpTemplateData("status", "已完成")); wxService.getTemplateMsgService().sendTemplateMsg(message);
-
消息安全与性能
- Token管理:使用Redis缓存Access Token,定时刷新避免超限(每日2000次)。
- 异步发送:将消息发送任务放入线程池,避免阻塞主业务逻辑。