☰
SpringBoot+Vue失物招领系统毕设全解析:设计与实现
2026/10/1 16:24:58 网站建设 项目流程

每年到这个时间段,私信里问得最多的就是“SpringBoot+Vue的毕设项目怎么做”“有没有完整的源码参考”,尤其是失物招领这种题目,看起来简单,真要动手写的时候才发现坑不少。前阵子刚好把校园失物招领系统完整梳理了一遍,从需求、数据库设计到前后端实现都重新过了一遍。这篇就把整个项目的设计思路、核心实现和实操过程完整拆开讲,给正在做类似题目的同学一条可以直接落地的路线。无论你是想用来交毕设,还是单纯想练手全栈开发,这个项目的体量和技术栈都非常合适:框架不冷门,功能不复杂,但足够展示CRUD、权限、文件上传、状态流转这些基本功。我尽量把每一步为什么这么做也讲清楚,而不是只丢一堆代码。

1. 先从需求说起:校园失物招领到底该做哪些事

1.1 场景痛点与功能边界

校园里丢东西太常见了。一卡通、耳机、雨伞、课本,几乎每天都在失物群和朋友圈里刷屏。但传统招领方式效率很低:失物信息分散在各院系群里,没有统一格式,认领时需要人工核对身份,时间一长很多失物就变成了无人认领的“孤儿”。

所以这个系统要解决的,本质上是三个问题:信息聚合、精准匹配、可信认领。信息聚合是指所有丢失和拾获信息集中在一个平台上;精准匹配是让失主能通过关键词、地点、时间快速找到自己的物品;可信认领则需要一个身份验证和状态流转机制,避免被人冒领或重复认领。

功能边界也要明确。我做这个项目时没有贪大,核心就两条主线:用户端负责发布和认领,管理端负责审核和数据维护。至于站内私信、消息推送这种锦上添花的功能,时间充裕可以加,时间紧张就砍掉,因为论文里的逻辑自洽比功能数量更重要。

1.2 两类核心角色和用户故事

系统角色不搞复杂,就两种:普通用户和管理员。普通用户登录后可以发布丢失物品、发布拾获物品、浏览信息列表、发起认领申请;管理员负责审核信息是否真实、处理认领申请、管理用户和统计失物数据。

用户故事写清楚之后,接口设计就顺了。比如“作为一个丢了一卡通的学生,我希望发布丢失信息时能上传图片和丢失地点,这样捡到的人能快速识别。”对应后端就是一个失物信息表加一个文件上传接口。“作为管理员,我希望看到失主提交的认领凭证,避免有人乱领。”对应的是认领申请带上详细描述和证明材料。

我在设计时特意把“认领”拆成申请和确认两步,而不是让捡到的人直接标记“已归还”。原因很简单:毕设答辩时老师大概率会问“如何保证认领真实性”,两步确认配合管理员的线下核验,就是最直接的答案。

1.3 功能模块清单

整理后的功能模块大致如下:

  • 用户端:注册登录、个人信息维护、发布丢失信息、发布拾获信息、失物/招领列表、关键词搜索、认领申请、我的发布记录、我的认领记录。
  • 管理端:登录、失物/招领信息审核、认领申请处理、用户管理、数据统计看板。
  • 公共功能:验证码、图片上传、分页搜索、状态自动流转。

不需要再做更多的功能扩展了。这个体量对毕设来说,代码量足够,论文工作量也足够,更重要的是你能够在两周内写完并且每一行代码都讲得清楚。把精力花在把现有模块做细,比堆砌一堆没打磨的功能要明智得多。

2. 技术选型:为什么是SpringBoot+Vue这对组合

2.1 后端选型的考量

选题时我看过不少技术方案,有人用SSH,有人用JSP,还有人直接Servlet手写。但最后几乎清一色推荐SpringBoot,原因很实际:SpringBoot让SSM时代的各种XML配置彻底消失,内嵌Tomcat意味着部署时不用单独装容器,一个jar包就能跑起来。对毕业设计来说,这意味着你写的每一行配置都是有意义的,而不是在复制粘贴看不懂的XML。

持久层我选的是MyBatis-Plus而非原生MyBatis。虽然很多老教程还在用MyBatis,但MyBatis-Plus内置了分页插件、逻辑删除、代码生成器,写单表CRUD基本不用手写SQL。毕设项目里80%的操作是单表查询,直接用BaseMapper现成方法省下的时间,足够你把认领审核逻辑写得更完善。

数据库用MySQL,没有悬念。版本最好别太老,MySQL 8.0以上配合配套驱动。字符集设置utf8mb4这一点尤其重要,因为用户发的失物描述里可能带表情符号,utf8mb3存不下会报错。这个坑我在第一次开发时就踩过,后面会专门说。

2.2 前端为什么选Vue而不是传统模板

我记得之前在SpringBoot项目里面直接用Thymeleaf做过一个页面,做到后面很难受:每个页面都要写整套HTML,按钮点击事件靠jQuery选择器去绑,数据一变化要手动操作DOM。页面少还能忍,一旦失物列表、详情、后台管理页加起来超过十几个,维护成本就会失控。

换成Vue之后,数据和视图是绑定的,列表重新渲染只需要改data数组,不用再碰HTML。配合Vue Router做页面跳转、Axios做HTTP请求、Element-UI做组件,一套后台管理系统和用户端页面搭建起来很快。而且Vue是当前前端岗位需求量最大的框架之一,写进简历里是不错的经验点。

不过这里有个建议:如果项目用的是Vue 2,就老老实实配Element-UI。如果选Vue 3,则配Element-Plus。千万别在Vue 3项目里装Element-UI,版本不兼容,崩起来很难查。我自己刚开始就把这两者搞混过一次,项目直接白屏,控制台刷了一堆Unknown custom element的报错。

2.3 认证与权限方案的选择

校园失物招领系统的用户权限很简单,不需要使用复杂的Spring Security。我用的是JWT加拦截器的方式:用户登录成功后,后端生成一个Token返回给前端;前端后续请求放在请求头里面;后端写一个拦截器校验Token有效性。管理员接口则多校验一次用户角色字段。

选择JWT而不是传统Session,主要有两个考虑:前后端分离架构下,Session依赖Cookie和服务器存储,跨域场景不友好;JWT是无状态的,后端不需要保存会话信息,扩展性更好。同时,写这个方案的过程本身就能在论文里单独成节,答辩时把JWT结构、校验逻辑讲清楚,是一个很好的加分点。

JWT的密钥不能写死在代码里,我放在application.yml配置中,后续通过自定义注解加拦截器做权限控制。用户表里加一个role字段,0代表普通用户,1代表管理员,简单直接。

3. 数据库设计与表结构

3.1 失物信息表

失物信息是整个系统的核心数据,我建的表叫lost_item。字段包括:id、用户id、物品名称、物品描述、物品图片、发生地点(丢失或拾获地点)、联系电话、发布时间、物品状态。为了后续搜索方便,还加了一个type字段,1表示丢失,0表示拾获。

物品状态这一列是重点。我设计的状态值有:0待审核、1待认领、2认领中、3已归还、4无人认领。流程是这样的:普通用户发布信息后默认待审核;管理员审核通过变为待认领;有用户提交认领申请后变为认领中;管理员确认归还后变为已归还;超过一段时间无人认领则标记为无人认领。

采用整型存状态而不是字符串,有两个好处:一是数据冗余小,二是代码里可以用常量类定义,避免拼写错误。类似的枚举值在毕设论文的数据字典部分还能直接列成表格,这属于“论述充分性”上的加分操作。

3.2 用户表与角色设计

用户表user字段不多:id、用户名、密码、昵称、联系方式、角色、创建时间。密码使用BCrypt加密存储,不能存明文。这一点在答辩中是高频问题,老师基本都会问“用户密码是怎么保存的”,如果你回答“MD5加密”,他会继续追问“MD5可逆吗”“为什么要加盐”。所以我在这个项目里直接选了Spring Security里常用的BCryptPasswordEncoder,虽然是单独依赖,但安全性说得清楚。

角色字段用int类型,0普通用户,1管理员。没有建角色表和权限表,因为这个系统的权限维度就两级,建三张关联表反而显得有些刻意。如果老师追问权限扩展性,可以解释:RBAC适合多角色多权限场景,这里两级权限用字段区分更直接。

3.3 认领记录与审核状态流转

认领记录表claim_record是我单独拆出来的一张表,字段包括:id、失物信息id、认领人id、认领描述、证明材料、联系电话、状态、申请时间、处理时间。状态有:0待处理、1已通过、2已拒绝。

很多类似的毕设项目会把认领操作直接做成修改失物信息表的状态,但没有认领记录表。这会导致一个麻烦:老师问“你怎么追溯谁在什么时候认领过?”你没有数据可展示。把认领记录独立成表之后,每个失物被谁申请过、最后怎么处理的都有痕迹,这在演示环节非常有说服力。

状态流转我放在后端Service里统一控制:用户提交认领时,先检查失物信息是否处于待认领状态;管理员处理申请时,要同时更新认领记录的状态和失物信息的状态。为了保证这两步的一致性问题,我在@Service里加了@Transactional事务注解,任何一部异常都会整体回滚。

4. 后端核心实现过程

4.1 项目初始化与分层结构

后端项目我按常规Maven结构创建,包名建议用com.campus.lost这类简洁的命名。包里分层清晰一些:controller、service、mapper、entity、common、config。用MyBatis-Plus的代码生成器或者手动写实体类都行,关键是字段命名要规范,比如数据库字段用下划线,实体类用驼峰,并开启MyBatis-Plus的下划线转驼峰配置。

Controller层只负责接收参数和返回统一结果,具体逻辑全部下沉到Service层。这里要强调一个习惯:接口返回值不要直接返回裸数据,而是统一封装成R对象,里面放code、msg、data三个字段。这样前端Axios拦截器就能统一判断接口是否成功,不用每次单独处理。这个封装也是论文里可以单独展示的一个亮点。

public class R<T> { private Integer code; private String msg; private T data; // 略去 getter/setter public static <T> R<T> ok(T data) { R<T> r = new R<>(); r.setCode(200); r.setMsg("success"); r.setData(data); return r; } public static <T> R<T> fail(String msg) { R<T> r = new R<>(); r.setCode(500); r.setMsg(msg); return r; } }

分层细致还有另一个好处:写论文架构设计那章时,你可以直接画一张分层图,从Controller到Service到Mapper,配合文字说明每层的职责。工作量几乎没增加,但整个论文的专业度会提升一个档次。

4.2 发布失物、招领信息的接口设计

发布信息接口我用POST /api/lostItem,接收参数为物品名称、描述、图片URL、类型、地点、联系电话。接口不接文件本身,而是接前端上传后返回的URL。这样设计是因为图片上传通常是独立的文件服务操作,把上传和业务解耦后,接口职责更单一。

对应的Service流程是:先校验参数是否完整,再把用户ID从JWT解析出来塞入实体,状态默认置为0(待审核),然后调用MyBatis-Plus的insert方法。这里有个容易被忽略的细节:物品图片字段我允许为空,但前台页面上要做好兜底,没有图片就显示默认占位图,否则前端会裂图一片。

@PostMapping("/api/lostItem") public R<Long> publish(@RequestBody LostItemDTO dto, @RequestAttribute Long userId) { if (StringUtils.isBlank(dto.getName()) || StringUtils.isBlank(dto.getLocation())) { return R.fail("物品名称和地点不能为空"); } LostItem item = new LostItem(); BeanUtils.copyProperties(dto, item); item.setUserId(userId); item.setStatus(LostItemStatus.PENDING_REVIEW); lostItemService.save(item); return R.ok(item.getId()); }

4.3 认领流程与状态控制

认领流程是这个项目里最值得多花时间讲的部分。用户发起认领时,后端要做三步校验:认领的信息是否存在,信息是否处于待认领状态,认领人是否就是发布者本人。第三步很关键,否则就会出现“自己捡到自己的东西然后自己申请认领”这种尴尬操作,答辩时被老师发现你连这种情况都没拦住,体验会很差。

校验通过后,插入认领记录,同时把失物信息状态从待认领改成认领中。管理员进入后台看到申请后,根据认领人填写的描述和证明材料判断是否通过。需要注意:管理员只能处理待处理状态的认领申请,如果已经处理,第二次点击按钮就要提示“该申请已处理”,防止脏数据。

@Transactional public boolean claim(Long itemId, Long currentUserId, ClaimDTO dto) { LostItem item = lostItemMapper.selectById(itemId); if (item == null || !item.getStatus().equals(LostItemStatus.WAITING)) { throw new ServiceException("该失物当前不可认领"); } if (item.getUserId().equals(currentUserId)) { throw new ServiceException("不能认领自己发布的信息"); } ClaimRecord record = new ClaimRecord(); record.setLostItemId(itemId); record.setClaimUserId(currentUserId); record.setStatus(ClaimStatus.PENDING); claimRecordMapper.insert(record); item.setStatus(LostItemStatus.CLAIMING); lostItemMapper.updateById(item); return true; }

这里我用了一个自定义的ServiceException,配合全局异常处理器统一返回错误信息。千万不要在Controller里try-catch后就吞掉异常,否则前端只能看到“系统错误”四个字,用户根本不知道哪里操作错了。

4.4 图片上传与静态资源映射

图片上传模块,我用的是SpringBoot原生MultipartFile上传,没有额外引入OSS等云存储。原因很务实:毕设一般不需要企业级的对象存储,本地磁盘存储加上虚拟路径映射已经足够。将上传路径配置为file.upload-dir,应用启动时创建目录,上传成功后返回一个/upload/xxx.jpg的访问URL。

访问URL如何映射到磁盘目录,需要在配置类中增加一个WebMvcConfigurer,把/upload/**映射到实际磁盘路径。如果不做这一步,前端上传后拿到的图片URL是访问不到的,会一直404。

file: upload-dir: D:/lost-and-found/upload
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/upload/**") .addResourceLocations("file:D:/lost-and-found/upload/"); } }

需要注意Windows和Linux路径分隔符差异。我当时的开发机是Windows,部署到Linux服务器时,发现斜杠路径必须要调整,否则图片上传报目录不存在。后来统一用Paths.get(uploadDir).toAbsolutePath().toString()去拼路径,才彻底解决。

5. 前端Vue实现要点

5.1 页面结构与路由划分

前端我用Vue CLI创建项目,安装vue-router、axios、element-ui。页面结构分为两个大区:用户端路由在根路径下,包括首页、列表页、详情页、发布页、我的页面;管理后台单独挂在/admin路由下,通过一级路由嵌套实现两套布局。

用户端布局我用了Element-UI的Container组件,分为上中下三块:顶部导航放Logo、搜索框和用户菜单;中间是路由出口;底部展示版权信息。管理后台则是另一个布局,左侧菜单、右侧内容区、顶部面包屑。

路由守卫这里注意一下:进入发布页面和管理后台之前都要判断Token是否存在,不存在就跳转到登录页。Vue Router的beforeEach钩子正好做这件事,我单独写了一个permission.js文件来放路由守卫逻辑,给前端项目的结构也留了清晰的模块边界。

5.2 列表页与筛选条件

列表页是整个系统使用频率最高的页面,核心就是“搜索加分页”。搜索条件包括关键词、类型(丢失/拾获)、地点、时间范围。前端使用Element-UI的Form组件搭了一个筛选区域,点击搜索按钮后重新拉取列表数据。

拉数据我用Axios的GET请求,参数通过params传递。后端用MyBatis-Plus的LambdaQueryWrapper动态拼装查询条件:关键词对物品名称和描述做模糊匹配,类型和时间分别做精确匹配和范围匹配。这样前端筛选条件再多,后端都只用一个方法就能完成。

前端切记要用v-loading给列表加加载状态,不然用户点搜索后页面没有任何反馈,会以为按钮失效。另外分页组件要接上current-change和size-change事件,页码变化后重新请求接口,同时把列表滚动到顶部。这些细节做完,用户体验会明显好一个档次。

5.3 表单校验与图片上传组件

发布信息页的表单有三个核心校验:物品名称必填、类型必选、地点必填。描述长度控制在500字以内,联系电话使用正则校验。Element-UI的Form组件自带rules校验规则,配合validate方法基本不需要自己写判断逻辑。

图片上传我封装了一个UploadImg组件,内部用Element-UI的upload组件,上传到后端接口,并设置headers携带Token。Element-UI默认的上传地址是字符串,如果直接绑定接口地址,会发现Token根本带不上去,因为字符串方式无法自定义请求头。正确的做法是使用:http-request自定义上传方法,或者通过before-upload钩子手动添加请求头。

handleUpload({ file }) { const formData = new FormData() formData.append('file', file) axios.post('/api/upload', formData, { headers: { 'Content-Type': 'multipart/form-data', 'token': getToken() } }).then(res => { this.form.imageUrl = res.data.data }) }

上传成功后把返回的URL赋值给隐藏字段,最后随表单一起提交。提交按钮要加:loading状态,防止用户二次重复提交。我见过不少项目没做这个防护,用户手一抖点了两次,数据库里就多了两条一样的失物信息,还得靠管理员手工清理。

5.4 管理后台的表格页

管理后台我用了Element-UI的Table组件来展示失物信息和认领记录。表格列不需要展示全部字段,比如物品描述太长了,就在表格里用tooltip截断显示,详情通过弹窗完整展示。管理员的审核操作直接在表格行内放按钮:审核通过、审核拒绝、查看详情。

后台的审核接口跟前端按钮的交互要注意一个隐藏问题:操作成功的提示和列表刷新。我建议在Mutation或方法里先调用接口,成功后再重新请求列表数据,而不是直接修改当前行数据。因为后端状态变更后可能还有其他联动更新(比如失物状态从待审核变成待认领),重新拉一次列表最稳妥。

数据统计看板我放了三张卡片:总失物数、待处理申请数、已归还数。后端分别提供三个统计接口,前端用三个数字卡片展示。简单直接,但演示效果很好,老师看一眼就知道系统有“数据可视化”层面的设计。

6. 从零跑通项目的完整步骤

6.1 环境准备与版本坑

我在配置环境时踩过一个印象很深的版本坑:SpringBoot版本和JDK版本一定要匹配。比如SpringBoot 2.x对应JDK 8或11,如果本机装了JDK 17,部分老版本项目启动会报IllegalArgumentException: Unsupported class file major version。我当时搞了半小时才反应过来是JDK版本太高,后来统一在pom里指定Java版本,问题才消失。

前端环境上,Node.js建议用14以上的稳定版。Vue CLI初始化项目时如果报npm权限错误或网络超时,多半是npm镜像源问题,换国内镜像源基本能解决。这里我没有使用任何特殊工具,就是正常的Node和npm配置。

数据库用Navicat或者命令行建库都行,关键初始化SQL脚本要准备好。脚本里除了建表语句,我还会插入一个默认管理员账号:用户名admin,密码admin123,密码字段用BCrypt加密后的值。这样后端和前端部署完成后,可以直接用管理员账号登录后台进行演示。

6.2 数据库初始化和配置

新建数据库lost_found,字符集选择utf8mb4,排序规则utf8mb4_general_ci。然后执行初始化SQL,依次创建user、lost_item、claim_record三张表。注意建表时给常用的查询字段加索引,比如lost_item表的状态字段、类型字段和发布时间字段。数据量小的时候感受不到索引重要性,但答辩时被问到“系统数据量大了怎么办”,索引是默认答案。

application.yml配置文件里,数据库连接信息改成你本机的地址、用户名和密码。MyBatis-Plus的逻辑删除配置局部打开即可:如果不想物理删除数据,可以在实体类加@TableLogic注解,这样删除操作自动变成更新逻辑删除字段。对失物信息这种有“已归还”等历史记录的场景,逻辑删除比物理删除更合理。

JWT的密钥配置在jwt.secret,同时设置合理的过期时间,比如7天。前端每次请求时,Axios拦截器会从localStorage拿Token,放到请求头里。后端校验Token时如果过期,返回401状态码,前端统一跳转登录页。

6.3 启动后端与前端联调

后端启动前,先确认8080端口没有被占用。前端项目默认端口8080经常和后端冲突,所以在vue.config.js里把前端端口改成8081,并配置proxy代理,把所有/api前缀的请求转发到http://localhost:8080。这样前端代码里的请求地址可以直接写/api/lostItem,不用在每一处写死localhost和端口,联调时也不会有跨域问题。

实际上,如果用了代理,开发阶段几乎不会出现CORS错误。但如果你坚持直接访问后端地址,就必须在后端写一个CorsFilter来允许跨域请求。我用代理的方式,前后端配置更清晰一些。联调的时候,先访问前端页面注册一个用户,再发布一条测试失物信息,然后去数据库里查一下是否新增成功,能走通这一条链路,整个项目就算通了。

6.4 打包部署的两种方式

第一种是前后端分离独立部署:后端用Maven打包成jar,java -jar运行;前端npm run build生成dist目录,用Nginx托管,并将/api路径反向代理到后端端口。这种方式更贴近真实项目,但步骤略多,容易在Nginx配置上卡住。

第二种是合并部署:把前端dist目录直接复制到SpringBoot的src/main/resources/static下,重新打包成一个jar。这样只需要跑一个jar,访问http://localhost:8080就能看到整个系统。对毕设演示来说,第二种方式省心很多,我最终交上去的运行包就是这种合并模式。

我不建议在答辩的时候现场演示打包过程,太容易翻车。比较稳的做法是提前打包好一个可运行jar,放到一个新建的干净目录下运行,展示时直接启动就行。同时把源码和SQL脚本放在另一个文件夹,方便老师当场检查。

7. 毕设答辩常被追问的问题

7.1 为什么用JWT不用Session?

这个问题几乎必问。回答时抓住两点说:无状态和跨域友好。Session需要服务端存储会话信息,在集群部署时会话同步是个麻烦事;JWT直接把用户身份信息加密放进Token里,后端只需验签,不需要保存状态,适合前后端分离架构。同时主动补充一下JWT由三部分组成:Header、Payload、Signature,验签时用密钥验证数据有没有被篡改。能说到这个层面,基本不会被难倒。

7.2 如何防止重复认领?

答案藏在状态字段和事务控制里。用户发起认领时,系统先检查失物信息的状态,只有待认领状态才能发起申请;申请成功后立刻把状态变为认领中。假设两个用户同时提交认领,在没有并发控制的情况下,确实有可能都通过校验。但毕设答辩时你先说清楚这个并发场景,再补充可以用数据库行锁或乐观锁来解决,就已经达到区分度了。我在实际代码里用了事务加状态判断,展示项目时也会主动提“极端并发下还需引入锁机制”,反而显得思考更全面。

7.3 模糊搜索怎么做的?

后端使用MyBatis-Plus的like方法,对物品名称和描述字段做模糊匹配。前端通过关键词输入框触发搜索,后端用LambdaQueryWrapper将其拼进SQL查询。回答时还可以说一句:如果将来要支持更复杂的搜索引擎,可以使用全文检索。但不需要为了答辩去写ES,那只会给自己挖坑。

7.4 密码加密的原理?

我使用BCrypt算法。它是不可逆的哈希算法,同一次密码每次加密的盐值不同,所以即使两个用户密码相同,存储的密文也不一样。判断密码时调用BCrypt的matches方法。答辩时不要试图手推算法细节,重点是能够解释为什么比普通MD5安全,以及密码为什么不能明文入库。

8. 常见问题与排查实录

8.1 前端请求跨域报错

开发阶段在浏览器看到CORS报错,大概率是没有使用代理或者代理配置没生效。先检查vue.config.js中proxy是否配置了/api前缀,再检查后端请求路径是否以/api开头。如果用了代理仍然报错,记得清一下浏览器缓存,开发环境有时会把旧的预检请求缓存住。

8.2 图片上传后403无法访问

403通常不是业务问题,而是Spring Security或Shiro拦截了静态资源。如果项目里引入了安全框架,需要配置/upload/**和某些静态路径为放行资源。如果你的项目只有JWT拦截器,也要检查拦截器排除列表里有没有放行/upload/**。我最初就吃过这个亏:上传成功了,但读取图片URL时被拦截器拦住了,整个页面图片全部显示不出来,排查了半天才反应过来。

8.3 MyBatis-Plus分页总少了数据

原因是分页插件没有配置。MyBatis-Plus的分页需要单独注册PaginationInnerInterceptor,不是光引入依赖就能自动生效的。很多教程里只提了依赖,没有提这个配置类,结果分页方法只返回当前页数据但total始终是0,或者第二页开始查不到数据。注册拦截器之后,分页查询的count语句才会自动生成。

8.4 发布信息时IDEA报字段找不到

报错信息经常是“Property ‘userId’ not found”之类的,原因很可能是实体类字段与数据库列名没有对应。检查一下数据库列名是user_id,实体类字段是userId,并且全局配置里开启了驼峰转换。如果用了MyBatis的注解方式,记得在字段上写@TableField。这个问题虽然低级,但确实是我在带别人跑项目时遇到次数最多的。

最后再分享一个实际经验

这个项目前后我完整写过两遍,第一遍照着一堆零散教程东拼西凑,数据库字段前后对不上,前端页面互相跳错路由,光是调试就花了快一个星期。第二遍重新梳理需求之后,我才发现一个道理:毕设项目不是一个功能越多越好的工程,而是一条每个环节都要对得上号的流水线。先画清楚数据表之间的关联,再定接口,再写页面,顺序一旦对了,做起来非常顺。

如果你正在做类似题目,建议也能从失物信息表、用户表、认领记录表这三张表出发,先把状态流转想明白了再动手。写完之后把整个项目从零启动到演示完整跑一遍,特别是把管理员审核、用户认领、确认归还这条主流程走通。这样到了答辩的时候,你心里会非常踏实。整个项目做下来,你会对SpringBoot的后端分层、Vue的前后端交互、JWT认证、数据库设计有非常完整的认知,这些积累比单单一套源码值钱得多。

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

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

立即咨询