这个基于SpringBoot+Vue的职工管理系统是一个现代化的企业人力资源管理解决方案。作为一名有多年开发经验的全栈工程师,我最近完成了一个完整的职工管理系统开发项目,现在将详细分享这个系统的设计思路、技术实现和开发经验。
这个系统采用前后端分离架构,后端使用SpringBoot框架,前端使用Vue.js,数据库采用MySQL。系统主要功能包括员工信息管理、考勤管理、奖惩管理、合同管理等模块,能够满足中小型企业的人力资源管理需求。
在项目初期,我经过仔细的技术选型评估,最终确定了以下技术栈:
后端技术栈:
前端技术栈:
开发工具:
系统采用典型的三层架构设计:
这种分层架构使得系统各组件职责明确,便于维护和扩展。前后端通过RESTful API进行通信,接口设计遵循OpenAPI规范。
用户认证是系统的核心功能之一,我采用了JWT(JSON Web Token)实现无状态认证。具体实现如下:
后端实现:
java复制// JWT工具类
public class JwtUtil {
private static final String SECRET_KEY = "your-secret-key";
private static final long EXPIRATION_TIME = 86400000; // 24小时
public static String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
public static Boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
}
前端实现:
javascript复制// 登录逻辑
async function login(userInfo) {
try {
const response = await axios.post('/api/auth/login', userInfo);
const token = response.data.token;
localStorage.setItem('token', token);
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
return response.data;
} catch (error) {
throw error.response.data;
}
}
员工信息管理模块实现了员工基本信息的CRUD操作。我使用了MyBatis-Plus简化数据库操作:
java复制@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee>
implements EmployeeService {
@Override
public Page<Employee> getEmployeesByPage(int pageNum, int pageSize,
String name, String department) {
QueryWrapper<Employee> queryWrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(name)) {
queryWrapper.like("name", name);
}
if (StringUtils.isNotBlank(department)) {
queryWrapper.eq("department", department);
}
return page(new Page<>(pageNum, pageSize), queryWrapper);
}
}
前端使用Element Plus的表格组件展示员工信息:
vue复制<template>
<el-table :data="employeeList" style="width: 100%">
<el-table-column prop="id" label="ID" width="80"></el-table-column>
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="department" label="部门"></el-table-column>
<el-table-column prop="position" label="职位"></el-table-column>
<el-table-column label="操作" width="180">
<template #default="scope">
<el-button size="small" @click="handleEdit(scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</template>
考勤管理模块实现了员工打卡、请假申请和考勤统计功能。我设计了以下数据库表:
sql复制CREATE TABLE `attendance` (
`id` bigint NOT NULL AUTO_INCREMENT,
`employee_id` bigint NOT NULL,
`check_in_time` datetime DEFAULT NULL,
`check_out_time` datetime DEFAULT NULL,
`status` varchar(20) DEFAULT 'NORMAL',
`remark` varchar(255) DEFAULT NULL,
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_employee_id` (`employee_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
考勤统计功能实现:
java复制public Map<String, Object> getAttendanceStatistics(Long employeeId, Date startDate, Date endDate) {
Map<String, Object> result = new HashMap<>();
// 查询考勤记录
List<Attendance> records = attendanceMapper.selectByEmployeeAndDateRange(
employeeId, startDate, endDate);
// 统计考勤情况
long normalCount = records.stream()
.filter(a -> "NORMAL".equals(a.getStatus()))
.count();
long lateCount = records.stream()
.filter(a -> "LATE".equals(a.getStatus()))
.count();
long absentCount = records.stream()
.filter(a -> "ABSENT".equals(a.getStatus()))
.count();
result.put("total", records.size());
result.put("normal", normalCount);
result.put("late", lateCount);
result.put("absent", absentCount);
return result;
}
系统设计了以下核心表:
为了提高系统性能,我采取了以下优化措施:
java复制// 分页查询示例
public Page<Employee> getEmployeesByPage(int pageNum, int pageSize,
String name, String department) {
QueryWrapper<Employee> queryWrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(name)) {
queryWrapper.like("name", name);
}
if (StringUtils.isNotBlank(department)) {
queryWrapper.eq("department", department);
}
return page(new Page<>(pageNum, pageSize), queryWrapper);
}
系统使用Spring Security实现基于角色的访问控制(RBAC):
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/api/employee/**").hasAnyRole("ADMIN", "EMPLOYEE")
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager()))
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
java复制// 密码加密示例
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// 用户注册时加密密码
public User register(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
return userRepository.save(user);
}
我采用模块化组件设计,主要组件包括:
使用Pinia进行状态管理:
javascript复制// store/employee.js
export const useEmployeeStore = defineStore('employee', {
state: () => ({
employees: [],
currentPage: 1,
total: 0,
loading: false
}),
actions: {
async fetchEmployees(page = 1, searchParams = {}) {
this.loading = true;
try {
const res = await employeeApi.getEmployees(page, searchParams);
this.employees = res.data.list;
this.currentPage = page;
this.total = res.data.total;
} finally {
this.loading = false;
}
}
}
});
统一封装API请求:
javascript复制// api/employee.js
import request from '@/utils/request';
export default {
getEmployees(page, params) {
return request({
url: '/api/employees',
method: 'get',
params: {
page,
...params
}
});
},
createEmployee(data) {
return request({
url: '/api/employees',
method: 'post',
data
});
}
};
系统支持多种部署方式:
Docker部署示例:
dockerfile复制# 后端Dockerfile
FROM openjdk:17-jdk-slim
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
# 前端Dockerfile
FROM nginx:alpine
COPY dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
java复制// 使用Redis缓存示例
public Employee getEmployeeById(Long id) {
String cacheKey = "employee:" + id;
Employee employee = redisTemplate.opsForValue().get(cacheKey);
if (employee == null) {
employee = employeeMapper.selectById(id);
if (employee != null) {
redisTemplate.opsForValue().set(cacheKey, employee, 1, TimeUnit.HOURS);
}
}
return employee;
}
解决方案:配置CORS
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.maxAge(3600);
}
}
解决方案:配置Spring Boot
properties复制# application.properties
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
解决方案:配置Nginx
nginx复制location / {
try_files $uri $uri/ /index.html;
}
这个职工管理系统项目让我深入理解了现代Web应用开发的完整流程,从需求分析到系统设计,从编码实现到测试部署。通过这个项目,我积累了丰富的全栈开发经验,特别是在SpringBoot和Vue.js的整合应用方面有了更深入的认识。