From 8b6b4652cee649d2e2d368a8f80a9b7ce2de7e5f Mon Sep 17 00:00:00 2001 From: dengqichen Date: Thu, 13 Nov 2025 10:31:58 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9E=84=E5=BB=BA=E9=80=9A?= =?UTF-8?q?=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/NotificationChannelServiceImpl.java | 72 ++++++------- .../impl/NotificationSendServiceImpl.java | 102 ++++++++++++++++++ .../service/impl/NotificationServiceImpl.java | 2 +- 3 files changed, 137 insertions(+), 39 deletions(-) create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/notification/service/impl/NotificationSendServiceImpl.java diff --git a/backend/src/main/java/com/qqchen/deploy/backend/notification/service/impl/NotificationChannelServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/notification/service/impl/NotificationChannelServiceImpl.java index c52b9b50..f90ee514 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/notification/service/impl/NotificationChannelServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/notification/service/impl/NotificationChannelServiceImpl.java @@ -35,19 +35,15 @@ import static com.qqchen.deploy.backend.framework.annotation.ServiceType.Type.DA @Slf4j @Service @ServiceType(DATABASE) -public class NotificationChannelServiceImpl - extends BaseServiceImpl - implements INotificationChannelService, INotificationSendService { - +public class NotificationChannelServiceImpl extends BaseServiceImpl 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配置转换为具体的配置类型 */ diff --git a/backend/src/main/java/com/qqchen/deploy/backend/notification/service/impl/NotificationSendServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/notification/service/impl/NotificationSendServiceImpl.java new file mode 100644 index 00000000..de662b9e --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/notification/service/impl/NotificationSendServiceImpl.java @@ -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()); + }; + } +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/notification/service/impl/NotificationServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/notification/service/impl/NotificationServiceImpl.java index 53ee70ca..58915667 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/notification/service/impl/NotificationServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/notification/service/impl/NotificationServiceImpl.java @@ -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()) {