认识MapStruct

发布时间:2026/7/28 18:13:08

认识MapStruct 1、MapStruct是用来做什么的在一个成熟的工程中尤其是现在的分布式系统中应用与应用之间还有单独的应用细分模块之后DO 一般不会让外部依赖这时候需要在提供对外接口的模块里放 DTO 用于对象传输也即是 DO 对象对内DTO对象对外DTO 可以根据业务需要变更并不需要映射 DO 的全部属性。这种对象与对象之间的互相转换就需要有一个专门用来解决转换问题的工具毕竟每一个字段都 get/set 会很麻烦。MapStruct 是一种属性映射工具只需要定义一个 Mapper 接口MapStruct 就会自动实现这个映射接口避免了复杂繁琐的映射实现。2、案例创建实体 user.javaGetter Setter NoArgsConstructor AllArgsConstructor public class User { private String userId; private String name; private Integer age; private String email; private Date birthDate; }创建实体VO userVo.javaGetter Setter AllArgsConstructor NoArgsConstructor public class UserVo { private String name; private Integer age; private String email; private Date birth; private String birthformat; }###创建Mapper UserConverterMapper.java可以看到UserConverterMapper是一个接口的形式存在的当然也可以是一个抽象类如果你需要在转换的时候才用个性化的定制的时候可以采用抽象类的方式相应的代码配置官方文档已经声明。Mapper注解是用于标注接口、抽象类是被MapStruct自动映射的标识只有存在该注解才会将内部的接口方法自动实现。Mapper(componentModel spring) public interface UserConverterMapper { UserConverterMapper INSTANCE Mappers.getMapper(UserConverterMapper.class); User UserVo2User(UserVo userVo); Mappings({ //属性名不一致映射 Mapping(source birthdate, target birth), //属性格式不一致 Mapping(target birthformat, expression java(org.apache.commons.lang3.time.DateFormatUtils.format(person.getBirthdate(),\yyyy-MM-dd HH:mm:ss\))), }) UserVo User2UserVo(User user); ListUser UsersVo2Users(ListUserVo userVos); ListUserVo Users2UserVos(ListUser user); }在Mapper接口定义方法上面声明了一系列的注解映射Mapping以及Mappings那么这两个注解是用来干什么工作的呢Mapping注解我们用到了两个属性分别是source、target,参数名称和参数类型不一致的时候可以使用映射参数关系。source代表的是映射接口方法内的参数名称如果是基本类型的参数参数名可以直接作为source的内容如果是实体类型则可以采用实体参数名.字段名的方式作为source的内容配置如上面UserConverterMapper内容所示。target代表的是映射到方法方法值内的字段名称配置如上面UserConverterMapper所示。###Mapper的实现MapStruct根据我们配置的Mapping注解自动将source实体内的字段进行了调用target实体内字段的setXxx方法赋值并且做出了一切参数验证。Component public class UserConverterMapperImpl implements UserConverterMapper { public UserConverterMapperImpl() { } public User UserVo2User(UserVo userVo) { if (userVo null) { return null; } else { User user new User(); user.setBirthDate(userVo.getBirth()); user.setName(userVo.getName()); user.setAge(userVo.getAge()); user.setEmail(userVo.getEmail()); return user; } } public UserVo User2UserVo(User user) { if (user null) { return null; } else { UserVo userVo new UserVo(); userVo.setBirth(user.getBirthDate()); userVo.setName(user.getName()); userVo.setAge(user.getAge()); userVo.setEmail(user.getEmail()); userVo.setBirthformat(DateFormatUtils.format(user.getBirthDate(), yyyy-MM-dd HH:mm:ss)); return userVo; } } public ListUser UsersVo2Users(ListUserVo userVos) { if (userVos null) { return null; } else { ListUser list new ArrayList(userVos.size()); Iterator var3 userVos.iterator(); while(var3.hasNext()) { UserVo userVo (UserVo)var3.next(); list.add(this.UserVo2User(userVo)); } return list; } } public ListUserVo Users2UserVos(ListUser user) { if (user null) { return null; } else { ListUserVo list new ArrayList(user.size()); Iterator var3 user.iterator(); while(var3.hasNext()) { User user1 (User)var3.next(); list.add(this.User2UserVo(user1)); } return list; } } }###测试和使用测试验证获取Mapper的方式就是采用Mappers通过动态工厂内部反射机制完成Mapper实现类的获取。public class ConverterTest { public static void main(String[] args) { UserVo userVo new UserVo(张三,22,1212qq.com,new Date(),null); User user UserConverterMapper.INSTANCE.UserVo2User(userVo); Assert.assertTrue(userVo.getName().equals(user.getName())); Assert.assertTrue(userVo.getAge().equals(user.getAge())); UserVo vo UserConverterMapper.INSTANCE.User2UserVo(user); Assert.assertTrue(vo.getName().equals(user.getName())); Assert.assertTrue(vo.getAge().equals(user.getAge())); } }使用在Mapper注解内添加componentModel属性值配置后在外部可以采用Autowired方式注入Mapper实现类完成映射方法调用由mapstruct自动生成的类文件会发现标记了Component注解。Autowired public UserConverterMapper userConverterMapper; RequestMapping(value /fetchUsers,method RequestMethod.GET) ResponseBody public BaseResultListUserVo fetchBatch(String name){ BaseResultListUserVo result new BaseResult(); try{ UserCondition condtion new UserCondition(); condtion.setName(name); ListUser userList userService.fetchUserList(condtion); ListUserVo vos this.userConverterMapper.Users2UserVos(userList); result.setCode(0); result.setMess(succ); result.setData(vos); return result; }catch (Exception e){ return result; } }调用返回结果{code:0, mess:succ, data:[ { name:小米, email:1212qq.com, birth:2019-08-14 03:34:56, age:22 }] }3、总结它可以自动封装一些同级属性名相同的属性名如上name age 属性可以无需手动写 Mapping对于非同级或属性名 需要写相关的 mapping 属性名不同可以查考 birth 属性配置。如果不同级Mapping(source “XXX.birthDate”, target “XX.birth”) 如此就行了。mapping 还有很多属性,可以查看API。

相关新闻