Mapstruct同配置多目标类映射方案咨询
复用MapStruct映射配置的三种可行方案
针对你遇到的「同结构不同包的自动生成类,无法继承但要复用映射配置」的场景,这三个方案可以直接解决:
方案1:用@MappingConfig抽公共配置(官方推荐)
这是MapStruct专门为复用映射规则设计的特性,把所有公共的@Mapping定义在一个配置接口里,两个Mapper直接引用即可:
步骤1:定义公共映射配置接口
import org.mapstruct.Mapping; import org.mapstruct.MappingConfig; @MappingConfig public interface DittaIndividualeMappingConfig { // 把所有共用的映射规则写在这里 @Mapping(source = "codiceFiscale", target = "taxCode") @Mapping(source = "ragioneSociale", target = "companyName") @Mapping(source = "dataIscrizione", target = "registrationDate", dateFormat = "yyyy-MM-dd") // 其他字段映射... }
步骤2:在两个Mapper中引用配置
// 第一个Mapper,目标类是package1下的DI import org.mapstruct.Mapper; import com.package1.DI; import com.yourpackage.DittaIndividualeDTO; @Mapper(config = DittaIndividualeMappingConfig.class) public interface FirstDIMapper { DI toDI(DittaIndividualeDTO source); } // 第二个Mapper,目标类是package2下的DI import org.mapstruct.Mapper; import com.package2.DI; import com.yourpackage.DittaIndividualeDTO; @Mapper(config = DittaIndividualeMappingConfig.class) public interface SecondDIMapper { DI toDI(DittaIndividualeDTO source); }
MapStruct会自动把配置里的所有映射规则应用到各自的toDI方法上,完全复用配置逻辑。
方案2:泛型抽象类统一映射逻辑
如果需要复用的不仅是字段映射,还有自定义转换逻辑,可以用泛型抽象类来封装,两个Mapper继承后指定具体目标类型:
import org.mapstruct.Mapping; import org.mapstruct.Mapper; public abstract class AbstractDIMapper { // 公共映射规则 @Mapping(source = "codiceFiscale", target = "taxCode") @Mapping(source = "ragioneSociale", target = "companyName") public abstract <T> T toDI(DittaIndividualeDTO source); // 如果有自定义转换方法,也可以写在这里复用 protected String normalizePhone(String phone) { return phone != null ? phone.replaceAll("[^0-9]", "") : null; } } // 第一个Mapper @Mapper public interface FirstDIMapper extends AbstractDIMapper { @Override com.package1.DI toDI(DittaIndividualeDTO source); } // 第二个Mapper @Mapper public interface SecondDIMapper extends AbstractDIMapper { @Override com.package2.DI toDI(DittaIndividualeDTO source); }
这种方式适合需要复用自定义转换逻辑的场景,MapStruct会自动处理泛型的类型擦除问题,只要两个DI类结构一致就没问题。
方案3:抽取公共转换组件(适合Spring环境)
如果你的项目用了Spring,可以把公共的映射逻辑抽到一个Spring组件里,两个Mapper注入这个组件来复用:
步骤1:定义公共转换组件
import org.springframework.stereotype.Component; @Component public class DittaIndividualeConverter { public void fillDICommonFields(DittaIndividualeDTO source, Object target) { // 利用类结构一致的特性,强转后设置公共字段 if (target instanceof com.package1.DI) { com.package1.DI di = (com.package1.DI) target; di.setTaxCode(source.getCodiceFiscale()); di.setCompanyName(source.getRagioneSociale()); } else if (target instanceof com.package2.DI) { com.package2.DI di = (com.package2.DI) target; di.setTaxCode(source.getCodiceFiscale()); di.setCompanyName(source.getRagioneSociale()); } // 其他公共字段设置... } }
步骤2:在Mapper中引用组件
import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingTarget; import org.springframework.beans.factory.annotation.Autowired; @Mapper(componentModel = "spring") public abstract class FirstDIMapper { @Autowired protected DittaIndividualeConverter converter; // 忽略公共字段,交给组件处理 @Mapping(target = "taxCode", ignore = true) @Mapping(target = "companyName", ignore = true) protected abstract com.package1.DI toDI(DittaIndividualeDTO source); // 用@AfterMapping调用公共组件补全字段 @AfterMapping protected void fillCommonFields(DittaIndividualeDTO source, @MappingTarget com.package1.DI target) { converter.fillDICommonFields(source, target); } }
第二个Mapper同理,只需要把目标类换成com.package2.DI即可。
内容的提问来源于stack exchange,提问作者Lore
相关产品推荐
相关产品推荐

