将昨天的例子:SSM框架(一):mybatis简单介绍和入门案例分析,我们移除pom.xml中的mybatis相关的坐标后,自定义一个mabatis框架,实现 "select * from user" 的功能。
最终我们的目录结构如下:
src
├─main
│ ├─java
│ │ └─cn
│ │ └─figo
│ │ ├─dao
│ │ ├─domain
│ │ └─mybatis
│ │ ├─annotation
│ │ ├─cfg
│ │ ├─io
│ │ ├─sqlsession
│ │ │ ├─defaults
│ │ │ └─proxy
│ │ └─utils
│ └─resources
│ └─cn
│ └─figo
│ └─dao
└─test
└─java
└─cn
└─figo
└─test
当通过注解配置持久化层后并修改主配置文件中的mapper属性为class后,我们可以通过自定义框架的注解进行查询:
![1b1e2113d7bb8d0298b51a59e8ddf7a6.png](https://i-blog.csdnimg.cn/blog_migrate/5b371a3da53de7125c46e7692ed96f28.jpeg)
![cba817d9af08ee34d3a770f56870ae95.png](https://i-blog.csdnimg.cn/blog_migrate/5c891878f4542aa9e9ac01ac11910f3e.jpeg)
最终输出如下:
![b55f2bfc163d9cfc87416588f884756a.png](https://i-blog.csdnimg.cn/blog_migrate/720d71175a2ce4e4b2084cd952243fd6.jpeg)
当通过xml配置持久化层后并修改主配置文件中的mapper属性为resource后,我们可以通过自定义框架的注解进行查询:
![6bdb42e1f9b300a393c87c1470a019e4.png](https://i-blog.csdnimg.cn/blog_migrate/3ae2a6570828fcf47a67c233c5828e1b.jpeg)
![156690114dbdd622b994c3060998166f.png](https://i-blog.csdnimg.cn/blog_migrate/bc22b630d7ae61e93c81e35bd65ce6aa.jpeg)
最终输出如下:
![3c18e3e56b2b44cfd38c665fc6943ac8.png](https://i-blog.csdnimg.cn/blog_migrate/3889d049f4a8b26895f72fa3bb2abbf4.jpeg)
我们定义的mybatis中的所有类、接口、注解如下图所示:
![db760ebc736310ca453e6673d3c8a688.png](https://i-blog.csdnimg.cn/blog_migrate/2105b427c954aa150df2c4d1b8074b3d.jpeg)
1、使用类加载器读取配置文件的类:Resources
package cn.figo.mybatis.io;
import java.io.InputStream;
/**
* @Author Figo
* @Date 2019/10/28 21:34
* 使用类加载器读取配置文件的类
*/
public class Resources {
/**
* 根据传入的参数,获取一个字节输入流
* @param filePath
* @return
*/
public static InputStream getResourceAsStream(String filePath){
return Resources.class.getClassLoader().getResourceAsStream(filePath);
}
}
2、用于保存数据库和映射配置信息的实体类:Configuration
package cn.figo.mybatis.cfg;
import java.util.HashMap;
import java.util.Map;
/**
* @Author Figo
* @Date 2019/10/28 21:58
* 自定义mybatis的配置类
*/
public class Configuration {
private String driver;
private String url;
private String username;
private String password;
// 用于存放从映射xml中读取的 SQL语句和结果类型的全限定类名,key为 dao的全限定类名.方法名
private Map<String,Mapper> mappers = new HashMap<String,Mapper>();
public Map<String, Mapper> getMappers() {
return mappers;
}
//此处需要使用追加的方式
public void setMappers(Map<String, Mapper> mappers) {
this.mappers.putAll(mappers);
}
// 其他 getter 和 setter 省略
}
3、用于保存sql语句和封装数据全限定类名的映射信息的实体类:Mapper
package cn.figo.mybatis.cfg;
/**
* @Author Figo
* @Date 2019/10/28 22:01
* 用于封装执行的SQL语句和结果类型的全限定类名
*/
public class Mapper {
//SQL
private String queryString;
//实体类的全限定类名
private String resultType;
// getter 和 setter 省略
}
4、构建工厂的构建者类:SqlSessionFactoryBuilder
package cn.figo.mybatis.sqlsession;
import cn.figo.mybatis.cfg.Configuration;
import cn.figo.mybatis.sqlsession.defaults.DefaultSqlSessionFactory;
import cn.figo.mybatis.utils.XMLConfigBuilder;
import java.io.InputStream;
/**
* @Author Figo
* @Date 2019/10/28 21:40
* 用于创建一个SqlSessionFactory对象
*/
public class SqlSessionFactoryBuilder {
/**
* 根据参数的字节输入流来构建一个SqlSessionFactory工厂
* @param config
* @return
*/
public SqlSessionFactory build(InputStream config){
Configuration cfg = XMLConfigBuilder.loadConfiguration(config);
return new DefaultSqlSessionFactory(cfg);
}
}
5、工厂接口和实现类:SqlSessionFactory 、DefaultSqlSessionFactory
package cn.figo.mybatis.sqlsession.defaults;
import cn.figo.mybatis.cfg.Configuration;
import cn.figo.mybatis.sqlsession.SqlSession;
import cn.figo.mybatis.sqlsession.SqlSessionFactory;
/**
* @Author Figo
* @Date 2019/10/28 22:19
* SqlSessionFactory接口的实现类
*/
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private Configuration cfg;
public DefaultSqlSessionFactory(Configuration cfg){
this.cfg = cfg;
}
/**
* 用于创建一个新的操作数据库对象
* @return
*/
@Override
public SqlSession openSession() {
return new DefaultSqlSession(cfg);
}
}
6、用于创建代理对象的接口和实现类:SqlSession、DefaultSqlSession
package cn.figo.mybatis.sqlsession.defaults;
import cn.figo.mybatis.cfg.Configuration;
import cn.figo.mybatis.sqlsession.SqlSession;
import cn.figo.mybatis.sqlsession.proxy.MapperProxy;
import cn.figo.mybatis.utils.DataSourceUtil;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;
/**
* @Author Figo
* @Date 2019/10/28 22:24
* SqlSession接口的实现类
*/
public class DefaultSqlSession implements SqlSession {
// Configuration 对象中包括数据库信息和映射信息
private Configuration cfg;
private Connection connection;
public DefaultSqlSession(Configuration cfg){
this.cfg = cfg;
connection = DataSourceUtil.getConnection(cfg);
}
/**
* 用于创建代理对象
* @param daoInterfaceClass dao的接口字节码
* @param <T>
* @return
*/
@Override
public <T> T getMapper(Class<T> daoInterfaceClass) {
Class[] x = new Class[]{daoInterfaceClass};
return (T)Proxy.newProxyInstance(daoInterfaceClass.getClassLoader(),
new Class[]{daoInterfaceClass},new MapperProxy(cfg.getMappers(),connection));
}
/**
* 用于释放资源
*/
@Override
public void close() {
if (connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
7、用于创建代理对象时增强功能InvocationHandler实现类:MapperProxy
package cn.figo.mybatis.sqlsession.proxy;
import cn.figo.mybatis.cfg.Mapper;
import cn.figo.mybatis.utils.Executor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.Map;
/**
* @Author Figo
* @Date 2019/10/28 22:31
* 用于创建代理对象时增强功能
*/
public class MapperProxy implements InvocationHandler {
// map的key是全限定类名+方法名
private Map<String, Mapper> mappers;
private Connection conn;
public MapperProxy(Map<String,Mapper> mappers,Connection conn){
this.mappers = mappers;
this.conn = conn;
}
/**
* 用于对方法进行增强的,我们的增强其实就是调用selectList方法
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
String className = method.getDeclaringClass().getName();
String key = className + "." + methodName;
Mapper mapper = mappers.get(key);
if (mapper == null){
throw new IllegalArgumentException("传入的参数有误");
}
return new Executor().selectList(mapper,conn);
}
}
8、用于解析配置文件的工具类:XMLConfigBuilder
9、用于获取数据库连接的工具类:DataSourceUtil
10、用于执行SQL语句,并且封装结果集的工具类:Executor
其中8、9、10工具类省略,push至github
YourFigo/javaSSMgithub.com![c640a72f8289c81c02e2811e29d8aea9.png](https://i-blog.csdnimg.cn/blog_migrate/6d508f25e7490ca27a993889fda57596.jpeg)