什么是Mapstruct?
Mapstruct是一个将Entity向Vo互相转换的工具,各实体间互相转换
为什么要用Mapstruct?
容易,方便,易理解,快捷高效
怎么用?
- 首先需要和lombok一起使用,因为这样很方便,当然也可以不用
因为使用lombok需要一些规范,后面会说
什么?lombok怎么用?
很容易!
lombok提供了很多注解,方便实体类的编写
如@Data,@Getter,@Setter等
(这里直接偷张图来)
下面例子用的lombok - maven导入这些包
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.0.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.0.Final</version>
</dependency>
- 现在有参数相同的User 和 UserVo,注意参数完全相同
User是Entity面向数据库
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String name;
private String pass;
}
UserVo(View Object)面向前端
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserVo {
private String name;
private String pass;
}
ok,资源都准备好了
正题来了
- 首先写个接口类,名字自己随便取
- 写上mapstruct的注解@Mapper,注意不是ibatis的
- 然后照着写就是了
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface converter {
converter INSTANCE = Mappers.getMapper(converter.class);
}
现在要将User转换成UserVo
- 当参数都相同时
@Mapper
public interface converter {
converter INSTANCE = Mappers.getMapper(converter.class);
/**
*
* @param user 被复制的对象
* @return 转换的对象
*/
UserVo ConverToUserVo(User user);
}
没错写完了,就这么容易
测试:
public class Test {
public static void main(String[] args) {
User user = new User("haha","123");
UserVo userVo = null;//并没有new
userVo = converter.INSTANCE.ConverToUserVo(user);//直接用接口的方法
System.out.println(userVo);//输出
}
输出:
我们看看Mapstruct干了什么:
很清楚的看到Mapstruct实现了我们写的接口
注意我之前并没有new UserVo,是因为我接口里的写法,Mapstruct会帮我们new
- 那么我们要求参数不同时怎么写呢?
我们将UserVo改成
public class UserVo {
private String nameVo;//name
private String passVo;//pass
}
- 一般情况推荐使用
这里使用@Mapping,用来指定谁是源谁是目标
很明显
source 代表 被复制的值
target 代表 被转换的值
@Mapper
public interface converter {
converter INSTANCE = Mappers.getMapper(converter.class);
/**
*
* @param user 被复制的对象
* @return 转换的对象
*/
@Mappings({
@Mapping(source = "name",target = "nameVo"),
@Mapping(source = "pass",target = "passVo")
})
UserVo ConverToUserVo(User user);
}
这里测试用例还是一样
实现类的get和set也相应的改了
- 当参数来自不同的source时,这时就需要我们指定source
写法如下:
注意观察写法不一样了
这里我们用对象来指定source
@Mapper
public interface converter {
converter INSTANCE = Mappers.getMapper(converter.class);
/**
*
* @param user 被复制的对象
* @return 转换的对象
*/
@Mappings({
@Mapping(source = "user.name",target = "nameVo"),
@Mapping(source = "userVo.passVo",target = "passVo")
})
UserVo ConverToUserVo(UserVo userVo, User user);
}
测试用例换成:
User user = new User("haha","123");
UserVo userVo = new UserVo("jj","456");//这里new了,不new不行
userVo = converter.INSTANCE.ConverToUserVo(userVo,user);
System.out.println(userVo);
结果:
UserVo(nameVo=haha, passVo=456)
实现类:
ok,这里有个bug,UserVo重复new了一次
- 那么当我们想要修改现有的对象的某个值,但不想重新创个对象的时候,怎么办呢?
这时@MappingTarget注解就有用了.
我们现在将接口方法改成:
@Mapper
public interface converter {
converter INSTANCE = Mappers.getMapper(converter.class);
/**
*
* @param user 被复制的对象
* @return 转换的对象
*/
@Mappings({
@Mapping(source = "name",target = "nameVo"),
@Mapping(source = "pass",target = "passVo")
})
//对转换对象加上@MappingTarget注解,表示这是我要转换的对象
UserVo ConverToUserVo(@MappingTarget UserVo userVo, User user);
}
@MappingTarget指定一个是转换的对象,没有注解的就是被复制的对象
缺点是,target的源固定,没法改,就是复制源不能再取自己了,改了会报错
优点是,对象用户自己定义,不会出现空指针
- 还有一种情况,当出现多层嵌套对象时
如User中还有一个对象Order,我们将orderName复制给UserVo.name
代码如下:
怎么办呢?
其实写法和上一个一样,我们指定源就是了
@Mapper
public interface converter {
converter INSTANCE = Mappers.getMapper(converter.class);
/**
*
* @param user 被复制的对象
* @return 转换的对象
*/
@Mappings({
//多重嵌套
@Mapping(source = "user.order.orderName",target = "nameVo"),
@Mapping(source = "pass",target = "passVo")//这里pass就源的pass
})
UserVo ConverToUserVo(@MappingTarget UserVo userVo, User user);
}
测试:
结果:
UserVo(nameVo=kaka, passVo=123)
实现类:
这里多了一块
最后说说一些注意事项
- Mapstruct和lombok一起用的参数命名
命名要求首字母不能大写,命名要规范,否则会出问题
类似userName,username,usernAme都可以
不能写成 UserName,Username… - 接口方法参数顺序无所谓
总结
本文章为了记录本人对Mapstruct学习经验,以免日后忘记.
还有很多不足的地方。望各位网友指教。
参考文章:https://blog.csdn.net/qq_40194399/article/details/110162124,感谢此文作者