千家信息网

分析mybatis中@Mapper注解的componentModel属性

发表于:2024-10-17 作者:千家信息网编辑
千家信息网最后更新 2024年10月17日,本篇内容主要讲解"分析mybatis中@Mapper注解的componentModel属性",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"分析mybatis
千家信息网最后更新 2024年10月17日分析mybatis中@Mapper注解的componentModel属性

本篇内容主要讲解"分析mybatis中@Mapper注解的componentModel属性",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"分析mybatis中@Mapper注解的componentModel属性"吧!

一、准备工作

1.1、了解@Mapper 注解

从 mybatis3.4.0 开始加入的 @Mapper 注解,目的就是为了不再写mapper映射文件。

我们只需要在 dao 层定义的接口上使用注解就可以实现sql语句的编写,例如:

@Select("select * from user where name = #{name}") public User find(String name);

如上就是一个简单的使用,虽然简单,但也确实体现出了这个注解的优越性,至少少写了一个xml文件。

所以我就只是想说下 @Mapper 注解的 componentModel 属性,componentModel 属性用于指定自动生成的接口实现类的组件类型,这个属性支持四个值:

  • default: 这是默认的情况,mapstruct 不使用任何组件类型, 可以通过Mappers.getMapper(Class)方式获取自动生成的实例对象。

  • cdi: the generated mapper is an application-scoped CDI bean and can be retrieved via @Inject

  • spring: 生成的实现类上面会自动添加一个@Component注解,可以通过Spring的 @Autowired方式进行注入

  • jsr330: 生成的实现类上会添加@javax.inject.Named 和@Singleton注解,可以通过 @Inject注解获取

1.2、依赖包

首先需要把依赖包导入,主要由两个包组成:

  • org.mapstruct:mapstruct:包含了一些必要的注解,例如@Mapping。r若我们使用的JDK版本高于1.8,当我们在pom里面导入依赖时候,建议使用坐标是:org.mapstruct:mapstruct-jdk8,这可以帮助我们利用一些Java8的新特性。

  • org.mapstruct:mapstruct-processor:注解处理器,根据注解自动生成mapper的实现。

         org.mapstruct                  mapstruct-jdk8         1.2.0.Final                   org.mapstruct         mapstruct-processor         1.2.0.Final     

好了,准备工作做完了,接下来我们就看看巧媳妇儿巧在什么地方吧。

二、先简单玩一把

2.1、定义实体类以及被映射类

// 实体类 @Data @NoArgsConstructor @AllArgsConstructor @Builder public class User {     private Integer id;     private String name;     private String createTime;     private LocalDateTime updateTime; }  // 被映射类VO1:和实体类一模一样 @Data @NoArgsConstructor @AllArgsConstructor @Builder public class UserVO1 {     private Integer id;     private String name;     private String createTime;     private LocalDateTime updateTime; }  // 被映射类VO1:比实体类少一个字段 @Data @NoArgsConstructor @AllArgsConstructor @Builder public class UserVO2 {     private Integer id;     private String name;     private String createTime;  }

2.2、定义接口:

当实体类和被映射对象属性相同或者被映射对象属性值少几个时:

@Mapper(componentModel = "spring") public interface UserCovertBasic {     UserCovertBasic INSTANCE = Mappers.getMapper(UserCovertBasic.class);      /**      * 字段数量类型数量相同,利用工具BeanUtils也可以实现类似效果      * @param source      * @return      */     UserVO1 toConvertVO1(User source);     User fromConvertEntity1(UserVO1 userVO1);      /**      * 字段数量类型相同,数量少:仅能让多的转换成少的,故没有fromConvertEntity2      * @param source      * @return      */     UserVO2 toConvertVO2(User source); }

从上面的代码可以看出:接口中声明了一个成员变量INSTANCE,母的是让客户端可以访问 Mapper 接口的实现。

2.3、使用

@RestController public class TestController {      @GetMapping("convert")     public Object convertEntity() {         User user = User.builder()                 .id(1)                 .name("张三")                 .createTime("2020-04-01 11:05:07")                 .updateTime(LocalDateTime.now())                 .build();         List objectList = new ArrayList<>();          objectList.add(user);          // 使用mapstruct         UserVO1 userVO1 = UserCovertBasic.INSTANCE.toConvertVO1(user);         objectList.add("userVO1:" + UserCovertBasic.INSTANCE.toConvertVO1(user));         objectList.add("userVO1转换回实体类user:" + UserCovertBasic.INSTANCE.fromConvertEntity1(userVO1));         // 输出转换结果         objectList.add("userVO2:" + " | " + UserCovertBasic.INSTANCE.toConvertVO2(user));         // 使用BeanUtils         UserVO2 userVO22 = new UserVO2();         BeanUtils.copyProperties(user, userVO22);         objectList.add("userVO22:" + " | " + userVO22);          return objectList;     } }

2.4、查看编译结果

通过IDE的反编译功能查看编译后自动生成 UserCovertBasic 的实现类 UserCovertBasicImpl ,内容如下:

@Component public class UserCovertBasicImpl implements UserCovertBasic {     public UserCovertBasicImpl() {     }      public UserVO1 toConvertVO1(User source) {         if (source == null) {             return null;         } else {             UserVO1 userVO1 = new UserVO1();             userVO1.setId(source.getId());             userVO1.setName(source.getName());             userVO1.setCreateTime(source.getCreateTime());             userVO1.setUpdateTime(source.getUpdateTime());             return userVO1;         }     }      public User fromConvertEntity1(UserVO1 userVO1) {         if (userVO1 == null) {             return null;         } else {             User user = new User();             user.setId(userVO1.getId());             user.setName(userVO1.getName());             user.setCreateTime(userVO1.getCreateTime());             user.setUpdateTime(userVO1.getUpdateTime());             return user;         }     }      public UserVO2 toConvertVO2(User source) {         if (source == null) {             return null;         } else {             UserVO2 userVO2 = new UserVO2();             userVO2.setId(source.getId());             userVO2.setName(source.getName());             userVO2.setCreateTime(source.getCreateTime());             return userVO2;         }     } }

2.5、浏览器查看结果

好了,一个流程就走完了,是不是感觉贼简单呢?

而且呀,阿粉温馨提醒:如果是要转换一个集合的话,只需要把这里的实体类换成集合就行了,例如:

List toConvertVOList(List source);

三、不简单的情况

上面已经把整个流程都给过了一遍了,相信大家对 mapstruct 也有了一个基础的了解了,所以接下来的情况我们就不展示全部代码了,毕竟篇幅也有限,所以就直接上关键代码(因为不关键的和上面内容一样,哈哈)

3.1、类型不一致

实体类我们还是沿用 User;被映射对象 UserVO3 改为:

@Data @NoArgsConstructor @AllArgsConstructor @Builder public class UserVO3 {     private String id;     private String name;     // 实体类该属性是String     private LocalDateTime createTime;     // 实体类该属性是LocalDateTime     private String updateTime; }

那么我们定义的接口就要稍稍修改一下了:

@Mappings({             @Mapping(target = "createTime", expression = "java(com.java.mmzsblog.util.DateTransform.strToDate(source.getCreateTime()))"),     })     UserVO3 toConvertVO3(User source);      User fromConvertEntity3(UserVO3 userVO3);

上面 expression 指定的表达式内容如下:

public class DateTransform {     public static LocalDateTime strToDate(String str){         DateTimeFormatter df = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm:ss");         return LocalDateTime.parse("2018-01-12 17:07:05",df);     }  }

通过IDE的反编译功能查看编译后的实现类,结果是这样子的:

从图中我们可以看到,编译时使用了expression中定义的表达式对目标字段 createTime 进行了转换;然后你还会发现 updateTime 字段也被自动从 LocalDateTime 类型转换成了 String 类型。

阿粉小结:

当字段类型不一致时,以下的类型之间是 mapstruct 自动进行类型转换的:

1、基本类型及其他们对应的包装类型。此时 mapstruct 会自动进行拆装箱。不需要人为的处理

2、基本类型的包装类型和string类型之间

除此之外的类型转换我们可以通过定义表达式来进行指定转换。

3.2、字段名不一致

实体类我们还是沿用 User;被映射对象 UserVO4 改为:

@Data @NoArgsConstructor @AllArgsConstructor @Builder public class UserVO4 {     // 实体类该属性名是id     private String userId;     // 实体类该属性名是name     private String userName;     private String createTime;     private String updateTime; }

那么我们定义的接口就要稍稍修改一下了:

@Mappings({             @Mapping(source = "id", target = "userId"),             @Mapping(source = "name", target = "userName")     })     UserVO4 toConvertVO(User source);          User fromConvertEntity(UserVO4 userVO4);

通过IDE的反编译功能查看编译后的实现类,编译后的结果是这样子的:

小结:

当字段名不一致时,通过使用 @Mappings 注解指定对应关系,编译后即可实现对应字段的赋值。

很明显, mapstruct 通过读取我们配置的字段名对应关系,帮我们把它们赋值在了相对应的位置上,可以说是相当优秀了,但这也仅仅是优秀,而更秀的还请继续往下看:

3.3、属性是枚举类型

实体类我们还是改用 UserEnum:

@Data @NoArgsConstructor @AllArgsConstructor @Builder public class UserEnum {     private Integer id;     private String name;     private UserTypeEnum userTypeEnum; }

被映射对象 UserVO5 改为:

@Data @NoArgsConstructor @AllArgsConstructor @Builder public class UserVO5 {     private Integer id;     private String name;     private String type; }

枚举对象是:

@Getter @AllArgsConstructor public enum UserTypeEnum {     Java("000", "Java开发工程师"),     DB("001", "数据库管理员"),     LINUX("002", "Linux运维员");          private String value;     private String title;  }

那么我们定义的接口还是照常定义,不会受到它是枚举就有所变化:

@Mapping(source = "userTypeEnum", target = "type")     UserVO5 toConvertVO5(UserEnum source);      UserEnum fromConvertEntity5(UserVO5 userVO5);

通过IDE的反编译功能查看编译后的实现类,编译后的结果是这样子的:

很明显, mapstruct 通过枚举类型的内容,帮我们把枚举类型转换成字符串,并给type赋值,可谓是小心使得万年船啊。

到此,相信大家对"分析mybatis中@Mapper注解的componentModel属性"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

类型 注解 实体 属性 编译 字段 接口 对象 内容 结果 生成 一致 功能 可以通过 数量 自动生成 还是 分析 相同 代码 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 美国服务器租赁安全吗 fm2022数据库怎么选 计算机软件开发哪个城市好 宝山区海航软件开发哪家便宜 数据库主码和候选关键字的区别 大连金融行业it服务软件开发 测定软件开发 山西水性软件开发发展现状 能回去程序数据库连线文件吗 紫荆网络安全 代理服务器下载快吗 外贸vps服务器打码机 b站公共解析服务器设置 唐山财务管理微服务架构数据库 松江CRT数据库密码 奉贤区即时网络技术展示 海南嚎然网络技术有限公司 计算机软件开发原型化方法 上海网络服务器机柜欢迎选购 武汉网络安全培训基地快递 日报表数据库设计入门经典 成都市网络安全产业基金 求生之路2服务器观战怎么加入 软件开发领域的三大方向 为啥进冥赤龙服务器老短 东莞支付软件开发报价 硬盘设置网络服务器 软件开发毕业软件那里买 软件开发项目资金使用计划 智能网络技术专用短程通信
0