当前位置: 移动技术网 > IT编程>开发语言>Java > 自定义mybatis

自定义mybatis

2019年06月12日  | 移动技术网IT编程  | 我要评论

玉面飞狐高清,户外婚礼流程,捐精网

架构分析

  1. configuration类:

    1. 得到数据源对象

    2. 加载其它的实体类映射文件:usermapper.xml,使用dom4j

  2. mapper类只是一个实体类:pojo,用来封装数据

  3. sqlsession类:

    1. 生成了usermapper接口的代理对象,jdk代理。

    2. 访问数据库:jdbc

    3. 封装查询的结果集,使用反射

使用到的技术

 

添加所需的所有依赖,做好准备工作。

pom.xml文件

 <properties>
        <!--dom4j版本-->
        <dom4j.vesrion>1.6.1</dom4j.vesrion>
        <!--dom4j依赖包版本-->
        <jaxen.version>1.1.6</jaxen.version>
        <!--mysql驱动版本-->
        <mysql.version>5.1.30</mysql.version>
        <!--c3p0版本-->
        <c3p0.version>0.9.2.1</c3p0.version>
        <!-- junit版本 -->
        <junit.version>4.12</junit.version>
    </properties>

    <dependencies>
        <!--dom4j依赖-->
        <dependency>
            <groupid>dom4j</groupid>
            <artifactid>dom4j</artifactid>
            <version>${dom4j.vesrion}</version>
        </dependency>
        <dependency>
            <groupid>jaxen</groupid>
            <artifactid>jaxen</artifactid>
            <version>${jaxen.version}</version>
        </dependency>
        <!-- mysql数据库依赖 -->
        <dependency>
            <groupid>mysql</groupid>
            <artifactid>mysql-connector-java</artifactid>
            <version>${mysql.version}</version>
        </dependency>
        <!--c3p0依赖-->
        <dependency>
            <groupid>com.mchange</groupid>
            <artifactid>c3p0</artifactid>
            <version>${c3p0.version}</version>
        </dependency>
        <!-- junit依赖 -->
        <dependency>
            <groupid>junit</groupid>
            <artifactid>junit</artifactid>
            <version>${junit.version}</version>
        </dependency>
    </dependencies>

自定义mybatis:mapper封装数据类

分析映射配置:usermapper.xml 

 

步骤

  1. 创建包com.it.mybatis

  2. 创建实体类:mapper包含4个属性:namespace,id,resulttype,sql

  3. 重写tostring()方法,方便后期测试看到封装的结果

  4. 生成get和set方法

  5. 一个mapper对象代表一条要操作的查询语句对象

代码

package com.it.mybatis;

/**
 用来封装映射文件的实体类
 */
public class mapper {

    private string namespace;  //接口类全名
    private string id;   //接口中方法名
    private string resulttype;  //封装的数据类型
    private string sql;   //要执行的sql语句

    @override
    public string tostring() {
        return "mapper{" +
                "namespace='" + namespace + '\'' +
                ", id='" + id + '\'' +
                ", resulttype='" + resulttype + '\'' +
                ", sql='" + sql + '\'' +
                '}';
    }

    public string getnamespace() {
        return namespace;
    }

    public void setnamespace(string namespace) {
        this.namespace = namespace;
    }

    public string getid() {
        return id;
    }

    public void setid(string id) {
        this.id = id;
    }

    public string getresulttype() {
        return resulttype;
    }

    public void setresulttype(string resulttype) {
        this.resulttype = resulttype;
    }

    public string getsql() {
        return sql;
    }

    public void setsql(string sql) {
        this.sql = sql;
    }
}

自定义mybatis:设计configuration的基本属性

  1. 设计configuration的基本属性

  2. 产生get和set方法

  3. 产生tostring()方法

分析

sqlmapconfig.xml文件

 

  1. 创建loadsqlmapconfig()方法,它的作用:

    1. 解析sqlmapconfig.xml配置文件,给configuration中的属性赋值

    2. 解析usermapper.xml配置文件,给mapper中的属性赋值

  2. 在构造方法中调用方法: loadsqlmapconfig()

  3. 作用:使用dom4j解析sqlmapconfig.xml文件,给数据库有关的属性赋值

    1. 从类路径加载/sqlmapconfig.xml配置文件,创建输入流

    2. 使用dom4j得到文档对象

    3. 使用xpath读取所有property元素

    4. 遍历每个property元素,读取它的name和value属性值

    5. 判断name的字符串,如果与类中的属性名相同,则赋值到相应属性中

  4.configuration解析实体类映射文件

         解析usermapper.xml并且封装到mapper类中

    1. 创建新的方法loadmapper(document document),将当前的文档对象传递给方法

    2. 读取<mapper>中的resource属性值

    3. 通过resource读取它对应的xml文件

    4. 得到namespace,id,resulttype,sql的值,封装成mapper对象

    5. 在loadsqlmapconfig()中调用此方法

 

 

loadmapper(document document)方法开发步骤

作用:进一步解析其它的xml文件,给mappers属性赋值

  1. 读取mapper中的resource属性值

    1. 使用xpath读取所有mapper元素

    2. 遍历每个mapper元素

    3. 读取mapper的resource属性值

  2. 通过resource读取它对应的xml文件,得到namespace,id,resulttype,sql的值

    1. 使用类对象,读取输入流下面resource,注:要加上/

    2. 创建文档对象

    3. 读取根元素mapper

    4. 读取namespace属性

    5. 读取根元素下的一个select标签

    6. 得到id,resulttype,sql内容

  3. 封装成mapper对象

    1. 创建一个自定义的mapper对象,封装上面三个属性

    2. 再封装namespace属性

    3. 将封装好的mapper对象添加到this的mappers属性中,其中键是namespace+"."+id,值是自定义的mapper对象。

代码

package com.it.mybatis;

import com.mchange.v2.c3p0.combopooleddatasource;
import org.dom4j.document;
import org.dom4j.documentexception;
import org.dom4j.element;
import org.dom4j.io.saxreader;

import javax.sql.datasource;
import java.beans.propertyvetoexception;
import java.io.inputstream;
import java.util.hashmap;
import java.util.list;
import java.util.map;

/**
 1. 封装sqlmapconfig.xml配置信息
 2. 得到数据源
 3. 加载usermapper.xml配置信息
 */
public class configuration {

    //数据源的四个属性
    private string username;
    private string password;
    private string url;
    private string driver;

    //封装其它的映射文件中属性
    private map<string, mapper> mappers = new hashmap<>();

    private datasource datasource;  //数据源

    //在构造方法中调用
    public configuration() {
        try {
            loadsqlmapconfig();  //加载配置文件
            createdatasource();  //创建数据源
        } catch (exception e) {
            e.printstacktrace();
        }
    }

    /*
        解析sqlmapconfig.xml文件,封装上面的数据源的四个属性
         */
    private void loadsqlmapconfig() throws exception {
        //得到输入流
        inputstream inputstream = configuration.class.getresourceasstream("/sqlmapconfig.xml");
        //得到文档对象
        saxreader saxreader = new saxreader();
        document document = saxreader.read(inputstream);
        //读取property
        list<element> list = document.selectnodes("//property");
        for (element property : list) {
            //读取name属性
            string name = property.attributevalue("name");
            //读取value属性
            string value = property.attributevalue("value");
            //判断是哪个属性
            switch (name) {
                case "username":
                    this.username = value;
                    break;
                case "password":
                    this.password = value;
                    break;
                case "driver":
                    this.driver = value;
                    break;
                case "url":
                    this.url = value;
                    break;
            }
        }
        //读取usermapper.xml文件
        loadmapper(document);
    }

    /**
    解析其它的实体类映射文件
    @param document 上面已经得到的文档对象
     */
    private void loadmapper(document document) throws exception {
        //读取mapper中resource属性
        list<element> list = document.selectnodes("//mapper");
        for (element mapperelement : list) {
            //读取mapper中resource属性
            string resource = mapperelement.attributevalue("resource");
            //再次读取新的xml文件
            inputstream in = configuration.class.getresourceasstream("/" + resource);
            //创建文档对象
            document doc = new saxreader().read(in);
            //得到根元素
            element rootelement = doc.getrootelement();
            string namespace = rootelement.attributevalue("namespace");
            //得到mapper下select元素
            element select = rootelement.element("select");
            //得到id属性
            string id = select.attributevalue("id");
            string resulttype = select.attributevalue("resulttype");
            string sql = select.gettexttrim();
            //创建mapper对象
            mapper mapper = new mapper();
            mapper.setid(id);
            mapper.setnamespace(namespace);
            mapper.setsql(sql);
            mapper.setresulttype(resulttype);
            //键=namespace + "." + "id";
            string key = namespace + "." + id;
            //将创建好的mapper对象加到map集合中
            mappers.put(key,mapper);
        }
    }

    /**
     创建数据源
     */
    private void createdatasource() throws propertyvetoexception {
        //使用c3p0的数据源
        combopooleddatasource ds = new combopooleddatasource();
        //设置数据库访问属性
        ds.setuser(username);
        ds.setpassword(password);
        ds.setjdbcurl(url);
        ds.setdriverclass(driver);
        this.datasource = ds;
    }

    @override
    public string tostring() {
        return "configuration{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", url='" + url + '\'' +
                ", driver='" + driver + '\'' +
                ", mappers=" + mappers +
                ", datasource=" + datasource +
                '}';
    }

    public string getusername() {
        return username;
    }

    public void setusername(string username) {
        this.username = username;
    }

    public string getpassword() {
        return password;
    }

    public void setpassword(string password) {
        this.password = password;
    }

    public string geturl() {
        return url;
    }

    public void seturl(string url) {
        this.url = url;
    }

    public string getdriver() {
        return driver;
    }

    public void setdriver(string driver) {
        this.driver = driver;
    }

    public map<string, mapper> getmappers() {
        return mappers;
    }

    public void setmappers(map<string, mapper> mappers) {
        this.mappers = mappers;
    }

    public datasource getdatasource() {
        return datasource;
    }

    public void setdatasource(datasource datasource) {
        this.datasource = datasource;
    }
}

 

核心组件sqlsession:编写getmapper方法

 

步骤

得到sql语句和返回类型

  1. 得到configuration中map集合

    1. 实例化configuration对象

    2. 通过configuration得到mapper对象的集合

  2. 得到map中的键:类全名.方法名

    1. 通过方法对象->得到声明的接口->得到名称:即类全名 com.it.dao.usermapper

    2. 获取当前执行的方法名称:findallusers

    3. 通过类全名+方法名得到键

  3. 得到mapper中相应的属性

    1. 通过类全名+"."+方法名,从mappers中得到映射的mapper对象

    2. 从mapper中获取查询的sql语句

    3. 从mapper中获取返回值类型resulttype

    4. 通过反射将上面的resulttype字符串转成类对象,供后面的方法使用

得到connection对象访问数据库

  1. 通过configuration得到数据源,通过数据源得到连接对象

  2. 调用list queryforlist(connection connection, string sql, class clazz)方法

    1. 参数:连接对象,sql语句,结果集的类型。 直接创建一个list集合,添加3个user对象到集合中,暂时不访问数据库。

    2. 返回封装好的集合

 

package com.it.mybatis;

import com.itheima.entity.user;

import javax.sql.datasource;
import java.lang.reflect.field;
import java.lang.reflect.invocationhandler;
import java.lang.reflect.method;
import java.lang.reflect.proxy;
import java.sql.*;
import java.util.arraylist;
import java.util.list;
import java.util.map;

/**
 核心类
 1. 生成了usermapper接口的代理对象,jdk代理。
 2. 访问数据库:jdbc
 3. 封装查询的结果集,使用反射。
 */
public class sqlsession {

    public <t> t getmapper(class<t> clazz) {
        /*
        参数1:类加载器
        参数2:接口数组
        参数3:每个方法调用一次
         */
        return (t) proxy.newproxyinstance(
                sqlsession.class.getclassloader(),
                new class[]{clazz},
                new invocationhandler() {
                    @override
                    public object invoke(object proxy, method method, object[] args) throws throwable {
                       //1. 通过键得到mapper对象
                        //创建configuration对象
                        configuration configuration = new configuration();
                        //得到集合
                        map<string, mapper> mappers = configuration.getmappers();
                        string id = method.getname();  //方法名
                        //getdeclaringclass得到method所在类全名
                        string namespace = method.getdeclaringclass().getname();
                        //如何得到键
                        string key = namespace + "." + id;
                        //通过键得到值
                        mapper mapper = mappers.get(key);

                        //2. 从mapper对象中得到sql语句执行,并且封装成对象返回
                        string sql = mapper.getsql();
                        //resulttype = com.itheima.entity.user
                        string resulttype = mapper.getresulttype();
                        //将字符串转成class
                        class type = class.forname(resulttype);

                        //3.查询数据库,必须要连接对象
                        //连接对象从数据源中得到
                        datasource datasource = configuration.getdatasource();
                        connection connection = datasource.getconnection();

                        //使用jdbc访问数据库得到封装好的结果
                        list list = queryforlist(connection, sql, type);
                        return list;
                    }
                });
    }

    /**
     通过jdbc来访问数据库
     @param connection 连接对象
     @param sql 语句
     @param type 返回类型
     @return
     */
    private list queryforlist(connection connection, string sql, class type) throws exception {
        list users = new arraylist<>();

        //1. 通过connection创建语句对象:preparedstatement
        preparedstatement ps = connection.preparestatement(sql);

        //2. 通过语句对象执行sql语句
        resultset rs = ps.executequery();

        //3. 执行完毕以后得到结果集resultset
        while(rs.next()) {
            //4. 将resultset进行遍历,封装成实体类对象,添加到集合中
            //创建对象
            object user = type.getconstructor().newinstance();
            //得到类中所有的属性
            field[] fields = type.getdeclaredfields();
            for (field field : fields) {
                //得到属性名
                string name = field.getname();
                //得到相应的值
                object value = rs.getobject(name);
                //暴力反射
                field.setaccessible(true);
                //给每个属性赋值
                field.set(user, value);
            }
            users.add(user);
        }

        //5.释放资源
        rs.close();
        ps.close();
        connection.close();

        return users;
    }

}

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网