在传统企业人事管理过程中,信息分散、流程繁琐、数据易错等问题长期困扰着人力资源部门。纸质档案查询困难、考勤统计耗时易错、薪资核算依赖人工计算等痛点,不仅降低了工作效率,也增加了企业运营成本与管理风险。针对这些挑战,我们设计并实现了一套基于SSH(Struts2 + Spring + Hibernate)技术栈的企业人力资源管理系统——"智汇HR管理平台"。该系统通过数字化、流程化的方式,将员工档案、合同管理、考勤记录、薪资核算等核心业务模块有机整合,为企业提供一体化、规范化的人力资源管理解决方案。
系统采用经典的三层架构设计,确保各层职责分离、耦合度低。表现层使用Struts2框架处理用户请求与页面跳转,通过配置Action映射实现前后端数据交互;业务层由Spring框架的IoC容器统一管理Service组件,利用声明式事务管理确保核心业务操作的原子性与数据一致性;数据持久层基于Hibernate实现对象关系映射(ORM),简化数据库操作,提高开发效率。这种架构不仅保证了系统的稳定性和可扩展性,也为后续功能迭代维护提供了良好基础。
技术架构深度解析
表现层:Struts2的请求控制与数据流转
Struts2作为MVC框架,通过拦截器机制对用户请求进行预处理和后处理。在系统中,每个业务模块对应一个或多个Action类,负责接收前端表单数据、调用业务逻辑处理,并返回结果视图。Struts2的类型转换和验证机制确保了数据的安全性和完整性。
<!-- struts.xml 配置示例 -->
<package name="hr" extends="struts-default" namespace="/">
<action name="employee_*" class="employeeAction" method="{1}">
<result name="success">/pages/employee/employee_list.jsp</result>
<result name="input">/pages/employee/employee_edit.jsp</result>
<interceptor-ref name="defaultStack"/>
</action>
</package>
业务层:Spring的依赖注入与事务管理
Spring框架通过IoC容器管理所有业务组件,实现组件间的松耦合。Service层包含核心业务逻辑,如员工信息管理、薪资计算、考勤统计等。通过声明式事务管理,确保数据库操作的ACID特性。
// Spring配置示例
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public EmployeeService employeeService() {
return new EmployeeServiceImpl();
}
@Bean
public SalaryCalculator salaryCalculator() {
return new SalaryCalculatorImpl();
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
return new JpaTransactionManager(emf);
}
}
持久层:Hibernate的对象关系映射
Hibernate通过注解或XML配置实现Java对象与数据库表的映射,简化了数据持久化操作。系统定义了员工、部门、考勤、薪资等实体类,通过Hibernate的Session管理数据库会话,实现高效的CRUD操作。
@Entity
@Table(name = "employee")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "emp_number", unique = true, nullable = false)
private String employeeNumber;
@Column(name = "name", nullable = false)
private String name;
@ManyToOne
@JoinColumn(name = "department_id")
private Department department;
// 其他字段及getter/setter方法
}
数据库设计亮点分析
系统数据库包含8个核心表,设计遵循第三范式,确保数据的一致性和完整性。以下是几个关键表的设计分析:
员工信息表(employee)设计
员工表作为系统的核心数据表,存储员工的基本信息、职位信息、部门关联等。设计上采用唯一工号作为业务主键,同时使用自增ID作为物理主键,既保证了业务上的唯一性,又提高了查询效率。
CREATE TABLE employee (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
emp_number VARCHAR(20) UNIQUE NOT NULL,
name VARCHAR(50) NOT NULL,
gender ENUM('M','F'),
birth_date DATE,
id_card VARCHAR(18) UNIQUE,
email VARCHAR(100),
phone VARCHAR(20),
address TEXT,
hire_date DATE NOT NULL,
position VARCHAR(50),
salary_level INT,
department_id BIGINT,
status ENUM('ACTIVE','INACTIVE') DEFAULT 'ACTIVE',
created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (department_id) REFERENCES department(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
该表设计的亮点包括:
- 使用ENUM类型限制性别和状态字段的取值范围,确保数据一致性
- 身份证号和工号设置唯一约束,防止重复数据
- 时间戳字段自动记录创建和修改时间,便于审计追踪
- 外键约束确保部门数据的引用完整性
薪资记录表(salary_record)设计
薪资表记录了每位员工的月度薪资明细,包含基本工资、绩效奖金、扣款项等。设计上采用复合索引优化查询性能,支持按员工和月份快速检索。
CREATE TABLE salary_record (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
employee_id BIGINT NOT NULL,
salary_month DATE NOT NULL,
base_salary DECIMAL(10,2) NOT NULL,
performance_bonus DECIMAL(10,2) DEFAULT 0,
overtime_pay DECIMAL(10,2) DEFAULT 0,
allowance DECIMAL(10,2) DEFAULT 0,
social_insurance DECIMAL(10,2) DEFAULT 0,
housing_fund DECIMAL(10,2) DEFAULT 0,
tax DECIMAL(10,2) DEFAULT 0,
other_deductions DECIMAL(10,2) DEFAULT 0,
net_salary DECIMAL(10,2) NOT NULL,
payment_status ENUM('PENDING','PAID') DEFAULT 'PENDING',
payment_date DATE,
remarks TEXT,
created_by BIGINT,
created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uk_employee_month (employee_id, salary_month),
FOREIGN KEY (employee_id) REFERENCES employee(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
该表设计的专业技术特点:
- 使用DECIMAL类型精确存储金额数据,避免浮点数精度问题
- 唯一约束防止同一员工同月薪资重复计算
- 支付状态字段支持流程控制,确保薪资发放的准确性
- 完整的审计字段记录操作人员和操作时间
考勤记录表(attendance)设计
考勤表记录了员工的每日考勤情况,支持多种考勤类型(正常、迟到、早退、缺勤等)。设计上采用分区表概念,可按月份进行数据管理,提高大数据量下的查询性能。
CREATE TABLE attendance (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
employee_id BIGINT NOT NULL,
attendance_date DATE NOT NULL,
check_in_time TIME,
check_out_time TIME,
attendance_type ENUM('NORMAL','LATE','EARLY_LEAVE','ABSENT','BUSINESS_TRIP','LEAVE') DEFAULT 'NORMAL',
work_hours DECIMAL(4,2),
overtime_hours DECIMAL(4,2) DEFAULT 0,
remarks VARCHAR(200),
created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_employee_date (employee_id, attendance_date),
INDEX idx_date (attendance_date),
FOREIGN KEY (employee_id) REFERENCES employee(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
核心功能模块实现详解
员工信息管理模块
员工信息管理是系统的基础功能,实现员工全生命周期数据的维护。前端采用分页表格展示员工列表,支持按部门、职位等多条件查询。

后端EmployeeAction处理员工信息的CRUD操作,通过Hibernate实现数据持久化:
@Controller
@Scope("prototype")
public class EmployeeAction extends BaseAction {
private Employee employee;
private List<Employee> employeeList;
private Long employeeId;
@Autowired
private EmployeeService employeeService;
// 查询员工列表
public String list() {
try {
Map<String, Object> params = new HashMap<>();
if (departmentId != null) {
params.put("departmentId", departmentId);
}
employeeList = employeeService.findByParams(params, getPage(), getRows());
setTotal(employeeService.getCountByParams(params));
return SUCCESS;
} catch (Exception e) {
addActionError("查询员工信息失败: " + e.getMessage());
return ERROR;
}
}
// 保存员工信息
public String save() {
try {
if (employee.getId() == null) {
employee.setEmployeeNumber(generateEmployeeNumber());
}
employeeService.saveOrUpdate(employee);
addActionMessage("员工信息保存成功");
return SUCCESS;
} catch (Exception e) {
addActionError("保存员工信息失败: " + e.getMessage());
return INPUT;
}
}
// 生成唯一工号
private String generateEmployeeNumber() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String dateStr = sdf.format(new Date());
Long count = employeeService.getTodayEmployeeCount();
return "EMP" + dateStr + String.format("%03d", count + 1);
}
}
薪资核算模块
薪资核算模块是系统的核心业务功能,实现自动化的薪资计算流程。系统根据考勤数据、绩效评分、社保政策等自动计算应发薪资和实发薪资。

薪资计算服务类实现复杂的薪资逻辑:
@Service
@Transactional
public class SalaryCalculatorImpl implements SalaryCalculator {
@Autowired
private AttendanceService attendanceService;
@Autowired
private SalaryPolicyService policyService;
@Override
public SalaryRecord calculateSalary(Long employeeId, Date salaryMonth) {
Employee employee = employeeService.findById(employeeId);
SalaryPolicy policy = policyService.getCurrentPolicy();
// 计算基本工资
BigDecimal baseSalary = calculateBaseSalary(employee, policy);
// 计算绩效奖金
BigDecimal performanceBonus = calculatePerformanceBonus(employee, salaryMonth);
// 计算加班工资
BigDecimal overtimePay = calculateOvertimePay(employee, salaryMonth, policy);
// 计算社保公积金
SocialInsuranceInfo insurance = calculateSocialInsurance(employee, baseSalary, policy);
// 计算个人所得税
BigDecimal tax = calculateIncomeTax(baseSalary, performanceBonus, overtimePay,
insurance.getTotalDeduction(), policy);
// 计算实发工资
BigDecimal netSalary = baseSalary.add(performanceBonus)
.add(overtimePay)
.subtract(insurance.getTotalDeduction())
.subtract(tax);
SalaryRecord record = new SalaryRecord();
record.setEmployee(employee);
record.setSalaryMonth(salaryMonth);
record.setBaseSalary(baseSalary);
record.setPerformanceBonus(performanceBonus);
record.setOvertimePay(overtimePay);
record.setSocialInsurance(insurance.getSocialInsurance());
record.setHousingFund(insurance.getHousingFund());
record.setTax(tax);
record.setNetSalary(netSalary);
return salaryRecordService.save(record);
}
private BigDecimal calculateOvertimePay(Employee employee, Date month, SalaryPolicy policy) {
List<Attendance> overtimeRecords = attendanceService
.getOvertimeRecords(employee.getId(), month);
BigDecimal totalOvertimePay = BigDecimal.ZERO;
for (Attendance record : overtimeRecords) {
BigDecimal hourlyRate = policy.getOvertimeRate()
.multiply(employee.getBasicSalary())
.divide(BigDecimal.valueOf(21.75 * 8), 2, RoundingMode.HALF_UP);
BigDecimal overtimePay = hourlyRate.multiply(BigDecimal.valueOf(record.getOvertimeHours()));
totalOvertimePay = totalOvertimePay.add(overtimePay);
}
return totalOvertimePay;
}
}
考勤管理模块
考勤管理模块实现员工打卡记录、考勤统计、异常考勤处理等功能。系统支持多种考勤方式,并与薪资模块紧密集成。

考勤数据服务类实现复杂的考勤逻辑判断:
@Service
@Transactional
public class AttendanceServiceImpl implements AttendanceService {
@Autowired
private AttendanceDao attendanceDao;
@Autowired
private WorkShiftService workShiftService;
@Override
public AttendanceRecord checkIn(CheckInRequest request) {
Employee employee = employeeService.findById(request.getEmployeeId());
WorkShift shift = workShiftService.getCurrentShift(employee);
AttendanceRecord record = new AttendanceRecord();
record.setEmployee(employee);
record.setAttendanceDate(new Date());
record.setCheckInTime(request.getCheckInTime());
// 判断考勤状态
if (request.getCheckInTime().after(shift.getLateThreshold())) {
record.setAttendanceType(AttendanceType.LATE);
record.setRemarks("迟到 " + calculateLateMinutes(request.getCheckInTime(), shift));
} else {
record.setAttendanceType(AttendanceType.NORMAL);
}
return attendanceDao.save(record);
}
@Override
public AttendanceSummary getMonthlySummary(Long employeeId, Date month) {
List<AttendanceRecord> records = attendanceDao.findByEmployeeAndMonth(employeeId, month);
int normalDays = 0;
int lateDays = 0;
int absentDays = 0;
double totalOvertime = 0;
for (AttendanceRecord record : records) {
switch (record.getAttendanceType()) {
case NORMAL:
normalDays++;
break;
case LATE:
lateDays++;
break;
case ABSENT:
absentDays++;
break;
}
totalOvertime += record.getOvertimeHours();
}
return new AttendanceSummary(normalDays, lateDays, absentDays, totalOvertime);
}
}
部门与岗位管理模块
部门管理实现组织架构的维护,支持树形结构展示。岗位管理定义各职位的基本信息和薪资等级。

部门实体类设计支持无限级树形结构:
@Entity
@Table(name = "department")
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "dept_name", nullable = false)
private String name;
@Column(name = "dept_code", unique = true)
private String code;
@ManyToOne
@JoinColumn(name = "parent_id")
private Department parent;
@OneToMany(mappedBy = "parent")
private Set<Department> children = new HashSet<>();
@Column(name = "manager_id")
private Long managerId;
@Column(name = "description")
private String description;
@Column(name = "sort_order")
private Integer sortOrder;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created_time")
private Date createdTime;
// 获取部门完整路径
public String getFullPath() {
if (parent == null) {
return name;
}
return parent.getFullPath() + " > " + name;
}
}
实体模型与业务逻辑设计
系统采用面向对象的设计思想,通过丰富的实体关系映射实现复杂的业务逻辑。以下是核心实体模型的关键设计:
员工实体关联设计
员工实体与多个业务实体建立关联关系,形成完整的业务数据模型:
@Entity
@Table(name = "employee")
public class Employee {
// 基础字段省略...
// 部门关联
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "department_id")
private Department department;
// 薪资记录(一对多)
@OneToMany(mappedBy = "employee", cascade = CascadeType.ALL)
private List<SalaryRecord> salaryRecords = new ArrayList<>();
// 考勤记录(一对多)
@OneToMany(mappedBy = "employee", cascade = CascadeType.ALL)
private List<AttendanceRecord> attendanceRecords = new ArrayList<>();
// 培训记录(多对多)
@ManyToMany
@JoinTable(name = "employee_training",
joinColumns = @JoinColumn(name = "employee_id"),
inverseJoinColumns = @JoinColumn(name = "training_id"))
private Set<Training> trainings = new HashSet<>();
// 业务方法:计算工龄
public int getWorkYears() {
if (hireDate == null) return 0;
Period period = Period.between(
hireDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(),
LocalDate.now()
);
return period.getYears();
}
}
服务层事务管理设计
业务服务层采用声明式事务管理,确保复杂业务操作的原子性:
@Service
@Transactional
public class EmployeeManagementServiceImpl implements EmployeeManagementService {
@Autowired
private EmployeeDao employeeDao;
@Autowired
private SalaryRecordDao salaryRecordDao;
@Autowired
private SystemLogService logService;
@Override
@Transactional(rollbackFor = Exception.class)
public void processEmployeeResignation(Long employeeId, ResignationInfo info) {
try {
// 1. 更新员工状态
Employee employee = employeeDao.findById(employeeId);
employee.setStatus(EmployeeStatus.INACTIVE);
employee.setResignationDate(info.getResignationDate());
employeeDao.update(employee);
// 2. 计算最后薪资
SalaryRecord finalSalary = salaryCalculator.calculateFinalSalary(employeeId, info);
salaryRecordDao.save(finalSalary);
// 3. 记录系统日志
logService.log