diff --git a/src/main/java/com/budwk/app/base/constant/RedisConstant.java b/src/main/java/com/budwk/app/base/constant/RedisConstant.java index 83bd8427..c68f2aa9 100644 --- a/src/main/java/com/budwk/app/base/constant/RedisConstant.java +++ b/src/main/java/com/budwk/app/base/constant/RedisConstant.java @@ -32,6 +32,8 @@ public class RedisConstant { // 短信token public final static String REDIS_SMS_TOKEN_KEY = PLATFORM_REDIS_PREFIX + "platfrom:sms:token:"; + public final static String REDIS_TODO_TOKEN_KEY = PLATFORM_REDIS_PREFIX + "platfrom:todo:token:"; + public final static String REDIS_KEY_API_SIGN_DEPLOY_NONCE = PLATFORM_REDIS_PREFIX + "api:sign:deploy:nonce:"; public final static String REDIS_KEY_API_SIGN_OPEN_NONCE = PLATFORM_REDIS_PREFIX + "api:sign:open:nonce:"; diff --git a/src/main/java/com/budwk/app/base/sms/SmsService.java b/src/main/java/com/budwk/app/base/sms/SmsService.java index 37ea187e..4003f203 100644 --- a/src/main/java/com/budwk/app/base/sms/SmsService.java +++ b/src/main/java/com/budwk/app/base/sms/SmsService.java @@ -2,12 +2,131 @@ package com.budwk.app.base.sms; import java.util.List; +/** + * 短信/消息发送服务接口 + * 保持参数直观可见,调用者无需查看实体类即可知晓参数含义 + */ public interface SmsService { - /** - * 单发 - * @param loginName 工号 - * @param content 内容 - */ - void send(String loginName, String content); + /** + * 单发普通消息(无标题) + * @param loginName 接收人工号(必填) + * @param content 消息内容(必填) + * @return + */ + void sendSingleMessage(String loginName, String content); + + /** + * 单发普通消息(带标题) + * @param loginName 接收人工号(必填) + * @param title 消息标题(可选,可为null) + * @param content 消息内容(必填) + * @return + */ + void sendSingleMessage(String loginName, String title, String content); + + /** + * 单发文本卡片消息 + * @param loginName 接收人工号(必填) + * @param content 卡片内容(必填) + * @param pcUrl PC端跳转链接(必填) + * @param mobileUrl 移动端跳转链接(必填) + * @return + */ + void sendSingleTextCard(String loginName, String content, String pcUrl, String mobileUrl); + + /** + * 单发文本卡片消息(带标题) + * @param loginName 接收人工号(必填) + * @param title 卡片标题(可选,可为null) + * @param content 卡片内容(必填) + * @param pcUrl PC端跳转链接(必填) + * @param mobileUrl 移动端跳转链接(必填) + * @return + */ + void sendSingleTextCard(String loginName, String title, String content, String pcUrl, String mobileUrl); + + /** + * 单发图文卡片消息 + * @param loginName 接收人工号(必填) + * @param content 卡片内容(必填) + * @param pcUrl PC端跳转链接(必填) + * @param mobileUrl 移动端跳转链接(必填) + * @param picUrl 图片链接(必填) + * @return + */ + void sendSinglePicTextCard(String loginName, String content, String pcUrl, String mobileUrl, String picUrl); + + /** + * 单发图文卡片消息(带标题) + * @param loginName 接收人工号(必填) + * @param title 卡片标题(可选,可为null) + * @param content 卡片内容(必填) + * @param pcUrl PC端跳转链接(必填) + * @param mobileUrl 移动端跳转链接(必填) + * @param picUrl 图片链接(必填) + * @return + */ + void sendSinglePicTextCard(String loginName, String title, String content, String pcUrl, String mobileUrl, String picUrl); + + /** + * 群发普通消息(多人接收相同内容) + * @param loginNames 接收人工号列表(必填,不能为空列表) + * @param content 消息内容(必填) + * @return void + */ + void massSendMessage(List loginNames, String content); + + /** + * 群发普通消息(多人接收相同内容) + * @param loginNames 接收人工号列表(必填,不能为空列表) + * @param title 消息标题(可选,可为null) + * @param content 消息内容(必填) + * @return void + */ + void massSendMessage(List loginNames, String title, String content); + + /** + * 群发短信文本卡片消息 + * @param loginNames 接收人工号列表(必填,不能为空列表) + * @param content 卡片内容(必填) + * @param pcUrl PC端跳转链接(必填) + * @param mobileUrl 移动端跳转链接(必填) + * @return + */ + void massSendTextCard(List loginNames, String content, String pcUrl, String mobileUrl); + + /** + * 群发短信文本卡片消息 + * @param loginNames 接收人工号列表(必填,不能为空列表) + * @param title 卡片标题(可选,可为null) + * @param content 卡片内容(必填) + * @param pcUrl PC端跳转链接(必填) + * @param mobileUrl 移动端跳转链接(必填) + * @return + */ + void massSendTextCard(List loginNames, String title, String content, String pcUrl, String mobileUrl); + + /** + * 群发图文卡片消息 + * @param loginNames 接收人工号列表(必填,不能为空列表) + * @param content 卡片内容(必填) + * @param pcUrl PC端跳转链接(必填) + * @param mobileUrl 移动端跳转链接(必填) + * @param picUrl 图片链接(必填) + * @return + */ + void massSendPicTextCard(List loginNames, String content, String pcUrl, String mobileUrl, String picUrl); + + /** + * 群发图文卡片消息 + * @param loginNames 接收人工号列表(必填,不能为空列表) + * @param title 卡片标题(可选,可为null) + * @param content 卡片内容(必填) + * @param pcUrl PC端跳转链接(必填) + * @param mobileUrl 移动端跳转链接(必填) + * @param picUrl 图片链接(必填) + * @return + */ + void massSendPicTextCard(List loginNames, String title, String content, String pcUrl, String mobileUrl, String picUrl); } diff --git a/src/main/java/com/budwk/app/base/sms/impl/ncu/SmsNcuServiceImpl.java b/src/main/java/com/budwk/app/base/sms/impl/ncu/SmsNcuServiceImpl.java index b332a0ea..5cfc7190 100644 --- a/src/main/java/com/budwk/app/base/sms/impl/ncu/SmsNcuServiceImpl.java +++ b/src/main/java/com/budwk/app/base/sms/impl/ncu/SmsNcuServiceImpl.java @@ -1,27 +1,155 @@ package com.budwk.app.base.sms.impl.ncu; +import cn.hutool.http.HttpUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; import com.budwk.app.base.sms.SmsService; import com.budwk.app.base.sms.impl.ncu.util.SmsTokenUtil; import lombok.extern.slf4j.Slf4j; import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.json.Json; +import org.nutz.lang.Lang; +import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * 南昌大学短信实现 */ -@IocBean @Slf4j +@IocBean public class SmsNcuServiceImpl implements SmsService { - private static final String SEND_MSG_URL = "https://api.ucpass.cn/sms/send"; - private static final String APP_ID = ""; + private static final String SEND_MSG_URL = "https://poa.ncu.edu.cn/apis/messagecenter/v1/poaMessage/messageSend"; + private static final String APP_ID = "72e34a101d3011f1a74cbae5193504f4"; + private static final String TEMPLATE_ID = "MT1773223005000"; + @Override + public void sendSingleMessage(String loginName, String content) { + this.sendSingleMessage(loginName, "智慧工会", content); + } - @Override - public void send(String loginName, String content) { - String token = SmsTokenUtil.getToken(); - } + @Override + public void sendSingleMessage(String loginName, String title, String content) { + this.massSendMessage(List.of(loginName), title, content); + } + @Override + public void sendSingleTextCard(String loginName, String content, String pcUrl, String mobileUrl) { + this.sendSingleTextCard(loginName, "智慧工会", content, pcUrl, mobileUrl); + } + + @Override + public void sendSingleTextCard(String loginName, String title, String content, String pcUrl, String mobileUrl) { + this.massSendTextCard(List.of(loginName), title, content, pcUrl, mobileUrl); + } + + @Override + public void sendSinglePicTextCard(String loginName, String content, String pcUrl, String mobileUrl, String picUrl) { + this.sendSinglePicTextCard(loginName, "智慧工会", content, pcUrl, mobileUrl, picUrl); + } + + @Override + public void sendSinglePicTextCard(String loginName, String title, String content, String pcUrl, String mobileUrl, String picUrl) { + this.massSendPicTextCard(List.of(loginName), title, content, pcUrl, mobileUrl, picUrl); + } + + @Override + public void massSendMessage(List loginNames, String content) { + this.massSendMessage(loginNames, "智慧工会", content); + } + + @Override + public void massSendMessage(List loginNames, String title, String content) { + String list = String.join(",", loginNames); + this.doSend("text", list, title, content, null, null, null); + } + + @Override + public void massSendTextCard(List loginNames, String content, String pcUrl, String mobileUrl) { + this.massSendTextCard(loginNames, "智慧工会", content, pcUrl, mobileUrl); + } + + @Override + public void massSendTextCard(List loginNames, String title, String content, String pcUrl, String mobileUrl) { + String list = String.join(",", loginNames); + this.doSend("textCard", list, title, content, pcUrl, mobileUrl, null); + } + + @Override + public void massSendPicTextCard(List loginNames, String content, String pcUrl, String mobileUrl, String picUrl) { + this.massSendPicTextCard(loginNames, "智慧工会", content, pcUrl, mobileUrl, picUrl); + } + + @Override + public void massSendPicTextCard(List loginNames, String title, String content, String pcUrl, String mobileUrl, String picUrl) { + String list = String.join(",", loginNames); + this.doSend("news", list, title, content, pcUrl, mobileUrl, picUrl); + } + + private void doSend(String sendType, + String receivers, + String title, + String content, + String pcUrl, + String mobileUrl, + String picUrl) { + + if (Lang.isEmpty(receivers)) { + log.error("【log】send fail by receivers is null"); + return; + } + try { + String token = SmsTokenUtil.getToken(); + if (Lang.isEmpty(token)) { + log.error("【log】send fail by token is null"); + return; + } + + Map params = new HashMap<>(); + params.put("appId", APP_ID); + params.put("sendId", ""); + params.put("sendType", Stream.of("WECHAT").toArray()); + params.put("messageTypeCode", TEMPLATE_ID); + params.put("promise", false); + params.put("importantIdentity", false); + params.put("toPersons", receivers); + + Map dataParams = new HashMap<>(); + dataParams.put("title", title); + dataParams.put("paramValueJson", Map.of("content", content)); + + if ("textCard".equals(sendType)) { + dataParams.put("url", pcUrl); + dataParams.put("mobileUrl", mobileUrl); + } + if ("news".equals(sendType)) { + dataParams.put("url", pcUrl); + dataParams.put("mobileUrl", mobileUrl); + dataParams.put("coverImageUrl", picUrl); + } + params.put("data", dataParams); + + log.info("【log】发送消息通知,请求参数:{}", Json.toJson(params)); + String body = HttpUtil.createPost(SEND_MSG_URL) + .header("Authorization", token) + .header("Content-Type", "application/json") + .form(params).execute().body(); + JSONObject resultJsonBody = JSONUtil.parseObj(body); + log.info("【log】发送消息通知,接口响应数据:{}", body); + + if (resultJsonBody.getInt("code") == 0) { + log.info("【log】发送消息通知成功"); + } else { + log.info("【log】发送消息通知失败:{}", resultJsonBody.getStr("message")); + } + } catch (Exception e) { + log.error("【log】发送消息通知失败", e); + } + } } diff --git a/src/main/java/com/budwk/app/base/sms/impl/ncu/util/SmsTokenUtil.java b/src/main/java/com/budwk/app/base/sms/impl/ncu/util/SmsTokenUtil.java index 16c3d52e..83916938 100644 --- a/src/main/java/com/budwk/app/base/sms/impl/ncu/util/SmsTokenUtil.java +++ b/src/main/java/com/budwk/app/base/sms/impl/ncu/util/SmsTokenUtil.java @@ -5,8 +5,10 @@ import cn.hutool.http.HttpUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.budwk.app.base.constant.RedisConstant; +import lombok.extern.slf4j.Slf4j; import org.nutz.integration.jedis.RedisService; import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.json.Json; import java.util.HashMap; import java.util.Map; @@ -18,19 +20,16 @@ import java.util.Map; * @Date 2025/12/3 9:53 * @注释 :短信token工具类 */ +@Slf4j public class SmsTokenUtil { @Inject private static RedisService redisService; - private static final String TOKEN_URL = "https://api.ucpass.cn/token"; - - private static final String CLINT_ID = ""; - - private static final String CLINT_SECRET = ""; - - private static final String SCOPE = ""; - + private static final String TOKEN_URL = "https://poa.ncu.edu.cn/oauth2/token"; + private static final String CLINT_ID = "dP7SXC1MoYAJHPh6k8Cgsda8tGY="; + private static final String CLINT_SECRET = "PFAwVcXOsVFzP3Jwb4RyO5V97o8j8zNTQ8QSTre8oIc="; + private static final String SCOPE = "messagecenter:v1:sendMessage"; public static String getToken() { String key = RedisConstant.REDIS_SMS_TOKEN_KEY; @@ -48,6 +47,7 @@ public class SmsTokenUtil { .formStr(param).execute().body(); JSONObject resultJsonBody = JSONUtil.parseObj(body); + log.info("【log】获取消息token接口回调数据:{}", Json.toJson(resultJsonBody)); if (resultJsonBody.getInt("code") == 200) { String accessToken = resultJsonBody.getStr("access_token"); Integer expiresIn = resultJsonBody.getInt("expires_in");