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

如何为同一个ModelMapper配置不同TypeMap以适配多调用方的字段返回需求

实现方案

以下三种方案覆盖不同场景的需求,可根据实际项目情况选择:

方案1:继续使用ModelMapper,用命名TypeMap避免冲突

ModelMapper本身支持为相同的源、目标类型创建多个不同名称的TypeMap,不需要覆盖原有规则,改动成本最低:

// 1. 为不同调用方注册独立的命名映射规则
// Consumer1 仅返回fullName、aadharNo和指定字段
modelMapper.typeMap(Student.class, StudentDto.class, "consumer1Map")
    .addMappings(new PropertyMap<Student, StudentDto>() {
        @Override
        protected void configure() {
            skip().setPassportNo(null);
            skip().setDrivingLicenceNo(null);
            // 剩余不需要返回的字段统一加skip配置
        }
    });

// Consumer3 仅返回fullName和drivingLicenceNo
modelMapper.typeMap(Student.class, StudentDto.class, "consumer3Map")
    .addMappings(new PropertyMap<Student, StudentDto>() {
        @Override
        protected void configure() {
            skip().setAadharNo(null);
            skip().setPassportNo(null);
            skip().setAge(null);
            skip().setSchoolName(null);
            // 剩余不需要返回的字段统一加skip配置
        }
    });

// 2. 调用时根据调用方身份选择对应映射规则
public StudentDto convertStudent(Student student, String consumerType) {
    return modelMapper.map(student, StudentDto.class, consumerType + "Map");
}

方案2:切换为MapStruct实现条件映射

如果对映射性能有要求、后续映射规则会持续迭代,推荐使用编译期生成代码的MapStruct,原生支持参数化条件映射:

// 映射接口定义
@Mapper(componentModel = "spring")
public interface StudentMapper {
    // 按调用方类型判断字段是否赋值
    @Mapping(target = "aadharNo", expression = "java(\"consumer1\".equals(consumerType) ? student.getAadharNo() : null)")
    @Mapping(target = "passportNo", expression = "java(\"consumer2\".equals(consumerType) ? student.getPassportNo() : null)")
    @Mapping(target = "drivingLicenceNo", expression = "java(\"consumer3\".equals(consumerType) ? student.getDrivingLicenceNo() : null)")
    // 其他字段同理配置规则
    StudentDto toDto(Student student, String consumerType);
}

规则复杂时可把判断逻辑抽为接口默认方法,代码可读性更高。

方案3:序列化阶段动态过滤(适配REST接口场景)

如果是HTTP接口返回JSON的场景,无需修改映射层逻辑,直接在序列化阶段按调用方过滤字段即可,用Jackson的JsonView功能就能实现:

// 1. 定义调用方视图层级
public class StudentView {
    public interface Consumer1 {}
    public interface Consumer2 extends Consumer1 {}
    public interface Consumer3 extends Consumer1 {}
    public interface Consumer4 extends Consumer1, Consumer2, Consumer3 {}
}

// 2. DTO字段标注所属视图
public class StudentDto {
    @JsonView(StudentView.Consumer1.class)
    private String fullName;
    @JsonView(StudentView.Consumer1.class)
    private String aadharNo;
    @JsonView(StudentView.Consumer2.class)
    private String passportNo;
    @JsonView(StudentView.Consumer3.class)
    private String drivingLicenceNo;
    // 剩余字段按需标注视图即可
}

// 3. 接口返回时指定对应序列化视图
// 示例:Consumer3调用时返回对应字段
@GetMapping("/student")
public MappingJacksonValue getStudent(String consumerType) {
    StudentDto dto = studentService.getStudent();
    MappingJacksonValue result = new MappingJacksonValue(dto);
    if ("consumer3".equals(consumerType)) {
        result.setSerializationView(StudentView.Consumer3.class);
    }
    return result;
}

该方案无需维护多套映射规则,字段权限统一管理,适合接口字段权限频繁调整的场景。


内容的提问来源于stack exchange,提问作者Abdul Razak AK

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 19:06:03