简介
MapStruct Plus 是 MapStruct 的增强工具,在 MapStruct 的基础上,实现了自动生成 Mapper 接口的功能,并强化了部分功能,使 Java 类型转换更加便捷、优雅。MapStruct Plus 可以实现代码的深拷贝
准备
我这里用的是 Maven 作为我的项目构建工具,先给项目添加 MapStruct Plus 的坐标和相应的解释器
<properties>
<mapstruct-plus.version>1.4.2</mapstruct-plus.version>
<lombok.version>1.18.32</lombok.version>
</properties>
<dependencies>
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus</artifactId>
<version>${mapstruct-plus.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
</dependencies>
<build>
<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.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<!-- 因为使用了 lombok 所以要在下面增加相应的解释器 -->
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
<path>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-processor</artifactId>
<version>${mapstruct-plus.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
创建一个配置文件 MapperConfiguration.java
import io.github.linpeilie.annotations.ComponentModelConfig;
@ComponentModelConfig(componentModel = "default")
public class MapperConfiguration {
}
创建几个实体类用来测试 MapStruct Plus 自动生成映射消息
Dept.java
import java.time.LocalDateTime;
import io.github.linpeilie.annotations.AutoMapping;
import lombok.Data;
/**
* 部门
*/
@Data
public class Dept {
private Integer id;
private String deptName;
/**
* 排序
*/
private Integer sort;
/**
* 部门负责人
*/
private String leaderName;
/**
* 部门负责人邮箱
*/
private String email;
/**
* 状态 true 能用 false 不能用
*/
private Boolean status;
private LocalDateTime craeteDate;
private LocalDateTime updateDate;
}
Role.java
import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 角色
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Role {
private Integer id;
private String roleKey;
private String roleName;
/**
* 状态 true 能用 false 不能用
*/
private Boolean status;
private LocalDateTime craeteDate;
private LocalDateTime updateDate;
}
User.java
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import com.runbrick.app.converter.StringToListStringConverter;
import com.runbrick.app.vo.UserVO;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMapping;
import lombok.Data;
@Data
@AutoMapper(target = UserVO.class, uses = { StringToListStringConverter.class })
public class User {
/**
* 用户身份信息
*/
@AutoMapping(target = "userCode")
private Integer id;
private String userName;
@AutoMapping(defaultValue = "noNickName")
private String nickName;
private Integer sex;
/**
* 角色列表
*/
private List<Role> roles;
/**
* 部门层级 eg: 1,23,120
*/
@AutoMapping(qualifiedByName = "StringToList")
private String deptTree;
/**
* 所属部门
*/
private Dept dept;
/**
* 登录时间
*/
@AutoMapping(dateFormat = "yyyy-MM-dd")
private LocalDateTime loginDate;
/**
* 状态 true 能用 false 不能用
*/
private Boolean status;
@AutoMapping(dateFormat = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime craeteDate;
@AutoMapping(dateFormat = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateDate;
/**
* 余额
*/
@AutoMapping(numberFormat = "$0.00")
private BigDecimal wallet;
}
UserVO.java
import java.util.ArrayList;
import java.util.List;
import com.runbrick.app.domain.Role;
import lombok.Data;
/**
* 用户视图类
*/
@Data
public class UserVO {
/**
* @see User.class id
*/
private Integer userCode;
private String userName;
private String nickName;
private ArrayList<Role> roles;
/**
* 部门名称
*/
private String deptName;
/**
* 部门层级
*/
private List<String> deptTree;
/**
* 状态 true 能用 false 不能用
*/
private Boolean status;
private String craeteDate;
private String updateDate;
/**
* 登录时间
*/
private String loginDate;
/**
* 余额
*/
private String wallet;
}
创建一个工具类 DataGenerationUtil.java 用来创建上面的实体数据
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import com.runbrick.app.domain.Dept;
import com.runbrick.app.domain.Role;
import com.runbrick.app.domain.User;
/**
* 数据生成类
*/
public class DataGenerationUtil {
public static User generationUser(Dept dept, ArrayList<Role> roles) {
LocalDateTime now = LocalDateTime.now();
User user = new User();
user.setId(10001);
user.setUserName("zhangsan");
user.setSex(1);
user.setRoles(roles);
user.setDept(dept);
user.setDeptTree("1,20,1001");
user.setStatus(true);
user.setCraeteDate(now);
user.setLoginDate(now.minusDays(20));
user.setUpdateDate(now.minusDays(10));
user.setWallet(new BigDecimal("120.30"));
return user;
}
public static ArrayList<Role> generationRoles() {
LocalDateTime now = LocalDateTime.now();
ArrayList<Role> roles = new ArrayList<Role>();
roles.add(new Role(1001, "ADMIN-ROLE", "管理员", true, now, now.minusDays(10)));
roles.add(new Role(1002, "USER-ROLE", "普通用户", true, now, now.minusDays(10)));
roles.add(new Role(1003, "MENU-ADMIN-ROLE", "菜单管理员", true, now, now.minusDays(10)));
return roles;
}
public static Dept generationDept() {
LocalDateTime now = LocalDateTime.now();
Dept dept = new Dept();
dept.setId(1001);
dept.setDeptName("生产部门");
dept.setSort(1);
dept.setLeaderName("侃大山");
dept.setEmail("xxx@qq.com");
dept.setStatus(true);
dept.setCraeteDate(now);
dept.setUpdateDate(now.minusDays(10));
return dept;
}
}
创建一个转换类用来转换部门层级
import java.util.Arrays;
import java.util.List;
import org.mapstruct.Named;
public class StringToListStringConverter {
/**
* 字符串转数组
*
* @param str 要转换的字符串,只支持用 "," 转换
* @return
*/
@Named("StringToList")
public List<String> stringToList(String str) {
if (!str.isEmpty() && str.length() > 0) {
return Arrays.asList(str.split(","));
}
return null;
}
}
创建一个测试方法用来测试上面的实体
import java.util.ArrayList;
import org.junit.Test;
import com.runbrick.app.domain.Dept;
import com.runbrick.app.domain.Role;
import com.runbrick.app.domain.User;
import com.runbrick.app.util.DataGenerationUtil;
import com.runbrick.app.vo.UserVO;
import io.github.linpeilie.Converter;
public class MapStructApplication {
private static Converter converter = new Converter();
@Test
public void testGeneration1() {
ArrayList<Role> generationRoles = DataGenerationUtil.generationRoles();
Dept generationDept = DataGenerationUtil.generationDept();
User generationUser = DataGenerationUtil.generationUser(generationDept, generationRoles);
// 创建转换
UserVO convert = converter.convert(generationUser, new UserVO());
System.out.println(convert);
}
}
执行结果:
UserVO(userCode=10001, userName=zhangsan, nickName=noNickName, roles=[Role(id=1001, roleKey=ADMIN-ROLE, roleName=管理员, status=true, craeteDate=2024-06-22T19:44:38.790, updateDate=2024-06-12T19:44:38.790), Role(id=1002, roleKey=USER-ROLE, roleName=普通用户, status=true, craeteDate=2024-06-22T19:44:38.790, updateDate=2024-06-12T19:44:38.790), Role(id=1003, roleKey=MENU-ADMIN-ROLE, roleName=菜单管理员, status=true, craeteDate=2024-06-22T19:44:38.790, updateDate=2024-06-12T19:44:38.790)], deptName=null, deptTree=[1, 20, 1001], status=true, craeteDate=2024-06-22 19:44:38, updateDate=2024-06-12 19:44:38, loginDate=2024-06-02, wallet=$120.30)
测试的时候发现,好像将 List<Entity>
中的某个元素转换另一个实体中的一个字符串实体并不能通过 指定转换方法 实现,不过普通的转换还是可以的。
评论区