Mapstruct如何指定List映射使用带双参数的DTO转换方法
问题
我定义了如下Character实体:
public class Character { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String image; @Column(nullable = false) private String name; @ManyToMany(cascade = CascadeType.ALL) @JoinTable( name = "characters_movies", joinColumns = @JoinColumn(name = "character"), inverseJoinColumns = @JoinColumn(name = "movie") ) private List<Movie> movies; }
对应的CharacterDTO:
public class CharacterDTO extends AbstractResponse{ private int id; private String image; private String name; private List<MovieDTO> movies; public CharacterDTO(String image, String name){ this.image= image; this.name= name; } }
以及CharacterMapper映射器接口:
@Mapper(componentModel = "spring", uses = MovieMapper.class) public interface CharacterMapper { List<CharacterDTO> toCharactersDTO(List<Character> characters); @InheritInverseConfiguration(name = "toCharacterDTO") Character toCharacter(CharacterDTO characterDTO); default CharacterDTO toCharacterDTO(Character character, String o){ return new CharacterDTO(character.getImage(), character.getName()); } default CharacterDTO toCharacterDTO(Character character){ return new CharacterDTO(character.getImage(), character.getName(), character.getAge(), character.getWeight(), character.getHistory(), null); } }
我通过两个toCharacterDTO转换方法控制不同场景下是否返回ID,当前方案可行,但希望指定toCharactersDTO方法使用带两个参数的toCharacterDTO转换方法,请问该如何实现?
解决方案
方法一:手动实现列表转换逻辑
直接将toCharactersDTO改为默认方法,手动循环调用带双参数的转换方法,同时传入所需的标记参数:
@Mapper(componentModel = "spring", uses = MovieMapper.class) public interface CharacterMapper { // 替换原来的自动生成方法,手动实现列表转换 default List<CharacterDTO> toCharactersDTO(List<Character> characters) { // 这里传入你需要的String参数值,比如"no-id"作为场景标记 return characters.stream() .map(character -> toCharacterDTO(character, "no-id")) .collect(Collectors.toList()); } @InheritInverseConfiguration(name = "toCharacterDTO") Character toCharacter(CharacterDTO characterDTO); default CharacterDTO toCharacterDTO(Character character, String o){ return new CharacterDTO(character.getImage(), character.getName()); } default CharacterDTO toCharacterDTO(Character character){ return new CharacterDTO(character.getImage(), character.getName(), character.getAge(), character.getWeight(), character.getHistory(), null); } }
方法二:使用MapStruct的@Named与@IterableMapping注解
通过命名标记区分不同转换方法,结合@IterableMapping指定列表转换时使用的方法,同时用@Context传递额外参数:
import org.mapstruct.Context; import org.mapstruct.Named; import org.mapstruct.IterableMapping; @Mapper(componentModel = "spring", uses = MovieMapper.class) public interface CharacterMapper { // 指定使用名为"withoutId"的转换方法,同时传递上下文参数 @IterableMapping(qualifiedByName = "withoutId") List<CharacterDTO> toCharactersDTO(List<Character> characters, @Context String o); @InheritInverseConfiguration(name = "toCharacterDTO") Character toCharacter(CharacterDTO characterDTO); // 给双参数方法命名为"withoutId" @Named("withoutId") default CharacterDTO toCharacterDTO(Character character, @Context String o){ return new CharacterDTO(character.getImage(), character.getName()); } // 给单参数方法命名为"withFullInfo"(可选,用于其他场景) @Named("withFullInfo") default CharacterDTO toCharacterDTO(Character character){ return new CharacterDTO(character.getImage(), character.getName(), character.getAge(), character.getWeight(), character.getHistory(), null); } }
调用时只需传入对应的String参数即可触发目标转换逻辑。
额外优化建议
如果不同场景下的DTO字段差异较大,建议拆分出不同的DTO类(比如CharacterBasicDTO仅包含image和name,CharacterFullDTO包含所有字段),这样转换逻辑更清晰,避免同一个DTO存在多套转换规则,降低后续维护成本。
内容的提问来源于stack exchange,提问作者Ernesto
相关产品推荐
相关产品推荐

