SSM基础篇(八)--手写mybatis

手写mybatis

项目导入三个jar包
image

包结构

SSM基础篇(八)--手写mybatis_第1张图片

执行流程

SSM基础篇(八)--手写mybatis_第2张图片

第一步定义User实体类和UserMapper接口

User实体类

package com.tedu;

public class User {
    int id;
    String username;
    
    @Override
    public String toString() {
        return "User [id=" + id + ", username=" + username + "]";
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
}

UserMapper接口

package com.tedu;

import java.util.List;

public interface UserMapper {
    public List findAll();
}

第二步创建配置文件UserMapper.xml和mybatis-config.xml配置文件

UserMapper.xml


mybatis-config.xml



    
        
        
        
        
    
    
        

    

第三步定义存放sql语句的实体类SqlMapper

package org.mybais.configuration;

//UserMapper.xml
public class SqlMapper {
    String id;
    String resultType;
    String sql;

    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;
    }

    public SqlMapper(String id, String resultType, String sql) {
        super();
        this.id = id;
        this.resultType = resultType;
        this.sql = sql;
    }

    @Override
    public String toString() {
        return "SqlMapper [id=" + id + ", resultType=" + resultType + ", sql=" + sql + "]";
    }

}

第四步定义存放连接数据源的信息的实体类Configuration

package org.mybais.configuration;
//mybatis-config.xml

import java.util.HashMap;

public class Configuration {
    String url;
    String driver;
    String username;
    String password;

    HashMap sqlMappers;

    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 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 HashMap getSqlMappers() {
        return sqlMappers;
    }

    public void setSqlMappers(HashMap sqlMappers) {
        this.sqlMappers = sqlMappers;
    }

    @Override
    public String toString() {
        return "Configuration [url=" + url + ", driver=" + driver + ", username=" + username + ", password=" + password
                + ", sqlMappers=" + sqlMappers + "]";
    }

}

第五步创建XmlConfigParser类

解析xml中的信息,将数据源的信息还有sql语句的信息封装在对象中

package org.mybais.configuration;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

//解析mybatis-config.xml和mapper.xml
public class XmlConfigParser {
    public static Configuration configuration=new Configuration();

    public void parser(InputStream inputStream) throws Throwable{
        SAXReader saxReader=new SAXReader();
        Document document=saxReader.read(inputStream);
        List propertyElments=document.selectNodes("//property");
        for (Element element:propertyElments) {
            String valueOfName=element.attributeValue("name");
            String value=element.attributeValue("value");
            System.out.println(valueOfName+":"+value);
            switch (valueOfName) {
            case "driver":
                configuration.setDriver(value);
                break;
            case "url":
                configuration.setUrl(value);
                break;
            case "username":
                configuration.setUsername(value);
                break;
            case "password":
                configuration.setPassword(value);
                break;
            default:
                break;
            }
        }
        System.out.println(configuration);
        //解析所有的mapper.xml
        List mapperElements=document.selectNodes("//mapper");
        for (Element element:mapperElements) {
            String mapperFileName=element.attributeValue("resource");
            System.out.println("mapperFileName="+mapperFileName);
            parseMapper(mapperFileName);
        }
        System.out.println(configuration);
        
    }

    private void parseMapper(String mapperFileName) throws Throwable {
        ClassLoader classLoader=XmlConfigParser.class.getClassLoader();
        InputStream inputStream=classLoader.getResourceAsStream(mapperFileName);
        SAXReader saxReader=new SAXReader();
        Document document=saxReader.read(inputStream);
        HashMap sqlMappers=new HashMap<>();
        configuration.setSqlMappers(sqlMappers);
        List selectElements=document.selectNodes("//select");
        for (Element element:selectElements) {
            String id=element.attributeValue("id");
            String resultType=element.attributeValue("resultType");
            String sql=element.getText();
            SqlMapper sqlMapper=new SqlMapper(id, resultType, sql);
            sqlMappers.put(id, sqlMapper);
        }
        
    }
}

第六步定义sqlsession来调用代理类对象

package org.mybais.executor;

import java.lang.reflect.Proxy;

public class SqlSession {
    public Object getMapper(Class clazz) {
        ClassLoader classLoader=clazz.getClassLoader();
        Class[] interfaces= {clazz};
        MapperProxy mapperProxy=new MapperProxy();
        
        return Proxy.newProxyInstance(classLoader, interfaces, mapperProxy);
    }

}

第七步定义代理类对象来执行数据库连接并获取执行结果

package org.mybais.executor;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

import org.mybais.configuration.Configuration;
import org.mybais.configuration.SqlMapper;
import org.mybais.configuration.XmlConfigParser;

public class MapperProxy implements InvocationHandler{

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("invoke");
        String methodName=method.getName();
        System.out.println("methodName="+methodName);
        //从XmlConfigParser.configuration得到url,driver,username,password
        //1,创建连接
        Configuration configuration=XmlConfigParser.configuration;
        String driver=configuration.getDriver();
        Class.forName(driver);
        Connection connection=DriverManager.getConnection
                (configuration.getUrl(),
                        configuration.getUsername(),
                        configuration.getPassword());
        System.out.println(connection);
        //2,读取数据库
        //2.1 得到id
        String interfaceName=method.getDeclaringClass().getName();
        String id=interfaceName+"."+methodName;
        System.out.println("id="+id);
        //2.2 从configuration.hashmap中根据id得到 sqlMapper
        SqlMapper sqlMapper=configuration.getSqlMappers().get(id);
        
        //2.3 得到 sql
        String sql=sqlMapper.getSql();
        System.out.println("sql="+sql);
        PreparedStatement preparedStatement=connection.prepareStatement(sql);
        ResultSet resultSet=preparedStatement.executeQuery();
        //3,读到表的列名id,username
        List list=new ArrayList();
        while(resultSet.next()) {            
            //4,读到每行数据
            ResultSetMetaData metaData=resultSet.getMetaData();
            int columnCount=metaData.getColumnCount();
            //把每行的数据转成一个对象
            
            //com.tedu.user
            String returnClassName=sqlMapper.getResultType();
            Class clazz=Class.forName(returnClassName);
            Object object=clazz.newInstance();
            for (int col=1;col<=columnCount;col++) {
                String columnName=metaData.getColumnLabel(col);
                Object dbValue=resultSet.getObject(columnName);
                System.out.println(columnName+":"+dbValue);
                
                //用反射给属性赋值
                Field field=clazz.getDeclaredField(columnName);
                field.setAccessible(true);
                field.set(object, dbValue);
            }
            System.out.println(object);
            list.add(object);

        }
        return list;
    }

} 
 

第八步编写测试类,调用sqlSession对象去访问数据库

package com.tedu;

import java.beans.XMLDecoder;
import java.io.InputStream;
import java.util.List;

import org.mybais.configuration.XmlConfigParser;
import org.mybais.executor.SqlSession;

public class TestMybatis {

    public static void main(String[] args) throws Throwable {

        ClassLoader classLoader = TestMybatis.class.getClassLoader();
        InputStream inputStream = classLoader.getResourceAsStream("mybatis-config.xml");
        XmlConfigParser xmlConfigParser = new XmlConfigParser();
        xmlConfigParser.parser(inputStream);
        
        SqlSession session=new SqlSession();
        Object proxy=session.getMapper(UserMapper.class);
        UserMapper userMapper=(UserMapper) proxy;
        List list =userMapper.findAll();
        System.out.println("main----------");
        System.out.println(list);
    }
}