暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MapStruct(entity优雅的转dto)

IT大咖说 2020-11-16
4041

开发中我们可能使用JPA、通用Mapper或者MyBatis-Plus去查询数据,而这类框架都是返回的实体,实体是和数据库中的表是一一对应的,而作为接口的返回值我们无需把整个实体都暴露给前端,通常会将实体转换成另一个DTO对象来返回,通常有以下转换方式:

  • 自己写代码手动转换(这种方式代码量多,而且不优雅)

  • BeanUtils.copyProperties(entity, dto),这种方式是通过反射来实现的,一般反射效率相对有点低

  • 使用ModelMapper框架(这种方式是通过反射来实现的,一般反射效率相对有点低)

  • 使用MapStruct框架(这种方式是在编译器自动生成转换代码,将原来的手动改为自动,相对于使用反射实现的此种方式效率更好)

综合比较性能、问题排查、文档、成熟度、扩展性等因素来考虑,MapStruct 是一个不错的选择,实体映射转换各个工具比较 https://java.libhunt.com/compare-mapstruct-vs-selma

  • MapStruct官网地址:http://mapstruct.org/,

  • GitHub示例程序:https://github.com/mapstruct/mapstruct-examples

1. 添加依赖 和 配置插件

注意:如果使用了lombok应尽量使用比较高的版本,maven-compiler-plugin 插件也最好使用较高的版本。否则有可能报这个错:

Error:(12, 5) java: No property named "xxx" exists in source parameter(s). Did you mean "null"?
<properties>    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>    <maven.compiler.source>1.8</maven.compiler.source>    <maven.compiler.target>1.8</maven.compiler.target>    <org.mapstruct.version>1.4.1.Final</org.mapstruct.version>    <org.projectlombok.version>1.18.12</org.projectlombok.version></properties><dependencies>    <dependency>        <groupId>org.mapstruct</groupId>        <artifactId>mapstruct</artifactId>        <version>${org.mapstruct.version}</version>    </dependency>    <dependency>        <groupId>org.projectlombok</groupId>        <artifactId>lombok</artifactId>        <version>${org.projectlombok.version}</version>        <scope>provided</scope>    </dependency>    <dependency>        <groupId>org.apache.commons</groupId>        <artifactId>commons-lang3</artifactId>    </dependency></dependencies><build>    <pluginManagement>        <plugins>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-compiler-plugin</artifactId>                <version>3.8.1</version>                <configuration>                    <source>1.8</source>                    <target>1.8</target>                    <annotationProcessorPaths>                        <path>                            <groupId>org.mapstruct</groupId>                            <artifactId>mapstruct-processor</artifactId>                            <version>${org.mapstruct.version}</version>                        </path>                        <path>                            <groupId>org.projectlombok</groupId>                            <artifactId>lombok</artifactId>                            <version>${org.projectlombok.version}</version>                        </path>                    </annotationProcessorPaths>                </configuration>            </plugin>        </plugins>    </pluginManagement></build>

2. 实体

@Getterpublic enum UserStatusEnum {   NORMAL(0, "正常"),   LOCK(1, "锁定");   private Integer code;   private String desc;   UserStatusEnum(Integer code, String desc) {      this.code = code;      this.desc = desc;   }}
@Datapublic class UserInfo {    private String address;    private String remark;}
@NoArgsConstructor@AllArgsConstructor@Datapublic class User {    private Long id;    private String name;    private String password;    private UserStatusEnum userStatusEnum;    private Date createTime;    private UserInfo userInfo;}

3. DTO

@NoArgsConstructor@AllArgsConstructor@Datapublic class UserDTO {    private Long id;    private String realName;    private Integer status;    private String address;    private String password;    private String createTimeFormat;}

4. 实体与DTO属性映射配置

@Mapper(componentModel="spring")public interface UserConverter {    @Mappings({        @Mapping(source = "name", target = "realName"),        @Mapping(target = "status", expression = "java(user.getUserStatusEnum().getCode())"),        @Mapping(source = "createTime", target = "createTimeFormat", dateFormat = "yyyy-MM-dd HH:mm:ss"),        @Mapping(source = "userInfo.address", target = "address"),        @Mapping(target = "password", ignore = true)    })    UserDTO entity2dto(User user);}
  • @Mapper 只有在接口加上这个注解,MapStruct 才会去实现该接口,@Mapper 里有个 componentModel 属性,主要是指定实现类的类型,一般用到两个:

  • default:默认,可以通过 Mappers.getMapper(Class) 方式获取实例对象。

  • spring:在接口的实现类上自动添加注解 @Component,可通过 @Autowired 方式注入。

  • @Mappings:配置多个@Mapping

  • @Mapping:属性映射,若源对象属性与目标对象名字一致,会自动映射对应属性

  • source:源属性

  • target:目标属性

  • dateFormat:String 到 Date 日期之间相互转换,通过 SimpleDateFormat,该值为 SimpleDateFormat的日期格式

  • expression:使用Java方法来格式化值

  • ignore: 忽略这个字段

@Mapper可以单独放在一个类中配置,也可以在JPA或者MyBatis中的Mapper类中来配置。

手工编译(mvn compile)或者启动 IDE 的时候, 会自动在 target/classes 下生成对应的实现类。

5. Test

@SpringBootTestclass SpringbootMapstructApplicationTests {    @Autowired    private UserConverter userConverter;    @Test    public void testMapStruct() {        UserInfo userInfo = new UserInfo();        userInfo.setAddress("上海市");        userInfo.setRemark("此人非常懒");        User user = new User();        user.setId(1L);        user.setName("周某人");        user.setPassword("123456");        user.setUserStatusEnum(UserStatusEnum.LOCK);        user.setCreateTime(new Date());        user.setUserInfo(userInfo);        UserDTO userDTO = userConverter.entity2dto(user);        System.out.println(userDTO);    }}

来源:

https://www.toutiao.com/i6894179501249561095/

“IT大咖说”欢迎广大技术人员投稿,投稿邮箱:aliang@itdks.com

来都来了,走啥走,留个言呗~

 IT大咖说  |  关于版权 

由“IT大咖说(ID:itdakashuo)”原创的文章,转载时请注明作者、出处及微信公众号。投稿、约稿、转载请加微信:ITDKS10(备注:投稿),茉莉小姐姐会及时与您联系!

感谢您对IT大咖说的热心支持!

相关推荐

推荐文章

文章转载自IT大咖说,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论