如何通过MapStruct将实体的多个字段映射到DTO的List集合?以Bank与BankDto为例
Absolutely! MapStruct makes this kind of custom field mapping straightforward—you have a few clean options to convert those individual employee1/employee2 fields into the employeeList collection in BankDto. Let's walk through the most common approaches:
First, let's recap your classes for clarity:
// Your entity class class Bank { private String name; private String employee1; private String employee2; // Getters and setters omitted for brevity } // Your DTO class class BankDto { private String name; private List<String> employeeList; // Getters and setters omitted for brevity }
Approach 1: Use @Mapping with an expression
For simple cases where you just want to wrap the two fields into a list (even if one is null), you can use MapStruct's expression attribute directly in the @Mapping annotation:
import org.mapstruct.Mapper; import org.mapstruct.Mapping; import java.util.Arrays; @Mapper(componentModel = "spring") // Use "default" if you don't need Spring integration public interface BankMapper { @Mapping(target = "employeeList", expression = "java(Arrays.asList(bank.getEmployee1(), bank.getEmployee2()))") BankDto bankToBankDto(Bank bank); }
Note: This will include null values in the list if either employee1 or employee2 is null. If you want to exclude nulls, see the next approaches.
Approach 2: Use a custom default method (for extra logic)
If you need to add filtering (like removing null values) or other custom logic, a default method in your mapper gives you full control:
import org.mapstruct.Mapper; import org.mapstruct.Mapping; import java.util.ArrayList; import java.util.List; @Mapper(componentModel = "spring") public interface BankMapper { // Map all fields except employeeList first @Mapping(target = "employeeList", ignore = true) BankDto bankToBankDto(Bank bank); // Custom method to handle the employee list default BankDto mapBankToDtoWithEmployees(Bank bank) { BankDto dto = bankToBankDto(bank); List<String> employees = new ArrayList<>(); if (bank.getEmployee1() != null) { employees.add(bank.getEmployee1()); } if (bank.getEmployee2() != null) { employees.add(bank.getEmployee2()); } dto.setEmployeeList(employees); return dto; } }
Approach 3: Use @AfterMapping (cleaner post-processing)
Another clean option is to use the @AfterMapping annotation to handle the employee list after the basic mapping is done:
import org.mapstruct.AfterMapping; import org.mapstruct.Mapper; import org.mapstruct.MappingTarget; import java.util.ArrayList; import java.util.List; @Mapper(componentModel = "spring") public interface BankMapper { // Basic mapping (MapStruct handles the 'name' field automatically) BankDto bankToBankDto(Bank bank); // Post-process the DTO to populate employeeList @AfterMapping default void populateEmployeeList(Bank bank, @MappingTarget BankDto dto) { List<String> employees = new ArrayList<>(); if (bank.getEmployee1() != null) { employees.add(bank.getEmployee1()); } if (bank.getEmployee2() != null) { employees.add(bank.getEmployee2()); } dto.setEmployeeList(employees); } }
How to use the mapper
MapStruct automatically generates an implementation of your mapper interface at compile time. You can inject it (if using Spring) or instantiate it manually:
// With Spring @Autowired private BankMapper bankMapper; // Or manual instantiation (for non-Spring projects) BankMapper bankMapper = Mappers.getMapper(BankMapper.class); // Convert a Bank to BankDto Bank bank = new Bank(); bank.setName("First National Bank"); bank.setEmployee1("Alice"); bank.setEmployee2("Bob"); BankDto dto = bankMapper.bankToBankDto(bank); // dto.getEmployeeList() will contain ["Alice", "Bob"]
All these approaches work well—pick the one that best fits your needs (simple expression for basic cases, default method/@AfterMapping for more control).
内容的提问来源于stack exchange,提问作者Andrey

