Mapstruct对象映射

本文详细介绍MapStruct工具类在Java对象映射中的应用,包括依赖导入、简单映射、类型转换、多参数映射及更新对象属性等高级用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MapStruct官网

https://mapstruct.org/documentation/ide-support/

简介

一个用于对象转换为另外一个对象的java工具类,主要适用于两个对象的大部分属性名称都相同的场景。相比于Spring的BeanUtils.copyProperties()方法,还可以实现不同名称字段之间的属性赋值

导入依赖

以maven工程为例,引入如下依赖:

<properties>
    <mapstruct.version>1.2.0.Final</mapstruct.version>
</properties>
<dependencies>
   <dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-jdk8</artifactId>
    <version>${mapstruct.version}</version>
   </dependency>
   <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-processor</artifactId>
        <version>${mapstruct.version}</version>
   </dependency>
</dependencies>

创建对象

public class Car {
 
    private String make;
    private int numberOfSeats;
 
    //constructor, getters, setters etc.
}


public class CarDto {

private String make;
private int seatCount;

//constructor, getters, setters etc.
}

package com.example.demo.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@Data
@NoArgsConstructor
public class User {
    private Long id;
    private String username;
    private String password;
    private String phoneNum;
    private String email;
    private Role role;
}



package com.example.demo.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class Role {
    private Long id;
    private String roleName;
    private String description;
}


package com.example.demo.dto;

import lombok.Data;

@Data
public class UserRoleDto {
    /**
     * 用户id
     */
    private Long userId;
    /**
     * 用户名
     */
    private String name;
    /**
     * 角色名
     */
    private String roleName;
}


package com.example.demo.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Customer {
    private Long id;
    private String name;
    private Boolean isDisable;

    private String email;

    private Date birthday;
}

定义mapper

基本使用,不同的名称字段可以通过@Mapping或者@Mappings来映射

定义简单的mapper

@Mapper
public interface CarMapper {
 	//为客户端提供对映射器实现的访问。
    CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );
 
    @Mapping(source = "numberOfSeats", target = "seatCount")
    CarDto carToCarDto(Car car);
}


简单mapper使用方式

package com.example.demo.mappers;

import com.example.demo.dto.CarDto;
import com.example.demo.entity.Car;
import org.junit.Test;



public class CarMapperTest {

    @Test
    public void shouldMapCarToDto() {
        //given
        Car car = new Car("Morris", 5);

        //when
        CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );

        System.out.println(carDto.toString());
    }
}

定义一个绑定spring的mapper

以使用springboot为示例,@Mapper(componentModel = “spring”),表示把当前Mapper类纳入spring容器。使用时可以直接使用@Autowired注入

package com.example.demo.mappers;


import com.example.demo.dto.UserRoleDto;
import com.example.demo.entity.Role;
import com.example.demo.entity.User;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.Mappings;


@Mapper(componentModel = "spring")
public interface UserRoleMapper {

    /**
     * 对象属性复制的方法
     *
     * @param user 这个参数就是源对象,也就是需要被复制的对象
     * @return 返回的是目标对象,就是最终的结果对象
     * @Mapping 用来定义属性复制规则 source 指定源对象属性 target指定目标对象属性
     */
    @Mappings({
            @Mapping(source = "id", target = "userId"),
            @Mapping(source = "username", target = "name"),
            @Mapping(source = "role.roleName", target = "roleName")
    })
    UserRoleDto toUserRoleDto(User user);
}

绑定spring的mapper使用方式

package com.example.demo.mappers;

import com.example.demo.DemoApplication;
import com.example.demo.dto.UserRoleDto;
import com.example.demo.entity.Role;
import com.example.demo.entity.User;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest(classes = DemoApplication.class)
@RunWith(SpringRunner.class)
public class UserRoleMapperTest {

    // 注入Mapper
    @Autowired
    private UserRoleMapper userRoleMapper;

    Role role = null;
    User user = null;

    @Before
    public void before() {
        role = new Role(2L, "admin", "超级管理员");
        user = new User(1L, "herion", "123456", "1389999888", "123@qq.com", role);
    }

    @Test
    public void toUserRoleDtorTest() {
        UserRoleDto userRoleDto=userRoleMapper.toUserRoleDto(user);
        System.out.println(userRoleDto);
    }
}

定义类型转换mapper

@Mapper( uses = { BooleanStrFormat.class}),注意,这里的users属性用于引用之前定义的转换规则的类:

定义类型转换规则

package com.example.demo.format;

import org.springframework.stereotype.Component;

@Component
public class BooleanStrFormat {
    public String toStr(Boolean isDisable) {
        if (isDisable) {
            return "Y";
        } else {
            return "N";
        }
    }
    public Boolean toBoolean(String str) {
        if (str.equals("Y")) {
            return true;
        } else {
            return false;
        }
    }
}

package cn.com.flashspace.cloud.oms.biz.utils;

import cn.com.flashspace.cloud.framework.utils.DateUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Date;

@Component
public class CommonMapperUtil {

    public Integer integerMaper(String intStr) {
        Integer result = 0;
        try {
            result = Integer.parseInt(intStr);
        } catch (Exception ex) {
        }
        return result;
    }

    public Double doubleMaper(String doubleStr) {
        Double result = 0.00;
        try {
            Double.parseDouble(doubleStr);
        } catch (Exception ex) {
        }
        return result;
    }

    public Date dateMaper(String dateStr) {
        if (StringUtils.isEmpty(dateStr))
            return null;
        return DateUtils.parseFromStringDefaultNotError(dateStr);
    }

}

定义类型转换mapper


package com.example.demo.mappers;

import com.example.demo.dto.CustomerDto;
import com.example.demo.entity.Customer;
import com.example.demo.format.BooleanStrFormat;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;

import java.util.List;

@Mapper(componentModel = "spring", uses = { BooleanStrFormat.class})
public interface CustomerListMapper {

    @Mappings({
            @Mapping(source = "name", target = "customerName"),
            @Mapping(source = "isDisable", target = "disable")
    })
    CustomerDto customersToCustomerDto(Customer customer);
}

类型转换mapper使用

@SpringBootTest(classes = DemoApplication.class)
@RunWith(SpringRunner.class)
public class CustomerMapperTest {

    @Autowired
    private CustomerListMapper customerListMapper;


    @Test
    public void customersToCustomerDtoTest(){
        Customer customer = new Customer(1L, "herion",true,null,new Date());
        CustomerDto customerDto = customerListMapper.customersToCustomerDto(customer);
        System.out.println(customerDto.toString());
    }

}

定义引用类型多个参数的mapper

@Mappings({
            // 把user中的id绑定到目标对象的userId属性中
            @Mapping(source = "user.id", target = "userId"),
            // 把user中的username绑定到目标对象的name属性中
            @Mapping(source = "user.username", target = "name"),
            // 把role对象的roleName属性值绑定到目标对象的roleName中
            @Mapping(source = "role.roleName", target = "roleName")
    })
    UserRoleDto toUserRoleDto(User user, Role role);

引用数据类型和基本数据类型多参数

@Mappings({
            // 把user中的id绑定到目标对象的userId属性中
            @Mapping(source = "user.id", target = "userId"),
            // 把user中的username绑定到目标对象的name属性中
            @Mapping(source = "user.username", target = "name"),
            // 把role对象的roleName属性值绑定到目标对象的roleName中
            @Mapping(source = "myRoleName", target = "roleName")
    })
    UserRoleDto useParameter(User user, String myRoleName);

引用类型多个参数的mapper使用方式

package com.example.demo.mappers;

import com.example.demo.DemoApplication;
import com.example.demo.dto.UserRoleDto;
import com.example.demo.entity.Role;
import com.example.demo.entity.User;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest(classes = DemoApplication.class)
@RunWith(SpringRunner.class)
public class UserRoleMapperTest {

    // 注入Mapper
    @Autowired
    private UserRoleMapper userRoleMapper;

    Role role = null;
    User user = null;

    @Before
    public void before() {
        role = new Role(2L, "admin", "超级管理员");
        user = new User(1L, "herion", "123456", "1389999888", "123@qq.com", role);
    }

    @Test
    public void toUserRoleDto2Test() {
        UserRoleDto userRoleDto=userRoleMapper.toUserRoleDto(user,role);
        System.out.println(userRoleDto);
    }
}

定义更新对象中的属性mapper

    @Mappings({
            @Mapping(source = "userId", target = "id"),
            @Mapping(source = "name", target = "username"),
            @Mapping(source = "roleName", target = "role.roleName")
    })
    void updateDto(UserRoleDto userRoleDto, @MappingTarget User user);

更新对象中的属性mapper使用方式

package com.example.demo.mappers;

import com.example.demo.DemoApplication;
import com.example.demo.dto.UserRoleDto;
import com.example.demo.entity.Role;
import com.example.demo.entity.User;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest(classes = DemoApplication.class)
@RunWith(SpringRunner.class)
public class UserRoleMapperTest {

    // 注入Mapper
    @Autowired
    private UserRoleMapper userRoleMapper;

    Role role = null;
    User user = null;

    @Before
    public void before() {
        role = new Role(2L, "admin", "超级管理员");
        user = new User(1L, "herion", "123456", "1389999888", "123@qq.com", role);
    }

      @Test
    public void updateDtoTest() {
        UserRoleDto userRoleDto=new UserRoleDto();
        userRoleDto.setName("管理员");
        userRoleDto.setRoleName("架构部");
        userRoleDto.setUserId(2L);

        System.out.println("执行前 userRoleDto:"+userRoleDto.toString());
        System.out.println("执行前 user:"+user.toString());
        userRoleMapper.updateDto(userRoleDto,user);
        System.out.println("执行后 userRoleDto:"+userRoleDto.toString());
        System.out.println("执行后 user:"+user.toString());
    }
}

运行结果

执行前 userRoleDto:UserRoleDto(userId=2, name=管理员, roleName=架构部)
执行前 user:User(id=1, username=herion, password=123456, phoneNum=1389999888, email=123@qq.com, role=Role(id=2, roleName=admin, description=超级管理员))
执行后 userRoleDto:UserRoleDto(userId=2, name=管理员, roleName=架构部)
执行后 user:User(id=2, username=管理员, password=123456, phoneNum=1389999888, email=123@qq.com, role=Role(id=2, roleName=架构部, description=超级管理员))

定义list转换mapper

@Mapper(componentModel = "spring", uses = { BooleanStrFormat.class})
public interface CustomerListMapper {

    @Mappings({
            @Mapping(source = "name", target = "customerName"),
            @Mapping(source = "isDisable", target = "disable")
    })
    CustomerDto customersToCustomerDto(Customer customer);


    List<CustomerDto> customersToCustomerDtos(List<Customer> customers);

}

list转换mapper使用

    @Test
    public void customersToCustomerDtosTest(){
        Customer customer1 = new Customer(1L, "herion1",true,null,new Date());
        Customer customer2 = new Customer(2L, "herion2",true,null,new Date());
        Customer customer3 = new Customer(3L, "herion3",true,null,new Date());
        List<Customer> list=new ArrayList<Customer>();
        list.add(customer1);
        list.add(customer2);
        list.add(customer3);
        List<CustomerDto> customerDtos = customerListMapper.customersToCustomerDtos(list);
        customerDtos.forEach(customer -> {
            System.out.println(customer.toString());
        });
    }

混合忽略/格式化/赋值mapper

   @Mappings({
            @Mapping(source = "customer.name", target = "username"),
            @Mapping(source = "customer.id", target = "id"),
            //格式转换
            @Mapping(source = "customer.isDisable", target = "disable"),
            //日期格式转换
            @Mapping(source = "customer.birthday", target = "birthDateFormat", dateFormat = "yyyy-MM-dd HH:mm:ss"),
            //ignore 忽略映射
            @Mapping(target = "email", ignore = true)
            @Mapping(target = "type", expression = "java(cn.com.flashspace.cloud.oms.biz.enums.OrderType.OrderRootType.ENTRY_ORDER.toString())")

    })
    CustomerVO userCustomerToCustomerVO(Customer customer, User user);

混合忽略/格式化mapper使用

 @Test
 public void userCustomerToCustomerVOTest(){
     Customer customer = new Customer();
     customer.setId(111L);
     customer.setName("herion");
     customer.setIsDisable(true);
     customer.setBirthday(new Date());

     User user=new User();
     user.setEmail("11@qq.com");
     user.setId(222L);
     user.setPhoneNum("13812344321");
     CustomerVO customerVO = customerMapper.userCustomerToCustomerVO(customer,user);
     System.out.println(customerVO.toString());
 }

### MapStruct 集合映射使用方法 对于集合类型的映射MapStruct 提供了简洁而强大的支持。通过定义映射器接口并利用 `@Mapper` 注解,能够轻松实现从一种实体列表到另一种实体列表的转换。 #### 定义映射器接口 为了执行具体的映射操作,需先声明一个带有 `@Mapper` 注解的接口,在其中指定源类型和目标类型的映射关系。当涉及到属性之间的复杂映射时,可以通过 `@Mapping` 来精确控制各个字段间的对应方式[^2]。 ```java import org.mapstruct.Mapper; import org.mapstruct.Mapping; // 声明 Mapper 接口 @Mapper public interface MyMapper { // 映射单个对象的方法也可以用于映射整个列表 @Mapping(source = "id", target = "key") @Mapping(source = "name", target = "value") TargetEntity doToVo(SourceEntity source); } ``` 值得注意的是,如果希望直接处理列表而不是单独的对象实例,则可以在上述基础上进一步简化配置: ```java List<TargetEntity> dos2vos(List<SourceEntity> sources); ``` 此时,无需显式地编写循环结构来逐项处理每一个元素;MapStruct 将自动识别输入参数为集合形式,并据此生成相应的批量转换逻辑。 #### 自定义映射逻辑的应用 除了基本的数据复制外,还经常遇到需要在映射过程中加入额外业务规则的情况,比如性别数值转字符串的例子。针对这类需求,MapStruct 支持借助装饰器模式或者前后置处理器机制来进行扩展性的开发工作[^1]。 例如,要将整数表示的性别编码转化为更具可读性的文字描述,可在映射函数内部嵌入条件判断语句,或是采用更优雅的方式—即注册专门负责此类变换的服务类,并让其参与到整体流程当中去。 ```java @AfterMapping default void adjustSexField(@MappingTarget PersonDTO personDTO, Person person){ if ("1".equals(person.getSex())){ personDTO.setSex("Male"); } else { personDTO.setSex("Female"); } } ``` 这种方法不仅减少了重复代码的数量,同时也提高了系统的灵活性与维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值