介绍
在 java 开发中,我们经常需要在不同的 java bean 之间进行数据映射,比如从实体类(entity)到数据传输对象(dto)的转换。传统的做法是手动编写大量的 setter 和 getter 方法来完成属性的赋值,这种方式不仅繁琐,而且容易出错。mapstruct 作为一个基于注解的代码生成工具,为我们提供了一种更加优雅、高效的解决方案。它在编译时自动生成映射代码,避免了运行时反射带来的性能开销,同时保证了类型安全。
优缺点
优点
- 高性能:mapstruct 在编译阶段生成映射代码,运行时直接调用这些代码,避免了反射的使用,从而显著提高了性能。
- 类型安全:由于映射代码是在编译时生成的,编译器会对类型进行检查,因此可以在编译阶段发现类型不匹配等错误,避免了运行时异常。
- 代码简洁:使用 mapstruct 只需要定义映射接口和使用注解进行配置,无需手动编写大量的映射逻辑,大大减少了代码量,提高了开发效率。
缺点
- 学习成本:需要学习 mapstruct 提供的各种注解及其使用方法,对于初学者来说可能有一定的学习曲线。
- 依赖管理:需要在项目中引入 mapstruct 的相关依赖,增加了项目的依赖管理复杂度。
核心注解及详细使用语法说明
@mapper
- 作用:用于标记一个接口为映射接口,mapstruct 会在编译时为该接口生成具体的实现类。
- 使用语法:
import org.mapstruct.mapper;
import org.mapstruct.factory.mappers;
@mapper
public interface usermapper {
// 通过 mappers.getmapper 方法获取映射接口的实例
usermapper instance = mappers.getmapper(usermapper.class);
// 定义从 userentity 到 userdto 的映射方法
userdto todto(userentity entity);
// 定义从 userdto 到 userentity 的映射方法
userentity toentity(userdto dto);
}
@mapping
- 作用:用于指定源对象和目标对象之间的属性映射关系,当源对象和目标对象的属性名
不一致时,可以使用该注解进行显式映射。 - 使用语法:
import org.mapstruct.mapper;
import org.mapstruct.mapping;
import org.mapstruct.factory.mappers;
@mapper
public interface usermapper {
usermapper instance = mappers.getmapper(usermapper.class);
// 使用 @mapping 注解指定 entityid 映射到 id,entityname 映射到 name
@mapping(source = "entityid", target = "id")
@mapping(source = "entityname", target = "name")
userdto todto(userentity entity);
// 反向映射
@mapping(source = "id", target = "entityid")
@mapping(source = "name", target = "entityname")
userentity toentity(userdto dto);
}
@mappings
- 作用:@mappings 是 @mapping 的集合形式,用于一次性指定
多个属性映射关系。 - 使用语法:
import org.mapstruct.mapper;
import org.mapstruct.mappings;
import org.mapstruct.mapping;
import org.mapstruct.factory.mappers;
@mapper
public interface usermapper {
usermapper instance = mappers.getmapper(usermapper.class);
@mappings({
@mapping(source = "entityid", target = "id"),
@mapping(source = "entityname", target = "name")
})
userdto todto(userentity entity);
@mappings({
@mapping(source = "id", target = "entityid"),
@mapping(source = "name", target = "entityname")
})
userentity toentity(userdto dto);
}
@context
- 作用:用于在映射过程中传递上下文信息,比如一些辅助对象,这些对象可以在映射方法中使用。
- 使用语法:
import org.mapstruct.mapper;
import org.mapstruct.context;
import org.mapstruct.factory.mappers;
import java.util.locale;
@mapper
public interface usermapper {
usermapper instance = mappers.getmapper(usermapper.class);
// 使用 @context 注解传递 locale 对象作为上下文信息
userdto todto(userentity entity, @context locale locale);
}
@aftermapping
- 作用:用于在映射完成后执行自定义的逻辑,比如对目标对象的某些属性进行额外的处理。
- 使用语法:
import org.mapstruct.mapper;
import org.mapstruct.aftermapping;
import org.mapstruct.mappingtarget;
import org.mapstruct.factory.mappers;
@mapper
public interface usermapper {
usermapper instance = mappers.getmapper(usermapper.class);
userdto todto(userentity entity);
// 使用 @aftermapping 注解定义映射完成后的自定义逻辑
@aftermapping
default void aftermapping(@mappingtarget userdto dto, userentity entity) {
// 将源对象的 firstname 和 lastname 拼接后赋值给目标对象的 fullname 属性
dto.setfullname(entity.getfirstname() + " " + entity.getlastname());
}
}
demo示例
公共基本类定义
import lombok.data;
// 用户实体类
@data
public class userentity {
private long id;
private string name;
private integer age;
private string firstname;
private string lastname;
private addressentity address;
private long entityid;
private string entityname;
}
// 用户数据传输对象类
@data
public class userdto {
private long id;
private string name;
private integer age;
private string fullname;
private addressdto address;
private long entityid;
private string entityname;
}
// 地址实体类
@data
public class addressentity {
private string street;
private string city;
}
// 地址数据传输对象类
@data
public class addressdto {
private string street;
private string city;
}
简单映射示例
import org.mapstruct.mapper;
import org.mapstruct.factory.mappers;
@mapper
public interface usermapper {
// 获取映射接口的实例
usermapper instance = mappers.getmapper(usermapper.class);
// 从 userentity 到 userdto 的映射方法
userdto todto(userentity entity);
// 从 userdto 到 userentity 的映射方法
userentity toentity(userdto dto);
}
// 测试代码
public class mainsimplemapping {
public static void main(string[] args) {
userentity userentity = new userentity();
userentity.setid(1l);
userentity.setname("john");
userentity.setage(25);
// 使用映射接口的实例进行映射
userdto userdto = usermapper.instance.todto(userentity);
system.out.println("简单映射示例结果:");
system.out.println("userdto: id=" + userdto.getid() + ", name=" + userdto.getname() + ", age=" + userdto.getage());
}
}
输出结果:
简单映射示例结果:
userdto: id=1, name=john, age=25
字段名不一致的映射示例
import org.mapstruct.mapper;
import org.mapstruct.mapping;
import org.mapstruct.factory.mappers;
@mapper
public interface usermapper {
usermapper instance = mappers.getmapper(usermapper.class);
@mapping(source = "entityid", target = "id")
@mapping(source = "entityname", target = "name")
userdto todto(userentity entity);
@mapping(source = "id", target = "entityid")
@mapping(source = "name", target = "entityname")
userentity toentity(userdto dto);
}
// 测试代码
public class mainfieldnamemismatch {
public static void main(string[] args) {
userentity userentity = new userentity();
userentity.setentityid(1l);
userentity.setentityname("john");
userentity.setage(25);
userdto userdto = usermapper.instance.todto(userentity);
system.out.println("字段名不一致映射示例结果:");
system.out.println("userdto: id=" + userdto.getid() + ", name=" + userdto.getname() + ", age=" + userdto.getage());
}
}
输出结果:
字段名不一致映射示例结果:
userdto: id=1, name=john, age=25
嵌套对象映射示例
import org.mapstruct.mapper;
import org.mapstruct.factory.mappers;
@mapper
public interface usermapper {
usermapper instance = mappers.getmapper(usermapper.class);
userdto todto(userentity entity);
userentity toentity(userdto dto);
addressdto todto(addressentity entity);
addressentity toentity(addressdto dto);
}
// 测试代码
public class mainnestedobjectmapping {
public static void main(string[] args) {
addressentity addressentity = new addressentity();
addressentity.setstreet("123 main st");
addressentity.setcity("new york");
userentity userentity = new userentity();
userentity.setid(1l);
userentity.setname("john");
userentity.setaddress(addressentity);
userdto userdto = usermapper.instance.todto(userentity);
system.out.println("嵌套对象映射示例结果:");
system.out.println("userdto: id=" + userdto.getid() + ", name=" + userdto.getname());
system.out.println("addressdto: street=" + userdto.getaddress().getstreet() + ", city=" + userdto.getaddress().getcity());
}
}
输出结果:
嵌套对象映射示例结果:
userdto: id=1, name=john
addressdto: street=123 main st, city=new york
自定义映射逻辑示例
import org.mapstruct.mapper;
import org.mapstruct.aftermapping;
import org.mapstruct.mappingtarget;
import org.mapstruct.factory.mappers;
@mapper
public interface usermapper {
usermapper instance = mappers.getmapper(usermapper.class);
userdto todto(userentity entity);
@aftermapping
default void aftermapping(@mappingtarget userdto dto, userentity entity) {
dto.setfullname(entity.getfirstname() + " " + entity.getlastname());
}
}
// 测试代码
public class maincustommappinglogic {
public static void main(string[] args) {
userentity userentity = new userentity();
userentity.setid(1l);
userentity.setfirstname("john");
userentity.setlastname("doe");
userdto userdto = usermapper.instance.todto(userentity);
system.out.println("自定义映射逻辑示例结果:");
system.out.println("userdto: id=" + userdto.getid() + ", fullname=" + userdto.getfullname());
}
}
输出结果:
自定义映射逻辑示例结果:
userdto: id=1, fullname=john doe
使用上下文示例
import org.mapstruct.mapper;
import org.mapstruct.context;
import org.mapstruct.factory.mappers;
import java.util.locale;
@mapper
public interface usermapper {
usermapper instance = mappers.getmapper(usermapper.class);
userdto todto(userentity entity, @context locale locale);
default string localize(string value, @context locale locale) {
// 根据 locale 进行本地化处理
return value;
}
}
// 测试代码
public class mainwithcontext {
public static void main(string[] args) {
userentity userentity = new userentity();
userentity.setid(1l);
userentity.setname("john");
locale locale = locale.us;
userdto userdto = usermapper.instance.todto(userentity, locale);
system.out.println("使用上下文示例结果:");
system.out.println("userdto: id=" + userdto.getid() + ", name=" + userdto.getname());
}
}
输出结果:
使用上下文示例结果:
userdto: id=1, name=john
通过以上示例可以看到,使用 mapstruct 能够方便快捷地完成 java bean 之间的映射,同时结合 lombok 的 @data 注解进一步简化了代码。并且从输出结果可以直观地验证各个映射场景的正确性。
到此这篇关于java中基于注解的代码生成工具mapstruct映射使用详解的文章就介绍到这了,更多相关java mapstruct内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论