..
This commit is contained in:
@@ -1,24 +0,0 @@
|
||||
package com.budwk.app.sys.controller.message;
|
||||
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
|
||||
/**
|
||||
* 消息发送者
|
||||
*/
|
||||
public interface SysMessageSender {
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
* @param message 消息内容
|
||||
* @param receiver 接收人
|
||||
* @return 发送结果
|
||||
*/
|
||||
// boolean send(Message message, Sys_user receiver);
|
||||
|
||||
/**
|
||||
* 支持的渠道类型
|
||||
* @return 渠道类型
|
||||
*/
|
||||
String getChannelType();
|
||||
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
package com.budwk.app.sys.controller.message;
|
||||
|
||||
public class SysSmsMessageSender {
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.budwk.app.zhgh.dayofficework.message.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 消息通道
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum GlobalMessageChannel {
|
||||
|
||||
LOCAL("本地"),
|
||||
|
||||
WECHAT("微信"),
|
||||
|
||||
EMAIL("邮件"),
|
||||
|
||||
SMS("短信"),
|
||||
|
||||
DINGDING("钉钉"),
|
||||
|
||||
WECHAT_ENTERPRISE("企业微信");
|
||||
|
||||
private final String value;
|
||||
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package com.budwk.app.zhgh.dayofficework.message.mode;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息发送请求
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class GlobalMessageSendRequest {
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 附件
|
||||
*/
|
||||
private List<JSONObject> attachments;
|
||||
|
||||
/**
|
||||
* 消息类型(1:系统通知 2:待办通知)
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
* 配置
|
||||
*/
|
||||
private JSONObject config;
|
||||
|
||||
/**
|
||||
* 接收人ID
|
||||
*/
|
||||
private List<String> receiverIds;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.budwk.app.zhgh.dayofficework.message.models;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.nutz.dao.entity.annotation.*;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Table("global_message")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("全局消息")
|
||||
public class GlobalMessage extends BaseModel {
|
||||
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("标题")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 255)
|
||||
private String title;
|
||||
|
||||
@Column
|
||||
@Comment("内容")
|
||||
@ColDefine(type = ColType.TEXT)
|
||||
private String content;
|
||||
|
||||
@Column
|
||||
@Comment("附件")
|
||||
@ColDefine(type = ColType.MYSQL_JSON)
|
||||
private List<JSONObject> attachments;
|
||||
|
||||
@Column
|
||||
@Comment("消息类型(1:系统公告 2:消息通知)")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer type;
|
||||
|
||||
@Column
|
||||
@Comment("发送人ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String senderId;
|
||||
|
||||
@Column
|
||||
@Comment("发送人姓名")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String senderName;
|
||||
|
||||
@Column
|
||||
@Comment("发送人工号")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String senderLoginName;
|
||||
|
||||
// @Column
|
||||
// @Comment("消息通道(用于第三方消息)")
|
||||
// @ColDefine(type = ColType.MYSQL_JSON)
|
||||
// private List<String> channels;
|
||||
|
||||
@Column
|
||||
@Comment("扩展字段")
|
||||
@ColDefine(type = ColType.MYSQL_JSON)
|
||||
private JSONObject ext;
|
||||
|
||||
@Column
|
||||
@Comment("状态(1:草稿 2:已发送 3:已撤回 4:已删除)")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer status;
|
||||
|
||||
@Column
|
||||
@Comment("发送成功")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("0")
|
||||
private Boolean sendSuccess;
|
||||
|
||||
@Column
|
||||
@Comment("发送结果")
|
||||
@ColDefine(type = ColType.MYSQL_JSON)
|
||||
private String sendResult;
|
||||
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.budwk.app.zhgh.dayofficework.message.models;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.nutz.dao.entity.annotation.*;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Table("global_message_receiver")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("全局消息接收用户")
|
||||
public class GlobalMessageReceiver extends BaseModel {
|
||||
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("消息ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String messageId;
|
||||
|
||||
@Column
|
||||
@Comment("接收人ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String receiverId;
|
||||
|
||||
@Column
|
||||
@Comment("接收人姓名")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String receiverName;
|
||||
|
||||
@Column
|
||||
@Comment("接收人工号")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String receiverLoginName;
|
||||
|
||||
@Column
|
||||
@Comment("阅读状态")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("0")
|
||||
private Boolean isRead;
|
||||
|
||||
@Column
|
||||
@Comment("阅读时间")
|
||||
@ColDefine(type = ColType.DATETIME)
|
||||
private Date readTime;
|
||||
|
||||
|
||||
|
||||
}
|
||||
+228
@@ -0,0 +1,228 @@
|
||||
package com.budwk.app.zhgh.dayofficework.message.service;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.zhgh.dayofficework.message.enums.GlobalMessageChannel;
|
||||
import com.budwk.app.zhgh.dayofficework.message.mode.GlobalMessageSendRequest;
|
||||
import com.budwk.app.zhgh.dayofficework.message.strategy.GlobalMessageSendStrategy;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.Ioc;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 全局消息发送服务
|
||||
*/
|
||||
@IocBean(create = "initStrategies")
|
||||
@Slf4j
|
||||
public class GlobalMessageSendService {
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
|
||||
@Inject
|
||||
private Ioc ioc;
|
||||
|
||||
/**
|
||||
* 消息发送策略缓存
|
||||
*/
|
||||
private final Map<GlobalMessageChannel, GlobalMessageSendStrategy> strategyMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 本地消息策略(必须存在)
|
||||
*/
|
||||
private GlobalMessageSendStrategy localStrategy;
|
||||
|
||||
/**
|
||||
* 初始化策略
|
||||
*/
|
||||
public void initStrategies() {
|
||||
try {
|
||||
log.info("开始初始化消息发送策略...");
|
||||
|
||||
// 获取所有实现了GlobalMessageSendStrategy接口的Bean
|
||||
String[] beanNames = ioc.getNames();
|
||||
for (String beanName : beanNames) {
|
||||
try {
|
||||
Object bean = ioc.get(null, beanName);
|
||||
if (bean instanceof GlobalMessageSendStrategy) {
|
||||
GlobalMessageSendStrategy strategy = (GlobalMessageSendStrategy) bean;
|
||||
GlobalMessageChannel channel = strategy.getChannel();
|
||||
strategyMap.put(channel, strategy);
|
||||
|
||||
// 缓存本地策略
|
||||
if (channel == GlobalMessageChannel.LOCAL) {
|
||||
localStrategy = strategy;
|
||||
}
|
||||
|
||||
log.info("注册消息发送策略:{} -> {}", channel.getValue(), strategy.getClass().getSimpleName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("初始化Bean {}时出错:{}", beanName, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (localStrategy == null) {
|
||||
throw new RuntimeException("本地消息发送策略未找到,系统无法正常工作");
|
||||
}
|
||||
|
||||
log.info("消息发送策略初始化完成,共注册{}个策略", strategyMap.size());
|
||||
} catch (Exception e) {
|
||||
log.error("消息发送策略初始化失败", e);
|
||||
throw new RuntimeException("消息发送策略初始化失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息(简化API)
|
||||
*/
|
||||
public void sendMessage(String title, String content, List<String> receiverIds) {
|
||||
sendMessage(title, content, 1, receiverIds, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息(完整API)
|
||||
*/
|
||||
public void sendMessage(String title, String content, Integer type, List<String> receiverIds, JSONObject config) {
|
||||
GlobalMessageSendRequest request = new GlobalMessageSendRequest();
|
||||
request.setTitle(title);
|
||||
request.setContent(content);
|
||||
request.setType(type);
|
||||
request.setReceiverIds(receiverIds);
|
||||
request.setConfig(config);
|
||||
|
||||
sendMessage(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息(使用请求对象)
|
||||
*/
|
||||
public void sendMessage(GlobalMessageSendRequest request) {
|
||||
try {
|
||||
log.info("开始发送全局消息,标题:{},接收人数量:{}", request.getTitle(),
|
||||
request.getReceiverIds() != null ? request.getReceiverIds().size() : 0);
|
||||
|
||||
// 参数校验
|
||||
validateRequest(request);
|
||||
|
||||
// 获取启用的策略
|
||||
List<GlobalMessageSendStrategy> enabledStrategies = getEnabledStrategies();
|
||||
|
||||
if (enabledStrategies.isEmpty()) {
|
||||
log.warn("没有找到启用的消息发送策略");
|
||||
return;
|
||||
}
|
||||
|
||||
// 执行消息发送 - 本地消息优先,然后是外部策略
|
||||
for (GlobalMessageSendStrategy strategy : enabledStrategies) {
|
||||
try {
|
||||
// 本地消息必须同步发送,确保优先完成
|
||||
if (strategy.getChannel() == GlobalMessageChannel.LOCAL) {
|
||||
strategy.send(request.getTitle(), request.getContent(), request.getType(),
|
||||
request.getReceiverIds(), request.getConfig());
|
||||
log.info("本地消息发送成功");
|
||||
} else {
|
||||
// 外部消息策略根据配置决定同步或异步
|
||||
if (strategy.supportAsync()) {
|
||||
// 异步发送
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
strategy.send(request.getTitle(), request.getContent(), request.getType(),
|
||||
request.getReceiverIds(), request.getConfig());
|
||||
log.info("异步发送消息成功,渠道:{}", strategy.getChannel().getValue());
|
||||
} catch (Exception e) {
|
||||
log.error("异步发送消息失败,渠道:{},错误:{}", strategy.getChannel().getValue(), e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 同步发送
|
||||
strategy.send(request.getTitle(), request.getContent(), request.getType(),
|
||||
request.getReceiverIds(), request.getConfig());
|
||||
log.info("同步发送消息成功,渠道:{}", strategy.getChannel().getValue());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("发送消息失败,渠道:{},错误:{}", strategy.getChannel().getValue(), e.getMessage(), e);
|
||||
// 本地消息发送失败时,记录严重错误并抛出异常
|
||||
if (strategy.getChannel() == GlobalMessageChannel.LOCAL) {
|
||||
log.error("本地消息发送失败,这可能影响消息的完整性");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.info("全局消息发送完成,标题:{}", request.getTitle());
|
||||
} catch (Exception e) {
|
||||
log.error("全局消息发送失败,标题:{},错误:{}", request.getTitle(), e.getMessage(), e);
|
||||
throw new RuntimeException("消息发送失败:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数校验
|
||||
*/
|
||||
private void validateRequest(GlobalMessageSendRequest request) {
|
||||
if (request == null) {
|
||||
throw new IllegalArgumentException("消息发送请求不能为空");
|
||||
}
|
||||
if (request.getTitle() == null || request.getTitle().trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("消息标题不能为空");
|
||||
}
|
||||
if (request.getContent() == null || request.getContent().trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("消息内容不能为空");
|
||||
}
|
||||
if (request.getReceiverIds() == null || request.getReceiverIds().isEmpty()) {
|
||||
throw new IllegalArgumentException("接收人不能为空");
|
||||
}
|
||||
if (request.getType() == null) {
|
||||
request.setType(1); // 默认为系统消息
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取启用的发送策略
|
||||
* 本地消息策略必须启用,其他策略根据isEnabled()方法判断
|
||||
*/
|
||||
private List<GlobalMessageSendStrategy> getEnabledStrategies() {
|
||||
List<GlobalMessageSendStrategy> enabledStrategies = new ArrayList<>();
|
||||
|
||||
// 本地消息策略必须存在且优先添加
|
||||
if (localStrategy != null) {
|
||||
enabledStrategies.add(localStrategy);
|
||||
log.debug("添加本地消息策略:{}", localStrategy.getChannel().getValue());
|
||||
}
|
||||
|
||||
// 查找其他启用的策略
|
||||
for (GlobalMessageSendStrategy strategy : strategyMap.values()) {
|
||||
// 跳过本地策略(已经添加)
|
||||
if (strategy.getChannel() == GlobalMessageChannel.LOCAL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查策略是否启用
|
||||
if (strategy.isEnabled()) {
|
||||
enabledStrategies.add(strategy);
|
||||
log.debug("添加启用的外部消息策略:{}", strategy.getChannel().getValue());
|
||||
} else {
|
||||
log.debug("跳过未启用的消息策略:{}", strategy.getChannel().getValue());
|
||||
}
|
||||
}
|
||||
|
||||
log.info("共找到{}个启用的消息发送策略", enabledStrategies.size());
|
||||
return enabledStrategies;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有可用的发送策略
|
||||
*/
|
||||
public Map<GlobalMessageChannel, GlobalMessageSendStrategy> getAvailableStrategies() {
|
||||
return new HashMap<>(strategyMap);
|
||||
}
|
||||
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package com.budwk.app.zhgh.dayofficework.message.strategy;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.zhgh.dayofficework.message.enums.GlobalMessageChannel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 全局消息发送策略
|
||||
*/
|
||||
public interface GlobalMessageSendStrategy {
|
||||
|
||||
/**
|
||||
* 获取渠道类型
|
||||
*/
|
||||
GlobalMessageChannel getChannel();
|
||||
|
||||
/**
|
||||
* 是否支持异步发送
|
||||
*/
|
||||
default boolean supportAsync() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用该策略
|
||||
* 默认启用,子类可以重写此方法来控制策略的启用状态
|
||||
*/
|
||||
default boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
* @param title 标题
|
||||
* @param content 内容
|
||||
* @param type 0:系统消息 1:待办消息
|
||||
* @param receiverIds 接收人ID
|
||||
* @param config 配置
|
||||
*/
|
||||
void send(String title, String content, Integer type, List<String> receiverIds, JSONObject config);
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
* @param title 标题
|
||||
* @param content 内容
|
||||
* @param type 0:系统消息 1:待办消息
|
||||
* @param receiverLoginNames 接收人登录名
|
||||
* @param config 配置
|
||||
*/
|
||||
void sendByLoginName(String title, String content, Integer type, List<String> receiverLoginNames, JSONObject config);
|
||||
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
package com.budwk.app.zhgh.dayofficework.message.strategy.impl;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.message.enums.GlobalMessageChannel;
|
||||
import com.budwk.app.zhgh.dayofficework.message.models.GlobalMessage;
|
||||
import com.budwk.app.zhgh.dayofficework.message.models.GlobalMessageReceiver;
|
||||
import com.budwk.app.zhgh.dayofficework.message.strategy.GlobalMessageSendStrategy;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 本地消息发送策略
|
||||
*/
|
||||
@IocBean
|
||||
@Slf4j
|
||||
public class LocalMessageSendStrategy implements GlobalMessageSendStrategy {
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
|
||||
@Override
|
||||
public GlobalMessageChannel getChannel() {
|
||||
return GlobalMessageChannel.LOCAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportAsync() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String title, String content, Integer type, List<String> receiverIds, JSONObject config) {
|
||||
List<Sys_user> users = dao.query(Sys_user.class, Cnd.where(Sys_user::getId, "in", receiverIds));
|
||||
sendMessage(title, content, type, users, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendByLoginName(String title, String content, Integer type, List<String> receiverLoginNames, JSONObject config) {
|
||||
List<Sys_user> users = dao.query(Sys_user.class, Cnd.where(Sys_user::getLoginname, "in", receiverLoginNames));
|
||||
sendMessage(title, content, type, users, config);
|
||||
}
|
||||
|
||||
private void sendMessage(String title, String content, Integer type, List<Sys_user> receivers, JSONObject config) {
|
||||
try {
|
||||
log.info("开始发送本地消息,标题:{},接收人数量:{}", title, receivers.size());
|
||||
|
||||
// 消息主体
|
||||
GlobalMessage globalMessage = new GlobalMessage();
|
||||
globalMessage.setTitle(title);
|
||||
globalMessage.setContent(content);
|
||||
globalMessage.setType(type);
|
||||
globalMessage.setSenderId(SecurityUtil.getUserId());
|
||||
globalMessage.setSenderName(SecurityUtil.getUserUsername());
|
||||
globalMessage.setSenderLoginName(SecurityUtil.getUserLoginname());
|
||||
globalMessage.setStatus(1); // 草稿状态
|
||||
globalMessage.setSendSuccess(false);
|
||||
dao.insert(globalMessage);
|
||||
|
||||
// 消息接收人
|
||||
List<GlobalMessageReceiver> receiverList = receivers.stream().map(r -> {
|
||||
GlobalMessageReceiver receiver = new GlobalMessageReceiver();
|
||||
receiver.setMessageId(globalMessage.getId());
|
||||
receiver.setReceiverId(r.getId());
|
||||
receiver.setReceiverName(r.getUsername()); // 修复:使用用户名而不是登录名
|
||||
receiver.setReceiverLoginName(r.getLoginname());
|
||||
receiver.setIsRead(false);
|
||||
return receiver;
|
||||
}).toList();
|
||||
dao.insert(receiverList);
|
||||
|
||||
// 更新消息状态为已发送
|
||||
globalMessage.setStatus(2);
|
||||
globalMessage.setSendSuccess(true);
|
||||
globalMessage.setSendResult("本地消息发送成功");
|
||||
dao.update(globalMessage);
|
||||
|
||||
log.info("本地消息发送成功,消息ID:{},接收人数量:{}", globalMessage.getId(), receivers.size());
|
||||
} catch (Exception e) {
|
||||
log.error("本地消息发送失败,标题:{},错误信息:{}", title, e.getMessage(), e);
|
||||
throw new RuntimeException("本地消息发送失败:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
package com.budwk.app.zhgh.dayofficework.message.strategy.impl;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
import com.budwk.app.zhgh.dayofficework.message.enums.GlobalMessageChannel;
|
||||
import com.budwk.app.zhgh.dayofficework.message.strategy.GlobalMessageSendStrategy;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 短信发送策略
|
||||
*/
|
||||
@IocBean
|
||||
@Slf4j
|
||||
public class SmsMessageSendStrategy implements GlobalMessageSendStrategy {
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
|
||||
@Override
|
||||
public GlobalMessageChannel getChannel() {
|
||||
return GlobalMessageChannel.SMS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportAsync() {
|
||||
return true; // 短信发送支持异步
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public boolean isEnabled() {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void send(String title, String content, Integer type, List<String> receiverIds, JSONObject config) {
|
||||
try {
|
||||
log.info("开始发送短信消息,标题:{},接收人数量:{}", title, receiverIds.size());
|
||||
|
||||
// 查询用户手机号
|
||||
List<Sys_user> users = dao.query(Sys_user.class, Cnd.where(Sys_user::getId, "in", receiverIds));
|
||||
sendSmsMessage(title, content, type, users, config);
|
||||
|
||||
log.info("短信消息发送完成,标题:{},接收人数量:{}", title, users.size());
|
||||
} catch (Exception e) {
|
||||
log.error("短信消息发送失败,标题:{},错误:{}", title, e.getMessage(), e);
|
||||
throw new RuntimeException("短信消息发送失败:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendByLoginName(String title, String content, Integer type, List<String> receiverLoginNames, JSONObject config) {
|
||||
try {
|
||||
log.info("开始发送短信消息(按登录名),标题:{},接收人数量:{}", title, receiverLoginNames.size());
|
||||
|
||||
// 查询用户手机号
|
||||
List<Sys_user> users = dao.query(Sys_user.class, Cnd.where(Sys_user::getLoginname, "in", receiverLoginNames));
|
||||
sendSmsMessage(title, content, type, users, config);
|
||||
|
||||
log.info("短信消息发送完成(按登录名),标题:{},接收人数量:{}", title, users.size());
|
||||
} catch (Exception e) {
|
||||
log.error("短信消息发送失败(按登录名),标题:{},错误:{}", title, e.getMessage(), e);
|
||||
throw new RuntimeException("短信消息发送失败:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送短信消息
|
||||
*/
|
||||
private void sendSmsMessage(String title, String content, Integer type, List<Sys_user> users, JSONObject config) {
|
||||
for (Sys_user user : users) {
|
||||
try {
|
||||
String mobile = user.getMobile();
|
||||
if (mobile == null || mobile.trim().isEmpty()) {
|
||||
log.warn("用户{}没有手机号,跳过短信发送", user.getUsername());
|
||||
continue;
|
||||
}
|
||||
|
||||
// 构建短信内容
|
||||
String smsContent = buildSmsContent(title, content, type);
|
||||
|
||||
// 执行发送
|
||||
|
||||
boolean success = true;
|
||||
|
||||
if (success) {
|
||||
log.info("短信发送成功:用户{},手机号:{}", user.getUsername(), mobile);
|
||||
} else {
|
||||
log.warn("短信发送失败:用户{},手机号:{}", user.getUsername(), mobile);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("发送短信给用户{}时出错:{}", user.getUsername(), e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建短信内容
|
||||
*/
|
||||
private String buildSmsContent(String title, String content, Integer type) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
// 根据消息类型添加前缀
|
||||
if (type != null && type == 2) {
|
||||
sb.append("【待办通知】");
|
||||
} else {
|
||||
sb.append("【系统通知】");
|
||||
}
|
||||
|
||||
// 添加标题和内容
|
||||
sb.append(title);
|
||||
if (content != null && !content.trim().isEmpty()) {
|
||||
sb.append(":").append(content);
|
||||
}
|
||||
|
||||
// 限制短信长度(一般短信限制70个字符)
|
||||
String smsContent = sb.toString();
|
||||
if (smsContent.length() > 67) {
|
||||
smsContent = smsContent.substring(0, 67) + "...";
|
||||
}
|
||||
|
||||
return smsContent;
|
||||
}
|
||||
|
||||
}
|
||||
+30
-2
@@ -6,18 +6,24 @@ import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.dayofficework.message.service.GlobalMessageSendService;
|
||||
import com.budwk.app.zhgh.staffbenefit.huimin.models.Huimin;
|
||||
import com.budwk.app.zhgh.staffbenefit.huimin.service.HuiminService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@IocBean
|
||||
@At("/platform/huimin/manage")
|
||||
@Api(("惠民服务管理"))
|
||||
@@ -28,6 +34,9 @@ public class HuiminManageController {
|
||||
@Inject
|
||||
private HuiminService huiminService;
|
||||
|
||||
@Inject
|
||||
private GlobalMessageSendService globalMessageSendService;
|
||||
|
||||
@At("")
|
||||
@SaCheckPermission("huimin.manage")
|
||||
@Ok("beetl:/platform/zhgh/staffbenefit/huimin/manage/index.html")
|
||||
@@ -37,11 +46,30 @@ public class HuiminManageController {
|
||||
@At
|
||||
@SaCheckPermission("huimin.manage")
|
||||
public Result pageData(PageForm pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
t1.*
|
||||
FROM
|
||||
huimin t1
|
||||
LEFT JOIN activity_user_scope aus ON t1.groupId = aus.groupId
|
||||
AND aus.userId = @userId
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if(StrUtil.isNotBlank(pageForm.getSearchKeyword())){
|
||||
cnd.where().andLike(Huimin::getTitle, pageForm.getSearchKeyword());
|
||||
cnd.where().andLike("t1.title", "%" + pageForm.getSearchKeyword() + "%");
|
||||
}
|
||||
Pagination pagination = huiminService.listPage(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
|
||||
cnd.and(Cnd.exps("aus.groupId","is not",null).or("t1.groupId","is",null));
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = huiminService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
|
||||
String title = "审批待办";
|
||||
String content = "您有一个新的审批任务需要处理,请及时登录系统查看。";
|
||||
List<String> receiverIds = Arrays.asList("00198c31ee094466845979ab8dabf83b", "00266dbf9e014376ab76072851b1a8ac");
|
||||
|
||||
// 自动发送到所有启用的渠道
|
||||
globalMessageSendService.sendMessage(title, content, 2, receiverIds, null);
|
||||
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user