java-dto-converter
npx skills add https://github.com/jianyun8023/my-skills --skill java-dto-converter
Agent 安装分布
Skill 文档
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<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<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<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<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<PolicyCard> toCards(List<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 转æ¢å段ï¼å¦åå¨è·¯å¾ â ä¸è½½é¾æ¥ï¼