本文参考 https://blog.csdn.net/u012373815/article/details/88367456

 主要是为了自己使用方便查询。 这些都是我平时用到了,大家有什么好方法或者有什么更多知识,希望大家不吝赐教

开发中,我们经常需要将PO转DTO、DTO转PO等一些实体间的转换。比较出名的有BeanUtil 和ModelMapper等,它们使用简单,但是在稍显复杂的业务场景下力不从心。MapStruct这个插件可以用来处理domin实体类与model类的属性映射,可配置性强。只需要定义一个 Mapper 接口,MapStruct 就会自动实现这个映射接口,避免了复杂繁琐的映射实现。MapStruct官网地址:http://mapstruct.org/

本文类型简单包含四方面:

(1)属性名称不对应

(2)list集合转换

(3)字段类型不对应

(4)多个来源实体转换成一个参数实体

引入依赖

<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.1.0.Final</version>
</dependency>

需求

我们假设有学生student 类 需要转换成 用户 user 类,将学生信息存入用户信息库

此时Student 类内容如下:

public class Student {
private Integer id;
private String name;
private Integer age;
private String sex;//setters, getters, toString() 方法此处省略不写,但是实际开发需要写的哦
}

此时User 类内容如下

public class User {
private Integer id;
private String name;
private Integer age;
private String sex;//setters, getters, toString() 方法此处省略不写,但是实际开发需要写的哦 }

普通转换model

此时 Student 和 User 的属性名字都相同那么转换接口就是

import org.mapstruct.Mapper;

@Mapper(componentModel = "spring")
public interface UserMapping { /**
* Student 转化为 User
* @param Student
* @return
*/
User studentToUser(Student student);
}

程序运行前要先编译 mvn clean compile , 从而mapstruct框架生成UserMappingImpl 实现类。

特殊转换model

(1)属性名称不对应,如果 User 和 Student 的属性名称不对应例如:

此时Student 类内容如下:

public class Student {
private Integer id;
private String sname;
private Integer age;
private String sex; //setters, getters, toString() 方法此处省略不写,但是实际开发需要写的哦
}

此时User 类内容如下:

public class User {
private Integer id;
private String uname;
private Integer age;
private String sex; //setters, getters, toString() 方法此处省略不写,但是实际开发需要写的哦 }

那么转换接口为

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings; @Mapper(componentModel = "spring")
public interface UserMapping { /**
* Student 转化为 User
* @param Student
* @return
*/
@Mappings({
@Mapping(target = "uname", source = "sname")
// 多个属性不对应可以用 "," 隔开编写多个@Mapping
// ,@Mapping(target = "uname", source = "sname")
})
User studentToUser(Student student);
}

(2) 转换集合list
当user 和 student 都是集合形式list 时应当如下转换
转化 List<> 集合时必须有 实体转化,因为在实现中,List 转换是 for循环调用 实体转化的。所以当属性名不对应时,应该在 实体转化进行 @Mappings 的属性名映射配置,然后list的转换也会继承这和属性的映射。

例如 属性名相同

import org.mapstruct.Mapper;

@Mapper(componentModel = "spring")
public interface UserMapping { /**
* Student 转化为 User
* @param Student
* @return
*/
User studentToUser(Student student); /**
* Students 转化为 Users
* @param Students
* @return
*/
List<User> studentsToUsers(List<Student> students);

属性名不同:

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings; @Mapper(componentModel = "spring")
public interface UserMapping { /**
* Student 转化为 User
* @param Student
* @return
*/
@Mappings({
@Mapping(target = "uname", source = "sname")
// 多个属性不对应可以用 "," 隔开编写多个@Mapping
// ,@Mapping(target = "uname", source = "sname")
})
User studentToUser(Student student); /**
* 此时 studentsToUsers 的实现为循环调用 studentToUser 并继承了 studentToUser 的属性映射
* Students 转化为 Users
* @param Students
* @return
*/
List<User> studentsToUsers(List<Student> students);
}

展示 自动生成的 UserMappingImpl 实现(此类为 执行 mvn clean compile 后自动生成)

@Component

public class UserMappingImpl implements UserMapping {

    @Override

    public User studentToUser(student student) {

        if ( student == null ) {

            return null;
} User user = new User(); User.setId(student.getId() );
User.setName(student.getName() );
// 如果配置了属性映射则为
//User.setUname(student.getSname() ); User.setSex(student.getSex() );
User.setAge(student.getAge() );
return user;
} @Override public List<User> studentsToUsers(List<student> students) { if ( students == null ) { return null;
} List<User> list = new ArrayList<User>(); for ( student student : students ) { list.add( studentToUser( student ) );
} return list;
}
}

(3)字段类型不对应

  字符串转时间,或者时间转字符串,都是用后面的dateFormat值为时间格式

    @Mappings({
@Mapping(target = "createTime", source = "createTimeStr", dateFormat = "yyyy-MM-dd~hh:mm:ss")
// 多个属性不对应可以用 "," 隔开编写多个@Mapping
})
User studentToUser(Student student);

字段类型不对应,比如说user 类的sex字段类型改为boolean
此时User 类内容如下:

public class User {
private Integer id;
private String uname;
private Integer age;
private boolean sex; //setters, getters, toString() 方法此处省略不写,但是实际开发需要写的哦 }
Mappings中qualifiedByName属性可以取由@Named声明的名称
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings; @Mapper(componentModel = "spring")
public interface UserMapping { /**
* Student 转化为 User
* @param Student
* @return
*/
@Mappings({
@Mapping(target = "uname", source = "sname",qualifiedByName = "booleanToString")
// 多个属性不对应可以用 "," 隔开编写多个@Mapping // ,@Mapping(target = "uname", source = "sname") 
})
User studentToUser(Student student); @Named("booleanToString")
default String booleanToString(boolean value){
if(value){
      return "男"; 
}
return "女";
}
}

有的时候有一个额外的转换方法多个mapping类文件都要用到,所以肯定有写一个工具类,mapping引用外部的方法

public class Utils{
@Named("booleanToString")
default String booleanToString(boolean value){
if(value){
return "男";
}
return "女";
}
}
@Mapper(componentModel = "spring",uses=Utils.class)
public interface UserMapping { /**
* Student 转化为 User
* @param Student
* @return
*/
@Mappings({
@Mapping(target = "uname", source = "sname",qualifiedByName = "booleanToString")
})
  User studentToUser(Student student);
}

  也可以直接使用expression

@Mappings({
@Mapping(target = "uname",expression = "java(booleanToString(student.getSname()))")
// 多个属性不对应可以用 "," 隔开编写多个@Mapping // ,@Mapping(target = "uname", source = "sname")
})

(4) 多个来源实体转换成一个参数实体

@Mappings({
@Mapping(target = "chartName", source = "chart.name"),
@Mapping(target = "title", source = "song.title"),
@Mapping(target = "artistName", source = "song.artist.name"),
@Mapping(target = "recordedAt", source = "song.artist.label.studio.name"),
@Mapping(target = "city", source = "song.artist.label.studio.city"),
@Mapping(target = "position", source = "position") })
ChartEntry map(Chart chart, Song song, Integer position);

(5)有一些参数不是来自传入参数,而是默认是一些外部的枚举类或者常量类数据,

  就可以在mapper中声明要导入的外部枚举类或者常量类,

@Mapper(componentModel = "spring",
unmappedTargetPolicy = ReportingPolicy.IGNORE,
imports = {StringUtils.class,
UserConsts.class,
UserStatusEnum.class
})
@Mapping(target = "key",expression = "java( UserConsts.FULL_GIFT)"),
@Mapping(target = "status",expression = "java(UserStatusEnum.VALID_STATUS_NO.getCode())"),

mapstruct 实体转换及List转换,@Mapper注解转换的更多相关文章

  1. php如何遍历多维的stdClass Object 对象,php的转换成数组的函数只能转换外面一丛数组

    php如何遍历多维的stdClass Object 对象,php的转换成数组的函数只能转换外面一丛数组 (2012-09-10 19:58:49) 标签: 杂谈 分类: 网页基础知识 php如何遍历多 ...

  2. piap.excel 微软 时间戳转换mssql sql server文件时间戳转换unix 导入mysql

    piap.excel 微软 时间戳转换mssql sql server文件时间戳转换unix 导入mysql 需要不个mssql的sql文件导入mysql.他们的时间戳格式不同..ms用的是自定义的时 ...

  3. 使用sed,awk将love转换成LOVE,将CHINA转换成china

    将love转换成LOVE,将CHINA转换成china echo "love CHINA" | sed -e 's/love/LOVE/' -e 's/CHINA/china/' ...

  4. 转换编码,将Unicode编码转换成可以浏览的utf-8编码

    //转换编码,将Unicode编码转换成可以浏览的utf-8编码 public function unicodeDecode($name) { $pattern = '/([\w]+)|(\\\u([ ...

  5. 2017春 前端自动化(二) 页面自动刷新、sass与css转换的使用、pxToRem直观转换

    2017春 前端自动化(二)   页面自动刷新.sass与css转换的使用.pxToRem直观转换 引言:   此文要演示:浏览器页面自动刷新:移动端px与rem的转换,简单直观化:使用sass自动生 ...

  6. MyBatis中的@Mapper注解及配套注解使用详解(上)

    前言: 从mybatis3.4.0开始加入了@Mapper注解,目的就是为了不再写mapper映射文件(那个xml写的是真的蛋疼...).很恶心的一个事实是源码中并没有对于这个注解的详细解释 现在我们 ...

  7. MyBatis中的@Mapper注解 @Mappe与@MapperScan关系

    从mybatis3.4.0开始加入了@Mapper注解,目的就是为了不再写mapper映射文件 现在项目中的配置 public interface DemoMapper{ int deleteByPr ...

  8. @Mapper注解在springboot中无法注入

    问题① @Mapper注解报红无法注入 方法 在pom文件中添加依赖

  9. matlab学习笔记10_6 字符串与数值间的转换以及进制之间的转换

    一起来学matlab-matlab学习笔记10 10_6 字符串与数值间的转换以及进制之间的转换 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考书籍 <matlab 程序设计与综合 ...

随机推荐

  1. Git 新建版本库命令

    Command line instructions Git global setup git config --global user.name "张三" git config - ...

  2. Isset、empty、count、is_null的比较

    1.empty判断变量是否为空, 先把变量转为布尔值再返回:对变量(字符串.数组等)赋值为一切为空的值.或者未定义的变量都返回true,即判断为空,比如null,' ',0,array(),false ...

  3. JAVA死锁排查-性能测试问题排查思路

    死锁原因 Java发生死锁的根本原因是:在申请锁时发生了交叉闭环申请.即线程在获得了锁A并且没有释放的情况下去申请锁B,这时,另一个线程已经获得了锁B,在释放锁B之前又要先获得锁A,因此闭环发生,陷入 ...

  4. web测试要点、方法_web端测试大全总结

    一.功能测试 1.1链接测试 链接是web应用系统的一个很重要的特征,主要是用于页面之间切换跳转,指导用户去一些不知道地址的页面的主要手段,链接测试一般关注三点: 1)链接是否按照既定指示那样,确实链 ...

  5. less的使用几个技巧

    1.层级关系 让这个box范围内的全部包进来,这样的话就完美的进行调节,再也不用到处找第几行第几个,我刚才在哪个位置给覆盖了.一看便知! .box{ width: 100%; height: 300p ...

  6. vx小程序(1)

    一.程序配置 app.json 1. pages字段——用于描述当前小程序的页面路径. 2.window字段——定义小程序所有页面的顶部背景颜色,文字颜色等. 注意:可以在pages/logs目录下的 ...

  7. 一文搞懂Python函数(匿名函数、嵌套函数、闭包、装饰器)!

    Python函数定义.匿名函数.嵌套函数.闭包.装饰器 目录 Python函数定义.匿名函数.嵌套函数.闭包.装饰器 函数核心理解 1. 函数定义 2. 嵌套函数 2.1 作用 2.2 函数变量作用域 ...

  8. redis(六):Redis 字符串(String)

    Redis 字符串数据类型的相关命令用于管理 redis 字符串值,基本语法如下: 语法 redis 127.0.0.1:6379> COMMAND KEY_NAME 实例 redis 127. ...

  9. Visual SVN Server+TortoiseSVN进行源代码管理

    安装VisualSVN Server 安装完之后,可配置SVN Server的IP地址,右键下图红色部分,选择属性,然后可配置ServeName和IP Address 之后可以创建用户.用户组和项目库 ...

  10. 聊聊Mysql主从同步读写分离配置实现

    Hi,各位热爱技术的小伙伴您们好,好久没有写点东西了,今天写点关于mysql主从同步配置的操作日志同大家一起分享.最近自己在全新搭建一个mysql主从同步读写分离数据库简单集群,我讲实际操作步骤整理分 ...