增加构建通知

This commit is contained in:
dengqichen 2025-11-13 11:15:50 +08:00
parent 8b6b4652ce
commit 5205c6aaa1
6 changed files with 57 additions and 42 deletions

View File

@ -25,63 +25,61 @@ import java.util.Properties;
@Slf4j @Slf4j
@Component @Component
public class EmailChannelAdapter implements INotificationChannelAdapter<EmailNotificationConfig, EmailSendNotificationRequest> { public class EmailChannelAdapter implements INotificationChannelAdapter<EmailNotificationConfig, EmailSendNotificationRequest> {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override @Override
public void send(EmailNotificationConfig emailConfig, EmailSendNotificationRequest request) throws Exception { public void send(EmailNotificationConfig emailConfig, EmailSendNotificationRequest request) throws Exception {
// 1. 校验配置 // 1. 校验配置
validateEmailConfig(emailConfig); validateEmailConfig(emailConfig);
// 2. 创建JavaMailSender // 2. 创建JavaMailSender
JavaMailSenderImpl mailSender = createMailSender(emailConfig); JavaMailSenderImpl mailSender = createMailSender(emailConfig);
// 3. 校验收件人 // 3. 校验收件人
if (CollectionUtils.isEmpty(request.getToReceivers())) { if (CollectionUtils.isEmpty(request.getToReceivers())) {
throw new IllegalArgumentException("收件人列表不能为空"); throw new IllegalArgumentException("收件人列表不能为空");
} }
// 4. 构建邮件 // 4. 构建邮件
MimeMessage mimeMessage = mailSender.createMimeMessage(); MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8"); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
// 设置发件人 // 设置发件人
if (emailConfig.getFromName() != null && !emailConfig.getFromName().isEmpty()) { if (emailConfig.getFromName() != null && !emailConfig.getFromName().isEmpty()) {
helper.setFrom(new InternetAddress(emailConfig.getFrom(), emailConfig.getFromName(), "UTF-8")); helper.setFrom(new InternetAddress(emailConfig.getFrom(), emailConfig.getFromName(), "UTF-8"));
} else { } else {
helper.setFrom(emailConfig.getFrom()); helper.setFrom(emailConfig.getFrom());
} }
// 设置收件人 // 设置收件人
helper.setTo(request.getToReceivers().toArray(new String[0])); helper.setTo(request.getToReceivers().toArray(new String[0]));
// 设置抄送 // 设置抄送
if (!CollectionUtils.isEmpty(request.getCcReceivers())) { if (!CollectionUtils.isEmpty(request.getCcReceivers())) {
helper.setCc(request.getCcReceivers().toArray(new String[0])); helper.setCc(request.getCcReceivers().toArray(new String[0]));
} }
// 设置密送 // 设置密送
if (!CollectionUtils.isEmpty(request.getBccReceivers())) { if (!CollectionUtils.isEmpty(request.getBccReceivers())) {
helper.setBcc(request.getBccReceivers().toArray(new String[0])); helper.setBcc(request.getBccReceivers().toArray(new String[0]));
} }
// 设置主题 // 设置主题
helper.setSubject(request.getSubject()); helper.setSubject(request.getSubject());
// 设置内容支持HTML // 设置内容支持HTML
helper.setText(request.getContent(), request.getIsHtml() != null ? request.getIsHtml() : false); helper.setText(request.getContent(), request.getIsHtml() != null ? request.getIsHtml() : false);
// 5. 发送邮件 // 5. 发送邮件
log.info("发送邮件通知 - 收件人: {}, 主题: {}", request.getToReceivers(), request.getSubject()); log.info("发送邮件通知 - 收件人: {}, 主题: {}", request.getToReceivers(), request.getSubject());
mailSender.send(mimeMessage); mailSender.send(mimeMessage);
log.info("邮件通知发送成功"); log.info("邮件通知发送成功");
} }
@Override @Override
public NotificationChannelTypeEnum supportedType() { public NotificationChannelTypeEnum supportedType() {
return NotificationChannelTypeEnum.EMAIL; return NotificationChannelTypeEnum.EMAIL;
} }
@Override @Override
public String validateConfig(EmailNotificationConfig emailConfig) { public String validateConfig(EmailNotificationConfig emailConfig) {
try { try {
@ -91,18 +89,18 @@ public class EmailChannelAdapter implements INotificationChannelAdapter<EmailNot
return "配置验证失败: " + e.getMessage(); return "配置验证失败: " + e.getMessage();
} }
} }
@Override @Override
public void testConnection(EmailNotificationConfig emailConfig) throws Exception { public void testConnection(EmailNotificationConfig emailConfig) throws Exception {
// 1. 校验配置 // 1. 校验配置
validateEmailConfig(emailConfig); validateEmailConfig(emailConfig);
// 3. 创建JavaMailSender // 3. 创建JavaMailSender
JavaMailSenderImpl mailSender = createMailSender(emailConfig); JavaMailSenderImpl mailSender = createMailSender(emailConfig);
// 4. 测试SMTP连接 // 4. 测试SMTP连接
log.info("测试SMTP连接 - 服务器: {}:{}", emailConfig.getSmtpHost(), emailConfig.getSmtpPort()); log.info("测试SMTP连接 - 服务器: {}:{}", emailConfig.getSmtpHost(), emailConfig.getSmtpPort());
try { try {
// 测试连接 // 测试连接
mailSender.testConnection(); mailSender.testConnection();
@ -111,11 +109,11 @@ public class EmailChannelAdapter implements INotificationChannelAdapter<EmailNot
log.error("SMTP连接测试失败: {}", e.getMessage()); log.error("SMTP连接测试失败: {}", e.getMessage());
throw new Exception("SMTP连接失败: " + e.getMessage(), e); throw new Exception("SMTP连接失败: " + e.getMessage(), e);
} }
// 5. 测试连接成功不发送测试邮件因为没有默认收件人 // 5. 测试连接成功不发送测试邮件因为没有默认收件人
log.info("邮件通知渠道配置测试成功 - SMTP连接正常"); log.info("邮件通知渠道配置测试成功 - SMTP连接正常");
} }
/** /**
* 校验邮件配置 * 校验邮件配置
*/ */
@ -123,24 +121,24 @@ public class EmailChannelAdapter implements INotificationChannelAdapter<EmailNot
if (config.getSmtpHost() == null || config.getSmtpHost().isEmpty()) { if (config.getSmtpHost() == null || config.getSmtpHost().isEmpty()) {
throw new IllegalArgumentException("SMTP服务器地址不能为空"); throw new IllegalArgumentException("SMTP服务器地址不能为空");
} }
if (config.getSmtpPort() == null) { if (config.getSmtpPort() == null) {
throw new IllegalArgumentException("SMTP端口不能为空"); throw new IllegalArgumentException("SMTP端口不能为空");
} }
if (config.getUsername() == null || config.getUsername().isEmpty()) { if (config.getUsername() == null || config.getUsername().isEmpty()) {
throw new IllegalArgumentException("SMTP用户名不能为空"); throw new IllegalArgumentException("SMTP用户名不能为空");
} }
if (config.getPassword() == null || config.getPassword().isEmpty()) { if (config.getPassword() == null || config.getPassword().isEmpty()) {
throw new IllegalArgumentException("SMTP密码不能为空"); throw new IllegalArgumentException("SMTP密码不能为空");
} }
if (config.getFrom() == null || config.getFrom().isEmpty()) { if (config.getFrom() == null || config.getFrom().isEmpty()) {
throw new IllegalArgumentException("发件人邮箱不能为空"); throw new IllegalArgumentException("发件人邮箱不能为空");
} }
} }
/** /**
* 创建JavaMailSender * 创建JavaMailSender
*/ */
@ -150,22 +148,22 @@ public class EmailChannelAdapter implements INotificationChannelAdapter<EmailNot
mailSender.setPort(config.getSmtpPort()); mailSender.setPort(config.getSmtpPort());
mailSender.setUsername(config.getUsername()); mailSender.setUsername(config.getUsername());
mailSender.setPassword(config.getPassword()); mailSender.setPassword(config.getPassword());
// 设置邮件属性 // 设置邮件属性
Properties props = mailSender.getJavaMailProperties(); Properties props = mailSender.getJavaMailProperties();
props.put("mail.transport.protocol", "smtp"); props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.auth", "true"); props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true"); props.put("mail.smtp.starttls.enable", "true");
props.put("mail.debug", "false"); props.put("mail.debug", "false");
// 如果使用SSL // 如果使用SSL
if (Boolean.TRUE.equals(config.getUseSsl())) { if (Boolean.TRUE.equals(config.getUseSsl())) {
props.put("mail.smtp.ssl.enable", "true"); props.put("mail.smtp.ssl.enable", "true");
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
} }
return mailSender; return mailSender;
} }
} }

View File

@ -20,36 +20,41 @@ import java.util.Optional;
*/ */
@Repository @Repository
public interface INotificationTemplateRepository extends IBaseRepository<NotificationTemplate, Long> { public interface INotificationTemplateRepository extends IBaseRepository<NotificationTemplate, Long> {
/** /**
* 根据编码查找模板 * 根据编码查找模板
*/ */
Optional<NotificationTemplate> findByCode(String code); Optional<NotificationTemplate> findByCode(String code);
/** /**
* 根据编码和启用状态查找模板 * 根据编码和启用状态查找模板
*/ */
Optional<NotificationTemplate> findByCodeAndEnabled(String code, Boolean enabled); Optional<NotificationTemplate> findByCodeAndEnabled(String code, Boolean enabled);
@Query("SELECT t FROM NotificationTemplate t WHERE t.id = :id AND t.enabled = :enabled AND t.deleted = false")
Optional<NotificationTemplate> findByIdAndEnabled(@Param("id") Long id, @Param("enabled") Boolean enabled);
/** /**
* 根据渠道类型查找模板 * 根据渠道类型查找模板
*/ */
List<NotificationTemplate> findByChannelTypeAndEnabled(NotificationChannelTypeEnum channelType, Boolean enabled); List<NotificationTemplate> findByChannelTypeAndEnabled(NotificationChannelTypeEnum channelType, Boolean enabled);
/** /**
* 检查编码是否存在排除指定ID * 检查编码是否存在排除指定ID
*/ */
@Query("SELECT COUNT(t) > 0 FROM NotificationTemplate t WHERE t.code = :code AND t.id != :id") @Query("SELECT COUNT(t) > 0 FROM NotificationTemplate t WHERE t.code = :code AND t.id != :id")
boolean existsByCodeAndIdNot(@Param("code") String code, @Param("id") Long id); boolean existsByCodeAndIdNot(@Param("code") String code, @Param("id") Long id);
/** /**
* 分页查询模板 * 分页查询模板
*/ */
@Query("SELECT t FROM NotificationTemplate t WHERE " + @Query("SELECT t FROM NotificationTemplate t WHERE " +
"(:name IS NULL OR t.name LIKE %:name%) AND " + "(:name IS NULL OR t.name LIKE %:name%) AND " +
"(:code IS NULL OR t.code LIKE %:code%) AND " + "(:code IS NULL OR t.code LIKE %:code%) AND " +
"(:channelType IS NULL OR t.channelType = :channelType) AND " + "(:channelType IS NULL OR t.channelType = :channelType) AND " +
"(:enabled IS NULL OR t.enabled = :enabled)") "(:enabled IS NULL OR t.enabled = :enabled)")
Page<NotificationTemplate> findByConditions( Page<NotificationTemplate> findByConditions(
@Param("name") String name, @Param("name") String name,
@Param("code") String code, @Param("code") String code,

View File

@ -26,6 +26,8 @@ public interface INotificationTemplateService extends IBaseService<NotificationT
String renderByCode(String templateCode, Map<String, Object> params); String renderByCode(String templateCode, Map<String, Object> params);
String renderById(Long id, Map<String, Object> params);
/** /**
* 根据编码获取模板 * 根据编码获取模板

View File

@ -143,8 +143,7 @@ public class NotificationChannelServiceImpl extends BaseServiceImpl<Notification
// 6. 发送通知 // 6. 发送通知
try { try {
log.info("发送通知 - 渠道ID: {}, 渠道类型: {}, 内容: {}", log.info("发送通知 - 渠道ID: {}, 渠道类型: {}, 内容: {}", channel.getId(), channel.getChannelType(), request.getContent());
channel.getId(), channel.getChannelType(), request.getContent());
adapter.send(config, request); adapter.send(config, request);

View File

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

View File

@ -69,6 +69,12 @@ public class NotificationTemplateServiceImpl extends BaseServiceImpl<Notificatio
return processTemplate(template.getContentTemplate(), params); return processTemplate(template.getContentTemplate(), params);
} }
@Override
public String renderById(Long id, Map<String, Object> params) {
NotificationTemplate template = getTemplateById(id);
return processTemplate(template.getContentTemplate(), params);
}
@Override @Override
public NotificationTemplateDTO getByCode(String code) { public NotificationTemplateDTO getByCode(String code) {
@ -92,6 +98,11 @@ public class NotificationTemplateServiceImpl extends BaseServiceImpl<Notificatio
.orElseThrow(() -> new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_NOT_FOUND)); .orElseThrow(() -> new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_NOT_FOUND));
} }
private NotificationTemplate getTemplateById(Long id) {
return notificationTemplateRepository.findByIdAndEnabled(id, true)
.orElseThrow(() -> new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_NOT_FOUND));
}
/** /**
* FreeMarker模板处理 * FreeMarker模板处理