自定义转换类型

  • 使用表达式进行定义类型转换, expression="java(。。。)"
    注意:使用表达式的时候,类必须是全路径的使用,或者@Mapper(imports={类名.class}

1、doTrim函数,toJsonString函数、自定义java函数(工具类见附录)

import com.dm.bs.model.vo.BsFieldTransResult;
import com.dm.bs.model.vo.BsFieldTransVO;
import com.dm.bs.repository.entity.BsFieldTrans;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
 * BsFieldTrans转换器
@Mapper(uses = {TypeConversionWorker.class})
public interface BsFieldTransMapping {
    BsFieldTransMapping INSTANCE = Mappers.getMapper(BsFieldTransMapping.class);
    @Mapping(target = "targetUrl",source = "targetUrl",qualifiedByName = "doTrim")
    @Mapping(target = "transKey",source = "transKey",qualifiedByName = "toJsonString")
    @Mapping(target = "transVal",source = "transVal",qualifiedByName = "toJsonString")
    @Mapping(target = "relatedField", expression = "java(typeConversionWorker.generateRelatedField(bsFieldTransVO.getTransKey(), bsFieldTransVO.getTransVal()))") //使用工具类处理
    BsFieldTrans transToBsFieldTrans(BsFieldTransVO bsFieldTransVO);
    @Mapping(target = "relatedField",source = "relatedField",qualifiedByName = "listStr2CommaStr")
    BsFieldTransResult transToBsFieldTransResult(BsFieldTrans bsFieldTrans);

1、转换工具类

import com.dm.bs.model.vo.TransKeyVO;
import com.dm.bs.model.vo.TransValVO;
import com.dm.bs.util.JacksonUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import org.mapstruct.Named;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
 * Mapping通用转换
@Component
@Named("TypeConversionWorker")
public class TypeConversionWorker {
     * 对象转json字符串
     * @param obj
     * @return
    @Named("toJsonString")
    public String toJsonString(Object obj) {
        if (Objects.isNull(obj)) {
            return null;
        return JacksonUtil.toJsonString(obj);
     * 去空格
     * @param str
     * @return
    @Named("doTrim")
    public String doTrim(String str) {
        if (StringUtils.isEmpty(str)) {
            return null;
        return str.trim();
     * 字符串转List对象
     * @param str
     * @return
    @Named("toStrList")
    public List<String> toStrList(String str) {
        if (StringUtils.isEmpty(str)) {
            return null;
        return JacksonUtil.jsonToObjByTypeRf(str, new TypeReference<List<String>>() {
     * json字符串转换为Map
     * @param obj
     * @return
    @Named("toStrObjMap")
    public Object toStrObjMap(Object obj) {
        if (Objects.isNull(obj)) {
            return null;
        return JacksonUtil.jsonToObjByTypeRf(obj.toString(), new TypeReference<Map<String, Object>>() {
     * jsonLsit转换为逗号隔开形式
     * @param obj
     * @return
    @Named("listStr2CommaStr")
    public String listStr2CommaStr(Object obj) {
        if (Objects.isNull(obj)) {
            return null;
        List<String> strings = JacksonUtil.jsonToObjByTypeRf(obj.toString(), new TypeReference<List<String>>() {
        if (strings != null) {
            return String.join(",", strings);
        return null;
     * BsFieldTransMapping生成relatedField内容
    @Named("generateRelatedField")
    public String generateRelatedField(List<TransKeyVO> transKey, List<TransValVO> transVal) {
        List<String> relatedFieldList = new ArrayList<>();
        if (transKey != null && transKey.size() > 0) {
            transKey.forEach(k -> relatedFieldList.add(k.getCurrentKey()));
        if (transVal != null && transVal.size() > 0) {
            transVal.forEach(v -> relatedFieldList.add(v.getTargetKey()));
        return JacksonUtil.toJsonString(relatedFieldList);
     * BsFieldTransMapping生成relatedField内容
    @Named("getParentScope")
    public String getParentScope(String targetScope) {
        String[] split = targetScope.split("\\.");
        if (split.length == 1) {
            return "";
        StringBuilder parentScope = new StringBuilder();
        for (int i = 0; i < split.length - 1; i++) {
            parentScope.append(split[i]);
            if (i < split.length - 2) {
                parentScope.append(".");
        return parentScope.toString();

2、工具类

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class JacksonUtil {
    private static ObjectMapper mapper = new ObjectMapper();
     * 对象转json
     * @param object
     * @return
    public static String toJsonString(Object object) {
        try {
            return mapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            log.error("...Err...Jackson转换字符串(String)过程失败:::", e);
            e.printStackTrace();
        return null;
     * json转对象
     * @param json
     * @param clazz
     * @param <T>
     * @return
    public static <T> T jsonToBean(String json, Class<T> clazz) {
        try {
            return mapper.readValue(json, clazz);
        } catch (JsonProcessingException e) {
            log.error("...Err...Jackson转换对象(Object)过程失败:::", e);
            e.printStackTrace();
        return null;
     * 字符串转换为List
     * @param listStr
     * @param typeReference new TypeReference<List<Object>>() {}
     * @param <T>
     * @return
    public static <T> T jsonToObjByTypeRf(String listStr, TypeReference<T> typeReference) {
        try {
            return mapper.readValue(listStr, typeReference);
        } catch (JsonProcessingException e) {
            log.error("...Err...Jackson转换Object过程失败:::", e);
            e.printStackTrace();
        return null;

是不是有时候发现明明source和target不是同一个类型,但是却转换成功了,这是因为mapstruct有一套自己的类型转换机制

类型转换的流程

  1. 首先尝试自动进行类型转换
  2. 若是无法支持的类型转换,则是尝试调用已经存在的类型转换方法
  3. 不存在可用的方法则是尝试自己创建一个类型转换方法

类型转换分类

以下的类型之间是mapstruct自动进行类型转换的。

  • 基本类型及其他们对应的包装类型。
    此时mapstruct会自动进行拆装箱。不需要人为的处理
  • 基本类型的包装类型和string类型之间
@Data
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@AllArgsConstructor
public class Item1 {
    Long itemId;
    String title;
@Data
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@AllArgsConstructor
public class Item2 {
    Long itemId;
    String title;
@Data
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@AllArgsConstructor
public class Sku2 {
    Long skuId;
    String skuCode;
    String skuPrice;
    List<String> nameList;
    Item1 item;
@Data
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@AllArgsConstructor
public class SkuDTO2 {
    Long skuId;
    String skuCode;
    Long skuPrice;
    List<String> nameList;
    Item2 item;
@Mapper
public interface ItemConvert {
    ItemConvert INSTANCE = Mappers.getMapper(ItemConvert.class);
    SkuDTO2 domain2Dto(Sku2 sku2);
// 以下为mapstruct自动生成
public class ItemConvertImpl implements ItemConvert {
    @Override
    public SkuDTO2 domain2Dto(Sku2 sku2) {
        if ( sku2 == null ) {
            return null;
        SkuDTO2 skuDTO2 = new SkuDTO2();
        skuDTO2.setSkuId( sku2.getSkuId() );
        skuDTO2.setSkuCode( sku2.getSkuCode() );
        if ( sku2.getSkuPrice() != null ) {
            skuDTO2.setSkuPrice( Long.parseLong( sku2.getSkuPrice() ) );
        List<String> list = sku2.getNameList();
        if ( list != null ) {
            skuDTO2.setNameList( new ArrayList<String>( list ) );
        skuDTO2.setItem( item1ToItem2( sku2.getItem() ) );
        return skuDTO2;
   protected Item2 item1ToItem2(Item1 item1) {
    if ( item1 == null ) {
        return null;
    Item2 item2 = new Item2();
    item2.setItemId( item1.getItemId() );
    item2.setTitle( item1.getTitle() );
    return item2;

自定义转换类型

  • 使用表达式进行定义类型转换,expression="java(。。。)"
    注意:使用表达式的时候,类必须是全路径的使用,或者@Mapper(imports={类名.class}
@Mapper(imports={DemandSourceEnum.class})
public interface CarDealMapper {
 CarDealMapper INSTANCE = Mappers.getMapper(CarDealMapper.class);
    @Mappings({
            @Mapping(target = "demandSource", expression = "java(DemandSourceEnum.getMeaning(carDealDO.getDemandSource()))"),
    SaleDemandVO doToVo(CarDealDO carDealDO);
  • 自定义方法进行类型转换
@Mapper
public interface ItemConvert {
    ItemConvert INSTANCE = Mappers.getMapper(ItemConvert.class);
    SkuDTO2 domain2Dto(Sku2 sku2);
    default Item2 item1ToItem2(Item1 item1) {
        if (item1 == null) {
            return null;
        Item2 item2 = new Item2();
        item2.setItemId(11111L);
        item2.setTitle(item1.getTitle());
        return item2;
// mapstruct 的实现类
@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2019-07-30T18:38:11+0800",
    comments = "version: 1.3.0.Final, compiler: javac, environment: Java 1.8.0_101 (Oracle Corporation)"
public class ItemConvertImpl implements ItemConvert {
    @Override
    public SkuDTO2 domain2Dto(Sku2 sku2) {
        if ( sku2 == null ) {
            return null;
        SkuDTO2 skuDTO2 = new SkuDTO2();
        skuDTO2.setSkuId( sku2.getSkuId() );
        skuDTO2.setSkuCode( sku2.getSkuCode() );
        if ( sku2.getSkuPrice() != null ) {
            skuDTO2.setSkuPrice( Long.parseLong( sku2.getSkuPrice() ) );
        List<String> list = sku2.getNameList();
        if ( list != null ) {
            skuDTO2.setNameList( new ArrayList<String>( list ) );
        // mapstruct直接调用的是在接口中自定义的实现
        skuDTO2.setItem( item1ToItem2( sku2.getItem() ) );
        return skuDTO2;
  • 使用策略的方式进行类型转换
    若是类型在很多Mapper中都需要使用,比较使用下例
public class BooleanStrategy {
    public String booleanToString(Boolean value) {
        if (value == null) {
            return "--";
        return value ? "是" : "否";
    public Integer booleanToInteger(Boolean value) {
        if (value == null) {
            return null;
        return value ? 1 : 0;
    public Boolean IntegerToBoolean(Integer value) {
        if (value == null) {
            return null;
        return value == 0 ? false : true;
    public String dateFormate(Date date) {
        if (date == null) {
            return "--";
        return DateFormatUtils.format(date, "yyyy-MM-dd HH:mm:ss");
@Mapper(uses = BooleanStrategy.class)
public interface CarDealMapper {
 CarDealMapper INSTANCE = Mappers.getMapper(CarDealMapper.class);
 CarDealDO dtoToDo(PlateCityMessageDTO plateCityMessageDTO);

方法中target和source 类型满足 BooleanStrategy方法的,会自动进行调用这个方法的类型转换进行处理

  • 自定义常量的方法

若是我们需要给一些属性定义一个固定的值,这个时候可以使用 constant

    @Mapping(target = "whetherPass", constant = "true")
    CentralizedNewCarShipDTO doToDubboDto(CarDealDO carDealDO);
  • 特殊类型的转换
  @Mapping(target = "createTime", dateFormat = "yyyy-MM-dd HH:mm:ss", expression = "java(new Date())")
    CarDTO doToDTO(CarDO carDO);

另外还有numberFormat定义数字的格式转换

  • 自定义初始值 defaultValue
    当source值为空的时候则会使用defaultValue定义的值。而constant则是无论source是否为空,都会使用constant定义的值,注意区分两者
* 单个参数的直接使用 * @param carDO source do * @return target dto @Mapping(target = "userName", constant = "yby") @Mapping(target = "modelColor", source = "modelColor", defaultValue = "标致") @Mapping(target = "createTime", dateFormat = "yyyy-MM-dd HH:mm:ss", expression = "java(new Date())") CarDTO doToDTO(CarDO carDO);

额外的请参考 org.mapstruct.Mapping

Collection转换

原理是遍历source collection然后转换类型,put到target collection中 如果是可以自动转换的则自动转换,同date type conversion;若是无法自动转换的,则会查看是否有可以调用的类型

@Mapper(imports = Date.class)
public interface CarMapper {
    CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);
     * 基本类型collection的转换
     * @param integers
     * @return
    Set<String> integerSetToStringSet(Set<Integer> integers);
     * 调用存在已有方法的转换
     * @param cars
     * @return
    List<CarDTO> carsToCarDtos(List<CarDO> cars);
     * 单个参数的直接使用
     * @param carDO source do
     * @return target dto
    @Mapping(target = "userName", constant = "yby")
    @Mapping(target = "modelColor", source = "modelColor", defaultValue = "标致")
    @Mapping(target = "createTime", dateFormat = "yyyy-MM-dd HH:mm:ss", expression = "java(new Date())")
    CarDTO doToDTO(CarDO carDO);
     * DTO转为VO
     * @param warehouseValidDTOList
     * @return
    List<WarehouseValidPageVO> dtoToVo(List<WarehouseValidDTO> warehouseValidDTOList);
// mapstruct实现
@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2019-07-30T19:27:05+0800",
    comments = "version: 1.3.0.Final, compiler: javac, environment: Java 1.8.0_101 (Oracle Corporation)"
public class CarMapperImpl implements CarMapper {
    @Override
    public Set<String> integerSetToStringSet(Set<Integer> integers) {
        if ( integers == null ) {
            return null;
        Set<String> set = new HashSet<String>( Math.max( (int) ( integers.size() / .75f ) + 1, 16 ) );
        for ( Integer integer : integers ) {
            set.add( String.valueOf( integer ) );
        return set;
    @Override
    public List<CarDTO> carsToCarDtos(List<CarDO> cars) {
        if ( cars == null ) {
            return null;
        List<CarDTO> list = new ArrayList<CarDTO>( cars.size() );
        for ( CarDO carDO : cars ) {
            list.add( doToDTO( carDO ) );
        return list;
    @Override
    public CarDTO doToDTO(CarDO carDO) {
        if ( carDO == null ) {
            return null;
        CarDTO carDTO = new CarDTO();
        if ( carDO.getModelColor() != null ) {
            carDTO.setModelColor( carDO.getModelColor() );
        else {
            carDTO.setModelColor( "标致" );
        if ( carDO.getNewCarGuidePrice() != null ) {
            carDTO.setNewCarGuidePrice( BigDecimal.valueOf( carDO.getNewCarGuidePrice() ) );
        carDTO.setBrandCode( carDO.getBrandCode() );
        carDTO.setBrandName( carDO.getBrandName() );
        carDTO.setSeriesCode( carDO.getSeriesCode() );
        carDTO.setSeriesName( carDO.getSeriesName() );
        carDTO.setModelCode( carDO.getModelCode() );
        carDTO.setModelName( carDO.getModelName() );
        carDTO.setModelColorCode( carDO.getModelColorCode() );
        carDTO.setUserName( "yby" );
        carDTO.setCreateTime( new Date() );
        return carDTO;
@Override
    public List<WarehouseValidPageVO> dtoToVo(List<WarehouseValidDTO> warehouseValidDTOList) {
        if ( warehouseValidDTOList == null ) {
            return null;
        List<WarehouseValidPageVO> list = new ArrayList<WarehouseValidPageVO>( warehouseValidDTOList.size() );
        for ( WarehouseValidDTO warehouseValidDTO : warehouseValidDTOList ) {
            list.add( warehouseValidDTOToWarehouseValidPageVO( warehouseValidDTO ) );
        return list;
    protected WarehouseValidPageVO warehouseValidDTOToWarehouseValidPageVO(WarehouseValidDTO warehouseValidDTO) {
        if ( warehouseValidDTO == null ) {
            return null;
        WarehouseValidPageVO warehouseValidPageVO = new WarehouseValidPageVO();
        warehouseValidPageVO.setId( warehouseValidDTO.getId() );
        warehouseValidPageVO.setWarehouseNo( warehouseValidDTO.getWarehouseNo() );
        warehouseValidPageVO.setWarehouseName( warehouseValidDTO.getWarehouseName() );
        warehouseValidPageVO.setPlateValid( warehouseValidDTO.getPlateValid() );
        return warehouseValidPageVO;
public interface SourceTargetMapper {
    @MapMapping(valueDateFormat = "dd.MM.yyyy")
    Map<String, String> longDateMapToStringStringMap(Map<Long, Date> source);
// mapstruct自己实现
@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2019-07-30T19:35:22+0800",
    comments = "version: 1.3.0.Final, compiler: javac, environment: Java 1.8.0_101 (Oracle Corporation)"
public class SourceTargetMapperImpl implements SourceTargetMapper {
    @Override
    public Map<String, String> longDateMapToStringStringMap(Map<Long, Date> source) {
        if ( source == null ) {
            return null;
        Map<String, String> map = new HashMap<String, String>( Math.max( (int) ( source.size() / .75f ) + 1, 16 ) );
        for ( java.util.Map.Entry<Long, Date> entry : source.entrySet() ) {
            String key = new DecimalFormat( "" ).format( entry.getKey() );
            String value = new SimpleDateFormat( "dd.MM.yyyy" ).format( entry.getValue() );
            map.put( key, value );
        return map;
                    自定义转换类型使用表达式进行定义类型转换,expression="java(。。。)"	注意:使用表达式的时候,类必须是全路径的使用,或者@Mapper(imports={类名.class}1、doTrim函数,toJsonString函数、自定义java函数(工具类见附录)import com.dm.bs.model.vo.BsFieldTransResult;import com.dm.bs.model.vo.BsFieldTransVO;import com.dm.bs.reposi
				
摘要: MapStruct有很多的配置选项,除了使用target和source外,还有一些注解选项可以实现更高级的功能。defaultValue有时候,在转换过程中,可能因为空值或其他原因使得映射结果不正确,此时可以指定一个默认值,防止程序出错。@Mappings( { @Mapping(target = "age", source = "evage", defaultValue
文章目录Mapstruct官方参考文档中的一些使用规则在mapstruct自定义转换方法引入依赖写转换接口测试官网将多个源对象的不同属性赋值给一个目标对象如果mapstruct放到了IOC容器里面,那么就不要实例化对象源对象中的对象属性怎么转化成目标对象中的对象属性? Mapstruct官方参考文档中的一些使用规则 在mapstruct自定义转换方法 <dependency> <groupId>org.mapstruct</groupId&
遇到一个需求,就是我费率返回给前端的时候,多余的小数位不要展示 我对象转换全是使用的mapstruct,有兴趣的可以了解一下。就是只需要自定义接口,然后在编译时生成转换逻辑的代码 这次我只是简单记录一下,特殊逻辑的时候,怎么实现自定义转换 首先,是自定义转换逻辑 public class ConvertExpression { private ConvertExpression() { public static String stripTrailingZer
推荐一个 Java 实体映射工具 MapStruct MapStruct是干什么的? java分布式系统经常需要做entity(数据库访问对象)对象跟dto(业务传输对象)。一般entity对象只涉及系统内部跟数据库的交互,如果跟其他系统通过rpc交互,需要定义dto对象。 但是entity对象跟dto对象有很多字段的名称和类型都是相同的,但是需要程序来做转换。 如果在业务代码中大量set,get...
MapStruct是一个Java注解处理器,它可以自动生成Java Bean之间的映射代码。以下是MapStruct用法: 1. 添加依赖:在pom.xml文件中添加MapStruct的依赖。 2. 添加注解:在需要进行映射的Java Bean类中添加@Mapper注解。 3. 定义映射方法:在@Mapper注解中定义映射方法,例如: @Mapper public interface UserMapper { UserDto toUserDto(User user); User toUser(UserDto userDto); 4. 调用映射方法:在需要进行Java Bean映射的代码中调用映射方法,例如: User user = new User("John", "Doe", 30); UserDto userDto = UserMapper.INSTANCE.toUserDto(user); 5. 配置Mapper:可以通过添加@Mapping注解来配置映射规则,例如: @Mapper public interface UserMapper { @Mapping(source = "firstName", target = "name") UserDto toUserDto(User user); 这将把User对象的firstName属性映射到UserDto对象的name属性上。 总之,MapStruct可以帮助开发者简化Java Bean之间的映射,提高代码的可读性和可维护性。