☰
基于Java的人事管理系统源码拆解:JSP+Servlet+MySQL实战
2026/10/4 10:30:46 网站建设 项目流程

简介:基于Java Web的人事人力资源管理系统毕业设计资料包,面向计算机相关专业学生及Java Web学习者,用于课程设计、毕业设计与期末大作业。压缩包共一百一十六个文件,总大小约三点零二兆,其中六十九个JSP页面构成系统核心界面,辅以CSS与JS前端脚本、Java类与JAR依赖库、SQL数据库脚本、DOCX开题报告及演示视频,可直接导入集成开发环境运行或对照学习。系统基于浏览器服务器架构,采用JSP、JDBC与MySQL设计,覆盖系统管理员、部门信息、员工信息、合同管理、绩效管理含工资与奖惩记录、考勤管理等主要功能模块,后台管理员操作流程完整。现有六十五人学习浏览,配套演示视频、开题报告和数据库文件,能帮助快速掌握项目运行流程、设计思路与答辩表述,适合用于毕业设计参考或二次开发。

1. 拆解Java人事人力资源管理系统:毕业设计里的JSP+MySQL经典配方

拿到这份“基于Java的人事人力资源管理系统”压缩包时,我先把文件清单翻了一遍:db.class、.classpath、style.css、CssAdmin.css、开题.docx、login.gif、userreg.gif,一看就是标准的MyEclipse工程结构。这套系统走的是JSP+Servlet+MySQL的B/S架构,开发环境是MyEclipse,服务器用Tomcat,通过JDBC和数据库完成数据交互。功能上覆盖了管理员登录、部门维护、员工信息管理、合同管理、绩效工资、奖惩记录和考勤管理,几乎把HR系统最常用的后台职能都做齐了。对正在做毕业设计、JSP期末大作业或者Java课程设计的同学来说,这套源码的意义不在于功能有多花哨,而在于它把“数据表怎么建、JDBC怎么连、页面怎么串、部署怎么跑”这条链路完整打通了。下面我按模块拆、按部署讲、按代码走读,把这份资源的真正价值给你盘清楚。

2. 六大核心模块与数据库设计:JSP+MySQL里的人力资源业务闭环

2.1 系统管理员模块:登录鉴权与Session控制的代码落点

整套系统的入口是后台管理员登录。业务流程并不复杂:登录页提交用户名和密码,后台Servlet接收请求参数,调用JDBC层查询admin表,验证通过后把管理员信息写入Session,然后跳转到后台首页。虽然流程简单,但它是整个系统的第一道门,也是答辩时最容易被追问的环节。

admin表的设计一般包含这几个字段:

CREATE TABLE admin ( admin_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '管理员ID', admin_name VARCHAR(50) NOT NULL UNIQUE COMMENT '登录账号', admin_password VARCHAR(64) NOT NULL COMMENT '登录密码', last_login_time DATETIME DEFAULT NULL COMMENT '最近登录时间' );

这个表结构里有三个细节值得注意。admin_name设置UNIQUE约束,防止重复账号被插进去;admin_password用VARCHAR(64)而不是VARCHAR(20),是为了兼容MD5加密后固定32位、SHA-256后64位的散列值;last_login_time设置默认NULL,在登录成功时用UPDATE语句回填,可以给系统加一个“最近登录时间”的展示功能。

登录校验的常见实现是在LoginServlet的doPost方法里完成:

// LoginServlet.java 关键逻辑 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); String username = request.getParameter("username"); String password = request.getParameter("password"); // 常见做法:先做一次MD5摘要后再去数据库比对 String md5Pwd = MD5Util.md5(password); AdminDao dao = new AdminDao(); Admin admin = dao.findByUsernameAndPwd(username, md5Pwd); if (admin != null) { // 登录成功,绑定Session HttpSession session = request.getSession(); session.setAttribute("admin", admin); response.sendRedirect("index.jsp"); } else { // 登录失败,返回错误提示 request.setAttribute("error", "用户名或密码错误"); request.getRequestDispatcher("login.jsp").forward(request, response); } }

这段代码有两个参数必须说清。request.setCharacterEncoding("UTF-8")必须放在读取任何getParameter之前,否则POST提交的中文参数会全部乱码,这是JSP开发中排序第一的经典坑。MD5Util.md5(password)是一个工具类封装,如果源码包里没有这个类,你可以用commons-codec或者自己写一个MessageDigest的封装,总之不要拿明文密码直接去数据库比对。

Session绑定之后,后台页面的权限判断通常写在JSP页头:

<% Admin admin = (Admin) session.getAttribute("admin"); if (admin == null) { response.sendRedirect("login.jsp"); return; } %>

这种在每个页面头部写判断的做法,优点是直观好讲,缺点是每个受保护的页面都重复一遍。如果你打算二次开发,可以把它提取成一个Filter过滤器,统一拦截除login.jsp和登录Servlet以外的所有请求。

2.2 部门与员工信息模块:主外键关系下的数据维护流程

部门和员工是人事系统的基础数据。部门表存组织架构,员工表通过dept_id外键关联部门,这样的设计保证了数据的一致性——员工所属部门必须存在于部门表中,不会出现“孤儿数据”。

部门表的典型设计如下:

CREATE TABLE department ( dept_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '部门ID', dept_name VARCHAR(100) NOT NULL COMMENT '部门名称', dept_manager VARCHAR(50) DEFAULT NULL COMMENT '部门负责人', dept_desc VARCHAR(255) DEFAULT NULL COMMENT '部门描述' );

员工表在部门表基础上扩展:

CREATE TABLE employee ( emp_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '员工ID', emp_no VARCHAR(20) NOT NULL UNIQUE COMMENT '员工编号', emp_name VARCHAR(50) NOT NULL COMMENT '员工姓名', dept_id INT COMMENT '所属部门ID', position VARCHAR(50) COMMENT '职位', basic_salary DECIMAL(10,2) DEFAULT 0 COMMENT '基本工资', hire_date DATE COMMENT '入职日期', phone VARCHAR(20) DEFAULT NULL COMMENT '联系电话', FOREIGN KEY (dept_id) REFERENCES department(dept_id) );

员工编号emp_no加UNIQUE约束是HR系统的行业习惯,员工编号一旦分配就不再复用。basic_salary用DECIMAL(10,2)而不是FLOAT或DOUBLE,这是工资存取里绝对不能妥协的一点——浮点数在金额计算上的精度偏差,会在工资累计到一定规模后暴露出来,具体现象就是小数点后面多出莫名其妙的一串数字。

员工信息模块的维护链路,在JSP里通常是三张页面一条Servlet:list.jsp负责展示列表,add_or_edit.jsp负责新增和编辑表单,DeleteServlet负责删除。查询列表时如果员工数量多,一定需要分页,常见分页SQL是:

-- 按页查询员工列表,pageSize代表每页条数,offset代表偏移量 SELECT e.emp_id, e.emp_no, e.emp_name, e.position, e.basic_salary, d.dept_name FROM employee e LEFT JOIN department d ON e.dept_id = d.dept_id ORDER BY e.emp_id LIMIT #{offset}, #{pageSize};

这里的LIMIT接收两个参数,第一个是偏移量offset,第二个是每页条数pageSize。offset的计算公式是(currentPage - 1) * pageSize。这里把ORDER BY e.emp_id加上是有意的——MySQL里如果不显式指定排序,分页查询的结果可能在两次查询间不稳定,尤其是数据发生增删之后。对Java基础阶段的读者来说,这个ORDER BY习惯是写分页必须刻在脑子里的。

2.3 合同、绩效与考勤模块:HR业务数据的关联统计

合同、绩效、考勤三个模块是人事系统的业务核心,也是这套源码里信息量最密的部分。合同表存员工劳动合同的起止时间、类型和状态;考勤表逐日记录员工出勤状态;绩效模块分工资记录和奖惩记录两方面。

合同表的典型结构:

CREATE TABLE contract ( contract_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '合同ID', emp_id INT NOT NULL COMMENT '员工ID', contract_type VARCHAR(20) COMMENT '合同类型:固定期限/无固定期限', start_date DATE NOT NULL COMMENT '合同开始日期', end_date DATE COMMENT '合同结束日期', contract_status VARCHAR(10) DEFAULT '有效' COMMENT '合同状态', FOREIGN KEY (emp_id) REFERENCES employee(emp_id) );

考勤表的设计要考虑“一人一天一条记录”的约束:

CREATE TABLE attendance ( attendance_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '考勤ID', emp_id INT NOT NULL COMMENT '员工ID', work_date DATE NOT NULL COMMENT '考勤日期', status VARCHAR(10) COMMENT '出勤状态:正常/迟到/早退/请假', UNIQUE KEY uk_emp_date (emp_id, work_date), FOREIGN KEY (emp_id) REFERENCES employee(emp_id) );

uk_emp_date联合唯一索引是考勤模块的关键设计。它从数据库层面保证了同一个员工同一天只能有一条考勤记录,即使页面端漏写了去重判断,数据库也能兜住底线。如果初学时忽略这个唯一约束,演示时重复插入数据,后面的考勤统计报表就会重复计数。

绩效模块的工资统计,通常需要按月关联员工表和考勤表:

-- 按月统计员工出勤天数和迟到早退次数 SELECT e.emp_name, SUM(CASE WHEN a.status = '正常' THEN 1 ELSE 0 END) AS normal_days, SUM(CASE WHEN a.status IN ('迟到', '早退') THEN 1 ELSE 0 END) AS late_days FROM attendance a JOIN employee e ON a.emp_id = e.emp_id WHERE a.emp_id = #{empId} AND DATE_FORMAT(a.work_date, '%Y-%m') = '2025-03' GROUP BY e.emp_name;

这条SQL的核心是CASE WHEN配合聚合函数做条件计数,它把逐条考勤记录的判断逻辑下沉到了数据库。Java层不需要把原始考勤记录全部拉回内存再手工循环累加,直接拿到聚合结果就能封装展示。工资和奖惩的汇总逻辑同理,能交给SQL聚合的统计就只交给SQL。

到这里,六个模块的骨架已经清晰了。系统管理员管入口,部门和员工管基础数据,合同、绩效、考勤管业务流转。把模块和表的关系理成下表,后面导入数据库文件时心里就有底了:

功能模块核心表关键字段关联对象
系统管理员adminadmin_name, admin_password无
部门管理departmentdept_id, dept_name, dept_manageremployee.dept_id
员工管理employeeemp_id, emp_no, basic_salarydepartment.dept_id
合同管理contractcontract_id, emp_id, start_date, end_dateemployee.emp_id
绩效管理reward_punishreward_amount, punish_amountemployee.emp_id
考勤管理attendanceattendance_id, emp_id, work_date, statusemployee.emp_id

3. 把源码跑起来:MyEclipse+Tomcat+MySQL的落地部署步骤

3.1 zip解压与项目导入:动手之前先看清工程结构

压缩包下载后先解压,这一点不需要额外工具,系统自带解压就能完成。解压后你会看到一堆文件,包括db.class、.classpath、style.css、CssAdmin.css、css.css、StyleSheet.css、开题.docx、userreg.gif、login.gif、1-1_01_01_02.gif。这些文件里,.classpath是Eclipse/MyEclipse的工程配置,它决定了项目导入后依赖哪些jar包和输出目录,不要手动删除;db.class是数据库访问类的编译产物,说明这个项目的编译环境已经跑通过一次;开题.docx是毕业设计的开题报告,答辩材料这部分你不用从零开始写。

在导入MyEclipse之前,先确认一下项目的顶层结构。规范的JSP课程设计项目通常是这样的组织方式:

HRMS/ ├── src/ # Java源码目录 │ └── com/hrms/ │ ├── db/DB.java # JDBC连接管理类 │ ├── dao/ # 数据访问层 │ ├── model/ # 实体类 │ └── servlet/ # 控制器Servlet ├── WebRoot/ # Web根目录 │ ├── css/ # style.css、CssAdmin.css等样式表 │ ├── images/ # login.gif、userreg.gif等图片 │ ├── WEB-INF/ │ │ ├── web.xml # Web应用配置文件 │ │ └── lib/ # MySQL JDBC驱动jar包 │ ├── login.jsp # 登录页 │ ├── index.jsp # 后台首页 │ ├── admin/ # 管理员相关页面 │ └── employee/ # 员工信息管理页面 └── hrms.sql # 数据库初始化脚本

这里要特别提醒一点:如果解压后只有.class文件没有.java源文件,那只能跑通演示,答辩时没法改代码。但正常的课程设计源码包都会保留.java和.jsp,你可以打开src目录确认一下。确认有源码后,在MyEclipse里选择File→Import→Existing Projects into Workspace,选中解压目录导入即可。如果导入后项目上有红色感叹号,多半是JDK版本或Tomcat运行时版本不匹配,右键项目→Properties→Java Build Path,把JRE System Library切换到你本机安装的JDK版本。

3.2 数据库初始化与JDBC连接配置:改对三个参数再启动

数据库文件一般是.sql脚本,里面建库建表并且插入了初始数据。导入顺序要讲究,务必先建库再导数据。

mysql -u root -p

进入MySQL交互终端后,执行:

CREATE DATABASE IF NOT EXISTS hrms DEFAULT CHARACTER SET utf8mb4; USE hrms; SOURCE /path/to/hrms.sql;

这里有两个关键点。第一,CREATE DATABASE后面的DEFAULT CHARACTER SET utf8mb4指定了整个库的字符集,如果脚本里没指定而你的MySQL默认字符集是latin1,后面页面上显示中文就会变成问号。第二,用SOURCE命令而不是把SQL内容复制粘贴到终端,SOURCE能正确跳过特殊字符和注释,粘贴长SQL非常容易在引号或转义上出错。

数据库导入完成后,需要确认JDBC连接参数。JSP课程设计里通常把连接信息集中写在DB类或一个jdbc.properties文件里。打开DB.java后会看到类似这样的代码:

// DB.java 数据库连接管理类 public class DB { private static String url = "jdbc:mysql://localhost:3306/hrms?useUnicode=true&characterEncoding=utf8"; private static String username = "root"; private static String password = "123456"; static { try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url, username, password); } }

这里需要改的就是三处:url里的库名hrms、username、password。url字符串里的useUnicode=true&characterEncoding=utf8参数对中文显示至关重要,不要删。如果你的MySQL是8.0以上版本,驱动类名要改成com.mysql.cj.jdbc.Driver,同时url里建议追加serverTimezone=Asia/Shanghai,否则会报时区错误。改完这三个参数后,先不急着启动Tomcat,单独写一个main方法调用DB.getConnection()测试连接,能拿到Connection再往下走。

3.3 发布到Tomcat与验证:端口冲突排查和演示视频对照

在MyEclipse中把项目发布到Tomcat,有两种常见方式:一种是在项目上右键选择Run As→MyEclipse Server Application,自动部署启动;另一种是使用Add Deployment把项目挂到Tomcat的webapps目录。推荐前一种,MyEclipse会替你管理部署路径和编译输出,比手动拷贝webapps更不容易出错。

启动Tomcat之前,先确认8080端口没有被占用:

netstat -ano | findstr :8080

如果看到LISTENING状态和对应的PID,说明端口被占。先别急着结束进程,用tasklist | findstr PID看一下这个进程是谁,如果是之前启动没关干净的Tomcat,自然要清理掉;如果是别的程序,就修改Tomcat的conf/server.xml,找到 ,改成8081或其他空闲端口。

Tomcat正常启动后,浏览器访问http://localhost:8080/HRMS/,看到登录页说明部署成功。这时候打开演示视频,按照视频里的操作顺序把六个模块过一遍:先登录管理员账号,然后依次进部门管理新增一个部门,再进员工管理新增员工并关联到该部门,接着维护合同、录考勤、填奖惩记录,最后查看工资汇总。整个过程走下来,你对这套系统的认知就从“文件清单”变成了“运行逻辑”。到这一步,MySQL管数据、Tomcat管Web服务、JSP负责展示数据的链路就完全串通了,后面再出问题,你也能按“数据库层”还是“Web层”来缩小排查范围。

4. 核心代码走读:登录鉴权、员工CRUD与工资统计的典型写法

4.1 登录鉴权完整链路:从login.jsp到后台首页的数据流转

登录模块是整个系统里代码链路最完整的部分,从页面到Servlet再到DAO和数据库,每个环节都有对应的代码文件。展开login.jsp的核心表单:

<form action="loginServlet" method="post"> <div class="login-row"> <label>用户名:</label> <input type="text" name="username" class="text-input" maxlength="20" /> </div> <div class="login-row"> <label>密 码:</label> <input type="password" name="password" class="text-input" maxlength="20" /> </div> <div class="login-row"> <label>验证码:</label> <input type="text" name="captcha" class="text-input-captcha" maxlength="4" /> <img src="captchaServlet" onclick="this.src='captchaServlet?t='+Math.random()" /> </div> <button type="submit" class="login-btn">登 录</button> </form>

表单的action指向loginServlet,method用post,这些是JSP开发的基础约定。验证码那行代码要留意,onclick里给img标签重新赋src,后面加的t=Math.random()是为了防止浏览器缓存同一张验证码图片。

后台Servlet拿到表单参数后,先比对验证码再验证账号密码:

// 验证码比对在doPost前面完成 String inputCaptcha = request.getParameter("captcha"); String sessionCaptcha = (String) session.getAttribute("captchaCode"); if (inputCaptcha == null || !inputCaptcha.equalsIgnoreCase(sessionCaptcha)) { request.setAttribute("error", "验证码不正确"); request.getRequestDispatcher("login.jsp").forward(request, response); return; }

这段代码的关键细节是equalsIgnoreCase,验证码通常不区分大小写。但比对之前一定要先判空,因为Session过期后sessionCaptcha为null,直接调equals会抛NullPointerException。这个判空习惯在后续所有Session取值场景里都通用。

4.2 员工信息CRUD:JDBC操作与JSP页面交互的标准模式

员工信息管理是Java课程设计里出现频率最高的CRUD模块,它完整覆盖了新增、查询、编辑、删除四种操作,还因为带了部门外键关联,涉及下拉框的数据填充。

新增员工页面上的部门下拉框,典型写法是直接嵌入JSP脚本:

<select name="deptId" class="select-box"> <option value="0">请选择部门</option> <% DepartmentDao dd = new DepartmentDao(); List<Department> deptList = dd.findAll(); for (Department dept : deptList) { %> <option value="<%= dept.getDeptId() %>"><%= dept.getDeptName() %></option> <% } %> </select>

这段代码把Java逻辑直接写在页面上,课程设计里最常见,优点是答辩时能非常直观地讲清楚数据来源。缺点是表现层和业务层耦合严重,如果后续项目规模变大,这种脚本片段会让页面维护变得痛苦。替代方案是用AJAX接口动态加载部门列表,但现阶段先跑通更重要。

员工列表的分页查询逻辑:

// EmployeeDao.java 分页查询 public List<Employee> findPage(int pageNum, int pageSize) { List<Employee> list = new ArrayList<Employee>(); int offset = (pageNum - 1) * pageSize; String sql = "SELECT * FROM employee LIMIT ?, ?"; try (Connection conn = DB.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setInt(1, offset); ps.setInt(2, pageSize); ResultSet rs = ps.executeQuery(); while (rs.next()) { Employee emp = new Employee(); emp.setEmpId(rs.getInt("emp_id")); emp.setEmpNo(rs.getString("emp_no")); emp.setEmpName(rs.getString("emp_name")); // 其余字段映射省略 list.add(emp); } } catch (SQLException e) { e.printStackTrace(); } return list; }

这里的核心是PreparedStatement的?占位符方式。setInt(1, offset)和setInt(2, pageSize)分别对应LIMIT后的偏移量和每页条数。必须强调:不要在SQL里用字符串拼接参数,比如"SELECT * FROM employee WHERE emp_no = '" + empNo + "'"。这不仅慢,更重要的是SQL注入风险。PreparedStatement的预编译机制能同时解决性能和安全性两个问题,这是Java基础阶段就必须建立的习惯。

4.3 工资统计与考勤汇总:SQL聚合是王道,Java层只做展示

如果要在这个系统基础上加一个“工资月报”功能,正解是直接在SQL里完成聚合,而不是在Java里循环累加。典型写法:

SELECT e.emp_name, e.basic_salary, COALESCE(SUM(r.reward_amount), 0) AS total_reward, COALESCE(SUM(r.punish_amount), 0) AS total_punish, e.basic_salary + COALESCE(SUM(r.reward_amount), 0) - COALESCE(SUM(r.punish_amount), 0) AS final_salary FROM employee e LEFT JOIN reward_punish r ON e.emp_id = r.emp_id WHERE DATE_FORMAT(r.occur_date, '%Y-%m') = '2025-03' GROUP BY e.emp_id;

这条SQL的精髓在COALESCE函数。当员工当月没有任何奖惩记录时,SUM(r.reward_amount)返回的是NULL,如果不对SUM做COALESCE兜底,最终算出的final_salary就会是NULL,Java端拿到NULL再去封装实体类,很容易在输出时出现“null”字符串或者NPE。COALESCE(SUM(...), 0)本质上是在SQL层给空值上了保险。

关于工资字段,在这里再强调一次:金额类型必须用DECIMAL(10,2),禁止用FLOAT或DOUBLE。浮点数在计算机里是近似存储,累加多次后精度误差会越积越大,到时候账面上出现几分钱的差异,查起来会让人怀疑人生。数据库设计阶段把类型定死,后面就不会有这种糟心事。

5. 避坑指南:跑通JSP人事系统的四个典型翻车现场

5.1 JDBC驱动报错ClassNotFoundException

现象:Tomcat启动后访问登录页正常,但点登录提交时页面报500错误,控制台出现java.lang.ClassNotFoundException: com.mysql.jdbc.Driver。

原因:MySQL驱动的jar包没有放进WEB-INF/lib目录,或者放进了目录但项目没有刷新。课程设计源码包经常把驱动jar漏掉,因为原作者用的是自己本地Tomcat的公共库,打包时不会带上外部依赖。

解决:先确认你本机MySQL版本。MySQL 5.x用mysql-connector-java 5.1.49版本,MySQL 8.x用8.0.x版本,驱动类名也要相应调整。把jar包拷贝到WebRoot/WEB-INF/lib目录下,在MyEclipse里右键项目→Refresh,然后clean重新部署。验证是否生效,可以临时在LoginServlet里打印Class.forName的结果,能加载成功就说明jar包路径没问题。

5.2 中文全部显示成问号

现象:系统启动后,后台页面上的部门名称、员工姓名、合同信息等中文全部显示为???,甚至登录后的欢迎语也是乱码。

原因:字符集不一致,且是三个环节同时不一致——数据库表字符集、JDBC连接字符集、JSP页面字符集。任何一个环节用了latin1或ISO-8859-1,中文就会在某个环节被截断成乱码。

解决:按链路逐层排查。第一层,数据库执行ALTER DATABASE hrms CHARACTER SET utf8mb4;第二层,JDBC的url追加useUnicode=true&characterEncoding=utf8;第三层,每个JSP页面头部设置pageEncoding="UTF-8",在Servlet入口调用request.setCharacterEncoding("UTF-8")。三层全部对齐后重启Tomcat。排查顺序一定是从数据库往页面逐层检查,哪一层没改就定位哪一层,不要只在页面端折腾。

5.3 Tomcat端口8080被占用

现象:启动Tomcat时立刻报Address already in use: JVM_Bind:8080,服务起不来,控制台堆栈直接指向端口绑定失败。

原因:本机有另一个Tomcat实例在运行,或者Oracle、Jenkins之类的程序占用了8080端口。课程设计场景里最常见的元凶是之前启动过Tomcat但没有正常关闭,残留的java进程还占着端口。

解决:用netstat -ano | findstr :8080查到PID,再用tasklist | findstr PID确认进程身份。确认是Tomcat残留就结束它;如果是其他必要程序,修改conf/server.xml里的 改成8081,之后访问地址统一换成http://localhost:8081/HRMS/。另外提醒一句,Tomcat关闭时使用shutdown.bat而不是直接关控制台窗口,能减少这类残留进程的出现频率。

5.4 数据库导入报外键约束失败

现象:执行hrms.sql时,在INSERT语句处报错Cannot add or update a child row: a foreign key constraint fails,导入中断。

原因:SQL脚本里建表和插数据的顺序不对——先插了员工表数据,但部门表还没插入对应记录,外键引用的dept_id在部门表里不存在;或者表结构里外键约束写死了,数据导入时无法跳过校验。

解决:导入前在脚本最前面加SET FOREIGN_KEY_CHECKS = 0,最后面加SET FOREIGN_KEY_CHECKS = 1,临时关闭外键检查。如果脚本已经部分执行,残留了半张表,先DROP DATABASE hrms再重新CREATE,避免脏数据干扰后续操作。这个技巧不仅适用于本次导入,以后处理任何带外键的SQL脚本都适用,属于数据库操作的通用后悔药。

6. 二次开发进阶:把课程设计改造成可答辩、可扩展的HR系统

这套系统从功能覆盖来说已经够毕业设计的水准,但要从“能跑”变成“拿得出手”,我建议在三个方向做加强。

第一个是密码安全。检查一下admin表里如果存的是明文密码,答辩时很容易被一句“密码安全怎么保证”问住。改造思路是把密码改成加盐的SHA-256散列存放,用SecureRandom生成独立的盐值字段,登录校验时取盐重新计算摘要再比对。这个改动涉及admin表结构、管理员注册或修改密码的Servlet、登录校验逻辑三处,工作量不大,但讲出来是明显的加分项。

第二个是权限控制规范化。目前每个页面头部的Session判断,可以统一收敛到一个LoginFilter里。在web.xml中配置拦截路径,放行login.jsp和loginServlet,其余所有请求都走过滤器校验。这样一来后续新增页面不需要重复写鉴权代码,也方便扩展不同管理员的访问级别。

第三个是数据导出。真实HR场景里,员工列表和考勤月报不能只在页面上看,要能导出Excel。实现方案是用POI的XSSFWorkbook把查询结果写入.xlsx,通过response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")设置MIME类型,浏览器收到响应后会弹出下载框。这个功能加完之后,整个系统的实用感会提升一大截。

验证方法同样值得投入时间。每改完一个功能,不要只点一遍正常路径,把异常路径也完整过一遍:登录时故意输入错误密码、查询时传一个不存在的员工编号、删除有员工关联的部门时观察外键约束是否阻止删除。数据一致性检查是答辩现场最容易让老师留下好印象的环节。

最后说我自己的一个习惯。每次动手改这套系统的代码之前,我都会先导出一份完整的数据库备份,再复制一份源码包放在旁边作为回滚点。改挂了随时还原,复盘时也有对照。从那以后我每次做课程设计改造都强制走这一遍备份流程,确实省掉了不少返工的折腾。希望这套人事系统的拆解对你有帮助。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询