增加构建通知
This commit is contained in:
parent
9d425aa1f7
commit
49c65b6886
@ -3,10 +3,10 @@ package com.qqchen.deploy.backend.notification.converter;
|
||||
import com.qqchen.deploy.backend.framework.converter.BaseConverter;
|
||||
import com.qqchen.deploy.backend.framework.utils.JsonUtils;
|
||||
import com.qqchen.deploy.backend.notification.dto.NotificationTemplateDTO;
|
||||
import com.qqchen.deploy.backend.notification.dto.template.BaseTemplateConfigDTO;
|
||||
import com.qqchen.deploy.backend.notification.dto.template.EmailTemplateConfigDTO;
|
||||
import com.qqchen.deploy.backend.notification.dto.template.WeworkTemplateConfigDTO;
|
||||
import com.qqchen.deploy.backend.notification.entity.NotificationTemplate;
|
||||
import com.qqchen.deploy.backend.notification.entity.config.BaseTemplateConfig;
|
||||
import com.qqchen.deploy.backend.notification.entity.config.EmailTemplateConfig;
|
||||
import com.qqchen.deploy.backend.notification.entity.config.WeworkTemplateConfig;
|
||||
import com.qqchen.deploy.backend.notification.enums.NotificationChannelTypeEnum;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
@ -23,7 +23,7 @@ import java.util.Map;
|
||||
public interface NotificationTemplateConverter extends BaseConverter<NotificationTemplate, NotificationTemplateDTO> {
|
||||
|
||||
@Override
|
||||
@Mapping(target = "templateConfig", expression = "java(mapToTemplateConfigDTO(entity.getTemplateConfig(), entity.getChannelType()))")
|
||||
@Mapping(target = "templateConfig", expression = "java(mapToTemplateConfig(entity.getTemplateConfig(), entity.getChannelType()))")
|
||||
@Mapping(target = "extraData", ignore = true)
|
||||
NotificationTemplateDTO toDto(NotificationTemplate entity);
|
||||
|
||||
@ -43,27 +43,27 @@ public interface NotificationTemplateConverter extends BaseConverter<Notificatio
|
||||
void updateEntity(@org.mapstruct.MappingTarget NotificationTemplate entity, NotificationTemplateDTO dto);
|
||||
|
||||
/**
|
||||
* 将Map转换为TemplateConfigDTO
|
||||
* 将Map转换为BaseTemplateConfig(根据渠道类型自动识别)
|
||||
*/
|
||||
default BaseTemplateConfigDTO mapToTemplateConfigDTO(Map<String, Object> configMap, NotificationChannelTypeEnum channelType) {
|
||||
default BaseTemplateConfig mapToTemplateConfig(Map<String, Object> configMap, NotificationChannelTypeEnum channelType) {
|
||||
if (configMap == null || channelType == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return switch (channelType) {
|
||||
case WEWORK -> JsonUtils.fromMap(configMap, WeworkTemplateConfigDTO.class);
|
||||
case EMAIL -> JsonUtils.fromMap(configMap, EmailTemplateConfigDTO.class);
|
||||
case WEWORK -> JsonUtils.fromMap(configMap, WeworkTemplateConfig.class);
|
||||
case EMAIL -> JsonUtils.fromMap(configMap, EmailTemplateConfig.class);
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 将TemplateConfigDTO转换为Map
|
||||
* 将BaseTemplateConfig转换为Map
|
||||
*/
|
||||
default Map<String, Object> mapToTemplateConfigMap(BaseTemplateConfigDTO configDTO) {
|
||||
if (configDTO == null) {
|
||||
default Map<String, Object> mapToTemplateConfigMap(BaseTemplateConfig config) {
|
||||
if (config == null) {
|
||||
return null;
|
||||
}
|
||||
return JsonUtils.toMap(configDTO);
|
||||
return JsonUtils.toMap(config);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.qqchen.deploy.backend.notification.dto;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
|
||||
import com.qqchen.deploy.backend.notification.dto.template.BaseTemplateConfigDTO;
|
||||
import com.qqchen.deploy.backend.notification.entity.config.BaseTemplateConfig;
|
||||
import com.qqchen.deploy.backend.notification.enums.NotificationChannelTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
@ -47,5 +47,5 @@ public class NotificationTemplateDTO extends BaseDTO {
|
||||
private Boolean enabled = true;
|
||||
|
||||
@Schema(description = "模板配置(根据渠道类型不同而不同)")
|
||||
private BaseTemplateConfigDTO templateConfig;
|
||||
private BaseTemplateConfig templateConfig;
|
||||
}
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
package com.qqchen.deploy.backend.notification.dto.template;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.qqchen.deploy.backend.notification.enums.NotificationChannelTypeEnum;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 模板配置DTO基类
|
||||
* 用于数据传输层,与Entity层的BaseTemplateConfig对应
|
||||
*
|
||||
* 使用 PROPERTY 方式,通过 templateConfig 内部的 channelType 字段
|
||||
* 进行多态反序列化(子类通过 final 字段自动提供该值)
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
@Data
|
||||
@JsonTypeInfo(
|
||||
use = JsonTypeInfo.Id.NAME,
|
||||
include = JsonTypeInfo.As.PROPERTY,
|
||||
property = "channelType"
|
||||
)
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = WeworkTemplateConfigDTO.class, name = "WEWORK"),
|
||||
@JsonSubTypes.Type(value = EmailTemplateConfigDTO.class, name = "EMAIL")
|
||||
})
|
||||
public abstract class BaseTemplateConfigDTO {
|
||||
|
||||
/**
|
||||
* 获取渠道类型(与外层 NotificationTemplateDTO.channelType 保持一致)
|
||||
*/
|
||||
public abstract NotificationChannelTypeEnum getChannelType();
|
||||
}
|
||||
@ -1,42 +0,0 @@
|
||||
package com.qqchen.deploy.backend.notification.dto.template;
|
||||
|
||||
import com.qqchen.deploy.backend.notification.enums.EmailContentTypeEnum;
|
||||
import com.qqchen.deploy.backend.notification.enums.EmailPriorityEnum;
|
||||
import com.qqchen.deploy.backend.notification.enums.NotificationChannelTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 邮件模板配置DTO
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "邮件模板配置")
|
||||
public class EmailTemplateConfigDTO extends BaseTemplateConfigDTO {
|
||||
|
||||
/**
|
||||
* 渠道类型(用于Jackson反序列化,与外层保持一致)
|
||||
*/
|
||||
private final NotificationChannelTypeEnum channelType = NotificationChannelTypeEnum.EMAIL;
|
||||
|
||||
/**
|
||||
* 内容类型
|
||||
*/
|
||||
@Schema(description = "内容类型", example = "TEXT", allowableValues = {"TEXT", "HTML"})
|
||||
private EmailContentTypeEnum contentType = EmailContentTypeEnum.TEXT;
|
||||
|
||||
/**
|
||||
* 邮件优先级
|
||||
*/
|
||||
@Schema(description = "邮件优先级", example = "NORMAL", allowableValues = {"LOW", "NORMAL", "HIGH"})
|
||||
private EmailPriorityEnum priority = EmailPriorityEnum.NORMAL;
|
||||
|
||||
@Override
|
||||
public NotificationChannelTypeEnum getChannelType() {
|
||||
return NotificationChannelTypeEnum.EMAIL;
|
||||
}
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
package com.qqchen.deploy.backend.notification.dto.template;
|
||||
|
||||
import com.qqchen.deploy.backend.notification.enums.NotificationChannelTypeEnum;
|
||||
import com.qqchen.deploy.backend.notification.enums.WeworkMessageTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 企业微信模板配置DTO
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "企业微信模板配置")
|
||||
public class WeworkTemplateConfigDTO extends BaseTemplateConfigDTO {
|
||||
|
||||
/**
|
||||
* 渠道类型(用于Jackson反序列化,与外层保持一致)
|
||||
*/
|
||||
private final NotificationChannelTypeEnum channelType = NotificationChannelTypeEnum.WEWORK;
|
||||
|
||||
/**
|
||||
* 消息类型
|
||||
*/
|
||||
@Schema(description = "消息类型", example = "TEXT", allowableValues = {"TEXT", "MARKDOWN", "FILE"})
|
||||
private WeworkMessageTypeEnum messageType = WeworkMessageTypeEnum.TEXT;
|
||||
|
||||
@Override
|
||||
public NotificationChannelTypeEnum getChannelType() {
|
||||
return NotificationChannelTypeEnum.WEWORK;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,102 @@
|
||||
package com.qqchen.deploy.backend.notification.dto.wework;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 企业微信 Webhook 消息请求体
|
||||
* 对应企微官方API格式:https://developer.work.weixin.qq.com/document/path/91770
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-13
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class WeworkWebhookRequest {
|
||||
|
||||
/**
|
||||
* 消息类型:text、markdown、file
|
||||
*/
|
||||
@JsonProperty("msgtype")
|
||||
private String msgtype;
|
||||
|
||||
/**
|
||||
* 文本消息内容
|
||||
*/
|
||||
@JsonProperty("text")
|
||||
private TextContent text;
|
||||
|
||||
/**
|
||||
* Markdown消息内容
|
||||
*/
|
||||
@JsonProperty("markdown")
|
||||
private MarkdownContent markdown;
|
||||
|
||||
/**
|
||||
* 文件消息内容
|
||||
*/
|
||||
@JsonProperty("file")
|
||||
private FileContent file;
|
||||
|
||||
/**
|
||||
* 文本消息内容
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public static class TextContent {
|
||||
|
||||
/**
|
||||
* 文本内容,最长不超过2048个字节
|
||||
*/
|
||||
@JsonProperty("content")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* userid的列表,提醒群中的指定成员(@某个成员),@all表示提醒所有人
|
||||
*/
|
||||
@JsonProperty("mentioned_list")
|
||||
private List<String> mentionedList;
|
||||
|
||||
/**
|
||||
* 手机号列表,提醒手机号对应的群成员(@某个成员),@all表示提醒所有人
|
||||
*/
|
||||
@JsonProperty("mentioned_mobile_list")
|
||||
private List<String> mentionedMobileList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Markdown消息内容
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public static class MarkdownContent {
|
||||
|
||||
/**
|
||||
* Markdown内容,最长不超过4096个字节
|
||||
*/
|
||||
@JsonProperty("content")
|
||||
private String content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件消息内容
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public static class FileContent {
|
||||
|
||||
/**
|
||||
* 文件id,通过文件上传接口获取
|
||||
*/
|
||||
@JsonProperty("media_id")
|
||||
private String mediaId;
|
||||
}
|
||||
}
|
||||
@ -6,11 +6,33 @@ import com.qqchen.deploy.backend.notification.enums.NotificationChannelTypeEnum;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 通知配置基类
|
||||
* 提取各渠道配置的共用字段
|
||||
* 通知渠道配置基类
|
||||
*
|
||||
* 支持 Jackson 多态反序列化:
|
||||
* 利用外层 NotificationChannelDTO 的 channelType 字段进行类型识别
|
||||
* <p><b>DDD 定位:Value Object(值对象)</b></p>
|
||||
*
|
||||
* <h3>设计说明:</h3>
|
||||
* <ul>
|
||||
* <li>作为值对象,可跨层使用(Domain Layer ↔ API Layer)</li>
|
||||
* <li>通过 Jackson 注解支持多态反序列化(基于 channelType 字段)</li>
|
||||
* <li>以 JSON 格式存储在 NotificationChannel.config 字段中</li>
|
||||
* <li>不同渠道有不同的配置子类(EmailNotificationConfig、WeworkNotificationConfig)</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h3>为何不需要单独的 DTO(务实的 DDD):</h3>
|
||||
* <ol>
|
||||
* <li>字段验证规则相同(创建和查询)</li>
|
||||
* <li>无复杂的转换逻辑,仅简单字段映射</li>
|
||||
* <li>相对稳定,不频繁变化</li>
|
||||
* <li>避免重复定义字段,减少维护成本</li>
|
||||
* </ol>
|
||||
*
|
||||
* <h3>未来如需引入 DTO 的场景:</h3>
|
||||
* <ul>
|
||||
* <li>不同场景需要不同的验证规则(如创建时必填,更新时可选)</li>
|
||||
* <li>需要敏感字段脱敏处理(如密码字段返回时隐藏)</li>
|
||||
* <li>需要复杂的字段转换逻辑</li>
|
||||
* <li>Config 频繁变化,影响 API 稳定性</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
|
||||
@ -7,9 +7,25 @@ import lombok.Data;
|
||||
|
||||
/**
|
||||
* 模板配置基类
|
||||
* 用于实体层,与DTO层的BaseTemplateConfigDTO对应
|
||||
*
|
||||
* 使用 PROPERTY 方式,通过 channelType 字段进行多态反序列化
|
||||
* <p><b>DDD 定位:Value Object(值对象)</b></p>
|
||||
*
|
||||
* <h3>设计说明:</h3>
|
||||
* <ul>
|
||||
* <li>作为值对象,可跨层使用(Domain Layer ↔ API Layer)</li>
|
||||
* <li>通过 Jackson 注解支持多态反序列化(基于 channelType 字段)</li>
|
||||
* <li>以 JSON 格式存储在 NotificationTemplate.templateConfig 字段中</li>
|
||||
* <li>不同渠道有不同的配置子类(EmailTemplateConfig、WeworkTemplateConfig)</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h3>为何不需要单独的 DTO(务实的 DDD):</h3>
|
||||
* <ol>
|
||||
* <li>无敏感字段,无需脱敏处理</li>
|
||||
* <li>字段验证规则相同(创建和查询)</li>
|
||||
* <li>无复杂的转换逻辑,仅简单字段映射</li>
|
||||
* <li>相对稳定,不频繁变化</li>
|
||||
* <li>避免重复定义字段,减少维护成本</li>
|
||||
* </ol>
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
|
||||
Loading…
Reference in New Issue
Block a user