自定义Mybatis框架

使用:

idea

apache-maven-3.3.9

jdk1.8.0_162

 

数据库mybatis1

数据表:user

CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;

 

创建maven工程并引入坐标:

例如:创建mybatis_frame的maven工程,并引入依赖

  

dom4j  jaxen  解析xml配置文件
 
<dependencies>
    <dependency>
        <groupId>dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>1.6.1</version>
    </dependency>
    <dependency>
        <groupId>jaxen</groupId>
        <artifactId>jaxen</artifactId>
        <version>1.1.6</version>
    </dependency>
</dependencies>

 


自定义框架原理:

 项目结构

 

1.编写配置文件:

         SqlMapConfig.xml

         UserMapper.xml

 

   SqlMapConfig.xml

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis1" />
                <property name="username" value="root" />
                <property name="password" value="root" />
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/review/mapper/UserMapper.xml"></mapper>
    </mappers>
</configuration> 
UserMapper.xml
<?xml version="1.0" encoding="utf-8" ?>
<mapper namespace="com.review.mapper.UserMapper">
    <select id="findAll" resultType="com.review.pojo.User">
        select * from user
    </select>
</mapper>

 

2 编写配置文件对应的实体类:

         Confinguration

 

 

public class Configuration {
    private String driverClass;
    private String url;
    private String username;
    private String password;
    private Map<String, Mapper> mappers = new HashMap<>();

    public String getDriverClass() {
        return driverClass;
    }

    public void setDriverClass(String driverClass) {
        this.driverClass = driverClass;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    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 Map<String, Mapper> getMappers() {
        return mappers;
    }

    public void setMappers(Map<String, Mapper> mappers) {
        this.mappers = mappers;
    }
}

 

         Mapper


public class Mapper {
    private String sql;//sql语句

    public String getSql() {
        return sql;
    }

    public void setSql(String sql) {
        this.sql = sql;
    }

    public String getResultType() {
        return resultType;
    }

    public void setResultType(String resultType) {
        this.resultType = resultType;
    }

    private String resultType;//返回值类型

}

 



3编写SqlSession接口及实现类SqlSessionImpl,Executor执行器

         SqlSession接口:对数据库进行操作的方法

         SqlSessionImpl类:对接口中的方法进行重写,在构造中创建executor对象,并对configuration赋值

         Executor: 用于实现 SQL 语句的执行,主要是调用 JDBC 来实现 SQL 语句的执行

SqlSession 接口:
public interface SqlSession {
    //执行
    public <T> List<T> selectList(String mapperId);
    //关闭资源
    public void close();
}

 


SqlSessionImpl类:
public class SqlSessionImpl implements SqlSession {
    private Configuration cfg;
    private Executor executor;


    public SqlSessionImpl(Configuration configuration) {
        this.cfg = configuration;
        this.executor = new Executor(cfg);
    }


    public <T> List<T> selectList(String mapperId) {
        Mapper mapper = cfg.getMappers().get(mapperId);
        String sql = mapper.getSql();
        String returnType = mapper.getResultType();
        return executor.executorQuery(sql, returnType);
    }
    public void close() {

        executor.release();
    }
}

 


 Executor类:用于实现 SQL 语句的执行,主要是调用 JDBC 来实现 SQL 语句的执行
public class Executor {
    private Configuration configuration;

    public Executor(Configuration configuration) {
        this.configuration = configuration;
    }

    private Connection conn = null;
    private PreparedStatement pst = null;
    private ResultSet rs = null;

    public <T> List<T> executorQuery(String sql, String returnType) {

        List<T> list = new ArrayList<T>();
        //连接数据库,执行sql语句
        try {
            //注册驱动
            Class.forName(configuration.getDriverClass());
            //获得链接
            conn = DriverManager.getConnection(configuration.getUrl(), configuration.getUsername(), configuration.getPassword());
            //获得执行者对象
            pst = conn.prepareStatement(sql);
            //获得结果集
            rs = pst.executeQuery();

            //获得元数据
            ResultSetMetaData metaData = rs.getMetaData();
            //字段数
            int columnCount = metaData.getColumnCount();
            //存放字段
            List<String> columnNames = new ArrayList<String>();

            //遍历字段数
            for (int i = 1; i <= columnCount; i++) {
                //获得对应的字段名
                String columnName = metaData.getColumnName(i);
                //放入到list集合
                columnNames.add(columnName);

            }

            //获得字节码文件
            Class obj = Class.forName(returnType);
            //解析结果集
            while (rs.next()) {
                //创建对象 相当于 new User();
                Object o = obj.newInstance();

                //获得User实体类中的所有方法
                Method[] methods = obj.getMethods();
                for (Method method : methods) {
                    //遍历字段
                    for (String columnName : columnNames) {
                        if (method.getName().equalsIgnoreCase("set" + columnName)) {
                            try {
                                method.invoke(o,rs.getObject(columnName));
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
                //放到对象集合中
                list.add((T) o);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }/*finally {
            relese();
        }*/
        return list;

    }

    public void release() {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }

        }
        if (pst != null) {
            try {
                pst.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }

        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }

        }

    }
}

 



4 编写SqlSessionFactory:创建SqlSession对象

         构造方法中传入InputStream对象

         提供返回值SqlSession 的openSession方法

         加载配置文件

public class SqlSessionFactory {
    private InputStream inputStream;
    //需要传入一个流对象
    public SqlSessionFactory(InputStream inputStream) {
        this.inputStream = inputStream;
    }

    //获取SqlSessiom 对象
    public SqlSession openSession() {
        Configuration configuration = new Configuration();
        loadConfiguration(configuration);
        return new SqlSessionImpl(configuration);
    }

    //读取配置文件
    private void loadConfiguration(Configuration cfg){

        SAXReader saxReader = new SAXReader();
        Document doc = null;
        Element rootElement = null;
        try {
            doc = saxReader.read(inputStream);
            rootElement = doc.getRootElement();
            List<Element> list = rootElement.selectNodes("//property");
            for (Element e : list) {
                //e.attributeValue(name) :获取指定的属性名的属性值
                //如果取出的name的属性值是driver,name就可以封装大搜Configuration中的driverClass属性中
                if(e.attributeValue("name").equalsIgnoreCase("driver")){
                    cfg.setDriverClass(e.attributeValue("value"));
                }
                if(e.attributeValue("name").equalsIgnoreCase("url")){
                    cfg.setUrl(e.attributeValue("value"));
                }
                if(e.attributeValue("name").equalsIgnoreCase("username")){
                    cfg.setUsername(e.attributeValue("value"));
                }
                if(e.attributeValue("name").equalsIgnoreCase("password")){
                    cfg.setPassword(e.attributeValue("value"));
                }


            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        //加载另一个配置文件

        Element mappers = rootElement.element("mappers");
        List<Element> mapperList = mappers.elements();
        for (Element e : mapperList) {
            String mapperPath = e.attributeValue("resource");
            loadMapperConfiguration(mapperPath, cfg);
        }

    }

    private void loadMapperConfiguration(String mapperPath, Configuration cfg) {
        InputStream inputStream = SqlSessionFactory.class.getClassLoader().getResourceAsStream(mapperPath);
        SAXReader saxReader = new SAXReader();
        try {
            Document doc = saxReader.read(inputStream);
            Element rootElement = doc.getRootElement();

            Map<String, Mapper> mapperMap = cfg.getMappers();

            String key = null;
            String namespace = rootElement.attributeValue("namespace");

            //获取根节点下所有的子节点
            List<Element> elements = rootElement.elements();
            for (Element element : elements) {
                String id = element.attributeValue("id");
                //com.itheima.mapper.UserDao.findAll
                key = namespace +"."+ id;
                // value:存储Mapper对象,返回值类型和sql语句
                Mapper mapper = new Mapper();
                //获取返回值类型
                String resultType = element.attributeValue("resultType");
                mapper.setResultType(resultType);
                //获取sql语句:getTextTrim{获取节点中的文本且去除两侧空白
                String sql = element.getTextTrim();
                mapper.setSql(sql);
                mapperMap.put(key,mapper);
            }



        } catch (DocumentException e) {
            e.printStackTrace();
        }

    }

}
View Code

 



5 编写SqlSessionFactoryBuilder

         三个重载的builder方法:无参,String path,InputStream is;

public class SqlSessionFactoryBuilder {

    public SqlSessionFactory builder(InputStream inputStream){
        return  new SqlSessionFactory(inputStream);
    }

    public SqlSessionFactory builder(String path){
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(path);
        return  new SqlSessionFactory(inputStream);
    }


    public SqlSessionFactory builder(){
        String path = "SqlMapConfig.xml";
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(path);
        return  new SqlSessionFactory(inputStream);
    }
}

 

把自定义的mybatis打成jar:install

 

测试自定义框架:
创建maven测试工程:
引入依赖:
  打成jar文件的自定义框架
  mysql驱动
  junit测试
<dependencies>
    <dependency>
        <groupId>com.review</groupId>
        <artifactId>mybatis_frame</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
</dependencies>

 




引入配置文件:自定义mybatis一样,将resource中的文件复制一份

创建User实体类:

public class User {
    private Integer id;
    private String name;
    private int age;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

 

测试类:
public class TestMybatis {
    SqlSessionFactory sessionFactory = null;
    @Before
    public void init(){
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("SqlMapConfig.xml");
        sessionFactory = new SqlSessionFactoryBuilder().builder(inputStream);
    }
    @Test
    public void FindAll(){
        SqlSession sqlSession = sessionFactory.openSession();
        List<User> userList = sqlSession.selectList("com.review.mapper.UserMapper.findAll");
        for (User user : userList) {
            System.out.println(user.getName());
        }
        sqlSession.close();

    }
}

 




 

 



 

posted on 2018-10-19 18:44  Cyan_W  阅读(1746)  评论(0编辑  收藏  举报

导航