作为一名长期从事企业级应用开发的工程师,我最近完成了一个基于SpringBoot+Vue3+MyBatis的项目申报系统。这个系统完美解决了传统纸质申报流程中的各种痛点:审批周期长、信息不透明、数据易丢失等问题。通过数字化手段,我们将整个申报流程的效率提升了3倍以上。
系统采用主流的前后端分离架构,后端使用SpringBoot 2.7提供RESTful API服务,前端采用Vue3+TypeScript构建响应式界面,数据库选用MySQL 8.0。这种技术组合既保证了系统的稳定性,又能满足高并发的业务需求。在实际部署中,系统单节点可以轻松支撑500+的并发申报请求。
选择SpringBoot作为后端框架主要基于以下几个考虑:
数据库访问层采用MyBatis而非JPA,主要因为:
重要提示:MyBatis的mapper文件建议按功能模块分包存放,避免所有SQL都堆在同一个文件中
Vue3的组合式API相比选项式API更适合大型项目开发:
javascript复制// 申报表单状态管理示例
const formState = reactive({
projectName: '',
projectDesc: '',
attachments: []
})
const submitForm = async () => {
try {
await api.submitProject(formState)
message.success('申报提交成功')
} catch (error) {
message.error(`提交失败: ${error.message}`)
}
}
Element Plus组件库的选择依据:
审批状态机设计是系统的核心难点之一。我们采用状态模式实现审批流转:
java复制public interface AuditState {
void handle(ProjectContext context);
}
// 具体状态实现
public class PendingState implements AuditState {
@Override
public void handle(ProjectContext context) {
// 待审批逻辑
}
}
审批流程配置采用数据库存储而非硬编码,便于后期调整:
sql复制CREATE TABLE audit_flow (
id BIGINT PRIMARY KEY,
flow_name VARCHAR(50),
steps JSON COMMENT '存储审批步骤配置'
);
考虑到申报材料可能包含大文件,我们实现了分片上传:
java复制@PostMapping("/upload")
public Result uploadChunk(
@RequestParam MultipartFile file,
@RequestParam String chunkMd5,
@RequestParam Integer chunkIndex) {
// 分片处理逻辑
}
实际踩坑:MinIO默认分片大小为5MB,对于视频类大文件需要调整配置
根据查询特点建立了复合索引:
sql复制-- 项目查询高频条件
CREATE INDEX idx_project_search ON project(
audit_status,
submit_time DESC,
user_id
);
-- 审批记录查询
CREATE INDEX idx_audit_record ON audit_log(
project_id,
audit_time DESC
);
申报提交需要保证数据一致性:
java复制@Transactional
public void submitProject(ProjectDTO dto) {
// 1. 保存项目基本信息
projectMapper.insert(dto);
// 2. 保存附件关系
attachmentMapper.batchInsert(dto.getAttachments());
// 3. 创建审批任务
auditService.createTask(dto.getId());
}
java复制@PreAuthorize("hasRole('ADMIN') or #userId == authentication.principal.id")
@GetMapping("/projects/{userId}")
public List<Project> getUserProjects(@PathVariable Long userId) {
// ...
}
java复制// 密码加密示例
String encodedPwd = new BCryptPasswordEncoder().encode(rawPassword);
使用Redis缓存高频访问数据:
java复制@Cacheable(value = "project", key = "#id")
public Project getProjectById(Long id) {
return projectMapper.selectById(id);
}
改造前慢查询:
sql复制SELECT * FROM project
WHERE audit_status = 0
ORDER BY submit_time DESC
优化后:
sql复制SELECT p.* FROM project p
JOIN (
SELECT id FROM project
WHERE audit_status = 0
ORDER BY submit_time DESC
LIMIT 20 OFFSET 0
) tmp ON p.id = tmp.id
Docker Compose编排文件示例:
yaml复制version: '3'
services:
app:
image: project-application:1.0
ports:
- "8080:8080"
depends_on:
- redis
- mysql
redis:
image: redis:6-alpine
ports:
- "6379:6379"
关键监控指标:
现象:多人同时申报时出现数据错乱
解决方案:
java复制@Transactional(isolation = Isolation.SERIALIZABLE)
public synchronized void submitProject(...) {
// 加锁处理
}
调整Nginx配置:
code复制client_max_body_size 100m;
proxy_read_timeout 600s;
系统后续可以增加:
技术债清单:
这个项目让我深刻体会到,一个好的业务系统不仅需要扎实的技术实现,更要深入理解业务流程。特别是在状态流转设计上,一定要预留足够的扩展性,因为审批流程的变更是最常见的需求变更之一