目录

Springboot对接微信公众号,发送模板消息,具体详细步骤

以下是使用 Spring Boot 对接微信公众号发送模板消息的详细步骤和完整实现方案:


1. 准备工作

  1. 公众号申请

    • 拥有认证的服务号(订阅号不支持模板消息)
    • 在公众号后台开通「模板消息」功能
  2. 获取模板ID

    • 在公众号后台 -> 功能 -> 模板消息 -> 添加模板
    • 选择行业模板或自定义模板内容
    • 记录生成的模板ID(如:XyZ1234...
  3. 获取凭证

    • AppIDAppSecret(公众号后台 -> 开发 -> 基本配置)

2. 项目配置

2.1 application.yml 配置

python 复制代码
# 微信配置
wechat:
  public:
    app-id: wx1234567890abcdef
    app-secret: 0123456789abcdef0123456789abcdef
    template-id: XyZ1234567890abcdefg  # 模板消息ID
    access-token-url: https://api.weixin.qq.com/cgi-bin/token
    template-msg-url: https://api.weixin.qq.com/cgi-bin/message/template/send

2.2 配置类

less 复制代码
@Data
@Configuration
@ConfigurationProperties(prefix = "wechat.public")
public class WechatPublicConfig {
    private String appId;
    private String appSecret;
    private String templateId;
    private String accessTokenUrl;
    private String templateMsgUrl;
}

3. AccessToken 管理

3.1 Redis 缓存实现

arduino 复制代码
@Component
public class WechatAccessTokenManager {
    
    @Autowired
    private WechatPublicConfig config;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    private static final String ACCESS_TOKEN_KEY = "wechat:public:access_token";

    public String getAccessToken() {
        String token = redisTemplate.opsForValue().get(ACCESS_TOKEN_KEY);
        if (StringUtils.isNotBlank(token)) {
            return token;
        }
        return refreshAccessToken();
    }

    private synchronized String refreshAccessToken() {
        String url = String.format("%s?grant_type=client_credential&appid=%s&secret=%s",
                config.getAccessTokenUrl(), config.getAppId(), config.getAppSecret());
        
        try {
            RestTemplate restTemplate = new RestTemplate();
            String response = restTemplate.getForObject(url, String.class);
            JsonObject json = JsonParser.parseString(response).getAsJsonObject();
            
            if (json.has("errcode")) {
                throw new RuntimeException("获取Token失败: " + response);
            }
            
            String newToken = json.get("access_token").getAsString();
            int expiresIn = json.get("expires_in").getAsInt();
            
            redisTemplate.opsForValue().set(
                ACCESS_TOKEN_KEY, 
                newToken, 
                expiresIn - 300,  // 提前5分钟过期
                TimeUnit.SECONDS
            );
            
            return newToken;
        } catch (Exception e) {
            throw new RuntimeException("刷新AccessToken失败", e);
        }
    }
}

4. 模板消息发送服务

4.1 消息发送核心类

typescript 复制代码
@Service
public class TemplateMessageService {

    @Autowired
    private WechatAccessTokenManager tokenManager;
    @Autowired
    private WechatPublicConfig config;

    public void sendTemplateMessage(String openId, Map<String, TemplateData> data) {
        String accessToken = tokenManager.getAccessToken();
        String url = config.getTemplateMsgUrl() + "?access_token=" + accessToken;

        Map<String, Object> params = new HashMap<>();
        params.put("touser", openId);
        params.put("template_id", config.getTemplateId());
        params.put("url", "https://yourdomain.com/detail"); // 跳转链接(可选)
        params.put("data", data);

        try {
            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            
            HttpEntity<Map<String, Object>> request = new HttpEntity<>(params, headers);
            ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
            
            handleResponse(response.getBody());
        } catch (Exception e) {
            throw new RuntimeException("发送模板消息失败", e);
        }
    }

    private void handleResponse(String responseBody) {
        JsonObject json = JsonParser.parseString(responseBody).getAsJsonObject();
        int errcode = json.get("errcode").getAsInt();
        if (errcode != 0) {
            String errmsg = json.get("errmsg").getAsString();
            throw new RuntimeException("微信接口错误[" + errcode + "]: " + errmsg);
        }
    }
}

// 模板数据封装类
@Data
@AllArgsConstructor
public class TemplateData {
    private String value;
    private String color; // 可选颜色值,如"#173177"
}

5. 控制器调用示例

less 复制代码
@RestController
@RequestMapping("/wechat/msg")
public class MessageController {

    @Autowired
    private TemplateMessageService messageService;

    @PostMapping("/send")
    public ResponseEntity<String> sendMsg(@RequestParam String openId) {
        // 构造模板参数(需与模板内容匹配)
        Map<String, TemplateData> data = new HashMap<>();
        data.put("first", new TemplateData("订单支付成功通知", "#173177"));
        data.put("keyword1", new TemplateData("2023123456789", null));
        data.put("keyword2", new TemplateData("¥199.00", "#FF0000"));
        data.put("remark", new TemplateData("感谢您的支持!", null));
        
        messageService.sendTemplateMessage(openId, data);
        return ResponseEntity.ok("消息已发送");
    }
}

6. 模板消息参数规范

假设模板内容为:

复制代码
{{first.DATA}}
订单编号:{{keyword1.DATA}}
订单金额:{{keyword2.DATA}}
{{remark.DATA}}

发送时 data 参数必须包含:

json 复制代码
{
  "data": {
    "first": {"value": "..."},
    "keyword1": {"value": "..."},
    "keyword2": {"value": "..."},
    "remark": {"value": "..."}
  }
}

7. 注意事项

  1. 模板匹配

    • 参数名称必须与模板中的 {{keywordX.DATA}} 完全一致
    • 参数个数必须匹配模板定义
  2. 颜色值

    • 可选参数,默认黑色
    • 使用十六进制格式(如 #173177
  3. 用户授权

    • 用户必须关注公众号
    • 模板消息需要用户授权(不同场景授权方式不同)
  4. 频率限制

    • 单个用户每日接收上限为 5 条
    • 同一内容 30 秒内不可重复发送
  5. 错误处理

    • 40001:AccessToken 失效,需刷新后重试
    • 41028:form_id 不正确(适用于一次性订阅场景)
    • 45009:API 调用太频繁

8. 完整调用流程

  1. 用户关注公众号,获取用户 openid
  2. 用户触发业务事件(如支付成功)
  3. 服务端构造模板参数
  4. 获取有效的 access_token
  5. 调用微信模板消息接口发送
  6. 处理发送结果(成功/失败)

9. 高级优化建议

  1. 异步发送 :使用 @Async 异步处理非实时消息
  2. 消息队列:通过 RabbitMQ/Kafka 解耦消息发送
  3. 模板管理:将模板ID存入数据库,实现动态配置
  4. 日志追踪:记录消息发送日志用于审计和排查问题
  5. HTTPS 证书:确保回调地址使用有效的 HTTPS 证书

通过以上步骤即可实现微信公众号模板消息的发送功能,建议结合具体业务需求进行扩展。

本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
li.siyuan1 天前
deepin使用autokey添加微信快捷键一键显隐ctrl+alt+w
微信
北屿升:2 天前
spark core
百度·微信·微信公众平台·facebook·新浪微博
小溪彼岸3 天前
【微信小程序】微信小程序注册流程
微信·微信小程序
泉城老铁5 天前
springboot对接微信公众号获取头像和昵称
微信
赵谨言6 天前
基于微信小程序的高校寝室快修小程序研究
经验分享·微信·毕业设计
微信开发api-视频号协议8 天前
常见的微信个人号二次开发功能
微信
泉城老铁8 天前
springboot 如何实现微信扫码登录
微信
北屿升:14 天前
Scala:大数据时代的多面手
百度·微信·微信公众平台·facebook·新浪微博
开开心心就好15 天前
开启智能生活新篇:免费 APP 实现家电万能操控
java·windows·python·微信·pdf·生活·软件需求