一. 什么是三层架构
三层架构来源于后端开发的一种分层的思想。
三层架构(3-tier architecture)通常意义上的三层架构就是将整个业务应用划分为:界面层(User Interface layer)、业务逻辑层(Business Logic Layer)、数据访问层(Data access layer)。区分层次的目的即为了“高内聚低耦合”的思想。在软件体系架构设计中,分层式结构是最常见,也是最重要的一种结构。微软推荐的分层式结构一般分为三层,从下至上分别为:数据访问层、业务逻辑层(又或称为领域层)、表示层。
1. 各层的作用
- 表示层:主要是指与用户交互的界面。用于接收用户输入的数据和显示处理后用户需要的数 据。
- 业务逻辑层:UI层和DAL层之间的桥梁。实现业务逻辑。业务逻辑具体包含:验证、计算、业务规则等等。
- 数据访问层:与数据库打交道。主要实现对数据的增、删、改、查。将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库。
2. 三层间的联系 -- 实体层
** Entity(实体层):**它不属于三层中的任何一层,但是它是必不可少的一层。
(1)Entity在三层架构中的作用:
- (1)实现面向对象思想中的"封装";
- (2)贯穿于三层,在三层之间传递数据;(注:确切的说实体层贯穿于三层之间,来连接三层)
- (3)对于初学者来说,可以这样理解:每张数据表对应一个实体,即每个数据表中的字段对应实体中的属性(注:当然,事实上不是这样。为什么?1>,可能我们需要的实体在数据表对应的实体中并不存在;2>,我们完全可以将所有数据表中的所有字段都放在一个实体里)
- (4)每一层(UI—>BLL—>DAL)之间的数据传递(单向)是靠变量或实体作为参数来传递的,这样就构造了三层之间的联系,完成了功能的实现。
(2)三层及实体层之间的依赖关系
二、为什么使用三层?
(1)使用三层架构的目的:解耦!
(2)三层与两层的区别?
两层:
(当任何一个地方发生变化时,都需要重新开发整个系统。"多层"放在一层,分工不明确耦合度高——难以适应需求变化,可维护性低、可扩展性低)
三层:
(发生在哪一层的变化,只需更改该层,不需要更改整个系统。层次清晰,分工明确,每层之间耦合度低——提高了效率,适应需求变化,可维护性高,可扩展性高)
三、三层架构的优劣势
(1)三层架构的优势:
- 1,结构清晰、耦合度低
- 2,可维护性高,可扩展性高
- 3,利于开发任务同步进行, 容易适应需求变化
(2)三层架构的劣势:
- 1、降低了系统的性能。这是不言而喻的。如果不采用分层式结构,很多业务可以直接造访数据库,以此获取相应的数据,如今却必须通过中间层来完成。
- 2、有时会导致级联的修改。这种修改尤其体现在自上而下的方向。如果在表示层中需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据访问层中都增加相应的代码
- 3、增加了代码量,增加了工作量
四. 三层架构如何实现
使用三层架构时,我们首先要先创建好不同的包,每一个包对应三层架构的一个层。下面通过一个学生登录功能的案例讲解三层架构的用法。
- 首先我们在数据库中==创建了 student表==,结构如下:
- 创建数据传递的载体==实体类==,一般我们将实体类放在domain/pojo/entity 这三者其中一个的包下,实体类的属性需要与数据库中的表一一对应。在 src 目录下创建了存放实体类的包:entity,然后在包下创建了Student类,它的属性和数据表student的属性一一对应,然后在实体类中给各个属性创建了对应的get/set方法,创建了有参/无参构造方法以及toString()方法。
- 创建==工具包util==,用于存放一些常用且不变的方法,比如IO流的读写,反反复复都是那些代码,我们就将这些重复的代码抽取出来将它封装成一个工具类,在我们需要用到这个方法的时候,直接调用即可。在验证登录这个案例里面,我们将连接数据库需要的代码抽取出来,这是因为每一次对数据库表进行增删改查访问的时候都需要连接数据库,所以将它抽取成工具类方便使用。
- 创建==数据访问层dao==,在数据访问层中将对数据库表进行操作的方法写在接口 StudentDao 中,然后通过实现类 StudentImpl 写具体操作数据库表的逻辑代码。先将需要用到的方法都封装好,不写方法的实现,用到某一个方法,写这个方法的具体实现。这里我们要做的是登录验证,所以我们封装了登录方法 login ,接下来我们分析:验证登录肯定需要学生先输入用户名和密码,有了用户名和密码之后去数据库表中查对应的数据,查到了就将这个学生的信息打印出来。经过分析我们知道方法的参数就是 name 和 password ,返回值就是这个学生 Student。方法的具体实现,就是通过sql语句对数据库表进行操作,都是固定的模板,通过 JDBCTemplate模板 调用实现的方法即可。
- 创建==业务逻辑层service==,业务逻辑层主要是对具体问题进行逻辑判断与执行操作,接收到表现层 UI 的用户指令后(用户某一步操作),会连接数据访问层 DAL进行业务处理。访问层在三层构架中位于表示层与数据层中间位置,同时也是表示层与数据层的桥梁,实现三层之间的数据连接和指令传达,可以对接收数据进行逻辑处理,实现数据的修改、获取、删除等功能,并将处理结果反馈到表示层 UI 中,实现软件功能。在登录案例里面,我们通过学生输入的名字和密码在数据库表里进行查找,如果没有,我们就告诉学生输入的姓名或者密码错误;如果学生输入的信息为空,那么我们就根本不用访问数据访问层的方法,直接提示用户输入错误。这一系列的逻辑判断我们都写在逻辑层service里面。
- 创建==用户表示层view==,表示层又称表现层 UI,位于三层构架的最上层,与用户直接接触,主要是 B/S 信息系统中的 Web浏览页面,由于我们还没有使用Web页面,所以我们的用户表示层,就是现在大家写的主函数里用户输入的信息。可以看到,我们的用户界面只有一句核心代码,就是调用业务逻辑层的 loginStu() 方法,其他的处理全都通过三层架构的方式分开存放,代码的逻辑变得非常的清晰。==注意:==这里解释为什么我们要先写接口再写实现类:使用接口是为了调用与实现解耦,带来的好处是可以各干各的。
五、三层架构代码实现
domain层(实体类)
package com.entity;
import java.sql.Date;
import java.sql.Timestamp;
public class User {
private int id ; //序号
private String user_id; // 用户编号(学号/教师编号)
private String password; // 密码
private String user_name; // 姓名
private int age; //年龄
private String gender; // 性别
private String phoneNumber; // 电话
private int identity; // 所在院系
private String department; // 所在院系
private int status; // 登录状态
private Timestamp registrationDate; // 注册日期
public User() {
}
public User(int id, String user_id, String password, String user_name, int age, String gender, String phoneNumber, int identity, String department, int status) {
this.id = id;
this.user_id = user_id;
this.password = password;
this.user_name = user_name;
this.age = age;
this.gender = gender;
this.phoneNumber = phoneNumber;
this.identity = identity;
this.department = department;
this.status = status;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getuser_id() {
return user_id;
}
public void setuser_id(String user_id) {
this.user_id = user_id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getuser_name() {
return user_name;
}
public void setuser_name(String user_name) {
this.user_name = user_name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public int getIdentity() {
return identity;
}
public void setIdentity(int identity) {
this.identity = identity;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public Timestamp getRegistrationDate() {
return registrationDate;
}
public void setRegistrationDate(Timestamp registrationDate) {
this.registrationDate = registrationDate;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", user_id='" + user_id + '\'' +
", password='" + password + '\'' +
", user_name='" + user_name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", phoneNumber='" + phoneNumber + '\'' +
", identity=" + identity +
", department='" + department + '\'' +
", status=" + status +
", registrationDate=" + registrationDate +
'}';
}
}
dao层(数据访问层)
接口(interface)
package com.dao;
import com.entity.User;
import java.util.List;
public interface UserDao {
//返回所有对象
List<User> queryAllList(String sql);
//查找多条记录
List<User> queryList(String sql, Object... parameters);
//查找一条记录
User queryOne(String sql, Object... parameters);
//修改(增删改)一条记录
int update(String sql, Object... parameters);
}
接口实现类(DaoImpl)
package com.dao.impl;
import com.dao.UserDao;
import com.entity.User;
import com.util.JDBCUtilsByDruid;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
public class UserDaoImpl implements UserDao {
private QueryRunner qr = new QueryRunner();
//返回所有对象
@Override
public List<User> queryAllList(String sql) {
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
return qr.query(connection, sql, new BeanListHandler<User>(User.class));
} catch (SQLException e) {
throw new RuntimeException(e); //将编译异常->运行异常 ,抛出
} finally {
JDBCUtilsByDruid.close(null, null, connection);
}
}
//返回多个对象(即查询的结果是多行)
@Override
public List<User> queryList(String sql, Object... parameters) {
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
return qr.query(connection, sql, new BeanListHandler<User>(User.class), parameters);
} catch (SQLException e) {
throw new RuntimeException(e); //将编译异常->运行异常 ,抛出
} finally {
JDBCUtilsByDruid.close(null, null, connection);
}
}
//查询单行结果
@Override
public User queryOne(String sql, Object... parameters) {
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
return qr.query(connection, sql, new BeanHandler<User>(User.class), parameters);
} catch (SQLException e) {
throw new RuntimeException(e); //将编译异常->运行异常 ,抛出
} finally {
JDBCUtilsByDruid.close(null, null, connection);
}
}
// 修改(增删改通用)
@Override
public int update(String sql, Object... parameters) {
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
int update = qr.update(connection, sql, parameters);
return update;
} catch (SQLException e) {
throw new RuntimeException(e); //将编译异常->运行异常 ,抛出
} finally {
JDBCUtilsByDruid.close(null,null,connection);
}
}
}
接口(interface)
service层(业务逻辑)
接口(interface)
package com.service;
import com.entity.User;
import java.util.List;
public interface UserService {
//根据userId查询一个user
User getUser(String id);
//根据userId和password查询一个user
Boolean ableLogin (String userId , String password);
//根据status查询一个user
User getLoginUser(int status);
//查找多条user对象
List<User> getUserList(Object... parameters);
//查找所有user对象
List<User> getAllUser();
//增加一个user
int addUser(Object... parameters);
//删除一个user
int deleteUser(int userId);
//修改一个user的信息
int updateUser(Object... parameters);
//修改一个user的登录状态
int updateUserStatus(int status,String userId);
//重置所有user的登录状态为0
int updAllUserStatus(int status);
//修改一个user的登录密码
int updateUserPassword(String password,String userId);
}
接口实现类(ServiceImpl)
package com.service.impl;
import com.dao.UserDao;
import com.dao.impl.UserDaoImpl;
import com.entity.User;
import com.service.UserService;
import java.util.List;
public class UserServiceImpl implements UserService {
//创建UserDaoImpl对象
private UserDao userDao = new UserDaoImpl();
//查询所有
@Override
public List<User> getAllUser() {
String sql ="select * from `user`";
try {
return userDao.queryAllList(sql);
} catch (Exception e) {
System.out.println(e);
return null;
}
}
//根据userId查询一个user
@Override
public User getUser(String userId) {
String sql = "select * from `user` where user_id = ? ";
try {
return userDao.queryOne(sql,userId);
} catch (Exception e) {
System.out.println(e);
return null;
}
}
//根据userId和password查询一个user
@Override
public Boolean ableLogin (String userId , String password) {
String sql ="select * from `user` where user_id = ? and password = ? ";
User user = userDao.queryOne(sql, userId, password);
return user != null ? true : false;
}
//根据status查询一个user
@Override
public User getLoginUser(int status) {
String sql = "select * from `user` where status = ? ";
try {
return userDao.queryOne(sql,status);
} catch (Exception e) {
System.out.println(e);
return null;
}
}
//根据条件查询多个user
@Override
public List<User> getUserList(Object... parameters) {
String sql ="select * from `user` where ? = ? ";
try {
return userDao.queryList(sql,parameters);
} catch (Exception e) {
System.out.println(e);
return null;
}
}
public List<User> getUserJz() {
String sql ="SELECT *FROM `user` WHERE user_id LIKE 'jz%'";
try {
return userDao.queryList(sql);
} catch (Exception e) {
System.out.println(e);
return null;
}
}
//增加一个user
@Override
public int addUser(Object... parameters) {
String sql ="insert into `user` values (null,?,?,?,?,?,?,?,?,DEFAULT,?) ";
return userDao.update(sql, parameters);
}
//删除一个user
@Override
public int deleteUser(int userId) {
String sql ="delete from `user` where id = ? ";
return userDao.update(sql,userId);
}
//修改一个user的信息
@Override
public int updateUser(Object... parameters) {
String sql ="update `user` set age = ?,gender = ?,phoneNumber = ?,department = ? where user_id = ? ";
return userDao.update(sql,parameters);
}
//修改一个user的登录状态
@Override
public int updateUserStatus(int status,String userId) {
String sql ="update `user` set status = ? where user_id = ? ";
return userDao.update(sql,status,userId);
}
//重置所有user的登录状态为0
@Override
public int updAllUserStatus(int status) {
String sql ="update `user` set status = ? ";
return userDao.update(sql,status);
}
//修改一个user的登录密码
@Override
public int updateUserPassword(String password,String userId) {
String sql ="update `user` set password = ? where user_id = ? ";
return userDao.update(sql,password,userId);
}
}
view层(用户界面层)
版权归原作者 待╮续 所有, 如有侵权,请联系我们删除。