增加构建通知

This commit is contained in:
dengqichen 2025-11-13 10:31:58 +08:00
parent e5e20a4dbb
commit 8b6b4652ce
3 changed files with 137 additions and 39 deletions

View File

@ -35,19 +35,15 @@ import static com.qqchen.deploy.backend.framework.annotation.ServiceType.Type.DA
@Slf4j
@Service
@ServiceType(DATABASE)
public class NotificationChannelServiceImpl
extends BaseServiceImpl<NotificationChannel, NotificationChannelDTO, NotificationChannelQuery, Long>
implements INotificationChannelService, INotificationSendService {
public class NotificationChannelServiceImpl extends BaseServiceImpl<NotificationChannel, NotificationChannelDTO, NotificationChannelQuery, Long> implements INotificationChannelService {
@Resource
private INotificationChannelRepository notificationChannelRepository;
@Resource
private NotificationChannelConverter notificationChannelConverter;
@Resource
private NotificationChannelAdapterFactory adapterFactory;
@Override
protected void validateUniqueConstraints(NotificationChannelDTO dto) {
// 检查渠道名称唯一性
@ -55,84 +51,84 @@ public class NotificationChannelServiceImpl
throw new UniqueConstraintException(ResponseCode.CONFLICT, "name", dto.getName());
}
}
@Override
@Transactional
public boolean testConnection(Long id) {
// 1. 查询渠道配置
NotificationChannel channel = notificationChannelRepository.findById(id)
.orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND));
log.info("开始测试通知渠道连接: id={}, name={}, type={}",
log.info("开始测试通知渠道连接: id={}, name={}, type={}",
id, channel.getName(), channel.getChannelType());
// 2. 获取对应的适配器
INotificationChannelAdapter adapter;
try {
adapter = adapterFactory.getAdapter(channel.getChannelType());
} catch (IllegalArgumentException e) {
log.error("获取通知渠道适配器失败: {}", e.getMessage());
throw new BusinessException(ResponseCode.ERROR, new Object[]{"不支持的渠道类型: " + channel.getChannelType()});
throw new BusinessException(ResponseCode.ERROR, new Object[] {"不支持的渠道类型: " + channel.getChannelType()});
}
// 3. 转换配置
BaseNotificationConfig config = convertConfig(channel);
// 4. 执行连接测试
try {
adapter.testConnection(config);
log.info("通知渠道连接测试成功: id={}, name={}", id, channel.getName());
return true;
return true;
} catch (Exception e) {
log.error("通知渠道连接测试失败: id={}, name={}, 错误: {}",
log.error("通知渠道连接测试失败: id={}, name={}, 错误: {}",
id, channel.getName(), e.getMessage(), e);
throw new BusinessException(ResponseCode.ERROR, new Object[]{"连接测试失败: " + e.getMessage()});
throw new BusinessException(ResponseCode.ERROR, new Object[] {"连接测试失败: " + e.getMessage()});
}
}
@Override
@Transactional
public void enable(Long id) {
NotificationChannel channel = notificationChannelRepository.findById(id)
.orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND));
channel.setEnabled(true);
notificationChannelRepository.save(channel);
log.info("启用通知渠道: id={}, name={}", id, channel.getName());
}
@Override
@Transactional
public void disable(Long id) {
NotificationChannel channel = notificationChannelRepository.findById(id)
.orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND));
channel.setEnabled(false);
notificationChannelRepository.save(channel);
log.info("禁用通知渠道: id={}, name={}", id, channel.getName());
}
public void send(BaseSendNotificationRequest request) {
// 1. 参数校验
if (request == null || request.getChannelId() == null) {
throw new BusinessException(ResponseCode.INVALID_PARAM);
}
if (request.getContent() == null || request.getContent().isEmpty()) {
throw new BusinessException(ResponseCode.INVALID_PARAM);
}
// 2. 查询渠道配置
NotificationChannel channel = notificationChannelRepository.findById(request.getChannelId())
.orElseThrow(() -> new BusinessException(ResponseCode.NOTIFICATION_CHANNEL_NOT_FOUND));
// 3. 校验渠道状态
if (!channel.getEnabled()) {
throw new BusinessException(ResponseCode.NOTIFICATION_CHANNEL_DISABLED);
}
// 4. 获取对应的适配器
INotificationChannelAdapter adapter;
try {
@ -141,28 +137,28 @@ public class NotificationChannelServiceImpl
log.error("获取通知渠道适配器失败: {}", e.getMessage());
throw new BusinessException(ResponseCode.ERROR);
}
// 5. 转换配置
BaseNotificationConfig config = convertConfig(channel);
// 6. 发送通知
try {
log.info("发送通知 - 渠道ID: {}, 渠道类型: {}, 内容: {}",
log.info("发送通知 - 渠道ID: {}, 渠道类型: {}, 内容: {}",
channel.getId(), channel.getChannelType(), request.getContent());
adapter.send(config, request);
log.info("通知发送成功 - 渠道ID: {}", channel.getId());
} catch (IllegalArgumentException e) {
// 配置错误 Webhook Key 未配置
log.error("通知渠道配置错误 - 渠道ID: {}, 错误: {}", channel.getId(), e.getMessage());
throw new BusinessException(ResponseCode.NOTIFICATION_CHANNEL_CONFIG_ERROR, new Object[]{e.getMessage()});
throw new BusinessException(ResponseCode.NOTIFICATION_CHANNEL_CONFIG_ERROR, new Object[] {e.getMessage()});
} catch (Exception e) {
log.error("通知发送失败 - 渠道ID: {}, 错误: {}", channel.getId(), e.getMessage(), e);
throw new BusinessException(ResponseCode.NOTIFICATION_SEND_FAILED, new Object[]{e.getMessage()});
throw new BusinessException(ResponseCode.NOTIFICATION_SEND_FAILED, new Object[] {e.getMessage()});
}
}
/**
* 将Map配置转换为具体的配置类型
*/

View File

@ -0,0 +1,102 @@
package com.qqchen.deploy.backend.notification.service.impl;
import com.qqchen.deploy.backend.framework.annotation.ServiceType;
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
import com.qqchen.deploy.backend.framework.exception.BusinessException;
import com.qqchen.deploy.backend.framework.exception.UniqueConstraintException;
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
import com.qqchen.deploy.backend.framework.utils.JsonUtils;
import com.qqchen.deploy.backend.notification.adapter.INotificationChannelAdapter;
import com.qqchen.deploy.backend.notification.dto.BaseSendNotificationRequest;
import com.qqchen.deploy.backend.notification.dto.NotificationChannelDTO;
import com.qqchen.deploy.backend.notification.dto.NotificationChannelQuery;
import com.qqchen.deploy.backend.notification.entity.NotificationChannel;
import com.qqchen.deploy.backend.notification.entity.config.BaseNotificationConfig;
import com.qqchen.deploy.backend.notification.entity.config.EmailNotificationConfig;
import com.qqchen.deploy.backend.notification.entity.config.WeworkNotificationConfig;
import com.qqchen.deploy.backend.notification.factory.NotificationChannelAdapterFactory;
import com.qqchen.deploy.backend.notification.repository.INotificationChannelRepository;
import com.qqchen.deploy.backend.notification.service.INotificationChannelService;
import com.qqchen.deploy.backend.notification.service.INotificationSendService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import static com.qqchen.deploy.backend.framework.annotation.ServiceType.Type.DATABASE;
/**
* 通知渠道Service实现
*
* @author qqchen
* @since 2025-10-22
*/
@Slf4j
@Service
@ServiceType(DATABASE)
public class NotificationSendServiceImpl implements INotificationSendService {
@Resource
private INotificationChannelRepository notificationChannelRepository;
@Resource
private NotificationChannelAdapterFactory adapterFactory;
public void send(BaseSendNotificationRequest request) {
// 1. 参数校验
if (request == null || request.getChannelId() == null) {
throw new BusinessException(ResponseCode.INVALID_PARAM);
}
if (request.getContent() == null || request.getContent().isEmpty()) {
throw new BusinessException(ResponseCode.INVALID_PARAM);
}
// 2. 查询渠道配置
NotificationChannel channel = notificationChannelRepository.findById(request.getChannelId()).orElseThrow(() -> new BusinessException(ResponseCode.NOTIFICATION_CHANNEL_NOT_FOUND));
// 3. 校验渠道状态
if (!channel.getEnabled()) {
throw new BusinessException(ResponseCode.NOTIFICATION_CHANNEL_DISABLED);
}
// 4. 获取对应的适配器
INotificationChannelAdapter adapter;
try {
adapter = adapterFactory.getAdapter(channel.getChannelType());
} catch (IllegalArgumentException e) {
log.error("获取通知渠道适配器失败: {}", e.getMessage());
throw new BusinessException(ResponseCode.ERROR);
}
// 5. 转换配置
BaseNotificationConfig config = convertConfig(channel);
// 6. 发送通知
try {
log.info("发送通知 - 渠道ID: {}, 渠道类型: {}, 内容: {}", channel.getId(), channel.getChannelType(), request.getContent());
adapter.send(config, request);
log.info("通知发送成功 - 渠道ID: {}", channel.getId());
} catch (IllegalArgumentException e) {
// 配置错误 Webhook Key 未配置
log.error("通知渠道配置错误 - 渠道ID: {}, 错误: {}", channel.getId(), e.getMessage());
throw new BusinessException(ResponseCode.NOTIFICATION_CHANNEL_CONFIG_ERROR, new Object[] {e.getMessage()});
} catch (Exception e) {
log.error("通知发送失败 - 渠道ID: {}, 错误: {}", channel.getId(), e.getMessage(), e);
throw new BusinessException(ResponseCode.NOTIFICATION_SEND_FAILED, new Object[] {e.getMessage()});
}
}
/**
* 将Map配置转换为具体的配置类型
*/
private BaseNotificationConfig convertConfig(NotificationChannel channel) {
return switch (channel.getChannelType()) {
case WEWORK -> JsonUtils.fromMap(channel.getConfig(), WeworkNotificationConfig.class);
case EMAIL -> JsonUtils.fromMap(channel.getConfig(), EmailNotificationConfig.class);
default -> throw new IllegalArgumentException("不支持的渠道类型: " + channel.getChannelType());
};
}
}

View File

@ -71,7 +71,7 @@ public class NotificationServiceImpl implements INotificationService {
}
// 5. 渲染模板内容
String content = notificationTemplateService.renderTemplate(template.getCode(), request.getParams());
String content = notificationTemplateService.renderByCode(template.getCode(), request.getParams());
// 6. 根据渠道类型发送通知
switch (template.getChannelType()) {