这个工作流程管理系统是我去年带队完成的一个企业级应用项目,核心目标是解决中小型团队在项目管理中的协作痛点。系统采用现在主流的前后端分离架构,后端基于SpringBoot 2.7.4构建,前端使用Vue 3.2+Element Plus,数据库选用MySQL 8.0。
为什么选择这套技术栈?在项目启动前的技术评估阶段,我们主要考虑了以下几个因素:
开发效率:SpringBoot的约定优于配置原则大幅减少了XML配置,Vue的组件化开发模式让前端模块可以并行开发。实测下来,基础框架搭建比传统SSM节省了约40%的时间。
团队适配:Java后端开发人员市场保有量大,Vue的学习曲线相对平缓,这样的人员组合在中小型企业中更容易组建。我们团队5人(3后端+2前端)在两周内就完成了技术栈的熟悉。
性能平衡:SpringBoot内嵌Tomcat在压力测试中可稳定支撑800+并发请求,配合Vue的异步加载特性,页面首屏加载时间控制在1.2秒内(测试环境数据)。
技术选型避坑提示:初期考虑过React+TypeScript方案,但评估后发现团队成员需要额外2周学习时间,最终选择了更熟悉的Vue技术栈。建议中小团队在技术选型时优先考虑团队现有技术储备。
系统采用经典的三层架构,但在具体实现上做了些优化调整:
code复制[浏览器] ←HTTP/HTTPS→ [Nginx] ←反向代理→ [Vue前端]
↓
[REST API]
↓
[SpringBoot] → [MyBatis-Plus] → [MySQL 8.0]
关键设计要点:
前后端分离:前端独立部署在Nginx,通过axios发送API请求。跨域问题通过@CrossOrigin注解解决,生产环境建议改用Nginx反向代理。
数据持久层:放弃原生MyBatis改用MyBatis-Plus 3.5.3,其Lambda表达式让代码可读性大幅提升。例如用户查询可以写成:
java复制userService.lambdaQuery()
.eq(User::getUsername, "admin")
.one();
数据库共设计12张核心表,这里重点说明几个关键设计:
sql复制CREATE TABLE `sys_user` (
`user_id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`dept_id` BIGINT DEFAULT NULL COMMENT '部门ID',
`username` VARCHAR(50) NOT NULL COMMENT '登录账号',
`password` VARCHAR(100) NOT NULL COMMENT '密码',
`salt` VARCHAR(20) DEFAULT NULL COMMENT '盐值',
`status` CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
`del_flag` CHAR(1) DEFAULT '0' COMMENT '删除标志(0存在 1删除)',
PRIMARY KEY (`user_id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
密码存储采用BCrypt+盐值双重加密,这是目前最推荐的密码存储方案。测试数据表明,在i7-10700 CPU上破解一个8位密码需要约3年时间。
sql复制CREATE TABLE `wk_project_progress` (
`progress_id` BIGINT NOT NULL AUTO_INCREMENT,
`project_id` BIGINT NOT NULL COMMENT '关联项目ID',
`progress` DECIMAL(5,2) DEFAULT '0.00' COMMENT '进度百分比',
`feedback` TEXT COMMENT '进度反馈',
`attachment` VARCHAR(255) DEFAULT NULL COMMENT '附件路径',
`create_by` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`progress_id`),
KEY `idx_project` (`project_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='项目进度表';
这里使用DECIMAL(5,2)存储进度百分比,相比FLOAT可以避免浮点精度问题。建立project_id索引后,查询速度从原来的230ms提升到12ms(10万条测试数据)。
权限管理采用RBAC(基于角色的访问控制)模型,实现要点:
java复制@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface RequiresPermissions {
String[] value();
Logical logical() default Logical.AND;
}
java复制public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) {
HandlerMethod handlerMethod = (HandlerMethod)handler;
RequiresPermissions permissions = handlerMethod.getMethodAnnotation(
RequiresPermissions.class);
if(permissions != null) {
String[] perms = permissions.value();
Subject subject = SecurityUtils.getSubject();
if(!subject.isPermittedAll(perms)) {
throw new UnauthorizedException("无操作权限");
}
}
return true;
}
踩坑记录:初期使用Shiro默认的权限字符串匹配方式,在权限较多时出现性能问题。后来改用Redis缓存权限数据,查询耗时从15ms降到0.3ms。
项目进度流转是本系统的核心功能,我们设计了一个轻量级状态机:
java复制public enum ProjectState {
DRAFT("草稿", Arrays.asList("submit")),
REVIEWING("审核中", Arrays.asList("approve", "reject")),
PROCESSING("进行中", Arrays.asList("complete", "pause")),
COMPLETED("已完成", Collections.emptyList());
private final String desc;
private final List<String> availableActions;
// 检查动作是否合法
public boolean canTransfer(String action) {
return availableActions.contains(action);
}
}
状态转换服务示例:
java复制@Transactional
public void changeState(Long projectId, String action) {
Project project = getById(projectId);
ProjectState current = ProjectState.valueOf(project.getStatus());
if(!current.canTransfer(action)) {
throw new BusinessException("当前状态不能执行此操作");
}
ProjectState newState = transfer(current, action);
project.setStatus(newState.name());
updateById(project);
// 记录状态变更日志
progressService.recordTransition(projectId,
current.getDesc(), newState.getDesc(), action);
}
我们制定了严格的组件开发规范:
code复制src/
├── components/
│ ├── common/ # 全局通用组件
│ ├── business/ # 业务组件
│ └── layout/ # 布局组件
├── views/
│ ├── project/ # 路由组件
│ └── system/
vue复制<template>
<el-card shadow="hover" class="project-card">
<template #header>
<div class="flex-between">
<span>{{ project.name }}</span>
<status-badge :status="project.status"/>
</div>
</template>
<progress-bar :percent="project.progress"/>
<div class="footer">
<el-button-group>
<el-button @click="handleDetail">详情</el-button>
<el-button v-if="hasPermission('edit')"
@click="handleEdit">编辑</el-button>
</el-button-group>
</div>
</el-card>
</template>
<script setup>
defineProps({
project: {
type: Object,
required: true
}
});
const hasPermission = usePermission();
</script>
通过以下措施将首屏加载时间从3.2s优化到1.4s:
js复制const routes = [
{
path: '/project',
component: () => import('@/views/project/index.vue')
}
];
js复制import { ElButton, ElCard } from 'element-plus';
export default {
components: {
[ElButton.name]: ElButton,
[ElCard.name]: ElCard
}
};
js复制const service = axios.create({
baseURL: import.meta.env.VITE_APP_API,
timeout: 10000,
withCredentials: true
});
// 请求拦截器
service.interceptors.request.use(config => {
config.headers['Authorization'] = getToken();
return config;
});
// 响应拦截器
service.interceptors.response.use(
response => {
const res = response.data;
if (res.code !== 200) {
return Promise.reject(new Error(res.message || 'Error'));
}
return res;
},
error => {
return Promise.reject(error);
}
);
推荐使用Docker Compose部署方案:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql/data:/var/lib/mysql
- ./mysql/conf:/etc/mysql/conf.d
ports:
- "3306:3306"
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/workflow?useSSL=false
frontend:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./frontend/dist:/usr/share/nginx/html
- ./nginx.conf:/etc/nginx/nginx.conf
关键配置说明:
yaml复制management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: always
js复制// 全局错误处理
app.config.errorHandler = (err, vm, info) => {
console.error(err);
logErrorToService({
error: err.stack,
component: vm?.$options.name,
info
});
};
// 接口错误统计
axios.interceptors.response.use(undefined, error => {
trackApiError(error);
return Promise.reject(error);
});
前后端协作:我们采用Swagger+YAPI的方案,后端定义好接口文档后,前端可以直接生成Mock数据。实测这种方式比传统口头沟通效率提升60%以上。
代码质量管理:引入SonarQube进行静态代码分析,配置了以下规则:
性能优化技巧:
这个项目从需求分析到最终上线共耗时4个月,最大的收获是验证了SpringBoot+Vue这套技术栈在中型企业应用中的可行性。特别是在快速迭代方面,前后端分离架构让我们可以并行开发多个功能模块,显著提升了交付效率。