Spring Data中含不同子类的继承类如何实现DTO投影?
这个需求完全可以实现,以下是两种常用的落地方案:
1 先定义DTO基础结构
首先要定义和实体对应的DTO结构,切断关联递归链:
// 基类QuestionDTO @Data public class QuestionDTO { private Long id; private String title; private String questionBody; private QuestionType questionType; } // 继承的TestQuestionDTO @Data public class TestQuestionDTO extends QuestionDTO { private Set<OptionDTO> options; private OptionDTO rightOption; } // 配套的OptionDTO,不要包含关联的TestQuestion属性 @Data public class OptionDTO { private Long id; private String content; }
2 方案1:手动转换器实现(轻量场景首选,无额外依赖)
写一个工具类做类型判断和属性转换:
public class QuestionConverter { // 单个实体转换 public static QuestionDTO convert(Question question) { if (question == null) { return null; } // 子类类型判断,分别转换 if (question instanceof TestQuestion testQuestion) { TestQuestionDTO dto = new TestQuestionDTO(); // 赋值基类属性 dto.setId(testQuestion.getId()); dto.setTitle(testQuestion.getTitle()); dto.setQuestionBody(testQuestion.getQuestionBody()); dto.setQuestionType(testQuestion.getQuestionType()); // 赋值子类特有属性 dto.setOptions(convertOptions(testQuestion.getOptions())); dto.setRightOption(convertOption(testQuestion.getRightOption())); return dto; } // 普通Question转换 QuestionDTO dto = new QuestionDTO(); dto.setId(question.getId()); dto.setTitle(question.getTitle()); dto.setQuestionBody(question.getQuestionBody()); dto.setQuestionType(question.getQuestionType()); return dto; } // 集合批量转换 public static List<QuestionDTO> convertList(List<Question> questions) { return questions.stream().map(QuestionConverter::convert).toList(); } // 辅助转换Option的方法 private static OptionDTO convertOption(Option option) { if (option == null) return null; OptionDTO dto = new OptionDTO(); dto.setId(option.getId()); dto.setContent(option.getContent()); return dto; } private static Set<OptionDTO> convertOptions(Set<Option> options) { if (options == null) return Collections.emptySet(); return options.stream().map(QuestionConverter::convertOption).collect(Collectors.toSet()); } }
使用方式:
List<Question> questions = questionRepository.fetchTestQuestions(testId); List<QuestionDTO> dtoList = QuestionConverter.convertList(questions); // 直接返回dtoList给前端即可
3 方案2:MapStruct自动映射(复杂场景首选,减少重复代码)
首先引入MapStruct依赖(Maven示例):
<dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>1.5.5.Final</version> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>1.5.5.Final</version> <scope>provided</scope> </dependency>
定义映射器接口:
@Mapper(componentModel = "spring") public interface QuestionMapper { // 普通Question转DTO QuestionDTO toDto(Question question); // TestQuestion转对应DTO,自动继承基类属性映射 TestQuestionDTO toTestDto(TestQuestion testQuestion); // Option转DTO OptionDTO toOptionDto(Option option); // 批量转换,自动匹配元素类型调用对应转换方法 default List<QuestionDTO> toDtoList(List<Question> questions) { return questions.stream().map(question -> { if (question instanceof TestQuestion tq) { return toTestDto(tq); } return toDto(question); }).toList(); } }
使用方式:
@Autowired private QuestionMapper questionMapper; // 业务逻辑中调用 List<Question> questions = questionRepository.fetchTestQuestions(testId); List<QuestionDTO> dtoList = questionMapper.toDtoList(questions);
内容的提问来源于stack exchange,提问作者Real Og
相关产品推荐
相关产品推荐

