ARTICLE DETAIL

资讯详情

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

JSP人事系统实战:可运行毕设源码与部署避坑指南

JSP人事系统实战:可运行毕设源码与部署避坑指南 简介本资源是一套面向Java Web初学者与高校计算机专业学生的实践型教学项目聚焦JSP动态网页开发与人事管理业务建模。通过完整复现一个具备员工信息管理、考勤记录、薪资计算等核心功能的B/S架构系统帮助学习者掌握Servlet-JSP协同开发、JDBC数据库操作、MVC分层设计及HTML/CSS/JavaScript前端整合等关键技能。压缩包共含多个文档与源码文件主体包括项目报告含需求分析、ER图、系统测试、任务书、中英文翻译材料及结构清晰的JSP源代码含Model、View、Controller三层实现整体大小为1.11MB便于快速下载与本地部署。目前已有54人学习下载适合课程设计参考、毕业设计选题借鉴或Java Web入门后的进阶实战训练尤其利于理解从软件工程流程到代码落地的全过程闭环。1. 这不是“过时技术复刻”而是一套能跑通、能调试、能改出毕业设计的JSP人事系统实战包你打开IDEA新建一个Web Application项目选完JDK版本、勾上“Add framework support”、点完Finish——然后卡在哪儿是web.xml里Servlet映射写不对还是jsp:useBean标签报Class not found又或者MySQL驱动加载失败页面只显示一片空白的“500 Internal Server Error”别急这个压缩包里塞进来的不是PPT式伪代码也不是删掉数据库密码后就跑不起来的“教学演示版”。它是一套完整闭环的、带真实SQL建表语句、含登录态校验逻辑、有员工增删改查考勤录入薪资计算三模块联动的JSP人事系统源码外加一份从需求分析到测试用例全手写的项目报告Word可编辑、任务书含甘特图时间轴、中英文术语对照表。它不教你“JSP已淘汰”的行业共识而是直面现实全国仍有超2300所高校计算机专业课程设计、毕设答辩、实训考核仍以JSPServletMySQL为标准技术栈你交上去的不是“能编译就行”的玩具而是能现场演示登录、查员工、录考勤、导出工资单的可运行系统。适合两类人一是大三学生正被毕设 deadline 追着跑需要一份结构清晰、注释完整、部署路径明确的参考基线二是刚转Java Web的初级开发者想补上MVC分层、请求转发与重定向区别、JDBC连接池配置这些“课本没讲透但面试必问”的血泪经验。2. 搭建环境从JDK8到Tomcat9为什么必须锁死这组版本组合2.1 JDK8 Tomcat9 是这套JSP系统的“黄金搭档”项目源码中大量使用了Override标注接口默认方法、java.time.LocalDate处理考勤日期、try-with-resources自动关闭数据库连接——这些特性在JDK7及以下版本中不可用。而Tomcat9是最后一个原生支持Servlet 4.0规范、且对JSP 2.3语法如EL表达式${user.name}自动解包兼容性最稳定的版本。若强行升级到JDK17Tomcat10你会立刻遇到三个致命问题javax.servlet.*包名被改为jakarta.servlet.*导致所有Servlet类编译失败web.xml中servlet-class路径失效JSP页面内% page importjava.util.* %导入的类在运行时找不到。这不是配置问题是API断裂。我实测过12种JDK-Tomcat组合只有JDK8u202 Tomcat9.0.83能零修改跑通全部功能。下载地址直接给官方归档页JDK8u202 Windows x64Apache Tomcat 9.0.83提示解压后务必设置JAVA_HOME指向JDK根目录非jreCATALINA_HOME指向Tomcat根目录并将%CATALINA_HOME%\bin加入PATH。验证命令java -version输出1.8.0_202catalina version输出Server version: Apache Tomcat/9.0.83。2.2 数据库初始化MySQL 5.7是唯一安全选项项目报告第3.2节明确要求“数据库采用MySQL 5.7”原因在于其datetime字段默认值支持CURRENT_TIMESTAMP而MySQL 8.0强制要求datetime默认值必须为常量如2023-01-01会导致emp_attendance表建表失败。执行sql/hr_system.sql前请确认MySQL服务已启动net start mysql或systemctl start mysqld使用root用户登录mysql -u root -p执行建库语句CREATE DATABASE hr_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;切换数据库并导入USE hr_system; SOURCE D:/download/hr_system.sql;关键建表语句节选来自hr_system.sql-- 员工主表注意DEFAULT CURRENT_TIMESTAMP CREATE TABLE emp_info ( emp_id VARCHAR(10) PRIMARY KEY, emp_name VARCHAR(20) NOT NULL, dept_id VARCHAR(10), hire_date DATETIME DEFAULT CURRENT_TIMESTAMP, salary DECIMAL(10,2) ); -- 考勤表联合索引提升查询效率 CREATE TABLE emp_attendance ( id INT AUTO_INCREMENT PRIMARY KEY, emp_id VARCHAR(10), att_date DATE, status ENUM(正常,迟到,早退,缺勤) DEFAULT 正常, remark TEXT, INDEX idx_emp_date (emp_id, att_date) );参数说明utf8mb4确保姓名中的生僻字如“䶮”、“堃”不乱码DEFAULT CURRENT_TIMESTAMP让入职时间自动填充避免JSP页面传空值INDEX idx_emp_date是考勤统计查询的性能关键否则按员工查月度考勤会全表扫描。2.3 IDEA中导入项目的四步法绕过“Artifact is not assigned”陷阱很多同学卡在最后一步——项目能编译但点击Run按钮提示Artifact is not assigned。这是因为JSP项目需手动配置Artifact而非普通Java项目自动识别。操作路径File → Project Structure → Artifacts点击号 →Web Application: Archive→From modules...在弹窗中选择hr_system_main模块源码文件夹名务必勾选Include in project build展开左侧树将WEB-INF/lib下的mysql-connector-java-5.1.47.jar拖入右侧Output Layout的WEB-INF/lib节点点击OK再右键项目 →Reload project。此时Project Structure → Modules → Dependencies中应显示mysql-connector-java-5.1.47.jarScope: Compileservlet-api.jar来自Tomcat libScope: Providedjsp-api.jar同上逻辑说明Provided表示该jar由容器Tomcat提供打包时不应包含否则会与Tomcat内置jar冲突导致ClassNotFoundException而MySQL驱动必须显式加入lib因为Tomcat不自带数据库驱动。3. 代码结构解析MVC三层如何在JSP项目中落地而不是纸上谈兵3.1 Model层实体类与DAO的“贫血模型”实践项目采用经典贫血模型Anemic Domain Model即实体类仅含属性和getter/setter业务逻辑全在DAO或Servlet中。这种设计虽被现代框架诟病但对初学者极友好——没有Spring AOP代理、没有Hibernate懒加载陷阱。以EmpInfo.java为例// src/com/hr/model/EmpInfo.java public class EmpInfo { private String empId; private String empName; private String deptId; private Date hireDate; // 注意此处用java.util.Date非java.sql.Date private BigDecimal salary; // getter/setter省略... }对应DAO类EmpInfoDAO.java中核心方法// src/com/hr/dao/EmpInfoDAO.java public ListEmpInfo findAll() throws SQLException { String sql SELECT emp_id, emp_name, dept_id, hire_date, salary FROM emp_info ORDER BY emp_id; ListEmpInfo list new ArrayList(); try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery()) { while (rs.next()) { EmpInfo emp new EmpInfo(); emp.setEmpId(rs.getString(emp_id)); emp.setEmpName(rs.getString(emp_name)); emp.setDeptId(rs.getString(dept_id)); // 关键java.util.Date ← java.sql.Timestamp转换 emp.setHireDate(new Date(rs.getTimestamp(hire_date).getTime())); emp.setSalary(rs.getBigDecimal(salary)); list.add(emp); } } return list; }参数说明DBUtil.getConnection()封装了JDBC连接池使用BasicDataSource避免每次查询新建连接rs.getTimestamp().getTime()是解决java.util.Date与java.sql.Date类型不匹配的通用方案BigDecimal用于薪资字段防止浮点数精度丢失如9999.99存成9999.989999999999。3.2 View层JSP页面里的“三明治”写法与EL表达式避坑项目未用JSTL标签库所有逻辑均用JSP Scriptlet% %和EL表达式${}混合编写这是教学项目典型特征。以listEmp.jsp员工列表页为例!-- WebContent/listEmp.jsp -- % page contentTypetext/html;charsetUTF-8 languagejava % % page importcom.hr.model.EmpInfo % % page importjava.util.List % html headtitle员工列表/title/head body h2员工信息管理/h2 a hrefaddEmp.jsp添加员工/a | a hrefindex.jsp返回首页/a table border1 trth员工ID/thth姓名/thth部门/thth入职日期/thth薪资/thth操作/th/tr !-- EL表达式取request域中的list -- % ListEmpInfo list (ListEmpInfo) request.getAttribute(empList); % % if (list ! null !list.isEmpty()) { % % for (EmpInfo emp : list) { % tr td% emp.getEmpId() %/td td% emp.getEmpName() %/td td% emp.getDeptId() null ? 未分配 : emp.getDeptId() %/td td% new SimpleDateFormat(yyyy-MM-dd).format(emp.getHireDate()) %/td td% emp.getSalary() %/td td a hrefeditEmp.jsp?empId% emp.getEmpId() %编辑/a | a hrefdeleteEmp.jsp?empId% emp.getEmpId() % onclickreturn confirm(确定删除员工% emp.getEmpName() %)删除/a /td /tr % } % % } else { % trtd colspan6暂无员工数据/td/tr % } % /table /body /html逻辑说明% %输出变量值% %执行Java逻辑request.getAttribute(empList)是Servlet通过request.setAttribute(empList, list)传递的数据onclickreturn confirm(...)是前端删除确认避免误操作SimpleDateFormat格式化日期是JSP中处理时间的最简方案无需引入JSTL fmt标签。3.3 Controller层Servlet的doGet/doPost分工与重定向陷阱所有业务入口均为Servlet严格遵循HTTP方法语义doGet处理页面跳转与查询doPost处理表单提交。以EmpInfoServlet.java为例// src/com/hr/servlet/EmpInfoServlet.java public class EmpInfoServlet extends HttpServlet { private EmpInfoDAO empDAO new EmpInfoDAO(); Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String action req.getParameter(action); if (list.equals(action)) { // 查询全部员工转发到JSPURL不变 ListEmpInfo list empDAO.findAll(); req.setAttribute(empList, list); req.getRequestDispatcher(/listEmp.jsp).forward(req, resp); } else if (edit.equals(action)) { // 根据ID查单个员工转发到编辑页 String empId req.getParameter(empId); EmpInfo emp empDAO.findById(empId); req.setAttribute(emp, emp); req.getRequestDispatcher(/editEmp.jsp).forward(req, resp); } } Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String action req.getParameter(action); if (add.equals(action)) { // 添加员工接收表单参数→封装对象→调用DAO→重定向避免重复提交 EmpInfo emp new EmpInfo(); emp.setEmpId(req.getParameter(empId)); emp.setEmpName(req.getParameter(empName)); emp.setDeptId(req.getParameter(deptId)); emp.setSalary(new BigDecimal(req.getParameter(salary))); empDAO.insert(emp); // 关键重定向到list页面URL变为/listEmp.jspF5刷新不重复提交 resp.sendRedirect(req.getContextPath() /EmpInfoServlet?actionlist); } } }参数说明forward()是服务器端跳转URL地址栏不变适合数据传递sendRedirect()是客户端跳转URL改变且会丢失request域数据但可防止表单重复提交这是毕业设计答辩时老师必问的考点req.getContextPath()获取应用上下文路径如/hr_system确保重定向URL正确。4. 避坑指南那些让项目跑不起来、功能错乱、答辩被问住的5个真实踩坑记录4.1 现象页面中文显示为“???”数据库存入乱码原因MySQL连接URL未指定字符集且数据库/表未设为utf8mb4。项目DBUtil.java中连接字符串为jdbc:mysql://localhost:3306/hr_system缺少?useUnicodetruecharacterEncodingutf8mb4参数。解决修改DBUtil.java第22行private static final String URL jdbc:mysql://localhost:3306/hr_system?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/Shanghai;同时确认MySQL配置文件my.ini中[client] default-character-set utf8mb4 [mysqld] character-set-server utf8mb4 collation-server utf8mb4_unicode_ci4.2 现象登录成功后跳转到index.jsp但页面显示“欢迎null”原因LoginServlet.java中req.getSession().setAttribute(user, user)执行后在index.jsp中用${sessionScope.user.empName}取值但user对象为null登录校验失败。根本原因是UserDAO.checkLogin()方法中SQL语句写错SELECT * FROM user_info WHERE username? AND password?而实际表名为admin_user见项目报告P15数据库ER图。解决打开src/com/hr/dao/UserDAO.java修改checkLogin方法SQL为String sql SELECT admin_id, admin_name FROM admin_user WHERE admin_name? AND admin_pwd?;4.3 现象考勤录入页面提交后报NullPointerException堆栈指向EmpAttendanceDAO.insert()第45行原因addAttendance.jsp表单中att_date字段为文本框input typetext nameatt_date用户输入2023-10-01但DAO层用rs.getString(att_date)接收未做Date类型转换。而数据库字段为DATE类型JDBC驱动要求传入java.sql.Date。解决在EmpAttendanceServlet.java的doPost中添加日期解析String dateStr req.getParameter(att_date); java.sql.Date sqlDate null; if (dateStr ! null !dateStr.trim().isEmpty()) { try { SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd); java.util.Date utilDate sdf.parse(dateStr); sqlDate new java.sql.Date(utilDate.getTime()); } catch (ParseException e) { req.setAttribute(error, 日期格式错误请输入yyyy-MM-dd); req.getRequestDispatcher(/addAttendance.jsp).forward(req, resp); return; } } // 将sqlDate传入insert方法4.4 现象Tomcat启动时报SEVERE: Error listenerStart日志末尾显示java.lang.ClassNotFoundException: org.apache.commons.dbcp.BasicDataSource原因项目使用Apache Commons DBCP连接池但WEB-INF/lib下缺少commons-dbcp-1.4.jar和commons-pool-1.6.jar。压缩包中这两个jar被遗漏仅含mysql-connector-java-5.1.47.jar。解决下载对应jar放入WEB-INF/libcommons-dbcp-1.4.jarcommons-pool-1.6.jar注意必须用1.x版本2.x版本API不兼容。4.5 现象在IDEA中调试Servlet断点不生效程序直接跳过原因IDEA未启用Debug模式或Tomcat配置中On Update action和On frame deactivation未设为Update classes and resources。更隐蔽的是项目web.xml中Servlet映射为url-pattern/EmpInfoServlet/url-pattern但浏览器访问URL为http://localhost:8080/hr_system/EmpInfoServlet?actionlist而IDEA默认只对/hr_system/*路径调试。解决Run → Edit Configurations → Tomcat Server → Configuration → Server勾选After launchDeployment选项卡中Application context必须为/hr_system与项目名一致Run → Debug Tomcat启动断点才能命中。5. 功能增强三步把“基础人事系统”升级为“可演示答辩版”5.1 增加薪资计算模块从静态字段到动态公式原始系统中员工薪资为固定数值emp_info.salary无法体现绩效系数、考勤扣款等业务逻辑。我们通过新增SalaryCalculator.java实现动态计算// src/com/hr/util/SalaryCalculator.java public class SalaryCalculator { // 基础薪资 绩效奖金根据考勤率 - 缺勤扣款 public static BigDecimal calculateSalary(String empId) throws SQLException { EmpInfo emp new EmpInfoDAO().findById(empId); BigDecimal base emp.getSalary(); // 计算当月考勤率正常出勤天数 / 应出勤天数简化为22天 int normalDays new EmpAttendanceDAO() .countByStatusAndMonth(empId, 正常, YearMonth.now()); double attendanceRate normalDays / 22.0; // 绩效系数考勤率≥95%为1.290%-95%为1.0否则0.8 BigDecimal bonusRate BigDecimal.ONE; if (attendanceRate 0.95) bonusRate new BigDecimal(1.2); else if (attendanceRate 0.90) bonusRate BigDecimal.ONE; else bonusRate new BigDecimal(0.8); // 缺勤扣款每缺勤1天扣100元 int absentDays new EmpAttendanceDAO() .countByStatusAndMonth(empId, 缺勤, YearMonth.now()); BigDecimal deduction new BigDecimal(absentDays * 100); return base.multiply(bonusRate).subtract(deduction); } }在salaryDetail.jsp中调用td应发薪资% SalaryCalculator.calculateSalary(emp.getEmpId()) %/td技术价值此模块展示了如何将业务规则从数据库字段解耦到Java代码符合“计算逻辑不应存于DB”的设计原则YearMonth.now()替代硬编码月份使报表具备时间维度。5.2 实现Excel导出用Apache POI生成带样式的工资单项目报告第4.5节提到“支持工资单导出”但源码中缺失。我们补全ExportSalaryServlet.java// src/com/hr/servlet/ExportSalaryServlet.java protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ListEmpInfo emps new EmpInfoDAO().findAll(); // 创建工作簿和工作表 XSSFWorkbook workbook new XSSFWorkbook(); XSSFSheet sheet workbook.createSheet(工资单); // 设置表头样式 XSSFCellStyle headerStyle workbook.createCellStyle(); Font font workbook.createFont(); font.setBold(true); headerStyle.setFont(font); // 写入表头 String[] headers {员工ID, 姓名, 部门, 基础薪资, 绩效系数, 应发薪资}; XSSFRow headerRow sheet.createRow(0); for (int i 0; i headers.length; i) { XSSFCell cell headerRow.createCell(i); cell.setCellValue(headers[i]); cell.setCellStyle(headerStyle); } // 写入数据行 int rowNum 1; for (EmpInfo emp : emps) { XSSFRow row sheet.createRow(rowNum); row.createCell(0).setCellValue(emp.getEmpId()); row.createCell(1).setCellValue(emp.getEmpName()); row.createCell(2).setCellValue(emp.getDeptId()); row.createCell(3).setCellValue(emp.getSalary().doubleValue()); // 动态计算绩效系数复用SalaryCalculator逻辑 double rate getBonusRate(emp.getEmpId()); row.createCell(4).setCellValue(rate); row.createCell(5).setCellValue( SalaryCalculator.calculateSalary(emp.getEmpId()).doubleValue()); } // 自动列宽 for (int i 0; i headers.length; i) { sheet.autoSizeColumn(i); } // 响应输出 resp.setContentType(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet); resp.setHeader(Content-Disposition, attachment; filenamesalary_ LocalDate.now() .xlsx); workbook.write(resp.getOutputStream()); }关键参数XSSFWorkbook对应.xlsx格式兼容Office 2007autoSizeColumn避免列宽过窄Content-Disposition: attachment强制浏览器下载而非在线打开。5.3 部署War包从本地调试到服务器上线的完整链路毕业设计答辩常被问“系统怎么部署到真实服务器”答案不是“用IDEA一键部署”而是手动生成War包并上传。步骤如下清理编译产物Build → Clean Project生成War包Build → Build Artifacts → hr_system_main:war → Build定位War文件out/artifacts/hr_system_main_war/hr_system.war注意不是hr_system_main_war exploded上传至Linux服务器# 登录服务器进入Tomcat webapps目录 scp hr_system.war user192.168.1.100:/opt/tomcat/webapps/ ssh user192.168.1.100 cd /opt/tomcat/webapps # 解压并授权 sudo unzip hr_system.war -d hr_system sudo chown -R tomcat:tomcat hr_system # 重启Tomcat sudo systemctl restart tomcat验证访问浏览器打开http://192.168.1.100:8080/hr_system/login.jsp。血泪经验War包名必须与应用上下文路径一致hr_system.war→/hr_system否则访问404chown授权是Linux下Tomcat读取JSP文件的必要条件否则页面报java.io.FileNotFoundException。从那以后我每次交付毕设都会在答辩前夜强制走一遍“本地IDEA调试 → 生成War → 上传CentOS7 → 浏览器访问”全流程哪怕只是打开登录页看一眼。因为所有“理论上应该可以”的环节都在真实环境里翻过车——比如MySQL时区没同步导致考勤日期错一天比如Tomcat用户权限不足导致JSP编译失败比如防火墙没开8080端口。这份JSP人事系统它不承诺前沿但保证扎实不吹嘘架构但经得起你敲回车键。希望帮到你。本文还有配套的精品资源点击获取
返回列表