简介:这是一套基于JSP+Servlet+Tomcat+MySQL实现的完整人事管理系统源码,面向计算机、数学、电子信息等专业的本科生与初学者,适用于课程设计、期末大作业及毕业设计参考,帮助学习Web基础开发流程与MVC分层实践。资源包共2000个文件,涵盖49个Java后端逻辑类、42个JSP页面模板、1294个JS交互脚本、404个CSS样式文件及2个SQL建表与初始化脚本,辅以HTML前端结构、配置properties与XML部署文件,整体73.74MB,结构完整、模块清晰,便于理解请求流转、数据库交互与前后端协同机制。已有205人学习下载,资源开箱即用,含AdminLTE风格前端界面(如adminlte.min.css等多版本样式文件),提供可运行的登录、员工信息管理、部门维护、权限控制等核心功能模块,是掌握Java Web传统三层架构的典型教学案例。
1. 这不是“又一个JSP demo”:它是一套能跑通、能改、能交差的Java Web人事系统骨架,专治课程设计卡在登录页、毕设部署报404、Tomcat启动后连localhost:8080都打不开的玄学崩溃
你手头这份基于jsp+servlet+tomcat+mysql的人事管理系统源码.zip,不是网上泛滥的“Hello World式Servlet练习”,也不是只有一张登录页、点进去就500的半成品。它是一套真实可运行、结构完整、前后端分离雏形清晰、数据库表设计合理、权限控制有逻辑闭环的Java Web系统——从员工信息增删改查、部门管理、岗位分配,到登录鉴权、角色权限校验、操作日志记录,全链路打通。我去年帮三个学院带毕设,学生用它做基底,平均节省3周环境搭建和基础CRUD开发时间;有位数学系同学靠它补全了“Web层逻辑缺失”的答辩短板,最终答辩时被问“你怎么保证delete操作不误删”,他当场翻出EmployeeServlet.java里那行if (id != null && !id.trim().isEmpty())加SQL预编译参数校验,老师点头放行。它适合两类人:一是急需交差但Java Web基础尚可(能看懂request.getParameter()、会配web.xml)、愿意花2小时调通环境的课程设计党;二是想从零理解传统Java Web分层架构(JSP视图层 + Servlet控制层 + JDBC数据层)如何协作的真实学习者。别指望它自带Spring Boot自动装配或Vue响应式界面——它的价值恰恰在于“裸露”:每个.jsp怎么接<%= %>,每个doPost()怎么解析表单,每条SQL怎么拼接防注入,Tomcat怎么认context.xml里的JNDI数据源,MySQL建表语句为什么用ENGINE=InnoDB而非MyISAM——这些被现代框架封装掉的“黑匣子”,在这里全摊开给你看。
2. 环境筑基:从JDK到Tomcat再到MySQL,三步踩准版本兼容性红线,避开“启动成功却连不上库”的经典翻车
这套系统不是写在真空里的。它依赖特定技术栈组合,版本错配是90%部署失败的根源。我拆包第一件事就是翻build.xml和pom.xml(如果存在),再扫WEB-INF/lib/下的jar包名——结果发现核心依赖是mysql-connector-java-5.1.47.jar、servlet-api-2.5.jar,结合web.xml里<web-app version="2.5">声明,立刻锁定:必须用JDK 8 + Tomcat 7/8 + MySQL 5.7。用JDK 17跑?javax.servlet.*包直接报红;用Tomcat 10?jakarta.servlet.*新命名空间让所有import javax.servlet.*失效;MySQL 8.0默认开启caching_sha2_password认证插件?你的mysql-connector-java-5.1.47根本连不上。下面这三步,是我反复验证过的最小可行路径。
2.1 JDK 8安装与环境变量固化:别信IDE自动检测,手动验证才是后悔药
很多同学装完JDK,IDEA显示“Project SDK: 1.8”,就以为万事大吉。但Tomcat启动脚本(startup.bat/sh)读的是系统JAVA_HOME,不是IDE配置。务必执行:
# Windows下cmd echo %JAVA_HOME% java -version javac -version# Linux/macOS下终端 echo $JAVA_HOME java -version javac -version提示:
java -version输出必须含1.8.0_XXX,且javac版本号一致。若显示11.0.20或17.0.1,说明JAVA_HOME指向错误。去Oracle官网下载JDK 8u391(最后公开更新版),解压后设置JAVA_HOME=D:\Program Files\Java\jdk1.8.0_391(Windows)或export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_391.jdk/Contents/Home(macOS),并把%JAVA_HOME%\bin(Windows)或$JAVA_HOME/bin(Linux/macOS)追加到PATH。重启命令行再验证——这一步省不得,否则后续所有报错都是假象。
2.2 Tomcat 8.5.94部署:解压即用,但必须动这三处配置才能让JSP活过来
下载apache-tomcat-8.5.94.zip(官方存档版,非最新9.x),解压到无中文、无空格路径(如D:\tomcat8)。关键修改在conf/server.xml和conf/context.xml:
<!-- conf/server.xml 第69行附近,确认Connector端口 --> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <!-- 确保port=8080未被占用,若被占用,改8081并记住 --><!-- conf/context.xml 根节点内,添加JNDI数据源声明 --> <Resource name="jdbc/hrms" auth="Container" type="javax.sql.DataSource" maxTotal="100" maxIdle="30" minIdle="10" maxWaitMillis="10000" username="root" password="123456" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/hrms?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8" />参数说明:
name="jdbc/hrms"是JNDI查找名,代码里用ctx.lookup("java:comp/env/jdbc/hrms")获取;url中serverTimezone=GMT%2B8解决MySQL 5.7时区报错;&是XML转义,不能写成&;driverClassName必须是com.mysql.jdbc.Driver(非com.mysql.cj.jdbc.Driver),因jar包是5.1.x版本。
2.3 MySQL 5.7.44初始化:建库、授予权限、导入SQL,三步缺一不可
解压MySQL 5.7.44(推荐mysql-5.7.44-winx64.zip),初始化后启动服务。执行以下SQL(用mysql -u root -p登录后):
-- 1. 创建数据库,显式指定字符集避免乱码 CREATE DATABASE hrms CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 2. 授予root用户对hrms库的全部权限(开发环境可接受) GRANT ALL PRIVILEGES ON hrms.* TO 'root'@'localhost' IDENTIFIED BY '123456'; -- 3. 刷新权限 FLUSH PRIVILEGES; -- 4. 切换到hrms库,执行源码包里的hrms.sql(通常在/sql/或/DB/目录下) USE hrms; SOURCE D:/hrms_source/sql/hrms.sql; -- 路径按实际调整注意:
hrms.sql文件里建表语句应含ENGINE=InnoDB DEFAULT CHARSET=utf8mb4,若为MyISAM或utf8,需手动替换。utf8mb4支持emoji和四字节UTF-8字符,避免姓名字段存入生僻字时报错。
3. 源码解构:从web.xml入口到EmployeeServlet业务流,看清JSP+Servlet如何用原始方式协同作战
拿到源码包,别急着扔进IDE。先用文本编辑器打开根目录下的web.xml——这是整个Web应用的“宪法”。它定义了URL路由、Servlet映射、过滤器链,是理解系统脉络的起点。我习惯按三块来读:<servlet>声明、<servlet-mapping>绑定、<welcome-file-list>首页。
3.1web.xml路由中枢:LoginServlet为何接管/login,EmployeeServlet又如何响应/employee/*
<!-- web.xml 片段 --> <servlet> <servlet-name>LoginServlet</servlet-name> <servlet-class>com.hrms.servlet.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping> <servlet> <servlet-name>EmployeeServlet</servlet-name> <servlet-class>com.hrms.servlet.EmployeeServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>EmployeeServlet</servlet-name> <url-pattern>/employee/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list>逻辑说明:当浏览器访问
http://localhost:8080/hrms/login,Tomcat根据<url-pattern>/login</url-pattern>匹配到LoginServlet,调用其doPost()方法处理表单提交;访问http://localhost:8080/hrms/employee/list,则由EmployeeServlet的doGet()处理,/employee/*中的*代表后续路径(如list、add、delete),Servlet内部通过request.getServletPath()解析具体动作。index.jsp作为欢迎页,通常含登录表单,action="/login"指向上述Servlet。
3.2LoginServlet.java鉴权流程:Session存储、重定向、错误提示的原始实现
// com/hrms/servlet/LoginServlet.java protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); String password = request.getParameter("password"); // 1. 简单判空(生产环境应前端+后端双重校验) if (username == null || username.trim().isEmpty() || password == null || password.trim().isEmpty()) { request.setAttribute("error", "用户名或密码不能为空"); request.getRequestDispatcher("/index.jsp").forward(request, response); return; } // 2. 调用DAO查询用户(此处简化,实际在UserDAO.java中) User user = userDao.findByUsername(username); if (user != null && user.getPassword().equals(password)) { // 3. 登录成功:存入Session,重定向到主页面 HttpSession session = request.getSession(); session.setAttribute("currentUser", user); // 关键!后续页面靠此判断登录态 response.sendRedirect(request.getContextPath() + "/main.jsp"); } else { // 4. 登录失败:设置错误信息,回传index.jsp request.setAttribute("error", "用户名或密码错误"); request.getRequestDispatcher("/index.jsp").forward(request, response); } }参数说明:
request.getContextPath()返回应用上下文路径(如/hrms),确保重定向URL正确;session.setAttribute("currentUser", user)将用户对象存入Session,后续main.jsp可通过<%= session.getAttribute("currentUser") != null ? "已登录" : "未登录" %>判断;forward()是服务器端跳转,URL不变;sendRedirect()是客户端重定向,URL改变且会丢失request域数据。
3.3EmployeeServlet.javaCRUD路由分发:一个Servlet如何扛起增删改查全部压力
// com/hrms/servlet/EmployeeServlet.java protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String pathInfo = request.getPathInfo(); // 获取 /employee/ 后的路径,如 /list 或 /add if (pathInfo == null || "/".equals(pathInfo)) { // 默认访问 /employee/ 时,重定向到 /employee/list response.sendRedirect(request.getContextPath() + "/employee/list"); return; } switch (pathInfo) { case "/list": showEmployeeList(request, response); break; case "/add": showAddForm(request, response); break; case "/edit": showEditForm(request, response); break; default: // 处理 /employee/123 形式,提取ID Long id = getIdFromPath(pathInfo); if (id != null) { showEmployeeDetail(request, response, id); } else { request.setAttribute("error", "无效的员工ID"); request.getRequestDispatcher("/error.jsp").forward(request, response); } } } private void showEmployeeList(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { List<Employee> employees = employeeDao.findAll(); // DAO层查询 request.setAttribute("employees", employees); // 存入request域 request.getRequestDispatcher("/WEB-INF/jsp/employee/list.jsp").forward(request, response); }关键点:
getPathInfo()是Servlet 3.0+特性,精准捕获RESTful风格路径;/WEB-INF/jsp/employee/list.jsp路径以/WEB-INF/开头,意味着该JSP无法被用户直接URL访问(安全防护),只能通过Servletforward()调用;request.setAttribute()传递数据给JSP,JSP用<c:forEach items="${employees}" var="emp">遍历(需引入JSTL标签库)。
4. 避坑指南:那些让新手调试到凌晨三点的“小问题”,其实都有固定解法
部署这套系统,最耗时间的往往不是写代码,而是解决一堆看似无关紧要、实则致命的细节问题。以下是我在带学生过程中,高频出现的5个坑,每个都附带现象、根因和一招毙命的解法。
4.1 现象:Tomcat启动成功,浏览器访问http://localhost:8080/hrms显示404,但http://localhost:8080/能进Tomcat首页
原因:项目未正确部署到Tomcat的webapps目录,或web.xml中<display-name>与实际Context Path不一致。
解决:确认源码包解压后的文件夹名是hrms(与URL路径一致),将其整个拷贝到tomcat/webapps/下;检查webapps/hrms/WEB-INF/web.xml是否真实存在且内容完整;若仍不行,在conf/server.xml的<Host>节点内添加<Context path="/hrms" docBase="hrms" reloadable="true"/>。
4.2 现象:登录页提交后报HTTP Status 500 – java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
原因:mysql-connector-java-5.1.47.jar未放入WEB-INF/lib/目录,或Tomcat的lib/目录下有冲突的高版本MySQL驱动。
解决:将mysql-connector-java-5.1.47.jar明确复制到webapps/hrms/WEB-INF/lib/下(不是Tomcat的lib/);删除Tomcatlib/目录下所有mysql-*.jar;重启Tomcat。
4.3 现象:登录成功后跳转main.jsp,页面显示空白,查看源码发现JSP表达式<%= session.getAttribute("currentUser") %>没渲染
原因:main.jsp顶部缺少<%@ page session="true" %>指令,导致Session未启用。
解决:在main.jsp第一行加入<%@ page session="true" %>;同理,所有需要Session的JSP都应显式声明。
4.4 现象:新增员工时,中文姓名存入MySQL后变成??乱码
原因:MySQL连接URL未指定字符集,或数据库/表本身字符集非utf8mb4。
解决:检查context.xml中url参数,确认含useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8;登录MySQL执行SHOW CREATE DATABASE hrms;,若非DEFAULT CHARSET=utf8mb4,执行ALTER DATABASE hrms CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;;再执行SHOW CREATE TABLE employee;,对表和字段逐一ALTER TABLE employee CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;。
4.5 现象:点击“删除员工”,浏览器地址栏变为http://localhost:8080/hrms/employee/delete?id=123,但员工未被删除
原因:EmployeeServlet.java中doGet()处理了/delete,但实际删除逻辑应在doPost()中(防止GET请求被缓存或重复提交),而前端表单method写成了get。
解决:检查list.jsp中删除链接,应为<a href="javascript:void(0)" onclick="if(confirm('确定删除?')){location.href='<%=request.getContextPath()%>/employee/delete?id=<%=emp.getId()%>';}">删除</a>(用JS确认+GET);或更规范地,将删除改为POST表单:<form action="${pageContext.request.contextPath}/employee/delete" method="post"><input type="hidden" name="id" value="${emp.id}"><button type="submit">删除</button></form>,并在EmployeeServlet.doPost()中处理/delete。
5. JSP页面定制实战:从AdminLTE皮肤嫁接到自定义员工头像上传,三步完成UI升级与功能增强
这套源码的UI基于AdminLTE 2.x(从adminlte.css等文件名可确认),它提供了成熟的响应式布局和组件,但默认未启用所有功能。我常让学生用它做两件事:一是替换首页index.jsp为AdminLTE登录模板,提升专业感;二是给员工管理页增加头像上传,把静态JSP变成动态交互。下面以“员工头像上传”为例,展示如何在不破坏原有架构的前提下安全增强。
5.1 前端:在employee/edit.jsp中嵌入文件上传表单,适配AdminLTE样式
<!-- employee/edit.jsp 中员工信息表单末尾 --> <div class="form-group"> <label for="avatar">头像</label> <div class="input-group"> <div class="input-group-prepend"> <span class="input-group-text"><i class="fas fa-image"></i></span> </div> <div class="custom-file"> <input type="file" class="custom-file-input" id="avatar" name="avatar" accept="image/*"> <label class="custom-file-label" for="avatar">选择图片</label> </div> </div> <small class="form-text text-muted">支持JPG、PNG格式,大小不超过2MB</small> </div>注意:
accept="image/*"限制文件类型;custom-file是AdminLTE 2.x的文件上传组件类,需确保adminlte.min.js已加载;name="avatar"是后端接收参数名,必须与Servlet中request.getPart("avatar")一致。
5.2 后端:改造EmployeeServlet.doPost(),用Part接口解析文件并保存
// EmployeeServlet.java 中 doPut() 或复用 doPost() 处理编辑提交 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // ... 其他字段解析 ... // 1. 获取文件Part Part avatarPart = request.getPart("avatar"); String fileName = Paths.get(avatarPart.getSubmittedFileName()).getFileName().toString(); // 2. 非空校验 if (fileName != null && !fileName.isEmpty()) { // 3. 生成唯一文件名,避免覆盖 String fileExt = fileName.substring(fileName.lastIndexOf(".")); String newFileName = System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8) + fileExt; // 4. 定义保存路径(建议放在webapps/hrms/upload/,非WEB-INF下) String uploadPath = request.getServletContext().getRealPath("") + File.separator + "upload"; File uploadDir = new File(uploadPath); if (!uploadDir.exists()) uploadDir.mkdirs(); // 5. 写入文件 String filePath = uploadPath + File.separator + newFileName; avatarPart.write(filePath); // 6. 将相对路径存入employee对象(如 /upload/1712345678_abc123.jpg) employee.setAvatar("/upload/" + newFileName); } // ... 保存employee到数据库 ... employeeDao.update(employee); response.sendRedirect(request.getContextPath() + "/employee/list"); }参数说明:
request.getPart("avatar")是Servlet 3.0+标准API,替代老旧的commons-fileupload;getRealPath("")获取应用根目录绝对路径;/upload/目录需手动在webapps/hrms/下创建,确保Tomcat进程有写权限;employee.setAvatar()假设Employee实体类已添加avatar字段及getter/setter。
5.3 数据库与实体:扩展employee表,同步更新Java Bean与DAO
-- 在MySQL中执行 ALTER TABLE employee ADD COLUMN avatar VARCHAR(255) DEFAULT NULL COMMENT '头像路径';// Employee.java 中添加 private String avatar; public String getAvatar() { return avatar; } public void setAvatar(String avatar) { this.avatar = avatar; }// EmployeeDAO.java 的update方法中,添加avatar字段更新 String sql = "UPDATE employee SET name=?, gender=?, dept_id=?, position=?, avatar=? WHERE id=?"; ps.setString(5, employee.getAvatar()); // 第5个参数关键技巧:头像路径存相对URL(如
/upload/xxx.jpg),而非绝对磁盘路径,这样JSP中<img src="${emp.avatar}">能直接渲染;upload目录放在webapps/hrms/下,Tomcat会自动将其映射为静态资源,无需额外配置;若需限制文件大小,在web.xml中添加<multipart-config>:
<servlet> <servlet-name>EmployeeServlet</servlet-name> <servlet-class>com.hrms.servlet.EmployeeServlet</servlet-class> <multipart-config> <max-file-size>2097152</max-file-size> <!-- 2MB --> <max-request-size>4194304</max-request-size> <!-- 4MB --> </multipart-config> </servlet>从那以后我每次接手学生毕设,只要看到JSP项目,第一件事就是检查web.xml的Servlet映射和context.xml的JNDI配置——这两处定乾坤。环境搭得稳,后面改功能才不会在底层报错里迷失方向。希望帮到你。
本文还有配套的精品资源,点击获取