武陟网站建设,教育培训网站建设ppt,做网站推广有作用没,网搜网MapStruct是一个代码生成器#xff0c;它基于约定优于配置的原则#xff0c;使用Java注解来简化从源对象到目标对象的映射过程。它主要用于减少样板代码#xff0c;提高开发效率#xff0c;并且通过编译时代码生成来保证性能。 我的个人实践方面是在2021年前那时候在项目中… MapStruct是一个代码生成器它基于约定优于配置的原则使用Java注解来简化从源对象到目标对象的映射过程。它主要用于减少样板代码提高开发效率并且通过编译时代码生成来保证性能。 我的个人实践方面是在2021年前那时候在项目中使用dozer较多后来发现MapStruct处理对象映射属性复制更灵活方便就直接转向使用MapStruct。 学习MapStruct的用法最简单高效就是去阅读官网的文档MapStruct – Java bean mappings, the easy way!以及下载官方的示例代码GitHub - mapstruct/mapstruct-examples: Examples for using MapStruct
各种用法还是比较详细的
目录
1. java对象基本属性映射
2.设置属性的默认值
3.使用条件表达式
4.映射集合类属性
5.使用自定义映射方法
6.继承和多态
7. 使用组件模型
8.忽略默认值
9.MapStruct的注解
10.使用 Mapper 注解定义映射器
11.映射多个源对象到一个目标对象
12. 映射一个源对象到多个目标对象
13.SpringBoot项目整合使用MapStruct 以下是MapStruct的一些常见用法和相应的代码示例
1. java对象基本属性映射
Mapper
public interface PersonMapper {PersonMapper INSTANCE Mappers.getMapper(PersonMapper.class);Mapping(target address, source personAddress)PersonDto personToPersonDto(Person person);
}class Person {private String name;private Address personAddress;// getters and setters
}class PersonDto {private String name;private AddressDto address;// getters and setters
}class Address {private String street;// getters and setters
}class AddressDto {private String street;// getters and setters
}
如果有多个属性值的名称不一样则需要使用Mappings注解来使用多个 Mapping来制定属性映射关系
比如
Mapper
public interface MyMapper {Mappings({Mapping(target name, source fullName),Mapping(target age, source years)})void updateTargetFromSource(Source source,Target target);
}2.设置属性的默认值
Mapper
public interface UserMapper {UserMapper INSTANCE Mappers.getMapper(UserMapper.class);Mapping(target email, expression java(email ! null ? email : defaultemail.com))UserDto userToUserDto(User user);
}class User {private String name;private String email;// getters and setters
}class UserDto {private String name;private String email;// getters and setters
}
3.使用条件表达式
Mapper
public interface OrderMapper {OrderMapper INSTANCE Mappers.getMapper(OrderMapper.class);Mapping(target status, expression java(order.isShipped() ? \SHIPPED\ : \PENDING\))OrderDto orderToOrderDto(Order order);
}class Order {private boolean shipped;// getters and setters
}class OrderDto {private String status;// getters and setters
}
4.映射集合类属性
Mapper
public interface ItemMapper {ItemMapper INSTANCE Mappers.getMapper(ItemMapper.class);Mapping(target items, expression java(mapItemsToItemDtos(order.getItems())))OrderDto orderToOrderDto(Order order);ListItemDto mapItemsToItemDtos(ListItem items);
}class Order {private ListItem items;// getters and setters
}class OrderDto {private ListItemDto items;// getters and setters
}class Item {// properties and methods
}class ItemDto {// properties and methods
}
5.使用自定义映射方法
Mapper
public interface CarMapper {CarMapper INSTANCE Mappers.getMapper(CarMapper.class);Mapping(licensePlate, ignore true)CarDto carToCarDto(MappingTarget CarDto target, Car car);void setLicensePlateIfPresent(MappingTarget CarDto target, Car car);
}class Car {private String make;private String licensePlate;// getters and setters
}class CarDto {private String make;// getters and setters
}// 在项目编译后MapStruct会自动在映射器实现类中实现该方法
void setLicensePlateIfPresent(CarDto target, Car car) {if (car.getLicensePlate() ! null !car.getLicensePlate().isEmpty()) {target.setLicensePlate(car.getLicensePlate());}
}
MappingTarget 是 MapStruct 中一个重要的注解用于标识目标对象。在使用 MapStruct 进行对象映射时有时我们需要将映射结果更新到一个已经存在的实例中而不是创建一个新的对象。MappingTarget 就是为此目的而设计的。
或者你可以直接在映射接口中实现一个默认的方法来自定义映射关系
public interface MyMapper {// 其他映射方法// 自定义映射逻辑的默认方法void customMapping(MappingTarget MyTarget target, MySource source) {if (source.getCondition()) {target.setSomeProperty(valueIfConditionTrue);} else {target.setSomeProperty(valueIfConditionFalse);}
}
}
或者直接调用另外的映射方法做属性映射
/** Copyright MapStruct Authors.** Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0*/
package org.mapstruct.example.mapper;import java.lang.annotation.Target;
import java.util.Map;import org.mapstruct.AfterMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.example.dto.Department;
import org.mapstruct.example.dto.Employee;
import org.mapstruct.factory.Mappers;/*** author Filip Hrisafov*/
Mapper
public interface MapToBeanMapper {MapToBeanMapper INSTANCE Mappers.getMapper(MapToBeanMapper.class);Mapping(target department, ignore true)Employee fromMap(MapString, String map);AfterMappingdefault void finishEmployee(MappingTarget Employee employee, MapString, String map) {employee.setDepartment(fromMapToDepartment(map));}Mapping(target id, source did)Mapping(target name, source dname)Department fromMapToDepartment(MapString, String map);
}这段代码通过 MapStruct 提供了一个完整的映射解决方案用于将 MapString, String 转换为 Employee 对象并通过一个 AfterMapping 方法在映射完成后手动设置 Employee 对象的 department 字段。
6.继承和多态
Mapper
public interface AnimalMapper {AnimalMapper INSTANCE Mappers.getMapper(AnimalMapper.class);AnimalDto animalToAnimalDto(Animal animal);
}class Animal {private String name;// getters and setters
}class Cat extends Animal {private String favoriteToy;// getters and setters
}class AnimalDto {private String name;// getters and setters
}class CatDto extends AnimalDto {private String favoriteToy;// getters and setters
}
MapStruct会自动处理继承关系将子类的属性也映射到相应的DTO中。
7. 使用组件模型
MapStruct允许开发者定义组件这些组件可以包含自定义的映射逻辑可以被多个映射器使用。
Mapper(componentModel spring,usesDepartmentNameMapper.class)
public interface EmployeeMapper {EmployeeMapper INSTANCE Mappers.getMapper(EmployeeMapper.class);Mapping(target departmentName, source department.name)EmployeeDto employeeToEmployeeDto(Employee employee);
}Component
public class DepartmentNameMapper {public String toDepartmentName(Department department) {return department.getName();}
}
在这个例子中DepartmentNameMapper是一个Spring组件它提供了一个方法来获取部门的名称这个方法可以在映射过程中被使用。
这些只是MapStruct的一些基本用法。MapStruct非常灵活支持许多高级特性如映射多个源对象到一个目标对象、使用自定义的映射方法、处理复杂的数据结构等
8.忽略默认值
在映射过程中你可能希望忽略源对象中的默认值只复制非默认值的属性。
Mapper
public interface ProductMapper {ProductMapper INSTANCE Mappers.getMapper(ProductMapper.class);Mapping(target price, ignore true)ProductDto productToProductDto(Product product);
}class Product {private double price 0.0; // 默认值// 其他属性和getter/setter
}class ProductDto {private double price;// getter/setter
}
在这个例子中ProductDto 的 price 字段将不会被 Product 对象的默认值 0.0 填充
9.MapStruct的注解
MapStruct 允许你使用 Mapping 注解来指定映射关系包括如何从源属性映射到目标属性。
Mapper
public interface UserMapper {UserMapper INSTANCE Mappers.getMapper(UserMapper.class);Mapping(target fullName, expression java(user.getFirstName() user.getLastName()))UserDto userToUserDto(User user);
}class User {private String firstName;private String lastName;// getters and setters
}class UserDto {private String fullName;// getter/setter
}
在这个例子中UserDto 的 fullName 属性是通过连接 User 对象的 firstName 和 lastName 属性来生成的。
使用MappingTarget可以自定义源对象到目标对象的属性的映射关系
使用 AfterMapping 或 BeforeMapping 注解结合 MappingTarget 来在映射前后执行自定义逻辑。上边的有结合 AfterMapping的示例
与AfterMapping相对应MapStruct还提供了BeforeMapping注解用于在映射开始之前执行自定义逻辑。
Mapper
public interface UserMapper {UserMapper INSTANCE Mappers.getMapper(UserMapper.class);BeforeMappingdefault void beforeMapping(MappingTarget UserDto target, User source) {// 执行映射前的自定义逻辑例如初始化或验证源对象if (source null) {throw new IllegalArgumentException(Source user cannot be null);}}UserDto userToUserDto(User user);
}
10.使用 Mapper 注解定义映射器
Mapper 注解用于定义映射器接口你可以通过这个注解来配置映射器的行为从而使用其他的自定义的映射器
Mapper(uses {DateMapper.class, EnumMapper.class})
public interface MyCustomMapper {// 映射方法
}Mapper
public abstract class DateMapper {Mapping(target dateAsString, expression java(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE.format(source.getDate())))abstract void mapDate(MappingTarget MyTarget target, MySource source);
}Mapper
public abstract class EnumMapper {// 映射枚举类型的逻辑
}
在这个例子中MyCustomMapper 使用了 uses 属性来指定其他映射器类这些类提供了额外的映射逻辑。
示例二
/** Copyright MapStruct Authors.** Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0*/
package org.mapstruct.example.mapper;import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.example.dto.Customer;
import org.mapstruct.example.dto.CustomerDto;
import org.mapstruct.factory.Mappers;/*** author Filip Hrisafov*/
Mapper(uses { OrderItemMapper.class })
public interface CustomerMapper {CustomerMapper MAPPER Mappers.getMapper( CustomerMapper.class );Mapping(source orders, target orderItems)Mapping(source customerName, target name)Customer toCustomer(CustomerDto customerDto);InheritInverseConfigurationCustomerDto fromCustomer(Customer customer);
}/** Copyright MapStruct Authors.** Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0*/
package org.mapstruct.example.mapper;import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.Mapper;
import org.mapstruct.example.dto.OrderItem;
import org.mapstruct.example.dto.OrderItemDto;
import org.mapstruct.factory.Mappers;/*** author Filip Hrisafov*/
Mapper
public interface OrderItemMapper {OrderItemMapper MAPPER Mappers.getMapper(OrderItemMapper.class);OrderItem toOrder(OrderItemDto orderItemDto);InheritInverseConfigurationOrderItemDto fromOrder(OrderItem orderItem);
}InheritInverseConfiguration 是 MapStruct 中的一个注解用于继承已有映射方法的逆向配置。这在需要定义双向映射从一个类到另一个类然后从另一个类再映射回第一个类时非常有用可以减少代码重复提高代码的可维护性。
11.使用 Named 注解
在mapstruct的源码中Named注解类就有对应的示例
/** Copyright MapStruct Authors.** Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0*/
package org.mapstruct;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** Marks mapping methods with the given qualifier name. Can be used to qualify a single method or all methods of a given* type by specifying this annotation on the type level.* * Will be used to select the correct mapping methods when mapping a bean property type, element of an iterable type* or the key/value of a map type.* * Example (both methods of {code Titles} are capable to convert a string, but the ambiguity is resolved by applying* the qualifiers in {code Mapping}:** * Named(TitleTranslator)* public class Titles {** Named(EnglishToGerman)* public String translateTitleEG(String title) {* // some mapping logic* }** Named(GermanToEnglish)* public String translateTitleGE(String title) {* // some mapping logic* }* }** Mapper( uses Titles.class )* public interface MovieMapper {** Mapping( target title, qualifiedByName { TitleTranslator, EnglishToGerman } )* GermanRelease toGerman( OriginalRelease movies );** }** The following implementation of {code MovieMapper} will be generated:*** public class MovieMapperImpl implements MovieMapper {* private final Titles titles new Titles();** Override* public GermanRelease toGerman(OriginalRelease movies) {* if ( movies null ) {* return null;* }** GermanRelease germanRelease new GermanRelease();** germanRelease.setTitle( titles.translateTitleEG( movies.getTitle() ) );** return germanRelease;* }* }*** author Sjaak Derksen* see org.mapstruct.Mapping#qualifiedByName()* see IterableMapping#qualifiedByName()* see MapMapping#keyQualifiedByName()* see MapMapping#valueQualifiedByName()*/
Target( { ElementType.TYPE, ElementType.METHOD } )
Retention( RetentionPolicy.CLASS )
Qualifier
public interface Named {/*** A name qualifying the annotated element** return the name.*/String value();
}在 MapStruct 中Named 注解主要用于自定义方法以便在映射器中引用这些方法。通过给这些方法加上 Named 注解并在 Mapping 注解中引用这些方法可以实现复杂的映射逻辑。MapStruct 支持 JSR-330 的 Named 注解这使得定义和使用自定义的转换逻辑更加灵活和清晰。
使用Named注解定义自定义方法
假设我们有一个自定义的方法需要在映射过程中使用我们可以使用 Named 注解为该方法命名并在 Mapping 注解中引用它。
示例
假设我们有以下两个类
public class Source {private String name;private String date;// getters and setters
}public class Target {private String fullName;private LocalDate birthDate;// getters and setters
}我们想要将 Source 的 name 映射到 Target 的 fullName并将 date 字符串转换为 LocalDate 并映射到 birthDate。为此我们可以定义一个自定义的日期转换方法。
定义映射器接口和自定义方法
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;import java.time.LocalDate;
import java.time.format.DateTimeFormatter;Mapper
public interface SourceToTargetMapper {SourceToTargetMapper INSTANCE Mappers.getMapper(SourceToTargetMapper .class);Mapping(source name, target fullName)Mapping(source date, target birthDate, qualifiedByName stringToLocalDate)Target sourceToTarget(Source source);Named(stringToLocalDate)default LocalDate stringToLocalDate(String date) {return LocalDate.parse(date, DateTimeFormatter.ofPattern(yyyy-MM-dd));}
}测试使用映射器
public class TestMapping {public static void main(String[] args) {Source source new Source();source.setName(John Doe);source.setDate(1980-01-01);Target target SourceToTargetMapper.INSTANCE.sourceToTarget(source);System.out.println(Full Name: target.getFullName()); // 输出: John DoeSystem.out.println(Birth Date: target.getBirthDate()); // 输出: 1980-01-01}
}11.映射多个源对象到一个目标对象
MapStruct允许你映射多个源对象到一个目标对象这对于需要将来自不同源的数据合并到一个目标对象的情况非常有用。MapStruct 提供了灵活的注解配置使得这种映射变得直观和易于实现。
示例假设我们有以下两个源对象 Source1 和 Source2以及一个目标对象 Target
public class Source1 {private String name;private String email;// getters and setters
}public class Source2 {private String address;private String phoneNumber;// getters and setters
}public class Target {private String name;private String email;private String address;private String phoneNumber;// getters and setters
}我们希望将 Source1 和 Source2 的属性合并到 Target 对象中
定义映射器接口
我们需要在映射器接口中定义一个方法该方法接受多个源对象并返回目标对象。
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;Mapper
public interface MyMapper {MyMapper INSTANCE Mappers.getMapper(MyMapper.class);Mapping(source source1.name, target name)Mapping(source source1.email, target email)Mapping(source source2.address, target address)Mapping(source source2.phoneNumber, target phoneNumber)Target map(Source1 source1, Source2 source2);
}由于两个源对象和目标对象中的属性名称一致所以也可以省略掉方法上的四个Mapping
测试类
public class TestMapping {public static void main(String[] args) {Source1 source1 new Source1();source1.setName(John Doe);source1.setEmail(john.doeexample.com);Source2 source2 new Source2();source2.setAddress(123 Main St);source2.setPhoneNumber(555-1234);Target target MyMapper.INSTANCE.map(source1, source2);System.out.println(Name: target.getName()); // 输出: John DoeSystem.out.println(Email: target.getEmail()); // 输出: john.doeexample.comSystem.out.println(Address: target.getAddress()); // 输出: 123 Main StSystem.out.println(Phone Number: target.getPhoneNumber()); // 输出: 555-1234}
}12. 映射一个源对象到多个目标对象
使用 MappingTarget 注解可以一次映射到多个目标对象。
示例
假设我们有一个源对象 Source 和两个目标对象 Target1 和 Target2我们希望将 Source 对象的一部分属性映射到 Target1另一部分属性映射到 Target2。
public class Source {private String name;private String email;private String address;private String phoneNumber;// getters and setters
}public class Target1 {private String name;private String email;// getters and setters
}public class Target2 {private String address;private String phoneNumber;// getters and setters
}定义映射接口 我们需要在映射器接口中定义一个方法该方法接受 Source 对象和两个目标对象并将 Source 对象的属性映射到相应的目标对象中。
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers;Mapper
public interface MyMapper {MyMapper INSTANCE Mappers.getMapper(MyMapper.class);void toMultiTargets(Source source, MappingTarget Target1 target1, MappingTarget Target2 target2);
}或者也可以自定义辅助方法实现具体的映射逻辑
Mapper
public interface MyMapper {MyMapper INSTANCE Mappers.getMapper(MyMapper.class);void toMultiTargets(Source source, MappingTarget Target1 target1, MappingTarget Target2 target2);default void toMultiTargets(Source source, MappingTarget Target1 target1, MappingTarget Target2 target2) {if (source ! null) {target1.setName(source.getName());target1.setEmail(source.getEmail());target2.setAddress(source.getAddress());target2.setPhoneNumber(source.getPhoneNumber());}}
}测试类
public class TestMapping {public static void main(String[] args) {Source source new Source();source.setName(John Doe);source.setEmail(john.doeexample.com);source.setAddress(123 Main St);source.setPhoneNumber(555-1234);Target1 target1 new Target1();Target2 target2 new Target2();MyMapper.INSTANCE.toMultiTargets(source, target1, target2);System.out.println(Target1 Name: target1.getName()); // 输出: John DoeSystem.out.println(Target1 Email: target1.getEmail()); // 输出: john.doeexample.comSystem.out.println(Target2 Address: target2.getAddress()); // 输出: 123 Main StSystem.out.println(Target2 Phone Number: target2.getPhoneNumber()); // 输出: 555-1234}
}13.SpringBoot项目整合使用MapStruct
在Spring Boot项目中集成MapStruct主要涉及几个步骤添加依赖、配置Mapper组件、使用MapStruct注解以及享受自动映射带来的便利。下面是详细的步骤和用法示例
添加依赖
首先需要在Spring Boot项目的pom.xml对于Maven项目或build.gradle对于Gradle项目中添加MapStruct的依赖。
Maven
dependencies!-- MapStruct依赖 --dependencygroupIdorg.mapstruct/groupIdartifactIdmapstruct/artifactIdversion1.5.2.Final/version/dependency!-- 处理器依赖用于生成映射代码 --dependencygroupIdorg.mapstruct/groupIdartifactIdmapstruct-processor/artifactIdversion1.5.2.Final/versionscopeprovided/scope/dependency
/dependencies
Gradle
dependencies {// MapStruct依赖implementation org.mapstruct:mapstruct:1.5.2.Final// 处理器依赖用于生成映射代码annotationProcessor org.mapstruct:mapstruct-processor:1.5.2.Final
}
2.配置Mapper组件
package com.example.demo.mapper;import org.mapstruct.Mapper;
import org.springframework.stereotype.Component;Mapper(componentModel spring)
public interface MyEntityMapper {MyDto entityToDto(MyEntity entity);Mapping(target createdDate, expression java(java.time.LocalDate.now()))MyDto entityToDtoWithDefaultDate(MyEntity entity);
}
在Spring组件中通过自动装配MapStruct Mapper接口来实现对象之间的自动映射。
package com.example.demo.service;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.demo.mapper.MyEntityMapper;
import com.example.demo.entity.MyEntity;
import com.example.demo.dto.MyDto;Service
public class MyService {private final MyEntityMapper myEntityMapper;Autowiredpublic MyService(MyEntityMapper myEntityMapper) {this.myEntityMapper myEntityMapper;}public MyDto convert(MyEntity entity) {return myEntityMapper.entityToDto(entity);}
}
确保Spring Boot的启动类或配置类中包含了EnableAutoConfiguration或SpringBootApplication注解这样Spring Boot就能自动配置应用程序包括MapStruct的Mapper组件。
package com.example.demo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}
更多用法可以详细参照官方的example示例代码分类挺详细的