
很多Java学习者在掌握了基础语法后常常面临不知道如何将知识点串联起来做项目的困境。人事管理系统作为企业级应用的经典场景涵盖了用户管理、权限控制、数据增删改查等核心功能是检验Java Web技术栈掌握程度的绝佳练手项目。本文将带你从零搭建一个完整的人事管理系统采用主流的JSPServlet技术架构包含前端界面设计、后端业务逻辑实现、数据库操作等完整环节。无论你是需要完成课程大作业的学生还是想积累项目经验的开发者都能通过这个实战案例快速掌握Java Web项目开发全流程。1. 项目需求分析与技术选型1.1 系统功能需求人事管理系统主要面向企业HR部门需要实现员工信息的全生命周期管理。核心功能包括员工信息管理新增、查询、修改、删除员工基本信息部门管理维护公司组织架构设置部门信息岗位管理定义不同岗位职责和权限用户权限控制不同角色用户拥有不同的操作权限数据统计展示以图表形式展示员工分布情况1.2 技术栈选择理由基于项目复杂度和学习成本考虑我们选择以下技术组合后端Servlet JSP作为Java Web开发的基础适合理解MVC架构原理前端JSP Bootstrap快速构建响应式界面降低前端开发难度数据库MySQL 8.0轻量级且功能完善的关系型数据库服务器Tomcat 9.x轻量级Servlet容器部署简单开发工具Eclipse或IntelliJ IDEA配合Maven进行依赖管理这种技术组合既保证了项目的完整性又避免了过度复杂的技术栈给初学者带来困扰。2. 开发环境准备与项目搭建2.1 环境配置清单在开始编码前请确保你的开发环境包含以下组件JDK 8或11建议使用LTS版本MySQL 8.0数据库Tomcat 9.x服务器Eclipse IDE for Enterprise Java and Web DevelopersMaven 3.62.2 创建Maven Web项目在Eclipse中新建Dynamic Web Project或使用Maven archetype创建项目结构!-- pom.xml 主要依赖配置 -- dependencies !-- Servlet API -- dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency !-- JSTL标签库 -- dependency groupIdjavax.servlet/groupId artifactIdjstl/artifactId version1.2/version /dependency !-- MySQL驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency !-- 数据库连接池 -- dependency groupIdcom.zaxxer/groupId artifactIdHikariCP/artifactId version5.0.1/version /dependency /dependencies2.3 数据库设计创建人事管理系统所需的数据库表结构-- 创建数据库 CREATE DATABASE hr_management CHARACTER SET utf8mb4; -- 部门表 CREATE TABLE department ( id INT PRIMARY KEY AUTO_INCREMENT, dept_name VARCHAR(50) NOT NULL, dept_desc VARCHAR(200), create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 员工表 CREATE TABLE employee ( id INT PRIMARY KEY AUTO_INCREMENT, emp_name VARCHAR(50) NOT NULL, gender ENUM(男,女), birth_date DATE, email VARCHAR(100), phone VARCHAR(20), dept_id INT, position VARCHAR(50), salary DECIMAL(10,2), hire_date DATE, status ENUM(在职,离职,休假), FOREIGN KEY (dept_id) REFERENCES department(id) ); -- 用户表系统登录 CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) UNIQUE NOT NULL, password VARCHAR(100) NOT NULL, role ENUM(admin,hr,employee) DEFAULT employee, emp_id INT, FOREIGN KEY (emp_id) REFERENCES employee(id) );3. 核心架构设计与实现3.1 MVC模式分层结构采用经典的三层架构确保代码的可维护性和扩展性src/main/java/com/hrsystem/ ├── controller/ # Servlet控制器 ├── service/ # 业务逻辑层 ├── dao/ # 数据访问层 ├── model/ # 实体类 └── util/ # 工具类3.2 数据库连接池配置使用HikariCP实现高效的数据库连接管理// 文件路径src/main/java/com/hrsystem/util/DatabaseUtil.java public class DatabaseUtil { private static HikariDataSource dataSource; static { HikariConfig config new HikariConfig(); config.setJdbcUrl(jdbc:mysql://localhost:3306/hr_management); config.setUsername(root); config.setPassword(your_password); config.setDriverClassName(com.mysql.cj.jdbc.Driver); config.setMaximumPoolSize(20); config.setMinimumIdle(5); config.setConnectionTimeout(30000); config.setIdleTimeout(600000); config.setMaxLifetime(1800000); dataSource new HikariDataSource(config); } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } }3.3 实体类设计定义与数据库表对应的JavaBean// 文件路径src/main/java/com/hrsystem/model/Employee.java public class Employee { private Integer id; private String empName; private String gender; private Date birthDate; private String email; private String phone; private Integer deptId; private String position; private BigDecimal salary; private Date hireDate; private String status; private String deptName; // 联表查询时使用 // 构造方法、getter和setter省略 // 实际开发中可以使用Lombok简化代码 }4. 数据访问层(DAO)实现4.1 基础DAO接口设计定义通用的数据操作接口// 文件路径src/main/java/com/hrsystem/dao/BaseDAO.java public interface BaseDAOT { int insert(T entity) throws SQLException; int update(T entity) throws SQLException; int delete(Integer id) throws SQLException; T findById(Integer id) throws SQLException; ListT findAll() throws SQLException; }4.2 员工DAO实现类实现员工数据的CRUD操作// 文件路径src/main/java/com/hrsystem/dao/EmployeeDAO.java public class EmployeeDAO implements BaseDAOEmployee { Override public int insert(Employee emp) throws SQLException { String sql INSERT INTO employee(emp_name, gender, birth_date, email, phone, dept_id, position, salary, hire_date, status) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?); try (Connection conn DatabaseUtil.getConnection(); PreparedStatement pstmt conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { pstmt.setString(1, emp.getEmpName()); pstmt.setString(2, emp.getGender()); pstmt.setDate(3, new java.sql.Date(emp.getBirthDate().getTime())); pstmt.setString(4, emp.getEmail()); pstmt.setString(5, emp.getPhone()); pstmt.setInt(6, emp.getDeptId()); pstmt.setString(7, emp.getPosition()); pstmt.setBigDecimal(8, emp.getSalary()); pstmt.setDate(9, new java.sql.Date(emp.getHireDate().getTime())); pstmt.setString(10, emp.getStatus()); int affectedRows pstmt.executeUpdate(); if (affectedRows 0) { try (ResultSet rs pstmt.getGeneratedKeys()) { if (rs.next()) { return rs.getInt(1); } } } return affectedRows; } } Override public ListEmployee findAll() throws SQLException { String sql SELECT e.*, d.dept_name FROM employee e LEFT JOIN department d ON e.dept_id d.id ORDER BY e.id DESC; ListEmployee employees new ArrayList(); try (Connection conn DatabaseUtil.getConnection(); PreparedStatement pstmt conn.prepareStatement(sql); ResultSet rs pstmt.executeQuery()) { while (rs.next()) { Employee emp resultSetToEmployee(rs); emp.setDeptName(rs.getString(dept_name)); employees.add(emp); } } return employees; } private Employee resultSetToEmployee(ResultSet rs) throws SQLException { Employee emp new Employee(); emp.setId(rs.getInt(id)); emp.setEmpName(rs.getString(emp_name)); emp.setGender(rs.getString(gender)); emp.setBirthDate(rs.getDate(birth_date)); emp.setEmail(rs.getString(email)); emp.setPhone(rs.getString(phone)); emp.setDeptId(rs.getInt(dept_id)); emp.setPosition(rs.getString(position)); emp.setSalary(rs.getBigDecimal(salary)); emp.setHireDate(rs.getDate(hire_date)); emp.setStatus(rs.getString(status)); return emp; } }5. 业务逻辑层(Service)实现5.1 员工服务接口定义业务操作规范// 文件路径src/main/java/com/hrsystem/service/EmployeeService.java public interface EmployeeService { boolean addEmployee(Employee employee); boolean updateEmployee(Employee employee); boolean deleteEmployee(Integer id); Employee getEmployeeById(Integer id); ListEmployee getAllEmployees(); ListEmployee getEmployeesByDept(Integer deptId); }5.2 员工服务实现类处理复杂的业务逻辑和事务管理// 文件路径src/main/java/com/hrsystem/service/impl/EmployeeServiceImpl.java public class EmployeeServiceImpl implements EmployeeService { private EmployeeDAO employeeDAO new EmployeeDAO(); Override public boolean addEmployee(Employee employee) { try { // 业务规则验证 if (employee.getEmpName() null || employee.getEmpName().trim().isEmpty()) { throw new IllegalArgumentException(员工姓名不能为空); } if (employee.getEmail() ! null !isValidEmail(employee.getEmail())) { throw new IllegalArgumentException(邮箱格式不正确); } int result employeeDAO.insert(employee); return result 0; } catch (SQLException e) { System.err.println(添加员工失败: e.getMessage()); return false; } } Override public ListEmployee getAllEmployees() { try { return employeeDAO.findAll(); } catch (SQLException e) { System.err.println(获取员工列表失败: e.getMessage()); return new ArrayList(); } } private boolean isValidEmail(String email) { String emailRegex ^[A-Za-z0-9_.-](.)$; return email.matches(emailRegex); } }6. 控制器层(Servlet)实现6.1 员工列表查询Servlet处理前端请求并返回数据// 文件路径src/main/java/com/hrsystem/controller/EmployeeListServlet.java WebServlet(/employee/list) public class EmployeeListServlet extends HttpServlet { private EmployeeService employeeService new EmployeeServiceImpl(); protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { ListEmployee employees employeeService.getAllEmployees(); request.setAttribute(employees, employees); request.getRequestDispatcher(/WEB-INF/views/employee_list.jsp).forward(request, response); } catch (Exception e) { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 系统错误); } } }6.2 添加员工Servlet处理表单提交和数据验证// 文件路径src/main/java/com/hrsystem/controller/AddEmployeeServlet.java WebServlet(/employee/add) public class AddEmployeeServlet extends HttpServlet { private EmployeeService employeeService new EmployeeServiceImpl(); protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); try { Employee employee new Employee(); employee.setEmpName(request.getParameter(empName)); employee.setGender(request.getParameter(gender)); employee.setEmail(request.getParameter(email)); employee.setPhone(request.getParameter(phone)); employee.setDeptId(Integer.parseInt(request.getParameter(deptId))); employee.setPosition(request.getParameter(position)); employee.setSalary(new BigDecimal(request.getParameter(salary))); // 日期转换 SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd); employee.setBirthDate(sdf.parse(request.getParameter(birthDate))); employee.setHireDate(sdf.parse(request.getParameter(hireDate))); employee.setStatus(在职); boolean success employeeService.addEmployee(employee); if (success) { response.sendRedirect(request.getContextPath() /employee/list?msgadd_success); } else { request.setAttribute(error, 添加员工失败); request.getRequestDispatcher(/WEB-INF/views/add_employee.jsp).forward(request, response); } } catch (Exception e) { request.setAttribute(error, 数据格式错误: e.getMessage()); request.getRequestDispatcher(/WEB-INF/views/add_employee.jsp).forward(request, response); } } }7. 前端界面设计与实现7.1 员工列表页面使用Bootstrap构建响应式数据表格%-- 文件路径WEB-INF/views/employee_list.jsp --% % page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % html head title员工管理/title link hrefhttps://cdn.jsdelivr.net/npm/bootstrap5.1.3/dist/css/bootstrap.min.css relstylesheet /head body div classcontainer mt-4 h2员工信息列表/h2 div classmb-3 a hrefc:url value/employee/add/ classbtn btn-primary新增员工/a /div c:if test${not empty param.msg} div classalert alert-success操作成功/div /c:if table classtable table-striped thead tr thID/th th姓名/th th性别/th th部门/th th岗位/th th薪资/th th状态/th th操作/th /tr /thead tbody c:forEach varemp items${employees} tr td${emp.id}/td td${emp.empName}/td td${emp.gender}/td td${emp.deptName}/td td${emp.position}/td td¥${emp.salary}/td td span classbadge bg-${emp.status eq 在职 ? success : secondary} ${emp.status} /span /td td a hrefedit?id${emp.id} classbtn btn-sm btn-warning编辑/a a hrefdelete?id${emp.id} classbtn btn-sm btn-danger onclickreturn confirm(确定删除该员工吗)删除/a /td /tr /c:forEach /tbody /table /div /body /html7.2 添加员工表单页面实现数据录入和前端验证%-- 文件路径WEB-INF/views/add_employee.jsp --% % page contentTypetext/html;charsetUTF-8 languagejava % html head title新增员工/title link hrefhttps://cdn.jsdelivr.net/npm/bootstrap5.1.3/dist/css/bootstrap.min.css relstylesheet /head body div classcontainer mt-4 h2新增员工信息/h2 c:if test${not empty error} div classalert alert-danger${error}/div /c:if form actionadd methodpost classneeds-validation novalidate div classrow div classcol-md-6 div classmb-3 label classform-label姓名 */label input typetext classform-control nameempName required /div div classmb-3 label classform-label性别/label select classform-select namegender option value男男/option option value女女/option /select /div div classmb-3 label classform-label出生日期/label input typedate classform-control namebirthDate /div /div div classcol-md-6 div classmb-3 label classform-label邮箱/label input typeemail classform-control nameemail /div div classmb-3 label classform-label电话/label input typetel classform-control namephone /div div classmb-3 label classform-label入职日期 */label input typedate classform-control namehireDate required /div /div /div div classrow div classcol-md-4 div classmb-3 label classform-label部门/label select classform-select namedeptId option value1技术部/option option value2人事部/option option value3财务部/option /select /div /div div classcol-md-4 div classmb-3 label classform-label岗位/label input typetext classform-control nameposition /div /div div classcol-md-4 div classmb-3 label classform-label薪资/label input typenumber classform-control namesalary step0.01 /div /div /div button typesubmit classbtn btn-primary提交/button a hreflist classbtn btn-secondary返回/a /form /div script // 表单验证 (function () { use strict var forms document.querySelectorAll(.needs-validation) Array.prototype.slice.call(forms).forEach(function (form) { form.addEventListener(submit, function (event) { if (!form.checkValidity()) { event.preventDefault() event.stopPropagation() } form.classList.add(was-validated) }, false) }) })() /script /body /html8. 系统部署与运行测试8.1 Tomcat服务器配置将项目部署到Tomcat服务器在Eclipse中右键项目 → Export → WAR file将生成的WAR文件复制到Tomcat的webapps目录启动Tomcat服务器访问 http://localhost:8080/your-project-name8.2 数据库初始化脚本创建初始数据用于测试-- 插入测试部门数据 INSERT INTO department (dept_name, dept_desc) VALUES (技术部, 负责产品研发和技术支持), (人事部, 负责招聘和员工关系管理), (财务部, 负责公司财务和薪酬管理); -- 插入测试员工数据 INSERT INTO employee (emp_name, gender, birth_date, email, phone, dept_id, position, salary, hire_date, status) VALUES (张三, 男, 1990-01-15, zhangsancompany.com, 13800138001, 1, Java工程师, 15000.00, 2020-03-01, 在职), (李四, 女, 1992-05-20, lisicompany.com, 13800138002, 2, HR专员, 8000.00, 2021-06-15, 在职);8.3 功能测试流程按照以下顺序验证系统功能访问员工列表页面确认数据正常显示测试新增员工功能包括表单验证和数据提交验证编辑功能修改员工信息并保存测试删除功能确认数据删除成功检查不同浏览器的兼容性9. 常见问题与解决方案9.1 数据库连接问题问题现象启动时报数据库连接失败解决方案检查MySQL服务是否启动确认数据库连接字符串中的用户名密码正确验证数据库驱动版本兼容性9.2 中文乱码问题问题现象页面显示或数据库存储出现乱码解决方案!-- 在web.xml中添加字符编码过滤器 -- filter filter-nameencodingFilter/filter-name filter-classorg.springframework.web.filter.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param /filter filter-mapping filter-nameencodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping9.3 依赖冲突问题问题现象ClassNotFoundException或NoSuchMethodError解决方案使用Maven的dependency:tree命令分析依赖关系排除冲突的依赖版本统一框架组件的版本号10. 项目优化与扩展建议10.1 性能优化方案数据库优化为常用查询字段添加索引缓存策略使用Redis缓存热点数据连接池调优根据并发量调整连接池参数前端优化压缩静态资源使用CDN加速10.2 功能扩展方向权限管理集成Spring Security实现细粒度权限控制文件上传支持员工照片和证件上传功能数据导出实现Excel格式的数据导出消息通知集成邮件或短信通知功能移动端适配开发响应式界面或独立移动端应用10.3 安全加固措施SQL注入防护始终使用PreparedStatementXSS防护对用户输入进行过滤和转义会话安全设置合理的Session超时时间密码安全使用BCrypt等算法加密存储密码这个人事管理系统项目涵盖了Java Web开发的核心技术要点通过完整的实战演练你不仅能够掌握MVC设计模式的实际应用还能深入理解Web应用的完整生命周期。建议在完成基础功能后尝试实现扩展功能来进一步提升技术水平。