一、可使用的业务场景
相信很多同学在编码过程中会遇到从数据库查询A对象的集合数据,然后遍历A对象集合,然后封装到B数据集合中,然后返回B数据集合给调用者。
如:
List<A> listA = getListA(); //调用数据库查询数据
for(A a :listA){
B b = new B();
b.setName(a.getName());
list.add(b);
}
在这个过程中,其实是没有什么难度的,就是遍历设置数据,当对象属性多的时候,设置的更加麻烦,今天就跟大家一起来学习mapstruct,看是如何解决这一问题,
在一个成熟可维护的工程中,细分模块后,domian工程最好不要被其他工程依赖,但是实体类一般存于domain之中,这样其他工程想获取实体类数据时就需要在各自工程写model,自定义model可以根据自身业务需要而并不需要映射整个实体属性。
二、什么是MapStruct
MapStruct 就是这样的一个属性映射工具,只需要定义一个 Mapper 接口,MapStruct 就会自动实现这个映射接口,避免了复杂繁琐的映射实现。MapStruct官网地址: http://mapstruct.org/
三、maven引入
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
<scope>compile</scope>
</dependency>
<!-- other dependencies -->
</dependencies>
四、具体使用实例
新建三个对象Car,CarTwo,CarVo(最终需要得到的对象)
import lombok.Data;
/**
* @ClassName: Car
* @Author: tanp
* @Date: 2020/3/31 11:34
*/
@Data
public class Car {
private String name;
private String price;
private String type;
private String region;
}
import lombok.Data;
/**
* @ClassName: CarTwo
* @Author: tanp
* @Date: 2020/3/31 14:55
*/
@Data
public class CarTwo {
private String sign;
}
import lombok.Data;
/**
* @ClassName: CarType
* @Author: tanp
* @Date: 2020/3/31 11:38
*/
@Data
public class CarVo {
private String name;
private String price;
private String type;
private String country;
private String sign;
}
新建一个接口import org.mapstruct.Mapper;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @ClassName: CarShow
* @Author: tanp
* @Date: 2020/3/31 11:43
*/
@Mapper(componentModel = "spring") //集成spring的写法
@Component
public interface CarShow {
List<CarVo> showVo(List<Car> cars);
CarVo shwoOneCarVo(Car car, CarTwo carTwo);
}
编写代码完成后,编译下代码,这时会自动生成以下接口实现类,代码如下
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Generated;
import org.springframework.stereotype.Component;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2020-03-31T14:59:17+0800",
comments = "version: 1.2.0.Final, compiler: javac, environment: Java 1.8.0_162 (Oracle Corporation)"
)
@Component
public class CarShowImpl implements CarShow {
@Override
public List<CarVo> showVo(List<Car> cars) {
if ( cars == null ) {
return null;
}
List<CarVo> list = new ArrayList<CarVo>( cars.size() );
for ( Car car : cars ) {
list.add( carToCarVo( car ) );
}
return list;
}
@Override
public CarVo shwoOneCarVo(Car car, CarTwo carTwo) {
if ( car == null && carTwo == null ) {
return null;
}
CarVo carVo = new CarVo();
if ( car != null ) {
carVo.setName( car.getName() );
carVo.setPrice( car.getPrice() );
carVo.setType( car.getType() );
}
if ( carTwo != null ) {
carVo.setSign( carTwo.getSign() );
}
return carVo;
}
protected CarVo carToCarVo(Car car) {
if ( car == null ) {
return null;
}
CarVo carVo = new CarVo();
carVo.setName( car.getName() );
carVo.setPrice( car.getPrice() );
carVo.setType( car.getType() );
return carVo;
}
}
五、知识点分析
1.实现类是自己生成的,前提是pom文件中引入mapstruct,然后在接口处引入了@Mapper(componentModel = "spring")
注解
2.看showVo方法,可以看到
Car类中的region属性,并没有在CarVo
设置到,而除region之外的其他属性在CarShowImp中都进行了设置,说明属性名相同直接设置,属性名不匹配的,如CarVo中的country属性,并没有被设置,所以在返回CarVo时,属性值设置为空,在本例中也就是country为空。当然也存在让属性名不同的属性互相设置,如把Car中的region属性的值,设置给CarVo中的country属性值,但是本人不推荐这种用法,所以这里没有详细讲解
3.查看shwoOneCarVo方法,可以看到是将两个实体属性的值设置到一个实体中,说明
MapStruct 可以将几种类型的对象映射为另外一种类型
六、MapStruct 注解的关键词
@Mapper 只有在接口加上这个注解, MapStruct 才会去实现该接口
@Mapper 里有个 componentModel 属性,主要是指定实现类的类型,一般用到两个
default:默认,可以通过 Mappers.getMapper(Class) 方式获取实例对象
spring:在接口的实现类上自动添加注解 @Component,可通过 @Autowired 方式注入
@Mapping:属性映射,若源对象属性与目标对象名字一致,会自动映射对应属性
source:源属性
target:目标属性
dateFormat:String 到 Date 日期之间相互转换,通过 SimpleDateFormat,该值为 SimpleDateFormat 的日期格式
ignore: 忽略这个字段
@Mappings:配置多个@Mapping