MyBatis-study notes 03 [03. Customize Mybatis framework]

  1. MyBatis-study notes 01 [01. Mybatis course introduction and environment construction] [day01]
  2. MyBatis-study notes 02 [02. Mybatis entry case]
  3. MyBatis-study notes 03 [03. Customize Mybatis framework]
  4. MyBatis-study notes 04 [04. Custom Mybatis framework based on annotation development] [day02]
  5. MyBatis-study notes 05 [05. Use Mybatis to complete CRUD]
  6. MyBatis-study notes 06 [06. Use Mybatis to complete the development of the DAO layer]
  7. MyBatis-study notes 07 [07. Mybatis connection pool and transaction]
  8. MyBatis- study notes 08 [08. Dynamic SQL]
  9. MyBatis-study notes 09 [09. Mybatis multi-table operation]
  10. MyBatis-study notes 10 [10. JNDI extended knowledge]
  11. MyBatis-study notes 11 [11. Mybatis cache]
  12. ​​​​​​​MyBatis-study notes 12 [12. Mybatis annotation development]

table of Contents

1 Customize the analysis of Mybatis-perform all the analysis of the query

2 Customize Mybatis analysis-create proxy object analysis

3 Customize the coding of mybatis-create interfaces and classes based on the missing test classes

class Resources

class SqlSessionFactoryBuilder

interface SqlSessionFactory

interface SqlSession

4 Custom mybatis encoding-introduction of tools for parsing XML

Import the coordinates of dom4j

Configuration.java

Mapper

XMLConfigBuilder.java

5 Customize Mybatis coding-create two default implementation classes and analyze the relationship between the classes

DefaultSqlSession.java

6 Customize Mybatis coding-realize all operations based on XML query

7 Customize Mybatis coding-realize all query based on annotation configuration


1 Customize the analysis of Mybatis-perform all the analysis of the query

6. Analysis of custom Mybatis:
    What does Mybatis do when adding, deleting, modifying and checking using the proxy dao?
        There are only two things:
            first: create a proxy object and
            second: call selectList in the proxy object

What statement is used to execute and where to encapsulate?

Read the stream and parse the configuration file.

(E) Forced conversion type

Query all analysis

2 Customize Mybatis analysis-create proxy object analysis

Custom Mybatis analysis

3 Customize the coding of mybatis-create interfaces and classes based on the missing test classes

6. Analysis of custom Mybatis:
    custom Mybatis can see the class through the entry case
        class Resources
        class SqlSessionFactoryBuilder
        interface SqlSessionFactory
        interface SqlSession

 

The benefits of custom implementation classes: to achieve flexible control (each more method, you can have more functions)!

class Resources

package com.itheima.mybatis.io;

import java.io.InputStream;

/**
 * 使用类加载器读取配置文件的类
 */
public class Resources {
    /**
     * 根据传入的参数,获取一个字节输入流
     *
     * @param filePath
     * @return
     */
    public static InputStream getResourceAsStream(String filePath) {
        //Resources.class得到当前类的字节码;getClassLoader()获取字节码的类加载器;
        //getResourceAsStream根据类加载器读取配置
        return Resources.class.getClassLoader().getResourceAsStream(filePath);
    }
}

class SqlSessionFactoryBuilder

package com.itheima.mybatis.sqlsession;

import com.itheima.mybatis.cfg.Configuration;
import com.itheima.mybatis.sqlsession.defaults.DefaultSqlSessionFactory;
import com.itheima.mybatis.utils.XMLConfigBuilder;

import java.io.InputStream;

/**
 * 用于创建一个SqlSessionFactory对象
 */
public class SqlSessionFactoryBuilder {
    /**
     * 根据参数的字节输入流来构建一个SqlSessionFactory工厂
     *
     * @param config
     * @return
     */
    public SqlSessionFactory build(InputStream config) {
        return null;
    }
}

interface SqlSessionFactory

package com.itheima.mybatis.sqlsession;

public interface SqlSessionFactory {
    /**
     * 用于打开一个新的SqlSession对象
     *
     * @return
     */
    SqlSession openSession();
}

interface SqlSession

package com.itheima.mybatis.sqlsession;

/**
 * 自定义Mybatis中和数据库交互的核心类
 * 它里面可以创建dao接口的代理对象
 */
public interface SqlSession {
    /**
     * 根据参数创建一个代理对象
     *
     * @param daoInterfaceClass dao的接口字节码
     * @param <T>
     * @return
     */
    <T> T getMapper(Class<T> daoInterfaceClass);

    /**
     * 释放资源
     */
    void close();
}

4 Custom mybatis encoding-introduction of tools for parsing XML

Import the coordinates of dom4j

 

Configuration.java

Mapper

XMLConfigBuilder.java

package com.itheima.mybatis.utils;

//import com.itheima.mybatis.annotations.Select;

import com.itheima.mybatis.annotations.Select;
import com.itheima.mybatis.cfg.Configuration;
import com.itheima.mybatis.cfg.Mapper;
import com.itheima.mybatis.io.Resources;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用于解析配置文件
 */
public class XMLConfigBuilder {
    /**
     * 解析主配置文件,把里面的内容填充到DefaultSqlSession所需要的地方
     * 使用的技术:
     * dom4j+xpath
     */
    public static Configuration loadConfiguration(InputStream config) {
        try {
            //定义封装连接信息的配置对象(mybatis的配置对象)
            Configuration cfg = new Configuration();
            //1.获取SAXReader对象
            SAXReader reader = new SAXReader();
            //2.根据字节输入流获取Document对象
            Document document = reader.read(config);
            //3.获取根节点
            Element root = document.getRootElement();
            //4.使用xpath中选择指定节点的方式,获取所有property节点
            List<Element> propertyElements = root.selectNodes("//property");
            //5.遍历节点
            for (Element propertyElement : propertyElements) {
                //判断节点是连接数据库的哪部分信息
                //取出name属性的值
                String name = propertyElement.attributeValue("name");
                if ("driver".equals(name)) {
                    //表示驱动
                    //获取property标签value属性的值
                    String driver = propertyElement.attributeValue("value");
                    cfg.setDriver(driver);
                }
                if ("url".equals(name)) {
                    //表示连接字符串
                    //获取property标签value属性的值
                    String url = propertyElement.attributeValue("value");
                    cfg.setUrl(url);
                }
                if ("username".equals(name)) {
                    //表示用户名
                    //获取property标签value属性的值
                    String username = propertyElement.attributeValue("value");
                    cfg.setUsername(username);
                }
                if ("password".equals(name)) {
                    //表示密码
                    //获取property标签value属性的值
                    String password = propertyElement.attributeValue("value");
                    cfg.setPassword(password);
                }
            }
            //取出mappers中的所有mapper标签,判断他们使用了resource还是class属性
            List<Element> mapperElements = root.selectNodes("//mappers/mapper");
            //遍历集合
            for (Element mapperElement : mapperElements) {
                //判断mapperElement使用的是哪个属性
                Attribute attribute = mapperElement.attribute("resource");
                if (attribute != null) {
                    System.out.println("使用的是XML");
                    //表示有resource属性,用的是XML
                    //取出属性的值
                    String mapperPath = attribute.getValue();//获取属性的值"com/itheima/dao/IUserDao.xml"
                    //把映射配置文件的内容获取出来,封装成一个map
                    Map<String, Mapper> mappers = loadMapperConfiguration(mapperPath);
                    //给configuration中的mappers赋值
                    cfg.setMappers(mappers);
                } else {
                    System.out.println("使用的是注解");
                    //表示没有resource属性,用的是注解
                    //获取class属性的值
                    String daoClassPath = mapperElement.attributeValue("class");
                    //根据daoClassPath获取封装的必要信息
                    Map<String, Mapper> mappers = loadMapperAnnotation(daoClassPath);
                    //给configuration中的mappers赋值
                    cfg.setMappers(mappers);
                }
            }
            //返回Configuration
            return cfg;
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                config.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 根据传入的参数,解析XML,并且封装到Map中
     *
     * @param mapperPath 映射配置文件的位置
     * @return map中包含了获取的唯一标识(key是由dao的全限定类名和方法名组成)
     * 以及执行所需的必要信息(value是一个Mapper对象,里面存放的是执行的SQL语句和要封装的实体类全限定类名)
     */
    private static Map<String, Mapper> loadMapperConfiguration(String mapperPath) throws IOException {
        InputStream in = null;
        try {
            //定义返回值对象
            Map<String, Mapper> mappers = new HashMap<String, Mapper>();
            //1.根据路径获取字节输入流
            in = Resources.getResourceAsStream(mapperPath);
            //2.根据字节输入流获取Document对象
            SAXReader reader = new SAXReader();
            Document document = reader.read(in);
            //3.获取根节点
            Element root = document.getRootElement();
            //4.获取根节点的namespace属性取值
            String namespace = root.attributeValue("namespace");//是组成map中key的部分
            //5.获取所有的select节点
            List<Element> selectElements = root.selectNodes("//select");
            //6.遍历select节点集合
            for (Element selectElement : selectElements) {
                //取出id属性的值      组成map中key的部分
                String id = selectElement.attributeValue("id");
                //取出resultType属性的值  组成map中value的部分
                String resultType = selectElement.attributeValue("resultType");
                //取出文本内容            组成map中value的部分
                String queryString = selectElement.getText();
                //创建Key
                String key = namespace + "." + id;
                //创建Value
                Mapper mapper = new Mapper();
                mapper.setQueryString(queryString);
                mapper.setResultType(resultType);
                //把key和value存入mappers中
                mappers.put(key, mapper);
            }
            return mappers;
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            in.close();
        }
    }

    /**
     * 根据传入的参数,得到dao中所有被select注解标注的方法。
     * 根据方法名称和类名,以及方法上注解value属性的值,组成Mapper的必要信息
     *
     * @param daoClassPath
     * @return
     */
    private static Map<String, Mapper> loadMapperAnnotation(String daoClassPath) throws Exception {
        //定义返回值对象
        Map<String, Mapper> mappers = new HashMap<String, Mapper>();
        //1.得到dao接口的字节码对象
        Class daoClass = Class.forName(daoClassPath);
        //2.得到dao接口中的方法数组
        Method[] methods = daoClass.getMethods();
        //3.遍历Method数组
        for (Method method : methods) {
            //取出每一个方法,判断是否有select注解
            boolean isAnnotated = method.isAnnotationPresent(Select.class);
            if (isAnnotated) {
                //创建Mapper对象
                Mapper mapper = new Mapper();
                //取出注解的value属性值
                Select selectAnno = method.getAnnotation(Select.class);
                String queryString = selectAnno.value();
                mapper.setQueryString(queryString);
                //获取当前方法的返回值,还要求必须带有泛型信息
                Type type = method.getGenericReturnType();//List<User>
                //判断type是不是参数化的类型
                if (type instanceof ParameterizedType) {
                    //强转
                    ParameterizedType ptype = (ParameterizedType) type;
                    //得到参数化类型中的实际类型参数
                    Type[] types = ptype.getActualTypeArguments();
                    //取出第一个
                    Class domainClass = (Class) types[0];
                    //获取domainClass的类名
                    String resultType = domainClass.getName();
                    //给Mapper赋值
                    mapper.setResultType(resultType);
                }
                //组装key的信息
                //获取方法的名称
                String methodName = method.getName();
                String className = method.getDeclaringClass().getName();
                String key = className + "." + methodName;
                //给map赋值
                mappers.put(key, mapper);
            }
        }
        return mappers;
    }

}

5 Customize Mybatis coding-create two default implementation classes and analyze the relationship between the classes

DefaultSqlSession.java

6 Customize Mybatis coding-realize all operations based on XML query

7 Customize Mybatis coding-realize all query based on annotation configuration

 

 

Guess you like

Origin blog.csdn.net/weixin_44949135/article/details/114361868