java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring Boot 集成 Lombok 和 MapStruct

Spring Boot 中集成 Lombok 和 MapStruct最佳实践指南

作者:三石成山

文章详解SpringBoot项目中Lombok与MapStruct整合实践,涵盖版本兼容、IDE配置、代码分层、映射配置、测试验证及性能优化,重点解决注解冲突、依赖注入等常见问题,强调分层管理和组件扫描配置,提升开发效率与代码简洁性,本文给大家介绍的非常详细,感兴趣的朋友一起看看吧

一、环境准备

1. 版本兼容性要求

组件最低版本要求推荐版本
Spring Boot2.2.x+3.1.x
Lombok1.18.16+1.18.28
MapStruct1.4.2.Final+1.5.5.Final
JavaJDK 8+JDK 17

2. IDE 插件安装

二、项目配置

1. Maven 配置

<dependencies>
    <!-- Spring Boot Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.28</version>
        <scope>provided</scope>
    </dependency>
    <!-- MapStruct -->
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>1.5.5.Final</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <annotationProcessorPaths>
                    <!-- Lombok 处理器 -->
                    <path>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                        <version>1.18.28</version>
                    </path>
                    <!-- MapStruct 处理器 -->
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>1.5.5.Final</version>
                    </path>
                    <!-- Lombok 与 MapStruct 的绑定器 -->
                    <path>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok-mapstruct-binding</artifactId>
                        <version>0.2.0</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

三、代码实现

1. 实体类 (使用 Lombok)

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String username;
    private String email;
    private LocalDateTime createTime;
}

2. DTO 类

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserDto {
    private Long id;
    private String name;
    private String emailAddress;
    private String createTimeFormatted;
}

3. Mapper 接口 (使用 MapStruct)

@Mapper(componentModel = "spring", imports = {DateTimeFormatter.class})
public interface UserMapper {
    @Mapping(source = "username", target = "name")
    @Mapping(source = "email", target = "emailAddress")
    @Mapping(target = "createTimeFormatted", 
             expression = "java(entity.getCreateTime().format(DateTimeFormatter.ISO_DATE_TIME))")
    UserDto toDto(User entity);
    @Mapping(source = "name", target = "username")
    @Mapping(source = "emailAddress", target = "email")
    User toEntity(UserDto dto);
    // 集合映射
    List<UserDto> toDtoList(List<User> entities);
    // 更新现有实例
    @Mapping(target = "id", ignore = true)
    void updateFromDto(UserDto dto, @MappingTarget User entity);
}

4. 服务层使用示例

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserMapper userMapper;
    private final UserRepository userRepository;
    public UserDto getUserById(Long id) {
        return userMapper.toDto(
            userRepository.findById(id).orElseThrow()
        );
    }
    public List<UserDto> getAllUsers() {
        return userMapper.toDtoList(userRepository.findAll());
    }
    public UserDto createUser(UserDto userDto) {
        User user = userMapper.toEntity(userDto);
        return userMapper.toDto(userRepository.save(user));
    }
}

四、高级配置

1. 全局映射配置

@MapperConfig(
    componentModel = "spring",
    unmappedTargetPolicy = ReportingPolicy.IGNORE,
    nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE
)
public interface CentralConfig {}
// 在具体Mapper中引用
@Mapper(config = CentralConfig.class)
public interface ProductMapper {}

2. 自定义映射方法

@Mapper(componentModel = "spring")
public abstract class CustomMapper {
    // 自定义转换逻辑
    protected String statusToString(Status status) {
        return status != null ? status.name() : "UNKNOWN";
    }
    // 抽象方法由MapStruct实现
    public abstract OrderDto toDto(Order entity);
}

3. 多源对象映射

@Mapper(componentModel = "spring")
public interface ComplexMapper {
    @Mapping(source = "user.username", target = "name")
    @Mapping(source = "profile.address", target = "location")
    @Mapping(source = "metadata.tags", target = "labels")
    CompositeDto mergeToDto(User user, UserProfile profile, Metadata metadata);
}

五、测试验证

1. 单元测试示例

@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    void testToDto() {
        User user = User.builder()
            .id(1L)
            .username("john_doe")
            .email("john@example.com")
            .createTime(LocalDateTime.now())
            .build();
        UserDto dto = userMapper.toDto(user);
        assertEquals(user.getUsername(), dto.getName());
        assertEquals(user.getEmail(), dto.getEmailAddress());
        assertNotNull(dto.getCreateTimeFormatted());
    }
    @Test
    void testToEntity() {
        UserDto dto = UserDto.builder()
            .name("jane_doe")
            .emailAddress("jane@example.com")
            .build();
        User user = userMapper.toEntity(dto);
        assertEquals(dto.getName(), user.getUsername());
        assertEquals(dto.getEmailAddress(), user.getEmail());
    }
}

2. 集成测试

@WebMvcTest(UserController.class)
@Import(UserMapper.class) // 显式导入Mapper
public class UserControllerIT {
    @Autowired
    private MockMvc mockMvc;
    @MockBean
    private UserService userService;
    @Test
    void getUserById() throws Exception {
        UserDto mockDto = UserDto.builder().id(1L).name("test").build();
        when(userService.getUserById(any())).thenReturn(mockDto);
        mockMvc.perform(get("/api/users/1"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.name").value("test"));
    }
}

六、常见问题解决

1. Lombok 与 MapStruct 冲突

​现象​​:编译时报错找不到 getter/setter
​解决​​:

  1. 确保添加了 lombok-mapstruct-binding
  2. 检查注解处理器顺序 (Lombok 必须在 MapStruct 之前)

2. Spring 依赖注入失败

​现象​​:NoSuchBeanDefinitionException
​解决​​:

  1. 确认 Mapper 接口有 @Mapper(componentModel = "spring")
  2. 检查组件扫描范围是否包含 Mapper 接口所在包

3. 集合映射问题

​现象​​:集合映射为空
​解决​​:

// 明确声明集合映射方法
@Mapping(target = "items", source = "orderItems")
OrderDto toDto(Order entity);

4. 复杂类型转换

​解决方案​​:

@Mapper(componentModel = "spring")
public interface ComplexMapper {
    @Named("stringToDate")
    default LocalDate map(String dateStr) {
        return LocalDate.parse(dateStr, DateTimeFormatter.ISO_DATE);
    }
    @Mapping(target = "birthDate", source = "birthDateStr", qualifiedByName = "stringToDate")
    PersonDto toDto(Person entity);
}

七、性能优化

1. 编译参数优化

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <compilerArgs>
            <arg>-Amapstruct.unmappedTargetPolicy=IGNORE</arg>
            <arg>-Amapstruct.defaultComponentModel=spring</arg>
            <arg>-Amapstruct.suppressGeneratorTimestamp=true</arg>
        </compilerArgs>
    </configuration>
</plugin>

2. 缓存映射器实例

@Mapper(componentModel = "spring")
public interface CachedMapper {
    @BeanMapping(resultType = CachedDto.class)
    CachedDto toCachedDto(Entity entity);
}

3. 批量映射优化

public interface BatchMapper {
    @IterableMapping(elementTargetType = BatchDto.class)
    List<BatchDto> toBatchDtos(List<Entity> entities);
}

八、最佳实践

@Mapper(componentModel = "spring")
public interface DocumentedMapper {
    /**
     * 用户实体转DTO
     * @param entity 用户实体
     * @return 用户DTO
     */
    @Mapping(source = "username", target = "name")
    UserDto toDto(User entity);
}

​版本控制​​:

public interface UserMapperV2 extends UserMapper {
    // 扩展或覆盖方法
}

对重大变更创建 V2 版本映射器

通过以上配置和实践,可以在 Spring Boot 项目中高效整合 Lombok 和 MapStruct,实现简洁的代码和高效的 DTO 转换。

到此这篇关于Spring Boot 中集成 Lombok 和 MapStruct最佳实践指南的文章就介绍到这了,更多相关Spring Boot 集成 Lombok 和 MapStruct内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文