前言

项目发布于半年前(2023年9月),这次是复习~来考古 =_=
点击前往 GitHub 项目页
该项目在之前的 学生管理系统 项目的基础上,增加了三层架构,对项目进行了分层

1. 三层架构

三层架构是一种分层的设计模式,将整个业务分为表示层、业务逻辑层、数据访问层(持久化层)
优点:降低了代码耦合度,层与层更方便管理,维护性和扩展性较高
缺点:开发成本高,系统性能较低(需要中间层)
具体实现如图:

  • 表示层(UI)
    显示数据和接受用户输入,实现用户与界面的交互
  • 业务逻辑层(BLL)
    表示层和数据访问层之间的桥梁,主要包含业务逻辑代码,负责数据的传递
  • 数据访问层(DAL)
    实现对数据库的访问和操作

2. JavaEE 设计模式之 DAO

DAO,Data Access Object(数据访问对象),是 JavaEE 的一种设计模式
只负责数据库表的 CRUD 操作,没有任何业务逻辑

3. 三层架构应用

目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
src
|--- com.xxx.student_manage
|--- bean
|--- Student
|--- dao 新增:数据访问层
|--- impl
|--- XxxDaoImpl 实现类
|--- XxxDao 接口
|--- filter
|--- LoginCheckFilter
|--- service 新增:业务逻辑层
|--- impl
|--- impl
|--- XxxServiceImpl 实现类
|--- XxxService 接口
|--- utils
|--- DBUtil
|--- web 原有:表示层,代码耦合度降低
|--- StudentServlet
|--- UserServlet
|--- WelcomeServlet
|--- resources
|--- jdbc.properties

web 原有:jsp 也属于表示层
|--- ...

代码实现

这里列举学生信息相关

DAO 层

只完成 CRUD 操作
接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* @author ShameYang
* @date 2023/9/14 12:26
* @description 学生表对应的 DAO
*/
public interface StudentDao {
int insert(Student student);

int deleteBySno(String sno);

int update(Student student);

Student selectBySno(String sno);

List<Student> selectAll();
}

实现类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/**
* @author ShameYang
* @date 2023/9/14 12:34
* @description StudentDao 实现类
*/
public class StudentDaoImpl implements StudentDao {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;

int count = 0;

@Override
public int insert(Student student) {
try {
conn = DBUtil.getConnection();
String sql = "insert into t_student(sno, sname, ssex, telephone) values (?, ?, ?, ?)";
ps = conn.prepareStatement(sql);
ps.setString(1, student.getSno());
ps.setString(2, student.getSname());
ps.setString(3, student.getSsex());
ps.setString(4, student.getTelephone());
count = 0;
count = ps.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
DBUtil.close(conn, ps, null);
}
return count;
}

@Override
public int deleteBySno(String sno) {
try {
conn = DBUtil.getConnection();
String sql = "delete from t_student where sno = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, sno);
count = 0;
count = ps.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
DBUtil.close(conn, ps, null);
}
return count;
}

@Override
public int update(Student student) {
try {
conn = DBUtil.getConnection();
String sql = "update t_student set sname=?, telephone=? where sno=?";
ps = conn.prepareStatement(sql);
ps.setString(1, student.getSname());
ps.setString(2, student.getTelephone());
ps.setString(3, student.getSno());
count = 0;
count = ps.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
DBUtil.close(conn, ps, null);
}
return count;
}

@Override
public Student selectBySno(String sno) {
Student student = new Student();
try {
conn = DBUtil.getConnection();
String sql = "select sno, sname, ssex, telephone from t_student where sno=?";
ps = conn.prepareStatement(sql);
ps.setString(1, sno);
rs = ps.executeQuery();
if (rs.next()) {
String sname = rs.getString("sname");
String ssex = rs.getString("ssex");
String telephone = rs.getString("telephone");

student.setSno(sno);
student.setSname(sname);
student.setSsex(ssex);
student.setTelephone(telephone);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
DBUtil.close(conn, ps, rs);
}
return student;
}

@Override
public List<Student> selectAll() {
List<Student> studentList = new ArrayList<>();
try {
conn = DBUtil.getConnection();
String sql = "select sno, sname, ssex, telephone from t_student";
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()) {
String sno = rs.getString("sno");
String sname = rs.getString("sname");
String ssex = rs.getString("ssex");
String telephone = rs.getString("telephone");

Student student = new Student();
student.setSno(sno);
student.setSname(sname);
student.setSsex(ssex);
student.setTelephone(telephone);

studentList.add(student);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
DBUtil.close(conn, ps, rs);
}
return studentList;
}
}

Service 层

实现业务逻辑,传递数据
接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* @author ShameYang
* @date 2023/9/14 12:34
* @description 学生信息管理业务
*/
public interface StudentService {
void doList(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;

void doDetail(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;

void doDel(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;

void doAdd(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;

void doModify(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;
}

实现类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/**
* @author ShameYang
* @date 2023/9/14 14:43
* @description 学生信息管理业务
*/
public class StudentServiceImpl implements StudentService {
StudentDao studentDao = new StudentDaoImpl();

@Override
public void doList(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
List<Student> studentList = studentDao.selectAll();
// 将集合放到请求域中
request.setAttribute("stuList", studentList);
// 转发到 JSP 页面
request.getRequestDispatcher("/list.jsp").forward(request, response);
}

@Override
public void doDetail(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String sno = request.getParameter("sno");
Student student = studentDao.selectBySno(sno);
request.setAttribute("student", student);
// 这样写可以转发给修改功能使用
request.getRequestDispatcher("/" + request.getParameter("f") + ".jsp").forward(request, response);
}

@Override
public void doDel(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String sno = request.getParameter("sno");
// 删除成功,重定向至学生列表页面
if (studentDao.deleteBySno(sno) == 1) {
response.sendRedirect(request.getContextPath() + "/student/list");
}
}

@Override
public void doAdd(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String sno = request.getParameter("sno");
String sname = request.getParameter("sname");
String ssex = request.getParameter("ssex");
String telephone = request.getParameter("telephone");
Student student = new Student(sno, sname, ssex, telephone);
if (studentDao.insert(student) == 1) {
response.sendRedirect(request.getContextPath() + "/student/list");
}
}

@Override
public void doModify(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String sno = request.getParameter("sno");
String sname = request.getParameter("sname");
String ssex = request.getParameter("ssex");
String telephone = request.getParameter("telephone");

Student student = new Student(sno, sname, ssex, telephone);

if (studentDao.update(student) == 1) {
response.sendRedirect(request.getContextPath() + "/student/list");
}
}
}

Web 层

StudentServlet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* @author ShameYang
* @date 2023/9/10 16:36
* @description 学生列表
*/
@WebServlet({"/student/list", "/student/detail", "/student/delete",
"/student/add", "/student/modify"})
public class StudentServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
StudentService studentService = new StudentServiceImpl();
String servletPath = request.getServletPath();
switch (servletPath) {
case "/student/list" -> studentService.doList(request, response);
case "/student/detail" -> studentService.doDetail(request, response);
case "/student/delete" -> studentService.doDel(request, response);
case "/student/add" -> studentService.doAdd(request, response);
case "/student/modify" -> studentService.doModify(request, response);
}
}
}