ARTICLE DETAIL

资讯详情

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

JSP+Servlet人事管理系统源码实战:环境搭建、源码解析与避坑指南

JSP+Servlet人事管理系统源码实战:环境搭建、源码解析与避坑指南 简介这份资源是基于JSPServletTomcatMySQL技术栈开发的人事管理系统完整源码包面向计算机、软件工程、电子信息等专业的学生与初级Java开发者适用于课程设计、期末大作业、毕业设计等场景也可作为学习Java Web传统MVC架构的参考案例。压缩包为zip格式共约2000个文件整体大小73.74MB其中以JavaScript脚本与CSS样式文件为主配合少量HTML页面、Java源文件、JSP视图、SQL建表脚本及properties配置文件覆盖前端界面、后端控制与数据库交互的完整链路。目前已有205人学习下载具备一定的参考热度。项目结构清晰读者可借此理解Servlet请求分发、JSP页面渲染、数据库连接与增删改查等核心流程并在此基础上自行调试、扩展考勤、薪资、部门管理等模块是入门Java Web开发与完成课设任务的实用参考资料。1. 拿到一份 JSPServlet 人事管理系统源码先别急着点运行很多人拿到「基于jspservlettomcatmysql的人事管理系统源码.zip」这类压缩包第一反应是解压、导入 IDE、点 Run然后被一连串 404、500、ClassNotFoundException 劝退。这套技术栈是典型的 JavaWeb 传统三层架构JSP 负责页面渲染Servlet 接请求做控制Tomcat 当 Web 容器MySQL 存员工、部门、考勤、薪资这些数据。它不新但它是理解 JavaWeb 请求流转最直白的样本也是很多公司内部老系统仍在跑的东西。这篇文章面向三类人想拿它当课程设计或练手项目的新手、需要把老系统跑起来做二次开发的工程师、以及想搞清楚 JSPServlet 这套「老古董」到底怎么落地的人。我会按「环境怎么搭 → 源码怎么读 → 数据库怎么接 → 坑在哪 → 怎么改造成自己能用的东西」这条线走每一步都给可复现的命令和参数。你不需要先精通 Servlet 生命周期跟着做就能跑通。2. 环境搭建JDK、Tomcat、MySQL 三件套的版本咬合2.1 为什么版本选错比代码写错更致命这套源码对版本极其敏感。JSPServlet 的 API 在 Java EE 和 Jakarta EE 之间改过包名Tomcat 8.5 用javax.servletTomcat 10 之后变成jakarta.servlet源码里写死的import javax.servlet.*在 Tomcat 10 上直接编译不过。MySQL 这边5.7 和 8.0 的 JDBC 驱动类名和连接串参数也不一样。所以第一步不是写代码是把版本锁死。我一般推荐这套组合JDK 8 或 JDK 11、Tomcat 8.5 或 9.0、MySQL 5.7 或 8.0。JDK 8 最稳因为大量老源码用的还是javax命名空间且 Tomcat 8.5 对 JDK 8 支持最好。如果你机器上已经装了 JDK 17 或更高别硬上单独装一个 JDK 8 并用JAVA_HOME切换比改源码包名省事得多。组件推荐版本原因不推荐JDK8 或 11兼容 javax.servletJDK 17 需改包名Tomcat8.5 或 9.0用 javax.servlet APITomcat 10 用 jakartaMySQL5.7 或 8.0驱动成熟语法稳定8.4 部分语法变动JDBC 驱动mysql-connector-java 5.1.x 或 8.0.x与 MySQL 版本对应混用会报时区/SSL 错2.2 Tomcat 安装与 IDEA 配置的实操命令Windows 下解压 Tomcat 后先确认JAVA_HOME指向 JDK 8然后进bin目录启动。Linux 下同理注意给startup.sh执行权限。# Linux/Mac 下启动 Tomcat先确认 JAVA_HOME export JAVA_HOME/usr/lib/jvm/jdk1.8.0_381 cd /opt/apache-tomcat-8.5.100/bin chmod x *.sh ./startup.sh # 验证浏览器访问 http://localhost:8080 看到 Tomcat 默认页即成功# 查看 Tomcat 是否真的起来了以及端口占用 ps -ef | grep tomcat netstat -tlnp | grep 8080 # 如果 8080 被占改 conf/server.xml 里的 Connector portIDEA 里配置 Tomcat 的路径是Run → Edit Configurations → → Tomcat Server → Local在 Server 选项卡里指定 Tomcat 安装目录在 Deployment 选项卡里添加 Artifact通常是war exploded。这里有个高频翻车点Artifact 没加或加错启动后访问项目路径就是 404。war exploded模式支持热更新改 JSP 不用重启改 Java 代码需要重启。2.3 MySQL 安装与建库建用户的边界MySQL 8.0 安装后默认有 SSL 和 caching_sha2_password 认证插件老驱动连不上会报Unable to load authentication plugin或 SSL 相关错误。最省事的做法是建一个专用用户并指定认证方式。-- 建库字符集用 utf8mb4避免中文乱码 CREATE DATABASE hrms DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; -- 建专用用户MySQL 8.0 下指定 mysql_native_password 兼容老驱动 CREATE USER hrmslocalhost IDENTIFIED WITH mysql_native_password BY Hrms2024; GRANT ALL PRIVILEGES ON hrms.* TO hrmslocalhost; FLUSH PRIVILEGES;参数说明utf8mb4比utf8多支持 emoji 和部分生僻字人事系统里员工姓名偶尔有生僻字用 utf8mb4 省心。mysql_native_password是为了兼容mysql-connector-java 5.1.x如果你用 8.0.x 驱动可以不改认证插件但连接串要加serverTimezoneAsia/ShanghaiuseSSLfalse。useSSLfalse在本地开发环境关掉 SSL 握手避免mysql ssl连接错误生产环境另说。3. 源码结构拆解从 web.xml 到 Servlet 的请求链路3.1 一个请求从浏览器到数据库走了哪几步JSPServlet 项目的请求链路是固定的浏览器发请求 → Tomcat 根据web.xml或注解把 URL 映射到某个 Servlet → Servlet 调 Service/DAO → DAO 用 JDBC 查 MySQL → 结果封装成实体 → Servlet 转发到 JSP → JSP 渲染 HTML 返回。理解这条链路你调试时就知道该在哪一环打断点。典型目录结构长这样src/main/java下按controller、service、dao、entity分包src/main/webapp下放 JSP、CSS、JS 和WEB-INF/web.xml。WEB-INF下的 JSP 不能被浏览器直接访问必须经 Servlet 转发这是安全设计别把登录后的页面挪到WEB-INF外面。!-- web.xml 里的 Servlet 映射老项目常见写法 -- servlet servlet-nameEmployeeServlet/servlet-name servlet-classcom.hrms.controller.EmployeeServlet/servlet-class /servlet servlet-mapping servlet-nameEmployeeServlet/servlet-name url-pattern/employee/*/url-pattern /servlet-mapping这段配置的意思是所有/employee/开头的请求都交给EmployeeServlet处理。url-pattern用/employee/*是前缀匹配Servlet 内部再根据request.getPathInfo()区分是查列表还是删员工。如果你在 Servlet 上用了WebServlet(/employee)注解就不要再在web.xml里重复配否则 Tomcat 启动会报重复映射。3.2 数据库连接配置别把密码硬编码在 Java 里老源码常见问题是 JDBC 连接写死在 Java 类里改数据库要重新编译。正确做法是抽到db.properties用Properties类加载。下面是一个可抄的连接工具类。// DBUtil.java —— 从 classpath 读配置避免硬编码 public class DBUtil { private static String url; private static String user; private static String password; static { try (InputStream in DBUtil.class.getClassLoader() .getResourceAsStream(db.properties)) { Properties props new Properties(); props.load(in); url props.getProperty(jdbc.url); user props.getProperty(jdbc.user); password props.getProperty(jdbc.password); // 显式加载驱动老驱动不加载会报 No suitable driver Class.forName(props.getProperty(jdbc.driver)); } catch (Exception e) { throw new ExceptionInInitializerError(数据库配置加载失败: e.getMessage()); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url, user, password); } }# db.properties 放在 src/main/resources 下 jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/hrms?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse jdbc.userhrms jdbc.passwordHrms2024参数说明com.mysql.cj.jdbc.Driver是 MySQL 8.0 驱动的类名5.1.x 驱动用com.mysql.jdbc.Driver写错会报ClassNotFoundException。serverTimezone不设会报时区错误characterEncodingutf8配合库的 utf8mb4 防止中文乱码。useSSLfalse只在本地用线上要配证书。这个工具类用静态块加载配置只执行一次getConnection每次新建连接简单但没连接池并发高了会慢后面第 6 章讲怎么加。3.3 导入 SQL 脚本时最容易忽略的三件事源码包里通常有个.sql文件导入时注意第一脚本里的建库语句可能写死utf8导入前改成utf8mb4第二脚本里的INSERT数据可能带外键依赖导入顺序错了会报Cannot add or update a child row先导主表再导从表第三MySQL 8.0 下GROUP BY默认开启ONLY_FULL_GROUP_BY老 SQL 里SELECT * ... GROUP BY dept会报错要么改 SQL要么临时关掉这个模式。-- 查看并临时关闭 ONLY_FULL_GROUP_BY会话级不影响全局 SELECT sql_mode; SET SESSION sql_mode STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION;4. 人事管理系统的核心模块怎么读和怎么改4.1 员工增删改查Servlet 里该写什么不该写什么人事系统的核心是员工表employee字段一般有id、name、gender、dept_id、position、hire_date、salary。Servlet 的职责是收参数、调 Service、转发视图不该在 Servlet 里写 SQL。常见翻车是把 JDBC 代码直接塞进doPost几百行一个方法改一个字段要翻半天。// EmployeeServlet 的 doGet按 action 分发保持方法短小 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String action req.getPathInfo(); // 对应 /employee/list、/employee/delete if (/list.equals(action)) { ListEmployee list employeeService.findAll(); req.setAttribute(employees, list); req.getRequestDispatcher(/WEB-INF/views/employee/list.jsp) .forward(req, resp); } else if (/delete.equals(action)) { int id Integer.parseInt(req.getParameter(id)); employeeService.deleteById(id); resp.sendRedirect(req.getContextPath() /employee/list); } else { resp.sendError(HttpServletResponse.SC_NOT_FOUND); } }逻辑说明getPathInfo()拿到的是/list这种后缀配合url-pattern的/employee/*实现一个 Servlet 管多个操作。查询用forward因为要把employees数据带到 JSP删除用sendRedirect避免用户刷新页面重复提交删除。参数id从 URL 拿Integer.parseInt要包 try-catch否则传个非数字直接 500。4.2 JSP 页面渲染EL 和 JSTL 怎么替代脚本片段老 JSP 里满屏% %脚本片段可读性差还容易出空指针。现代写法用 EL 表达式${}和 JSTL 标签。列表页用c:forEach遍历比 Java 循环干净得多。% taglib prefixc urihttp://java.sun.com/jsp/jstl/core % table trth姓名/thth部门/thth职位/thth操作/th/tr c:forEach items${employees} varemp tr td${emp.name}/td td${emp.deptName}/td td${emp.position}/td tda href${pageContext.request.contextPath}/employee/delete?id${emp.id}删除/a/td /tr /c:forEach /table注意${pageContext.request.contextPath}拿的是项目上下文路径部署到 Tomcat 后项目名可能是hrms直接写/employee/delete会 404。JSTL 的c标签库需要jstl.jar和standard.jar在WEB-INF/lib下缺了会报The absolute uri cannot be resolved。如果页面加载后需要刷新一次才显示数据常见原因是 AJAX 请求在 DOM 没就绪时就发了把初始化逻辑放进window.onload或DOMContentLoaded里。4.3 部门与考勤模块的关联查询怎么写才不慢部门表和员工表是一对多考勤表和员工表也是一对多。列表页要显示员工所属部门名就得关联查询。新手容易在循环里查部门N1 问题100 个员工发 101 条 SQL。正确做法是一条 JOIN 查完。-- 员工列表带部门名一条 SQL 搞定 SELECT e.id, e.name, e.position, e.salary, d.dept_name FROM employee e LEFT JOIN department d ON e.dept_id d.id ORDER BY e.hire_date DESC;LEFT JOIN保证没分配部门的员工也能查出来dept_name为 null 时 JSP 里用c:out value${emp.deptName} default未分配/兜底。考勤统计按月分组用DATE_FORMAT(check_date, %Y-%m)做分组键配合COUNT和SUM算迟到次数。数据量上万后check_date上要建索引否则全表扫描。-- 考勤按月统计check_date 建索引后走 range 扫描 CREATE INDEX idx_check_date ON attendance(check_date); SELECT emp_id, DATE_FORMAT(check_date, %Y-%m) AS month, COUNT(*) AS total, SUM(is_late) AS late_count FROM attendance WHERE check_date BETWEEN 2024-01-01 AND 2024-12-31 GROUP BY emp_id, month;5. 避坑与排查这套老技术栈最常翻车的五个地方5.1 启动报 ClassNotFoundException: com.mysql.jdbc.Driver现象Tomcat 启动或第一次访问数据库时抛ClassNotFoundException指向驱动类。原因驱动 jar 没放进WEB-INF/lib或者驱动类名和 MySQL 版本不匹配。解决确认WEB-INF/lib下有mysql-connector-java-x.x.x.jarMySQL 8.0 用com.mysql.cj.jdbc.Driver5.7 用com.mysql.jdbc.Driver。IDEA 里还要在 Project Structure → Artifacts 里确认这个 jar 被包含进输出。5.2 页面中文乱码数据库里存进去是问号现象表单提交中文数据库里变成???。原因三层编码没统一——JSP 页面pageEncoding、请求体编码、数据库连接串编码、表字符集。解决JSP 顶部写% page contentTypetext/html;charsetUTF-8 pageEncodingUTF-8 %Servlet 里request.setCharacterEncoding(UTF-8)要在取参数之前调连接串加characterEncodingutf8建库用utf8mb4。Tomcat 8 以上默认 URI 编码是 UTF-8一般不用改server.xml。5.3 访问项目路径 404但 Tomcat 首页正常现象http://localhost:8080能打开http://localhost:8080/hrms/报 404。原因Artifact 没部署、context path 不对、或者web.xml里welcome-file没配。解决IDEA 的 Deployment 选项卡里看 Application context 是不是/hrmsweb.xml里加welcome-filelogin.jsp/welcome-file。如果项目根目录没有默认页Tomcat 不会自动找index.jsp除非你配了。5.4 MySQL 8.0 连接报 Public Key Retrieval is not allowed现象用 8.0 驱动连 MySQL 8.0报Public Key Retrieval is not allowed。原因caching_sha2_password 认证插件在非 SSL 连接下需要公钥检索驱动默认禁止。解决连接串加allowPublicKeyRetrievaltrue或者把用户认证插件改成mysql_native_password。本地开发两种都行线上建议用 SSL 而不是开这个参数。5.5 修改 Java 代码后页面没变化现象改了 Servlet 或 Service重启 Tomcat 后行为还是旧的。原因IDEA 的war exploded模式下编译输出目录和 Tomcat 部署目录不同步或者 classes 没重新编译。解决Build → Rebuild Project然后在 Tomcat 配置里确认 On Update action 设为 Update classes and resources。JSP 改动一般不用重启Java 改动必须重启或热部署。如果用了war包部署每次都要重新打包麻烦开发阶段一律用war exploded。6. 从能跑到能用连接池、分页与二次开发的具体技巧把系统跑起来只是起点真要拿去用或者写进简历得解决性能和可维护性。第一个要动的是数据库连接。前面DBUtil每次getConnection都新建物理连接并发一高就崩。换成 Druid 或 HikariCP 连接池改造成本很低。// 用 HikariCP 替换 DriverManager注意关闭连接时是归还池而非真关 private static HikariDataSource dataSource; static { HikariConfig config new HikariConfig(); config.setJdbcUrl(jdbc:mysql://localhost:3306/hrms?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse); config.setUsername(hrms); config.setPassword(Hrms2024); config.setMaximumPoolSize(10); // 按并发量调一般 CPU 核数 * 2 磁盘数 config.setMinimumIdle(2); config.setConnectionTimeout(30000); // 30 秒拿不到连接就抛异常别无限等 dataSource new HikariDataSource(config); } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); }参数说明maximumPoolSize不是越大越好10 到 20 对中小系统足够设太大反而拖慢数据库。connectionTimeout必须设否则数据库挂了线程会一直阻塞。用完连接一定要在finally里close()在池化环境下close是归还不关会导致池耗尽报Connection is not available。第二个是分页。员工表数据多了SELECT *全查出来再在 JSP 分页是灾难。MySQL 用LIMIT offset, size配合COUNT(*)算总页数。-- 分页查询page 从 1 开始size 每页条数 SELECT e.id, e.name, d.dept_name FROM employee e LEFT JOIN department d ON e.dept_id d.id ORDER BY e.id LIMIT #{offset}, #{size}; -- offset (page - 1) * size注意LIMIT在大偏移量时比如LIMIT 100000, 10会扫描前 10 万行再丢弃慢。优化思路是用WHERE id 上一页最大 id的游标分页或者业务上限制最多翻到第几页。人事系统一般数据量不大普通LIMIT够用但要知道这个边界。第三个技巧是给 JSP 页面加统一的错误页别让用户看到 Tomcat 的 500 堆栈。在web.xml里配error-page把 404 和 500 指向自定义页面同时把异常日志写到文件而不是只打控制台。日志用 Log4j2 或 JUL别用System.out.println上线后控制台一关就什么都看不到。!-- web.xml 错误页配置 -- error-page error-code404/error-code location/WEB-INF/views/error/404.jsp/location /error-page error-page error-code500/error-code location/WEB-INF/views/error/500.jsp/location /error-page最后说个我自己的习惯拿到任何一份老源码先别改业务先把它在本地跑通然后用 Git 建一个分支把环境配置、数据库脚本、启动命令写成 README。这套 JSPServlet 的东西虽然老但它是理解请求流转、会话管理、JDBC 的最佳样本跑通一次后面看 Spring MVC 的 DispatcherServlet 会顺很多。我踩过最深的坑是版本不匹配还硬调代码浪费两天后来养成先锁版本再动手的习惯省下的时间够写好几个模块。希望帮到你。本文还有配套的精品资源点击获取
返回列表