如何为同一个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
相关产品推荐
相关产品推荐

