创建SqlMapConfig.xml 和Mapper.xml
SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<property value="com.mysql.jdbc.Driver"></property>
<property value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false"></property>
<property value="root"></property>
<property value="123456"></property>
<mapper resource="UserMapper.xml">
</mapper>
</configuration>
可以看到我们xml 中就配置了数据库的连接信息,以及mapper 一个索引。mybatis中的SqlMapConfig.xml 中还包含其他的标签,只是丰富了功能而已,所以我们只用最主要的。
mapper.xml
是每个类的sql 都会生成一个对应的mapper.xml 。我们这里就用User 类来说吧,所以我们就创建一个UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<mapper namespace="cn.quellanan.dao.UserDao">
<select resultType="cn.quellanan.pojo.User">
select * from user
</select>
<select resultType="cn.quellanan.pojo.User" paramType="cn.quellanan.pojo.User">
select * from user where username=#{username}
</select>
</mapper>
可以看到有点mybatis 里面文件的味道,有namespace表示命名空间,id 唯一标识,resultType 返回结果集的类型,paramType 参数的类型。
我们使用端先创建到这,主要是两个配置文件,我们接下来看看框架端是怎么实现的。
加油哈哈。
框架端实现
框架端,我们按照上面的设计思路一步一步来。
获取配置
怎么样获取配置文件呢?我们可以使用JDK自带自带的类Resources加载器来获取文件。我们创建一个自定义Resource类来封装一下:
import java.io.InputStream;
public class Resources {
public static InputStream getResources(String path){
//使用系统自带的类Resources加载器来获取文件。
return Resources.class.getClassLoader().getResourceAsStream(path);
}
}
这样通过传入路径,就可以获取到对应的文件流啦。
解析配置文件
上面获取到了SqlMapConfig.xml 配置文件,我们现在来解析它。
不过在此之前,我们需要做一点准备工作,就是解析的内存放到什么地方?
所以我们来创建两个实体类Mapper 和Configuration。
Mapper
Mapper 实体类用来存放使用端写的mapper.xml 文件的内容,我们前面说了里面有.id、sql、resultType 和paramType .所以我们创建的Mapper实体如下:
public class Mapper {
private String id;
private Class<?> resultType;
private Class<?> parmType;
private String sql;
//getter()和setter()方法
}
这里我们为什么不添加namespace 的值呢?
聪明的你肯定发现了,因为mapper里面这些属性表明每个sql 都对应一个mapper,而namespace 是一个命名空间,算是sql 的上一层,所以在mapper中暂时使用不到,就没有添加了。
Configuration
Configuration 实体用来保存SqlMapConfig 中的信息。所以需要保存数据库连接,我们这里直接用JDK提供的 DataSource。还有一个就是mapper 的信息。每个mapper 有自己的标识,所以这里采用hashMap来存储。如下:
public class Configuration {
private DataSource dataSource;
HashMap <String,Mapper> mapperMap=new HashMap<>();
//getter()和setter方法
}
XmlMapperBuilder
做好了上面的准备工作,我们先来解析mapper 吧。我们创建一个XmlMapperBuilder 类来解析。通过dom4j 的工具类来解析XML 文件。我这里用的dom4j 依赖为:
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
</dependency>
思路:
1、获取文件流,转成document。
2、获取根节点,也就是mapper。获取根节点的namespace属性值
3、获取select 节点,获取其id,sql,resultType,paramType
4、将select 节点的属性封装到Mapper 实体类中。
5、同理获取update/insert/delete 节点的属性值封装到Mapper 中
6、通过namespace.id 生成key 值将mapper对象保存到Configuration实体中的HashMap 中。
7、返回 Configuration实体
代码如下:
public class XmlMapperBuilder {
private Configuration configuration;
public XmlMapperBuilder(Configuration configuration){
this.configuration=configuration;
}
public Configuration loadXmlMapper(InputStream in) throws DocumentException, ClassNotFoundException {
Document document=new SAXReader().read(in);
Element rootElement=document.getRootElement();
String namespace=rootElement.attributeValue("namespace");
List<Node> list=rootElement.selectNodes("//select");
for (int i = 0; i < list.size(); i++) {
Mapper mapper=new Mapper();
Element element= (Element) list.get(i);
String id=element.attributeValue("id");
mapper.setId(id);
String paramType = element.attributeValue("paramType");
if(paramType!=null && !paramType.isEmpty()){
mapper.setParmType(Class.forName(paramType));
}
String resultType = element.attributeValue("resultType");
if (resultType != null && !resultType.isEmpty()) {
mapper.setResultType(Class.forName(resultType));
}
mapper.setSql(element.getTextTrim());
String key=namespace+"."+id;
configuration.getMapperMap().put(key,mapper);
}
return configuration;
}
}
上面我只解析了select 标签。大家可以解析对应insert/delete/uupdate 标签,操作都是一样的。
XmlConfigBuilder