前言

前两篇文章分别讲解了JDBC和Mybatis的基本知识,以及自定义持久层框架的设计思路,从这篇文章开始,我们正式来实现一个持久层框架。

新建一个项目

首先我们新建一个maven项目,将其命名为IPersistence,创建以下目录结构:

完成目录创建工作后,我们首先在pom.xml文件中引入相关依赖:

 1 <?xml version="1.0" encoding="UTF-8"?>
2 <project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <modelVersion>4.0.0</modelVersion>
6
7 <groupId>com.hardy</groupId>
8 <artifactId>IPersistence</artifactId>
9 <version>1.0-SNAPSHOT</version>
10
11 <properties>
12 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13 <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
14 <java.version>1.8</java.version>
15 <maven.compiler.source>1.8</maven.compiler.source>
16 <maven.compiler.target>1.8</maven.compiler.target>
17 </properties>
18
19 <dependencies>
20 <dependency>
21 <groupId>mysql</groupId>
22 <artifactId>mysql-connector-java</artifactId>
23 <version>8.0.19</version>
24 </dependency>
25 <dependency>
26 <groupId>c3p0</groupId>
27 <artifactId>c3p0</artifactId>
28 <version>0.9.1.2</version>
29 </dependency>
30 <dependency>
31 <groupId>log4j</groupId>
32 <artifactId>log4j</artifactId>
33 <version>1.2.16</version>
34 </dependency>
35 <dependency>
36 <groupId>junit</groupId>
37 <artifactId>junit</artifactId>
38 <version>4.12</version>
39 </dependency>
40 <dependency>
41 <groupId>dom4j</groupId>
42 <artifactId>dom4j</artifactId>
43 <version>1.6.1</version>
44 </dependency>
45 <dependency>
46 <groupId>jaxen</groupId>
47 <artifactId>jaxen</artifactId>
48 <version>1.1.6</version>
49 </dependency>
50 </dependencies>
51
52 </project>

下面,就可以开始正式的编码工作了。

读取配置文件

前面讲到了,第一步是要读取数据库配置的相关信息,以流的形式将其存放在内存中。那么首先我们就要在上图“io”包下创建一个Resources类,编写如下代码:

 1 package com.hardy.io;
2
3 import java.io.InputStream;
4
5 public class Resources {
6
7 // 根据配置文件的路径,将配置文件加载成字节输入流,存储在内存中
8 public static InputStream getResourceAsStream(String path) {
9 InputStream resourceAsStream = Resources.class.getClassLoader().getResourceAsStream(path);
10 return resourceAsStream;
11 }
12 }

这个类的调用方法十分简单,直接传递配置文件的路径名作为参数即可。

解析配置文件

创建容器对象

上面读取完配置文件的信息后,仅仅是将其以输入流的形式存放在内存中,而我们在项目开发过程中,需要调用到这些配置信息中的很多不同属性,如果每次都从内存中读取数据流,是很不方便的。

这里我们将配置文件分为核心配置文件(提供存放数据库核心配置的信息)和映射配置文件(提供sql配置信息(包括sql语句、参数类型和返回类型))。因此,我们可以在“pojo”包下创建两个容器对象类,分别命名为Configuration(存放核心配置信息)和MappedStatement(存放映射配置信息),编写如下代码:

 1 package com.hardy.pojo;
2
3 import javax.sql.DataSource;
4 import java.util.HashMap;
5 import java.util.Map;
6
7 /*
8 Configuration:
9 核心配置类,存放数据库基本信息
10 即sqlMapConfig.xml解析出来的内容
11 */
12 public class Configuration {
13
14 private DataSource dataSource;
15
16 /*
17 key: statementId value: 封装好的mappedStatement对象
18 */
19 Map<String, MappedStatement> mappedStatementMap = new HashMap<>();
20
21 public DataSource getDataSource() {
22 return dataSource;
23 }
24
25 public void setDataSource(DataSource dataSource) {
26 this.dataSource = dataSource;
27 }
28
29 public Map<String, MappedStatement> getMappedStatementMap() {
30 return mappedStatementMap;
31 }
32
33 public void setMappedStatementMap(Map<String, MappedStatement> mappedStatementMap) {
34 this.mappedStatementMap = mappedStatementMap;
35 }
36
37 }
 1 package com.hardy.pojo;
2
3 // Mapper.xml文件中一个select标签对应一个MappedStatement对象
4
5 /*
6 映射配置类:
7 存放sql语句、statement类型、输入参数java类型、输出参数java类型
8 即Mapper.xml解析出来的内容
9 */
10 public class MappedStatement {
11
12 // id标识
13 private String id;
14
15 // sql语句
16 private String sql;
17
18 // 输入参数值类型
19 private String parameterType;
20
21 // 返回结果集类型
22 private String resultType;
23
24 public String getId() {
25 return id;
26 }
27
28 public void setId(String id) {
29 this.id = id;
30 }
31
32 public String getSql() {
33 return sql;
34 }
35
36 public void setSql(String sql) {
37 this.sql = sql;
38 }
39
40 public String getParameterType() {
41 return parameterType;
42 }
43
44 public void setParameterType(String parameterType) {
45 this.parameterType = parameterType;
46 }
47
48 public String getResultType() {
49 return resultType;
50 }
51
52 public void setResultType(String resultType) {
53 this.resultType = resultType;
54 }
55
56 }

创建配置文件解析类

上面创建了存放配置文件信息的两个容器对象,但配置文件信息不会自动存放到容器对象中,因此我们还需要编写两个配置文件信息的解析类,可以在“config”包下分别创建XMLConfigBuilder和XMLMapperBuilder,编写以下代码:

 1 package com.hardy.config;
2
3 import com.hardy.io.Resources;
4 import com.hardy.pojo.Configuration;
5 import com.mchange.v2.c3p0.ComboPooledDataSource;
6 import org.dom4j.Document;
7 import org.dom4j.DocumentException;
8 import org.dom4j.Element;
9 import org.dom4j.io.SAXReader;
10
11 import java.beans.PropertyVetoException;
12 import java.io.InputStream;
13 import java.util.List;
14 import java.util.Properties;
15
16 public class XMLConfigBuilder {
17
18 private Configuration configuration;
19
20 public XMLConfigBuilder(Configuration configuration) {
21 this.configuration = new Configuration();
22 }
23
24 /*
25 该方法就是使用dom4j对配置文件进行解析,封装成Configuration
26 */
27 public Configuration parseConfiguration(InputStream inputStream) throws DocumentException, PropertyVetoException, ClassNotFoundException {
28
29 // 1、解析sqlMapConfig.xml
30 /*
31 * 这里需要注意一下:Document和Element等类用的都是org.dom4j库中的类,而不是javax.swing的
32 * 若编译器自动导入了javax.swing,需要手动删除,否则会报错
33 * */
34 Document document = new SAXReader().read(inputStream);
35 //<configuation>
36 Element rootElement = document.getRootElement();
37 List<Element> propertyElements =
38 rootElement.selectNodes("//property");
39 Properties properties = new Properties();
40 for (Element propertyElement : propertyElements) {
41 String name = propertyElement.attributeValue("name");
42 String value = propertyElement.attributeValue("value");
43 properties.setProperty(name,value);
44 }
45 // 连接池
46 ComboPooledDataSource comboPooledDataSource = new
47 ComboPooledDataSource();
48 comboPooledDataSource.setDriverClass(properties.getProperty("driverClass"));
49 comboPooledDataSource.setJdbcUrl(properties.getProperty("jdbcUrl"));
50 comboPooledDataSource.setUser(properties.getProperty("username"));
51 comboPooledDataSource.setPassword(properties.getProperty("password"));
52
53 // 填充configuration
54 configuration.setDataSource(comboPooledDataSource);
55
56 // 2、解析UserMapper.xml:拿到路径——获取字节输入流——使用dom4j进行解析
57 List<Element> mapperElements = rootElement.selectNodes("//mapper");
58 XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configuration);
59 for (Element element : mapperElements) {
60 String mapperPath = element.attributeValue("resource");
61 InputStream resourceAsStream = Resources.getResourceAsStream(mapperPath);
62 xmlMapperBuilder.parse(resourceAsStream);
63 }
64
65 return configuration;
66 }
67 }
 1 package com.hardy.config;
2
3 import com.hardy.pojo.Configuration;
4 import com.hardy.pojo.MappedStatement;
5 import com.hardy.pojo.SqlOperationEnum;
6 import org.dom4j.Document;
7 import org.dom4j.DocumentException;
8 import org.dom4j.Element;
9 import org.dom4j.io.SAXReader;
10
11 import java.io.InputStream;
12 import java.util.List;
13
14 public class XMLMapperBuilder {
15
16 private Configuration configuration;
17
18 public XMLMapperBuilder(Configuration configuration) {
19 this.configuration = configuration;
20 }
21
22 // 解析mapper.xml文件
23 public void parse(InputStream inputStream) throws DocumentException {
24 Document document = new SAXReader().read(inputStream);
25 Element rootElement = document.getRootElement();
26
27 String namespace = rootElement.attributeValue("namespace");
28
29 List<Element> elementList = rootElement.elements();
30 for (Element element : elementList) {
31 // id的值
32 String id = element.attributeValue("id");
33 // 输入参数类型
34 String parameterType = element.attributeValue("parameterType");
35 // 返回结果集类型
36 String resultType = element.attributeValue("resultType");
37 // sql语句
38 String sqlText = element.getTextTrim();
39
40 // 封装mappedStatement
41 MappedStatement mappedStatement = new MappedStatement();
42 mappedStatement.setId(id);
43 mappedStatement.setParameterType(parameterType);
44 mappedStatement.setResultType(resultType);
45 mappedStatement.setSql(sqlText);
46
47 // 获取sql操作名,并将其转换为大写
48 String elementName = element.getName();
49 mappedStatement.setSqlOperationEnum(SqlOperationEnum.valueOf(elementName.toUpperCase()));
50
51 // statementId
52 String key = namespace + "." + id;
53
54 //填充configuration
55 configuration.getMappedStatementMap().put(key, mappedStatement);
56
57 }
58 }
59
60 }

总结

本篇文章中,我们创建了IPersistence项目,做了一些必要的准备工作,然后完成了读取数据库配置信息及解析数据库配置信息的编码工作。

到这里,我们就可以调用我们自定义的工具来读取和解析数据库配置信息了,下一篇文章会讲解如何调用这些工具。

最新文章

  1. 通过jquery js 实现幻灯片切换轮播效果
  2. C#_基本类型
  3. awk(2)-模式(pattern)
  4. 《CoffeeScript应用开发》学习:第二章 编写第一个CoffeeScript应用程序
  5. 第53讲:Scala中结构类型实战详解
  6. VS对路径的访问被拒绝
  7. 使用Netty收发二进制报文问题记
  8. spring集成环境下的axis webservice的发布,调试
  9. LINQ(隐式表达式、lambda 表达式)
  10. 更新wix installer里的Guid
  11. iBatis 的删除一条记录
  12. eclipse-自动注释
  13. php之文件上传类代码
  14. 2. SpringMVC 上传文件操作
  15. c#(控制台应用程序)实现排序算法的研究总结
  16. 移动开发day1_过渡_2d转换_3d立体
  17. 虚拟机——虚拟机VMware Workstation 的.vmdk格式与VirtualBox 的.vdi格式相互转换
  18. TechnoSoftware OPCDA client(1.2.1) Error Codes
  19. Implementation of Message Receiver
  20. javascript 及 vue 中的变量前面的美元符号 $ 是什么意思

热门文章

  1. POJ_2387 Til the Cows Come Hom 【最短路】
  2. Django之cookie 与session组件
  3. python爬取三国演义的所有章节储存到本地文件中
  4. 得分(JAVA语言)
  5. apktool 回编译报错:No resource identifier found for attribute &#39;xxxxxx&#39; in package &#39;android&#39; W:
  6. Python基础(九):字典的使用
  7. 拇指记者深入Android公司,打探事件分发机制背后的秘密
  8. OO 第一单元
  9. HTML5与CSS3新增特性笔记
  10. k8s kubernetes 集群 证书更新操作