SpringBoot+Vue文物征集管理系统:从需求到部署的完整实践
一个“文物征集管理系统”听起来好像很小众但放在毕设和课设的背景下这其实是一个非常经典、非常聪明的选题。它表面上是一个面向“红色革命文物”的业务管理系统实际上内核是一个标准的信息管理平台有用户权限、有业务流程流转、有文件上传、有数据统计难度适中业务故事也好讲。很多同学拿到类似的源码要么只会对着教程跑起来要么不知道怎么在答辩时讲清楚更别说万一遇到问题如何排查。这篇文章我就以这套 SpringBoot Vue 的 MVC 模式管理系统为例从头到尾拆一遍它解决什么问题、技术架构怎么选、核心代码怎么写、数据库怎么建、怎么从零跑起来以及我在实际调试中踩过的一些坑。先说结论这套东西你把它吃透了不只是完成一个毕设而是真正理解了企业级前后端分离开发的基本套路。1. 需求先想清楚再动手这个系统到底要管什么很多同学拿到项目第一件事就是打开 IDEA 开始跑代码其实这是比较低效的做法。先搞清楚业务再看代码事半功倍。1.1 别被“文物征集”四个字劝退拆解核心业务红色革命文物征集系统的核心业务说白了就是一件事把散落在民间的文物线索和实物征集信息系统化地管起来。传统的线下流程是发布征集公告 - 群众来电来信提供线索 - 工作人员登记纸质信息 - 专家鉴定审核 - 入库登记 - 建立台账。这个过程里问题很多纸质表格容易丢、想查一条记录翻半天档案柜、审核进度谁也不知道、统计本月征集了多少文物全靠人工数。而管理系统要做的就是把这条链路搬到线上。我建议你把整个系统抽象成一条“征集业务线”所有功能都围绕这条线展开线索登记群众或者征集员录入文物基本信息名称、年代、类别、来源、保存现状、征集方式等。材料附件上传文物照片、相关证明文件。审核流转管理员或者专家对征集信息进行审核可能通过、可能退回补充材料。入库登记审核通过后文物正式进入馆藏台账生成唯一编号。统计展示按年代、类别、征集状态等维度做统计让管理者掌握征集进度。理解了这条线你再看代码里的实体类、数据库表、接口设计就会觉得“原来如此”而不是“这是什么鬼”。1.2 功能模块划分与权限设计系统里不是所有人都能干所有事的这就是权限设计的由来。一个完整的征集管理系统至少要考虑三类角色系统管理员拥有全部权限包括用户管理、数据字典维护、审核管理、统计查看。征集员/录入员可以新增征集信息、录入文物资料、维护自己创建的记录。专家/审核员主要负责审核征集线索和文物信息给出审核意见。有些系统里还会把“普通社会公众”角色放进来用于在线提交征集线索这就是另一个典型的业务场景了。模块和权限的合理划分是你答辩时可以重点讲的一个亮点。比如“为什么同一个登录接口要返回不同的菜单权限”“为什么征集的文物信息要用状态字段而不是直接删除”这些都是体现你对系统思考深度的点。权限设计做得好这个系统的框架感就出来了后面加功能也只是在模块里堆接口而已。2. 技术选型解析SpringBoot Vue MVC 这个组合为什么“稳”选技术栈不要追求新奇要追求“能跑、好讲、有问题能搜到答案”。SpringBoot Vue 这个组合可以说是当下Java Web前后端分离项目的“标准答案”。2.1 后端SpringBoot 到底帮我们省了哪些事SpringBoot 是一个建立在 Spring 框架之上的快速开发脚手架。没有它的时候你要配置 SpringMVC、配置 Tomcat、配置 MyBatis 的 SqlSessionFactory、写一大堆 XML。有了 SpringBoot 之后很多配置都变成了“约定大于配置”你只需要引入依赖写上application.yml就能快速启动一个 Web 服务。在这套系统里SpringBoot 的核心作用有几个内嵌 Tomcat打包成 jar直接java -jar就能启动不用单独装 Tomcat 服务器。Starter 机制引入spring-boot-starter-web就完成了 Web 环境搭建引入mybatis-plus-boot-starter就有了数据库操作能力。统一配置数据库连接、文件上传大小、端口号等都在application.yml里管理改配置不用重编译。还有一个很实用的点是SpringBoot 项目现在几乎都配套 MyBatis-Plus 使用。它帮你封装了单表的增删改查不需要写基础的 SQL。比如你要按 ID 查一条文物信息只需要CulturalRelic relic culturalRelicMapper.selectById(id);连 SQL 都不用写。对于这类业务相对标准化的管理系统来说MyBatis-Plus 能减少大量低级重复劳动你只需要把心思放在业务流程上。2.2 MVC 三层架构在前后端分离项目里怎么落地项目标题里有一个词“MVC模式”这个是答辩的时候老师几乎必问的。MVC 不是前后端分离时代的专用概念但它依然适用于这种架构。我们来说清楚它在前后端分离里分别对应什么。后端里的严格分层是这样的Controller 层表现层只负责接收前端请求、解析参数、调用 Service、封装返回结果。它不写业务逻辑也不直接操作数据库。一个干净的 Controller 方法大概长这样RestController RequestMapping(/api/relic) public class CulturalRelicController { Resource private CulturalRelicService relicService; PostMapping(/add) public Result add(RequestBody CulturalRelicDTO dto) { return Result.success(relicService.addRelic(dto)); } }Service 层业务逻辑层这是整个系统的核心负责处理业务流程、做事务控制、调用数据层接口。判断状态、校验参数、组织数据都在这一层完成。Mapper/DAO 层数据访问层跟数据库打交道。MyBatis-Plus 的 Mapper 接口继承BaseMapperT后就自动拥有单表的 CRUD 能力你需要关注的就是那些自定义的复杂 SQL 和分页查询。至于前端 Vue它本身是一个 MVVM 框架Model-View-ViewModel但这里的“View”只负责渲染和交互并没有承担业务处理和数据库操作的职责。所以整套系统的业务归属是清晰的Vue 管界面SpringBoot 的 Controller 管接口Service 管业务Mapper 管数据。这就是 MVC 思想在后端落地的方式。2.3 数据库与中间件选型数据库用的 MySQL 8.0这是目前最主流的选择。跟这套系统配合你需要注意两点驱动选择连接 URL 里建议写成com.mysql.cj.jdbc.Driver这是 MySQL 8.x 的驱动类老的com.mysql.jdbc.Driver在新版本下会报警告甚至报错。时区问题URL 后面一定要加serverTimezoneAsia/Shanghai否则数据库连接很容易报时区错误。这套系统里基本不需要 Redis、消息队列这类中间件除非你想给它加分比如用 Redis 存登录 token、用 RabbitMQ 做提交征集信息后的异步通知。基础版本MySQL 足够。3. 数据库设计核心表结构这样建才合理数据库设计决定了整个系统代码好不好写。很多同学在建表的时候喜欢一股脑把所有字段堆在一张表里后面做状态流转就各种别扭。这里我直接把核心表拆给你看。3.1 文物征集表业务主表怎么设计这张表是整个系统的核心建议叫cultural_relic字段设计要有业务导向思维。注意名称、类别、年代这种是很多查询条件的来源必须单独设计字段。字段名类型注释idbigint主键IDrelic_namevarchar(100)文物名称relic_categoryvarchar(50)文物类别文件/实物/照片/其他relic_eravarchar(50)所属年代source_typevarchar(20)征集方式捐赠/移交/购买/借展current_ownervarchar(50)当前持有人contact_phonevarchar(20)联系电话descriptiontext文物描述/历史背景说明statustinyint状态0草稿/1待审核/2审核通过/3已入库/4已退回submitter_idbigint提交人IDcreate_timedatetime创建时间update_timedatetime更新时间这里有几个很容易踩的坑一种是“所有字段都用 varchar ”比如描述文本也用 varchar(255)后面存超过 255 字就报错了。描述类字段用text日期用datetime金额用decimal该用什么类型就用什么答辩的时候被问到字段类型选择这也是一个加分点。另一种是遗漏status状态字段。没有状态字段你就无法区分一条记录是“刚登记”还是“已经入库”审核流程的代码根本写不出来。状态字段一定要预留而且建议用tinyint0 到 255 的取值空间足够用十年。3.2 辅助表与状态流转除了主表至少还需要这几张辅助表文物图片表relic_image一张文物对应多张图片。字段就是id、relic_id、image_url、is_primary是否主图。这就是一对多关系的标准建模方式前端展示图片列表时直接WHERE relic_id ?查询即可。审核记录表audit_record记录谁在什么时间审核了哪条文物意见是什么。字段包含id、relic_id、auditor_id、audit_status、audit_comment、audit_time。用户表sys_user账户、密码、姓名、角色、手机号、创建时间。这是数据库层面必须有的“家底”。建好这几张表整个系统的数据流转就顺理成章了。文物征集的状态流转建议用状态机思想来控制而不是随随便便在代码里赋值草稿(0) - 待审核(1) - 审核通过(2) - 已入库(3) \- 已退回(4) - 修改后重新提交 - 待审核(1)这个流转关系画成图贴在论文里也是很有说服力的。4. 后端核心功能实现细节4.1 文物征集登记接口DTO VO 分层不能省后端代码的复杂度往往不是功能有多难而是代码组织得好不好。比如一个“新增征集信息”的接口很多初学者会直接把实体类CulturalRelic作为接收参数PostMapping(/add) public Result add(RequestBody CulturalRelic relic) { ... }这在简单场景下没什么问题但在实际项目中前端传来的字段和后端实体类的字段往往不是完全一致的。比如前端要传一个“拟征集方式”而实体类里根本没有这个字段或者前端会把“图片列表”也一起传过来你总不能指望实体类里包含一个 List。更好的做法是给前端单独定义一个接收对象 DTOData Transfer Object比如CulturalRelicDTOData public class CulturalRelicDTO { private String relicName; private String relicCategory; private String relicEra; private String sourceType; private String currentOwner; private String contactPhone; private String description; private ListString imageUrls; // 图片地址列表 }然后在 Service 层把 DTO 转换成实体类再保存到数据库。同理接口返回给前端的数据最好也用 VOView Object包装不要直接把数据库实体暴露出去。这样做的好处很明显接口字段可控数据库表结构调整不会影响前端联调代码也更规范。答辩时你可以说“这是为了接口层与持久层解耦”这个话一出来档次就上去了。4.2 审核流程事务控制是关键“审核”是征集系统里最核心的业务操作。审核通过一条文物记录意味着两件事同时发生修改cultural_relic表的status为“审核通过”。往audit_record表插入一条审核记录。这两个操作必须同时成功或者同时失败。如果你只改了主表状态插入审核记录时数据库报错了那么就会出现“状态已经变了但没有任何审核记录”的数据不一致问题。解决办法就是加事务Transactional(rollbackFor Exception.class) public Result audit(AuditDTO auditDTO) { // 1. 修改文物状态 CulturalRelic relic culturalRelicMapper.selectById(auditDTO.getRelicId()); relic.setStatus(auditDTO.getAuditStatus()); culturalRelicMapper.updateById(relic); // 2. 插入审核记录 AuditRecord record new AuditRecord(); record.setRelicId(relic.getId()); record.setAuditorId(...); record.setAuditStatus(auditDTO.getAuditStatus()); record.setAuditComment(auditDTO.getAuditComment()); auditRecordMapper.insert(record); return Result.success(); }Transactional就是告诉 Spring这个方法里的所有数据库操作要么都提交要么都回滚。这是 Java 后端开发者必须掌握的基础知识点也是所有业务系统里保护数据一致性的常规手段。4.3 文件图片上传别把文件存进数据库文物征集系统里图片上传是必不可少的功能。这里有一个最常见的新手误区想都不想就把图片转成 Base64 字符串存进数据库或者干脆把图片的二进制数据用blob类型存进去。这个方案在毕设项目里能跑但一旦图片多了数据库体积会膨胀得非常快数据库备份和查询性能都会受拖累。正确的常规做法是文件存磁盘数据库只存文件路径。在 SpringBoot 中上传文件的 Controller 方法可以这样写PostMapping(/upload) public Result upload(RequestParam(file) MultipartFile file) { // 1. 生成唯一文件名防止重名覆盖 String originalFilename file.getOriginalFilename(); // 例如 xxx.jpg String fileSuffix originalFilename.substring(originalFilename.lastIndexOf(.)); String newFileName UUID.randomUUID().toString().replace(-, ) fileSuffix; // 2. 指定存储目录注意目录要先创建 String dirPath D:/upload/relic/; File dir new File(dirPath); if (!dir.exists()) { dir.mkdirs(); } // 3. 保存文件 file.transferTo(new File(dirPath newFileName)); // 4. 返回可访问的 URL 地址 return Result.success(/files/relic/ newFileName); }这里要注意的是第 3 步的transferTo如果报错大概率是目录没有创建权限Linux 下尤为常见。文件存好之后还差一步让 URL 能访问到它。在 SpringBoot 里你需要配置一个静态资源映射把/files/**路径映射到磁盘目录Configuration public class WebMvcConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/files/**) .addResourceLocations(file:D:/upload/); } }这样前端拿到/files/relic/xxx.jpg浏览器直接就能打开图片。4.4 统计报表的 SQL 写法统计分析模块在毕设里很受老师青睐因为它能直接体现“数据是有价值的”。常用的统计有两个维度一是按文物类别统计看看征集到的文物里文件类、实物类、照片类各占多少。SQL 其实非常简单SELECT relic_category AS category, COUNT(*) AS count FROM cultural_relic WHERE status 3 GROUP BY relic_category;二是按年代统计比如解放战争时期、土地革命时期等同样用 GROUP BY 就能完成。这种统计结果传给前端之后配合 ECharts 画饼图、柱状图视觉效果非常好答辩的时候把图一展示比空口说“系统很完善”有用得多。5. 前端 Vue 实现要点5.1 项目初始化与路由设计前端的工程化开发一定要从“创建一个标准项目”开始。Vue 官方推荐的脚手架是 Vite但很多老教程用的是 Vue CLI也就是 webpack 方案。这里我的建议是如果你选 Vue 2用 Vue CLInpm install -g vue/cli然后vue create 项目名。如果你选 Vue 3直接用 Vitenpm create vitelatest 项目名 -- --template vue。无论哪种生成的项目骨架都是标准的 src 结构。路由设计上一个典型的管理系统包含这些页面/login 登录页 /layout 主布局包含侧边栏和顶栏 ├── /dashboard 数据统计首页 ├── /relic/list 文物征集列表 ├── /relic/add 新增征集信息 ├── /relic/detail/:id 文物详情 ├── /audit/list 审核管理 └── /user/list 用户管理管理员可见路由配置要配合权限来做。最简单的做法是登录时后端返回当前用户的角色前端根据角色动态决定渲染哪些菜单和路由。比如“专家”角色就不显示“用户管理”菜单而“管理员”则全部可见。这个功能实现起来不难但非常能体现“系统的完整性”。5.2 列表页与表单页的实操要点列表展示是整个前端最常用的功能。我们可以用 Element UI 的el-table加上el-pagination来做分页。关键点在于前端不要把后端返回的全量数据在内存里做分页应该把当前页码和第页条数传给后端由后端 SQL 分页返回。页面第一次加载时调用后端接口查询第一页数据this.loadData();async loadData() { const res await this.$http.get(/api/relic/list, { params: { pageNum: this.pageNum, pageSize: this.pageSize, relicName: this.searchForm.relicName, status: this.searchForm.status } }); this.tableData res.data.records; this.total res.data.total; }然后每次切换页码、修改搜索条件重新调用loadData()就行。这里有一个“经典坑”很多同学在搜索时把搜索条件里的空字符串也传给后端导致 SQL 里出现WHERE relic_name 的情况。稳妥的做法是在后端接口里对空字符串做一次判断或者用 MyBatis-Plus 的StringUtils.isNotBlank()配合 QueryWrapper 动态拼接条件QueryWrapperCulturalRelic wrapper new QueryWrapper(); if (StringUtils.isNotBlank(relicName)) { wrapper.like(relic_name, relicName); }这样搜索条件为空时就不会拼接 SQL避免了很多隐性问题。5.3 axios 封装与拦截器前端拿不到数据、接口报错很多时候不是后端问题而是 axios 没有封装好。我建议项目一开始就封装一个统一的请求模块给所有接口设置一个 baseURL同时配置请求拦截器和响应拦截器import axios from axios; import { Message } from element-ui; import router from ../router; const request axios.create({ baseURL: /api, timeout: 10000 }); // 请求拦截器附加 token request.interceptors.request.use(config { const token localStorage.getItem(token); if (token) { config.headers[Authorization] token; } return config; }); // 响应拦截器统一处理错误 request.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 { Message.error(网络异常请稍后重试); return Promise.reject(error); } ); export default request;有了这个封装前端每个页面调用接口时只需要关心业务数据不需要每个地方都写错误处理。尤其是登录功能里“token 过期自动跳转登录页”的逻辑在响应拦截器里统一写一次就够了。这个模块如果写好了整个前端工程质量立刻提升一个档次。6. 从源码到跑起来环境准备与部署启动拿到源码之后很多同学卡在最开始的环境搭配上。这里给出一份经过实测的版本组合能少走很多弯路。6.1 后端环境搭配与启动流程推荐这套组合JDK 1.8或者 JDK 11SpringBoot 2.x 都支持Maven 3.6MySQL 8.0SpringBoot 2.7.x不是 3.x3.x 基于 JDK17学生项目没必要追新2.7 的资料最多遇到问题最好搜启动前要做的三件事第一在 MySQL 里创建数据库并导入 SQL 文件。一般源码包里会有一个.sql文件用 Navicat 或者命令行执行mysql -u root -p relic_system.sql执行前看一眼 SQL 文件里的建库语句如果没有CREATE DATABASE那就要自己先在 Navicat 里新建一个数据库再导入。第二修改application.yml里的数据库连接配置。把你的数据库名、用户名、密码改对spring: datasource: url: jdbc:mysql://localhost:3306/relic_system?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8 username: root password: 你自己的密码 driver-class-name: com.mysql.cj.jdbc.Driver这里特别强调useSSLfalse和serverTimezoneAsia/Shanghai。MySQL 8 默认开启了 SSL本地开发不需要不加这个参数可能报SSL connection error时区不配的话数据库连接池初始化就可能直接报错。第三启动项目。在 IDEA 里打开项目等待 Maven 依赖下载完成找到主启动类右键 Run。如果看到类似Tomcat started on port(s): 8080的日志说明后端已经起来了。6.2 前端环境配置与启动流程前端需要安装 Node.js建议版本 14 或者 16。启动步骤npm install npm run servenpm install第一次执行时可能很慢尤其是安装 electron 那类跨平台依赖。常规做法是改 registry 镜像源npm config set registry https://registry.npmmirror.com然后再跑npm install速度会快很多。前端默认端口是 8080后端的端口也是 8080就会冲突。处理方法有两个推荐改前端的 devServer 端口比如改成 8081然后配置代理转发到 8080。Vue CLI 项目在vue.config.js里配置代理module.exports { devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } };或者直接改后端端口为 8080 之外的端口如 9090。就算只用一套系统前端 8081 代理到后端 9090 也是可以的。顺带一提前端发请求时用/api/relic/list这种以/api开头的相对路径代理会帮它转发到后端就不会有跨域问题了。如果你的前端直接写http://localhost:8080/api/relic/list全路径请求那必须让后端开启跨域CrossOrigin否则浏览器会拦截响应。7. 常见问题与排查技巧实录这部分内容真的是你在实际开发和学习过程中大概率会遇到的比看一百遍教程都有用。我把这套系统里高频故障整理成速查表。症状常见原因解决办法后端启动时数据库报 SSL 连接错误连接 URL 缺少useSSLfalse在application.yml的 url 里加上useSSLfalse时区报错The server time zone value连接 URL 缺少serverTimezone加上serverTimezoneAsia/Shanghai前端请求后端接口 404代理没配好或请求路径不对检查vue.config.js的 proxy 配置路径是否以/api开头接口 405 错误请求方式不匹配检查是 POST 还是 GET前后端保持一致请求 401/无权限没带 token或 token 过期看前端请求拦截器有没有附加 token后端是否校验图片上传后访问 404静态资源映射没配置在 WebMvcConfig 里配置/files/**映射到磁盘目录前端页面白屏控制台报错路由或组件引入路径不对检查路由配置和 import 路径有些源码里的路径直接用绝对路径需要改成相对路径npm install非常慢默认源在国外用registry.npmmirror.com镜像MyBatis-Plus 分页查询返回 total 是 0少了分页插件配置检查是否配置了MybatisPlusInterceptor且添加了PaginationInnerInterceptor数据库导入 SQL 报错SQL 文件编码不是 UTF-8用 Navicat 导入时选择 UTF-8 编码或在命令行执行时指定--default-character-setutf87.1 排查问题的通用方法论光有速查表还不够我给你一个通用的排查思路这个方法比任何具体答案都管用。很多同学遇到报错的第一反应就是把报错信息复制粘贴到百度这本身没错但效率太低了。正确顺序是第一步看控制台最底部的 Caused by 信息。Java 的报错信息往往很长真正的原因藏在最下面。比如你在 IDEA 的红色报错信息里往上翻几页找到Caused by: java.sql.SQLException: Access denied for user rootlocalhost (using password: YES)这时候就直接知道是数据库账号密码不对而不是被上面的什么 NullPointerException 带偏。第二步确认错误属于哪个层级。是数据库连接失败还是 SQL 拼写错误还是业务代码空指针还是前端网络请求失败层级判断准确查找范围缩小一半。第三步断点调试。不要觉得断点调试很难。在 IDEA 里打个断点用调试模式启动一步步看代码执行到哪一步出错、某个变量的值是什么十次里有八次能直接揪出问题。这比盲猜变量值高效得多。第四步保留原始日志。排查问题之前先复制完整的日志片段再去查。很多问题单看报错标题判断不出来但结合完整的异常堆栈很容易定位。问别人问题的时候也一定要把完整日志贴出来而不是只说“报错了”。7.2 跨域问题关键是不重蹈覆辙我单独把跨域拎出来说因为这个是前后端分离项目里最容易困扰新人的问题。浏览器有一个同源策略A 网站的 JavaScript 代码默认无法直接访问 B 网站的接口。如果前端跑在http://localhost:8081后端跑在http://localhost:8080端口不同就算域名相同也算跨域。最省事的方案就是上面说的代理转发。前端的所有请求路径都写成相对路径以/api开头由 Vite 或 webpack-dev-server 代理转发到后端。这样浏览器看到的请求就是同源的都在 8081跨域问题不存在。如果确实不走代理要后端开跨域你可以在 SpringBoot 里写一个全局的跨域配置比在每个 Controller 上加CrossOrigin注解更干净Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOrigins(http://localhost:8081) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true); } }需要提醒的是allowedOrigins写死前端地址如果是线上部署用 nginx 反代这句通常却是不需要的有些情况下反而会导致登录的 cookie 带不上。8. 二开扩展让这个系统从“能交”变成“出彩”基础功能跑通只是第一步如果想在答辩时拿高分或者自己在技术上真的有收获一定要尝试做一两个扩展功能。我给你几个方向难度从低到高。第一个方向是接入 JWT 做无状态登录。现在很多管理系统的登录方案还是基于 Session 的但前后端分离环境下更通用的是 JWT。原理是用户登录成功后后端生成一个带签名的 token 返回给前端前端把 token 存在 localStorage 里之后每次请求在请求头带上这个 token。后端用拦截器校验 token 是否有效、是否是当前用户。这个机制不复杂但做完之后你对“登录态”的理解会通透很多。第二个方向是引入对象存储服务。我上面文章里写的图片上传是存本地磁盘这在教学项目里足够。但如果你想让项目更接近生产环境可以考虑把文件上传到云端的对象存储服务比如 MinIO。MinIO 是开源的对象存储方案可以部署在你自己的服务器上文档也比较友好。SpringBoot 整合 MinIO 有对应的 SDK接口两三行代码就能实现上传。这个改造既解决了“文件存在服务器本地”的扩容难题也让你提前接触了企业里常用的文件存储方案。热搜词里还提到了“minio加入到springboot”这正好是一个加分项。第三个方向是引入工作流引擎。比如 Flowable 或者 Activiti把审核流程做成可配置的动态流程。这个难度高但对于“征集审核”“入库审批”这种多环节业务来说确实更贴切。如果你时间充裕可以建议团队里一两个人专门研究这个方向作为进阶功能展示。这几个扩展方向里我个人最推荐第二个方案。理由很简单在你们整个前后端分离的架构里文件存储是不可或缺的一个环节MinIO 的引入不会打断现有代码逻辑又能在答辩时展示你对“生产级文件存储”的认知性价比最高。9. 写在后面做项目最忌讳“跑起来就完事”最后分享一点我自己做这些项目时的心得。很多人把一个项目拉下来之后跑起来截几张图论文一贴就觉得自己完成任务了。实际上等到答辩的时候老师随便问一个“审核状态是怎么流转的”立刻就露馅了。我的建议是你拿到任何系统源码不要急着跑而是先干两件事第一件事用笔在纸上画一遍数据库关系图。不用画得多华丽就画出用户表、文物征集表、审核记录表、图片表之间谁关联谁就能明确这个系统的业务主链路。画完你就能发现原来从这个系统里随便找一个功能点都离不开这几张表的联动。第二件事把其中一个核心功能从头到尾写一遍。不需要完整重写整个系统但你可以试着自己写一个“文物征集信息新增”功能从建表、写实体、写 Mapper、写 Service、写 Controller到前端写一个表单页、调接口、刷新列表。亲手写完这一个闭环你就掌握了前后端分离项目里 80% 的套路。剩下的功能无非是列表查询、状态修改、删除、统计套路都是同一个。这套项目值不值得学关键不在于它的功能有多炫而在于它把 Java Web 后端开发最常用的一整套知识串了起来MVC 分层、ORM 框架、事务管理、文件上传、权限控制、前后端联调、部署启动。你把这个项目吃透自己做毕业设计的时候完全不需要再到处找模板只需要在这个基础上改业务字段、加模块就行——因为骨架已经在你脑子里。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →