package com.ruoyi.message.wechat.support; 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 org.apache.commons.lang3.StringUtils; import java.util.Map; /** * 微信公众号消息发送工具类(微信官方 SDK 通道)。 *

* 支持:文本客服消息、模板消息。 *

* 迁移说明:原类为 {@code com.ruoyi.common.utils.WxMpUtils},行为未改动,仅换包。 * 现状:全项目没有业务调用点(只有 {@code SysLoginController} 与 * {@code WeChatService} 里的注释/测试代码),属于「已具备能力但未接入」的通道。 */ @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(含值和颜色) * @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 为字段显示的文本内容 * @param defaultColor 默认颜色 * @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); } }