You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Stream:如何将多层级实体映射到单个CountryDTO?

正确实现实体到CountryDTO的映射

一、Java Stream直接实现(逻辑清晰,推荐)

你之前的代码核心错误是用flatMap把Country拆成了State流,导致每个State生成一个CountryDTO,违背了"一个国家对应一个DTO"的需求。正确做法是直接遍历每个Country,单独计算聚合数据:

List<CountryDTO> countries = countryRepository.findAll().stream()
    .map(country -> {
        // 计算当前国家所有州的人口总和
        Long totalPopulation = country.getStates().stream()
            .mapToLong(State::getPopulation)
            .sum();
        
        // 收集当前国家所有城镇并转换为TownDTO
        List<TownDTO> townDTOs = country.getStates().stream()
            .flatMap(state -> state.getTowns().stream())
            .map(town -> ObjectMapperUtils.map(town, TownDTO.class))
            .toList();
        
        // 实例化DTO(假设Country实体有getId()方法,若无则去掉id参数)
        return new CountryDTO(country.getId(), country.getName(), totalPopulation, townDTOs);
    })
    .toList();

关键修正点:

  • 移除flatMap,直接对单个Country做映射
  • 用嵌套Stream计算人口总和(mapToLong+sum)
  • 用flatMap展开所有州的城镇列表,统一转换为TownDTO

二、ModelMapper实现(适合复杂映射场景)

如果要使用ModelMapper,需要自定义映射逻辑处理聚合字段:

1. 配置ModelMapper自定义规则

ModelMapper modelMapper = new ModelMapper();

// 配置Country到CountryDTO的映射关系
modelMapper.typeMap(Country.class, CountryDTO.class)
    // 自动映射id、name(字段名一致时可省略显式配置)
    .addMapping(Country::getId, CountryDTO::setId)
    .addMapping(Country::getName, CountryDTO::setName)
    // 自定义人口总和计算逻辑
    .addMappings(mapper -> {
        mapper.map(source -> source.getStates().stream()
                .mapToLong(State::getPopulation)
                .sum(), CountryDTO::setPopulation);
    })
    // 自定义城镇列表聚合+转换逻辑
    .addMappings(mapper -> {
        mapper.map(source -> source.getStates().stream()
                .flatMap(state -> state.getTowns().stream())
                .map(town -> modelMapper.map(town, TownDTO.class))
                .toList(), CountryDTO::setTowns);
    });

2. 执行转换

// 单对象转换后收集为列表
List<CountryDTO> countries = countryRepository.findAll().stream()
    .map(country -> modelMapper.map(country, CountryDTO.class))
    .toList();

// 或者直接批量转换
List<CountryDTO> countries = modelMapper.map(
    countryRepository.findAll(),
    new TypeToken<List<CountryDTO>>(){}.getType()
);

内容的提问来源于stack exchange,提问作者Jack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 10:55:50