04-08手写持久层框架——核心配置和映射配置文件解析
学习资料视频来源:https://www.bilibili.com/video/BV1R14y1W7yS
文章目录
- 1. 项目介绍
- 1.1 项目结构
- 1.2 项目依赖
- (1) ipersistent依赖
- (2) ipersistent-test依赖
- 1.3 配置文件
- (1) 核心配置文件
- (2) 映射配置文件
- 2. 核心源码类
- 2.1 ipersistent
- Resources
- Configuration
- MappedStatement
- XMLConfigBuilder
- XMLMapperBuilder
- SqlSessionFactoryBuilder
- SqlSessionFactory
- DefaultSqlSessionFactory
- 2.2 ipersistent-test
- 测试类
1. 项目介绍
1.1 项目结构
项目分为2个模块,ipersistent 和ipersistent-test。ipersistent为框架,ipersistent-test为框架使用端,ipersistent-test依赖ipersistent。视频里是使用maven管理项目,我这里是使用gradle管理项目。目录结构如下:
1.2 项目依赖
(1) ipersistent依赖
plugins {
id 'java-library'
}
group = 'com.mql'
repositories {
maven {
url 'https://maven.aliyun.com/nexus/content/groups/public/'
}
mavenCentral()
}
dependencies {
testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation 'org.junit.jupiter:junit-jupiter'
// 引入dom4j依赖,用于解析xml文件
api 'dom4j:dom4j:1.6.1'
runtimeOnly 'mysql:mysql-connector-java:5.1.40'
//阿里德鲁伊数据库连接池
implementation ('com.alibaba:druid:1.2.8')
implementation 'jaxen:jaxen:1.2.0'
annotationProcessor 'org.projectlombok:lombok:1.18.20'
compileOnly 'org.projectlombok:lombok:1.18.20'
}
(2) ipersistent-test依赖
plugins {
id 'java'
}
group = 'com.mql'
repositories {
mavenCentral()
}
dependencies {
testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation 'org.junit.jupiter:junit-jupiter'
// 引用ipersistent
implementation project(':ipersistent')
implementation 'org.apache.logging.log4j:log4j-core:2.14.1'
implementation 'org.apache.logging.log4j:log4j-api:2.14.1'
}
test {
useJUnitPlatform()
}
1.3 配置文件
核心配置文件映射配置文件,都是在ipersistent-test提供。
(1) 核心配置文件
<configuration>
<!-- 数据源配置 -->
<datasource>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</datasource>
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
(2) 映射配置文件
<mapper namespace="user">
<!-- 唯一标识: namespace.id-->
<!-- 查询所有用户 -->
<select id="selectList" resultType="com.mqlyes.pojo.User">
select * from user
</select>
<!-- 按条件查询用户 -->
<!-- -->
<select id="selectOne" resultType="com.mqlyes.pojo.User" parameterType="com.mqlyes.pojo.User">
select * from user where id = #{id} and username = #{username}
</select>
</mapper>
2. 核心源码类
2.1 ipersistent
Resources
作用:根据路径,加载配置文件,并转换成字节流,比较简单。
public class Resources {
/**
* 根据配置文件的路径加载配置文件存到内存中
* @param path
* @return
*/
public static InputStream getResource(String path) {
return Resources.class.getClassLoader().getResourceAsStream(path);
}
}
Configuration
作用:Configuration存储核心配置和映射配置文件解析出的配置信息。分别对应dataSource和mappedStatementMap。
/**
* 存数据库配置信息 从sqlMapper.xml中解析出的东西
*/
public class Configuration {
// 数据源对象
private DataSource dataSource;
// key为 statementID
private Map<String, MappedStatement> mappedStatementMap = new HashMap<>();
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public Map<String, MappedStatement> getMappedStatementMap() {
return mappedStatementMap;
}
public void setMappedStatementMap(Map<String, MappedStatement> mappedStatementMap) {
this.mappedStatementMap = mappedStatementMap;
}
}
MappedStatement
作用:存储映射配置文件中解析出信息,一个MappedStatement对应一个xxxmapper.xml文件
public class MappedStatement {
// 唯一标识
private String StatementID;
private String resultType;
private String parameterType;
private String sql;
public String getStatementID() {
return StatementID;
}
public void setStatementID(String statementID) {
StatementID = statementID;
}
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
public String getParameterType() {
return parameterType;
}
public void setParameterType(String parameterType) {
this.parameterType = parameterType;
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
}
XMLConfigBuilder
作用:先解析核心配置文件中数据库配置信息,封装成Datasource。再解析mapper文件所有路径
调用XMLMapperBuilder解析mapper文件,并封装进MappedStatement。解析二者的过程中,把Datasource和MappedStatement封装进Configuration。
public class XMLConfigBuilder {
private Configuration configuration;
public XMLConfigBuilder() {
this.configuration = new Configuration();
}
/**
* 解析配置文件 封装到Configuration中
*
* @param inputStream
* @return
*/
public Configuration parse(InputStream inputStream) throws DocumentException {
Document document = new SAXReader().read(inputStream);
Element rootElement = document.getRootElement();
List<Element> list = rootElement.selectNodes("//property");
Properties properties = new Properties();
for (Element element : list) {
String name = element.attributeValue("name");
String value = element.attributeValue("value");
properties.put(name, value);
}
// 创建数据源对象
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(properties.getProperty("driver"));
druidDataSource.setUrl(properties.getProperty("url"));
druidDataSource.setUsername(properties.getProperty("username"));
druidDataSource.setPassword(properties.getProperty("password"));
configuration.setDataSource(druidDataSource);
// 获取映射配置文件路径
List<Element> mapperList = rootElement.selectNodes("//mapper");
for (Element element : mapperList) {
String mapperPath = element.attributeValue("resource");
InputStream resource = Resources.getResource(mapperPath);
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configuration);
xmlMapperBuilder.parse(resource);
}
return configuration;
}
}
XMLMapperBuilder
public class XMLMapperBuilder {
private Configuration configuration;
public XMLMapperBuilder(Configuration configuration) {
this.configuration = configuration;
}
public void parse(InputStream inputStream) throws DocumentException {
Document document = new SAXReader().read(inputStream);
Element rootElement = document.getRootElement();
String namespace = rootElement.attributeValue("namespace");
List<Element> elements = rootElement.selectNodes("//select");
for (Element element : elements) {
String id = element.attributeValue("id");
String resultType = element.attributeValue("resultType");
String parameterType = element.attributeValue("parameterType");
String sql = element.getTextTrim();
MappedStatement mappedStatement = new MappedStatement();
mappedStatement.setStatementID(namespace + "." + id);
mappedStatement.setSql(sql);
mappedStatement.setResultType(resultType);
mappedStatement.setParameterType(parameterType);
configuration.getMappedStatementMap().put(mappedStatement.getStatementID(), mappedStatement);
}
}
}
SqlSessionFactoryBuilder
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(InputStream inputStream) throws DocumentException {
XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder();
Configuration configuration = xmlConfigBuilder.parse(inputStream);
// 创建SqlSessionFactory工厂对想
DefaultSqlSessionFactory defaultSqlSessionFactory = new DefaultSqlSessionFactory(configuration);
return defaultSqlSessionFactory;
}
}
SqlSessionFactory
public interface SqlSessionFactory {
}
DefaultSqlSessionFactory
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
}
2.2 ipersistent-test
测试类
使用端目前只有一个测试类,看返回结果中的configuration对象信息是否完整。
public class IpersistentTest {
@Test
public void test1() throws Exception {
InputStream resource = Resources.getResource("sqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resource);
System.out.println(build);
}
}