MapStruct的自学历程
我懵了,哈哈
- 昨天看了一个刚起步的项目,自己这边的模块可能还没开始,第二天我就开始设计表了,虽说经验不足,但也不怕,只有尝试才能不断进步嘛,这不,看到一些不懂的代码,今天总算是搞明白了,其中的MapStruct就是一个,学到新东西总是让人忍不住的开心啊
MapStruct的必要性
在我们的分布式结构中,由controller直接到dao层的查询条件对象我们一般用co,由dao到service层的数据传输对象我们一般用dto作数据返回,而由controller到service我们一般用vo作为业务处理,其中数据库返回的entity中可能有不想暴露给前端的数据,这时我们就需要使用转换,移除也可以说是过滤到某些字段,在我们最快能联想到的就是使用set和get方法去实现转换的效果,但是这样代码不优雅且冗余,于是MapStruct应运而生!
开撸案例,边用边学
起步依赖
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.4.1.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.4.1.Final</version>
</dependency>
所有依赖展示一下
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.5.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.23</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.2.0.Final</version>
</dependency>
</dependencies>
原始entity
@Data
@TableName("mall_goods")
public class MallGoodsEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_ID)
private Long spuId;
/**
* 货号
*/
private String productSn;
/**
* SPU名
*/
private String goodsName;
/**
* 默认SKU
*/
private Long defaultSkuId;
/**
* 状态 0:未审核 1:审核通过 2:审核不通过
*/
private String auditStatus;
/**
* 是否上架 0:下架 1:上架
*/
private String isMarketable;
/**
* 品牌
*/
private Long brandId;
/**
* 副标题
*/
private String caption;
/**
* 一级类目
*/
private Long category1Id;
/**
* 二级类目
*/
private Long category2Id;
/**
* 三级类目
*/
private Long category3Id;
/**
* 画册图片,连产品图片限制为5张,以逗号分割
*/
private String albumPics;
/**
* 商城价
*/
private BigDecimal price;
/**
* 分类模板ID
*/
private Long typeTemplateId;
/**
* 是否启用规格
*/
private String isEnableSpec;
/**
* 是否删除 0:表示不删除 1:表示删除
*/
private String isDelete;
/**
* 文案id(作废)
*/
private String copyId;
/**
* 商品的规格信息
*/
private String spuSpecInfo;
/**
* 热度值 =销量*0.6+好评*0.2+浏览量*0.2
*/
private String hot;
/**
* 销量
*/
private Integer sale;
/**
*
*/
private LocalDateTime createTime;
/**
*
*/
private LocalDateTime updateTime;
/**
* 商家ID 作废
*/
private String sellerId;
}
表信息如下
可以看到这里的表和entity的字段是一一对应的
domain层的模型如下
@Data
public class MallGoodsVO {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_ID)
private Long spuId;
/**
* 货号
*/
private String productSn;
/**
* SPU名
*/
private String goodsName;
/**
* 默认SKU
*/
private Long defaultSkuId;
/**
* 状态 0:未审核 1:审核通过 2:审核不通过
*/
private String auditStatus;
}
为了方便演示,我只截取了部分字段作为vo返回
spring中的java配置类
@MapperConfig(
componentModel = "spring",
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
unmappedTargetPolicy = ReportingPolicy.WARN
)
@Configuration
public class MapStructConfiguration {
}
选项 | 目的 | 默认 |
---|---|---|
suppressGeneratorTimestamp | 如果设置为 true ,@Generated 则会在生成的映射器类的注释中创建时间戳 | false |
suppressGeneratorVersionInfoComment | 如果设置为 true ,则会在生成的映射器类中注释中的 comment 属性创建 @Generated 被抑制。该注释包含有关 MapStruct版本和用于注释处理的编译器的信息 | false |
defaultComponentModel | 根据生成映射器的组件模型的名称,支持的值 : 1> default : 映射器不使用组件模型,通常通过实例检索实例 Mappers#getMapper(Class) 2> cdi : 生成的映射器是一个应用程序范围的CDI bean,可以通过检索 @Inject 3> spring : 生成的映射器是一个单一范围的 Spring bean,可以通过检索 @Autowired 4> jsr330 : 生成的映射器使用 {@code @Named} 进行注释,并且可以通过 @Inject 使用 Spring 进行检索如果为特定的映射器通过组件模型 @Mapper#componentModel() ,则注释中的值优先 | default |
unmappedTargetPolicy | 在映射方法的目标对象的属性未填充源值的情况下应用的默认报告策略,支持的值 : 1> ERROR : 任何未映射的目标属性都将导致映射代码生成失败 2> WARN : 任何未映射的目标属性将在构建时引发警告 3> IGNORE : 未映射的目标属性被忽略如果为特定的映射器通过了策略 @Mapper#unmappedTargetPolicy() ,则注释中的值优先 | WARN |
mapper层,service层都是基本的Mybatis_Plus代码
- mapper层
@Mapper
public interface MallGoodsEntityMapper extends BaseMapper<MallGoodsEntity> {
}
- service层
/**
* @Author Lixiaodong
* @Date 2021/11/9 22:50
*/
@Service
public class MallGoodsEntityServiceImpl extends ServiceImpl<MallGoodsEntityMapper, MallGoodsEntity> implements MallGoodsEntityService {
}
转换的接口
/**
* @Author Lixiaodong
* @Date 2021/11/9 22:56
*/
// 这里的mapper注解是mapstruct提供的
@Mapper(config = MapStructConfiguration.class)
public interface MallGoodsConvert {
/**
* 转vo
* @param mallGoodsEntity
* @return vo
*/
MallGoodsVO toDto(MallGoodsEntity mallGoodsEntity);
}
controller层直接调用转换
@RestController
@RequestMapping("goods")
public class MallGoodsController {
@Autowired
private MallGoodsEntityService mallGoodsEntityService;
@Autowired
private MallGoodsConvert mallGoodsConvert;
@RequestMapping("list")
public MallGoodsVO list() {
return mallGoodsConvert.toDto(mallGoodsEntityService.getById(1));
}
}
运行调用后看结果
按原本的entity来看应该是很多字段的,而经过mapstruct之后只有VO中的字段了
- 反馈的数据
至此,我们MapStruct的基本使用完毕,学会了基本就要往更深处去研究了,加油!!!