在企业数字化转型浪潮中,人事管理作为企业运营的核心环节,其效率与准确性直接影响到组织效能。传统依赖纸质档案和分散电子表格的人事管理方式,普遍存在数据冗余、流程滞后、信息孤岛等问题。针对这一痛点,我们设计并实现了一套轻量级企业人事管理平台,该系统采用经典的JSP+Servlet架构,将人事管理的各个环节进行系统化整合,为中小企业提供了一套完整的人事信息化解决方案。
系统架构与技术栈
该平台采用典型的三层架构模式,展现层使用JSP技术实现动态页面渲染,业务逻辑层通过Servlet控制器处理各类请求,数据持久层基于JDBC实现与MySQL数据库的交互。这种分层架构确保了代码的清晰性和可维护性。
核心配置文件示例:
<!-- web.xml中Servlet配置 -->
<servlet>
<servlet-name>EmployeeServlet</servlet-name>
<servlet-class>com.hr.controller.EmployeeServlet</servlet>
</servlet>
<servlet-mapping>
<servlet-name>EmployeeServlet</servlet-name>
<url-pattern>/employee/*</url-pattern>
</servlet-mapping>
数据库连接采用连接池技术优化性能:
// 数据库连接工具类
public class DBUtil {
private static DataSource dataSource;
static {
try {
Context context = new InitialContext();
dataSource = (DataSource) context.lookup("java:comp/env/jdbc/hrDB");
} catch (NamingException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
数据库设计亮点分析
组织架构表的树形结构设计
t_organization表采用经典的父ID设计实现组织层级管理:
CREATE TABLE `t_organization` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '组织ID',
`name` varchar(55) DEFAULT NULL COMMENT '组织名称',
`description` varchar(50) DEFAULT NULL COMMENT '描述',
`p_id` int(11) DEFAULT NULL COMMENT '父级ID',
`del` varchar(50) DEFAULT NULL COMMENT '删除标记',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='组织表'
设计优势分析:
- 层级管理:通过
p_id字段实现无限级次的部门树形结构,支持大型企业的复杂组织架构 - 软删除机制:
del字段采用标记删除而非物理删除,确保历史数据的完整性 - 索引优化:主键ID自增设计提高插入性能,同时为
p_id字段建立索引优化查询效率
请假申请表的业务流程设计
t_qingjiashenqing表完整记录了请假审批流程:
CREATE TABLE `t_qingjiashenqing` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '请假申请ID',
`kaishishijian` varchar(50) DEFAULT NULL COMMENT '开始时间',
`jieshushijian` varchar(50) DEFAULT NULL COMMENT '结束时间',
`beizhu` varchar(5000) DEFAULT NULL COMMENT '备注',
`yuangong_id` int(11) DEFAULT NULL COMMENT '员工ID',
`shenhezhuangtai` varchar(50) DEFAULT NULL COMMENT '审核状态',
`huifuxinxi` varchar(50) DEFAULT NULL COMMENT '回复信息',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='请假申请表'
业务流程完整性:
- 状态跟踪:
shenhezhuangtai字段记录审批流程的各个状态(待审批、已批准、已拒绝) - 反馈机制:
huifuxinxi字段存储审批人的处理意见,形成完整的流程闭环 - 大文本支持:
beizhu字段采用5000字符长度,满足详细请假事由的描述需求

核心功能实现详解
员工信息管理模块
员工信息管理作为系统基础模块,实现了完整的CRUD操作:
// EmployeeServlet中的添加员工方法
public void addEmployee(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
Employee employee = new Employee();
employee.setName(request.getParameter("name"));
employee.setGender(request.getParameter("gender"));
employee.setAge(Integer.parseInt(request.getParameter("age")));
employee.setPosition(request.getParameter("position"));
employee.setDepartmentId(Integer.parseInt(request.getParameter("departmentId")));
EmployeeDAO dao = new EmployeeDAO();
boolean success = dao.addEmployee(employee);
if (success) {
request.setAttribute("message", "员工添加成功");
} else {
request.setAttribute("error", "员工添加失败");
}
request.getRequestDispatcher("/employee_list.jsp").forward(request, response);
} catch (Exception e) {
e.printStackTrace();
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
// 分页查询员工列表
public void listEmployees(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int page = 1;
int pageSize = 10;
if (request.getParameter("page") != null) {
page = Integer.parseInt(request.getParameter("page"));
}
EmployeeDAO dao = new EmployeeDAO();
List<Employee> employees = dao.getEmployeesByPage(page, pageSize);
int totalCount = dao.getEmployeeCount();
int totalPages = (int) Math.ceil((double) totalCount / pageSize);
request.setAttribute("employees", employees);
request.setAttribute("currentPage", page);
request.setAttribute("totalPages", totalPages);
request.getRequestDispatcher("/employee_list.jsp").forward(request, response);
}

工资管理业务流程
工资管理模块实现了工资记录的创建、修改和查询功能:
// 工资计算业务逻辑
public class SalaryService {
private SalaryDAO salaryDAO = new SalaryDAO();
private AttendanceDAO attendanceDAO = new AttendanceDAO();
public boolean calculateSalary(int employeeId, String month, int baseSalary) {
try {
// 获取该月出勤天数
Attendance attendance = attendanceDAO.getAttendance(employeeId, month);
if (attendance == null) {
return false;
}
// 计算实际工资(基础工资/22 * 实际出勤天数)
int actualSalary = baseSalary / 22 * attendance.getDays();
Salary salary = new Salary();
salary.setEmployeeId(employeeId);
salary.setMonth(month);
salary.setAmount(actualSalary);
return salaryDAO.addSalary(salary);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
// 工资DAO数据访问层
public class SalaryDAO {
public boolean addSalary(Salary salary) throws SQLException {
String sql = "INSERT INTO t_gongzi (yuefen, jine, yuangong_id) VALUES (?, ?, ?)";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, salary.getMonth());
pstmt.setInt(2, salary.getAmount());
pstmt.setInt(3, salary.getEmployeeId());
return pstmt.executeUpdate() > 0;
}
}
public List<Salary> getSalariesByEmployee(int employeeId) throws SQLException {
String sql = "SELECT g.*, e.name as employee_name FROM t_gongzi g " +
"JOIN t_employee e ON g.yuangong_id = e.id WHERE g.yuangong_id = ?";
List<Salary> salaries = new ArrayList<>();
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, employeeId);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
Salary salary = new Salary();
salary.setId(rs.getInt("id"));
salary.setMonth(rs.getString("yuefen"));
salary.setAmount(rs.getInt("jine"));
salary.setEmployeeName(rs.getString("employee_name"));
salaries.add(salary);
}
}
return salaries;
}
}

请假审批工作流
请假审批模块实现了完整的业务流程管理:
// 请假审批Servlet
public class LeaveServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getParameter("action");
switch (action) {
case "apply":
applyLeave(request, response);
break;
case "approve":
approveLeave(request, response);
break;
case "reject":
rejectLeave(request, response);
break;
}
}
private void applyLeave(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
LeaveApplication leave = new LeaveApplication();
leave.setEmployeeId(Integer.parseInt(request.getParameter("employeeId")));
leave.setStartTime(request.getParameter("kaishishijian"));
leave.setEndTime(request.getParameter("jieshushijian"));
leave.setRemark(request.getParameter("beizhu"));
leave.setStatus("pending");
LeaveDAO dao = new LeaveDAO();
boolean success = dao.applyLeave(leave);
if (success) {
request.setAttribute("message", "请假申请提交成功,等待审批");
} else {
request.setAttribute("error", "请假申请提交失败");
}
request.getRequestDispatcher("/leave_result.jsp").forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
private void approveLeave(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int leaveId = Integer.parseInt(request.getParameter("leaveId"));
String reply = request.getParameter("huifuxinxi");
LeaveDAO dao = new LeaveDAO();
boolean success = dao.updateLeaveStatus(leaveId, "approved", reply);
// 发送通知邮件或消息
sendApprovalNotification(leaveId);
response.sendRedirect("leave_management.jsp?message=审批完成");
}
}

考勤数据管理
考勤管理模块实现出勤记录的统计和分析:
// 考勤服务类
public class AttendanceService {
public boolean recordAttendance(int employeeId, String month, int days) {
String sql = "INSERT INTO t_chuqin (yuefen, tianshu, yuangong_id) VALUES (?, ?, ?) " +
"ON DUPLICATE KEY UPDATE tianshu = ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, month);
pstmt.setInt(2, days);
pstmt.setInt(3, employeeId);
pstmt.setInt(4, days);
return pstmt.executeUpdate() > 0;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
public Map<String, Object> getAttendanceReport(String department, String month) {
Map<String, Object> report = new HashMap<>();
String sql = "SELECT e.name, e.position, c.tianshu " +
"FROM t_chuqin c " +
"JOIN t_employee e ON c.yuangong_id = e.id " +
"JOIN t_organization o ON e.department_id = o.id " +
"WHERE o.name = ? AND c.yuefen = ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, department);
pstmt.setString(2, month);
ResultSet rs = pstmt.executeQuery();
List<Map<String, Object>> data = new ArrayList<>();
int totalDays = 0;
int employeeCount = 0;
while (rs.next()) {
Map<String, Object> record = new HashMap<>();
record.put("name", rs.getString("name"));
record.put("position", rs.getString("position"));
record.put("days", rs.getInt("tianshu"));
data.add(record);
totalDays += rs.getInt("tianshu");
employeeCount++;
}
report.put("data", data);
report.put("averageDays", employeeCount > 0 ? totalDays / employeeCount : 0);
report.put("totalEmployees", employeeCount);
} catch (SQLException e) {
e.printStackTrace();
}
return report;
}
}

实体模型设计
系统采用标准的JavaBean设计模式,每个实体类都对应数据库中的表结构:
// 员工实体类
public class Employee {
private int id;
private String name;
private String gender;
private int age;
private String position;
private int departmentId;
private String departmentName;
private Date createTime;
// 无参构造函数
public Employee() {}
// 带参构造函数
public Employee(int id, String name, String gender, int age,
String position, int departmentId) {
this.id = id;
this.name = name;
this.gender = gender;
this.age = age;
this.position = position;
this.departmentId = departmentId;
}
// Getter和Setter方法
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
// 其他getter/setter方法...
@Override
public String toString() {
return "Employee{id=" + id + ", name='" + name + "', position='" + position + "'}";
}
}
// 工资实体类
public class Salary {
private int id;
private String month;
private int amount;
private int employeeId;
private String employeeName;
// 构造函数和方法...
public Salary() {}
public Salary(int id, String month, int amount, int employeeId) {
this.id = id;
this.month = month;
this.amount = amount;
this.employeeId = employeeId;
}
// Getter和Setter方法...
}
功能展望与优化方向
1. 性能优化与缓存集成
当前系统在数据查询方面存在优化空间,建议引入Redis缓存层:
// 缓存优化示例
@Service
public class CachedEmployeeService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final String EMPLOYEE_CACHE_KEY = "employee:";
private static final long CACHE_EXPIRE_HOURS = 24;
public Employee getEmployeeWithCache(int employeeId) {
String cacheKey = EMPLOYEE_CACHE_KEY + employeeId;
// 先从缓存获取
Employee employee = (Employee) redisTemplate.opsForValue().get(cacheKey);
if (employee != null) {
return employee;
}
// 缓存未命中,查询数据库
employee = employeeDAO.getEmployeeById(employeeId);
if (employee != null) {
redisTemplate.opsForValue().set(cacheKey, employee,
CACHE_EXPIRE_HOURS, TimeUnit.HOURS);
}
return employee;
}
}
2. 微服务架构改造
将单体应用拆分为微服务架构,提升系统可扩展性:
- 人事核心服务:处理员工信息、组织架构等基础数据
- 考勤服务:独立处理考勤数据和统计
- 薪酬服务:专门负责工资计算和发放
- 审批流服务:统一处理各类审批流程
3. 移动端适配与响应式设计
增加移动端支持,采用响应式前端框架:
<!-- 响应式页面示例 -->
<div class="container-fluid">
<div class="row">
<div class="col-12 col-md-6 col-lg-4">
<div class="card employee-card">
<div class="card-body">
<h5 class="card-title" th:text="${employee.name}"></h5>
<p class="card-text" th:text="${employee.position}"></p>
</div>
</div>
</div>
</div>
</div>
4. 大数据分析与报表增强
集成数据分析工具,提供更深入的HR数据分析:
- 员工离职率预测分析
- 薪酬结构合理性评估
- 绩效考核趋势分析
- 人力成本优化建议
5. 安全增强与审计日志
加强系统安全性,完善操作审计:
// 审计日志切面
@Aspect
@Component
public class AuditLogAspect {
@Autowired
private AuditLogService auditLogService;
@Around("@annotation(RequiresAudit)")
public Object auditMethod(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
AuditLog log = new AuditLog();
log.setOperation(joinPoint.getSignature().getName());
log.setDuration(endTime - startTime);
log.setOperator(getCurrentUser());
log.setTimestamp(new Date());
auditLogService.recordLog(log);
return result;
}
}
该人事管理平台通过系统化的功能设计和稳健的技术实现,为企业提供了完整的人