package com.ruoyi.common.utils; import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; import me.chanjar.weixin.mp.bean.template.WxMpTemplateData; import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; import java.util.Map; /** * 微信公众号消息发送工具类 * 支持:文本客服消息、模板消息 */ @Slf4j public class WxMpUtils { private final WxMpService wxMpService; /** * 构造方法,通过 appId 和 appSecret 初始化微信公众号服务 * * @param appId 微信公众号 AppID * @param appSecret 微信公众号 AppSecret */ public WxMpUtils(String appId, String appSecret) { WxMpInMemoryConfigStorage configStorage = new WxMpInMemoryConfigStorage(); configStorage.setAppId(appId); configStorage.setSecret(appSecret); wxMpService = new WxMpServiceImpl(); wxMpService.setWxMpConfigStorage(configStorage); } // ------------------------------------------------------------------------- // 文本客服消息 // ------------------------------------------------------------------------- /** * 向指定 openid 的用户发送文本客服消息 * 注意:用户需在48小时内与公众号有过交互才可发送 * * @param openid 用户的微信 openid * @param content 消息内容 * @return 发送成功返回 true,失败返回 false */ public boolean sendTextMessage(String openid, String content) { if (StringUtils.isEmpty(openid)) { log.warn("【WxMpUtils】sendTextMessage 失败:openid 为空"); return false; } if (StringUtils.isEmpty(content)) { log.warn("【WxMpUtils】sendTextMessage 失败:content 为空"); return false; } try { WxMpKefuMessage message = WxMpKefuMessage.TEXT() .toUser(openid) .content(content) .build(); boolean result = wxMpService.getKefuService().sendKefuMessage(message); log.info("【WxMpUtils】文本客服消息发送{},openid:{}", result ? "成功" : "失败", openid); return result; } catch (WxErrorException e) { log.error("【WxMpUtils】文本客服消息发送异常,openid:{},错误:{}", openid, e.getError(), e); return false; } } // ------------------------------------------------------------------------- // 模板消息 // ------------------------------------------------------------------------- /** * 向指定 openid 的用户发送模板消息(含跳转URL) * * @param openid 用户的微信 openid * @param templateId 模板消息 ID(在微信公众平台配置) * @param url 点击消息后的跳转 URL,不需要跳转可传 null * @param dataMap 模板数据,key 为模板字段名,value 为 WxMpTemplateData(含值和颜色) * 示例:{"first": new WxMpTemplateData("first", "你好", "#173177"), ...} * @return 发送成功返回微信返回的 msgid,失败返回 null */ public String sendTemplateMessage(String openid, String templateId, String url, Map dataMap) { if (StringUtils.isEmpty(openid)) { log.warn("【WxMpUtils】sendTemplateMessage 失败:openid 为空"); return null; } if (StringUtils.isEmpty(templateId)) { log.warn("【WxMpUtils】sendTemplateMessage 失败:templateId 为空"); return null; } try { WxMpTemplateMessage templateMessage = new WxMpTemplateMessage(); templateMessage.setToUser(openid); templateMessage.setTemplateId(templateId); if (StringUtils.isNotEmpty(url)) { templateMessage.setUrl(url); } if (dataMap != null) { for (WxMpTemplateData data : dataMap.values()) { templateMessage.addData(data); } } String msgId = wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage); log.info("【WxMpUtils】模板消息发送成功,openid:{},msgId:{}", openid, msgId); return msgId; } catch (WxErrorException e) { log.error("【WxMpUtils】模板消息发送异常,openid:{},templateId:{},错误:{}", openid, templateId, e.getError(), e); return null; } } /** * 向指定 openid 的用户发送模板消息(简化版,value 不设置颜色) * * @param openid 用户的微信 openid * @param templateId 模板消息 ID * @param url 点击消息后的跳转 URL,不需要跳转可传 null * @param dataMap 模板数据,key 为模板字段名,value 为字段显示的文本内容 * 示例:{"first": "你好", "keyword1": "2024-01-01", "remark": "感谢使用"} * @return 发送成功返回微信返回的 msgid,失败返回 null */ public String sendTemplateMessage(String openid, String templateId, String url, Map dataMap, String defaultColor) { if (StringUtils.isEmpty(openid)) { log.warn("【WxMpUtils】sendTemplateMessage 失败:openid 为空"); return null; } if (StringUtils.isEmpty(templateId)) { log.warn("【WxMpUtils】sendTemplateMessage 失败:templateId 为空"); return null; } try { WxMpTemplateMessage templateMessage = new WxMpTemplateMessage(); templateMessage.setToUser(openid); templateMessage.setTemplateId(templateId); if (StringUtils.isNotEmpty(url)) { templateMessage.setUrl(url); } if (dataMap != null) { String color = StringUtils.isEmpty(defaultColor) ? "#173177" : defaultColor; for (Map.Entry entry : dataMap.entrySet()) { templateMessage.addData(new WxMpTemplateData(entry.getKey(), entry.getValue(), color)); } } String msgId = wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage); log.info("【WxMpUtils】模板消息发送成功,openid:{},msgId:{}", openid, msgId); return msgId; } catch (WxErrorException e) { log.error("【WxMpUtils】模板消息发送异常,openid:{},templateId:{},错误:{}", openid, templateId, e.getError(), e); return null; } } // ------------------------------------------------------------------------- // 静态工厂方法(快速构造) // ------------------------------------------------------------------------- /** * 快速创建 WxMpUtils 实例 * * @param appId 微信公众号 AppID * @param appSecret 微信公众号 AppSecret * @return WxMpUtils 实例 */ public static WxMpUtils of(String appId, String appSecret) { return new WxMpUtils(appId, appSecret); } }