资讯动态

JSP+Servlet人事管理系统实战部署与安全加固

发布时间:2026/10/8 11:50:10 来源:尧图企业网站定制
简介这是一套基于JSPServletTomcatMySQL实现的完整人事管理系统源码面向计算机、数学、电子信息等专业的本科生与初学者适用于课程设计、期末大作业及毕业设计参考。系统涵盖员工信息管理、部门维护、考勤统计、权限控制等核心模块代码结构清晰具备典型Web三层架构特征便于理解MVC模式在Java Web开发中的实际应用。资源包共2000个文件以49个Java类文件支撑业务逻辑、42个JSP页面实现前端交互、1294个JS和404个CSS文件保障AdminLTE后台界面功能与样式另含6个SQL脚本用于数据库初始化整体压缩包大小为73.74MB。目前已有205人学习下载提供开箱即用的可运行环境含配置说明与部署指南读者可快速部署调试、深入分析请求流转机制、学习数据库表设计思路及前后端数据交互方式是夯实Java Web基础与项目实战能力的优质学习材料。1. 这不是“过时技术堆砌”而是用 JSP Servlet Tomcat MySQL 搭建可交付、可维护、能上线的人事管理系统它解决的是中小团队「无现成HR SaaS预算、又不敢上SpringBoot微服务」的真实困境你搜“JSP人事管理系统源码”大概率会看到一堆带.zip后缀的压缩包点开是乱序的WebContent、src、lib目录web.xml里还写着servlet-classcom.servlet.AddEmpServlet/servlet-class——第一反应是“这玩意儿2010年就该进博物馆了”。但现实是长三角300人以下制造企业87%的内部系统仍跑在Tomcat 8.5JDK 8组合上某地人社部门下属培训中心用同一套JSP架构支撑着6年未重构的员工档案、考勤、薪资模块日均处理2300次表单提交。这不是怀旧是成本与风险的权衡没有运维团队不碰Docker和K8sJava工程师平均年龄42岁SpringBoot配置文件写错一个冒号就要重启三次MySQL 5.7.44仍是政企采购白名单版本。本篇不讲“为什么JSP被淘汰”只讲怎么用这套被低估的组合把人事管理系统真正跑起来、改得动、查得清、扛得住并发压测——从解压zip那一刻起到登录页显示“张三人事专员”为止每一步都踩过坑、调过参数、验过数据一致性。2. 解压即启动用最简路径跑通人事管理系统绕过IDEA/Tomcat配置黑洞2.1 确认源码包结构是否符合Java Web经典分层否则后续全崩拿到人事管理系统源码.zip后不要急着导入IDEA。先解压用命令行快速验证目录合法性unzip -l 人事管理系统源码.zip | head -20你必须看到以下4个关键路径存在缺一不可WebContent/WEB-INF/web.xml→ Servlet注册入口WebContent/WEB-INF/lib/*.jar→ 至少含mysql-connector-java-5.1.47.jar或8.0.28.jarsrc/com/servlet/*.java→ 所有Servlet类如LoginServlet.javasrc/com/dao/*.java→ 数据访问层如EmployeeDAO.java提示若看到src/main/java或pom.xml说明这是Maven项目本篇不适用——本文所有操作基于传统Ant构建风格的纯War结构。遇到Maven版请立即停止转用mvn clean package生成war包后再部署。2.2 Tomcat 8.5本地部署避开“Server not found”和“Context path empty”两大玄学报错Tomcat版本必须锁定为8.5.x推荐8.5.99原因很实在Tomcat 9默认禁用org.apache.jasper.runtime.JspFactoryImpl而JSP页面里大量jsp:useBean依赖此实现Tomcat 10全面转向Jakarta EE命名空间jakarta.servlet.*但源码中所有import仍是javax.servlet.*强行升级必报NoClassDefFoundError。下载地址官方归档页https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.99/bin/apache-tomcat-8.5.99.zip解压后不要动conf/server.xml——尤其别改Connector port8080因为源码中所有AJAX请求硬编码了http://localhost:8080/emp/xxx。将解压后的源码目录重命名为hrms复制到apache-tomcat-8.5.99/webapps/下。启动前执行关键检查# 检查端口占用Windows netstat -ano | findstr :8080 # 若有PID用 taskkill /F /PID XXXX 强制结束 # Linux/macOS lsof -i :8080 kill -9 $(lsof -t -i :8080)启动命令Windowscd apache-tomcat-8.5.99\bin startup.bat启动后立刻打开浏览器访问http://localhost:8080/hrms/login.jsp——注意不是/hrms/根路径绝大多数JSP人事系统把登录页设为context path下的第一入口。若返回40490%概率是webapps/hrms/目录下缺少login.jsp此时需检查源码包中WebContent/login.jsp是否被解压到正确位置。2.3 MySQL 5.7.44数据库初始化用SQL脚本而非图形化工具导入避免字符集翻车源码包中必然包含sql/或db/目录里面是.sql文件常见名hrms_db.sql、init.sql。严禁用Navicat或MySQL Workbench双击导入——它们默认用UTF8mb4字符集创建库而JSP页面% page contentTypetext/html;charsetgb2312%声明的是GB2312导致中文姓名存入后变成????。正确做法命令行强制指定字符集# 创建数据库时显式指定字符集 mysql -u root -p -e CREATE DATABASE hrms DEFAULT CHARACTER SET gbk COLLATE gbk_chinese_ci; # 导入SQL关键--default-character-setgbk mysql -u root -p --default-character-setgbk hrms sql/hrms_db.sql验证导入结果USE hrms; SHOW TABLES; -- 应看到 emp_info, dept_info, salary_record 等表 SELECT * FROM emp_info LIMIT 1; -- 检查中文字段是否正常显示注意若SQL脚本中含CREATE DATABASE ... CHARSETutf8mb4语句必须手动编辑删除该行否则CREATE DATABASE会覆盖你刚建的gbk库。3. 登录失败数据库连不上JSP页面空白——人事管理系统启动阶段三大避坑清单3.1 现象访问login.jsp页面显示空白F12看Network无任何HTTP响应原因JSP编译失败Tomcat未生成.class文件但错误日志被默认级别屏蔽解决打开apache-tomcat-8.5.99/conf/logging.properties将org.apache.jasper.level WARNING改为org.apache.jasper.level FINE重启Tomcat在logs/catalina.out末尾搜索JasperException90%是% page importcom.dao.UserDAO%路径错误或DAO类未编译→血泪经验src/com/dao/UserDAO.java必须被javac编译成WEB-INF/classes/com/dao/UserDAO.class检查WEB-INF/classes/下是否存在对应.class文件树3.2 现象输入账号密码点击登录页面跳转到error.jsp且URL变为/hrms/servlet/LoginServlet原因web.xml中servlet-mapping的url-pattern与JSP中form action不一致解决打开WebContent/login.jsp找到form actionservlet/LoginServlet methodpost再打开WEB-INF/web.xml确认存在servlet servlet-nameLoginServlet/servlet-name servlet-classcom.servlet.LoginServlet/servlet-class /servlet servlet-mapping servlet-nameLoginServlet/servlet-name url-pattern/servlet/LoginServlet/url-pattern !-- 必须与form action完全一致 -- /servlet-mapping→关键细节Tomcat 8.5对URL Pattern匹配极其严格/servlet/LoginServlet不能写成/servlet/loginServlet大小写敏感3.3 现象登录后跳转到main.jsp但员工列表区域显示“查询失败Communications link failure”原因com.dao.BaseDAO.java中数据库连接URL写死为localhost而MySQL服务实际运行在Docker容器或远程服务器解决找到src/com/dao/BaseDAO.java定位private static final String URL jdbc:mysql://localhost:3306/hrms?useUnicodetruecharacterEncodinggbk;将localhost改为真实IP如192.168.1.100同时确保MySQL已授权远程访问CREATE USER hrms_user% IDENTIFIED BY StrongPass123!; GRANT ALL PRIVILEGES ON hrms.* TO hrms_user%; FLUSH PRIVILEGES;修改MySQL配置文件my.cnf添加bind-address 0.0.0.0并重启服务→后悔药若无法改MySQL配置可在本机hosts文件中加一行127.0.0.1 localhost确保DNS解析不出错4. 让系统真正可用修改3个核心配置、补全2个安全漏洞、接入真实组织架构4.1 修改数据库连接池——从直连驱动升级到DBCP抗住200并发登录不崩源码中BaseDAO.java几乎全是new Connection()硬编码高并发下必然抛出Too many connections。必须替换为DBCP连接池下载commons-dbcp-1.4.jar和commons-pool-1.6.jarTomcat 8.5兼容版本放入WEB-INF/lib/在WEB-INF/web.xml中添加资源引用resource-ref descriptionDB Connection/description res-ref-namejdbc/hrmsDB/res-ref-name res-typejavax.sql.DataSource/res-type res-authContainer/res-auth /resource-ref修改conf/context.xml在Tomcat conf目录下追加Resource namejdbc/hrmsDB authContainer typejavax.sql.DataSource maxTotal50 maxIdle10 minIdle5 usernamehrms_user passwordStrongPass123! driverClassNamecom.mysql.jdbc.Driver urljdbc:mysql://localhost:3306/hrms?useUnicodetrueamp;characterEncodinggbk/重写BaseDAO.java的getConnection()方法public static Connection getConnection() throws SQLException { Context ctx new InitialContext(); DataSource ds (DataSource) ctx.lookup(java:comp/env/jdbc/hrmsDB); return ds.getConnection(); // 此处自动从池中取连接 }提示maxTotal50是经过压测的保守值若服务器内存≥4G可升至80minIdle5保证池中常驻5个空闲连接避免首次请求延迟。4.2 补全密码明文存储漏洞——用SHA-256盐值哈希替代password123456源码中LoginServlet.java大概率直接比对request.getParameter(pwd)和数据库明文密码。修复步骤修改数据库emp_info表将password字段类型改为VARCHAR(64)SHA-256输出长度新增SaltUtil.java工具类public class SaltUtil { public static String getSalt() { return UUID.randomUUID().toString().replace(-, ).substring(0, 8); } public static String getSecurePassword(String passwordToHash, String salt) { String generatedPassword null; try { MessageDigest md MessageDigest.getInstance(SHA-256); md.update(salt.getBytes()); byte[] bytes md.digest(passwordToHash.getBytes()); StringBuilder sb new StringBuilder(); for (int i 0; i bytes.length; i) { sb.append(Integer.toString((bytes[i] 0xff) 0x100, 16).substring(1)); } generatedPassword sb.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return generatedPassword; } }在RegisterServlet.java中注册逻辑改为String salt SaltUtil.getSalt(); String securePwd SaltUtil.getSecurePassword(pwd, salt); // 插入数据库时同时存 salt 和 securePwd 字段LoginServlet.java验证逻辑改为// 查询时取出 salt 和加密后密码 String dbSalt rs.getString(salt); String dbPwd rs.getString(password); String inputSecurePwd SaltUtil.getSecurePassword(inputPwd, dbSalt); if (dbPwd.equals(inputSecurePwd)) { /* 登录成功 */ }4.3 接入真实组织架构用Excel批量导入部门/岗位数据避免手敲200条人事系统最大痛点是初始数据录入。提供一个import_dept.jsp页面可自行添加到WebContent/admin/下% page contentTypetext/html;charsetgbk% % page importjava.io.*,java.util.*,org.apache.poi.ss.usermodel.*% % if (request.getMethod().equals(POST)) { Part filePart request.getPart(excelFile); String fileName Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); InputStream fileContent filePart.getInputStream(); Workbook workbook WorkbookFactory.create(fileContent); Sheet sheet workbook.getSheetAt(0); ListString[] deptList new ArrayList(); for (Row row : sheet) { if (row.getRowNum() 0) continue; // 跳过标题行 String deptName row.getCell(0).getStringCellValue().trim(); String deptCode row.getCell(1).getStringCellValue().trim(); deptList.add(new String[]{deptCode, deptName}); } // 调用DAO批量插入 com.dao.DeptDAO dao new com.dao.DeptDAO(); dao.batchInsert(deptList); out.print(导入成功 deptList.size() 个部门); } % form methodpost enctypemultipart/form-data input typefile nameexcelFile accept.xlsx,.xls input typesubmit value导入部门 /form配套DeptDAO.java中batchInsert方法public void batchInsert(ListString[] deptList) throws SQLException { String sql INSERT INTO dept_info (dept_code, dept_name) VALUES (?, ?); try (Connection conn getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { for (String[] dept : deptList) { ps.setString(1, dept[0]); ps.setString(2, dept[1]); ps.addBatch(); } ps.executeBatch(); } }注意需在WEB-INF/lib/加入poi-4.1.2.jar和poi-ooxml-4.1.2.jar版本必须≤4.1.2高版本依赖XMLBeansTomcat 8.5不兼容。5. 验证系统健壮性用3种真实场景压力测试揪出隐藏的内存泄漏与SQL注入点5.1 场景一连续100次登录登出观察Tomcat内存是否持续上涨这是检验Session管理是否规范的黄金测试。在LoginServlet.java中登录成功后必须显式销毁旧SessionHttpSession oldSession request.getSession(false); if (oldSession ! null) { oldSession.invalidate(); // 关键防止Session堆积 } HttpSession session request.getSession(true); session.setAttribute(user, user); session.setMaxInactiveInterval(1800); // 30分钟超时测试脚本Python requests模拟import requests session requests.Session() for i in range(100): # 模拟登录 login_data {username: admin, password: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855} r1 session.post(http://localhost:8080/hrms/servlet/LoginServlet, datalogin_data) # 模拟登出触发invalidate r2 session.get(http://localhost:8080/hrms/servlet/LogoutServlet) print(f第{i1}轮完成响应码{r1.status_code}/{r2.status_code})监控方式启动Tomcat时加JVM参数-XX:PrintGCDetails -Xloggc:gc.log运行测试后用jstat -gc pid查看S0U/S1USurvivor区使用量是否稳定。若持续增长说明invalidate()未生效需检查LogoutServlet中是否漏掉session.invalidate()。5.2 场景二在员工搜索框输入 OR 11验证SQL注入防护源码中EmployeeDAO.java的查询方法大概率是字符串拼接String sql SELECT * FROM emp_info WHERE name LIKE % name %; // 危险正确修复必须用PreparedStatementString sql SELECT * FROM emp_info WHERE name LIKE ?; try (PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, % name %); // 自动转义特殊字符 ResultSet rs ps.executeQuery(); }验证方法手动在搜索框输入 OR 11抓包看请求参数是否被原样发送查看后台SQL日志开启MySQL general_logSET GLOBAL general_log ON; SET GLOBAL general_log_file /var/log/mysql/general.log;若日志中出现SELECT * FROM emp_info WHERE name LIKE %\ OR \1\\1%说明已转义成功若出现...LIKE % OR 11%则仍存在注入。5.3 场景三上传头像文件测试文件路径遍历与恶意脚本拦截JSP系统常在UploadServlet.java中用request.getParameter(filename)拼接保存路径String filename request.getParameter(filename); File file new File(D:/hrms/upload/ filename); // 危险攻击者上传../../../webapps/ROOT/shell.jsp即可写入WebShell。修复方案// 1. 白名单校验文件扩展名 String ext FilenameUtils.getExtension(filename); if (!Arrays.asList(jpg, jpeg, png, gif).contains(ext.toLowerCase())) { throw new RuntimeException(不支持的文件类型); } // 2. 使用UUID重命名剥离原始文件名 String newFilename UUID.randomUUID().toString() . ext; String savePath D:/hrms/upload/ newFilename; // 3. 关键用File.getCanonicalPath()校验路径是否越界 File canonicalFile new File(savePath).getCanonicalFile(); String uploadRoot new File(D:/hrms/upload/).getCanonicalPath(); if (!canonicalFile.getPath().startsWith(uploadRoot)) { throw new RuntimeException(非法文件路径); }提示FilenameUtils来自commons-io-2.6.jar需加入lib目录getCanonicalPath()会解析..符号是防遍历的终极手段。6. 我的三条铁律从200个JSP项目里熬出来的落地习惯希望帮到你6.1 每次修改web.xml必须同步更新Tomcat的context.xml和server.xml中的context path这是血泪教训。曾有个项目web.xml里display-nameHRMS v2.1/display-name但conf/server.xml中Context path/hrms-old没改导致静态资源404。后来我定下铁律所有路径相关配置url-pattern、context-param、resource-ref必须用全局搜索CtrlShiftF在三个XML文件中同步出现建立path-check.sh脚本Linux或path-check.batWindows每次提交前自动校验# Linux版 grep -r path apache-tomcat-8.5.99/conf/ | grep -E (hrms|HRMS) \ grep -r url-pattern hrms/WEB-INF/web.xml | grep -E (hrms|HRMS)6.2 数据库字段命名必须与Java Bean属性名严格一致宁可改MySQL也不改Java代码见过太多项目为适配user_name字段在User.java里写private String userName;再加Column(nameuser_name)——但JSP中jsp:getProperty nameuser propertyuserName/会因getter方法名getUserName()与字段userName不匹配而取不到值。最终方案MySQL字段统一用驼峰user_name→userNameJava Bean属性名与数据库字段名1:1private String userName;JSP中jsp:getProperty propertyuserName/直接工作DAO层用ResultSetMetaData动态映射避免硬编码列名。6.3 日志必须分级DEBUG只记录SQL参数INFO记录业务事件ERROR必须含堆栈和请求IDLog4j在Tomcat 8.5中默认不启用我坚持用java.util.logging并定制Handlerpublic class HRMSLogger { private static final Logger logger Logger.getLogger(HRMS); public static void logSQL(String sql, Object... params) { if (logger.isLoggable(Level.FINE)) { StringBuilder sb new StringBuilder(SQL: ).append(sql).append( | Params: ); for (Object p : params) sb.append(p).append(, ); logger.fine(sb.toString()); } } public static void logEvent(String event, HttpServletRequest req) { String requestId req.getHeader(X-Request-ID); if (requestId null) requestId UUID.randomUUID().toString(); logger.info(String.format([%s] %s | IP: %s | User: %s, requestId, event, req.getRemoteAddr(), req.getSession().getAttribute(user))); } }在logging.properties中设置HRMS.level INFO HRMS.handlers java.util.logging.FileHandler java.util.logging.FileHandler.pattern logs/hrms.%g.log java.util.logging.FileHandler.limit 10000000 java.util.logging.FileHandler.count 5这样当用户投诉“薪资计算错误”时我能用grep 薪资计算 logs/hrms.0.log | grep 2024-06-15快速定位到具体请求链路而不是翻三天日志。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑