Servlet及Filter基础实验
1 实验类型
验证型,2学时,必选实验
2 实验目的
掌握前后端协作过程;理解前后端数据交换原理;
3 实验要求
验证参考代码;修改参考代码,实现自己的设计;将关键结果截图及源代码整理成实验报告
4 实验环境
Windows 7 64、Open JDK 23+、Tomcat 11+、Spring Tools 4(STS4)、Visual Studio Code(VS Code)、Microsoft Edge/Chrome/Firefox等浏览器
、sqlite-jdbc-3.41.0.0.jar
5 实验步骤
创建工作目录:{盘符}:/{学号}/exp5_advanced
用JSP实现学生表的增、删、改、查操作,前端:用JSP页面编写操作界面,后端:用4层架构通过JDBC存储数据于Sqlite数据库
后端
后端4层架构如下:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
subgraph "表现层 (Action)"
A(JSP页面):::process
end
subgraph "业务逻辑层 (Service)"
B(StudentService):::process
end
subgraph "数据访问层 (DAO)"
C(StudentDAO):::process
end
subgraph "实体层 (Domain)"
D(Student):::process
end
A -->|调用业务方法| B
B -->|调用数据访问方法| C
C -->|操作实体| D
classDef database fill:#FFEBEB,stroke:#E68994,stroke-width:2px;
E[(学生表)]:::database
C -->|CRUD 操作| E
-
创建Java Web工程StudentCRUD
-
将sqlite-jdbc-3.49.1.0.jar放入WEB-INF/lib目录
-
创建实体类:xust.demo.stu.domain.Student
,参考代码如下:
xust.demo.stu.domain.Student类 |
---|
| package xust.demo.stu.domain;
/**
* Class Student
* 学生表
*
* @author XUST
* @version 1.0, 2023-04-20
*/
public class Student {
/**
* 学号
*/
private String no;
public String getNo() {
return no;
}
public void setNo(String newValue) {
no = newValue;
}
/**
* 姓名
*/
private String name;
public String getName() {
return name;
}
public void setName(String newValue) {
name = newValue;
}
/**
* 性别
*/
private String gender;
public String getGender() {
return gender;
}
public void setGender(String newValue) {
gender = newValue;
}
/**
* 年龄
*/
private Integer age;
public Integer getAge() {
return age;
}
public void setAge(Integer newValue) {
age = newValue;
}
/**
* 所在系
*/
private String dept;
public String getDept() {
return dept;
}
public void setDept(String newValue) {
dept = newValue;
}
@Override
/**
* 将对象序列化为JSON字符串
*/
public String toString() {
return "{" + "\"no\": " + "\"" + no + "\"" + ", " + "\"name\": " + "\"" + name + "\"" + ", " + "\"gender\": " + "\""
+ gender + "\"" + ", " + "\"age\": " + age + ", " + "\"dept\": " + "\"" + dept + "\"" + "}";
}
}
|
-
创建数据库连接类:xust.demo.ConnectionUtil
;数据库文件存放在:d:/stu.db
,代码中自动创建,无须手动创建,参考代码如下:
xust.demo.ConnectionUtil类 |
---|
| package xust.demo;
import java.sql.*;
/**
* 连接辅助类
*/
public class ConnectionUtil {
/**
* 创建连接
*
* @return 连接对象
*/
public static Connection getConnection() {
Connection res = null;
try {
Class.forName("org.sqlite.JDBC");
// 在数据库文件stu.db存放在D盘下
res = DriverManager.getConnection("jdbc:sqlite:d:/stu.db");
} catch (Exception e) {
System.err.println(e.getClass().getName() + ": " + e.getMessage());
System.exit(0);
}
return res;
}
/**
* 关闭连接
*
* @param connection 连接对象
*/
public static void closeConnection(Connection connection) {
if (connection != null) {
try {
connection.close();
} catch (Exception e) {
System.err.println(e.getClass().getName() + ": " + e.getMessage());
System.exit(0);
}
}
}
/**
* 关闭语句
*
* @param pstmt 语句对象
*/
public static void closePstmt(PreparedStatement pstmt) {
if (pstmt != null) {
try {
pstmt.close();
} catch (Exception e) {
System.err.println(e.getClass().getName() + ": " + e.getMessage());
System.exit(0);
}
}
}
/**
* 关闭语句
*
* @param pstmt 语句对象
*/
public static void closeStmt(Statement stmt) {
if (stmt != null) {
try {
stmt.close();
} catch (Exception e) {
System.err.println(e.getClass().getName() + ": " + e.getMessage());
System.exit(0);
}
}
}
}
|
-
创建结果类:xust.demo.Result
,参考代码如下:
xust.demo.Result类 |
---|
| package xust.demo;
/**
* 操作结果类
*/
public class Result {
/**
* 结果码,0为成功
*/
public int code;
/**
* 结果信息
*/
public String message;
/**
* 结果数据
*/
public Object data;
public Result() {
}
public Result(Boolean v) {
code = v ? 0 : 1;
}
}
|
-
创建数据访问接口:xust.demo.stu.dao.StudentDao
和实现类:xust.demo.stu.dao.StudentDaoImpl
,参考代码如下:
xust.demo.stu.dao.StudentDao接口 |
---|
| package xust.demo.stu.dao;
import xust.demo.Result;
import xust.demo.stu.domain.Student;
public interface StudentDao {
/**
* 初始化表
*
* @return
*/
Result init();
/**
* 增
*
* @param o
* @return
*/
Result create(Student o);
/**
* 删
*
* @param id
* @return
*/
Result delete(String no);
/**
* 改
*
* @param o
* @return
*/
Result update(Student o);
/**
* 查
*
* @param no
* @return
*/
Result get(String no);
/**
* 查
*
* @return
*/
Result getAll();
}
|
xust.demo.stu.dao.StudentDaoImpl类 |
---|
| package xust.demo.stu.dao;
import java.sql.*;
import java.util.ArrayList;
import xust.demo.Result;
import xust.demo.ConnectionUtil;
import xust.demo.stu.domain.Student;
public class StudentDaoImpl implements StudentDao {
public Result init() {
Result res = new Result(false);
Connection con = null;
Statement stmt = null;
String sql = "create table Student(" +
"no TEXT primary key," +
"name TEXT not null," +
"gender TEXT," +
"age INTEGER," +
"dept TEXT" +
");";
con = ConnectionUtil.getConnection();
if (con != null) {
try {
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(String.format(
"select count(*) from sqlite_master where type = 'table' and Upper(name) = '%s'", "Student".toUpperCase()));
while (rs.next()) {
int count = rs.getInt(1);
if (count == 0 && stmt.executeUpdate(sql) > 0) {
res.code = 0;
}
}
} catch (Exception e) {
e.printStackTrace();
res.message = e.getMessage();
} finally {
ConnectionUtil.closeStmt(stmt);
ConnectionUtil.closeConnection(con);
}
}
return res;
}
/**
* 对象填充到关系
*/
private void toR(Student o, PreparedStatement stmt) throws Exception {
if (o != null && stmt != null) {
String no = o.getNo();
if (no != null) {
stmt.setString(1, no);
}
String name = o.getName();
if (name != null) {
stmt.setString(2, name);
}
String gender = o.getGender();
if (gender != null) {
stmt.setString(3, gender);
}
Integer age = o.getAge();
if (age != null) {
stmt.setInt(4, age);
}
String dept = o.getDept();
if (dept != null) {
stmt.setString(5, dept);
}
}
}
/**
* 关系填充到对象
*/
private Student toO(ResultSet rs) throws Exception {
Student res = null;
if (rs != null) {
res = new Student();
res.setNo(rs.getString("no"));
res.setName(rs.getString("name"));
res.setGender(rs.getString("gender"));
res.setAge(rs.getInt("age"));
res.setDept(rs.getString("dept"));
}
return res;
}
public Result create(Student o) {
Result res = new Result(false);
Connection con = null;
PreparedStatement stmt = null;
String sql = "insert into Student values (?, ?, ?, ?, ?)";
con = ConnectionUtil.getConnection();
if (o != null && con != null) {
try {
stmt = con.prepareStatement(sql);
toR(o, stmt);
int row_effected = stmt.executeUpdate();
if (row_effected > 0) {
res.code = 0;
}
res.data = row_effected;
} catch (Exception e) {
res.message = e.getMessage();
e.printStackTrace();
} finally {
ConnectionUtil.closePstmt(stmt);
ConnectionUtil.closeConnection(con);
}
}
return res;
}
public Result delete(String no) {
Result res = new Result(false);
Connection con = null;
PreparedStatement stmt = null;
String sql = "delete from Student where no = ?;";
con = ConnectionUtil.getConnection();
if (con != null) {
try {
stmt = con.prepareStatement(sql);
stmt.setString(1, no);
int row_effected = stmt.executeUpdate();
if (row_effected > 0) {
res.code = 0;
}
res.data = row_effected;
} catch (Exception e) {
res.message = e.getMessage();
e.printStackTrace();
} finally {
ConnectionUtil.closePstmt(stmt);
ConnectionUtil.closeConnection(con);
}
}
return res;
}
public Result update(Student o) {
Result res = new Result(false);
Connection con = null;
PreparedStatement stmt = null;
String sql = "update Student set No = ?, Name = ?, Gender = ?, Age = ?, Dept = ? where no = ?";
con = ConnectionUtil.getConnection();
if (o != null && con != null) {
try {
stmt = con.prepareStatement(sql);
toR(o, stmt);
stmt.setString(6, o.getNo());
int row_effected = stmt.executeUpdate();
if (row_effected > 0) {
res.code = 0;
}
res.data = row_effected;
} catch (Exception e) {
e.printStackTrace();
res.message = e.getMessage();
} finally {
ConnectionUtil.closePstmt(stmt);
ConnectionUtil.closeConnection(con);
}
}
return res;
}
public Result get(String no) {
Result res = new Result(false);
Connection con = null;
PreparedStatement stmt = null;
String sql = "select * from Student where no = ?";
con = ConnectionUtil.getConnection();
if (con != null) {
try {
stmt = con.prepareStatement(sql);
stmt.setString(1, no);
ResultSet rs = stmt.executeQuery();
Student last = null;
while (rs.next()) {
last = new Student();
last.setNo(rs.getString("no"));
last.setName(rs.getString("name"));
last.setGender(rs.getString("gender"));
last.setAge(rs.getInt("age"));
last.setDept(rs.getString("dept"));
}
res.code = 0;
res.data = last;
} catch (Exception e) {
res.message = e.getMessage();
e.printStackTrace();
} finally {
ConnectionUtil.closePstmt(stmt);
ConnectionUtil.closeConnection(con);
}
}
return res;
}
public Result getAll() {
Result res = new Result(false);
Connection con = null;
PreparedStatement stmt = null;
String sql = "select * from Student";
con = ConnectionUtil.getConnection();
if (con != null) {
try {
stmt = con.prepareStatement(sql);
ResultSet rs = stmt.executeQuery();
ArrayList<Student> data = new ArrayList<Student>();
while (rs.next()) {
Student last = toO(rs);
data.add(last);
}
res.code = 0;
res.data = data;
} catch (Exception e) {
res.message = e.getMessage();
e.printStackTrace();
} finally {
ConnectionUtil.closePstmt(stmt);
ConnectionUtil.closeConnection(con);
}
}
return res;
}
}
|
-
创建业务逻辑接口:xust.demo.stu.service.StudentService
和实现类:xust.demo.stu.service.StudentServiceImpl
,参考代码如下:
xust.demo.stu.serviceStudentService接口 |
---|
| package xust.demo.stu.service;
import xust.demo.Result;
import xust.demo.stu.domain.Student;
import jakarta.servlet.http.HttpServletRequest;
public interface StudentService {
Student toO(HttpServletRequest request);
/**
* 增
*
* @param o
* @return
*/
Result create(Student o);
/**
* 删
*
* @param id
* @return
*/
Result delete(String no);
/**
* 改
*
* @param o
* @return
*/
Result update(Student o);
/**
* 查
*
* @param no
* @return
*/
Result get(String no);
/**
* 查
*
* @return
*/
Result getAll();
}
|
xust.demo.stu.service.StudentServiceImpl类 |
---|
| package xust.demo.stu.service;
import xust.demo.Result;
import xust.demo.stu.domain.Student;
import xust.demo.stu.dao.StudentDao;
import xust.demo.stu.dao.StudentDaoImpl;
import jakarta.servlet.http.HttpServletRequest;
public class StudentServiceImpl implements StudentService {
private StudentDao _StudentDao;
public StudentServiceImpl() {
_StudentDao = new StudentDaoImpl();
_StudentDao.init();
}
/**
* 参数填充到对象
*/
public Student toO(HttpServletRequest request) {
Student res = null;
if (request != null) {
res = new Student();
String p = null;
p = request.getParameter("no");
if (p != null) {
res.setNo(request.getParameter("no"));
}
p = request.getParameter("name");
if (p != null) {
res.setName(request.getParameter("name"));
}
p = request.getParameter("gender");
if (p != null) {
res.setGender(request.getParameter("gender"));
}
p = request.getParameter("age");
if (p != null) {
res.setAge(Integer.parseInt(request.getParameter("age")));
}
p = request.getParameter("dept");
if (p != null) {
res.setDept(request.getParameter("dept"));
}
}
return res;
}
public Result create(Student o) {
Result res = new Result(false);
if (_StudentDao != null && o != null) {
res = _StudentDao.create(o);
}
return res;
}
public Result delete(String no) {
Result res = new Result(false);
if (_StudentDao != null) {
res = _StudentDao.delete(no);
}
return res;
}
public Result update(Student o) {
Result res = new Result(false);
if (_StudentDao != null && o != null) {
res = _StudentDao.update(o);
}
return res;
}
public Result get(String no) {
Result res = new Result(false);
if (_StudentDao != null) {
res = _StudentDao.get(no);
}
return res;
}
public Result getAll() {
Result res = new Result(false);
if (_StudentDao != null) {
res = _StudentDao.getAll();
}
return res;
}
}
|
前端
前端主要页面功能如下:
url |
功能 |
/stu/init.jsp |
初始化学生列表,成功后跳转到list.jsp |
/stu/list.jsp |
以表格显示学生列表,每行包含修改、删除链接 |
/stu/add_view.jsp |
添加学生页面,成功后跳转到list.jsp |
/stu/add.jsp |
添加学生,成功后跳转到list.jsp |
/stu/update_view.jsp |
修改学生页面,成功后跳转到list.jsp |
/stu/delete.jsp |
删除学生,成功后跳转到list.jsp |
/stu/update.jsp |
修改学生,成功后跳转到list.jsp |
sequenceDiagram
title JSP实现学生表增删改查操作流程(4层架构与SQLite)
participant User
participant InitJSP as /stu/init.jsp
participant ListJSP as /stu/list.jsp
participant AddViewJSP as /stu/add_view.jsp
participant AddJSP as /stu/add.jsp
participant UpdateViewJSP as /stu/update_view.jsp
participant DeleteJSP as /stu/delete.jsp
participant UpdateJSP as /stu/update.jsp
participant Controller
participant Service
participant DAO
participant SQLiteDB
User->>InitJSP: 访问初始化页面
InitJSP->>Controller: 调用初始化逻辑
Controller->>Service: 调用服务层初始化方法
Service->>DAO: 调用数据访问层获取学生列表方法
DAO->>SQLiteDB: 执行SQL查询获取学生列表数据
SQLiteDB-->>DAO: 返回学生列表数据
DAO-->>Service: 返回学生列表数据
Service-->>Controller: 返回学生列表数据
Controller-->>ListJSP: 初始化成功,跳转并传递学生列表数据
User->>ListJSP: 查看学生列表
User->>ListJSP: 点击添加链接
ListJSP-->>AddViewJSP: 跳转到添加页面
User->>AddViewJSP: 填写学生信息并提交
AddViewJSP->>Controller: 传递添加学生信息
Controller->>Service: 调用服务层添加学生方法
Service->>DAO: 调用数据访问层添加学生方法
DAO->>SQLiteDB: 执行SQL插入操作添加学生数据
SQLiteDB-->>DAO: 返回操作结果
DAO-->>Service: 返回添加操作结果
Service-->>Controller: 返回添加操作结果
Controller-->>ListJSP: 添加成功,跳转
User->>ListJSP: 查看更新后的学生列表
User->>ListJSP: 点击某行修改链接
ListJSP-->>UpdateViewJSP: 跳转到修改页面并传递学生信息
User->>UpdateViewJSP: 修改学生信息并提交
UpdateViewJSP->>Controller: 传递修改后学生信息
Controller->>Service: 调用服务层修改学生方法
Service->>DAO: 调用数据访问层修改学生方法
DAO->>SQLiteDB: 执行SQL更新操作修改学生数据
SQLiteDB-->>DAO: 返回操作结果
DAO-->>Service: 返回修改操作结果
Service-->>Controller: 返回修改操作结果
Controller-->>ListJSP: 修改成功,跳转
User->>ListJSP: 查看再次更新后的学生列表
User->>ListJSP: 点击某行删除链接
ListJSP->>Controller: 传递要删除学生标识
Controller->>Service: 调用服务层删除学生方法
Service->>DAO: 调用数据访问层删除学生方法
DAO->>SQLiteDB: 执行SQL删除操作删除学生数据
SQLiteDB-->>DAO: 返回操作结果
DAO-->>Service: 返回删除操作结果
Service-->>Controller: 返回删除操作结果
Controller-->>ListJSP: 删除成功,跳转
User->>ListJSP: 查看最终的学生列表
-
创建列表页面:stu/list.jsp
,显示学生列表,参考代码如下:
stu/list.jsp |
---|
| <%@ page import="xust.demo.Result" %>
<%@ page import="xust.demo.stu.domain.Student" %>
<%@ page import="xust.demo.stu.service.StudentService" %>
<%@ page import="xust.demo.stu.service.StudentServiceImpl" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=utf-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>学生表</title>
</head>
<body>
<h3>学生表</h3>
<a href="<%=request.getContextPath()%>/stu/add_view.jsp">新增</a>
<table id="STUDENT" border="1" width="100%">
<thead>
<th>学号</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
<th>所在系</th>
<th>操作</th>
</thead>
<tbody>
<%
StudentService _StudentService = new StudentServiceImpl();
List<Student> students = (List<Student>)(_StudentService.getAll().data);
if(students != null){
for(Student stu: students){
String line = "";
line += String.format("<td>%s</td>", stu.getNo());
line += String.format("<td>%s</td>", stu.getName());
line += String.format("<td>%s</td>", stu.getGender());
line += String.format("<td>%s</td>", stu.getAge());
line += String.format("<td>%s</td>", stu.getDept());
line += String.format("<td><a href='%s/stu/update_view.jsp?no=%s'>修改</a> <a href='%s/stu/delete.jsp?no=%s'>删除</a></td>", request.getContextPath(), stu.getNo(), request.getContextPath(), stu.getNo());
out.print(String.format("<tr>%s</tr>", line));
}
}
%>
</tbody>
</table>
</body>
</html>
|
-
创建新建界面页面:stu/add_view.jsp
,用于添加界面,参考代码如下:
stu/add_view.jsp |
---|
| <%@ page contentType="text/html;charset=utf-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>学生表</title>
</head>
<body>
<h3>学生表</h3>
<div>
<form action="<%=String.format(" %s/stu/add.jsp", request.getContextPath())%>">
<div>
<label for="no">学号:</label>
<input type="text" id="no" name="no" placeholder="请输入学号..">
</div>
<div>
<label for="name">姓名:</label>
<input type="text" id="name" name="name" placeholder="请输入姓名..">
</div>
<div>
<label for="gender">性别:</label>
<input type="text" id="gender" name="gender" placeholder="请输入性别..">
</div>
<div>
<label for="age">年龄:</label>
<input type="number" id="age" name="age" placeholder="请输入年龄..">
</div>
<div>
<label for="dept">所在系:</label>
<input type="text" id="dept" name="dept" placeholder="请输入所在系..">
</div>
<button type="submit">提交</button>
</form>
</div>
</body>
</html>
|
-
创建新建页面:stu/add.jsp
,实现添加功能,参考代码如下:
stu/add.jsp |
---|
| <%@ page import="xust.demo.Result" %>
<%@ page import="xust.demo.stu.domain.Student" %>
<%@ page import="xust.demo.stu.service.StudentService" %>
<%@ page import="xust.demo.stu.service.StudentServiceImpl" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=utf-8" %>
<%
StudentService _StudentService = new StudentServiceImpl();
Student stu_new = new Student();
Student o = _StudentService.toO(request);
Result res = _StudentService.create(o);
//操作完成,回到列表
response.sendRedirect(String.format("%s%s", request.getContextPath(), "/stu/list.jsp"));
%>
|
-
创建修改界面页面:stu/update_view.jsp
,用于修改界面,参考代码如下:
stu/update_view.jsp |
---|
| <%@ page import="xust.demo.Result"%>
<%@ page import="xust.demo.stu.domain.Student"%>
<%@ page import="xust.demo.stu.service.StudentService"%>
<%@ page import="xust.demo.stu.service.StudentServiceImpl"%>
<%@ page import="java.util.ArrayList"%>
<%@ page import="java.util.List"%>
<%@ page contentType="text/html;charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>学生表</title>
</head>
<body>
<h3>学生表</h3>
<%
StudentService _StudentService = new StudentServiceImpl();
Student stu = (Student)_StudentService.get(request.getParameter("no")).data;
if (stu == null) {
stu = new Student();
}
%>
<div>
<form
action="<%=String.format("%s/stu/update.jsp", request.getContextPath())%>">
<div>
<label for="no">学号:</label> <input type="text" id="no" name="no"
placeholder="请输入学号.." value="<%=stu.getNo()%>" readonly="true">
</div>
<div>
<label for="name">姓名:</label> <input type="text" id="name"
name="name" placeholder="请输入姓名.." value="<%=stu.getName()%>">
</div>
<div>
<label for="gender">性别:</label> <input type="text" id="gender"
name="gender" placeholder="请输入性别.." value="<%=stu.getGender()%>">
</div>
<div>
<label for="age">年龄:</label> <input type="number" id="age"
name="age" placeholder="请输入年龄.." value="<%=stu.getAge()%>">
</div>
<div>
<label for="dept">所在系:</label> <input type="text" id="dept"
name="dept" placeholder="请输入所在系.." value="<%=stu.getDept()%>">
</div>
<button type="submit">提交</button>
</form>
</div>
</body>
</html>
|
-
创建修改页面:stu/update.jsp
,实现修改功能,参考代码如下:
stu/update.jsp |
---|
| <%@ page import="xust.demo.Result"%>
<%@ page import="xust.demo.stu.domain.Student"%>
<%@ page import="xust.demo.stu.service.StudentService"%>
<%@ page import="xust.demo.stu.service.StudentServiceImpl"%>
<%@ page import="java.util.ArrayList"%>
<%@ page import="java.util.List"%>
<%@ page contentType="text/html;charset=utf-8"%>
<%
StudentService _StudentService = new StudentServiceImpl();
Student stu_new = new Student();
Student o = _StudentService.toO(request);
Result res = _StudentService.update(o);
//操作完成,回到列表
response.sendRedirect(String.format("%s%s", request.getContextPath(), "/stu/list.jsp"));
%>
|
-
创建删除页面:stu/delete.jsp
,实现删除功能,参考代码如下:
stu/delete.jsp |
---|
| <%@ page import="xust.demo.Result"%>
<%@ page import="xust.demo.stu.domain.Student"%>
<%@ page import="xust.demo.stu.service.StudentService"%>
<%@ page import="xust.demo.stu.service.StudentServiceImpl"%>
<%@ page import="java.util.ArrayList"%>
<%@ page import="java.util.List"%>
<%@ page contentType="text/html;charset=utf-8"%>
<%
StudentService _StudentService = new StudentServiceImpl();
Result res = _StudentService.delete(request.getParameter("no"));
//操作完成,回到列表
response.sendRedirect(String.format("%s%s", request.getContextPath(), "/stu/list.jsp"));
%>
|
-
测试全部功能
拓展练习
- 使用JSP实现课程表的增、删、改、查操作