ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Java Web员工管理系统:Servlet+JSP+JDBC实战指南

Java Web员工管理系统:Servlet+JSP+JDBC实战指南 简介这是一套面向Java Web初学者与进阶开发者的员工管理系统实战源码资源聚焦Servlet、JSP、JDBC及MVC分层架构的综合应用帮助开发者掌握企业级Web应用从数据库设计到前后端交互的完整开发流程。压缩包共246个文件包含50个核心Java源文件如Emploe、DeptDaoImpl等业务类、28个JSP页面实现员工信息增删改查、部门管理等前端视图、102个编译后Class文件以及SQL建库脚本、web.xml配置、项目元数据.project/.classpath和静态资源PNG/JPG/GIF整体仅2.45MB轻量易部署。已有1086人学习下载资源结构清晰src目录按包组织业务逻辑WebContent承载视图与配置database提供可直接导入的MySQL脚本配合完整DAO层实现与Manager/EmploeUpdate等典型控制器类便于理解分层协作与CRUD实践。1. 为什么一个“Java Web员工管理系统”压缩包至今仍是校招面试官手里的压轴题你打开这个名为java web员工管理系统(源码数据库).zip的压缩包时看到的不只是几个.java文件和一个.sql脚本——它是一套被反复验证过的、能跑通「增删改查→权限控制→页面跳转→数据持久化」全链路的最小可行闭环。不是 Spring Boot 自动装配的黑匣子不是 Vue Axios 的前端胶水逻辑而是用 Servlet JSP JDBC MySQL 原生堆出来的、每行代码都暴露在请求生命周期里的老派扎实感。它解决的不是“高并发”或“分布式事务”而是当一个刚学完 JDBC 连接池、还没搞懂 Filter 和 Listener 区别的学生如何在 3 天内把课本上的 DAO 模式真正焊进浏览器地址栏里适合 Java 初学者做课程设计、转岗者补 Web 开发手感、面试前复盘 MVC 分层逻辑——尤其当你被问到“请手写一个用户登录校验流程”时这个项目里LoginServlet.doPost()里那 12 行带request.getSession().setAttribute()的代码就是你的后悔药。2. 从解压到启动用最原始的方式跑通这个系统不依赖任何 IDE 插件这个压缩包的结构非常典型src/下是 Java 源码WebContent/或webapp/下是 JSP 和静态资源db/或根目录下有.sql文件。它默认面向 Tomcat 7–9不带 Maven 依赖声明意味着你要亲手把 jar 包塞进WEB-INF/lib/。这不是缺陷是刻意为之——它逼你直面 ClassLoader 加载顺序、web.xml的servlet-mapping如何劫持 URL、以及为什么jdbc:mysql://localhost:3306/emp?useSSLfalseserverTimezoneUTC里那个serverTimezoneUTC少了就会报java.sql.SQLException: The server time zone value XXX is unrecognized。2.1 解压与目录结构确认先看清“战场”解压后务必确认以下三个核心目录是否存在且内容合理src/应包含com.emp.dao/DAO 层、com.emp.servlet/Servlet 层、com.emp.entity/实体类等标准包结构WebContent/或webapp/必须有index.jsp首页、login.jsp登录页、list.jsp员工列表页以及WEB-INF/web.xmldb/或根目录应有一个.sql文件如emp_system.sql内容以CREATE DATABASE IF NOT EXISTS emp_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;开头。提示如果src/下全是.class文件而非.java说明你拿到的是编译后版本——立刻放弃这不是你要的“源码”。真正的源码包src/里每个.java文件都该有package com.emp.xxx;声明和清晰的import列表。2.2 数据库初始化别让ClassNotFoundException出现在建表之前先启动 MySQL5.7 或 8.0然后执行 SQL 脚本。关键动作不是直接source emp_system.sql而是先创建数据库并指定编码mysql -u root -pCREATE DATABASE emp_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE emp_system; SOURCE /path/to/emp_system.sql;为什么强调utf8mb4因为员工姓名可能含 emoji 或生僻字如“䶮”、“堃”utf8在 MySQL 8.0 中已被标记为 deprecated且实际只支持 3 字节 UTF-8utf8mb4才是完整四字节支持。若建库时漏掉后续插入中文会报Incorrect string value而错误堆栈里根本不会提示编码问题只会卡在PreparedStatement.executeUpdate()。执行后用SELECT * FROM employee;确认有测试数据通常含id1, name张三, dept技术部, salary8000等。这步验证通过才代表数据库层已就绪。2.3 Tomcat 部署手动拷贝 WAR 包比 IDE 一键部署更能暴露问题不要用 Eclipse/IntelliJ 的 “Run on Server” 功能——它会自动帮你生成context.xml、注入 JVM 参数、甚至悄悄替换web.xml版本号。我们要的是“裸机部署”将整个项目文件夹如emp-system/重命名为emp-system不能含中文、空格、特殊符号拷贝到TOMCAT_HOME/webapps/目录下启动 TomcatTOMCAT_HOME/bin/startup.shLinux/Mac或startup.batWindows观察TOMCAT_HOME/logs/catalina.out等待出现INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory。逻辑说明Tomcat 启动时会扫描webapps/将文件夹名作为 Context Path。emp-system/部署后访问地址就是http://localhost:8080/emp-system/。如果首页打不开第一反应不是查 JSP 语法而是看 catalina.out 里有没有SEVERE: Error filterStart或Caused by: java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver——这说明 MySQL 驱动没放对位置。2.4 驱动 Jar 包落位WEB-INF/lib/是唯一合法的“藏身之处”下载mysql-connector-java-8.0.33.jar适配 MySQL 8.0或mysql-connector-java-5.1.47.jar适配 MySQL 5.7必须放入emp-system/WEB-INF/lib/目录下而不是TOMCAT_HOME/lib/。原因Servlet 规范要求 Web 应用的类加载器WebAppClassLoader优先从WEB-INF/lib/加载这是应用级隔离的基础。若放错位置会出现两种诡异现象Class.forName(com.mysql.cj.jdbc.Driver)成功但DriverManager.getConnection(...)报No suitable driver found驱动类被加载但 DriverManager 未注册或者更隐蔽的Connection对象能获取但执行executeQuery(SELECT * FROM employee)时抛SQLException: Unknown system variable query_cache_size驱动版本与 MySQL 版本不匹配。验证方式启动后访问http://localhost:8080/emp-system/login.jsp输入默认账号常见为admin/123456若跳转到list.jsp且显示员工表格则 JDBC 层打通。3. 代码层拆解看懂这个系统如何用原生 Servlet 实现 MVC 分层这个项目的价值不在功能多炫酷而在它用最朴素的方式实现了教科书级的分层entity存数据结构dao封装 SQLservlet当控制器jsp做视图。没有 Spring 的Autowired注入所有对象靠new创建没有 MyBatis 的 XML 映射SQL 字符串硬编码在EmployeeDao.java里。这种“笨功夫”恰恰是理解 Web 容器工作原理的必经之路。3.1 Entity 层为什么private Integer id;比private int id;更安全查看src/com/emp/entity/Employee.java你会发现主键字段声明为private Integer id; private String name; private String department; private Double salary;而非int id、double salary。原因在于数据库中id允许为 NULL新增员工时主键由数据库自增Java 对象初始值应为 null而非 0。若用基本类型new Employee()后id0插入时会违反主键约束或覆盖已有 ID。同理salary可能为空如实习生未定薪Double可为null而double强制为0.0导致业务语义丢失。参数说明Integer是int的包装类支持null值JDBC 的rs.getInt(id)若数据库值为 NULL会返回0但rs.getObject(id, Integer.class)则返回null——所以 DAO 层读取时必须用后者否则空值会被误转为0。3.2 DAO 层PreparedStatement的占位符不是摆设是防 SQL 注入的最后防线打开src/com/emp/dao/EmployeeDao.java查找insert(Employee emp)方法public boolean insert(Employee emp) { String sql INSERT INTO employee(name, department, salary) VALUES(?, ?, ?); try (Connection conn JdbcUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, emp.getName()); ps.setString(2, emp.getDepartment()); ps.setDouble(3, emp.getSalary()); return ps.executeUpdate() 0; } catch (SQLException e) { e.printStackTrace(); return false; } }注意三点SQL 字符串里用?占位而非 emp.getName() 拼接——这是防 SQL 注入的基石ps.setString(1, ...)的参数索引从 1 开始不是 0且类型严格匹配name是VARCHAR必须用setStringtry-with-resources自动关闭Connection和PreparedStatement避免连接泄漏。逻辑说明若此处写成sql INSERT INTO employee(name,...) VALUES( emp.getName() ,...)当emp.getName()为张三; DROP TABLE employee; --时整条 SQL 变成INSERT ... VALUES(张三; DROP TABLE employee; --,...)数据库会执行恶意语句。而PreparedStatement会将?参数作为纯数据传给 MySQL ServerServer 不会将其解析为 SQL 语法。3.3 Servlet 层request.getParameter()的返回值永远要判空这是血泪经验LoginServlet.java的doPost方法里必然有String username request.getParameter(username); String password request.getParameter(password); if (username null || username.trim().isEmpty() || password null || password.trim().isEmpty()) { request.setAttribute(msg, 用户名或密码不能为空); request.getRequestDispatcher(login.jsp).forward(request, response); return; }为什么username.trim().isEmpty()不可省略因为 HTML 表单提交时若用户只敲空格再提交getParameter返回 含空格字符串 null为 false但业务上它仍是无效输入。若不trim()会导致username.equals(admin)为 false登录失败却无提示。参数说明request.getParameter()在参数不存在时返回null存在但为空字符串时返回存在且含空格时返回 。三者必须分别处理否则NullPointerException或逻辑漏洞必然出现。3.4 JSP 层EL 表达式${employee.name}背后是pageContext.findAttribute()的查找链list.jsp中遍历员工列表c:forEach items${requestScope.employees} varemp tr td${emp.id}/td td${emp.name}/td td${emp.department}/td td${emp.salary}/td /tr /c:forEach这里${emp.name}能工作是因为Servlet 中request.setAttribute(employees, empList)将 List 放入 request 域JSP 容器在解析 EL 时对emp变量调用pageContext.findAttribute(emp)该方法按page → request → session → application顺序查找emp是c:forEach的var属于 page 域所以能直接访问其 getter 方法getname()→getName()。注意若Employee类中getName()方法抛出异常如 NPEJSP 页面会显示???而非堆栈调试困难。因此 DAO 层返回的Employee对象所有字段必须确保非 null如department为null时emp.getDepartment()返回null${emp.department}输出空字符串安全。4. 避坑指南那些让新手调试到凌晨三点的“玄学”错误这个项目看似简单但因技术栈古老、环境敏感、错误信息晦涩极易陷入“改了十处只有一处生效”的泥潭。以下是我在带实习生时记录的真实踩坑清单每一条都附带现象 → 原因 → 解决的闭环。4.1 现象登录成功后跳转list.jsp页面显示空白查看源码只有htmlbody/body/html原因list.jsp中使用了 JSTL 标签如c:forEach但WEB-INF/lib/下缺少jstl.jar和standard.jarJSTL 1.1或jakarta.servlet.jsp.jstl-api-2.0.0.jartomcat-jasper-el-9.0.83.jarJSTL 2.0。JSP 编译时无法解析c:前缀直接忽略标签导致循环体不渲染。解决下载对应 JSTL 版本 jar 包放入WEB-INF/lib/同时检查list.jsp顶部是否有% taglib prefixc urihttp://java.sun.com/jsp/jstl/core %JSTL 1.1或% taglib prefixc urihttp://xmlns.jcp.org/jsp/jstl/core %JSTL 2.0URI 必须与 jar 包匹配。4.2 现象添加新员工时中文姓名存入数据库后变成??但数据库和表字符集已设为utf8mb4原因JDBC URL 缺少characterEncodingutf8mb4参数或 Tomcat 的server.xml中Connector未配置URIEncodingUTF-8。前者导致 MySQL Server 接收字节流时按 latin1 解码后者导致 GET 请求参数如?name张三在 Tomcat 解码时乱码。解决JDBC URL 改为jdbc:mysql://localhost:3306/emp_system?useSSLfalseserverTimezoneUTCcharacterEncodingutf8mb4TOMCAT_HOME/conf/server.xml中Connector port8080 ... /添加属性URIEncodingUTF-8重启 Tomcat。4.3 现象修改员工信息后页面跳回list.jsp但数据未更新刷新后才显示新值原因浏览器缓存了list.jsp的响应。Servlet 跳转用的是response.sendRedirect(list.jsp)302 重定向但list.jsp本身未设置缓存控制头浏览器可能复用旧缓存。解决在list.jsp顶部添加缓存禁用指令% response.setHeader(Cache-Control, no-cache, no-store, must-revalidate); response.setHeader(Pragma, no-cache); response.setDateHeader(Expires, 0); %4.4 现象点击“删除”按钮URL 变为delete?id5但数据库无变化控制台无任何日志原因delete.jsp或DeleteServlet.java中request.getParameter(id)返回null因为 HTML 表单的methodget时a hrefdelete?id${emp.id}的链接参数名是id但 Servlet 中request.getParameter(id)取不到——因为delete是 JSP 文件名Tomcat 默认将其映射为delete.jsp而delete.jsp里没写 Java 代码处理删除逻辑它只是个静态页面。真实删除逻辑应在DeleteServlet.java中且web.xml必须有servlet-mapping将/deleteURL 映射到该 Servlet。解决检查web.xml是否有servlet servlet-nameDeleteServlet/servlet-name servlet-classcom.emp.servlet.DeleteServlet/servlet-class /servlet servlet-mapping servlet-nameDeleteServlet/servlet-name url-pattern/delete/url-pattern /servlet-mapping确保链接是a hrefdelete?id${emp.id}指向/delete而非a hrefdelete.jsp?id${emp.id}指向静态 JSP。4.5 现象部署到 Tomcat 9 后web.xml报错The content of element type web-app must match (icon?,display-name?,description?,distributable?,context-param*,filter*,filter-mapping*,listener*,servlet*,servlet-mapping*,session-config?,mime-mapping*,welcome-file-list?,error-page*,taglib*,resource-env-ref*,security-constraint*,login-config?,security-role*,env-entry*,ejb-ref*,ejb-local-ref*)原因web.xml的 DTD 或 schema 声明版本过低。Tomcat 9 要求web-app版本为4.0而老项目常写2.3或2.4。解决将web.xml顶部声明替换为?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.05. 进阶改造把“教学项目”变成“可交付原型”的 3 个关键动作跑通只是起点。这个系统真正的价值在于它提供了一个极简但完整的骨架让你能快速验证业务想法。我带团队做内部工具时常以它为基线三天内完成需求落地。以下是三个最实用、零成本的改造点每个都附具体代码和效果说明。5.1 给员工列表加搜索框10 行代码实现模糊查询原始list.jsp是全量展示加搜索只需两步Step 1在list.jsp表格上方加表单form actionlist methodpost input typetext namekeyword placeholder按姓名或部门搜索 value${param.keyword} button typesubmit搜索/button a hreflist清空搜索/a /formStep 2修改ListServlet.java的doPost方法protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String keyword request.getParameter(keyword); ListEmployee employees; if (keyword ! null !keyword.trim().isEmpty()) { employees new EmployeeDao().search(keyword.trim()); // 新增 search 方法 } else { employees new EmployeeDao().findAll(); } request.setAttribute(employees, employees); request.getRequestDispatcher(list.jsp).forward(request, response); }Step 3在EmployeeDao.java中新增search方法public ListEmployee search(String keyword) { String sql SELECT * FROM employee WHERE name LIKE ? OR department LIKE ?; try (Connection conn JdbcUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { String likeKeyword % keyword %; ps.setString(1, likeKeyword); ps.setString(2, likeKeyword); ResultSet rs ps.executeQuery(); ListEmployee list new ArrayList(); while (rs.next()) { Employee emp new Employee(); emp.setId(rs.getInt(id)); emp.setName(rs.getString(name)); emp.setDepartment(rs.getString(department)); emp.setSalary(rs.getDouble(salary)); list.add(emp); } return list; } catch (SQLException e) { e.printStackTrace(); return new ArrayList(); } }效果输入“技术”返回所有name或department含“技术”的员工。无需改数据库、不引入新框架纯 JDBC 原生实现。5.2 用 Cookie 记住用户名让用户下次打开登录页时自动填充LoginServlet.java登录成功后添加 Cookie 写入逻辑// 登录验证通过后 Cookie userCookie new Cookie(username, username); userCookie.setMaxAge(60 * 60 * 24 * 7); // 7 天 userCookie.setPath(/); // 作用域为整个应用 response.addCookie(userCookie);然后在login.jsp的input中读取input typetext nameusername value${cookie.username.value} /注意cookie.username.value是 EL 表达式cookie是隐式对象username是 Cookie 名。若用户清除 Cookievalue为 null输入框为空安全无副作用。5.3 导出 Excel用 Apache POI 一行代码生成可下载文件在ListServlet.java中新增导出逻辑需引入poi-5.2.4.jarprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (export.equals(request.getParameter(action))) { ListEmployee employees new EmployeeDao().findAll(); HSSFWorkbook workbook new HSSFWorkbook(); HSSFSheet sheet workbook.createSheet(员工列表); String[] headers {ID, 姓名, 部门, 薪资}; HSSFRow headerRow sheet.createRow(0); for (int i 0; i headers.length; i) { headerRow.createCell(i).setCellValue(headers[i]); } int rowNum 1; for (Employee emp : employees) { HSSFRow row sheet.createRow(rowNum); row.createCell(0).setCellValue(emp.getId()); row.createCell(1).setCellValue(emp.getName()); row.createCell(2).setCellValue(emp.getDepartment()); row.createCell(3).setCellValue(emp.getSalary()); } response.setContentType(application/vnd.ms-excel); response.setHeader(Content-Disposition, attachment; filenameemployees.xls); workbook.write(response.getOutputStream()); return; } // ... 原有 list 逻辑 }在list.jsp加导出链接a hreflist?actionexport导出 Excel/a效果点击即下载employees.xlsExcel 打开后格式规整。POI 4.x 支持.xlsx但老项目用.xls兼容性更好无需额外依赖。我习惯在接手一个新项目时先用这个员工管理系统搭起本地开发环境再逐步替换为真实业务模块——它像一把瑞士军刀不锋利但每个刃口都磨得恰到好处。希望帮到你。本文还有配套的精品资源点击获取
返回列表