### 基于Spring Boot的OA系统薪资管理模块实现
本文介绍了如何使用Spring Boot和MySQL开发一个简单的OA系统薪资管理模块,包括基础设置、考勤数据导入、绩效考核、工资单查询,并扩展到使用Spring Security进行安全认证和权限控制,以及使用Spring Scheduler进行定时任务管理。
#### 项目结构
1. **Spring Boot**: 主要框架,负责处理业务逻辑和REST API。
2. **MySQL**: 数据存储。
3. **Thymeleaf**: 前端模板渲染。
4. **Spring Data JPA**: 数据库操作。
5. **Spring Security**: 安全认证和权限控制。
6. **Spring Scheduler**: 定时任务管理。
### 数据库设计
#### 数据库表
```sql
CREATE TABLE employee (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
base_salary DECIMAL(10, 2),
allowance DECIMAL(10, 2),
subsidy DECIMAL(10, 2),
bonus DECIMAL(10, 2)
);
CREATE TABLE attendance (
id INT AUTO_INCREMENT PRIMARY KEY,
employee_id INT,
date DATE,
hours_worked DECIMAL(5, 2),
leave_hours DECIMAL(5, 2),
FOREIGN KEY (employee_id) REFERENCES employee(id)
);
CREATE TABLE performance (
id INT AUTO_INCREMENT PRIMARY KEY,
employee_id INT,
score DECIMAL(5, 2),
FOREIGN KEY (employee_id) REFERENCES employee(id)
);
CREATE TABLE payroll (
id INT AUTO_INCREMENT PRIMARY KEY,
employee_id INT,
month DATE,
total_salary DECIMAL(10, 2),
FOREIGN KEY (employee_id) REFERENCES employee(id)
);
```
### Spring Boot 代码实现
#### 1. 薪资基础设置
**Controller**
```java
@RestController
@RequestMapping("/api/salary")
public class SalaryController {
@Autowired
private EmployeeRepository employeeRepository;
@PostMapping("/set")
public ResponseEntity<Employee> setSalary(@RequestBody Employee employee) {
Employee savedEmployee = employeeRepository.save(employee);
return ResponseEntity.ok(savedEmployee);
}
}
```
**Repository**
```java
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {}
```
**Entity**
```java
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private BigDecimal baseSalary;
private BigDecimal allowance;
private BigDecimal subsidy;
private BigDecimal bonus;
// Getters and setters
}
```
#### 2. 考勤数据导入
**Controller**
```java
@RestController
@RequestMapping("/api/attendance")
public class AttendanceController {
@Autowired
private AttendanceRepository attendanceRepository;
@PostMapping("/import")
public ResponseEntity<Attendance> importAttendance(@RequestBody Attendance attendance) {
Attendance savedAttendance = attendanceRepository.save(attendance);
return ResponseEntity.ok(savedAttendance);
}
}
```
**Repository**
```java
public interface AttendanceRepository extends JpaRepository<Attendance, Integer> {}
```
**Entity**
```java
@Entity
public class Attendance {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Integer employeeId;
private Date date;
private BigDecimal hoursWorked;
private BigDecimal leaveHours;
// Getters and setters
}
```
#### 3. 绩效考核
**Controller**
```java
@RestController
@RequestMapping("/api/performance")
public class PerformanceController {
@Autowired
private PerformanceRepository performanceRepository;
@PostMapping("/evaluate")
public ResponseEntity<Performance> evaluatePerformance(@RequestBody Performance performance) {
Performance savedPerformance = performanceRepository.save(performance);
return ResponseEntity.ok(savedPerformance);
}
}
```
**Repository**
```java
public interface PerformanceRepository extends JpaRepository<Performance, Integer> {}
```
**Entity**
```java
@Entity
public class Performance {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Integer employeeId;
private BigDecimal score;
// Getters and setters
}
```
#### 4. 工资单查询
**Controller**
```java
@RestController
@RequestMapping("/api/payroll")
public class PayrollController {
@Autowired
private PayrollRepository payrollRepository;
@GetMapping("/list")
public ResponseEntity<List<Payroll>> listPayrolls() {
List<Payroll> payrolls = payrollRepository.findAll();
return ResponseEntity.ok(payrolls);
}
@GetMapping("/export/{id}")
public ResponseEntity<Payroll> exportPayroll(@PathVariable Integer id) {
Optional<Payroll> payroll = payrollRepository.findById(id);
return payroll.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());
}
}
```
**Repository**
```java
public interface PayrollRepository extends JpaRepository<Payroll, Integer> {}
```
**Entity**
```java
@Entity
public class Payroll {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Integer employeeId;
private Date month;
private BigDecimal totalSalary;
// Getters and setters
}
```
### 安全认证和权限控制
#### 添加Spring Security依赖
在`pom.xml`中添加Spring Security依赖:
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
```
#### 配置Spring Security
创建一个Security配置类来配置基本的安全设置:
```java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/salary/**", "/api/attendance/**", "/api/performance/**", "/api/payroll/**").authenticated()
.and()
.httpBasic()
.and()
.csrf().disable(); // Disable CSRF for simplicity
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin")
.password(passwordEncoder().encode("admin123"))
.roles("ADMIN");
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
```
### 定时任务管理
#### 添加Spring Scheduler依赖
在`pom.xml`中添加Spring Scheduler依赖:
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
```
#### 配置Spring Scheduler
在应用程序主类或配置类上启用定时任务功能:
```java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class PayrollApplication {
public static void main(String[] args) {
SpringApplication.run(PayrollApplication.class, args);
}
}
```
#### 实现定时任务
创建一个定时任务类,按月自动计算工资:
```java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@Component
public class PayrollScheduler {
@Autowired
private PayrollRepository payrollRepository;
@Autowired
private EmployeeRepository employeeRepository;
@Autowired
private AttendanceRepository attendanceRepository;
@Autowired
private PerformanceRepository performanceRepository;
@Scheduled(cron = "0 0 0 1 * ?") // 每月1号凌晨0点触发
public void calculateMonthlyPayroll() {
List<Employee> employees = employeeRepository.findAll();
for (Employee employee : employees) {
BigDecimal totalSalary = calculateSalary(employee);
Payroll payroll = new Payroll();
payroll.setEmployeeId(employee.getId());
payroll.setMonth(new Date());
payroll.setTotalSalary(totalSalary);
payrollRepository.save(payroll);
}
}
private BigDecimal calculateSalary(Employee employee) {
BigDecimal baseSalary = employee.getBaseSalary();
BigDecimal allowance = employee.getAllowance();
BigDecimal subsidy = employee.getSubsidy();
BigDecimal bonus = employee.getBonus();
BigDecimal performanceSalary = performanceRepository.findByEmployeeId(employee.getId())
.map(Performance::getScore)
.orElse(BigDecimal.ZERO);
BigDecimal attendanceDeduction = attendanceRepository.findByEmployeeId(employee.getId())
.stream()
.map(attendance -> attendance.getHoursWorked().subtract(attendance.getLeaveHours()))
.reduce(BigDecimal.ZERO, BigDecimal::add);
return baseSalary.add(allowance).add(subsidy).add(bonus).add(performanceSalary).subtract(attendanceDeduction);
}
}
```
### 总结
本文展示了如何使用Spring Boot、MySQL、Spring Security和Spring Scheduler开发一个简单的OA系统薪资管理模块。通过这些技术的结合,实现了薪资基础设置、考勤数据导入、绩效考核、工资单查询等功能,并确保系统的安全性和定时任务管理。