news 2026/11/4 17:45:04

JavaWeb增删改查源码包怎么跑通?从技术栈到部署避坑全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaWeb增删改查源码包怎么跑通?从技术栈到部署避坑全解析

简介:面向JavaWeb初学者的MVC增删改查完整项目源码,基于JSP+Servlet+三层架构演示数据管理流程,适合正在学习Servlet、JSP及JDBC开发的读者。压缩包共40个文件,约920KB,包含9个JSP视图页面、9个Java控制类及对应class编译文件,另有XML配置、SQL脚本等辅助资源,可完整查看页面层与后端逻辑的对应关系。已有3753人学习下载。项目附带shopping.sql数据库脚本,导入后即可运行体验,重点展示新增记录、删除数据、修改字段和条件查询四大功能,帮助读者理解从JSP表单提交、Servlet请求分发到JDBC执行SQL的完整调用链路,同时体会MVC模式如何通过模型层封装数据库操作、视图层呈现数据,是结合理论练习与代码参照的实用学习资料。

1. 一个 javaweb 增删改查源码包,值得你花一个晚上把它跑通

“javaweb 增删改查(含源码).zip”这类压缩包,是后端入门最常见的练手资源:一个能导入 IDEA 直接跑的 Web 项目,自带数据库脚本、页面和后端代码,跑起来就是对一张表做增删改查。我第一次拿到这类包时,以为解压就能看界面,结果花了一晚上配 Tomcat、换 MySQL 驱动、调中文编码,才在浏览器里看到列表页。这个标题真正解决的是:拿到别人写好的 javaweb 增删改查源码后,怎么让它在本机跑通,并且看懂浏览器、Servlet、DAO、MySQL 这条链路的每一环。适合课程设计、刚学完 Servlet 找完整案例对照、以及接手老项目需要快速摸清结构的开发者。

2. 拆开 zip 之前:先看清这套增删改查用什么技术栈在跑

2.1 JSP + Servlet + JDBC:为什么这类 javaweb 项目完整案例还在用这套组合

这类 zip 的解压结构五花八门,但九成能跑的项目都沿着同一个骨架:JSP 负责页面,Servlet 负责接收请求和跳转,JDBC 负责操作 MySQL,Tomcat 负责把组件拉起来。这个组合在 Spring Boot 普及后看起来老,但胜在链路短、依赖少、和教材同步。我见过不少课程设计交的就是这个结构,评审老师也最容易接受。它的价值在于把 Web 开发的骨架暴露得很直白:一个 HTTP 请求从 URL 到数据库,每一层只有一个类,断点打进去就能看到数据怎么流。相比之下 SSM 虽然更接近生产环境,但容器、代理、配置多出几倍,对“跑通增删改查”这个目标来说反而容易被框架细节盖住。

注意:标题里的“源码”并不代表这是多新的项目。多数这类包是 2018 到 2021 年之间的写法,JDK 1.8 + Tomcat 8.5 + MySQL 5.7 是匹配度最高的运行环境,后面章节会反复回到这套组合。

2.2 解压后按顺序看这四个文件:pom.xml、web.xml、数据库脚本、README

拿到 zip 第一件事不是找启动脚本,而是看目录结构。常见结构大概长这样:

javaweb-crud/ ├── README.md # 运行说明:数据库账号、部署顺序 ├── pom.xml # Maven 依赖清单(也可能没有) ├── db/ │ └── user.sql # 数据库初始化脚本 └── src/main/ ├── java/com/example/crud/ │ ├── dao/UserDao.java # 数据访问层,写增删改查 SQL │ ├── entity/User.java # 实体类,对应一张表 │ ├── servlet/UserServlet.java # 请求入口 │ └── util/DBUtil.java # JDBC 连接工具类 └── webapp/ ├── WEB-INF/web.xml # Servlet 映射和欢迎页配置 ├── list.jsp # 列表页 ├── add.jsp # 新增表单页 └── edit.jsp # 编辑表单页

这段目录结构基本覆盖了这类项目的共同骨架。pom.xml存在说明是 Maven 工程,IDEA 导入时选择“作为 Maven 项目打开”,依赖会自动下载;没有也无所谓,传统做法是直接把 jar 包放进WEB-INF/lib。web.xml负责 Servlet 映射,Tomcat 8/9 支持@WebServlet注解,老代码则依赖web.xml,如果两种并存,以web.xml为准。db/user.sql是数据库脚本,必须先导入,否则启动不报错、一查数据就空。README 经常被忽略,但它通常写了数据库账号、Tomcat 版本、需要改哪些配置,我一般第一步就看它,这能省出半小时试错时间。

2.3 选型边界:JDBC 直连和 MyBatis/MyBatis-Plus 的改造成本差多少

拿到源码后,很多人第一反应是“要不要换成 MyBatis”。我的建议是先把原版跑通,再考虑替换,因为两套方案的复杂度差距不小:

对比项JDBC 直连MyBatis / MyBatis-Plus
依赖数量一个 mysql-connector jarmybatis、spring-jdbc 等多个 jar
上手难度低,SQL 写在 Java 里中,要理解 XML 或注解映射
增删改查写法每个表写一套 PreparedStatement继承 BaseMapper 后自带通用 CRUD
课程设计接受度最常见也可以,但需要讲清框架选型

JDBC 直连的好处是你能在代码里看清 SQL 和参数的对应关系,出了问题可以直接在 MySQL 里把 SQL 复制出来跑一遍。对新手来说,这比对着 MyBatis 的 mapper XML 猜映射更直接。标题里的“含源码”通常也指的是这种完整可读的写法,而不是封装好的框架壳子。

3. 数据库与核心代码:把增删改查四个动作写进 DAO 层

3.1 建表 SQL 与连接参数:utf8mb4 和时区两个小细节

增删改查落到数据库层面,就是 INSERT、SELECT、UPDATE、DELETE 四条 SQL。先看初始化脚本,这类项目通常围绕一张业务表展开,比如用户表:

CREATE DATABASE javaweb_crud DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE javaweb_crud; CREATE TABLE `user` ( id INT NOT NULL AUTO_INCREMENT, user_name VARCHAR(50) NOT NULL, password VARCHAR(50) NOT NULL, email VARCHAR(100) DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

这段脚本有两点值得注意:一是库和表都指定utf8mb4,MySQL 8 之前的utf8实际是utf8mb3,存不了生僻字和 Emoji,统一用utf8mb4能从源头避开一类乱码问题;二是表名user虽然不是 MySQL 保留字,但和系统库里的mysql.user同名,我一般会加上反引号user,防止其他工具解析时报错。字段方面,id用自增主键,InnoDB 引擎,这些都是源码包里的普遍写法,不用大改。

连接数据库的工具类 DBUtil 是另一个关键文件,常见写法如下:

package com.example.crud.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBUtil { private static final String URL = "jdbc:mysql://localhost:3306/javaweb_crud" + "?useUnicode=true&characterEncoding=utf8" + "&useSSL=false" + "&serverTimezone=Asia/Shanghai" + "&allowPublicKeyRetrieval=true"; private static final String USER = "root"; private static final String PASSWORD = "123456"; static { try { Class.forName("com.mysql.cj.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }

这段代码里,URL 的后缀参数是踩坑重灾区。useUnicode=true&characterEncoding=utf8保证发给 MySQL 的 SQL 按 UTF-8 编码;serverTimezone=Asia/Shanghai是给 MySQL 8 新驱动用的,不加容易报时区异常;allowPublicKeyRetrieval=true解决 MySQL 8 默认认证插件导致的连接报错。驱动类名也要注意:MySQL 8 的驱动类改成了com.mysql.cj.jdbc.Driver,老代码写com.mysql.jdbc.Driver在 MySQL 8 下会直接 ClassNotFound。

3.2 DAO 层四个方法:参数顺序、返回值设计决定了代码好不好改

DAO(Data Access Object)是这套代码的核心层。以 UserDao 为例,最值得抄的是 findAll 和 add 两个方法:

public List<User> findAll() { List<User> list = new ArrayList<>(); String sql = "SELECT id, user_name, password, email FROM `user` ORDER BY id"; try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery()) { while (rs.next()) { User u = new User(); u.setId(rs.getInt("id")); u.setUserName(rs.getString("user_name")); u.setPassword(rs.getString("password")); u.setEmail(rs.getString("email")); list.add(u); } } catch (SQLException e) { e.printStackTrace(); } return list; } public int add(User user) { String sql = "INSERT INTO `user`(user_name, password, email) VALUES(?, ?, ?)"; try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, user.getUserName()); ps.setString(2, user.getPassword()); ps.setString(3, user.getEmail()); return ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } return 0; }

这里有两个设计习惯值得沿用。第一,SQL 全部用PreparedStatement的?占位符,不拼接字符串,避免 SQL 注入,也省去手动处理单引号转义的麻烦;第二,新增和修改这类写操作返回int,表示受影响行数,调用方通过返回值判断成功还是失败,比返回 boolean 信息量更大。try-with-resources写法会自动关闭 Connection、PreparedStatement、ResultSet,老代码里的手动 close 容易出现连接泄漏,遇到就顺手改掉。update 和 delete 的结构完全一致,只是 SQL 不同,写的时候注意参数顺序和 WHERE 条件的 id 要放对位置就行。

3.3 Servlet 层:转发、重定向与中文编码三个分工

DAO 写完,需要一个入口让浏览器请求到达 DAO。这类项目最常用的做法是一个 UserServlet 统一接收action参数,区分不同操作:

@WebServlet("/user") public class UserServlet extends HttpServlet { private UserDao userDao = new UserDao(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); resp.setContentType("text/html;charset=UTF-8"); String action = req.getParameter("action"); if ("edit".equals(action)) { int id = Integer.parseInt(req.getParameter("id")); req.setAttribute("user", userDao.findById(id)); req.getRequestDispatcher("/edit.jsp").forward(req, resp); } else if ("delete".equals(action)) { int id = Integer.parseInt(req.getParameter("id")); userDao.delete(id); resp.sendRedirect(req.getContextPath() + "/user"); } else { req.setAttribute("userList", userDao.findAll()); req.getRequestDispatcher("/list.jsp").forward(req, resp); } } }

这段逻辑里有两个关键动作:转发和重定向。转发用getRequestDispatcher().forward(),发生在服务端内部,浏览器地址栏不变,适合把查询结果带给 JSP 渲染;重定向用sendRedirect(),会让浏览器重新发起一次请求,适合删除、新增、修改这类写操作,避免用户刷新页面时重复提交。编码方面,每个 Servlet 方法开头都要设置请求和响应编码,否则后面加中文参数时很容易乱码。

对应的列表页 list.jsp 核心片段大概是:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <table border="1"> <tr><th>ID</th><th>用户名</th><th>邮箱</th><th>操作</th></tr> <c:forEach items="${userList}" var="u"> <tr> <td>${u.id}</td> <td>${u.userName}</td> <td>${u.email}</td> <td> <a href="${pageContext.request.contextPath}/user?action=edit&id=${u.id}">编辑</a> <a href="${pageContext.request.contextPath}/user?action=delete&id=${u.id}" onclick="return confirm('确定删除吗?')">删除</a> </td> </tr> </c:forEach> </table>

这里最容易翻车的是链接路径。写<a href="/user?action=edit">在部署上下文不是根路径时会 404,必须用${pageContext.request.contextPath}拼出上下文路径,也就是第四章要配好的 Application context。

4. IDEA 运行 javaweb 项目的完整配置:从导入 zip 到 Tomcat 启动

4.1 两种导入方式:Maven 工程和非 Maven 工程的处理差别

拿到 zip 后,先在 IDEA 里用 Open 打开解压目录。如果根目录有pom.xml,IDEA 会识别成 Maven 工程,右下角弹出依赖导入提示,等它把 jar 下载完即可。如果没有pom.xml,需要手动处理:新建一个空 Java Enterprise 工程,把源码里的src/main/java和src/main/webapp内容分别拷贝到对应目录,再把WEB-INF/lib下的 jar 重新加进模块依赖。这个步骤容易漏的是WEB-INF/lib,因为 IDEA 不会自动把普通文件目录变成依赖,需要右键 lib 目录 → Add as Library。

对非 Maven 老项目,我见过最多的失败原因就是 lib 目录没生效,代码编辑器里不报错,一运行 Tomcat 就 ClassNotFoundException。遇到这种情况,优先确认部署产物的WEB-INF/lib里是否有对应的 jar。

4.2 Tomcat 与 Artifact:上下文路径决定了 404 还是 200

运行 javaweb 项目前,需要先配置 Tomcat 这个容器。在 IDEA 里走 Run → Edit Configurations → 左上角加号 → Tomcat Server → Local,如果列表里没有 Tomcat 选项,先在 Plugins 里确认 Tomcat 插件已启用。Server 页填写 Tomcat 安装目录、JRE 版本和 HTTP 端口,默认 8080。

关键在 Deployment 页。需要把当前 Web 项目添加为 Artifact,并设置 Application context,比如/javaweb-crud。这个值就是浏览器访问时的第一段路径,例如访问http://localhost:8080/javaweb-crud/list.jsp。如果你发现页面一直 404,先看两处是否一致:地址栏里的路径,和 Deployment 页里的 Application context。还要记得在启动前手动 Build → Build Artifacts → Rebuild,否则改过的代码不会进部署产物。

少数使用 Maven 的源码包会在 pom.xml 里配 Tomcat 插件,这时命令行启动更简单:

<plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> <path>/javaweb-crud</path> <uriEncoding>UTF-8</uriEncoding> </configuration> </plugin>

然后在项目根目录执行mvn tomcat7:run。这个插件的名字虽然叫 tomcat7,实际能跑多数 javaweb 老项目。path就是上下文路径,uriEncoding必须设成 UTF-8,否则 Tomcat 解析中文请求参数时可能乱码。这种方式的好处是绕开 IDEA 的 Artifact 配置,适合排查“IDEA 里跑不起来但不确定是代码还是配置问题”的情况。

4.3 数据库前置检查:先命令行验证,再让项目连库

跑项目之前,我习惯先用命令行验证数据库本身是通的,而不是等 Tomcat 报了错才回头查:

mysql -uroot -p123456 -h127.0.0.1 --default-character-set=utf8mb4 use javaweb_crud; source /path/to/user.sql; select * from `user`;

这段命令做了四件事:连接 MySQL、切换数据库、执行建表脚本、查询一次数据。如果select能返回空表,说明数据库侧没有问题了,后面的问题集中在代码和 Tomcat 配置。--default-character-set=utf8mb4很重要,它保证命令行客户端和 MySQL 服务端的字符集一致,避免手动插入测试中文数据时变问号。

驱动 jar 方面,MySQL 8 对应的是mysql-connector-java-8.0.x.jar,里面同时兼容com.mysql.cj.jdbc.Driver。如果源码包里只有旧的 5.1.x jar,可以先替换 jar,再改 DBUtil 里的驱动类名和 URL 参数,这两处不匹配,项目必然在获取连接时报错。

5. 避坑:源码跑不通,八成是 Tomcat、驱动和编码在打架

5.1 现象:Tomcat 启动成功,页面却 404

这是最挫败的场景:控制台一堆启动日志,浏览器打开却是一整页 404。原因通常有两个,一是 IDEA 的 Artifact 没有真正部署,二是访问路径和应用上下文不匹配。解决时先看 Deployment 页确认 Artifact 已添加,再看地址栏是否带着上下文路径。我排查时会直接在浏览器输入http://localhost:8080/javaweb-crud/list.jsp,如果还 404,就去 Tomcat 的 webapps 目录看有没有生成对应的部署文件夹。老项目里还有一个小概率原因:web.xml 里配置的欢迎页是index.jsp,但这个文件根本不存在。

5.2 现象:ClassNotFoundException: com.mysql.jdbc.Driver

这个报错十有八九是 MySQL 版本和驱动类名不匹配。MySQL 8.0 之后驱动类名变成了com.mysql.cj.jdbc.Driver,而老源码里普遍写的是com.mysql.jdbc.Driver。解决方法是二选一:把 DBUtil 的Class.forName改成新类名,同时把驱动 jar 换成 8.x 版本;或者把数据库降级到 MySQL 5.7,继续沿用旧驱动。我建议直接升到 MySQL 8,因为本机数据库通常不只服务这个项目,新版驱动也修复了老版本的一些连接问题。

5.3 现象:插入中文后数据库里显示问号

中文乱码是 javaweb 项目最经典的坑,本质是链路里某一环的编码不是 UTF-8。至少四个地方要统一:JSP 页面开头的pageEncoding="UTF-8"、Servlet 里的request.setCharacterEncoding("UTF-8")、Tomcat 的server.xml里 Connector 加URIEncoding="UTF-8"、JDBC URL 里带characterEncoding=utf8。如果四选一漏了,表现可能是列表页正常但新增乱码,或者新增正常但编辑乱码。我一般会把上述四处全部改完再跑一次,而不是只改一处反复试。数据库表字符集也要用utf8mb4,这在一开始的建表脚本里已经提到。

5.4 现象:form 表单提交后 404,但列表页打开正常

增删改查里的“增”和“改”都依赖 form 提交。老源码里的 form 或链接如果写死了/user,在部署上下文为/javaweb-crud时会错位,因为请求实际去了http://localhost:8080/user,而不是http://localhost:8080/javaweb-crud/user。解决方式是所有页面内链接都加上${pageContext.request.contextPath}前缀,Servlet 重定向时用req.getContextPath()拼接。这也是我拿到源码后最先全局搜索的地方,搜索action="/和href="/基本能定位全部问题点。

5.5 现象:MySQL 8 连接时报 Public Key Retrieval is not allowed

这个报错只出现在 MySQL 8 + 新驱动组合下。MySQL 8 默认使用caching_sha2_password认证插件,非 SSL 连接下驱动需要先请求公钥,但又默认不允许这个动作,于是报错。解决最快的方式是在 JDBC URL 追加两个参数:allowPublicKeyRetrieval=true&useSSL=false。如果项目用的是连接池,参数同样要加在数据源 URL 里。改完重启 Tomcat,问题一般就消失。这个坑和代码逻辑无关,纯粹是新版本驱动在使用习惯上的变化。

6. 跑通之后这样验收:四类操作各做一遍,再看把 DAO 换成通用 CRUD

项目跑起来不代表完事,我习惯按真实用户路径验收一遍:先在新增页提交一条含中文的数据,回列表页确认这条数据出现;再点编辑,确认表单回显了刚才填的内容,改一个字段保存,列表页同步变化;最后点删除,确认弹窗确认后列表少了一条。到这一步,程序的“增删改查”闭环才算真正验证完。接着去 MySQL 命令行执行select * from user;,对比页面显示和数据表内容,确认编码、主键自增都正常。这四步里任何一步卡住,都值得回到对应章节排查。

验收通过后,如果想把这份 javaweb 源码做得更接近生产环境,我建议从 DAO 层下手。JDBC 直连的代码里,每个实体都要重复写增删改查的 PreparedStatement,模板化严重。可以引入 MyBatis-Plus,让 Mapper 接口直接继承 BaseMapper,获得现成的通用 CRUD 方法:

import com.baomidou.mybatisplus.core.mapper.BaseMapper; public interface UserMapper extends BaseMapper<User> { }

这样selectById、insert、updateById、deleteById这些无状态增删改查方法都不用手写 SQL,主键由框架自动填充。但我建议不要在大作业里直接替换,先把它作为一个独立分支做,等熟悉了项目的原有逻辑再合并。我的习惯是拿到任何源码包,第一件事永远是看 README 和数据库脚本,先跑通再改代码,这个顺序能少走一半弯路。折腾一晚上之后你会发现,这套看似老的 javaweb 增删改查,反而是理解 Web 项目生命周期最好的教材。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/2 10:18:27

法律文书NER实战:BERT+BiLSTM+CRF抽取交通肇事案事件要素

简介&#xff1a;一份面向法律文本挖掘与自然语言处理学习者的完整项目包&#xff0c;基于BERTBiLSTMCRF实现法律文书命名实体识别&#xff0c;并针对交通肇事案进行事件要素抽取&#xff0c;适合用作课程设计、期末大作业或毕设参考资料。压缩包共48个文件、约693KB&#xff0…

作者头像 李华
网站建设 2026/10/25 8:06:53

一份国赛样题zip如何变成一套可复现的配置链路?

简介&#xff1a;面向职业院校网络竞赛选手与指导教师的2019年网络搭建与应用国赛样题一参考答案包&#xff0c;基于神州数码设备环境&#xff0c;覆盖路由、交换、防火墙及无线AC等关键配置。资源共42个文件&#xff0c;约153MB&#xff0c;包含txt设备配置答案、Python自动化…

作者头像 李华
网站建设 2026/11/4 8:04:39

OpenAI接口演进:从Chat到Responses兼容实践

最近在排查内部网关日志时&#xff0c;又看到一行让人血压升高的报错&#xff1a;unexpected endpoint or method. (POST /chat/completions)。这不是我第一次遇到它&#xff0c;也不会是最后一次。说实话&#xff0c;OpenAI 的接口规范演进速度比大多数人的认知要快&#xff1…

作者头像 李华
网站建设 2026/11/3 19:31:25

TL082运放DIY非线性负阻抗电路:原理、设计与实测

1. 从一块TL082说起&#xff1a;为什么我要折腾非线性负阻抗 手头攒了一堆TL082&#xff0c;这玩意儿是老牌双运放&#xff0c;JFET输入级&#xff0c;输入阻抗高、偏置电流小&#xff0c;价格便宜到按斤称都不心疼。很多人拿它做音频前级、做滤波器&#xff0c;但我一直想用它…

作者头像 李华
网站建设 2026/10/24 8:38:47

实时搜索如何重塑 AI 工作流?从信息收集到决策辅助的实战拆解

最近一段时间&#xff0c;我身边不少朋友的工作方式正在悄悄起变化&#xff1a;写方案之前不先去搜资料&#xff0c;而是先打开 AI 对话框&#xff1b;处理一堆重复的邮件和文档&#xff0c;不再自己手动复制粘贴&#xff0c;而是丢给一个自动化流程&#xff1b;甚至连每天早上…

作者头像 李华
网站建设 2026/10/23 22:56:45

零依赖与WebRTC P2P:网页小游戏联机架构实战白皮书

我最近把网页小游戏合集项目 OmniGame 从零重构了一遍&#xff0c;从立项第一天起就给自己上了两条硬约束&#xff1a;运行时零依赖&#xff0c;联机能走 WebRTC P2P 就绝不绕服务器中转。先把这俩约束摆出来&#xff0c;是因为网页小游戏这个品类太容易走上“为了省事堆依赖”…

作者头像 李华