tk.mapper_需求分析4个步骤

tk.mapper_需求分析4个步骤引言  Mybatis支持@SelectProvider注解,tkMapper正是运用了该技术,通过解析持久类,拼接xml形式的SQL语句,重新为MappedStatment设置SqlSource实现功能。核心配置<beanclass=”tk.mybatis.spring.mapper.MapperScannerConfigurer”>&l…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

引言

  Mybatis支持@SelectProvider注解,tk Mapper正是运用了该技术,通过解析持久类,拼接xml形式的SQL语句,重新为MappedStatment设置SqlSource实现功能。

核心配置

<bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
      <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
      <property name="basePackage" value="com.wjz.mapper" />
</bean>

tk.mapper_需求分析4个步骤

  private MapperHelper mapperHelper = new MapperHelper();

  @Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
     // 调用mybatis的后置注册处理,扫描mapper类注册为MapperFactoryBean对象
super.postProcessBeanDefinitionRegistry(registry); // 如果没有注册过接口,就注册默认的Mapper接口,后文详解#1 this.mapperHelper.ifEmptyRegisterDefaultInterface(); String[] names = registry.getBeanDefinitionNames(); GenericBeanDefinition definition; for (String name : names) { BeanDefinition beanDefinition = registry.getBeanDefinition(name); if (beanDefinition instanceof GenericBeanDefinition) { definition = (GenericBeanDefinition) beanDefinition;
          // 判断注册的bean是MapperFactoryBean,设置beanClass为 tk.mybatis.spring.mapper.MapperFactoryBean
          // 设置MapperHelper属性
if (StringUtil.isNotEmpty(definition.getBeanClassName()) && definition.getBeanClassName().equals("org.mybatis.spring.mapper.MapperFactoryBean")) { definition.setBeanClass(MapperFactoryBean.class); definition.getPropertyValues().add("mapperHelper", this.mapperHelper); } } } }

书接前文#1

MapperHelper中注册Mapper接口

// 如果当前注册的接口为空,自动注册默认的接口tk.mybatis.mapper.common.Mapper
public
void ifEmptyRegisterDefaultInterface() { if (registerClass.size() == 0) { registerMapper("tk.mybatis.mapper.common.Mapper"); } }

public void registerMapper(String mapperClass) {
        try {
             // 实例化Mapper接口
        registerMapper(Class.forName(mapperClass)); }
catch (ClassNotFoundException e) { throw new MapperException("注册通用Mapper[" + mapperClass + "]失败,找不到该通用Mapper!"); } }

public void registerMapper(Class<?> mapperClass) {
        if (!registerMapper.containsKey(mapperClass)) {
            registerClass.add(mapperClass);
        // 注册Mapper的Class和通过通用Mapper接口获取对应的MapperTemplate,后文详解#2 registerMapper.put(mapperClass, fromMapperClass(mapperClass)); }
// 自动注册继承的接口 Class<?>[] interfaces = mapperClass.getInterfaces(); if (interfaces != null && interfaces.length > 0) { for (Class<?> anInterface : interfaces) {
          // 递归注册Mapper接口继承的其他接口如BaseMapper接口 registerMapper(anInterface); } } }

书接前文#2

private MapperTemplate fromMapperClass(Class<?> mapperClass) {
    
    
     // 获得接口中的方法,BaseMapper接口中没有方法,SelectOneMapper接口中有selectOne方法 Method[] methods
= mapperClass.getDeclaredMethods(); Class<?> templateClass = null; Class<?> tempClass = null; Set<String> methodSet = new HashSet<String>(); for (Method method : methods) {
        // 判断接口的方法中是否有SelectProvider注解修饰
if (method.isAnnotationPresent(SelectProvider.class)) { SelectProvider provider = method.getAnnotation(SelectProvider.class); tempClass = provider.type(); methodSet.add(method.getName()); } else if (method.isAnnotationPresent(InsertProvider.class)) { InsertProvider provider = method.getAnnotation(InsertProvider.class); tempClass = provider.type(); methodSet.add(method.getName()); } else if (method.isAnnotationPresent(DeleteProvider.class)) { DeleteProvider provider = method.getAnnotation(DeleteProvider.class); tempClass = provider.type(); methodSet.add(method.getName()); } else if (method.isAnnotationPresent(UpdateProvider.class)) { UpdateProvider provider = method.getAnnotation(UpdateProvider.class); tempClass = provider.type(); methodSet.add(method.getName()); } if (templateClass == null) {
          // 将注解中的type属性值赋值给templateClass变量,如BaseSelectProvider templateClass
= tempClass; } else if (templateClass != tempClass) { throw new MapperException("一个通用Mapper中只允许存在一个MapperTemplate子类!"); } }
     // 判断templateClass变量是否为null或者判断templateClass变量值是否继承自MapperTemplate如BaseSelectProvider
if (templateClass == null || !MapperTemplate.class.isAssignableFrom(templateClass)) { templateClass = EmptyProvider.class; } MapperTemplate mapperTemplate = null; try {
        // 通过构造反射实例化MapperTemplate如BaseSelectProvider,构造参数为Mapper的Class(如SelectOneMapper.class)、MapperHelper.class mapperTemplate
= (MapperTemplate) templateClass.getConstructor(Class.class, MapperHelper.class).newInstance(mapperClass, this); } catch (Exception e) { throw new MapperException("实例化MapperTemplate对象失败:" + e.getMessage()); } // 注册方法 for (String methodName : methodSet) { try {
          // 注册templateClass中的方法如BaseSelectProvider中的selectOne方法 mapperTemplate.addMethodMap(methodName, templateClass.getMethod(methodName, MappedStatement.
class)); } catch (NoSuchMethodException e) { throw new MapperException(templateClass.getCanonicalName() + "中缺少" + methodName + "方法!"); } }
     // 返回Mapper模板对象
return mapperTemplate; }

tk.mybatis.spring.mapper.MapperScannerConfigurer后置处理时,注册了tk.mybatis.spring.mapper.MapperFactoryBean

tk.mapper_需求分析4个步骤

@Override
    protected void checkDaoConfig() {
    
    
     // 调用父类org.mybatis.spring.mapper.MapperFactoryBean,解析Mapper的注解,为Configuration注册Mapper
    
 // 如解析类注解注册Cache,解析方法注解注册MappedStatment(包括parameterType,SqlSource,ResultMap等)
super.checkDaoConfig(); // 判断Mapper接口是否继承了通用Mapper,getObjectType()为当前Mapper接口 if (mapperHelper.isExtendCommonMapper(getObjectType())) {
        // 处理Configuration,为MappedStatment重新设置SqlSource mapperHelper.processConfiguration(getSqlSession().getConfiguration(), getObjectType()); } }

public void processConfiguration(Configuration configuration, Class<?> mapperInterface) {
        String prefix;
        if (mapperInterface != null) {
            prefix = mapperInterface.getCanonicalName();
        } else {
            prefix = "";
        }
     // 遍历所有的MappedStatment
for (Object object : new ArrayList<Object>(configuration.getMappedStatements())) { if (object instanceof MappedStatement) { MappedStatement ms = (MappedStatement) object; if (ms.getId().startsWith(prefix) && isMapperMethod(ms.getId())) {
            // 判断是否解析注解生成的SqlSource
if (ms.getSqlSource() instanceof ProviderSqlSource) {
               // 重新为MappedStatment设置SqlSource setSqlSource(ms); } } } } }

public void setSqlSource(MappedStatement ms) {
    
    
     // 从缓存中获得MapperTemplate,如BaseSelectProvider MapperTemplate mapperTemplate
= msIdCache.get(ms.getId()); try { if (mapperTemplate != null) { mapperTemplate.setSqlSource(ms); } } catch (Exception e) { throw new RuntimeException(e); } }

public void setSqlSource(MappedStatement ms) throws Exception {
        if (this.mapperClass == getMapperClass(ms.getId())) {
            throw new RuntimeException("请不要配置或扫描通用Mapper接口类:" + this.mapperClass);
        }
     // 从缓存中获得方法,如selectOne方法 Method method
= methodMap.get(getMethodName(ms)); try { //第一种,直接操作ms,不需要返回值 if (method.getReturnType() == Void.TYPE) { method.invoke(this, ms); } //第二种,返回SqlNode else if (SqlNode.class.isAssignableFrom(method.getReturnType())) { SqlNode sqlNode = (SqlNode) method.invoke(this, ms); DynamicSqlSource dynamicSqlSource = new DynamicSqlSource(ms.getConfiguration(), sqlNode); setSqlSource(ms, dynamicSqlSource); } //第三种,返回xml形式的sql字符串 else if (String.class.equals(method.getReturnType())) {
          // 方法反射调用,如selectOne方法,后文详解#3 String xmlSql
= (String) method.invoke(this, ms);
          // 通过LanguageDriver创建SqlSource SqlSource sqlSource
= createSqlSource(ms, xmlSql); // 替换原有的SqlSource,后文详解#4 setSqlSource(ms, sqlSource); } else { throw new RuntimeException("自定义Mapper方法返回类型错误,可选的返回类型为void,SqlNode,String三种!"); } //cache checkCache(ms); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e.getTargetException() != null ? e.getTargetException() : e); } }

书接前文#3

以BaseSelectProvider的selectOne方法为例

public String selectOne(MappedStatement ms) {
    
    
     // 从MappedStatment中拿到MapperClass,如com.wjz.StudentMapper.class
     // 再拿到StudentMapper的泛型类型,如Student.class,后文详解#3-1
Class
<?> entityClass = getEntityClass(ms); // 修改返回值类型为实体类型,后文详解#3-2 setResultType(ms, entityClass); StringBuilder sql = new StringBuilder();
     // 拼接查询的字段,后文详解#3-3 sql.append(SqlHelper.selectAllColumns(entityClass));
     // 拼接表名,表名从EntityTable中的name属性中拿 sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
     // 拼接where条件,后文详解#3-4 sql.append(SqlHelper.whereAllIfColumns(entityClass, isNotEmpty()));
return sql.toString(); }

书接前文#3-1

 

public Class<?> getEntityClass(MappedStatement ms) {
        String msId = ms.getId();
        if (entityClassMap.containsKey(msId)) {
    
    
       // 从缓存中获得
return entityClassMap.get(msId); } else { Class<?> mapperClass = getMapperClass(msId); Type[] types = mapperClass.getGenericInterfaces(); for (Type type : types) { if (type instanceof ParameterizedType) { ParameterizedType t = (ParameterizedType) type; if (t.getRawType() == this.mapperClass || this.mapperClass.isAssignableFrom((Class<?>) t.getRawType())) { Class<?> returnType = (Class<?>) t.getActualTypeArguments()[0]; // 获取该类型后,第一次对该类型进行初始化 EntityHelper.initEntityNameMap(returnType, mapperHelper.getConfig());
               // 放置到缓存中 entityClassMap.put(msId, returnType);
return returnType; } } } } throw new RuntimeException("无法获取Mapper<T>泛型类型:" + msId); }

 

public static synchronized void initEntityNameMap(Class<?> entityClass, Config config) {
        if (entityTableMap.get(entityClass) != null) {
            return;
        }
        Style style = config.getStyle();
        // 检查类上是否有NameStyle注解,有的话获得Style枚举的值
        if (entityClass.isAnnotationPresent(NameStyle.class)) {
            NameStyle nameStyle = entityClass.getAnnotation(NameStyle.class);
            style = nameStyle.value();
        }

        // 创建并缓存EntityTable
        EntityTable entityTable = null;
        if (entityClass.isAnnotationPresent(Table.class)) {
            Table table = entityClass.getAnnotation(Table.class);
            if (!table.name().equals("")) {
                entityTable = new EntityTable(entityClass);
                entityTable.setTable(table);
            }
        }
        if (entityTable == null) {
            entityTable = new EntityTable(entityClass);
            // 可以通过style控制
            entityTable.setName(StringUtil.convertByStyle(entityClass.getSimpleName(), style));
        }
        entityTable.setEntityClassColumns(new LinkedHashSet<EntityColumn>());
        entityTable.setEntityClassPKColumns(new LinkedHashSet<EntityColumn>());
        // 处理所有列
        List<EntityField> fields = null;
        if (config.isEnableMethodAnnotation()) {
            fields = FieldHelper.getAll(entityClass);
        } else {
            fields = FieldHelper.getFields(entityClass);
        }
        for (EntityField field : fields) {
    
    
       // 加工字段,后文详解 processField(entityTable, style, field); }
// 当pk.size=0的时候使用所有列作为主键 if (entityTable.getEntityClassPKColumns().size() == 0) { entityTable.setEntityClassPKColumns(entityTable.getEntityClassColumns()); } entityTable.initPropertyMap(); entityTableMap.put(entityClass, entityTable); }

加工字段

private static void processField(EntityTable entityTable, Style style, EntityField field) { // 如果持久类中有字段被Transient注解修饰排除该字段 if (field.isAnnotationPresent(Transient.class)) { return; } // Id注解 EntityColumn entityColumn = new EntityColumn(entityTable); if (field.isAnnotationPresent(Id.class)) { entityColumn.setId(true); } // Column注解 String columnName = null; if (field.isAnnotationPresent(Column.class)) { Column column = field.getAnnotation(Column.class); columnName = column.name(); entityColumn.setUpdatable(column.updatable()); entityColumn.setInsertable(column.insertable()); } // ColumnType注解 if (field.isAnnotationPresent(ColumnType.class)) { ColumnType columnType = field.getAnnotation(ColumnType.class); // column可以起到别名的作用 if (StringUtil.isEmpty(columnName) && StringUtil.isNotEmpty(columnType.column())) { columnName = columnType.column(); } if (columnType.jdbcType() != JdbcType.UNDEFINED) { entityColumn.setJdbcType(columnType.jdbcType()); } if (columnType.typeHandler() != UnknownTypeHandler.class) { entityColumn.setTypeHandler(columnType.typeHandler()); } } // 当字段没有被Column注解修饰时,通过Style枚举值获得字段名,后文详解 if (StringUtil.isEmpty(columnName)) { columnName = StringUtil.convertByStyle(field.getName(), style); } entityColumn.setProperty(field.getName()); entityColumn.setColumn(columnName); entityColumn.setJavaType(field.getJavaType()); // OrderBy注解 if (field.isAnnotationPresent(OrderBy.class)) { OrderBy orderBy = field.getAnnotation(OrderBy.class); if (orderBy.value().equals("")) { entityColumn.setOrderBy("ASC"); } else { entityColumn.setOrderBy(orderBy.value()); } } // 主键策略 - Oracle序列,MySql自动增长,UUID if (field.isAnnotationPresent(SequenceGenerator.class)) { SequenceGenerator sequenceGenerator = field.getAnnotation(SequenceGenerator.class); if (sequenceGenerator.sequenceName().equals("")) { throw new RuntimeException(entityTable.getEntityClass() + "字段" + field.getName() + "的注解@SequenceGenerator未指定sequenceName!"); } entityColumn.setSequenceName(sequenceGenerator.sequenceName()); } else if (field.isAnnotationPresent(GeneratedValue.class)) { GeneratedValue generatedValue = field.getAnnotation(GeneratedValue.class); if (generatedValue.generator().equals("UUID")) { entityColumn.setUuid(true); } else if (generatedValue.generator().equals("JDBC")) { entityColumn.setIdentity(true); entityColumn.setGenerator("JDBC"); entityTable.setKeyProperties(entityColumn.getProperty()); entityTable.setKeyColumns(entityColumn.getColumn()); } else { //允许通过generator来设置获取id的sql,例如mysql=CALL IDENTITY(),hsqldb=SELECT SCOPE_IDENTITY() //允许通过拦截器参数设置公共的generator if (generatedValue.strategy() == GenerationType.IDENTITY) { //mysql的自动增长 entityColumn.setIdentity(true); if (!generatedValue.generator().equals("")) { String generator = null; IdentityDialect identityDialect = IdentityDialect.getDatabaseDialect(generatedValue.generator()); if (identityDialect != null) { generator = identityDialect.getIdentityRetrievalStatement(); } else { generator = generatedValue.generator(); } entityColumn.setGenerator(generator); } } else { throw new RuntimeException(field.getName() + " - 该字段@GeneratedValue配置只允许以下几种形式:" + "\n1.全部数据库通用的@GeneratedValue(generator=\"UUID\")" + "\n2.useGeneratedKeys的@GeneratedValue(generator=\\\"JDBC\\\") " + "\n3.类似mysql数据库的@GeneratedValue(strategy=GenerationType.IDENTITY[,generator=\"Mysql\"])"); } } } entityTable.getEntityClassColumns().add(entityColumn); if (entityColumn.isId()) { entityTable.getEntityClassPKColumns().add(entityColumn); } }

通过Style枚举值获得字段名

public static String convertByStyle(String str, Style style) { switch (style) { 
       // 去掉下划线
case camelhump: return camelhumpToUnderline(str);
       // 改成大写
case uppercase: return str.toUpperCase();
       // 改成小写
case lowercase: return str.toLowerCase();
       // 去掉下划线并改成小写
case camelhumpAndLowercase: return camelhumpToUnderline(str).toLowerCase();
       // 去掉下划线并改成大写
case camelhumpAndUppercase: return camelhumpToUnderline(str).toUpperCase();
       // 什么都不做
case normal: default: return str; } }

 

书接前文#3-2

protected void setResultType(MappedStatement ms, Class<?> entityClass) { 
     // 从缓存中拿到EntityTable EntityTable entityTable
= EntityHelper.getEntityTable(entityClass); List<ResultMap> resultMaps = new ArrayList<ResultMap>();
     // 从缓存中拿到ResultMap添加到List中 resultMaps.add(entityTable.getResultMap(ms.getConfiguration())); MetaObject metaObject
= SystemMetaObject.forObject(ms);
     // 通过反射为Configuration设置resultMaps属性设置值 metaObject.setValue(
"resultMaps", Collections.unmodifiableList(resultMaps)); }

书接前文#3-3

public static String selectAllColumns(Class<?> entityClass) { StringBuilder sql = new StringBuilder(); sql.append("SELECT ");
     // 拼接所有的查询字段 sql.append(getAllColumns(entityClass)); sql.append(
" "); return sql.toString(); }

public static String getAllColumns(Class<?> entityClass) { 
     // 使用EntityHelper根据实例Class获得所有EntityColumn,EntityTable中有Set<EntityColumn>属性 Set
<EntityColumn> columnList = EntityHelper.getColumns(entityClass); StringBuilder sql = new StringBuilder();
     // 循环所有的EntityColumn,拼接字段
for (EntityColumn entityColumn : columnList) { sql.append(entityColumn.getColumn()).append(","); } return sql.substring(0, sql.length() - 1); }

书接前文#3-4

public static String whereAllIfColumns(Class<?> entityClass, boolean empty) { StringBuilder sql = new StringBuilder();
     // 拼接XML形式的XNode sql.append(
"<where>"); //获取全部列 Set<EntityColumn> columnList = EntityHelper.getColumns(entityClass); //当某个列有主键策略时,不需要考虑他的属性是否为空,因为如果为空,一定会根据主键策略给他生成一个值 for (EntityColumn column : columnList) { sql.append(getIfNotNull(column, " AND " + column.getColumnEqualsHolder(), empty)); } sql.append("</where>"); return sql.toString(); }

书接前文#4

protected void setSqlSource(MappedStatement ms, SqlSource sqlSource) { 
     // 通过反射为MappedStatment设置SqlSource MetaObject msObject
= SystemMetaObject.forObject(ms); msObject.setValue("sqlSource", sqlSource); //如果是Jdbc3KeyGenerator,就设置为MultipleJdbc3KeyGenerator KeyGenerator keyGenerator = ms.getKeyGenerator(); if (keyGenerator instanceof Jdbc3KeyGenerator) { msObject.setValue("keyGenerator", new MultipleJdbc3KeyGenerator()); } }

 

转载于:https://www.cnblogs.com/BINGJJFLY/p/7902563.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/188489.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • python win32api教程_python通过api获取数据

    python win32api教程_python通过api获取数据0x01Win32API简介Win32API即为Microsoft32位平台(包括:Windows9x,WindowsNT3.1/4.0/5.0,WindowsCE等)的应用程序编程接口(ApplicationProgrammingInterface),是构筑所有32位Windows平台的基石,所有在Win32平台上运行的应用程序都可以调用这些函数。使用Win32API,应用…

    2022年10月11日
  • 大数据时代下数据挖掘技术的应用[通俗易懂]

    大数据时代下数据挖掘技术的应用[通俗易懂]原文链接:https://mp.weixin.qq.com/s/bxSEO4gKQ-BbDWT1BNnwyw随着社会信息化的迅速发展,无论是数据的变化速率,还是数据的新增种类都在不断更新,数据研究变得越来越复杂,这意味着“大数据时代”到来。2011年,互联网数据中心(internetdatacenter,IDC)将大数据重新定义为:在大数据原有的三维特征——数量、多样、速度基础上,增加了另…

  • ETH挖矿显卡算力大全[通俗易懂]

    ETH挖矿显卡算力大全[通俗易懂]大家买显卡挖ETH,肯定最关心算力了,这里我整理一版,供大家参考,目前只有主流的整理上了,后期会完善更多的供大家参考!欢迎大家加入大力矿工群:621159725  软件下载:百度云盘链接:https://pan.baidu.com/s/1o9tw41k密码:vkyi…

  • android之Unable to execute dex: Multiple dex files define「建议收藏」

    出现了异常Dex Loader:Unable to execute dex: Multiple dex files define Landroid/support/v4/accessibilityservice/AccessibilityServiceInfoCompat$AccessibilityServiceInfoVersionImpl; 查了好多方法都不行,最后得到了解决方法:

  • ASP.NET MVC 上传文件方法

    ASP.NET MVC 上传文件方法开发工具和关键技术:VisualStudio2015,ASP.NETMVC作者:金建勇撰写时间:2019年4月24日,在完成MVC项目的过程中,经常会涉及到上传文件,而且更多的是上传图片,需要上传一张或多张图片到网页上,这个时候就要一个上传文件的方法.下面就讲解如何编写一个上传文件的方法:首先去到控制器创建一个方法,如下图所示:需要先定义好一个字符串,用…

  • navicate15激活码【在线破解激活】

    navicate15激活码【在线破解激活】,https://javaforall.cn/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号