☰
SpringBoot+Vue店铺租赁平台毕设全栈实战:从建模到部署
2026/10/10 4:12:06 网站建设 项目流程

每年到毕业季,总有一批同学在Spring Boot + Vue这个技术栈上卡壳——题目定了,数据库不知道怎么设计;表建好了,业务状态流转又理不清;功能做出来了,答辩演示又不知道从哪讲起。我接手过不少这类“店铺租赁租凭平台”的毕设项目,说句掏心窝的话:这个选题本身并不难,难的是你把业务模型想清楚,把代码讲清楚。今天这篇就把一个基于SpringBoot+Vue的店铺租赁平台从选题分析、数据库建模、后端接口设计、前端页面实现到联调部署完整拆开讲,不管是正在做毕设的同学,还是想练手SpringBoot+Vue全栈项目的新手,都能照着往下走。

1. 为什么“店铺租赁平台”是毕设里稳妥又出彩的选题

1.1 选题的技术覆盖面:一张表看清它覆盖了哪些考点

店铺租赁平台这个题目,本质上是一个“带审批流和支付流的综合管理系统”。它跟酒店预订、二手交易平台在业务形态上非常接近,但在毕设场景下更讨巧:实体关系清晰、角色划分明显、状态流转简单却足够拿来讲“业务设计能力”。我把它涉及的技术点拆成一张表,你一看就知道为什么选它:

技术点在项目里的落地位置说明
用户认证与权限控制登录、注册、角色隔离管理员/店铺出租方/承租方三类角色,用拦截器+注解就能实现
核心业务CRUD店铺信息发布、修改、下架、删除多条件筛选和分页查询是高频考点
复杂业务状态流转租赁订单的意向、锁定、签约、终止状态机的实现方式很适合拿来答辩提问
文件上传与存储店铺图片、合同附件上传本地存储或对象存储选一个,写清路径映射
定时任务与提醒租期到期提醒、逾期未付款订单关闭Spring的@Scheduled注解即可,量轻效果好
事务控制与并发同一店铺被多人同时发起租赁用数据库行锁或乐观锁解决,这部分是加分项

这些点单独看都不算新技术,但组合在一个完整项目里,正好踩在毕业设计评分标准的各个档位上:系统功能完整能拿基础分,有事务和并发考虑能拿到良好档,再加个到期提醒和消息通知,就具备了冲优秀的条件。

1.2 业务需求拆解:这个平台到底要管哪些事

做毕设最容易犯的毛病是一上来就写代码,写到一半发现业务模型前后矛盾。正确的做法是先花半天时间把角色和业务流程拉通。店铺租赁平台的业务链条可以这样梳理:

  • 店铺出租方:登录后发布店铺信息,选择位置、面积、租金、租期;查看自己名下店铺收到的租赁意向;同意或拒绝承租方的意向申请;店铺被签约后可以看到合同信息。
  • 承租方 / 租客:浏览店铺列表,按商圈、租金范围、面积筛选;查看店铺详情并收藏;发起租赁意向(提交期望租期和用途说明);确定意向后在线签约。
  • 平台管理员:审核店铺是否允许上架,处理违规内容;管理用户状态(封禁、解封);查看全平台订单数据概览;处理双方纠纷的基础记录。

三个角色之间的核心流转是:出租方发布店铺 → 管理员审核上架 → 承租方浏览并发起意向 → 出租方确认意向 → 等待承租方支付押金和首期租金 → 在线生成租赁合同 → 租期开始 → 到期提醒或续租。这个过程涵盖了“商品发布-审核-撮合-交易-履约”的完整闭环,比单纯做一套增删改查的仓库管理系统不知道高到哪里去了,关键它也没有复杂到让人做不完。

我见过不少同学把目光盯在“地图选店铺”“在线聊天”“电子合同签名”这些花活上,结果基础功能都没跑通。坦白讲,毕设阶段不需要这些。核心业务做成闭环,每一环都能讲出设计意图,就足够你在答辩时从容应对了。

2. 数据库建模:先把业务拆成能落地的表

2.1 核心表结构:七张表撑起整个平台

数据库设计是整个项目的地基,这一部分我在辅导时往往花的时间最长。店铺租赁平台不需要太多表,但每张表的字段设计都必须经得起追问。我按实际项目中的最终版本列出核心表:

第一张是用户表,字段包括主键id、用户名、密码(BCrypt加密存储)、昵称、手机号、角色(1-管理员、2-出租方、3-承租方)、状态(正常/禁用)、创建时间。注意手机号和用户名在创建时要做唯一索引,这是注册接口的防重约束。

第二张是店铺表,字段包括主键id、出租方用户id、店铺名称、店铺地址、所属商圈、面积(平方米)、月租金(元)、押金(元)、租期要求、店铺描述、图片(多个url用分隔符拼接)、审核状态(待审核/已上架/已拒绝/已下架)、出租状态(待租/被锁定/已出租)、浏览量、创建时间。这里把审核状态和出租状态分开成两个字段,目的是避免状态互相污染——一个“已上架”的店铺可以同时是“待租”的,你如果只用一个字段,后面查询逻辑会非常痛苦。

第三张是租赁订单表,也是整个系统的核心。字段包括主键id、订单编号(唯一,业务规则生成)、店铺id、承租方用户id、出租方用户id(冗余存储,方便列表查询)、期望租期开始时间、期望租期结束时间、用途说明、订单状态(意向待确认/已确认待支付/已支付已签约/已拒绝/已取消/已到期/已终止)、支付状态(未支付/部分支付/已支付)、创建时间、更新时间。

第四张是合同表,字段包括主键id、关联订单id、合同编号、起租日期、到期日期、月租金、押金、合同状态(生效中/已到期/已终止)、双方确认状态、签署时间。

第五张是收藏表,字段包括主键id、用户id、店铺id、创建时间,联合唯一索引(用户id,店铺id)防止重复收藏。

第六张是支付流水表,字段包括主键id、订单id、支付单号、支付金额、支付方式(模拟支付/余额支付等)、支付状态、回调时间。毕设一般不做真实支付网关接入,用一个模拟支付接口生成支付记录即可,但要说明真实环境下这里对接微信/支付宝支付通道的逻辑。

第七张是通知消息表,字段包括主键id、接收用户id、消息类型、关联业务id、消息内容、已读状态、创建时间。这个表服务于“意向被确认”“合同已生成”“租期即将到期”这类异步通知。

2.2 订单状态设计:为什么要把意向和签约分开

状态设计是数据库环节最值得讲的一部分。店铺租赁跟买商品完全不同:商品下单即支付,一次到底;而店铺租赁天然是“撮合型”业务,承租方看中店铺只是起点,出租方还要评估承租方的用途是否合适,双方还要谈细节。所以我把订单状态做成一条清晰的线性流:

意向待确认 → 已确认待支付 → 已支付已签约 → 已到期 / 已终止

中间插入两个关键分支:出租方可以直接拒绝意向,此时订单进入“已拒绝”;承租方在支付之前可以主动取消,此时订单进入“已取消”;合同生效后任何一方违约或正常到期,都走向“已终止”或“已到期”。提出这个状态机之后,我通常还会追问一句话:为什么“已确认待支付”还要单独设状态?因为支付动作是异步发生的,而且支付后又会触发合同生成、店铺锁定等一连串操作,如果只用一个状态表达,代码里会出现大量“if状态在某个区间”的判断,很脆。

对应到店铺表,“待租 / 被锁定 / 已出租”这三个出租状态要和订单状态联动。具体规则是:承租方发起租赁意向后,店铺不锁定,因为意向不代表任何约束;出租方确认意向且承租方支付成功后,店铺才置为“被锁定”,因为此时订单已进入合同生成流程,不能再被别人发起新意向;合同签订完成,店铺变为“已出租”。这个细节是很多同学忽略的核心联动逻辑,但恰恰是答辩时最容易出彩的设计亮点。

2.3 字段设计的边界情况:预留扩展不靠乱加字段

数据库设计里还有一个常见毛病:想着“以后可能要用”,于是每个表都塞一堆八竿子打不着的字段。我的原则是能不加就不加,真需要扩展时用统一方案解决。比如店铺图片,一个店铺可能传5张图也可能传20张图,不要在店铺表里搞photo1、photo2、photo3…这种死列,直接用一个分隔符拼接的字符串字段或者一张独立的图片子表。毕设规模用字符串拼接足够了,查询出来split一下就能用;如果考虑到正规商用,再做独立表也不迟。

另外要给关键业务表加一个deleted逻辑删除标记,用MyBatis-Plus的@TableLogic注解,这样“删除”操作变成“更新”,数据不会真丢,对答辩演示也有好处——演示时你点删除,再去数据库一看,记录还在,就能讲清楚“逻辑删除保证运营数据可追溯”这个点。

最后提一个很多人会踩的坑:时间字段统一用datetime,不要用timestamp,更不要拿字符串存。涉及到租期计算、到期判断,在代码里直接LocalDateTime运算比解析字符串省一百倍的心。数据库层面给创建时间建默认值,给更新时间设置自动更新,尽量避免所有写操作都手动set时间,代码里会清爽很多。

3. SpringBoot后端落地:从登录到状态机的实现路径

3.1 角色权限:拦截器加注解的双层设计

店铺租赁平台的三类角色权限划分比较清晰,我建议用一个轻量方案:登录拦截器校验登录态,方法注解标注权限码,再写一个权限校验拦截器做二次过滤。注意登录拦截和权限拦截要区分开——登录拦截管“你是谁”,权限拦截管“你能干什么”,混在一起会很难维护。

先定义权限注解,类似下面这样:

@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RequireRole { String[] value() default {}; }

然后在需要权限控制的接口上加注解,比如管理员审核店铺接口:

@RequireRole({"ADMIN"}) @PostMapping("/shop/audit") public R audit(@RequestBody ShopAuditDTO dto) { // 业务逻辑 }

拦截器里做一个请求前置校验:先检查请求头中的token,解析出当前用户信息放入ThreadLocal;再读取目标方法的@RequireRole注解,判断当前用户角色是否命中;没有命中直接返回403,连Controller都不进。这样权限逻辑全部收敛到一个地方,业务代码里不需要重复写角色判断。

至于登录的产生,推荐用JWT。JWT的实现很简单:用户登录成功后生成一个带用户id、角色和过期时间的token返回前端,前端存到localStorage,后续请求统一加到请求头。毕设项目不用去碰那些复杂的认证框架,但你要能回答清楚:token的无状态性和在服务端拦截校验的必要性,这是答辩提问的高频问题。

3.2 下单、确认、支付的完整业务闭环

上面那张订单状态机图要变成代码,核心是“每一步操作都做状态校验 + 业务联动”。我最常跟同学强调的是:不要每个接口里复制粘贴同样的状态判断,把关键动作封装成订单状态流转方法,Service内部调用。

以一个承租方“发起租赁意向”为例,流程拆开是这样的:

@Override @Transactional(rollbackFor = Exception.class) public Long createLeaseIntent(LeaseIntentDTO dto) { // 1. 校验店铺是否存在且出租状态为待租 Shop shop = shopMapper.selectById(dto.getShopId()); if (shop == null) { throw new BizException("店铺不存在"); } if (!"待租".equals(shop.getRentStatus())) { throw new BizException("该店铺当前不可发起租赁"); } // 2. 校验租期合法性:开始时间必须在当前时间之后 if (dto.getStartTime().isBefore(LocalDateTime.now())) { throw new BizException("租期开始时间不能早于当前时间"); } // 3. 校验店铺出租状态是否被并发修改 // 通过乐观锁版本号判断,见3.3节 // 4. 创建订单,状态为意向待确认 LeaseOrder order = new LeaseOrder(); order.setOrderNo(generateOrderNo()); order.setShopId(dto.getShopId()); order.setTenantId(CurrentUser.getId()); order.setOwnerId(shop.getOwnerId()); order.setStatus("PENDING"); // 5. 通知出租方 noticeService.send(shop.getOwnerId(), "收到新的租赁意向", order.getId()); return order.getId(); }

出租方“确认意向”这一步要反过来校验:订单必须仍然处于意向待确认状态,且操作人必须是当前登录的出租方,防止有人越权操作别人的订单。确认之后订单变为“已确认待支付”,并在支付过期前保留有效期,具体用定时任务去关掉超时未支付的订单。

承租方“支付”这一步是事务的重头戏。我给出的推荐实现是:先根据订单号锁定订单记录,校验状态后同时做四件事——更新订单状态为已支付待签约、更新支付流水表、把店铺出租状态改为被锁定、生成合同草稿记录。四件事必须放在一个事务里,任何一步失败都要整体回滚。用代码表现就是上面那段里加@Transactional,并把涉及订单和店铺的写操作放到同一个事务事务中处理。

3.3 并发安全:用什么方式防止两个人抢同一间店

这个点是大多数毕设里缺失的,但加了之后整个项目档次立刻不一样。店铺租赁不是秒杀系统,没有那么夸张的并发规模,但确实存在“两个承租方几乎同时在列表页看到店铺并同时发起租赁意向”的可能。处理方式有两个档次:

基础版:在“发起租赁意向”时,用Update语句把店铺从待租更新为意向中,更新影响行数为0则说明已被抢占。类似这样:

int rows = shopMapper.updateRentStatusWithVersion(shopId, "待租", "意向中", version); if (rows == 0) { throw new BizException("手速慢了,店铺已被其他人抢先一步"); }

进阶版:在订单表加一个店铺唯一性约束(在途订单的店铺id不能重复),保证同一时间同一店铺最多只有一单在有效流转中。用数据库的唯一约束兜底,代码层面的校验只负责友好提示。两套一起上,业务上基本无懈可击。

我跟同学们讲这个设计时常用一个类比:这就跟两个人同时看上同一间铺子一个道理,房东会先问谁先付定金,谁能证明自己的意向有效,谁才有资格谈下一步。你的代码里如果没有任何并发校验,那等于房东同时把铺子租给了两个人,逻辑上就是事故。这个点写进答辩陈述里,老师一听就知道你不是照抄的项目。

4. Vue前端:页面规划与组件复用

4.1 页面路由与组件划分:先画功能地图再写代码

Vue端的实现我建议先做页面规划,再动手写组件。店铺租赁平台的页面不算多,按角色可以分成三组:公共页面(登录、注册、店铺列表、店铺详情)、承租方页面(我的收藏、发起租赁、我的合同列表)、出租方页面(店铺管理、意向管理、合同管理),再加一个管理员后台(用户管理、店铺审核、数据概览)。这些页面加起来大概十五个左右,对应Vue Router里十五条规则,每条规则对应一个视图组件。

组件的复用重点在于列表和表单。以店铺列表页为例,筛选条件区做成一个ShopFilter组件,店铺卡片做成ShopCard组件,分页条用封装好的Pagination组件。店Details页中的基本信息、图片墙、操作栏拆成子组件后,页面文件里只保留组合逻辑。这样做的直接好处是:出租方管理自己店铺时复用ShopCard,管理员审核时复用ShopCard加一个审核按钮,一处修改,处处生效。

4.2 状态管理:别把数据请求写在组件里散一地

店铺列表的筛选条件、当前页码、排序方式这些数据在刷新后要恢复,租客在前端切换不同筛选条件时需要维护一份统一的查询状态。建议用Pinia(Vue3)或Vuex(Vue2)建一个shopModule,把查询条件、结果列表、加载状态集中管理,组件里只调action。很多同学觉得小项目用不上状态管理,但当你做店铺详情页时发现需要回跳列表并保留筛选条件,没有状态管理就只能用路由参数来回传,非常难受。

Vue3的新项目我统一推荐用Composition Api配合Pinia。接口请求层单独放到src/api目录,按业务模块拆文件,比如shop.js里就是店铺相关接口的axios封装,order.js里就是订单相关接口。这样Controller层的接口路径一目了然,后端接口调整时只需要改api目录里的配置,不用去业务组件里逐个翻。

4.3 表单校验与交互细节:体验感就是这么拉开的

毕设答辩时,老师会真正点击页面上的一些按钮,表单校验的完善程度直接决定他对项目完成度的判断。店铺发布表单建议至少做好四类校验:必填校验(店铺名称、地址、月租金、面积)、格式校验(租金必须为大于0的数字、联系方式手机号格式)、范围校验(面积不应超过合理上限)、业务校验(发布前店铺必须已登录为出租方)。

交互细节方面,我的建议是不要堆动画效果,把精力放在实用反馈上。以店铺审核流程为例:出租方提交店铺后,页面应明确显示“待审核中”,按钮置灰防止重复提交,同时顶栏消息提醒出现一条新的通知;管理员审核通过后,出租方刷新页面能看到状态变化。这些看似不起眼的细节,却是评委判断“系统是否完整可用”最直观的依据。

5. 联调、部署与演示:最容易翻车也最容易被低估的环节

5.1 前后端联调三座大山:跨域、日期格式、拦截器

项目在本地能跑起来,不代表前后端已经联调通过。我几乎每次都会被问到同样的问题:前端调接口报跨域错误,为什么?日期传过去变成一串数字,为什么?登录后访问另一个接口还是401,为什么?

跨域问题解决分两种场景。开发环境我推荐在Vue配置里加代理:把所有以/api开头的请求转发到本机8080端口,这样前端视角下是同源的。生产环境则推荐在后端加统一CORS配置类,用WebMvcConfigurer实现addCorsMappings方法,把允许的域名、请求头、请求方法都配置完整。两个方案不要混用,否则会出现开发环境好端端、打包部署到服务器后请求又裂了的尴尬。

日期格式问题几乎必踩。默认情况下,后端返回LocalDateTime会被序列化成“2024-06-01T10:30:00”,前端展示很难看。推荐在application.yml里配置全局Jackson格式:

spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8

同时在实体类的日期字段上加@JsonFormat注解双保险。前端传日期字符串过来时,后端用@DateTimeFormat注解接收或直接在DTO里用String接,再手动转LocalDateTime,这个写法虽然土但最不容易出错。

拦截器问题通常出在“登录后才能访问”的接口拦截配置上。正确做法是配置拦截器时把登录、注册、店铺列表、店铺详情这些公共接口加进excludePathPatterns,其余接口全部校验。常见错误是只放行了登录接口,结果前端每次刷新页面、每次请求店铺详情都飘token,一飘就401。调试时先打开浏览器F12看Network面板,看是请求没带token还是拦截器拒绝,一次就能定位到是前端还是后端的锅。

5.2 打包部署与演示环境准备

答辩演示如果用自己的电脑,建议提前准备好一套独立的演示环境,避免现场现充数据、现调接口。数据库要准备一套演示专用数据,包含至少三个角色账号、五六家不同状态的店铺(包含已上架、待审核、已出租等)、两三个处在不同流转阶段的订单。演示剧本也要排练两遍,重点演示业务流程闭环:登录 → 浏览店铺 → 发起租赁 → 管理员登录审核 → 出租方登录确认 → 承租方支付签约 → 数据变化可视化。

后端打包建议用Maven的package命令打出jar包,运行命令记在一个txt里,现场直接复用。前端用npm run build生成dist目录,由后端设为静态资源目录统一托管是最省事的方式;如果坚持分开部署,就要检查CORS和静态资源路径,别在答辩现场翻控制台。

提示:演示数据里千万不要留一堆垃圾测试数据,例如“测试店铺123”“asdf”这种名称,会给评委留下非常差的印象。演示数据要模拟真实业务,店铺名称像样、租金数值合理、订单状态完整,这本身就是在展示你对业务的理解。

6. 代码讲解技巧:会写代码还要会讲代码

6.1 按业务主线讲代码:从Controller到Service再到Mapper

很多同学综述自己很熟系统,但被老师一问“这个接口怎么实现”,就只会从头念代码。我的建议是答辩代码讲解按住一条主线讲:用户发起租赁请求后,数据是怎么从前端流到数据库的。这条主线串起来之后,再拆到三层去讲。

以“确认租赁意向”接口为例,你可以这样讲:

  1. 前端点击确认按钮,调用api/order/confirm接口,带上的参数是orderId;
  2. 后端Controller接收请求,先通过当前登录用户的身份信息校验操作权限;
  3. Service层调用validateOrderState方法,检查订单当前状态是否为“意向待确认”;
  4. 校验通过,执行update语句将订单状态更新为“已确认待支付”,同时向承租方发送站内通知;
  5. Mapper只负责两件事:按id查订单、更新订单状态。

这样讲,老师听到的是你理解每一层职责,而不是在背代码。最关键的一步是第3步的状态校验,一定要单独强调——这是业务规则和CRUD的区别所在,也是代码里最值得讲的部分。

6.2 论述亮点:把“自己做的部分”讲出设计重量

可能有些同学项目里参考了网上开源的代码,答辩时最怕被追问。应对方法其实很简单:把每个模块的设计理由理清楚,变成自己的语言。比如我问你“为什么要用逻辑删除而不是物理删除”,你的回答可以是“店铺和订单都是核心业务数据,误删后影响不可逆,逻辑删除保留数据轨迹,后续还能做数据统计分析”;再比如“订单状态为什么要搞这么多状态”,回答“店铺租赁是撮合型业务,意向后需要出租方确认,确认后需要承租方支付,每个节点用户的预期不同,不拆状态会导致用户看不到进度”。能答出这些“为什么”,代码是哪来的已经不重要了,因为你确实理解它。

6.3 文档配合:设计说明书里的三张关键图

毕设文档部分不需要长篇大论,但有三张图必须质量过关:总体架构图、业务流程图、E-R图。总体架构图展示前后端分离、后端分层、数据库存储的整体关系;业务流程图把三类角色在平台上的操作路径画清楚;E-R图把核心实体及其关联摆明白。这三张图看起来是文档基本功,实际上能倒逼你把项目逻辑再梳理一遍,画图的过程就是查漏补缺的过程。

我在设计说明书里一般会让同学把“订单状态机”单独画一张状态转换图,把每个状态之间是谁触发的、触发条件是标注清楚。答辩时老师只要看到这张图,立刻就知道你对业务核心的理解深度,这个动作比多写三十页废话管用得多。

7. 复盘与进阶:店铺租赁平台还能怎么扩展

做完核心功能之后,可以依照自己的时间精力量力扩展。我个人比较推荐三个方向:第一个是“到期提醒”,用Spring的@Scheduled定时任务搭配通知消息表,在租期结束前7天给双方发提醒,代码量不大,但很有业务完成度;第二个是“数据统计面板”,给管理员后台加几个统计卡片,展示店铺总数、出租率、订单金额趋势,用SQL聚合就能实现;第三个是“合同Word生成”,用Java模板技术把合同草稿渲染成Word文件下载,视觉冲击力很强,答辩时直接展示一份格式规范的合同,非常加分。

如果还有余力,可以考虑Spring Security替换手写拦截器方案、引入Redis缓存店铺列表、用RabbitMQ做订单消息异步通知。这些属于拔高项,不纳入必做范围,但每加一个都能多聊三分钟深度,同时也会增加不少调试工作量,建议先完成主线功能,再按“性价比优先”的原则决定加不加。

最后分享一个我自己的体会:很多人做毕设把重心放到了“功能数量”上,觉得页面多就是成果多。实际上,一个完整的业务闭环加上清晰的设计思路,比五个残缺的模块更有价值。店铺租赁平台这个题目最好的地方就是它能让你以较小的代价想清楚“状态管理”“事务一致性”“角色权限”这些真正会在工作中碰到的概念。把这些理解了,整个SpringBoot+Vue的体系也算真正入门了。做项目的过程肯定会遇到接口联不通、数据对不上、组件渲染报错这类问题,别急着搜了改、改了试,先定位是哪一层出了问题——前端、后端还是数据库,这个排查习惯比项目本身更值钱。做毕设真正留下的,不只是那份代码和文档,而是你独立排查问题、梳理业务逻辑的能力。

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

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

立即咨询