JSP+Servlet实现对数据库增删改查功能
前提概要
需要理解的重要概念
-
MVC模式:
- Model(person类):数据模型
- View(JSP):显示界面
- Controller(Servlet):处理业务逻辑
-
请求流程:
浏览器 → Servlet → 数据库 → JSP → 浏览器 -
两种跳转方式:
- 转发(forward):服务器内部跳转,地址栏不变
- 重定向(redirect):告诉浏览器重新请求,地址栏变化
-
数据库操作步骤:
加载驱动 → 获取连接 → 创建语句 → 执行SQL → 处理结果 → 关闭连接
代码框架:

一、Person类
Person类:
这个类的作用:
- 就像"用户信息模板",每个person对象对应数据库中的一条用户记录
- 包含三个属性:
- id:用户唯一标识
- name:用户名
- pwd:密码
- Getter/Setter方法用于外部访问这些私有属性(Java封装的特性)
package com.Person;public class person {private int id;private String name;private String pwd;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPwd() {return pwd;}public void setPwd(String pwd) {this.pwd = pwd;} } -
二、Servlet类
AddServlet类
- 用户访问/add,GET请求会跳转到add.jsp(显示表单)
- 用户提交表单时(POST请求):
- 接收用户名和密码
- 连接数据库并插入新用户
- 成功后自动跳转到用户列表页
package com.servlet;import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.sql.*;@WebServlet(name = "AddServlet", urlPatterns = "/add")
public class AddServlet extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.sendRedirect("add.jsp"); // 跳转到添加页面}protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {request.setCharacterEncoding("UTF-8");String name = request.getParameter("username");String pwd = request.getParameter("userpwd");try {Class.forName("com.mysql.cj.jdbc.Driver");Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/users?useSSL=false&serverTimezone=UTC", "root", "cjl");PreparedStatement statement = connection.prepareStatement("INSERT INTO person (name, pwd) VALUES (?, ?)");statement.setString(1, name);statement.setString(2, pwd);statement.executeUpdate();response.sendRedirect("listall"); // 添加成功跳转列表statement.close();connection.close();} catch (Exception e) {e.printStackTrace();}}
}
ListAllServlet类:
- 查询数据库获取所有用户
- 把每个用户数据封装成person对象
- 把用户列表存入request(就像把数据装进快递盒)
- 转发到list.jsp显示(快递员把盒子送到JSP)
package com.servlet;import com.Person.person; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException; import java.sql.*; import java.util.ArrayList; import java.util.List;@WebServlet(name = "ListAllServlet", urlPatterns = "/listall") public class ListAllServlet extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {try {Class.forName("com.mysql.cj.jdbc.Driver");Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/users?useSSL=false&serverTimezone=UTC", "root", "cjl");Statement statement = connection.createStatement();ResultSet resultSet = statement.executeQuery("SELECT * FROM person");// 将数据存入 List<person>List<person> userList = new ArrayList<>();while (resultSet.next()) {person p = new person();p.setId(resultSet.getInt("id")); // 确保列名与数据库一致p.setName(resultSet.getString("name"));p.setPwd(resultSet.getString("pwd"));userList.add(p);}// 关键修复点:将数据存入 request 并转发到 JSPrequest.setAttribute("userList", userList);request.getRequestDispatcher("/list.jsp").forward(request, response);// 关闭资源resultSet.close();statement.close();connection.close();} catch (Exception e) {e.printStackTrace();response.getWriter().println("数据库错误,请检查控制台日志");}} }DeleteServlet类
- 通过URL参数获取要删除的用户id(如/del?id=3)
- 执行数据库删除操作
- 完成后跳回列表页
package com.servlet;import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException; import java.sql.*;@WebServlet(name = "DeleteServlet", urlPatterns = "/del") public class DeleteServlet extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String id = request.getParameter("id");try {Class.forName("com.mysql.cj.jdbc.Driver");Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/users?useSSL=false&serverTimezone=UTC", "root", "cjl");PreparedStatement statement = connection.prepareStatement("DELETE FROM person WHERE id=?");statement.setInt(1, Integer.parseInt(id));statement.executeUpdate();response.sendRedirect("listall"); // 直接跳转,不处理失败情况statement.close();connection.close();} catch (Exception e) {e.printStackTrace();}} }UpdateServlet类(显示修改页面):
- 根据id查询要修改的用户
- 把用户数据传给update.jsp显示在表单里
package com.servlet;import com.Person.person; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException; import java.sql.*;@WebServlet(name = "UpdateServlet", urlPatterns = "/update") public class UpdateServlet extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String id = request.getParameter("id");if (id == null || id.isEmpty()) {response.sendRedirect("error.jsp?msg=Invalid+ID");return;}Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try {Class.forName("com.mysql.cj.jdbc.Driver");connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/users?useSSL=false&serverTimezone=UTC", "root", "cjl");statement = connection.prepareStatement("SELECT * FROM person WHERE id=?");statement.setInt(1, Integer.parseInt(id));resultSet = statement.executeQuery();if (resultSet.next()) {person p = new person();p.setId(resultSet.getInt("id"));p.setName(resultSet.getString("name"));p.setPwd(resultSet.getString("pwd"));request.setAttribute("user", p);} else {response.sendRedirect("error.jsp?msg=User+not+found");return;}request.getRequestDispatcher("/update.jsp").forward(request, response);} catch (ClassNotFoundException | SQLException e) {e.printStackTrace();response.sendRedirect("error.jsp?msg=Database+error");} finally {try {if (resultSet != null) resultSet.close();if (statement != null) statement.close();if (connection != null) connection.close();} catch (SQLException e) {e.printStackTrace();}}} }UpdateDoServlet类(处理修改提交)
- 接收修改后的用户名和密码
- 执行数据库更新操作
- 返回列表页
package com.servlet;import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException; import java.sql.*;@WebServlet(name = "UpdateDoServlet", urlPatterns = "/updateDo") public class UpdateDoServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {request.setCharacterEncoding("UTF-8");String id = request.getParameter("id");String name = request.getParameter("username");String pwd = request.getParameter("userpwd");try {Class.forName("com.mysql.cj.jdbc.Driver");Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/users?useSSL=false&serverTimezone=UTC", "root", "cjl");PreparedStatement statement = connection.prepareStatement("UPDATE person SET name=?, pwd=? WHERE id=?");statement.setString(1, name);statement.setString(2, pwd);statement.setInt(3, Integer.parseInt(id));statement.executeUpdate();response.sendRedirect("listall"); // 直接跳转列表statement.close();connection.close();} catch (Exception e) {e.printStackTrace();}} }Q:为什么修改用户要分成两个Servlet?
A:一个负责显示修改页面(GET),一个处理修改提交(POST),符合单一职责原则
三、JSP
add页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>新增用户</title>
</head>
<body>
<h1>新增用户</h1>
<form action="add" method="post">姓名:<input type="text" name="username"><br>密码:<input type="password" name="userpwd"><br><input type="submit" value="提交">
</form>
</body>
</html>
list 页面
<%@ page import="com.Person.person" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>用户列表</title>
</head>
<body>
<h1>用户列表</h1>
<a href="add">新增用户</a>
<table border="1"><tr><th>ID</th><th>姓名</th><th>密码</th><th>操作</th></tr><%List<person> userList = (List<person>) request.getAttribute("userList");if (userList != null) {for (person user : userList) {%><tr><td><%= user.getId() %></td><td><%= user.getName() %></td><td><%= user.getPwd() %></td><td><a href="del?id=<%= user.getId() %>">删除</a><a href="update?id=<%= user.getId() %>">修改</a></td></tr><%}} else {%><tr><td colspan="4">暂无用户数据</td></tr><% } %>
</table>
</body>
</html>
update页面
<%@ page import="com.Person.person" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>修改用户</title>
</head>
<body>
<h1>修改用户信息</h1>
<%person user = (person) request.getAttribute("user");if (user != null) {%>
<form action="updateDo" method="post"><input type="hidden" name="id" value="<%= user.getId() %>">姓名:<input type="text" name="username" value="<%= user.getName() %>"><br>密码:<input type="password" name="userpwd" value="<%= user.getPwd() %>"><br><input type="submit" value="提交修改">
</form>
<% } else { %>
<p>错误:用户信息不存在!</p>
<% } %>
</body>
</html>
error页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>错误页面</title>
</head>
<body>
<h1>错误:<%= request.getParameter("msg") %></h1>
<a href="listall">返回用户列表</a>
</body>
</html>
相关文章:
JSP+Servlet实现对数据库增删改查功能
前提概要 需要理解的重要概念 MVC模式: Model(person类):数据模型View(JSP):显示界面Controller(Servlet):处理业务逻辑 请求流程: 浏览器 …...
C++【类和对象】
类和对象 1.this 指针2.类的默认成员函数3.构造函数4.析构函数5.拷贝构造函数 1.this 指针 接上文 this指针存在内存的栈区域。 2.类的默认成员函数 定义:编译器自动生成的成员函数。一个类,我们不写的情况下会默认生成六个成员函数。 3.构造函数 函…...
GStreamer —— 2.13、Windows下Qt加载GStreamer库后运行 - “教程13:播放控制“(附:完整源码)
运行效果(音频) 简介 上一个教程演示了GStreamer工具。本教程介绍视频播放控制。快进、反向播放和慢动作都是技术 统称为 Trick Modes,它们都有一个共同点 修改 Normal playback rate。本教程介绍如何实现 这些效果并在交易中添加了帧步进。特别是,它 显…...
MongoDB winx64 msi包安装详细教程
首先我们可以从官网上选择对应版本和对应的包类型进行安装: 下载地址:Download MongoDB Community Server | MongoDB 这里可以根据自己的需求, 这里我选择的是8.0.5 msi的版本,采用的传统装软件的方式安装。无需配置命令。 下载…...
要查看 SQLite 数据库中的所有表,可以通过查询 SQLite 的系统表 sqlite_master
要查看 SQLite 数据库中的所有表,可以查询 SQLite 的系统表 sqlite_master。 每个 SQLite 数据库都包含一个名为 sqlite_master 的系统表。该表定义了数据库的模式,存储了数据库中所有表、索引、视图和触发器等对象的信息。 通过查询 sqlite_master&am…...
WinUI 3 支持的三种窗口 及 受限的窗口透明
我的目标 希望能够熟悉 WinUI 3 窗口的基本使用方式,了解可能出现的问题 。 WinUI 3 支持三种窗口模式,分别为:常规窗口模式、画中画模式、全屏模式。 窗口模式:常规 即我们最常见的普通窗口。 支持:显示最大化按钮…...
如何借助 ArcGIS Pro 高效统计基站 10km 范围内的村庄数量?
在当今数字化时代,地理信息系统(GIS)技术在各个领域都发挥着重要作用。 特别是在通信行业,对于基站周边覆盖范围内的地理信息分析,能够帮助我们更好地进行网络规划、资源分配以及市场分析等工作。 今天,就…...
Linux网络之数据链路层协议
目录 数据链路层 MAC地址与IP地址 数据帧 ARP协议 NAT技术 代理服务器 正向代理 反向代理 上期我们学习了网络层中的相关协议,为IP协议。IP协议通过报头中的目的IP地址告知了数据最终要传送的目的主机的IP地址,从而指引了数据在网络中的一步…...
如何使用 PyInstaller 打包 Python 脚本?一看就懂的完整教程!
PyInstaller 打包指令教程 1. 写在前面 通常,在用 Python 编写完一个脚本后,需要将它部署并集成到一个更大的项目中。常见的集成方式有以下几种: 使用 PyInstaller 打包。使用 Docker 打包。将 Python 嵌入到 C 代码中,并封装成…...
解锁DeepSpeek-R1大模型微调:从训练到部署,打造定制化AI会话系统
目录 1. 前言 2.大模型微调概念简述 2.1. 按学习范式分类 2.2. 按参数更新范围分类 2.3. 大模型微调框架简介 3. DeepSpeek R1大模型微调实战 3.1.LLaMA-Factory基础环境安装 3.1大模型下载 3.2. 大模型训练 3.3. 大模型部署 3.4. 微调大模型融合基于SpirngBootVue2…...
Hadoop、Hive、Spark的关系
Part1:Hadoop、Hive、Spark关系概览 1、MapReduce on Hadoop 和spark都是数据计算框架,一般认为spark的速度比MR快2-3倍。 2、mapreduce是数据计算的过程,map将一个任务分成多个小任务,reduce的部分将结果汇总之后返回。 3、HIv…...
基于VMware虚拟机的Ubuntu22.04系统安装和配置(新手保姆级教程)
文章目录 一、前期准备1. 硬件要求2. 软件下载2-1. 下载虚拟机运行软件 二、安装虚拟机三、创建 Ubuntu 系统虚拟机四、Ubuntu 系统安装过程的配置五、更换国内镜像源六、设置静态 IP七、安装常用软件1. 编译工具2. 代码管理工具3. 安装代码编辑软件(VIM)…...
Python|基于DeepSeek大模型,自动生成语料数据(10)
前言 本文是该专栏的第10篇,后面会持续分享AI大模型干货知识,记得关注。 在本专栏之前,笔者在文章《Python|基于DeepSeek大模型,实现文本内容仿写(8)》中,有详细介绍通过Python+DeepSeek大模型,实现对目标文本内容的仿写。 而在本文中,笔者将基于DeepSeek大模型,通…...
基于SpringBoot的历史馆藏系统设计与实现(源码+SQL脚本+LW+部署讲解等)
专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…...
蓝桥杯[每日两题] 真题:好数 神奇闹钟 (java版)
题目一:好数 题目描述 一个整数如果按从低位到高位的顺序,奇数位(个位、百位、万位 )上的数字是奇数,偶数位(十位、千位、十万位 )上的数字是偶数,我们就称之为“好数”。给定…...
基于BMO磁性细菌优化的WSN网络最优节点部署算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 无线传感器网络(Wireless Sensor Network, WSN)由大量分布式传感器节点组成,用于监测物理或环境状况。节点部署是 WSN 的关键问…...
学习笔记:Python网络编程初探之基本概念(一)
一、网络目的 让你设备上的数据和其他设备上进行共享,使用网络能够把多方链接在一起,然后可以进行数据传递。 网络编程就是,让在不同的电脑上的软件能够进行数据传递,即进程之间的通信。 二、IP地址的作用 用来标记唯一一台电脑…...
Laya中runtime的用法
文章目录 0、环境:2.x版本1、runtime是什么2、使用实例情景需要做 3、script组件模式 0、环境:2.x版本 1、runtime是什么 简单来说,如果创建了一个scene,加了runtime和没加runtime的区别就是: 没加runtimeÿ…...
Docker中GPU的使用指南
在当今的计算领域,GPU(图形处理单元)已经成为了加速各种计算密集型任务的关键硬件,特别是在深度学习、科学模拟和高性能计算等领域。Docker作为流行的容器化平台,允许开发者将应用程序及其依赖打包成一个可移植的容器,在不同的环境中运行。当需要在Docker容器中利用GPU的…...
OpenCV计算摄影学(16)调整图像光照效果函数illuminationChange()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 对选定区域内的梯度场应用适当的非线性变换,然后通过泊松求解器重新积分,可以局部修改图像的表观照明。 cv::illuminati…...
【爬虫】开篇词
一、网络爬虫概述 二、网络爬虫的应用场景 三、爬虫的痛点 四、需要掌握哪些技术? 在这个信息爆炸的时代,如何高效地获取和处理海量数据成为一项核心技能。无论是数据分析、商业情报、学术研究,还是人工智能训练,网络爬虫&…...
C#变量与变量作用域详解
一、变量基础 1. 声明与初始化 声明语法:<数据类型> <变量名>(如 int age; string name)初始化要求: 1、 类或结构体中的字段变量(全局变量)无需显式初始化,默认值…...
深度解析 slabtop:实时监控内核缓存的利器
文章目录 深度解析 slabtop:实时监控内核缓存的利器slabtop 简介基本语法与选项命令语法主要选项详解 实际应用实例示例 1:每 5 秒刷新显示 slab 缓存信息示例 2:按名称排序,每 10 秒刷新一次显示 slab 缓存信息 如何解读 slabtop…...
力扣-股票买入问题
dp dp元素代表最大利润 f[j][1] 代表第 j 次交易后持有股票的最大利润。在初始状态,持有股票意味着你花钱买入了股票,此时的利润应该是负数(扣除了买入股票的成本),而不是 0。所以,把 f[j][1] 初始化为负…...
微服务保护:Sentinel
home | Sentinelhttps://sentinelguard.io/zh-cn/ 微服务保护的方案有很多,比如: 请求限流 线程隔离 服务熔断 服务故障最重要原因,就是并发太高!解决了这个问题,就能避免大部分故障。当然,接口的并发…...
蓝桥杯刷题周计划(第二周)
目录 前言题目一题目代码题解分析 题目二题目代码题解分析 题目三题目代码题解分析 题目四题目代码题解分析 题目五题目代码题解分析 题目六题目代码题解分析 题目七题目代码题解分析 题目八题目题解分析 题目九题目代码题解分析 题目十题目代码题解分析 题目十一题目代码题解分…...
【C++】C++11部分
目录 一、列表初始化 1.1 {}初始化 1.2 initializer_list 二、变量类型推导 2.1 auto 2.2 decltype 三、STL中一些变化 3.1 新增容器 四、lambda表达式 4.1 C98中的一个例子 4.2 lambda表达式 4.3 函数对象与lambda表达式 五、包装器 5.1 function包装器 5.2 fu…...
【分布式】聊聊分布式id实现方案和生产经验
对于分布式Id来说,在面试过程中也是高频面试题,所以主要针对分布式id实现方案进行详细分析下。 应用场景 对于无论是单机还是分布式系统来说,对于很多场景需要全局唯一ID, 数据库id唯一性日志traceId 可以方便找到日志链&#…...
[MERN] 使用 socket.io 实现即时通信功能
[MERN] 使用 socket.io 实现即时通信功能 效果实现如下: MERN-socket.io 实现即时聊天 Github 项目地址:https://github.com/GoldenaArcher/messenger-mern 项目使用了 MERN(MongoDB, Express, React, Node.js) socket.io 实现即时通信功能,并且使用了…...
c#面试题整理6
1.String类能否被继承,为什么 可以看到String类的修饰符是sealed,即是密封类,故不可被继承 2.一个对象的方法是否只能由一个线程访问 不是,但是可通过同步机制,确保同一个时间只有一个线程访问 3.计算2*8ÿ…...
