端请求通过VO对象接收,并通过DTO对象进行流转,最后转换成DO对象与数据库DAO层进行交互,反之亦然。
当业务简单的时候,可以通过手动编码getter/setter函数来复制对象属性。但是当业务变的复杂,对象属性变得很多,那么手写复制属性代码不仅十分繁琐,非常耗时间,并且还可能容易出错。
为了解决这个痛点,在项目初期,项目的解决方法是随手写的转换工具函数:根据变量名进行反射,对基础类型和枚举的变量进行赋值。
总结下目前该工具函数的优缺点:
优点:
- 开发效率高,随时想要转换的时候,传入源对象以及指定class,调用下函数即可。
缺点:
- 项目中大量的反射会严重影响代码执行效率
- 由于使用了反射,所以成员变量的使用被追踪就很麻烦
- 转换失败只有在运行中报错才会发现
- 对于嵌套对象字段的情况无能为力
- 只能对基础类型进行复制
- 对字段名不一致的属性无法赋值
接下来就要介绍MapStruct 这个工具类,这个工具类之所以运行速度与硬编码差不多,这是因为MapStruct在编译期间就生成属性复制的代码,运行期间就无需使用反射或者字节码技术,从而确保了高性能。
另外,由于编译期间就生成了代码,所以如果有任何问题,编译期间就可以提前暴露,这对于开发人员来讲就可以提前解决问题,而不用等到代码应用上线了,运行之后才发现错误。
所以,为了克服项目中当前函数的被提到的五个缺点,笔者引入了MapStruct。
2. 如何引入MapStruct
只需要引入MapStruct的依赖,同时由于MapStruct需要在编译器期间生成代码,所以我们需要maven-compiler-plugin插件中配置
复制
// pom.xml
<dependency>
<groupId>org.MapStruct</groupId>
<artifactId>MapStruct</artifactId>
<version>1.4.1.Final</version>
</dependency>
.高效性:
1.编译期 自动生成映射代码
类型检查报错
2.灵活性:支持复杂映射(对象、集合列表)
支持属性不同字段名、类型的赋值
3.直观性:使用注解来定义映射规则 (根据需求指定返回类型、忽略属性,添加 条件判断来决定是否执行映射操作)
package com.mdgyl.hussar.basic.supplier.changeorder.converter.struct;
import com.mdgyl.common.util.DateUtils;
import com.mdgyl.hussar.basic.model.supplier.masterdata.*;
import com.mdgyl.hussar.basic.model.supplier.supplierchangeorder.*;
import com.mdgyl.hussar.basic.supplier.changeorder.domain.*;
import org.apache.commons.lang3.StringUtils;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
@Mapper
public interface ChangeOrderMapperConverter {
ChangeOrderMapperConverter INSTANCE = Mappers.getMapper(ChangeOrderMapperConverter.class);
@Mappings({
@Mapping(target = "score", expression = "java(exchangeRateDO.getScore() == null? null:exchangeRateDO.getScore().toString())"),
@Mapping(target = "operatingStartTime", expression = "java(exchangeRateDO.getOperatingStartTime() == null? null:formatDate(exchangeRateDO.getOperatingStartTime()))"),
})
SupplierChangeOrderModel doToModel(SupplierChangeOrderDo exchangeRateDO);
@Mappings({
@Mapping(target = "id", ignore = true),
@Mapping(source = "tenantId", target = "tenantId"),
@Mapping(target = "status", ignore = true),
@Mapping(source = "id", target = "supplierDataId"),
@Mapping(target = "deleteFlag", constant = "0")
})
SupplierChangeOrderModel converterSupplierToChangeOrder(SupplierModel supplierModel);
@Mappings({
@Mapping(target = "id", ignore = true),
@Mapping(source = "id", target = "supplierAddressId")
})
SupplierChangeOrderAddressModel convertAddressesModel(SupplierAddressModel supplierAddressModel);
@Mappings({
@Mapping(target = "id", ignore = true),
@Mapping(source = "id", target = "supplierBankId")
})
SupplierChangeOrderBankModel convertBankModel(SupplierBankModel supplierBankModel);
@Mappings({
@Mapping(target = "id", ignore = true),
@Mapping(source = "id", target = "supplierContactsId"),
})
SupplierChangeOrderContactsModel convertContactModel(SupplierContactsModel supplierContactsModel);
@Mappings({
@Mapping(target = "id", ignore = true),
@Mapping(source = "id", target = "supplierInfoId"),
})
SupplierChangeOrderInfoModel convertOderInfoModel(SupplierInfoModel supplierInfo);
@Mappings({
@Mapping(target = "score", expression = "java(parseBigDecimal(supplierChangeOrderModel.getScore()))"),
@Mapping(target = "operatingStartTime", expression = "java(supplierChangeOrderModel.getOperatingStartTime() == null ? null : parseDate(supplierChangeOrderModel.getOperatingStartTime()))"),
})
SupplierChangeOrderDo converterModelToDo(SupplierChangeOrderModel supplierChangeOrderModel);
@Mappings({
@Mapping(target = "taxRate", expression = "java(parseBigDecimal(supplierChangeOrderModel.getTaxRate()))"),
@Mapping(target = "staffSize", expression = "java(supplierChangeOrderModel.getStaffSize() == null || supplierChangeOrderModel.getStaffSize().isEmpty() ? null : new Integer(supplierChangeOrderModel.getStaffSize()))"),
@Mapping(target = "numberOfInsured", expression = "java(supplierChangeOrderModel.getNumberOfInsured() == null || supplierChangeOrderModel.getNumberOfInsured().isEmpty() ? null : new Integer(supplierChangeOrderModel.getNumberOfInsured()))")
})
SupplierChangeOrderInfo converterInfoModelToDo(SupplierChangeOrderInfoModel supplierChangeOrderModel);
SupplierChangeOrderAddress converterAddressModelToDo(SupplierChangeOrderAddressModel supplierChangeOrderAddressModel);
SupplierChangeOrderBank converterBankModelToDo(SupplierChangeOrderBankModel supplierChangeOrderBankModel);
SupplierChangeOrderContacts converterContactsModel(SupplierChangeOrderContactsModel supplierChangeOrderContactsModel);
@Mappings({
@Mapping(target = "taxRate", expression = "java(supplierInfo.getTaxRate() == null? null:supplierInfo.getTaxRate().toString())"),
@Mapping(target = "staffSize", expression = "java(supplierInfo.getStaffSize() == null? null:supplierInfo.getStaffSize().toString())"),
@Mapping(target = "numberOfInsured", expression = "java(supplierInfo.getNumberOfInsured() == null? null:supplierInfo.getNumberOfInsured().toString())")
})
SupplierChangeOrderInfoModel converterInfoDoToModel(SupplierChangeOrderInfo supplierInfo);
SupplierChangeOrderAddressModel convertAddressesDoToModel(SupplierChangeOrderAddress supplierChangeOrderAddress);
SupplierChangeOrderContactsModel convertContactsDoToModel(SupplierChangeOrderContacts supplierChangeOrderContacts);
SupplierChangeOrderBankModel convertBankDoToModel(SupplierChangeOrderBank supplierChangeOrderContacts);
@Mappings({
@Mapping(source = "supplierDataId", target = "id"),
@Mapping(source = "status", target = "status", ignore = true),
@Mapping(target = "score", expression = "java(parseBigDecimal(changeOrderModel.getScore()))"),
@Mapping(target = "operatingStartTime", expression = "java(parseLocalDateTime(changeOrderModel.getOperatingStartTime()))")
})
SupplierModel converterChangeOrderToSupplier(SupplierChangeOrderModel changeOrderModel);
@Mappings({
@Mapping(source = "supplierInfoId", target = "id"),
@Mapping(target = "staffSize", expression = "java(changeOrderInfo.getStaffSize() == null|| changeOrderInfo.getStaffSize().isEmpty() ? null : Integer.parseInt(changeOrderInfo.getStaffSize()))"),
@Mapping(target = "taxRate", expression = "java(parseBigDecimal(changeOrderInfo.getTaxRate()))"),
@Mapping(target = "numberOfInsured", expression = "java(changeOrderInfo.getNumberOfInsured() == null || changeOrderInfo.getNumberOfInsured().isEmpty()? null : Integer.parseInt(changeOrderInfo.getNumberOfInsured()))"),
})
SupplierInfoModel convertOderInfoToSupplierModel(SupplierChangeOrderInfoModel changeOrderInfo);
@Mappings({
@Mapping(source = "supplierAddressId", target = "id")
})
SupplierAddressModel convertAddressesToSupplierModel(SupplierChangeOrderAddressModel supplierChangeOrderAddressModel);
@Mappings({
@Mapping(source = "supplierBankId", target = "id")
})
SupplierBankModel convertBankToSupplierModel(SupplierChangeOrderBankModel supplierBankModel);
@Mappings({
@Mapping(source = "supplierContactsId", target = "id"),
})
SupplierContactsModel convertContactToSupplierModel(SupplierChangeOrderContactsModel supplierContactsModel);
default Date parseDate(String dateString) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
try {
return format.parse(dateString);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
default BigDecimal parseBigDecimal(String taxRate) {
if (StringUtils.isEmpty(taxRate)) {
return null;
}
return new BigDecimal(taxRate);
}
default String formatDate(Date date) {
SimpleDateFormat format = new SimpleDateFormat(DateUtils.YYYY_MM_DD);
return format.format(date);
}
// 自定义方法用于解析日期字符串
default LocalDate parseLocalDate(String dateString) {
if (dateString == null) {
return null;
}
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DateUtils.YYYY_MM_DD);
try {
LocalDateTime dateTime = LocalDateTime.parse(dateString, formatter);
return dateTime.toLocalDate();
} catch (Exception e) {
return null;
}
}
// 自定义方法用于解析日期字符串
default LocalDateTime parseLocalDateTime(String dateStr) {
if (StringUtils.isBlank(dateStr)) {
return null;
}
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DateUtils.YYYY_MM_DD_HH_MM_SS);
return LocalDateTime.parse(dateStr, formatter);
} catch (Exception e) {
return null;
}
}
}
package com.mdgyl.hussar.basic.supplier.changeorder.converter.service;
import com.google.common.collect.Lists;
import com.jxdinfo.hussar.support.audit.plugin.mongodb.support.query.entity.Page;
import com.mdgyl.common.helper.CollectionHelper;
import com.mdgyl.common.helper.MapHelper;
import com.mdgyl.hussar.basic.enums.SupplierChangeOrderStatusEnum;
import com.mdgyl.hussar.basic.enums.SupplierStatusEnum;
import com.mdgyl.hussar.basic.model.supplier.masterdata.SupplierAddressModel;
import com.mdgyl.hussar.basic.model.supplier.masterdata.SupplierBankModel;
import com.mdgyl.hussar.basic.model.supplier.masterdata.SupplierContactsModel;
import com.mdgyl.hussar.basic.model.supplier.masterdata.SupplierModel;
import com.mdgyl.hussar.basic.model.supplier.supplierchangeorder.*;
import com.mdgyl.hussar.basic.supplier.changeorder.converter.struct.ChangeOrderMapperConverter;
import com.mdgyl.hussar.basic.supplier.changeorder.domain.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class ChangeOrderServiceConverter {
public static SupplierChangeOrderModel converterModel(SupplierChangeOrderDo supplierChangeOrderDo) {
if (supplierChangeOrderDo == null) {
return null;
}
SupplierChangeOrderModel supplierChangeOrderModel = ChangeOrderMapperConverter.INSTANCE.doToModel(supplierChangeOrderDo);
supplierChangeOrderModel.setStatus(SupplierChangeOrderStatusEnum.getDescByCode(supplierChangeOrderDo.getStatus()));
return supplierChangeOrderModel;
}
public static Page<SupplierChangeOrderModel> converterModelPage(Page<SupplierChangeOrderDo> supplierChangeOrderDos) {
if (supplierChangeOrderDos == null) {
return new Page<SupplierChangeOrderModel>(); // 如果输入是 null,返回一个空的 Page
}
// 转换数据列表
List<SupplierChangeOrderModel> modelList = supplierChangeOrderDos.getRecords().stream()
.map(ChangeOrderServiceConverter::converterModel)
.collect(Collectors.toList());
// 创建并返回新的 Page<SupplierChangeOrderModel> 对象
Page<SupplierChangeOrderModel> page = new Page<>(supplierChangeOrderDos.getCurrent(), supplierChangeOrderDos.getSize(), supplierChangeOrderDos.getTotal());
page.setRecords(modelList);
return page;
}
public static SupplierChangeOrderModel converterSupplierToChangeOrderModel(SupplierModel supplierModel) {
if (supplierModel == null) {
return null;
}
SupplierChangeOrderModel supplierChangeOrderModel = ChangeOrderMapperConverter.INSTANCE.converterSupplierToChangeOrder(supplierModel);
SupplierStatusEnum supplierStatus = supplierModel.getStatus();
supplierChangeOrderModel.setAddresses(CollectionHelper.collectNotNullList(supplierModel.getAddresses(), ChangeOrderMapperConverter.INSTANCE::convertAddressesModel));
supplierChangeOrderModel.setBanks(CollectionHelper.collectNotNullList(supplierModel.getBanks(), ChangeOrderMapperConverter.INSTANCE::convertBankModel));
supplierChangeOrderModel.setContacts(CollectionHelper.collectNotNullList(supplierModel.getContacts(), ChangeOrderMapperConverter.INSTANCE::convertContactModel));
SupplierChangeOrderInfoModel supplierChangeOrderInfoModel = ChangeOrderMapperConverter.INSTANCE.convertOderInfoModel(supplierModel.getSupplierInfo());
if (ObjectUtils.isEmpty(supplierChangeOrderInfoModel)) {
supplierChangeOrderInfoModel=new SupplierChangeOrderInfoModel();
supplierChangeOrderInfoModel.setSupplierDataId(supplierModel.getId());
}
supplierChangeOrderInfoModel.setSupplierStatus(supplierStatus);
supplierChangeOrderModel.setChangeOrderInfo(supplierChangeOrderInfoModel);
return supplierChangeOrderModel;
}
public static SupplierChangeOrderModel converterToChangeOrderModel(SupplierChangeOrderDo supplierChangeOrder, SupplierChangeOrderInfo changeOrderInfoDo, List<SupplierChangeOrderAddress> addresses, List<SupplierChangeOrderBank> banks, List<SupplierChangeOrderContacts> contacts) {
if (supplierChangeOrder == null) {
return null;
}
SupplierChangeOrderModel supplierChangeOrderModel = ChangeOrderMapperConverter.INSTANCE.doToModel(supplierChangeOrder);
supplierChangeOrderModel.setAddresses(CollectionHelper.collectNotNullList(addresses, ChangeOrderMapperConverter.INSTANCE::convertAddressesDoToModel));
supplierChangeOrderModel.setBanks(CollectionHelper.collectNotNullList(banks, ChangeOrderMapperConverter.INSTANCE::convertBankDoToModel));
supplierChangeOrderModel.setContacts(CollectionHelper.collectNotNullList(contacts, ChangeOrderMapperConverter.INSTANCE::convertContactsDoToModel));
supplierChangeOrderModel.setChangeOrderInfo(ChangeOrderMapperConverter.INSTANCE.converterInfoDoToModel(changeOrderInfoDo));
return supplierChangeOrderModel;
}
public static SupplierChangeOrderDo converterModelToDo(SupplierChangeOrderModel supplierChangeOrderModel) {
if (supplierChangeOrderModel == null) {
return null;
}
return ChangeOrderMapperConverter.INSTANCE.converterModelToDo(supplierChangeOrderModel);
}
public static SupplierChangeOrderInfo converterInfoModelToDo(SupplierChangeOrderInfoModel supplierChangeOrderInfoModel) {
if (supplierChangeOrderInfoModel == null) {
return null;
}
return ChangeOrderMapperConverter.INSTANCE.converterInfoModelToDo(supplierChangeOrderInfoModel);
}
public static List<SupplierChangeOrderAddress> converterAddressModelToDoList(List<SupplierChangeOrderAddressModel> supplierChangeOrderAddressList) {
if (CollectionUtils.isEmpty(supplierChangeOrderAddressList)) {
return Lists.newArrayList();
}
return supplierChangeOrderAddressList.stream().map(ChangeOrderMapperConverter.INSTANCE::converterAddressModelToDo).collect(Collectors.toList());
}
public static List<SupplierChangeOrderBank> converterBankModelToDoList(List<SupplierChangeOrderBankModel> supplierChangeOrderBankList) {
if (CollectionUtils.isEmpty(supplierChangeOrderBankList)) {
return Lists.newArrayList();
}
return supplierChangeOrderBankList.stream().map(ChangeOrderMapperConverter.INSTANCE::converterBankModelToDo).collect(Collectors.toList());
}
public static List<SupplierChangeOrderContacts> converterContactsModelToDoList(List<SupplierChangeOrderContactsModel> supplierChangeOrderContactList) {
if (CollectionUtils.isEmpty(supplierChangeOrderContactList)) {
return Lists.newArrayList();
}
return supplierChangeOrderContactList.stream().map(ChangeOrderMapperConverter.INSTANCE::converterContactsModel).collect(Collectors.toList());
}
public static List<SupplierChangeOrderAddressModel> converterChangeOrderAddressList(List<SupplierChangeOrderAddress> addressesList) {
if (CollectionUtils.isEmpty(addressesList)) {
return Lists.newArrayList();
}
return addressesList.stream().map(ChangeOrderMapperConverter.INSTANCE::convertAddressesDoToModel).collect(Collectors.toList());
}
public static List<SupplierChangeOrderAddressModel> converterAddressList(List<SupplierAddressModel> addressesList) {
if (CollectionUtils.isEmpty(addressesList)) {
return Lists.newArrayList();
}
return addressesList.stream().map(ChangeOrderMapperConverter.INSTANCE::convertAddressesModel).collect(Collectors.toList());
}
public static List<SupplierChangeOrderBankModel> converterBankList(List<SupplierBankModel> bankList) {
if (CollectionUtils.isEmpty(bankList)) {
return Lists.newArrayList();
}
return bankList.stream().map(ChangeOrderMapperConverter.INSTANCE::convertBankModel).collect(Collectors.toList());
}
public static List<SupplierChangeOrderContactsModel> converterContactsList(List<SupplierContactsModel> bankList) {
if (CollectionUtils.isEmpty(bankList)) {
return Lists.newArrayList();
}
return bankList.stream().map(ChangeOrderMapperConverter.INSTANCE::convertContactModel).collect(Collectors.toList());
}
public static SupplierChangeOrderInfoModel converterInfoModel(SupplierChangeOrderInfo supplierInfo) {
if (supplierInfo == null) {
return null;
}
return ChangeOrderMapperConverter.INSTANCE.converterInfoDoToModel(supplierInfo);
}
public static List<SupplierChangeOrderContactsModel> converterChangeOrdeContactsList(List<SupplierChangeOrderContacts> contactList) {
if (CollectionUtils.isEmpty(contactList)) {
return Lists.newArrayList();
}
return contactList.stream().map(ChangeOrderMapperConverter.INSTANCE::convertContactsDoToModel).collect(Collectors.toList());
}
public static List<SupplierChangeOrderBankModel> converterChangeOrdeBankList(List<SupplierChangeOrderBank> banks) {
if (CollectionUtils.isEmpty(banks)) {
return Lists.newArrayList();
}
return banks.stream().map(ChangeOrderMapperConverter.INSTANCE::convertBankDoToModel).collect(Collectors.toList());
}
public static List<Long> getAddressDeleteIds(List<SupplierChangeOrderAddressModel> supplierAddressModels, Map<Long, SupplierChangeOrderAddressModel> addressUpdateMap) {
// 对比出删除的现场考察数据
return CollectionHelper.collectNotNullList(supplierAddressModels, param -> {
Long addressId = param.getId();
SupplierChangeOrderAddressModel supplierChangeOrderAddressModel = MapHelper.getValue(addressUpdateMap, addressId);
if (supplierChangeOrderAddressModel == null) {
return addressId;
}
return null;
});
}
public static List<Long> getBankDeleteIds(List<SupplierChangeOrderBankModel> supplierBankModels, Map<Long, SupplierChangeOrderBankModel> bankUpdateMap) {
// 对比出删除的样品检测数据
return CollectionHelper.collectNotNullList(supplierBankModels, param -> {
Long bankId = param.getId();
SupplierChangeOrderBankModel supplierChangeOrderBankModel = MapHelper.getValue(bankUpdateMap, bankId);
if (supplierChangeOrderBankModel == null) {
return bankId;
}
return null;
});
}
public static List<Long> getContactsDeleteIds(List<SupplierChangeOrderContactsModel> supplierContactsModels, Map<Long, SupplierChangeOrderContactsModel> contactUpdateMap) {
// 对比出删除的资质审查数据
return CollectionHelper.collectNotNullList(supplierContactsModels, param -> {
Long contactsId = param.getId();
SupplierChangeOrderContactsModel supplierChangeOrderContactsModel = MapHelper.getValue(contactUpdateMap, contactsId);
if (supplierChangeOrderContactsModel == null) {
return contactsId;
}
return null;
});
}
public static SupplierModel converterChangeOrderToSupplierModel(SupplierChangeOrderModel changeOrderModel) {
if (changeOrderModel == null) {
return null;
}
SupplierModel supplierModel = ChangeOrderMapperConverter.INSTANCE.converterChangeOrderToSupplier(changeOrderModel);
supplierModel.setStatus(changeOrderModel.getChangeOrderInfo().getSupplierStatus());
supplierModel.setAddresses(CollectionHelper.collectNotNullList(changeOrderModel.getAddresses(), ChangeOrderMapperConverter.INSTANCE::convertAddressesToSupplierModel));
supplierModel.setBanks(CollectionHelper.collectNotNullList(changeOrderModel.getBanks(), ChangeOrderMapperConverter.INSTANCE::convertBankToSupplierModel));
supplierModel.setContacts(CollectionHelper.collectNotNullList(changeOrderModel.getContacts(), ChangeOrderMapperConverter.INSTANCE::convertContactToSupplierModel));
supplierModel.setSupplierInfo(ChangeOrderMapperConverter.INSTANCE.convertOderInfoToSupplierModel(changeOrderModel.getChangeOrderInfo()));
return supplierModel;
}
}