☰
SpringBoot+Vue实战:大学生创新创业项目管理系统全栈开发指南
2026/10/19 14:54:24 网站建设 项目流程

做“大学生创新创业项目管理系统”这种题目,算是Java全栈方向里非常经典的一类实战项目。它是典型的业务管理系统,数据模型不算复杂,业务链路却足够长:申报、审核、立项、中期检查、结题验收,每个环节都有状态流转,也有不同角色参与。正好适合拿SpringBoot+Vue这套技术栈来完整走一遍前后端分离开发。

哪怕你拿到的标题里“管理系统”打了两遍,也不影响这个题目的含金量。真正有价值的是把项目从需求拆开、数据库设计好、接口写明白、页面能跑通这一整套过程。这篇内容我按自己做过的实际项目复盘来写,不是官方案例的复读,重点是设计思路、核心实现、部署细节和踩坑记录。如果你正准备做毕设、课程设计,或者只是想通过一个完整项目把Java后端和Vue前端串起来,这篇文章可以直接拿来当参考路线图。

1. 拆解整体思路:为什么这个系统值得做,前后端分离好在哪

1.1 核心需求解析:大创项目管理到底在管什么

大学生创新创业项目,通常简称为“大创项目”,指的是高校组织学生围绕创新训练、创业训练、创业实践等方向申报课题,并给予经费支持的一种实践教学机制。实际业务场景中,项目从申报到结题要经过非常多的环节。

学生需要在线填写项目申报书、添加成员、选择指导教师;导师要审核申报内容并给出意见;学院或学校的管理员要组织专家评审、公示立项名单;项目立项后,还要提交中期检查材料;最终要上传结题报告、成果清单(论文、专利、软著、获奖等)。这些流程如果靠纸质材料加Excel表格来管,会非常痛苦——版本混乱、状态不清、数据统计困难。

系统要解决的核心问题,翻译成技术语言就是三类:第一,多角色的身份认证和权限控制;第二,以“项目”为主线的全生命周期状态管理;第三,围绕项目展开的增删改查、文件上传、评审记录和数据统计。业务边界一旦清楚,后面的数据库设计和接口设计就不会跑偏。

1.2 技术选型为什么这么定:SpringBoot+Vue+MySQL+MyBatis

这个技术组合在JavaWeb领域属于“标准答案”级别的配置。SpringBoot解决了Spring配置繁琐的问题,内嵌Tomcat,一个java -jar就能跑起来;Vue作为前端框架,配合Element UI可以非常快速地搭建后台管理界面;MySQL是最常用的关系型数据库,处理这种结构化业务数据绰绰有余;MyBatis则把SQL和Java方法做了映射,让开发者对查询逻辑有完全的控制权。

相比直接用JSP加Servlet做单体项目,前后端分离最大的优势是开发和部署解耦。前端团队和后端团队可以并行工作,只要接口约定好;部署时前端静态资源可以扔到Nginx,后端打jar包独立运行。对于单人开发来说,这种结构也更容易排查问题。相比Spring Data JPA,我更喜欢MyBatis的原因很直接:复杂查询、多表关联、动态条件这些场景,用SQL写出来一目了然,出了问题直接在SQL层面排查,不需要猜框架帮你做了什么。

1.3 功能模块拆解:哪些功能是必须有的

根据“申报—审核—执行—结题”这条主线,我把系统拆成六个核心模块。

用户管理模块负责学生、教师、管理员三类账号的创建和角色分配;项目管理模块是最重的部分,包含项目申报、查询、修改、删除、提交审核;审批管理模块处理导师审核、学院推荐、专家评审,并记录每一级意见;过程管理模块覆盖中期检查、结题申请和成果上传;系统管理模块包含项目类型维护、公告发布、数据统计;文件管理模块负责申报书、中期报告、结题材料等附件的上传和下载。

这套模块划分覆盖了完整业务流程,同时也是典型的“可增删”结构。如果你时间紧张,可以砍掉公告和统计部分;如果想让系统更完整,可以往上加消息通知、经费管理、双导师分配。核心业务链路不变,扩展空间非常灵活。

1.4 技术版本与基础依赖:起步前先定好

版本定不好,后面全是坑。我这里用的是长期稳定的一套组合:JDK 1.8,SpringBoot 2.7.x,MyBatis 2.3.x,MySQL 5.7或8.0都可以,前端Vue 2.6加Element UI 2.15,Node环境14以上。这套组合的兼容性经过大量项目验证,遇到问题能搜索到的解决方案也最多。

需要注意,SpringBoot 3.x已经发布,但它要求JDK 17起步,部分老版本MyBatis依赖不兼容。如果项目需求里没有强制要求最新技术栈,没必要为了追新给自己增加风险。在工程领域,稳定和可复现永远比版本号新鲜更重要。

依赖方面,SpringBoot的starter-web、starter-jdbc基础包肯定要加,MyBatis-SpringBoot-Starter负责集成,MySQL驱动用mysql-connector-java,分页用PageHelper,鉴权可以用JWT加拦截器来实现,工具类用Hutool能省不少事,Lombok建议加上,能让实体类代码少一半。

2. 数据库设计实战:核心表结构与字段到底该怎么定

2.1 从实体关系出发:先画清楚谁和谁有关系

我对这类项目的建库习惯是:先列实体,再谈字段。系统的核心实体包括用户(User)、项目(Project)、项目类型(ProjectType)、项目成员(ProjectMember)、附件(Attachment)、审核记录(AuditRecord)、中期检查(MidtermCheck)、结题报告(FinalReport)。

实体之间的关系要重点理清:一个项目属于一个负责人,但可以有多个成员,所以需要独立的成员表或者用JSON字段保存成员列表,我更推荐独立成员表,后续可以做成员变更记录;一个项目会经历多次审核,所以“项目”和“审核记录”是一对多关系;一个项目可能多次上传材料,所以“项目”和“附件”也是一对多关系。

理清这些关系之后,外键字段就很好确定了。项目表里有creator_id(负责人)、type_id(项目类型)、teacher_id(指导教师);审核表里有project_id、auditor_id;附件表里有project_id。实体关系图不用画得很复杂,能指导建表就够了,关键是别把多对多关系硬塞进单张表。

2.2 核心表设计:用户表和项目表的字段说明

用户表字段相对标准:id、username、password、real_name、role(1学生、2教师、3管理员)、college、phone、email、avatar、status、create_time。密码一定要加密存储,MD5已经不安全,至少用BCrypt。

项目表是系统里字段最多的表,也是整个系统的数据核心,设计时要考虑查询和状态流转的双重需求:

字段名类型说明
idbigint主键,自增
project_namevarchar(200)项目名称
project_novarchar(50)项目编号,立项后生成
type_idbigint关联项目类型表
creator_idbigint负责人用户ID
teacher_idbigint指导教师用户ID
member_jsontext成员信息(备选方案)
summarytext项目简介
budgetdecimal(10,2)申请经费金额
statusint项目状态,1草稿 2待导师审核 3待学院审核 4待评审 5已立项 6中期检查中 7待结题 8已结题 9已终止
audit_opiniontext最近一次审核意见
create_timedatetime创建时间
update_timedatetime更新时间
deletedtinyint逻辑删除标记

status用int而不是varchar,是因为状态是一个固定枚举值,用int存储更省空间、索引更快,代码里再用枚举类或者常量类做映射。budget必须用decimal而不是float/double,经费金额涉及精度问题,二进制浮点数会带来计算误差。deleted字段做逻辑删除,这是业务系统的通用做法,一旦项目进入审核流程,不能物理删除,只能标记作废。

2.3 关联表与索引设计:查询性能的关键

审核记录表要记录每次操作的可追溯信息,字段包括id、project_id、auditor_id、audit_role(导师/学院/专家)、opinion、result(通过/退回)、audit_time。这张表会增长得很快,project_id必须加普通索引,如果需要按审核人查历史,再加一个auditor_id的联合索引。

项目表的索引设计更讲究。状态筛选是最高频的操作,status字段单独建索引;如果经常按“类型+状态”组合查询,建联合索引(type_id, status);如果经常按负责人查,creator_id也要建索引。附件表主要按project_id查,所以project_id加普通索引就够了。

关于物理外键,我的建议是只在设计文档里体现逻辑外键,不在数据库层面加FOREIGN KEY约束。理由有三点:物理外键在数据量大、并发高时会影响插入和更新性能;删除和修改主表记录时会被外键约束卡住,迁移数据极其麻烦;团队开发或二次开发时,逻辑外键配合索引已经能满足所有查询需求,物理外键属于额外负担。

2.4 初始化SQL的几个硬性注意点

建库语句必须指定utf8mb4字符集,utf8mb4是utf8的超集,支持emoji和更多特殊字符,排序规则选utf8mb4_general_ci就行。存储引擎用InnoDB,这是支持事务的唯一选择,项目资金和审核记录这类数据绝不能出现半截写入。

时间字段统一用datetime,不要用timestamp格式化,datetime在业务展示时更直接,也不受2038年问题影响。预算字段用decimal(10,2),整数部分10位足够,小数部分统一两位。默认值要设置好,比如create_time用DEFAULT CURRENT_TIMESTAMP,deleted默认0,status默认1,可以减少很多后端代码的冗余赋值。

建完表之后,建议顺手插入一个初始化管理员账号。比如用户名admin、密码用BCrypt生成加密串后手动写入,这样后端代码启动后直接可以登录,不用再额外写注册管理员的接口。

3. 后端核心功能落地:SpringBoot+MyBatis 这样写最稳

3.1 工程结构规划:从启动类到业务层一次到位

后端工程结构我习惯按职责分包,不按技术类型分包。controller放接口入口,service放业务逻辑,mapper放数据库操作,entity放数据库映射实体,dto放接收参数的类,vo放返回前端的视图类,common放统一返回结果、全局异常、常量定义,config放配置类。

src/main/java/com/example/project/ ├── common/ │ ├── Result.java │ ├── PageResult.java │ ├── GlobalExceptionHandler.java │ └── Constant.java ├── config/ │ ├── WebConfig.java │ └── JwtInterceptor.java ├── controller/ │ ├── AuthController.java │ ├── ProjectController.java │ └── UploadController.java ├── service/ │ ├── ProjectService.java │ └── impl/ProjectServiceImpl.java ├── mapper/ │ ├── UserMapper.java │ └── ProjectMapper.java ├── entity/ │ ├── User.java │ └── Project.java ├── dto/ │ └── ProjectApplyDTO.java ├── vo/ │ └── ProjectDetailVO.java └── ProjectApplication.java

Result类是所有接口的统一返回格式,包含code、message、data三个字段,成功时code为200,失败时按异常类型返回。不要小看这个包装类,它会让前端拦截器处理也变得非常统一。全局异常处理器用@RestControllerAdvice标注,把参数校验异常、业务异常、系统异常分层处理,避免把堆栈信息直接返回给前端。

3.2 登录鉴权:JWT加拦截器,比引入Spring Security更省心

大创项目管理系统这种规模,不需要把Spring Security整套引进来,JWT加拦截器足够。用户在登录接口提交用户名和密码,后端校验通过后用JWT工具类生成token,token里放用户ID和角色信息,然后返回给前端。前端每次请求在Header里带Authorization: Bearer xxx,后端拦截器统一解析并校验。

拦截器里要做的事很明确:放行登录接口和路径,校验token是否存在、是否过期、是否合法,再把用户信息放入ThreadLocal或者Request属性中供后续代码使用。角色权限的校验也放在拦截器或者注解里完成,比如项目管理接口只允许负责人操作,审批接口只允许对应角色的教师操作。

有一点容易踩坑:拦截器注册时不要拦截静态资源和文件下载路径。文件下载如果是登录后才能访问,可以在下载接口内部校验,但更简单的做法是在WebConfig里把/api/file/download/**加入放行白名单,安全校验在接口方法内部做。

3.3 项目状态流转:用状态枚举加校验,别把流程写死在if里

项目状态是这条业务链路的中枢。简单来说,每个状态能执行的操作是不同的:草稿状态可以编辑和提交;待导师审核状态下,学生不能再编辑,导师可以审核通过或退回;立项后学生可以提交中期检查材料;结题状态下学生提交结题报告和成果。

实现上有两种思路。第一种是写一堆if-else判断当前状态允许执行什么操作,代码简单但后期改流程很痛苦;第二种是用状态机模式,定义状态转换映射表,比如:

// 状态流转配置:当前状态 -> 可执行操作 -> 目标状态 Map<Integer, Map<String, Integer>> TRANSITIONS = new HashMap<>() {{ put(1, Map.of("submit", 2)); // 草稿 -> 提交导师审核 put(2, Map.of("approve", 3)); // 导师通过 -> 学院审核 put(2, Map.of("reject", 1)); // 导师退回 -> 变成草稿 put(3, Map.of("approve", 4)); // 学院通过 -> 专家评审 put(4, Map.of("approve", 5)); // 评审通过 -> 立项 }};

然后在业务方法里做一个通用校验:操作前查当前状态,从映射表里找到目标状态,如果映射不存在就抛异常,存在就更新状态并记录审核记录。这样做的好处是流程调整时只改一张映射表,不用动核心代码。对于课程设计级别的项目,这个方案完全可以做得优雅又实用。

3.4 多条件查询与分页:动态SQL的正确打开方式

项目列表页基本都会有筛选条件:项目名称模糊查询、负责人姓名、项目类型、立项状态、时间范围。写死在SQL里肯定不行,MyBatis的动态SQL就是为这种场景准备的。

<select id="selectProjectPage" resultType="com.example.project.vo.ProjectVO"> SELECT p.*, u.real_name AS creator_name FROM project p LEFT JOIN user u ON p.creator_id = u.id <where> <if test="projectName != null and projectName != ''"> AND p.project_name LIKE CONCAT('%', #{projectName}, '%') </if> <if test="typeId != null"> AND p.type_id = #{typeId} </if> <if test="status != null"> AND p.status = #{status} </if> <if test="deleted != null"> AND p.deleted = #{deleted} </if> </where> ORDER BY p.create_time DESC </select>

配合PageHelper分页插件,接口只需要在调用mapper方法前写一行PageHelper.startPage(pageNum, pageSize),返回值用一个PageInfo包装,前端就能拿到总记录数、总页数、当前页数据这些标准分页结构。注意查询条件里的LIKE一定要拼接CONCAT而不是直接写死'%#{name}%',MyBatis的#{}预处理下,直接写在字符串里会导致参数无法正常绑定。

3.5 文件上传与下载:本地存储方案的细节处理

大创项目里申报书、中期报告、结题材料大多是Word或PDF文件,量级不大,服务器本地存储完全够用,没必要上来就接OSS。本地存储方案的重点是配置好上传路径和文件名策略。

file: upload-dir: /data/project-files/ max-size: 20MB

上传接口里用UUID重命名文件,不保留用户上传时的原始文件名,避免中文文件名乱码和路径穿越问题。原始文件名单独存到附件表中,下载的时候通过响应头Content-Disposition设置回给用户。存放目录按年月分子目录,比如/data/project-files/2025/06/,这样目录不会因为文件太多而失控。

文件下载接口要注意校验文件路径是否合法。简单做法是:根据附件表的ID查数据库拿到存储路径,再判断路径是否存在于允许的根目录下,不要直接拿前端传过来的文件名去拼接路径。这个点看着小,但很多安全问题都出在这种地方。

4. 前端页面实现复盘:Vue+Element UI 的这些交互细节别跳过

4.1 前端目录规划与路由守卫

前端工程我用Vue CLI生成,目录结构按视图模块划分。views下面按角色分目录:student放申报页面、我的项目列表;teacher放待审核列表、指导学生列表;admin放项目管理、用户管理、类型管理、数据统计。components放公共组件,比如状态标签、分页工具栏、步骤条。api目录放按模块拆分的接口请求文件,router目录统一管理路由。

路由守卫是权限控制的第一道关卡。全局前置守卫里判断token是否存在:

router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') if (to.path !== '/login' && !token) { next('/login') return } next() })

角色级别的页面权限,可以在路由meta里定义roles数组,比如项目审批页面只允许teacher角色进入,在守卫里再叠加一层角色判断。菜单按钮级别的权限放到页面内用v-if控制,比如学生列表页只有项目负责人才能看到“编辑”按钮。

4.2 Axios封装:统一处理token和错误弹窗

不封装的Axios会写出一堆重复代码。我在utils/request.js里做统一处理:请求拦截器从localStorage取token并设置到Header;响应拦截器检查HTTP状态码,业务码非200时统一提示错误信息,HTTP 401时清除登录状态并跳转登录页。

service.interceptors.response.use( (response) => { const res = response.data if (res.code !== 200) { Message.error(res.message || '请求失败') return Promise.reject(new Error(res.message)) } return res }, (error) => { if (error.response && error.response.status === 401) { localStorage.removeItem('token') router.push('/login') } Message.error(error.message || '网络异常') return Promise.reject(error) } )

接口请求方法统一放在api/目录里导出,页面组件不直接写axios.get。这样做的好处是接口路径集中管理,后端接口一旦调整只需要改一处。比如api/project.js里导出getProjectList(params)、applyProject(data)、auditProject(id, data)这些方法,组件里按需导入。

4.3 申报表单与项目列表:多步骤表单和动态成员操作

项目申报是整个系统里最复杂的表单。用Element UI的el-steps组件做三步引导:第一步填项目基本信息,包括名称、类型、简介、经费;第二步填成员信息,成员列表是可以动态增删的表格;第三步上传申报书附件并最终提交。

动态成员是实现时要多留心的部分。一个项目可能有多个成员,每个人的字段是姓名、学号、专业、年级。我用了el-table加弹窗的方式管理成员列表,成员数据维护在一个本地数组中,提交时随表单一起传给后端,后端统一存到成员表。如果成员信息允许后续变更,那么编辑接口也要处理增删差异,最直接的办法是删除旧成员记录再批量插入新记录。

列表页要关注的交互细节是筛选条件和状态的联动展示。搜索区放项目名称、类型、状态三个筛选控件,点“查询”后重新请求分页接口;“重置”按钮要清空所有条件并把页码重置为1。表格里的状态列用el-tag做不同颜色映射,比如草稿是灰色、审核中是蓝色、立项是绿色、已结题是青色,用户一眼能看出项目走到哪一步。

4.4 审核页面与操作按钮的权限反应

审核页面要展示的信息比较多:项目基本信息、成员列表、申报书预览下载按钮、历史审核记录时间线。我用了el-descriptions做详情展示,历史记录用el-timeline渲染,每次审核的结论和意见按照时间倒序排列。

审核操作区域根据当前用户角色不同显示不同按钮。导师看到的是“通过”和“退回”,管理员看到的是“立项”“终止”。按钮点击后弹窗让审核人填写意见,意见必填并做字数限制。这里有个细节:项目一旦审核通过,学生端页面上的“编辑”按钮必须消失,最稳妥的做法不是在前端隐藏,而是后端在编辑接口里校验项目状态,前端隐藏只是体验层面的优化,真正防线在后端。

5. 从0到1跑通项目:本地部署全流程与常见踩坑指南

5.1 环境准备清单:版本先对齐

跑这个项目,本地需要装齐一套环境:JDK 1.8以上,Maven 3.6以上,MySQL 5.7或8.0,Node.js 14以上,开发工具用IDEA和VSCode都行。装完以后先分别验证一下版本号,确认java -version、mvn -version、node -v、npm -v都正常,不要在环境没就绪时直接打开工程,不然报错的第一时间你会怀疑代码而不是怀疑环境。

数据库准备分两步:先用root账号登录MySQL,执行建库语句CREATE DATABASE IF NOT EXISTS project_manage DEFAULT CHARACTER SET utf8mb4;,然后选定这个库,导入项目里提供的SQL脚本。导入后有一步很容易忽略:检查一下user表里的密码加密串和注册代码使用的加密算法是否一致。如果是用SQL直接插的管理员账号,可能需要先启动后端,走注册接口创建一个账号,再用SQL把role改成管理员,这样密码加密方式保证一致。

5.2 后端启动:配置文件和启动方式

后端配置文件application.yml里关键要改三处:数据源地址jdbc:mysql://localhost:3306/project_manage?serverTimezone=Asia/Shanghai&useSSL=false&characterEncoding=utf8,数据库账号密码,文件上传路径。这里最不能省的是serverTimezone=Asia/Shanghai参数,MySQL 8.0版本如果不带时区参数,启动时大概率会抛InvalidConnectionAttributeException。

启动方式二选一:在IDEA里直接运行启动类,或者命令行执行mvn spring-boot:run。如果工程里配置了Swagger或者Knife4j,启动成功后访问http://localhost:8080/doc.html就能看到接口文档。把接口文档跑出来是联调前最重要的验证,接口能正常列出、数据库能连上,后端这一步就算过了。

5.3 前端启动:代理配置解决跨域

前端工程安装依赖是第一个大坑点,速度慢、容易卡住,解决方案是把npm镜像源切换到国内镜像:npm config set registry https://registry.npmmirror.com。装完依赖执行npm run serve,默认会跑在http://localhost:8080端口,和后端的8080冲突,所以前端devServer要改成8081。

跨域问题的标准做法是在vue.config.js里配置代理:

devServer: { port: 8081, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } }

前端发的请求路径是/api/project/list,代理会把请求转发到http://localhost:8080/api/project/list,浏览器层面没有跨域,后端也不需要专门配跨域过滤器。这里一定要确认后端接口的context-path,如果后端设置了server.servlet.context-path: /api,那前端代理路径和后端接口前缀就要设计一致,否则请求会404。

5.4 打包发布:从开发环境到服务器的最后一公里

开发联调没问题后,打包部署是验证项目完整性的必经环节。后端打包在项目根目录执行mvn clean package -DskipTests,成功后target目录下会生成一个xxx.jar包。在服务器上运行nohup java -jar xxx.jar > app.log 2>&1 &,日志输出到文件方便排查。

前端打包在工程根目录执行npm run build,生成dist目录。如果服务器有Nginx,配置一个server块,root指向dist目录,同时把/api路径反向代理到后端端口:

location /api/ { proxy_pass http://127.0.0.1:8080/; }

如果不想装Nginx,也可以把dist目录复制到src/main/resources/static/下再重新打包后端,SpringBoot会自动把static下的文件作为静态资源服务,这样只有一个jar包,部署更简单。两种方式我都试过,Nginx方式更标准,单jar方式适合快速演示。

5.5 接口排错第一步:看日志看日志看日志

本地联调时接口返错,不要急着查前端,先切到后端控制台看日志。最常见的三类问题:数据库连接失败会看到Communications link failure;字段映射错误会看到org.apache.ibatis.reflection.ReflectionException;请求路径没匹配到会看到404 No mapping found。日志里已经把出错原因写得很清楚,只要耐下心来看,大多数问题都能在五分钟内定位。

6. 常见故障排查速查表:我遇到过的问题基本都在这

现象根因解决方案
后端启动报InvalidConnectionAttributeExceptionMySQL 8驱动要求指定时区jdbcUrl加serverTimezone=Asia/Shanghai
前端请求接口404代理没生效或路径前缀不一致检查vue.config.js代理配置,确认后端context-path
页面中文乱码数据库表不是utf8mb4或前端页面编码问题建库指定utf8mb4,HTTP响应显式声明UTF-8
本地8080端口被占用其他程序占用了默认端口改后端server.port或前端devServer端口
Maven依赖下载卡住默认中央仓库访问慢配置阿里云Maven镜像
npm install报错node-sass版本与Node版本不兼容换dart-sass或升级Node到项目要求的版本
文件上传失败上传路径不存在或没有写权限启动前手动创建upload目录,设置读写权限
项目状态能跳回草稿状态校验只在前端做了后端每个变更接口必须校验状态映射
Linux运行jar后无法访问防火墙或安全组没放开端口检查服务器防火墙,放行8080端口

6.1 数据库连接问题:一半的新手卡在这里

数据库连接错误集中在两类:一是服务没启动,MySQL服务没开或者被安全软件拦截;二是驱动参数问题,报错里带Communications link failure说明网络和端口问题,带InvalidConnectionAttributeException说明时区参数问题。建议启动项目前先用Navicat或者命令行客户端手动连一次库,数据库能连上再启动后端,可以少走很多弯路。

6.2 跨域和路径混淆:前后端联调的三座大山

跨域报错在浏览器控制台里会显示CORS policy字样,但这个项目开发模式下用代理基本遇不到。真正容易踩的是路径混淆:后端接口是/api/project/list,代理target是http://localhost:8080,前端请求也是/api/project/list,看起来能通,但如果后端设置了context-path: /api,那么真实接口路径就变成了/api/api/project/list,必然404。我的建议是后端不设置context-path,统一在接口路径上写/api前缀,前端代理直接转发,逻辑最清晰。

6.3 逻辑删除和状态枚举:别让历史数据悄悄消失

项目进了审核流程之后,学生理论上不能删除项目,但实际业务里允许主动撤回或终止。我设计时用deleted字段做逻辑删除,状态流转里增加了“撤回”动作,这样数据永远留在库里,审计记录不会断。查询列表时SQL里默认过滤deleted = 0,管理员后台可以查全部数据。这个设计在答辩环节也很加分,说明你考虑了数据安全。

6.4 性能优化:数据量上来之后的三个小技巧

这个系统数据量大概率不会特别大,但养成写SQL的好习惯没有坏处。一是列表页查询只查需要的字段,不写SELECT *;二是分页查询不要join太多张表,像成员名称这种可以通过单独的字典查询缓存处理;三是导出功能如果是Excel导出,不要用前端导出大列表,后端异步生成文件再提供下载链接,否则接口容易超时。

6.5 二次开发的扩展点:这个项目还能往哪些方向延伸

如果你不满足于课设完成,可以尝试加两个功能:消息通知模块,在审核状态变化时自动生成消息推送给项目负责人;数据看板,用ECharts展示各学院立项数量、项目类型分布、经费规模趋势。技术层面可以试试把MyBatis替换成MyBatis-Plus简化CRUD,或者把Vue2升级到Vue3加TypeScript。这些都是很好的加分项,而且不会影响原有核心结构。

我在实际做这类项目的过程中,最大的体会是:状态机设计是全局最关键的环节,数据库建表前一定要先花半天把业务角色和状态流转画清楚,这个环节省下来的时间,后面会在改表结构时十倍还回去。另外,前端虽然看着代码多,但真正决定系统质量的是接口规范和后端的数据结构设计。先把用户、项目、审核记录这三张核心表设计到能应对所有查询场景,后面的开发就会顺很多。

最后分享一个小技巧:项目跑通后,一定要把业务数据真实地走一遍全流程,从学生注册、项目申报、导师审核、学院评审、立项、中期检查到结题,每个状态都实际点一遍,你会发现很多理论上顺畅的环节在实际操作中就是会有问题。这套流程走完,你对这个系统的理解深度,和只写代码跑通接口完全不是一个层次。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询