项目三层架构介绍
三层架构有哪些
- 表示层
- 业务层
- 数据访问层
三层架构好处
- 降低层与层之间的耦合性。
- 提高软件的可维护性。
- 提升软件的可扩展性。
框架概述
什么是框架
框架是别人写好的代码,是对常见功能的封装,是一个半成品。在框架的基础上开发出成品的软件。
假如要造一辆马车,在没有零件的情况下,需要自己去伐木,去把木头做成木板,木棍,然后做成轮子,门,等部件,然后组装起来,很麻烦。框架就相当于现成的轮子,门等部件。只需要拿过来使用即可。
常见框架如:Spring,SpringMVC,Mybatis,JdbcTemplate,Bootstrap等等。
框架解决的问题
提升了开发效率
企业项目中使用框架,程序员不再需要重复造轮子,只需要专注实现业务需求,提升了开发效率。
提升了系统稳定性
一个成熟的框架,经过了在众多企业项目中的验证使用,稳定性有保障。
分层开发下常见框架
ssm就是3个框架:Spring、SpringMVC、MyBatis
持久层框架
MyBatis是一款优秀的持久层框架,MyBatis 避免了几乎所有的 JDBC代码和手动设置参数以及获取结果集。
关于持久层的框架,还有一个封装程度更高的框架(hibernate)。该框架相对比较重量级,以及其它各个方面的原因,目前流行程度下降了很多,企业项目中用的越来越少了。
表现层框架
SpringMVC是一种基于Java,实现了Web MVC设计模式,将Web层进行解耦。SpringMVC可以简化我们日常Web开发。
整合的框架
Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。让开发变的更简单。
mybatis框架介绍和下载
mybatis框架介绍
mybatis是Apache软件基金会下的一个开源项目,前身是iBatis框架。2010年这个项目改名为mybatis。是一个持久层框架
mybatis的优点
- 简单易学:不需要关注JDBC的资源获取和释放,配置几个SQL映射文件即可。
- 解除SQL与程序代码的耦合:SQL语句和代码分离,提高了可维护性。
官方网站
http://www.mybatis.org/mybatis-3/
框架包下载
连接到github地址:https://github.com/mybatis/mybatis-3/releases
mybatis入门示例(环境的搭建)
需求
利用mybatis框架,从MySQL中查询所有的用户
用户表SQL
CREATE TABLE USER (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(20) NOT NULL,
birthday DATE,
sex CHAR(1) DEFAULT '男',
address VARCHAR(50)
);
INSERT INTO USER VALUES (NULL, '小明','1996-10-24','男','香港');
SELECT * FROM USER;
mybatis开发步骤
- 创建新模块
- 加入mybatis和数据库驱动jar包
- 编写用户实体类(User)
- 准备核心配置文件:sqlMapConfig.xml
- 编写用户 dao 接口(UserMapper)
- 编写用户 dao 接口映射文件(UserMapper.xml)
- 编写测试代码
环境搭建
-
创建模块:mybatis_demo
-
加入mybatis相关jar包:在模块下新建lib文件夹,复制mybatis框架jar包到lib文件夹下
mybatis 框架包
mysql 数据库驱动包
log4j 日志包 -
编写用户实体类(User)
/** 用户实体类对象 */ public class User { private Integer id; private String username; private Date birthday; private String sex; private String address; // 省略构造方法/getter/setter/toString }
配置文件
复制log4j.properties到 src 下
### 设置Logger输出级别和输出目的地 ###
log4j.rootLogger=debug, stdout
### 把日志信息输出到控制台 ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
Mybatis配置文件分类
mybatis为了灵活,将数据库相关数据和SQL语句写到XML配置文件中。
- 核心配置文件:配置数据库的连接url,账号,密码,一般核心配置文件的名称:sqlMapConfig.xml
- 接口的映射文件:配置要执行的SQL语句,一般名称: XxxMapper.xml
核心配置文件sqlMapConfig.xml
复制mybatis框架模板\sqlMapConfig.xml到src下,说明:它是mybatis框架的核心配置文件,mybatis就是靠这些信息来运行的。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--可以配置多个环境,可以访问不同种类的数据库:mysql, oracle-->
<environments default="default">
<!-- 其中的一个配置环境,这个配置方案的唯一标识 -->
<environment id="default">
<!--
指定事务管理器的类型:
JDBC:使用JDBC来管理事务
-->
<transactionManager type="JDBC"/>
<!--
数据源的类型:
1. POOLED:使用mybatis创建的连接池
2. UNPOOLED:不使用连接池,每次都创建和关闭连接
-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--加载接口映射文件-->
<mappers>
<mapper resource="接口映射文件位置"/>
</mappers>
</configuration>
接口映射文件UserMapper.xml
UserMapper接口的创建
创建com.xxx.dao包,创建UserMapper接口。编写查询所有用户的方法:List<User> findAllUsers();
/**
定义DAO中方法
*/
public interface UserMapper {
/**
查询所有的用户
*/
List<User> findAllUsers();
}
UserMapper.xml映射文件
在com.xxx.dao包中创建UserMapper.xml映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace属性:指定DAO接口中类全名-->
<mapper namespace="com.xxx.dao.UserMapper">
<!--
id:接口中方法的名字
resultType: 返回的数据类型,如果是集合类型,这里应该指定集合中元素的类型全名
文本:SQL语句
-->
<select id="findAllUsers" resultType="com.xxx.entity.User">
select * from user;
</select>
</mapper>
核心配置文件sqlMapConfig.xml
在src/sqlMapConfig.xml添加UserMapper.xml的映射
<!--加载其它的实体映射文件-->
<mappers>
<!--指定要加载的映射文件-->
<mapper resource="com/xxx/dao/UserMapper.xml"/>
</mappers>
测试类
三大对象
- SqlSessionFactoryBuilder:负责构建SqlSessionFactory
- SqlSessionFactory:创建SqlSession实例的工厂
- SqlSession:用于执行SQL操作的对象
编写代码流程
- 创建SqlSessionFactoryBuilder对象
- 得到会话工厂SqlSessionFactory类
- 得到SqlSession对象
- 通过SqlSession对象得到Mapper接口的代理对象
- Mapper接口的代理对象执行数据库的查询操作
示例代码
public class TestUserMapper {
public static void main(String[] args) throws IOException {
// 1.得到核心配置文件的输入流
InputStream in = TestMybatis.class.getResourceAsStream("/sqlMapConfig.xml");
// 2.创建会话工厂建造类
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 3.创建会话工厂
SqlSessionFactory factory = builder.build(inputStream);
// 4.通过会话工厂得到会话对象
SqlSession session = factory.openSession();
// 5.由会话对象得到DAO接口的对象,由mybatis生成接口的代理对象。
UserMapper userMapper = session.getMapper(UserMapper.class);
// 6.实现CRUD
List<User> userList = userMapper.findAllUsers();
for (User user : userList) {
System.out.println(user);
}
// 7.释放资源
session.close();
}
}
注:UserMapper的对象是由mybatis生成的接口代理对象
自定义mybatis
编写SqlSession类
- 新建
com.xxx.mybatis
包 - 在
com.xxx.mybatis
创建SqlSession类 SqlSession
中编写getMapper
获取Mapper
的代理对象
SqlSession sqlSession = new SqlSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
import java.lang.reflect.Proxy;
// SqlSession的作用是获取Mapper的代理对象
public class SqlSession {
/*
Object newProxyInstance(ClassLoader loader, 类加载器
Class<?>[] interfaces, 接口
InvocationHandler h) 调用处理器
*/
public <T> T getMapper(Class<T> type) {
// 生成参数的代理对象
return (T)Proxy.newProxyInstance(
this.getClass().getClassLoader(),
new Class[] {type},
new MyInvocationHandler()
);
}
}
Mapper
的代理对象是用来执行SQL语句的
List<User> users = userMapper.findAllUsers();
先固定写一些数据
public class MyInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 返回查询数据
ArrayList<User> list = new ArrayList<>();
list.add(new User(2, "小明", new Date(100), "男", "天津"));
list.add(new User(3, "小红", new Date(200), "女", "福建"));
return list;
}
}
解析sqlMapConfig.xml核心配置文件
实现步骤
- 使用dom4j解析sqlMapConfig.xml文件
- 获取数据库相关信息
- 创建Druid连接池
Configuration代码
public class Configuration {
// 数据源
private DataSource dataSource;
public Configuration() {
// 加载sqlMapConfig.xml中的数据库链接参数
// 得到输入流
InputStream in = Configuration.class.getResourceAsStream("/sqlMapConfig.xml");
// DOM解析
// 得到文档对象
SAXReader saxReader = new SAXReader();
try {
Document document = saxReader.read(in);
// 加载数据库连接参数
// 获得数据库连接字符串:driver
Element driverElement = (Element) document.selectSingleNode("//property[@name='driver']");
driver = driverElement.attributeValue("value");
// 获得数据库连接字符串:url
Element urlElement = (Element) document.selectSingleNode("//property[@name='url']");
url = urlElement.attributeValue("value");
// 获得数据库连接字符串:username
Element usernameElement = (Element) document.selectSingleNode("//property[@name='username']");
username = usernameElement.attributeValue("value");
// 获得数据库连接字符串:password
Element passwordElement = (Element) document.selectSingleNode("//property[@name='username']");
password = passwordElement.attributeValue("value");
// 创建数据源
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
this.dataSource = ds;
// TODO:加载接口映射文件
} catch (DocumentException e) {
e.printStackTrace();
}
}
}
设计Mapper类
步骤
- 创建Mapper实体类:包含4个属性:namespace,id,resultType,sql
- 生成get和set方法
代码
/**
用来封装映射文件的实体类
一个Mapper对象代表一条要操作的查询语句对象
*/
public class Mapper {
private String namespace; //接口类全名
private String id; //接口中方法名
private String resultType; //封装的数据类型
private String sql; //要执行的SQL语句
// 省略getter/setter
}
写Configuration解析Mapper实体类映射文件
实现步骤
-
读取mapper中的resource属性值
-
解析resource对应的XML文件,得到namespace,id,resultType,sql的值
-
封装成Mapper对象,保存到Map集合中
示例代码
public class Configuration {
// 数据源
private DataSource dataSource;
// 封装其它的映射文件中属性
private Map<String, Mapper> mappers = new HashMap<>();
public Configuration() {
// 加载sqlMapConfig.xml中的数据库链接参数
// 得到输入流
InputStream in = Configuration.class.getResourceAsStream("/sqlMapConfig.xml");
// DOM解析
// 得到文档对象
SAXReader saxReader = new SAXReader();
try {
Document document = saxReader.read(in);
// 加载数据库连接参数
// 获得数据库连接字符串:driver
Element driverElement = (Element) document.selectSingleNode("//property[@name='driver']");
driver = driverElement.attributeValue("value");
// 获得数据库连接字符串:url
Element urlElement = (Element) document.selectSingleNode("//property[@name='url']");
url = urlElement.attributeValue("value");
// 获得数据库连接字符串:username
Element usernameElement = (Element) document.selectSingleNode("//property[@name='username']");
username = usernameElement.attributeValue("value");
// 获得数据库连接字符串:password
Element passwordElement = (Element) document.selectSingleNode("//property[@name='username']");
password = passwordElement.attributeValue("value");
// 创建数据源
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
this.dataSource = ds;
// 加载接口映射文件
Element mapperElement = (Element) document.selectSingleNode("//mapper[@resource]");
// com/xxx/dao/UserMapper.xml
String resource = mapperElement.attributeValue("resource");
InputStream mapperIn = Configuration.class.getResourceAsStream("/" + resource);
// DOM解析
SAXReader reader = new SAXReader();
Document mapperDocument = reader.read(mapperIn);
// rootElement:<mapper namespace="com.xxx.dao.UserMapper">
Element rootElement = mapperDocument.getRootElement();
String namespace = rootElement.attributeValue("namespace");
/* <select id="findAllUsers" resultType="com.xxx.entity.User">
select * from user;
</select>*/
Element select = rootElement.element("select");
// 获得id属性值
String id = select.attributeValue("id");
// 获得返回值类型
String resultType = select.attributeValue("resultType");
// 获得标签体内容:sql语句字符串
String sql = select.getTextTrim();
// 创建Mapper对象
Mapper mapper = new Mapper(namespace, id, resultType, sql);
// 将Mapper对象添加到集合mappers中
mappers.put(namespace + "." + id, mapper);
} catch (DocumentException e) {
e.printStackTrace();
}
}
// 省略getter/setter
}
封装查询的结果集
步骤
-
通过连接池得到连接对象
-
使用JDBC访问数据库执行SQL语句
-
处理结果集中的每条记录
-
使用反射将每条记录封装成一个对象
-
关闭资源
代码
// Mapper的代理对象是用来执行SQL语句的
public class MyInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 去数据库查询数据返回
String methodName = method.getName();
// 得到这个方法声明是的Class对象
String className = method.getDeclaringClass().getName();// 得到类全名
String allName = className + "." + methodName;
System.out.println("allName = " + allName);
// 通过键找到值,mapper对象
Configuration configuration = new Configuration();
Mapper mapper = configuration.getMappers().get(allName);
String sql = mapper.getSql();
String resultTypeString = mapper.getResultType(); // com.xxx.entity.User
Class<?> resultType = Class.forName(resultTypeString);
// 执行SQL
// 1.通过连接池得到连接对象
DruidDataSource dds = configuration.getDds();
Connection conn = dds.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
// 2.使用JDBC访问数据库执行SQL语句
ResultSet rs = pstmt.executeQuery();
// 3.处理结果集中的每条记录
ArrayList list = new ArrayList();
// 4.使用反射将每条记录封装成一个对象
while (rs.next()) {
// 1.创建对象
Object user = resultType.newInstance();
Field[] fields = resultType.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
// 获取成员变量名
String name = field.getName();
// 获取字段值
Object value = rs.getObject(name);
field.set(user, value);
}
// 5.将对象添加到集合中
list.add(user);
}
// 6.关闭资源
rs.close();
pstmt.close();
conn.close();
return list;
}
}