1. 项目概述:企业级全栈解决方案
这套基于SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0的企业项目管理系统,是我在参与某制造业数字化转型项目时沉淀的实战成果。系统采用前后端分离架构,后端使用SpringBoot2提供RESTful API,前端通过Vue3实现响应式管理界面,数据持久层采用MyBatis-Plus简化CRUD操作,配合MySQL8.0的窗口函数和CTE特性实现复杂报表统计。
注意:选择SpringBoot2而非3.x版本是考虑到企业环境中JDK8仍占主流,而Vue3的Composition API相比Options API更适合大型项目管理系统的状态维护。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术栈深度解析
2.1 后端架构设计
SpringBoot2.7.18作为基础框架,其自动配置机制大幅减少了XML配置。我在项目中特别优化了以下配置:
java复制// 多数据源配置示例(适用于分库场景)
@Configuration
@MapperScan(basePackages = "com.epms.mapper.primary", sqlSessionTemplateRef = "primarySqlSessionTemplate")
public class PrimaryDataSourceConfig {
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
}
MyBatis-Plus 3.5.3的Lambda查询构建器让动态SQL编写更直观:
java复制// 动态条件查询示例
public Page<ProjectVO> selectProjectPage(Page<ProjectVO> page, ProjectQuery query) {
return projectMapper.selectProjectPage(page,
Wrappers.<Project>lambdaQuery()
.like(StringUtils.isNotBlank(query.getProjectName()), Project::getProjectName, query.getProjectName())
.eq(query.getProjectStatus() != null, Project::getStatus, query.getProjectStatus())
.between(query.getStartTime() != null && query.getEndTime() != null,
Project::getCreateTime, query.getStartTime(), query.getEndTime())
);
}
2.2 前端工程化实践
Vue3 + Vite构建的响应式前端具有以下特点:
- 使用Pinia替代Vuex进行状态管理
- Element Plus按需加载减小打包体积
- 动态路由配合后端权限数据实现菜单鉴权
javascript复制// 动态路由处理示例
const asyncRoutes = rawRoutes.map(route => {
return {
path: route.path,
component: () => import(`../views/${route.component}.vue`),
meta: { title: route.title, icon: route.icon }
}
})
2.3 数据库优化策略
MySQL8.0的特性应用:
sql复制-- 使用窗口函数计算项目进度排名
SELECT
project_id,
progress_rate,
RANK() OVER(ORDER BY progress_rate DESC) AS rank_num
FROM project_progress;
3. 核心功能实现
3.1 多维度权限控制系统
采用RBAC模型扩展实现数据权限:
- 用户-角色-菜单三级权限控制
- 部门数据隔离(通过MyBatis-Plus拦截器自动注入WHERE条件)
- 按钮级权限控制(v-permission指令)
权限表设计关键字段:
sql复制CREATE TABLE `sys_role` (
`role_id` bigint NOT NULL AUTO_INCREMENT,
`role_name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,
`data_scope` tinyint NOT NULL COMMENT '1全部 2本部门 3自定义',
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
3.2 项目全生命周期管理
从立项到结项的完整流程控制:
- 甘特图实现(基于Gantt-elastic组件)
- 里程碑节点预警(Quartz定时任务扫描)
- 文档版本管理(MinIO存储+版本号控制)
进度计算算法:
java复制// 基于任务权重的进度计算
public BigDecimal calculateProjectProgress(Long projectId) {
List<Task> tasks = taskMapper.selectList(
Wrappers.<Task>lambdaQuery().eq(Task::getProjectId, projectId));
BigDecimal totalWeight = tasks.stream()
.map(Task::getWeight)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal completedWeight = tasks.stream()
.filter(t -> t.getStatus() == TaskStatus.DONE)
.map(Task::getWeight)
.reduce(BigDecimal.ZERO, BigDecimal::add);
return totalWeight.compareTo(BigDecimal.ZERO) > 0 ?
completedWeight.divide(totalWeight, 2, RoundingMode.HALF_UP) :
BigDecimal.ZERO;
}
4. 部署与性能优化
4.1 容器化部署方案
Docker Compose编排文件关键配置:
yaml复制services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql/conf:/etc/mysql/conf.d
- ./mysql/data:/var/lib/mysql
ports:
- "3306:3306"
backend:
build: ./epms-backend
ports:
- "8080:8080"
depends_on:
- mysql
environment:
SPRING_PROFILES_ACTIVE: prod
4.2 高频访问接口优化
-
二级缓存策略:
- 本地Caffeine缓存(短时效数据)
- Redis集群(分布式锁/共享数据)
-
SQL优化示例:
sql复制-- 原查询(存在N+1问题)
SELECT * FROM project WHERE dept_id = 1;
-- 优化后(JOIN+批量查询)
SELECT p.*, d.dept_name
FROM project p
LEFT JOIN department d ON p.dept_id = d.dept_id
WHERE p.dept_id IN (1,2,3);
5. 典型问题排查实录
5.1 跨域会话失效问题
现象:Vue前端登录后,后续请求出现401未授权。
排查过程:
- 检查浏览器Application面板发现JWT token已正确存储
- 后端日志显示OPTIONS预检请求通过,但实际请求缺失Authorization头
- 发现axios请求配置中未携带credentials
解决方案:
javascript复制// axios实例配置
const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API,
withCredentials: true // 允许携带cookie
})
5.2 MyBatis-Plus批量插入性能瓶颈
原始方案:循环调用mapper.insert()
java复制// 低效写法
for (ProjectMember member : members) {
memberMapper.insert(member);
}
优化方案:使用SQL批处理
java复制// 批量插入(需配置jdbc参数rewriteBatchedStatements=true)
List<ProjectMember> batchList = new ArrayList<>();
for (int i = 0; i < members.size(); i++) {
batchList.add(members.get(i));
if (i % 1000 == 0 || i == members.size() - 1) {
memberMapper.insertBatchSomeColumn(batchList);
batchList.clear();
}
}
6. 扩展开发建议
- 工作流引擎集成:可接入Activiti7实现复杂审批流
- 移动端适配:基于Uniapp开发配套小程序
- 数据分析扩展:使用Apache POI+ECharts实现自定义报表导出
- 消息推送增强:集成WebSocket实现实时通知看板
项目文档包含:
- 数据库ER图(PowerDesigner文件)
- API接口文档(Swagger+Postman集合)
- 前端组件说明文档
- 压力测试报告(JMeter测试计划)
