commit
This commit is contained in:
@@ -2,38 +2,102 @@ package com.budwk.app.base.sms;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 短信/消息发送服务接口
|
||||||
|
* 保持参数直观可见,调用者无需查看实体类即可知晓参数含义
|
||||||
|
*/
|
||||||
public interface SmsService {
|
public interface SmsService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单发
|
* 单发普通消息(无标题)
|
||||||
* @param loginName 工号
|
* @param loginName 接收人工号(必填)
|
||||||
* @param content 内容
|
* @param content 消息内容(必填)
|
||||||
*/
|
* @return
|
||||||
void send(String loginName, String content);
|
*/
|
||||||
|
void sendSingleMessage(String loginName, String content);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单发
|
* 单发普通消息(带标题)
|
||||||
* @param loginName 工号
|
* @param loginName 接收人工号(必填)
|
||||||
* @param title 标题
|
* @param title 消息标题(可选,可为null)
|
||||||
* @param content 内容
|
* @param content 消息内容(必填)
|
||||||
*/
|
* @return
|
||||||
void send(String loginName, String title, String content);
|
*/
|
||||||
|
void sendSingleMessage(String loginName, String title, String content);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单发
|
* 单发文本卡片消息
|
||||||
* @param loginName 工号
|
* @param loginName 接收人工号(必填)
|
||||||
* @param title 标题
|
* @param content 卡片内容(必填)
|
||||||
* @param content 内容
|
* @param pcUrl PC端跳转链接(必填)
|
||||||
* @param link 链接
|
* @param mobileUrl 移动端跳转链接(必填)
|
||||||
*/
|
* @return
|
||||||
void send(String loginName, String title, String content, String url, String mobileUrl);
|
*/
|
||||||
|
void sendSingleTextCard(String loginName, String content, String pcUrl, String mobileUrl);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 群发 多人接收内容相同时使用该方法
|
* 单发文本卡片消息(带标题)
|
||||||
* @param loginNames 工号
|
* @param loginName 接收人工号(必填)
|
||||||
* @param title 标题
|
* @param title 卡片标题(可选,可为null)
|
||||||
* @param content 内容
|
* @param content 卡片内容(必填)
|
||||||
* @param link 链接
|
* @param pcUrl PC端跳转链接(必填)
|
||||||
*/
|
* @param mobileUrl 移动端跳转链接(必填)
|
||||||
void massSend(List<String> loginNames, String title, String content, String url, String 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 title 消息标题(可选,可为null)
|
||||||
|
* @param content 消息内容(必填)
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void massSendMessage(List<String> loginNames, String title, String content);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 群发短信文本卡片消息
|
||||||
|
* @param loginNames 接收人工号列表(必填,不能为空列表)
|
||||||
|
* @param title 卡片标题(可选,可为null)
|
||||||
|
* @param content 卡片内容(必填)
|
||||||
|
* @param pcUrl PC端跳转链接(必填)
|
||||||
|
* @param mobileUrl 移动端跳转链接(必填)
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
void massSendTextCard(List<String> loginNames, String title, String content, String pcUrl, String mobileUrl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 群发图文卡片消息
|
||||||
|
* @param loginNames 接收人工号列表(必填,不能为空列表)
|
||||||
|
* @param title 卡片标题(可选,可为null)
|
||||||
|
* @param content 卡片内容(必填)
|
||||||
|
* @param pcUrl PC端跳转链接(必填)
|
||||||
|
* @param mobileUrl 移动端跳转链接(必填)
|
||||||
|
* @param picUrl 图片链接(必填)
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
void massSendPicTextCard(List<String> loginNames, String title, String content, String pcUrl, String mobileUrl, String picUrl);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
package com.budwk.app.base.sms.impl.jshvc;
|
package com.budwk.app.base.sms.impl.jshvc;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.crypto.digest.DigestUtil;
|
|
||||||
import cn.hutool.http.HttpRequest;
|
|
||||||
import cn.hutool.http.HttpResponse;
|
|
||||||
import com.budwk.app.base.sms.SmsService;
|
import com.budwk.app.base.sms.SmsService;
|
||||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
import com.budwk.app.todo.platform.TodoPlatformConfig;
|
||||||
|
import com.wisedu.casp.sdk.api.mc.ReceiverDto;
|
||||||
|
import com.wisedu.casp.sdk.api.mc.SendMsgRequest;
|
||||||
|
import com.wisedu.casp.sdk.api.mc.SendMsgResponse;
|
||||||
|
import com.wisedu.casp.sdk.api.mc.constants.MsgType_Constants;
|
||||||
|
import com.wisedu.casp.sdk.api.mc.constants.SendType_Constants;
|
||||||
|
import com.wisedu.casp.sdk.api.mc.constants.WxSendType_Constants;
|
||||||
|
import com.wisedu.casp.sdk.core.Client;
|
||||||
|
import com.wisedu.casp.sdk.core.DefaultClient;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.nutz.integration.jedis.RedisService;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
import org.nutz.json.Json;
|
import org.nutz.json.Json;
|
||||||
import org.nutz.lang.Lang;
|
import org.nutz.lang.Lang;
|
||||||
import org.nutz.lang.util.NutMap;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ClassName SmsJshvcServiceImpl
|
* @ClassName SmsJshvcServiceImpl
|
||||||
@@ -28,126 +28,112 @@ import java.util.Map;
|
|||||||
@IocBean
|
@IocBean
|
||||||
public class SmsJshvcServiceImpl implements SmsService {
|
public class SmsJshvcServiceImpl implements SmsService {
|
||||||
|
|
||||||
private static final String APPID = "1430576717768122368";
|
private void doSend(String sendType,
|
||||||
private static final String APP_SECRET = "19A0ACB03FBQHL4R4XQD";
|
List<ReceiverDto> receivers,
|
||||||
private static final String TOKEN_URL = "https://gateway.jshvc.edu.cn/token/gateway/accessToken";
|
String title,
|
||||||
private static final String MSG_URL = "https://gateway.jshvc.edu.cn/mp/restful/v2/message/send";
|
String content,
|
||||||
private static final String REDIS_KEY_MSG_ACCESS_TOKEN = "msg:token:";
|
String pcUrl,
|
||||||
|
String mobileUrl,
|
||||||
@Inject
|
String picUrl) {
|
||||||
private RedisService redisService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void send(String loginName, String content) {
|
|
||||||
send(loginName, "智慧工会", content);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void send(String loginName, String title, String content) {
|
|
||||||
send(loginName, "智慧工会", content, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void send(String loginName, String title, String content, String url, String mobileUrl) {
|
|
||||||
Map<String, String> paramMap = Map.of("userId", loginName);
|
|
||||||
doSend(title, content, List.of(paramMap), url, mobileUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void massSend(List<String> loginNames, String title, String content, String url, String mobileUrl) {
|
|
||||||
List<Map<String, String>> receivers = loginNames.stream()
|
|
||||||
.map(name -> Map.of("userId", name))
|
|
||||||
.toList();
|
|
||||||
doSend(title, content, receivers, url, mobileUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sign: 请求签名:(accessToken + 第一个receivers 的userID )的32位小写的MD5加密值,其中如果相应部分没有则忽略
|
|
||||||
* msgType: 0: 普通消息(默认) 1: 必读消息 2: 验证码(为验证码时消息一定不入收件箱)
|
|
||||||
* expiredTime: 当msgType 为1必读消息 ,该字段为必填字段 格式:yyyy-MM-dd HH:mm:ss
|
|
||||||
* sendType: 1.只发送PC门户 2.只发送移动校园 3.邮件 4.短信 5.微信企业号 6.钉钉企业内部应用工作通知 7.微信服务号 8.welink
|
|
||||||
* wxSendType: 当发送类型为5时此字段才会生效:text(文本消息)、textcard(文本卡片)、nes(图文卡片,如果图文,则qyWeChatImgUrl必填)、button(按钮卡片详见示例),不传默认为text
|
|
||||||
* receiverType: 1:用户 2:用户组 3:部门,默认为1
|
|
||||||
*
|
|
||||||
* @param title
|
|
||||||
* @param content
|
|
||||||
* @param receivers
|
|
||||||
*/
|
|
||||||
private void doSend(String title, String content, List<Map<String, String>> receivers, String pcUrl, String mobileUrl) {
|
|
||||||
|
|
||||||
if (Lang.isEmpty(receivers)) {
|
if (Lang.isEmpty(receivers)) {
|
||||||
log.error("send fail by receivers is null");
|
log.error("send fail by receivers is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取token
|
|
||||||
String accessToken = buildAccessToken();
|
|
||||||
// 获取第一个接收人的userID
|
|
||||||
String firstUserId = receivers.get(0).get("userId");
|
|
||||||
// md5小写加密生成签名
|
|
||||||
String sign = DigestUtil.md5Hex(accessToken + firstUserId);
|
|
||||||
|
|
||||||
NutMap paramsMap = new NutMap();
|
|
||||||
paramsMap.put("sign", sign);
|
|
||||||
paramsMap.put("msgType", "0");
|
|
||||||
paramsMap.put("subject", "智慧工会");
|
|
||||||
paramsMap.put("content", content);
|
|
||||||
paramsMap.put("sendType", "5");
|
|
||||||
paramsMap.put("receivers", receivers);
|
|
||||||
if (StrUtil.isBlank(pcUrl) && StrUtil.isBlank(mobileUrl)) {
|
|
||||||
paramsMap.put("wxSendType", "text");
|
|
||||||
} else {
|
|
||||||
paramsMap.put("wxSendType", "textcard");
|
|
||||||
paramsMap.put("pcUrl", pcUrl);
|
|
||||||
paramsMap.put("mobileUrl", mobileUrl);
|
|
||||||
// 这是图文卡片,后面用到再对接吧
|
|
||||||
// paramsMap.put("qyWeChatImgUrl", "");
|
|
||||||
paramsMap.put("urlDesc", "查看详情");
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("send params: {}", Json.toJson(paramsMap));
|
|
||||||
|
|
||||||
HttpRequest request = HttpRequest.post(MSG_URL)
|
|
||||||
.header("appId", APPID)
|
|
||||||
.header("accessToken", accessToken)
|
|
||||||
.body(Json.toJson(paramsMap));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
HttpResponse response = request.execute();
|
// 创建客户端
|
||||||
log.info("send response body: {}", response.body());
|
Client client = new DefaultClient(TodoPlatformConfig.TODO_PLATFORM_BASE_URL, TodoPlatformConfig.TODO_APP_ID, TodoPlatformConfig.TODO_APP_SECRET);
|
||||||
|
SendMsgRequest request = new SendMsgRequest();
|
||||||
|
request.setSubject(title);
|
||||||
|
request.setContent(content);
|
||||||
|
request.setMsgType(MsgType_Constants.COMMON);
|
||||||
|
request.setSendType(SendType_Constants.WECHAT_ENTERPRISE);
|
||||||
|
request.setWxSendType(sendType);
|
||||||
|
request.setReceivers(receivers);
|
||||||
|
|
||||||
NutMap bodyMap = Json.fromJson(NutMap.class, response.body());
|
if (WxSendType_Constants.TEXT_CARD.equals(sendType)) {
|
||||||
if (bodyMap.getInt("status") == 200) {
|
request.setPcUrl(pcUrl);
|
||||||
log.info("send success code: {}, msg: {}", bodyMap.getInt("status"), bodyMap.getString("msg"));
|
request.setMobileUrl(mobileUrl);
|
||||||
|
request.setUrlDesc("查看详情");
|
||||||
|
}
|
||||||
|
if (WxSendType_Constants.NEWS.equals(sendType)) {
|
||||||
|
request.setPcUrl(pcUrl);
|
||||||
|
request.setMobileUrl(mobileUrl);
|
||||||
|
request.setUrlDesc("查看详情");
|
||||||
|
request.setQyWeChatImgUrl(picUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("发送企业微信通知,请求参数:{}", Json.toJson(request));
|
||||||
|
SendMsgResponse response = client.execute(request);
|
||||||
|
log.info("发送企业微信通知,接口响应数据:{}", Json.toJson(response));
|
||||||
|
|
||||||
|
if (response.isSuccess() && response.getStatus() == 200) {
|
||||||
|
log.info("发送企业微信通知成功: {}, msg: {}", response.getStatus(), response.getMsg());
|
||||||
} else {
|
} else {
|
||||||
log.error("send error code: {}, msg: {}", bodyMap.getInt("status"), bodyMap.getString("msg"));
|
log.info("发送企业微信通知失败:{}", response.getMsg());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Failed to send: {}", e.getMessage(), e);
|
log.error("发送企业微信通知失败", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildAccessToken() {
|
@Override
|
||||||
String token = redisService.get(REDIS_KEY_MSG_ACCESS_TOKEN);
|
public void sendSingleMessage(String loginName, String content) {
|
||||||
if (StrUtil.isNotBlank(token)) {
|
this.sendSingleMessage(loginName, "智慧工会", content);
|
||||||
return token;
|
}
|
||||||
}
|
|
||||||
HttpRequest request = HttpRequest.get(TOKEN_URL);
|
|
||||||
request.header("appId", APPID);
|
|
||||||
request.header("appSecret", APP_SECRET);
|
|
||||||
|
|
||||||
HttpResponse response = request.execute();
|
@Override
|
||||||
|
public void sendSingleMessage(String loginName, String title, String content) {
|
||||||
|
this.massSendMessage(List.of(loginName), title, content);
|
||||||
|
}
|
||||||
|
|
||||||
log.info("accessToken response: {}", Json.toJson(response.body()));
|
@Override
|
||||||
|
public void sendSingleTextCard(String loginName, String content, String pcUrl, String mobileUrl) {
|
||||||
|
this.sendSingleTextCard(loginName, "智慧工会", content, pcUrl, mobileUrl);
|
||||||
|
}
|
||||||
|
|
||||||
NutMap bodyMap = Json.fromJson(NutMap.class, response.body());
|
@Override
|
||||||
if (bodyMap.getInt("errcode") == 0) {
|
public void sendSingleTextCard(String loginName, String title, String content, String pcUrl, String mobileUrl) {
|
||||||
log.info("accessToken status: {}", bodyMap.getInt("errorcode"));
|
this.massSendTextCard(List.of(loginName), title, content, pcUrl, mobileUrl);
|
||||||
redisService.setex(REDIS_KEY_MSG_ACCESS_TOKEN, 60 * 120, bodyMap.getString("data"));
|
}
|
||||||
return bodyMap.getString("data");
|
|
||||||
} else {
|
@Override
|
||||||
log.error("accessToken status: {}", bodyMap.getInt("errorcode"));
|
public void sendSinglePicTextCard(String loginName, String content, String pcUrl, String mobileUrl, String picUrl) {
|
||||||
}
|
this.sendSinglePicTextCard(loginName, "智慧工会", content, pcUrl, mobileUrl, picUrl);
|
||||||
return "";
|
}
|
||||||
|
|
||||||
|
@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<String> loginNames, String title, String content) {
|
||||||
|
List<ReceiverDto> list = loginNames.stream().map(loginName -> {
|
||||||
|
ReceiverDto receiverDto = new ReceiverDto();
|
||||||
|
receiverDto.setUserId(loginName);
|
||||||
|
return receiverDto;
|
||||||
|
}).toList();
|
||||||
|
this.doSend(WxSendType_Constants.TEXT, list, title, content, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void massSendTextCard(List<String> loginNames, String title, String content, String pcUrl, String mobileUrl) {
|
||||||
|
List<ReceiverDto> list = loginNames.stream().map(loginName -> {
|
||||||
|
ReceiverDto receiverDto = new ReceiverDto();
|
||||||
|
receiverDto.setUserId(loginName);
|
||||||
|
return receiverDto;
|
||||||
|
}).toList();
|
||||||
|
this.doSend(WxSendType_Constants.TEXT_CARD, list, title, content, pcUrl, mobileUrl, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void massSendPicTextCard(List<String> loginNames, String title, String content, String pcUrl, String mobileUrl, String picUrl) {
|
||||||
|
List<ReceiverDto> list = loginNames.stream().map(loginName -> {
|
||||||
|
ReceiverDto receiverDto = new ReceiverDto();
|
||||||
|
receiverDto.setUserId(loginName);
|
||||||
|
return receiverDto;
|
||||||
|
}).toList();
|
||||||
|
this.doSend(WxSendType_Constants.NEWS, list, title, content, pcUrl, mobileUrl, picUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user