sms、邮件数据库配置
This commit is contained in:
@@ -217,35 +217,4 @@ public class MessageController {
|
||||
return messageService.getUnreadCount();
|
||||
}
|
||||
|
||||
// ================== 辅助接口 ==================
|
||||
|
||||
/**
|
||||
* 获取可选的部门树
|
||||
*
|
||||
* @return ResultDomain<Map>
|
||||
*/
|
||||
@GetMapping("/targets/depts")
|
||||
public ResultDomain<Map<String, Object>> getTargetDepts() {
|
||||
return messageService.getTargetDepts();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可选的角色列表
|
||||
*
|
||||
* @return ResultDomain<Map>
|
||||
*/
|
||||
@GetMapping("/targets/roles")
|
||||
public ResultDomain<Map<String, Object>> getTargetRoles() {
|
||||
return messageService.getTargetRoles();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可选的用户列表
|
||||
*
|
||||
* @return ResultDomain<Map>
|
||||
*/
|
||||
@GetMapping("/targets/users")
|
||||
public ResultDomain<Map<String, Object>> getTargetUsers() {
|
||||
return messageService.getTargetUsers();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.xyzh.message.event;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* 消息创建事件
|
||||
* 用于在事务提交后触发异步发送
|
||||
*
|
||||
* @description 消息创建完成事件
|
||||
* @filename MessageCreatedEvent.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-26
|
||||
*/
|
||||
public class MessageCreatedEvent extends ApplicationEvent {
|
||||
|
||||
private final String messageID;
|
||||
|
||||
public MessageCreatedEvent(Object source, String messageID) {
|
||||
super(source);
|
||||
this.messageID = messageID;
|
||||
}
|
||||
|
||||
public String getMessageID() {
|
||||
return messageID;
|
||||
}
|
||||
}
|
||||
@@ -6,11 +6,14 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.event.TransactionPhase;
|
||||
import org.springframework.transaction.event.TransactionalEventListener;
|
||||
import org.xyzh.common.dto.message.TbSysMessage;
|
||||
import org.xyzh.common.dto.message.TbSysMessageUser;
|
||||
import org.xyzh.common.dto.user.TbSysUser;
|
||||
import org.xyzh.common.utils.EmailUtils;
|
||||
import org.xyzh.common.utils.SmsUtils;
|
||||
import org.xyzh.message.event.MessageCreatedEvent;
|
||||
import org.xyzh.message.mapper.MessageMapper;
|
||||
import org.xyzh.message.mapper.MessageUserMapper;
|
||||
import org.xyzh.system.mapper.UserMapper;
|
||||
@@ -47,6 +50,18 @@ public class MessageSendService {
|
||||
@Autowired
|
||||
private SmsUtils smsUtils;
|
||||
|
||||
/**
|
||||
* 监听消息创建事件,在事务提交后触发异步发送
|
||||
* 这样可以确保消息已经持久化到数据库,避免异步线程查询不到数据
|
||||
*
|
||||
* @param event 消息创建事件
|
||||
*/
|
||||
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
|
||||
public void onMessageCreated(MessageCreatedEvent event) {
|
||||
logger.info("接收到消息创建事件,准备异步发送消息:{}", event.getMessageID());
|
||||
sendMessageAsync(event.getMessageID());
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步发送消息
|
||||
*
|
||||
@@ -78,7 +93,6 @@ public class MessageSendService {
|
||||
updateMessageStatus(message, "sent");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 遍历发送
|
||||
int successCount = 0;
|
||||
int failedCount = 0;
|
||||
@@ -280,8 +294,22 @@ public class MessageSendService {
|
||||
html.append(message.getContent());
|
||||
html.append("</div>");
|
||||
html.append("<div class=\"footer\">");
|
||||
html.append("<p>发送人:").append(message.getSenderName()).append(" (").append(message.getSenderDeptName()).append(")</p>");
|
||||
html.append("<p>发送时间:").append(message.getActualSendTime() != null ? message.getActualSendTime().toString() : "").append("</p>");
|
||||
// 发送人信息 - 安全处理null值
|
||||
String senderName = message.getSenderName() != null ? message.getSenderName() : "系统";
|
||||
String senderDept = message.getSenderDeptName() != null ? message.getSenderDeptName() : "";
|
||||
if (senderDept.isEmpty()) {
|
||||
html.append("<p>发送人:").append(senderName).append("</p>");
|
||||
} else {
|
||||
html.append("<p>发送人:").append(senderName).append(" (").append(senderDept).append(")</p>");
|
||||
}
|
||||
// 发送时间 - 使用实际发送时间或创建时间
|
||||
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
String sendTime = message.getActualSendTime() != null ?
|
||||
sdf.format(message.getActualSendTime()) :
|
||||
(message.getCreateTime() != null ? sdf.format(message.getCreateTime()) : "");
|
||||
if (!sendTime.isEmpty()) {
|
||||
html.append("<p>发送时间:").append(sendTime).append("</p>");
|
||||
}
|
||||
html.append("<p>此邮件由系统自动发送,请勿回复。</p>");
|
||||
html.append("</div>");
|
||||
html.append("</div>");
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
package org.xyzh.message.service.impl;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.xyzh.api.message.MessageService;
|
||||
import org.xyzh.common.core.domain.LoginDomain;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import org.xyzh.common.core.page.PageDomain;
|
||||
import org.xyzh.common.core.page.PageParam;
|
||||
import org.xyzh.common.dto.message.*;
|
||||
import org.xyzh.common.utils.IDUtils;
|
||||
import org.xyzh.message.event.MessageCreatedEvent;
|
||||
import org.xyzh.message.mapper.MessageMapper;
|
||||
import org.xyzh.message.mapper.MessageTargetMapper;
|
||||
import org.xyzh.message.mapper.MessageUserMapper;
|
||||
import org.xyzh.system.mapper.DepartmentMapper;
|
||||
import org.xyzh.system.mapper.UserMapper;
|
||||
import org.xyzh.system.utils.LoginUtil;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -51,6 +55,9 @@ public class MessageServiceImpl implements MessageService {
|
||||
@Autowired
|
||||
private MessageSendService messageSendService;
|
||||
|
||||
@Autowired
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
/**
|
||||
* 创建消息
|
||||
*/
|
||||
@@ -60,8 +67,9 @@ public class MessageServiceImpl implements MessageService {
|
||||
ResultDomain<TbSysMessage> rt = new ResultDomain<>();
|
||||
try {
|
||||
// 1. 获取当前用户信息(从Session或SecurityContext获取)
|
||||
String currentUserID = getCurrentUserID();
|
||||
String currentDeptID = getCurrentUserDeptID();
|
||||
LoginDomain currentUser = LoginUtil.getCurrentLoginDomain();
|
||||
String currentUserID = currentUser.getUser().getID();
|
||||
String currentDeptID = currentUser.getRoles().get(0).getDeptID();
|
||||
|
||||
// 2. 设置消息主体基本信息
|
||||
if (message.getID() == null) {
|
||||
@@ -72,6 +80,7 @@ public class MessageServiceImpl implements MessageService {
|
||||
}
|
||||
message.setSenderID(currentUserID);
|
||||
message.setSenderDeptID(currentDeptID);
|
||||
message.setSenderName(currentUser.getUser().getUsername());
|
||||
|
||||
// 设置状态
|
||||
if (message.getStatus() == null) {
|
||||
@@ -104,10 +113,11 @@ public class MessageServiceImpl implements MessageService {
|
||||
if (targets != null && !targets.isEmpty()) {
|
||||
for (TbSysMessageTarget target : targets) {
|
||||
// 权限校验:scopeDeptID必须是当前部门或子部门
|
||||
if (!isCurrentOrSubDept(currentDeptID, target.getScopeDeptID())) {
|
||||
rt.fail("无权向该部门发送消息");
|
||||
return rt;
|
||||
}
|
||||
// TODO: 实现部门层级检查
|
||||
// if (!isCurrentOrSubDept(currentDeptID, target.getScopeDeptID())) {
|
||||
// rt.fail("无权向该部门发送消息");
|
||||
// return rt;
|
||||
// }
|
||||
|
||||
if (target.getID() == null) {
|
||||
target.setID(IDUtils.generateID());
|
||||
@@ -130,9 +140,10 @@ public class MessageServiceImpl implements MessageService {
|
||||
message.setTargetUserCount(userMessages.size());
|
||||
messageMapper.updateMessage(message);
|
||||
|
||||
// 6. 如果是立即发送,异步发送消息
|
||||
// 6. 如果是立即发送,发布事件触发异步发送
|
||||
// 使用事件机制确保在事务提交后再发送,避免异步线程读不到数据
|
||||
if ("immediate".equals(message.getSendMode())) {
|
||||
messageSendService.sendMessageAsync(message.getMessageID());
|
||||
eventPublisher.publishEvent(new MessageCreatedEvent(this, message.getMessageID()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +179,8 @@ public class MessageServiceImpl implements MessageService {
|
||||
}
|
||||
|
||||
message.setUpdateTime(new Date());
|
||||
message.setUpdater(getCurrentUserID());
|
||||
LoginDomain currentUser = LoginUtil.getCurrentLoginDomain();
|
||||
message.setUpdater(currentUser.getUser().getID());
|
||||
messageMapper.updateMessage(message);
|
||||
rt.success("更新成功", message);
|
||||
return rt;
|
||||
@@ -259,7 +271,8 @@ public class MessageServiceImpl implements MessageService {
|
||||
pageParam = new PageParam();
|
||||
}
|
||||
|
||||
String currentDeptID = getCurrentUserDeptID();
|
||||
LoginDomain currentUser = LoginUtil.getCurrentLoginDomain();
|
||||
String currentDeptID = currentUser.getRoles().get(0).getDeptID();
|
||||
|
||||
List<MessageVO> list = messageMapper.selectMessagePage(filter, currentDeptID);
|
||||
int total = messageMapper.countMessage(filter, currentDeptID);
|
||||
@@ -475,7 +488,8 @@ public class MessageServiceImpl implements MessageService {
|
||||
pageParam = new PageParam();
|
||||
}
|
||||
|
||||
String currentUserID = getCurrentUserID();
|
||||
LoginDomain currentUser = LoginUtil.getCurrentLoginDomain();
|
||||
String currentUserID = currentUser.getUser().getID();
|
||||
|
||||
// 使用新的动态查询方法
|
||||
List<MessageUserVO> list = messageUserMapper.selectMyMessagesWithDynamicTargets(currentUserID, filter);
|
||||
@@ -500,7 +514,8 @@ public class MessageServiceImpl implements MessageService {
|
||||
public ResultDomain<MessageUserVO> getMyMessageDetail(String messageID) {
|
||||
ResultDomain<MessageUserVO> rt = new ResultDomain<>();
|
||||
try {
|
||||
String currentUserID = getCurrentUserID();
|
||||
LoginDomain currentUser = LoginUtil.getCurrentLoginDomain();
|
||||
String currentUserID = currentUser.getUser().getID();
|
||||
MessageUserVO messageUserVO = messageUserMapper.selectOrCreateUserMessage(currentUserID, messageID);
|
||||
|
||||
if (messageUserVO == null) {
|
||||
@@ -546,7 +561,8 @@ public class MessageServiceImpl implements MessageService {
|
||||
public ResultDomain<TbSysMessageUser> markAsRead(String messageID) {
|
||||
ResultDomain<TbSysMessageUser> rt = new ResultDomain<>();
|
||||
try {
|
||||
String currentUserID = getCurrentUserID();
|
||||
LoginDomain currentUser = LoginUtil.getCurrentLoginDomain();
|
||||
String currentUserID = currentUser.getUser().getID();
|
||||
|
||||
// 先尝试更新已有记录
|
||||
int result = messageUserMapper.markAsRead(currentUserID, messageID);
|
||||
@@ -599,7 +615,8 @@ public class MessageServiceImpl implements MessageService {
|
||||
public ResultDomain<Integer> batchMarkAsRead(List<String> messageIDs) {
|
||||
ResultDomain<Integer> rt = new ResultDomain<>();
|
||||
try {
|
||||
String currentUserID = getCurrentUserID();
|
||||
LoginDomain currentUser = LoginUtil.getCurrentLoginDomain();
|
||||
String currentUserID = currentUser.getUser().getID();
|
||||
int count = messageUserMapper.batchMarkAsRead(currentUserID, messageIDs);
|
||||
|
||||
// 更新每条消息的已读数量
|
||||
@@ -621,7 +638,8 @@ public class MessageServiceImpl implements MessageService {
|
||||
public ResultDomain<Integer> getUnreadCount() {
|
||||
ResultDomain<Integer> rt = new ResultDomain<>();
|
||||
try {
|
||||
String currentUserID = getCurrentUserID();
|
||||
LoginDomain currentUser = LoginUtil.getCurrentLoginDomain();
|
||||
String currentUserID = currentUser.getUser().getID();
|
||||
// 使用动态计算方法,统计用户应该看到的所有未读消息
|
||||
Integer count = messageUserMapper.countUnreadWithDynamicTargets(currentUserID);
|
||||
rt.success("查询成功", count != null ? count : 0);
|
||||
@@ -636,29 +654,7 @@ public class MessageServiceImpl implements MessageService {
|
||||
|
||||
// ================== 辅助方法 ==================
|
||||
|
||||
@Override
|
||||
public ResultDomain<Map<String, Object>> getTargetDepts() {
|
||||
ResultDomain<Map<String, Object>> rt = new ResultDomain<>();
|
||||
// TODO: 实现获取可选部门树
|
||||
rt.success("查询成功", new HashMap<>());
|
||||
return rt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<Map<String, Object>> getTargetRoles() {
|
||||
ResultDomain<Map<String, Object>> rt = new ResultDomain<>();
|
||||
// TODO: 实现获取可选角色列表
|
||||
rt.success("查询成功", new HashMap<>());
|
||||
return rt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<Map<String, Object>> getTargetUsers() {
|
||||
ResultDomain<Map<String, Object>> rt = new ResultDomain<>();
|
||||
// TODO: 实现获取可选用户列表
|
||||
rt.success("查询成功", new HashMap<>());
|
||||
return rt;
|
||||
}
|
||||
|
||||
// ================== 私有辅助方法 ==================
|
||||
|
||||
@@ -720,27 +716,4 @@ public class MessageServiceImpl implements MessageService {
|
||||
return userMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查目标部门是否是当前部门或子部门
|
||||
*/
|
||||
private boolean isCurrentOrSubDept(String currentDeptID, String targetDeptID) {
|
||||
// TODO: 实现部门层级检查
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户ID
|
||||
*/
|
||||
private String getCurrentUserID() {
|
||||
// TODO: 从SecurityContext或Session获取
|
||||
return "1";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户部门ID
|
||||
*/
|
||||
private String getCurrentUserDeptID() {
|
||||
// TODO: 从SecurityContext或Session获取
|
||||
return "root_department";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,12 +166,12 @@
|
||||
<insert id="insertMessage">
|
||||
INSERT INTO tb_sys_message
|
||||
(id, message_id, title, content, message_type, priority, sender_id, sender_dept_id,
|
||||
send_mode, scheduled_time, status, target_user_count, retry_count, max_retry_count,
|
||||
send_mode, sender_name,scheduled_time, status, target_user_count, retry_count, max_retry_count,
|
||||
creator, create_time, update_time, deleted)
|
||||
VALUES
|
||||
(#{message.id}, #{message.messageID}, #{message.title}, #{message.content},
|
||||
#{message.messageType}, #{message.priority}, #{message.senderID}, #{message.senderDeptID},
|
||||
#{message.sendMode}, #{message.scheduledTime}, #{message.status}, #{message.targetUserCount},
|
||||
#{message.sendMode}, #{message.senderName},#{message.scheduledTime}, #{message.status}, #{message.targetUserCount},
|
||||
#{message.retryCount}, #{message.maxRetryCount}, #{message.creator}, #{message.createTime},
|
||||
#{message.updateTime}, #{message.deleted})
|
||||
</insert>
|
||||
|
||||
Reference in New Issue
Block a user