java-dto-converter

为分层架构项目创建规范的 DTO(数据传输对象)和 MapStruct Converter(对象转换器)。

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "java-dto-converter" with this command: npx skills add jianyun8023/my-skills/jianyun8023-my-skills-java-dto-converter

DTO 与 Converter

为分层架构项目创建规范的 DTO(数据传输对象)和 MapStruct Converter(对象转换器)。

DTO 命名体系

请求 DTO

用途 命名 示例

创建 {Resource}CreateReq

PolicyCreateReq

更新 {Resource}UpdateReq

PolicyUpdateReq

分页查询 {Resource}PageReq

PolicyPageReq

批量操作 {Resource}BatchReq

TaskBatchReq

响应 DTO

用途 命名 示例

列表卡片 {Resource}Card

PolicyCard

详情 {Resource}Detail

PolicyDetail

通用响应 {Resource}Resp

VideoSourceResp

批量结果 {Resource}BatchResp

TaskBatchResp

通用 DTO

类 用途

IdResp

创建操作返回 ID

PageReq

分页请求基类 (page, size)

PageResult<T>

偏移分页结果 (records, total, page, size)

CursorPageResult<T>

游标分页结果 (records, nextCursor, hasMore, count)

@Data @Schema(description = "分页请求基类") public class PageReq { @Schema(description = "页码", example = "1") @Min(value = 1, message = "页码不能小于1") private Integer page = 1;

@Schema(description = "每页大小", example = "20")
@Range(min = 1, max = 100, message = "每页大小需在1-100之间")
private Integer size = 20;

}

@Data @Schema(description = "创建操作返回ID") public class IdResp { @Schema(description = "资源ID") private Long id;

public IdResp(Long id) { this.id = id; }

}

包组织

DTO 按业务模块分子目录:

dto/ ├── policy/ │ ├── PolicyCreateReq.java │ ├── PolicyUpdateReq.java │ ├── PolicyCard.java │ └── PolicyDetail.java ├── task/ │ ├── AnalysisTaskCreateReq.java │ └── ... ├── ApiResponse.java ├── IdResp.java ├── PageReq.java ├── PageResult.java └── CursorPageResult.java

DTO 注解规范

请求 DTO 模板

@Data @Schema(description = "策略创建请求") public class PolicyCreateReq {

@Schema(description = "策略名称", example = "火灾预警策略")
@NotBlank(message = "策略名称不能为空")
private String name;

@Schema(description = "策略描述")
private String description;

@Schema(description = "告警等级")
@NotNull(message = "告警等级不能为空")
private AlertLevelEnum alertLevel;

@Schema(description = "关联设备ID列表")
@NotEmpty(message = "设备ID列表不能为空")
private List&#x3C;String> deviceIds;

}

更新 DTO 模板

更新 DTO 与创建 DTO 的区别:字段通常全部可选(仅传入需要修改的字段),不加 @NotBlank 等必填校验。

@Data @Schema(description = "策略更新请求") public class PolicyUpdateReq {

@Schema(description = "策略名称", example = "火灾预警策略V2")
private String name;

@Schema(description = "策略描述")
private String description;

@Schema(description = "告警等级")
private AlertLevelEnum alertLevel;

@Schema(description = "关联设备ID列表")
private List&#x3C;String> deviceIds;

}

设计策略: 若业务要求全量更新(每次提交完整数据),则 UpdateReq 可加必填校验,与 CreateReq 类似。

响应 DTO 模板

@Data @Schema(description = "策略卡片") public class PolicyCard {

@Schema(description = "策略ID")
private Long id;

@Schema(description = "策略名称")
private String name;

@Schema(description = "是否启用")
private Boolean enabled;

@Schema(description = "告警等级")
private AlertLevelEnum alertLevel;

@Schema(description = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;

}

详情继承卡片

@Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) @Schema(description = "策略详情") public class PolicyDetail extends PolicyCard {

@Schema(description = "策略描述")
private String description;

@Schema(description = "时间计划列表")
private List&#x3C;TimePlanResp> timePlans;

@Schema(description = "更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;

}

继承场景必须: @EqualsAndHashCode(callSuper = true)

  • @ToString(callSuper = true) ,否则父类字段不参与 equals/toString。

分页请求继承基类

@Data @EqualsAndHashCode(callSuper = true) @Schema(description = "策略分页查询请求") public class PolicyPageReq extends PageReq {

@Schema(description = "策略名称(模糊查询)")
private String name;

@Schema(description = "告警等级列表(多选)")
private List&#x3C;AlertLevelEnum> alertLevels;

@Schema(description = "开始时间")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime startTime;

}

常用注解速查

注解 用途 示例

@Schema(description, example)

OpenAPI 字段说明 @Schema(description = "用户名", example = "张三")

@NotBlank

字符串非空 必填 String 字段

@NotNull

非 null 必填枚举/对象字段

@NotEmpty

集合非空 必填 List 字段

@JsonFormat(pattern)

JSON 日期格式 "yyyy-MM-dd HH:mm:ss"

@JsonProperty

JSON 字段名 @JsonProperty("sourceId")

@DateTimeFormat(pattern)

查询参数日期解析 GET 请求的日期参数

枚举序列化

DTO 中使用枚举类型时,需明确 JSON 序列化/反序列化策略:

@Getter @AllArgsConstructor public enum AlertLevelEnum { HIGH("high", "高"), MEDIUM("medium", "中"), LOW("low", "低");

@JsonValue   // 序列化时输出 value 值(如 "high")
private final String value;

private final String label;

@JsonCreator // 反序列化时按 value 匹配
public static AlertLevelEnum fromValue(String value) {
    for (AlertLevelEnum e : values()) {
        if (e.value.equals(value)) return e;
    }
    throw new IllegalArgumentException("未知告警等级: " + value);
}

}

注解 用途

@JsonValue

控制枚举序列化输出(推荐使用业务值而非 name/ordinal)

@JsonCreator

控制枚举反序列化匹配逻辑

MapStruct Converter

统一配置(推荐)

所有 Converter 共享的配置,自动忽略未映射字段,无需逐个 @Mapping(ignore=true) :

@MapperConfig( componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE, unmappedSourcePolicy = ReportingPolicy.IGNORE ) public interface ConverterConfig { }

推荐策略: 优先使用 config = ConverterConfig.class (简洁、统一)。仅在需要显式控制映射关系(如字段名不同、常量赋值)时才使用 @Mapping 。

Converter 接口模板

@Mapper(config = ConverterConfig.class) public interface PolicyConverter {

// Entity → DTO
PolicyCard toCard(AlertPolicy entity);
PolicyDetail toDetail(AlertPolicy entity);
List&#x3C;PolicyCard> toCards(List&#x3C;AlertPolicy> entities);

// 创建: DTO → Entity
AlertPolicy toEntity(PolicyCreateReq req);

// 更新: DTO 合并到已有 Entity(仅覆盖非 null 字段)
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
void updateEntity(PolicyUpdateReq req, @MappingTarget AlertPolicy entity);

}

不使用 ConverterConfig 的写法: 将 @Mapper(config = ConverterConfig.class) 替换为 @Mapper(componentModel = "spring") ,并手动添加 @Mapping(target = "id", ignore = true) 等忽略注解。

方法命名规范

方法 用途

toEntity(Req)

请求 DTO → 新 Entity(创建)

updateEntity(Req, @MappingTarget Entity)

请求 DTO 合并到已有 Entity(更新)

toCard(Entity)

Entity → 列表卡片 DTO

toDetail(Entity)

Entity → 详情 DTO

toResp(Entity)

Entity → 通用响应 DTO

toCards(List)

批量转换

字段映射

// 忽略字段 @Mapping(target = "id", ignore = true)

// 字段名不同 @Mapping(source = "sort", target = "sortOrder")

// 常量值 @Mapping(target = "status", constant = "DISABLED")

// 表达式 @Mapping(target = "syncTime", expression = "java(java.time.LocalDateTime.now())")

// 嵌套属性 @Mapping(target = "typeName", source = "entity.modelType.label")

后处理 (@AfterMapping)

用于 MapStruct 自动映射后的补充逻辑(组装显示名称、计算派生字段等):

@AfterMapping default void enrichCard(AlertPolicy entity, @MappingTarget PolicyCard card) { // 组装显示名称 card.setDisplayName(entity.getName() + " (" + entity.getAlertLevel().getLabel() + ")"); }

@AfterMapping default void setDefaultValues(@MappingTarget AlertPolicy entity) { if (entity.getEnabled() == null) entity.setEnabled(false); if (entity.getStatus() == null) entity.setStatus(PolicyStatusEnum.DISABLED); }

null 值处理: 简单的 null → 默认值场景优先使用 @BeanMapping(nullValuePropertyMappingStrategy) 或 ConverterConfig 级别配置,@AfterMapping 保留给需要自定义逻辑的场景。

自定义转换 (default 方法)

用于枚举、时间戳等需要逻辑的转换:

@Mapper(config = ConverterConfig.class) public interface AlertConverter {

AlertCard toCard(AlertRecord entity);

// 自定义时间戳转换(MapStruct 自动调用匹配的类型转换方法)
default LocalDateTime timestampToLocalDateTime(long timestamp) {
    if (timestamp == 0) return null;
    return LocalDateTime.ofInstant(
        Instant.ofEpochSecond(timestamp),
        ZoneId.systemDefault()
    );
}

// 自定义枚举转换
default OnlineStatus convertOnlineStatus(String videoUrlStatus) {
    return OnlineStatus.fromVideoUrlStatus(videoUrlStatus);
}

}

组合 Converter (uses)

当 Entity 含有嵌套对象需要转换时,使用 uses 引入其他 Converter:

@Mapper(config = ConverterConfig.class, uses = {TimePlanConverter.class}) public interface PolicyConverter { // MapStruct 自动调用 TimePlanConverter 转换嵌套的 TimePlan → TimePlanResp PolicyDetail toDetail(AlertPolicy entity); }

@Mapper(config = ConverterConfig.class) public interface TimePlanConverter { TimePlanResp toResp(TimePlan entity); List<TimePlanResp> toResps(List<TimePlan> entities); }

必须忽略的字段

当 DTO → Entity 转换时,以下字段必须 ignore(由框架自动填充):

字段 原因

id

数据库自增

deleted

默认值 0

createTime / updateTime

MetaObjectHandler 自动填充

createUser / updateUser

MetaObjectHandler 自动填充

versionNum

默认值 1

当 Entity → DTO 转换时,以下字段由 Facade 层填充,Converter 应 ignore:

  • 关联数据字段(如 agentNames , regionPath , deviceGroups )

  • 计算字段(如 sourceCount , taskCount )

  • URL 转换字段(如存储路径 → 下载链接)

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

java-crud-module

No summary provided by upstream source.

Repository SourceNeeds Review
General

landing-page-guide-v2

No summary provided by upstream source.

Repository SourceNeeds Review
605-bear2u
General

nixos-best-practices

No summary provided by upstream source.

Repository SourceNeeds Review
General

card-news-generator-v2

No summary provided by upstream source.

Repository SourceNeeds Review