大家在开发中,最让人头疼的就是:对象之间的拷贝,前端的VO和数据库的Entity不一致!
性能最好的就是手动set
,主要是枯燥且无技术含量,不仅耗费大量时间而且很容易出错;
所以我们要成为优秀的程序员,要多借助轮子,开发效率事半功倍,开发技能也是增长不少!
如果系统性能没有要求,怎么实现都是好的,但是我们要有追求哈,追求高质量!
每个东西都有存在的价值,不要捧一踩一哈!
MapStruct是基于JSR 269
的Java注释处理器,用于生成类型安全的 Bean 映射类。
您所要做的就是定义一个映射器接口,该接口声明任何所需的映射方法。在编译过程中,MapStruct将生成此接口的实现
。此实现使用纯 Java 方法调用在源对象和目标对象之间进行映射,即无反射
或类似内容。
与手动编写映射代码相比,MapStruct通过生成繁琐且容易出错的代码来节省时间
。遵循配置方法的约定
,MapStruct使用合理的默认值,但在配置或实现特殊行为时会步入歧途。
在这里插入图片描述
与动态映射框架相比,MapStruct具有以下优点:
通过使用普通方法调用而不是反射
快速执行
编译时类型安全
:只能映射彼此映射的对象和属性,不会意外地将订单实体映射到客户 DTO 等。
在构建时清除错误报告,如果
性能图大家可以看一下:
@Mapper
将接口标记为映射接口 对于源对象和目标对象中具有不同名称的属性,可以使用注释来配置名称:@Mapping
按照约定,接口声明一个成员Mappers INSTANCE
,为客户端提供对映射器实现的访问。下面我们来具体使用!
这里使用最新的,如果引入了lombok可能会有问题,就是他们俩都是在编译期运行的,mapstruct如果比lombok先执行,就会找不到get、set方法,所以会有问题,官网已经有了解决方案!现在是启动不会报错!
org.mapstruct
mapstruct
1.5.3.Final
org.projectlombok
lombok
1.18.24
我们需要加上依赖:
org.mapstruct
mapstruct-processor
1.5.3.Final
java: No property named "name" exists in source parameter(s).
Type "UserVO" has no properties.
官网解决文章地址
org.apache.maven.plugins
maven-compiler-plugin
3.8.1
1.8
org.mapstruct
mapstruct-processor
1.5.3.Final
org.projectlombok
lombok
1.18.24
org.projectlombok
lombok-mapstruct-binding
0.2.0
用户表:
@Data
public class User {
private Integer id;
private String username;
private Integer age;
}
前端用户VO:
@Data
public class UserVO {
private Integer id;
private String name;
private Integer age;
}
我们创建接口进行两个对象之间的映射:
import com.example.demo.mapstruct.entity.User;
import com.example.demo.mapstruct.entity.UserVO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
/**
* @author wangzhenjun
* @date 2023/1/28 16:05
*/
@Mapper
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
@Mapping(source ="name",target = "username")
User userVOToUser(UserVO userVO);
}
属性多了可以嵌套:
@Mappings({
@Mapping(source ="name",target = "username"),
@Mapping(source ="name1",target = "username1")
})
也可以:
@Mapping(source ="name",target = "username")
@Mapping(source ="name1",target = "username1")
编写测试类:
@SpringBootTest
class DemoApplicationTests {
@Test
void demoMapstruct(){
UserVO userVO = new UserVO(1,"小红",18);
User user = UserMapper.INSTANCE.userVOToUser(userVO);
System.out.println(user);
}
}
我们看到拷贝没有任何问题!
我们看看是怎么实现的:
mapstruct
会在编译期自动生成实现类去帮助我们去赋值,不指定默认策略,名称一致进行copy!不一致可以按上面的进行指定,不指定则不会有set方法!
在这里插入图片描述
下面进行多个源参数的映射方法演示:
我们把user类加上一个字段:
private BigDecimal score;
新增加一个Score
类:
@Data
@AllArgsConstructor
public class Score {
private Integer studentId;
private BigDecimal score;
}
调整上面的UserMapper
接口:
@Mappings({
@Mapping(source ="userVO.name",target = "username"),
@Mapping(source ="score.score",target = "score")
})
User userVOToUser(UserVO userVO, Score score);
测试代码:
UserVO userVO = new UserVO(1,"小红",18);
Score score = new Score(1,new BigDecimal(100));
User user = UserMapper.INSTANCE.userVOToUser(userVO,score);
System.out.println(user);
结果显示正常:
在这里插入图片描述
我们再来看一个企业级能够用得上的,就是自定义方法,然后进行赋值:
场景:一个商品有长宽高,我们把长宽高从cm变为m!
还有很多String转Integer、Float等等,都是按照下面这种自定义方法去实现!
VO和对象都是一样的哈!
@Data
@AllArgsConstructor
public class ProductVO {
private Integer id;
private String name;
private BigDecimal length;
private BigDecimal width;
private BigDecimal high;
}
看清楚,别导错包了!qualifiedByName
:指定自定义方法的名称@Named("cmToM")
:起别名,不使用找不到方法
可以写一起,也可以整一个工具类里写方法,在这里进行引用!如果是使用spring,我们可以把接口作为bean进行注入调用(推荐) 加上参数即可开启:@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
/**
* @author wangzhenjun
* @date 2023/1/28 17:13
*/
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
public interface ProductMapper {
@Mapping(source = "length",target = "length",qualifiedByName = "cmToM")
@Mapping(source = "width",target = "width",qualifiedByName = "cmToM")
@Mapping(source = "high",target = "high",qualifiedByName = "cmToM")
Product productVOToPrduct(ProductVO productVO);
@Named("cmToM")
default BigDecimal cmToM (BigDecimal oldValue){
if (oldValue == null) {
return BigDecimal.ZERO;
}
return oldValue.divide(new BigDecimal("100"));
}
}
测试:
@SpringBootTest
class DemoApplicationTests {
@Autowired
private ProductMapper productMapper;
@Test
void demoMapstruct(){
ProductVO productVO = new ProductVO(1,"美丽家园地板",new BigDecimal(100),new BigDecimal(50),new BigDecimal(8));
Product product = productMapper.productVOToProduct(productVO);
System.out.println(product);
}
}
完美转化!
在这里插入图片描述
在实战一个LocalDateTime、String相互转化的
,后面大家可以去官网文档去找你需要的:
在刚刚的商品类加个字段:
private String createdAt;
VO里也加上一个:
private LocalDateTime createdAt;
编写个转化类:这里交给spring管理了,因为ProductMapper也交给spring管理,不加的话会找不到此类!
@Component
public class LocalDateTimeMapper {
public String asString(LocalDateTime date) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return date != null ? date.format(formatter): null;
}
public LocalDateTime asLocalDateTime(String date) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return date != null ? LocalDateTime.parse(date,formatter) : null;
}
}
ProductMapper修改一下:
uses = LocalDateTimeMapper.class
使用咱们上面写的类即可!
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING,uses = LocalDateTimeMapper.class)
public interface ProductMapper {
@Mapping(source = "length",target = "length",qualifiedByName = "cmToM")
@Mapping(source = "width",target = "width",qualifiedByName = "cmToM")
@Mapping(source = "high",target = "high",qualifiedByName = "cmToM")
Product productVOToProduct(ProductVO productVO);
@Named("cmToM")
default BigDecimal cmToM (BigDecimal oldValue){
if (oldValue == null) {
return BigDecimal.ZERO;
}
return oldValue.divide(new BigDecimal("100"));
}
}
测试一下:
ProductVO productVO = new ProductVO(1,"美丽家园地板",
new BigDecimal(100),new BigDecimal(50),
new BigDecimal(8), LocalDateTime.now());
Product product = productMapper.productVOToProduct(productVO);
System.out.println(product);
完美转化:
在这里插入图片描述
通过简介到实战,这时咱们就是优雅的程序员了!
更多的例子可以去官网进行查看:
alue.divide(new BigDecimal(“100”));
}
}
测试一下:
ProductVO productVO = new ProductVO(1,“美丽家园地板”,
new BigDecimal(100),new BigDecimal(50),
new BigDecimal(8), LocalDateTime.now());
Product product = productMapper.productVOToProduct(productVO);
System.out.println(product);
完美转化:
[外链图片转存中...(img-CHac062B-1696815679059)]在这里插入图片描述
## 六、总结
通过简介到实战,这时咱们就是优雅的程序员了!
更多的例子可以去官网进行查看:
mapstruct开发文档:https://mapstruct.org/documentation/stable/reference/html/#Preface