最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot 對(duì)象轉(zhuǎn)換 MapStruct的實(shí)現(xiàn)小結(jié)

 更新時(shí)間:2026年02月12日 11:26:28   作者:油墨香^_^  
MapStruct是一個(gè)基于注解的Java對(duì)象映射工具,通過在編譯時(shí)生成映射代碼實(shí)現(xiàn)高效的對(duì)象轉(zhuǎn)換,下面就來詳細(xì)的介紹一下SpringBoot 對(duì)象轉(zhuǎn)換 MapStruct的實(shí)現(xiàn),感興趣的可以了解一下

1. MapStruct 簡(jiǎn)介與核心概念

1.1 什么是 MapStruct

MapStruct 是一個(gè)基于注解的 Java 對(duì)象映射工具,它通過在編譯時(shí)生成映射代碼來實(shí)現(xiàn)對(duì)象之間的轉(zhuǎn)換。與其他映射框架(如 ModelMapper)相比,MapStruct 的主要優(yōu)勢(shì)在于:

  • 編譯時(shí)生成代碼:性能接近手寫代碼
  • 類型安全:編譯時(shí)檢查映射的正確性
  • 零運(yùn)行時(shí)依賴:生成的代碼不依賴 MapStruct
  • 豐富的映射功能:支持復(fù)雜映射場(chǎng)景

1.2 核心概念解析

映射器 (Mapper)

  • 負(fù)責(zé)對(duì)象轉(zhuǎn)換的核心接口
  • 通過 @Mapper 注解標(biāo)識(shí)
  • 編譯時(shí)生成實(shí)現(xiàn)類

映射方法 (Mapping Method)

  • 在映射器接口中定義的具體轉(zhuǎn)換方法
  • 支持單個(gè)對(duì)象、集合、Map 等轉(zhuǎn)換

轉(zhuǎn)換規(guī)則 (Mapping Rules)

  • 通過注解配置的屬性映射規(guī)則
  • 支持自定義轉(zhuǎn)換邏輯

2. 環(huán)境搭建與基礎(chǔ)配置

2.1 依賴配置

Maven 配置

<properties>
    <org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>${org.mapstruct.version}</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.11.0</version>
            <configuration>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

Gradle 配置

plugins {
    id 'java'
}

dependencies {
    implementation 'org.mapstruct:mapstruct:1.5.5.Final'
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'
}

compileJava {
    options.annotationProcessorPath = configurations.annotationProcessor
}

2.2 Spring Boot 集成

@Configuration
public class MapStructConfig {
    
    @Bean
    public UserMapper userMapper() {
        return Mappers.getMapper(UserMapper.class);
    }
}

或者使用組件掃描:

@Mapper(componentModel = "spring")
public interface UserMapper {
    // 映射方法
}

3. 基礎(chǔ)映射功能詳解

3.1 簡(jiǎn)單對(duì)象映射

源對(duì)象和目標(biāo)對(duì)象定義

// 源對(duì)象
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String username;
    private String email;
    private String password;
    private LocalDateTime createTime;
    private Integer status;
}

// 目標(biāo)對(duì)象
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDTO {
    private Long id;
    private String username;
    private String email;
    private String createTime;
    private String statusDesc;
}

基礎(chǔ)映射器

@Mapper(componentModel = "spring")
public interface UserMapper {
    
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
    
    // 基礎(chǔ)映射 - 屬性名相同時(shí)自動(dòng)映射
    UserDTO toDTO(User user);
    
    // 反向映射
    User toEntity(UserDTO userDTO);
}

3.2 屬性名不同的映射

@Mapper(componentModel = "spring")
public interface UserMapper {
    
    @Mapping(source = "username", target = "name")
    @Mapping(source = "createTime", target = "registrationDate")
    @Mapping(source = "status", target = "userStatus")
    UserDTO toDTO(User user);
    
    @Mapping(source = "name", target = "username")
    @Mapping(source = "registrationDate", target = "createTime")
    @Mapping(source = "userStatus", target = "status")
    User toEntity(UserDTO userDTO);
}

3.3 類型轉(zhuǎn)換

內(nèi)置類型轉(zhuǎn)換

@Mapper(componentModel = "spring")
public interface UserMapper {
    
    // 自動(dòng)類型轉(zhuǎn)換:LocalDateTime -> String
    @Mapping(source = "createTime", target = "createTimeStr")
    // 數(shù)字轉(zhuǎn)字符串
    @Mapping(source = "status", target = "statusStr")
    UserDTO toDTO(User user);
    
    // 使用表達(dá)式進(jìn)行復(fù)雜轉(zhuǎn)換
    @Mapping(target = "statusDesc", 
             expression = "java(convertStatus(user.getStatus()))")
    UserDTO toDTOWithExpression(User user);
    
    default String convertStatus(Integer status) {
        switch (status) {
            case 0: return "禁用";
            case 1: return "啟用";
            default: return "未知";
        }
    }
}

4. 高級(jí)映射功能

4.1 嵌套對(duì)象映射

復(fù)雜對(duì)象結(jié)構(gòu)

// 地址對(duì)象
@Data
public class Address {
    private String province;
    private String city;
    private String street;
    private String zipCode;
}

// 用戶詳情對(duì)象
@Data
public class UserDetail {
    private Long id;
    private String username;
    private Address address;
    private List<String> hobbies;
}

// DTO 對(duì)象
@Data
public class UserDetailDTO {
    private Long id;
    private String username;
    private String province;
    private String city;
    private String street;
    private String zipCode;
    private String hobbies;
}

嵌套映射配置

@Mapper(componentModel = "spring")
public interface UserDetailMapper {
    
    @Mapping(source = "address.province", target = "province")
    @Mapping(source = "address.city", target = "city")
    @Mapping(source = "address.street", target = "street")
    @Mapping(source = "address.zipCode", target = "zipCode")
    @Mapping(source = "hobbies", target = "hobbies")
    UserDetailDTO toDTO(UserDetail userDetail);
    
    // 反向映射
    @Mapping(target = "address.province", source = "province")
    @Mapping(target = "address.city", source = "city")
    @Mapping(target = "address.street", source = "street")
    @Mapping(target = "address.zipCode", source = "zipCode")
    UserDetail toEntity(UserDetailDTO dto);
}

4.2 集合映射

列表和數(shù)組映射

@Mapper(componentModel = "spring")
public interface UserMapper {
    
    // 列表映射
    List<UserDTO> toDTOList(List<User> users);
    
    // 集合映射
    Set<UserDTO> toDTOSet(Set<User> users);
    
    // 數(shù)組映射
    UserDTO[] toDTOArray(User[] users);
}

Map 映射

@Mapper(componentModel = "spring")
public interface UserMapper {
    
    // Map 值映射
    @Mapping(source = "value", target = "value")
    Map<String, UserDTO> toDTOMap(Map<String, User> userMap);
    
    // Map 鍵值都映射
    @MapMapping(keyTargetType = String.class, valueTargetType = UserDTO.class)
    Map<String, UserDTO> toDTOFullMap(Map<Long, User> userMap);
}

4.3 多源對(duì)象映射

@Data
public class UserBasicInfo {
    private String firstName;
    private String lastName;
    private Integer age;
}

@Data
public class UserContactInfo {
    private String email;
    private String phone;
    private Address address;
}

@Data
public class CompleteUserDTO {
    private String fullName;
    private Integer age;
    private String email;
    private String phone;
    private String address;
}

@Mapper(componentModel = "spring")
public interface MultiSourceMapper {
    
    @Mapping(target = "fullName", expression = "java(basicInfo.getFirstName() + \" \" + basicInfo.getLastName())")
    @Mapping(source = "basicInfo.age", target = "age")
    @Mapping(source = "contactInfo.email", target = "email")
    @Mapping(source = "contactInfo.phone", target = "phone")
    @Mapping(target = "address", expression = "java(formatAddress(contactInfo.getAddress()))")
    CompleteUserDTO toCompleteDTO(UserBasicInfo basicInfo, UserContactInfo contactInfo);
    
    default String formatAddress(Address address) {
        return address.getProvince() + address.getCity() + address.getStreet();
    }
}

5. 自定義映射與高級(jí)配置

5.1 自定義映射方法

@Mapper(componentModel = "spring")
public abstract class CustomUserMapper {
    
    // 使用抽象類以便實(shí)現(xiàn)自定義方法
    
    public abstract UserDTO toDTO(User user);
    
    public abstract List<UserDTO> toDTOList(List<User> users);
    
    // 自定義映射邏輯
    public UserDTO toCustomDTO(User user) {
        if (user == null) {
            return null;
        }
        
        UserDTO dto = new UserDTO();
        dto.setId(user.getId());
        dto.setUsername(user.getUsername().toUpperCase()); // 自定義處理
        dto.setEmail(user.getEmail());
        dto.setCreateTime(formatDateTime(user.getCreateTime()));
        
        return dto;
    }
    
    protected String formatDateTime(LocalDateTime dateTime) {
        if (dateTime == null) {
            return null;
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return dateTime.format(formatter);
    }
}

5.2 使用表達(dá)式和常量

@Mapper(componentModel = "spring")
public interface ExpressionMapper {
    
    // 使用常量
    @Mapping(target = "sourceSystem", constant = "WEB_APPLICATION")
    // 使用默認(rèn)值
    @Mapping(source = "status", target = "status", defaultValue = "1")
    // 使用表達(dá)式
    @Mapping(target = "createTime", 
             expression = "java(java.time.LocalDateTime.now())")
    @Mapping(target = "fullName", 
             expression = "java(user.getFirstName() + \" \" + user.getLastName())")
    UserDTO toDTO(User user);
    
    // 條件映射
    @Mapping(target = "email", 
             condition = "java(user.getEmail() != null && user.getEmail().contains(\"@\"))")
    UserDTO toDTOConditional(User user);
}

5.3 繼承映射配置

// 基礎(chǔ)映射配置
@MapperConfig
public interface BaseMapperConfig {
    
    @Mapping(target = "createTime", ignore = true)
    @Mapping(target = "updateTime", ignore = true)
    User toEntity(UserDTO dto);
}

// 具體映射器繼承配置
@Mapper(componentModel = "spring", config = BaseMapperConfig.class)
public interface UserMapper extends BaseMapperConfig {
    
    // 繼承基礎(chǔ)配置,可以覆蓋或添加新映射
    @Mapping(target = "createTime", source = "registrationDate")
    @Override
    User toEntity(UserDTO dto);
    
    // 新增映射方法
    UserDTO toDTO(User user);
}

6. Spring Boot 集成實(shí)踐

6.1 配置類定義

@Configuration
@MapperScan(basePackages = "com.example.mapper")
public class MapStructAutoConfiguration {
    
    @Bean
    @Primary
    public UserMapper userMapper() {
        return new UserMapperImpl();
    }
    
    @Bean
    public ProductMapper productMapper() {
        return new ProductMapperImpl();
    }
}

6.2 服務(wù)層使用

@Service
@Transactional
public class UserService {
    
    private final UserRepository userRepository;
    private final UserMapper userMapper;
    
    public UserService(UserRepository userRepository, UserMapper userMapper) {
        this.userRepository = userRepository;
        this.userMapper = userMapper;
    }
    
    public UserDTO createUser(UserCreateRequest request) {
        User user = userMapper.toEntity(request);
        user.setCreateTime(LocalDateTime.now());
        user.setStatus(1);
        
        User savedUser = userRepository.save(user);
        return userMapper.toDTO(savedUser);
    }
    
    public UserDTO getUserById(Long id) {
        return userRepository.findById(id)
                .map(userMapper::toDTO)
                .orElseThrow(() -> new ResourceNotFoundException("用戶不存在"));
    }
    
    public Page<UserDTO> getUsers(Pageable pageable) {
        Page<User> userPage = userRepository.findAll(pageable);
        return userPage.map(userMapper::toDTO);
    }
    
    public List<UserDTO> searchUsers(UserSearchCriteria criteria) {
        List<User> users = userRepository.findByCriteria(criteria);
        return userMapper.toDTOList(users);
    }
}

6.3 控制器層應(yīng)用

@RestController
@RequestMapping("/api/users")
@Validated
public class UserController {
    
    private final UserService userService;
    
    public UserController(UserService userService) {
        this.userService = userService;
    }
    
    @PostMapping
    public ResponseEntity<UserDTO> createUser(@Valid @RequestBody UserCreateRequest request) {
        UserDTO userDTO = userService.createUser(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(userDTO);
    }
    
    @GetMapping("/{id}")
    public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
        UserDTO userDTO = userService.getUserById(id);
        return ResponseEntity.ok(userDTO);
    }
    
    @GetMapping
    public ResponseEntity<Page<UserDTO>> getUsers(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(defaultValue = "id") String sort) {
        
        Pageable pageable = PageRequest.of(page, size, Sort.by(sort));
        Page<UserDTO> userPage = userService.getUsers(pageable);
        return ResponseEntity.ok(userPage);
    }
    
    @PutMapping("/{id}")
    public ResponseEntity<UserDTO> updateUser(
            @PathVariable Long id,
            @Valid @RequestBody UserUpdateRequest request) {
        
        UserDTO userDTO = userService.updateUser(id, request);
        return ResponseEntity.ok(userDTO);
    }
}

7. 復(fù)雜業(yè)務(wù)場(chǎng)景實(shí)戰(zhàn)

7.1 訂單系統(tǒng)映射

領(lǐng)域模型

// 訂單實(shí)體
@Data
@Entity
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String orderNo;
    private BigDecimal totalAmount;
    private Integer status;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
    
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<OrderItem> items;
    
    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;
}

// 訂單項(xiàng)實(shí)體
@Data
@Entity
public class OrderItem {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "order_id")
    private Order order;
    
    @ManyToOne
    @JoinColumn(name = "product_id")
    private Product product;
    
    private Integer quantity;
    private BigDecimal price;
    private BigDecimal subtotal;
}

// 訂單 DTO
@Data
public class OrderDTO {
    private Long id;
    private String orderNo;
    private BigDecimal totalAmount;
    private String statusDesc;
    private String createTime;
    private String updateTime;
    private String customerName;
    private String customerEmail;
    private List<OrderItemDTO> items;
}

// 訂單項(xiàng) DTO
@Data
public class OrderItemDTO {
    private Long productId;
    private String productName;
    private Integer quantity;
    private BigDecimal price;
    private BigDecimal subtotal;
}

復(fù)雜映射器

@Mapper(componentModel = "spring", uses = {ProductMapper.class})
public interface OrderMapper {
    
    @Mapping(source = "user.username", target = "customerName")
    @Mapping(source = "user.email", target = "customerEmail")
    @Mapping(target = "statusDesc", expression = "java(convertOrderStatus(order.getStatus()))")
    @Mapping(source = "createTime", target = "createTime", dateFormat = "yyyy-MM-dd HH:mm:ss")
    @Mapping(source = "updateTime", target = "updateTime", dateFormat = "yyyy-MM-dd HH:mm:ss")
    OrderDTO toDTO(Order order);
    
    List<OrderDTO> toDTOList(List<Order> orders);
    
    @Mapping(source = "product.id", target = "productId")
    @Mapping(source = "product.name", target = "productName")
    OrderItemDTO itemToDTO(OrderItem item);
    
    List<OrderItemDTO> itemsToDTO(List<OrderItem> items);
    
    default String convertOrderStatus(Integer status) {
        switch (status) {
            case 0: return "待支付";
            case 1: return "已支付";
            case 2: return "已發(fā)貨";
            case 3: return "已完成";
            case 4: return "已取消";
            default: return "未知狀態(tài)";
        }
    }
    
    // 更新映射 - 只更新非空字段
    @Mapping(target = "id", ignore = true)
    @Mapping(target = "orderNo", ignore = true)
    @Mapping(target = "createTime", ignore = true)
    void updateOrderFromDTO(OrderUpdateDTO dto, @MappingTarget Order order);
}

7.2 繼承體系映射

繼承結(jié)構(gòu)對(duì)象

// 基礎(chǔ)支付類
@Data
public abstract class Payment {
    private Long id;
    private BigDecimal amount;
    private Integer status;
    private LocalDateTime createTime;
}

// 支付寶支付
@Data
@EqualsAndHashCode(callSuper = true)
public class AlipayPayment extends Payment {
    private String alipayTradeNo;
    private String buyerId;
    private String buyerEmail;
}

// 微信支付
@Data
@EqualsAndHashCode(callSuper = true)
public class WechatPayment extends Payment {
    private String wechatTradeNo;
    private String openId;
    private String appId;
}

// 支付 DTO
@Data
public class PaymentDTO {
    private Long id;
    private BigDecimal amount;
    private String statusDesc;
    private String createTime;
    private String paymentType;
    private Map<String, Object> extraInfo;
}

繼承映射器

@Mapper(componentModel = "spring")
public interface PaymentMapper {
    
    // 使用子類映射器
    AlipayMapper alipayMapper();
    WechatMapper wechatMapper();
    
    default PaymentDTO toDTO(Payment payment) {
        if (payment instanceof AlipayPayment) {
            return alipayMapper.toDTO((AlipayPayment) payment);
        } else if (payment instanceof WechatPayment) {
            return wechatMapper.toDTO((WechatPayment) payment);
        } else {
            return baseToDTO(payment);
        }
    }
    
    @Mapping(target = "paymentType", constant = "BASE")
    @Mapping(target = "extraInfo", ignore = true)
    PaymentDTO baseToDTO(Payment payment);
    
    List<PaymentDTO> toDTOList(List<Payment> payments);
}

@Mapper(componentModel = "spring")
public interface AlipayMapper {
    
    @Mapping(target = "paymentType", constant = "ALIPAY")
    @Mapping(target = "extraInfo", expression = "java(createAlipayExtraInfo(alipayPayment))")
    PaymentDTO toDTO(AlipayPayment alipayPayment);
    
    default Map<String, Object> createAlipayExtraInfo(AlipayPayment payment) {
        Map<String, Object> extra = new HashMap<>();
        extra.put("alipayTradeNo", payment.getAlipayTradeNo());
        extra.put("buyerId", payment.getBuyerId());
        extra.put("buyerEmail", payment.getBuyerEmail());
        return extra;
    }
}

@Mapper(componentModel = "spring")
public interface WechatMapper {
    
    @Mapping(target = "paymentType", constant = "WECHAT")
    @Mapping(target = "extraInfo", expression = "java(createWechatExtraInfo(wechatPayment))")
    PaymentDTO toDTO(WechatPayment wechatPayment);
    
    default Map<String, Object> createWechatExtraInfo(WechatPayment payment) {
        Map<String, Object> extra = new HashMap<>();
        extra.put("wechatTradeNo", payment.getWechatTradeNo());
        extra.put("openId", payment.getOpenId());
        extra.put("appId", payment.getAppId());
        return extra;
    }
}

8. 性能優(yōu)化與最佳實(shí)踐

8.1 性能優(yōu)化策略

批量映射優(yōu)化

@Mapper(componentModel = "spring")
public interface OptimizedMapper {
    
    // 使用 @Named 注解優(yōu)化重復(fù)映射
    @Named("toUserDTO")
    @Mapping(target = "statusDesc", expression = "java(convertStatus(user.getStatus()))")
    UserDTO toUserDTO(User user);
    
    // 批量映射使用相同邏輯
    List<UserDTO> toUserDTOList(List<User> users);
    
    // 避免在循環(huán)中調(diào)用復(fù)雜邏輯
    default List<UserDTO> optimizedToDTOList(List<User> users) {
        if (users == null) {
            return null;
        }
        
        List<UserDTO> list = new ArrayList<>(users.size());
        for (User user : users) {
            list.add(toUserDTO(user));
        }
        
        return list;
    }
}

懶加載處理

@Mapper(componentModel = "spring")
public interface LazyLoadingMapper {
    
    @Mapping(target = "orderItems", expression = "java(handleLazyItems(order.getItems()))")
    OrderDTO toDTO(Order order);
    
    default List<OrderItemDTO> handleLazyItems(List<OrderItem> items) {
        // 處理 Hibernate 懶加載
        if (items instanceof PersistentCollection && !((PersistentCollection) items).wasInitialized()) {
            return Collections.emptyList();
        }
        return itemsToDTO(items);
    }
    
    List<OrderItemDTO> itemsToDTO(List<OrderItem> items);
}

8.2 最佳實(shí)踐

配置統(tǒng)一管理

@MapperConfig(
    componentModel = "spring",
    unmappedTargetPolicy = ReportingPolicy.IGNORE,
    nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE
)
public interface CentralConfig {
    
    @Mapping(target = "id", ignore = true)
    @Mapping(target = "createTime", ignore = true)
    @Mapping(target = "updateTime", ignore = true)
    void toEntity(Object dto, @MappingTarget Object entity);
}

@Mapper(config = CentralConfig.class)
public interface UserMapper extends CentralConfig {
    // 具體映射方法
}

錯(cuò)誤處理

@Mapper(componentModel = "spring")
public interface SafeMapper {
    
    default UserDTO safeToDTO(User user) {
        try {
            return toDTO(user);
        } catch (Exception e) {
            log.error("對(duì)象轉(zhuǎn)換失敗: {}", user, e);
            return createFallbackDTO(user);
        }
    }
    
    UserDTO toDTO(User user);
    
    default UserDTO createFallbackDTO(User user) {
        UserDTO dto = new UserDTO();
        if (user != null) {
            dto.setId(user.getId());
            dto.setUsername("轉(zhuǎn)換失敗");
        }
        return dto;
    }
}

9. 測(cè)試策略

9.1 單元測(cè)試

@ExtendWith(MockitoExtension.class)
class UserMapperTest {
    
    @InjectMocks
    private UserMapperImpl userMapper;
    
    @Test
    void testToDTO() {
        // 準(zhǔn)備測(cè)試數(shù)據(jù)
        User user = new User();
        user.setId(1L);
        user.setUsername("testuser");
        user.setEmail("test@example.com");
        user.setCreateTime(LocalDateTime.now());
        user.setStatus(1);
        
        // 執(zhí)行轉(zhuǎn)換
        UserDTO dto = userMapper.toDTO(user);
        
        // 驗(yàn)證結(jié)果
        assertThat(dto.getId()).isEqualTo(1L);
        assertThat(dto.getUsername()).isEqualTo("testuser");
        assertThat(dto.getEmail()).isEqualTo("test@example.com");
        assertThat(dto.getStatusDesc()).isEqualTo("啟用");
    }
    
    @Test
    void testToDTOList() {
        List<User> users = Arrays.asList(
            createUser(1L, "user1"),
            createUser(2L, "user2")
        );
        
        List<UserDTO> dtos = userMapper.toDTOList(users);
        
        assertThat(dtos).hasSize(2);
        assertThat(dtos.get(0).getUsername()).isEqualTo("user1");
        assertThat(dtos.get(1).getUsername()).isEqualTo("user2");
    }
    
    private User createUser(Long id, String username) {
        User user = new User();
        user.setId(id);
        user.setUsername(username);
        user.setEmail(username + "@example.com");
        user.setStatus(1);
        return user;
    }
}

9.2 集成測(cè)試

@SpringBootTest
@Transactional
class UserMapperIntegrationTest {
    
    @Autowired
    private UserMapper userMapper;
    
    @Autowired
    private UserRepository userRepository;
    
    @Test
    void testEntityToDTOMapping() {
        // 創(chuàng)建并保存實(shí)體
        User user = new User();
        user.setUsername("integrationuser");
        user.setEmail("integration@example.com");
        user.setPassword("password");
        user.setCreateTime(LocalDateTime.now());
        user.setStatus(1);
        
        User savedUser = userRepository.save(user);
        
        // 測(cè)試映射
        UserDTO dto = userMapper.toDTO(savedUser);
        
        assertThat(dto.getId()).isNotNull();
        assertThat(dto.getUsername()).isEqualTo("integrationuser");
        assertThat(dto.getEmail()).isEqualTo("integration@example.com");
    }
}

10. 常見問題與解決方案

10.1 編譯問題

問題1:映射器實(shí)現(xiàn)類未生成

// 解決方案:檢查注解處理器配置
@Mapper(componentModel = "spring") // 確保使用正確注解
public interface UserMapper {
    UserDTO toDTO(User user);
}

問題2:依賴沖突

<!-- 確保 MapStruct 版本兼容 -->
<properties>
    <org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
</properties>

10.2 運(yùn)行時(shí)問題

問題1:空指針異常

@Mapper(componentModel = "spring")
public interface SafeMapper {
    
    // 使用 nullValuePropertyMappingStrategy 避免 NPE
    @Mapping(target = "statusDesc", 
             nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_NULL)
    UserDTO toDTO(User user);
}

問題2:循環(huán)依賴

// 使用 @Context 避免循環(huán)依賴
@Mapper(componentModel = "spring")
public interface OrderMapper {
    
    OrderDTO toDTO(Order order, @Context CycleAvoidingMappingContext context);
}

// 循環(huán)依賴上下文
public class CycleAvoidingMappingContext {
    private Map<Object, Object> knownInstances = new IdentityHashMap<>();
    
    @SuppressWarnings("unchecked")
    public <T> T getMappedInstance(Object source, Class<T> targetType) {
        return (T) knownInstances.get(source);
    }
    
    public void storeMappedInstance(Object source, Object target) {
        knownInstances.put(source, target);
    }
}

總結(jié)

MapStruct 是一個(gè)功能強(qiáng)大、性能優(yōu)異的對(duì)象映射框架,特別適合在 Spring Boot 項(xiàng)目中使用。通過本文的詳細(xì)講解,您應(yīng)該已經(jīng)掌握了

  • 基礎(chǔ)配置和簡(jiǎn)單映射 - 快速上手基礎(chǔ)功能
  • 高級(jí)映射特性 - 處理復(fù)雜業(yè)務(wù)場(chǎng)景
  • Spring Boot 集成 - 在實(shí)際項(xiàng)目中的應(yīng)用
  • 性能優(yōu)化 - 提升系統(tǒng)性能的最佳實(shí)踐
  • 測(cè)試策略 - 保證代碼質(zhì)量的方法
  • 問題解決 - 應(yīng)對(duì)常見問題的方案

到此這篇關(guān)于SpringBoot 對(duì)象轉(zhuǎn)換 MapStruct的實(shí)現(xiàn)小結(jié)的文章就介紹到這了,更多相關(guān)SpringBoot 對(duì)象轉(zhuǎn)換 MapStruct內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java實(shí)現(xiàn)二分法的完整代碼

    java實(shí)現(xiàn)二分法的完整代碼

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)二分法的完整代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-11-11
  • IntelliJ IDEA窗口組件具體操作方法

    IntelliJ IDEA窗口組件具體操作方法

    IDEA剛接觸不久,各種常用工具窗口找不到,不小心關(guān)掉不知道從哪里打開,今天小編給大家分享這個(gè)問題的解決方法,感興趣的朋友一起看看吧
    2021-09-09
  • Java實(shí)現(xiàn)阿里云短信接口的示例

    Java實(shí)現(xiàn)阿里云短信接口的示例

    這篇文章主要介紹了Java實(shí)現(xiàn)阿里云短信接口的示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Java接口和抽象類有什么區(qū)別

    Java接口和抽象類有什么區(qū)別

    這篇文章主要介紹了Java接口和抽象類有什么區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-12-12
  • 淺談一下maven優(yōu)缺點(diǎn)及使用和特點(diǎn)

    淺談一下maven優(yōu)缺點(diǎn)及使用和特點(diǎn)

    這篇文章主要介紹了淺談一下maven優(yōu)缺點(diǎn)及使用和特點(diǎn),一個(gè)項(xiàng)目管理工具軟件,那么maven項(xiàng)目有什么優(yōu)缺點(diǎn)呢,讓我們一起來看看吧
    2023-03-03
  • idea2020導(dǎo)入spring5.1的源碼詳細(xì)教程

    idea2020導(dǎo)入spring5.1的源碼詳細(xì)教程

    這篇文章主要介紹了idea2020導(dǎo)入spring5.1的源碼的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Freemarker中的3種循環(huán)模式

    Freemarker中的3種循環(huán)模式

    這篇文章主要介紹了Freemarker中的3種循環(huán)模式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • Java遞歸遍歷文件目錄代碼實(shí)例

    Java遞歸遍歷文件目錄代碼實(shí)例

    這篇文章主要介紹了Java遞歸遍歷文件目錄代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • Java如何實(shí)現(xiàn)圖片的疊加與拼接操作

    Java如何實(shí)現(xiàn)圖片的疊加與拼接操作

    這篇文章主要介紹了Java如何實(shí)現(xiàn)圖片的疊加與拼接操作,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • FreeSWITCH跨NAT部署配置詳解

    FreeSWITCH跨NAT部署配置詳解

    這篇文章主要為大家介紹了FreeSWITCH跨NAT部署配置詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02

最新評(píng)論

玉田县| 千阳县| 阜平县| 肥西县| 灵石县| 平顺县| 邵武市| 平江县| 文登市| 娱乐| 武夷山市| 濮阳县| 方城县| 瓦房店市| 尖扎县| 长武县| 高安市| 松阳县| 琼海市| 铁岭县| 闸北区| 宜君县| 铁岭市| 襄汾县| 新余市| 扶风县| 宜川县| 广宗县| 安平县| 晋江市| 威海市| 涿鹿县| 通州区| 清苑县| 浪卡子县| 景德镇市| 石棉县| 喜德县| 墨竹工卡县| 昂仁县| 商南县|