资讯动态

Spring Boot+Vue公寓出租系统毕业设计实战指南

发布时间:2026/10/4 2:39:18 来源:尧图企业网站定制
1. 项目整体设计与技术选型1.1 为什么选 Spring Boot Vue 这套技术组合公寓出租系统这个题目在毕业设计里出现频率极高算是典型的“管理信息系统”类项目。这种项目的共同特征是业务边界清晰、角色明确、CRUD操作占大头、权限控制是考核重点。用Java做后端、Vue做前端几乎是最稳妥的答案——Spring Boot 提供了足够完善的生态支持Vue 则能快速搭建出可交互的管理界面。后端选 Spring Boot 还有一个直接原因面试官对这套技术栈的接受度最高。你在简历上写“基于Spring Boot Vue的公寓出租系统”对口岗位的技术筛选基本不会卡壳。如果换成 Python Flask 或者 Node.js虽然开发效率也不差但在 Java 岗位的校招场景下会显得不够贴题。另一个实际考量是Spring Boot 自带内嵌 Tomcat项目打包成 jar 就能跑不需要单独折腾服务器配置这对很多没有运维经验的学生来说省掉了最头疼的一步。前端选 Vue 的核心原因是组件化开发效率高。公寓出租系统有管理员、房东、租客三种角色每个角色看到的页面差异很大——管理员看统计报表和用户管理房东管房源和合同租客负责浏览下单和缴费。如果不用组件拆分的思路这三个角色的页面写到后期基本会变成一坨意大利面。Vue 的单文件组件SFC天然适合这种多角色多页面的场景公共的页面布局、表单组件、表格组件都能直接复用后期加功能也不会牵一发动全身。1.2 需求拆解三种角色到底要管什么这套系统做之前不要急着写代码先把角色和功能矩阵理清楚。我见过太多人拿到题目就建表结果做一半发现房东和租客的需求重叠了又回头重构数据库白白浪费一周时间。公寓出租系统的核心角色就三个管理员、房东或者叫公寓运营方、租客。它们的关系是层层管理、相互依赖的。管理员负责的是平台层面的管理审核房东提交的房源信息确保公寓照片和描述属实管理全部的用户账号冻结违规账号查看整个平台的出租率、营收统计处理租客的投诉建议。房东是系统的核心业务操作者发布和上下架房源、设置租金和押金规则、管理自己名下所有房源的状态、生成租房合同、记录每月账单、催收租金、处理退租和退押金流程。在数据权限上房东只能看到自己名下的房源和合同这是系统设计里必须严控的点。租客的操作链路最简单但体验要求最高注册登录、浏览房源、按区域或租金筛选、预约看房或直接在线签约、在线支付房租和水电费、查看账单历史、申请退租并办理退押金。把角色和功能理清楚之后数据库的表结构就有底了用户表要带上角色字段房源表要关联房东ID合同表和账单表都要关联房源与租客。这比一开始就照抄别人的表结构要靠谱得多。1.3 数据库设计八张表怎么串成一条链路数据库是整个系统的地基表关系设计错了后面所有接口都会跟着别扭。公寓出租系统建议至少准备八张核心表用户表含角色区分、房源表、房源图片表、租房合同表、账单表、看房预约表、收藏表、公告表。用户表的核心字段是角色标识建议用整数枚举1管理员2房东3租客不要用字符串中文查询对比时整数效率更高而且日后再加角色也好扩展。密码字段务必存加密后的结果Spring Boot 集成 Spring Security 的 BCrypt 或者直接用 hutool 的 DigestUtil 都能搞定明文存密码是答辩时最容易被老师怼的硬伤。房源表的字段要覆盖核心信息标题、描述、户型、面积、租金、押金方式、所在城市和小区、具体地址、经纬度、房源状态待审核/已上架/已下架/已出租、所属房东ID。这里有个容易被忽略的设计点经纬度字段最好单独存两个 DOUBLE 类型不要合成一个字符串。后续如果要加地图选房功能单独字段可以直接用 MySQL 的空间索引字符串就没法做高效的地理范围查询了。合同表和账单表要注意状态字段的设计。合同状态建议用待签署、生效中、已退租、已完结账单状态建议用待支付、已支付、逾期、已退款。状态字段配上时间戳的记录创建时间、支付时间、退租时间后面写统计报表时才有数据可查。还有一个实用的建议所有表都加上 create_time 和 update_time 字段并且在插入和更新时自动填充。MyBatis-Plus 提供了 MetaObjectHandler 可以直接实现字段自动填充省掉每次手动 set 的麻烦。这个细节虽然不起眼但答辩时老师问“如果用户量大了怎么排查数据问题”这就是一个能讲两分钟的亮点。2. 核心功能模块与实现细节2.1 登录鉴权JWT 方案怎么落地不踩坑登录鉴权我建议直接用 JWTJSON Web Token比传统的 Session 方案更适合前后端分离的架构。Session 方案需要服务端保存会话状态前端拿到 cookie 之后每次请求都要带着走跨域场景下 cookie 的携带规则很烦人容易埋坑。JWT 则是无状态的服务端不用保存会话令牌本身包含用户ID和角色信息前端每次请求在 Header 里带上Authorization: Bearer token即可。具体落地分三步。第一步用户登录成功后后端把用户ID、用户名、角色封装进 token用密钥签名设置过期时间建议24小时。第二步前端 axios 请求拦截器统一读取本地存储的 token 并附加到请求头。第三步后端写一个 JWT 拦截器从请求头解析 token校验签名和过期时间通过后把用户信息放入 ThreadLocal 供业务层取用。这里必须提醒三个坑。第一个坑token 不要放在 localStorage 里太久XSS 攻击可以直接偷走本地存储的任何内容生产中建议放 HttpOnly 的 cookie 里当然课程设计阶段放 localStorage 问题不大但你在文档里要写清楚这是一个待改进项答辩时反而是加分点。第二个坑密钥不要硬编码散落在代码的每个角落统一放到 application.yml 里通过Value注入文档里要说明生产环境下应该用环境变量或密钥管理服务。第三个坑拦截器放行路径的配置要仔细。登录接口、注册接口、房源浏览接口未登录也能看房必须放行后台管理相关的路径全部拦截。每次新增接口时都要想着这个路由规则不然就是你前脚写完接口后脚发现前端调用 401排查半天才发现拦截器把开放接口也拦掉了。2.2 房源管理图片上传与审核流房源管理是系统的业务重心里面有两个值得展开的功能点图片上传和审核流程。图片上传推荐使用本地存储加数据库路径引用的方案。前端用 Vue 的 el-upload 组件配上 action 指向后端的/api/upload/image接口后端接收 MultipartFile生成 UUID 作为新文件名避免中文文件名和重名导致的问题按照日期分目录存放最后把可访问的 URL 存进房源的图片列表字段。这里要注意上传接口要限制文件类型和大小推荐只允许 jpg、png、webp 格式单张限制在 5MB 以内。前端还要配一个图片压缩的步骤用 canvas 把超过 2MB 的图片压缩后再上传不然用手机拍的照片大几兆一张五张照片就能把服务器带宽跑满加载时全是转圈。审核流程的功能逻辑是房东提交房源后房源状态变成“待审核”管理员在后台能看到待审核列表点击审核通过后状态改为“已上架”前端才能搜到该房源。这个流程有个数据库层面的关键点房源状态字段要加普通索引因为所有房源列表查询都会带上状态条件没有索引的话数据量一上来查询就很慢。另外审核驳回时管理员可以填写驳回原因房东端在房源列表里要能看到原因展示不然房东不知道自己哪里不符合规范体验很差。2.3 合同与账单时间戳驱动的状态机合同和账单是公寓出租系统里最需要动脑子设计的地方因为它们不是单纯的增删改查而是有一套状态流转规则。租客下单签约后系统生成一份租房合同状态为“待签署”。租客点击确认签署后合同状态变为“生效中”同时系统会自动生成第一期的账单月租费押金。之后每个月到了约定的缴费日系统通过定时任务或逻辑触发生成新一期账单。这里我推荐的做法是不要真的用定时任务去扫描生成账单而是设计一个“懒生成”策略——租客或房东查看账单列表时系统先根据合同起始时间和当前时间计算出应该有多少期账单再把缺失的账单批量补生成。这样省去了配置 cron 表达式的麻烦也不会出现定时任务跑了但数据没对上这种诡异问题。账单状态机要处理的关键场景是逾期。公寓出租业务里房租逾期三天内正常提醒超过三天要产生滞纳金。这个逻辑建议在账单查询时动态算出滞纳金金额更新到账单的“逾期费”字段中而不是提前把滞纳金金额写死到数据库。因为滞纳金的利率例如每天万分之五如果后期调整了老账单的金额就会失真动态计算就没有这个烦恼。退租流程同样是一套状态流转租客发起退租申请房东确认后系统计算水电费差额和可能的房屋损坏扣款从押金里扣除后生成退款记录最后把合同状态改为“已退租”房源状态改回“待出租”。这套流程哪怕逻辑再简单也要保证是在同一个事务里完成的——不然就会出现合同已经关闭了但房源还是“已出租”状态的脏数据。2.4 统计报表给管理员一张能看的数据面板管理员登录后的首页需要展示整个平台的运行情况。这个模块不需要单独的报表表直接从现有数据里聚合查询即可。推荐的展示项有六个总房源数、在租房源数、待审核房源数、总租客数、当月新增合同数、当月累计营收。营收的计算是从账单表里对支付成功的账单按月求和注意要带上支付时间而不是账单生成时间的条件。后端用 MyBatis-Plus 的QueryWrapper结合SelectCount、Sum等聚合函数就能搞定不需要写原生的复杂SQL。不过有一个性能细节值得注意这些统计接口在管理员每次刷新页面时都会调用建议加上 Spring Cache 的本地缓存缓存过期时间设置成30秒。这样即使有十几个管理员同时在线数据库的聚合查询压力也不会太大。这个优化点不需要额外的技术栈就是 Spring 自带的Cacheable注解加一个Caffeine本地缓存就行性价比非常高而且答辩时能讲两分钟。3. 实操过程与核心环节实现3.1 前端环境搭建Vue CLI 到路由配通前端项目建议直接用 Vue CLI 创建不要用手动 webpack 配置的方式除非你想徒手造轮子。创建命令是vue create apartment-frontend然后选择 Vue 3 和默认的 TypeScript 选项要不要 TypeScript 看自己水平课程设计不强求但我个人推荐上 TS后期改代码的时候心里会踏实很多。项目目录建议这样组织src/views放页面级组件按角色分子目录admin、landlord、tenantsrc/components放公共组件图片上传、分页表格、城市选择等src/router放路由配置文件src/api放 axios 接口封装模块src/store放 Pinia 状态管理的用户信息和权限状态路由设计时务必配置路由守卫。Vue Router 的beforeEach钩子里判断用户角色未登录跳登录页登录了但访问无权访问的页面要跳 403 页面不要只跳回首页不然用户会以为系统坏了。axios 封装有两个必做的配置请求拦截器里从 Pinia 取 token 放进请求头响应拦截器里全局处理 HTTP 401 状态统一跳登录页并清掉本地用户信息。这样后端的登录态过期处理就只写一遍每个页面都不用单独处理因为 token 过期导致的一堆报错。3.2 后端接口开发从 Entity 到 Controller 的四层写法后端建议采用四层结构Controller → Service → Mapper → Entity。Controller 只做参数接收和结果包装Service 写业务逻辑Mapper 负责数据库交互Entity 是对应数据库表的实体类。以一个典型的新增房源接口为例完整步骤是Controller 层接收前端传来的 JSON 数据用一个RequestBody的HouseCreateDTO接收。DTO 和 Entity 的区别在于 DTO 只包含前端传来的字段而 Entity 额外包含数据库自动生成的创建时间、更新时间和状态字段。很多人图省事直接用 Entity 接收前端数据最后发现前端多传了几个字段就把数据库字段覆盖了排查半天才发现问题这就是不分层带来的隐患。Service 层的处理逻辑里第一件事是判断当前登录用户的角色是否允许发布房源。用一个自定义注解RequireRole(LANDLORD)或者手动从 ThreadLocal 里取用户角色进行校验都可以。第二件事是把 DTO 转换成 Entity补上初始状态字段待审核。第三件事是调用 Mapper 插入数据同时批量插入房源图片的关联记录。这三步必须在同一个事务方法里用Transactional注解保证原子性——如果图片插入失败但房源信息插入了数据就出现不一致了。统一返回体的设计也要提前定好。我用的方案是{ code: 200, message: success, data: {...} }成功的接口 code 一律 200业务逻辑异常可以自定义 code401代表未登录、403代表无权限、404代表数据不存在、500代表系统错误。前端响应拦截器里对 code 做统一判断和 message 展示这样后端就不用每种错误都写一遍try-catch然后返回一堆格式不统一的 JSON 了。3.3 前后端联调时避不开的那几个问题前后端联调是整个项目里最磨人的阶段至少有一半的 Bug 出在两边对接口定义的理解不一致上。我自己联调时碰到的高频问题整理出来基本可以覆盖大多数场景接口地址拼错或带了多余斜杠是最常见的低级错误。后端路径写的是/api/house/list前端请求写的是api/house/list/或者baseURL已经包含/api了还在路径里重复写。这类问题可以用统一的 API 前缀配置来规避——前端在 axios 实例的baseURL里统一写/api之后每层路径都不要再写/api前缀约定好了就不会再犯。字段大小写不一致是第二个高频问题。Java 后端默认返回的 JSON 字段是实体的属性名比如createTime但前端代码里手写对象时习惯写成create_time于是接口返回后页面表格这一列就是空的。这个问题建议前端不要手写对象映射直接用接口返回的数据渲染或者后端在实体字段上加JsonProperty(createTime)统一规范命名两边对齐即可。时间格式不统一也很常见。后端默认返回的LocalDateTime序列化后是2025-01-15T10:30:00前端时间选择器拿到这个字符串直接展示会非常难看。解决办法是在后端配置全局的 Jackson 序列化格式在application.yml里配spring.jackson.date-formatyyyy-MM-dd HH:mm:ss和spring.jackson.time-zoneGMT8这样所有时间字段都会输出成人类可读的格式。跨域问题就更基本了。前后端分离项目前端跑在 8080 端口后端跑在 8081 端口直接请求必然触发 CORS 报错。最简单的解法是在后端写一个全局的 WebMvcConfigurer 配置类允许所有来源的跨域请求并允许携带 Authorization 请求头。注意如果用了 JWT 方案allowedHeaders里一定要包含AuthorizationexposedHeaders里也要暴露它不然前端无法读取到登录接口返回的 token。3.4 数据库脚本管理与版本记录源码包里带数据库脚本是必须的但脚本怎么写是有讲究的。不要只导出一份最终的建表语句就完事建议提供两个文件init.sql负责建库建表和初始化基础数据管理员账号、公告数据、测试用房东和租客账号sample_data.sql负责插入一些演示用的房源和合同数据方便老师或面试官直接跑起来看效果。初始化数据里管理员账号的密码用 BCrypt 加密后的字符串不要明文写123456。演示账号的密码统一设置成123456并在文档里注明这样搭建环境和测试都方便。房源演示数据要覆盖不同的状态已上架、已出租、待审核各准备两三条这样前端页面的各种状态展示都能看到效果不会因为缺数据误以为功能没实现。另外建议在init.sql里显式添加数据库字符集和排序规则CREATE DATABASE IF NOT EXISTS apartment_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;用utf8mb4而不是utf8的原因非常实际utf8在 MySQL 里只支持三个字节的字符用户在备注里输入 emoji 表情会直接插入失败报Incorrect string value错误。这个坑我替很多人踩过提前在脚本里定好字符集能救一大票人。4. 常见问题与排查技巧实录4.1 后端接口报 500 的几种典型场景面对 500 错误不要慌先看日志。Spring Boot 的默认控制台日志已经把异常栈打出来了错误类型基本能直接告诉你答案。第一个高频场景实体字段和数据库列名对不上。比如实体里写了private String houseDesc;但数据库列名是house_desc并且没开启 MyBatis-Plus 的下划线转驼峰映射查询时就会报Unknown column house_desc的错误。检查方案是确认application.yml里配置了mybatis-plus.configuration.map-underscore-to-camel-case: true或者干脆把实体字段名和数据库列名保持一致少给自己找麻烦。第二个高频场景空指针异常。Service 里从数据库查了房源对象直接取关联字段但这条房源记录没有关联数据于是NullPointerException。这类问题要从源头规避——对任何可能不存在的查询结果都要先做空值判断再取字段。MyBatis-Plus 的getOne方法推荐配合last(limit 1)使用因为如果查询结果有多条记录直接getOne会抛异常。第三个高频场景类型转换错误。前端传来的是字符串2025-01-15后端接参的字段是LocalDate类型如果没有配置全局的日期转换器Spring 默认的转换策略转不动直接 500。解决方法是写一个ControllerAdvice配合InitBinder处理字符串转日期或者全局配置 Jackson 的日期反序列化器。这类问题在联调阶段出现频率极高提前配好能省一大半的排查时间。4.2 前端页面白屏排查思路和执行顺序页面白屏是最让人抓狂的问题之一但排查思路非常固定按顺序执行基本十分钟内搞定。第一步打开浏览器开发者工具的 Console 面板看有没有红色报错。最常见的报错是Cannot read properties of undefined (reading xxx)说明数据还没回来你就去渲染它的属性了在模板里加v-if判断就能解决。另一个常见报错是Failed to load resource: the server responded with a status of 404基本就是接口路径错了去 Network 面板看具体请求的 URL和后端确认一下路径就知道问题出在哪。第二步如果 Console 没有报错但页面依旧是空白重点检查路由配置。看看访问的路由路径是否和 router 里定义的 path 完全一致特别是静态资源路径。Vue 3 的 history 模式在刷新时会向服务器发送真正的请求如果部署环境没有做 fallback 配置刷新二级路由页面时就会 404 白屏。课程设计阶段建议直接用 hash 模式createWebHashHistory刷新永远没问题等以后真的做生产部署再换成 history 模式。第三步如果路由和 Console 都没问题检查数据渲染的问题。在 Vue Devtools 插件里查看组件的数据流确认请求到的数据真的传到了渲染层。这里有一个细节父组件发请求拿数据传给子组件作为 prop子组件在初始化时就用了 prop 的值但此时网络请求还没返回prop 是空的页面自然白屏。解决办法是子组件里监听 prop 变化或者用v-ifdata.length 0控制渲染时机。4.3 部署到 Linux 服务器时要注意的细节课程设计如果只要求答辩演示在本地跑就行。但如果老师要求部署到服务器很多学校有这个环节有几个坑是每届都会有人踩的。前端打包后的静态资源路径问题首当其冲。Vue 3 默认的publicPath是/打包后资源引用路径是根路径下的/assets/xxx.js。如果 nginx 把前端项目放在某个子路径下比如/web/不配置publicPath的话所有资源都会 404。最简单的方式是在.env.production里设置VUE_APP_PUBLIC_PATH: ./使用相对路径这样不管放在哪个目录都能访问。后端打包成 jar 之后运行命令建议用java -jar apartment-server.jar --spring.profiles.activeprod把开发环境和生产环境的配置拆成两个文件application-dev.yml连本地数据库application-prod.yml连服务器的 MySQL。生产环境的数据库密码不要写在配置文件里用环境变量注入这是最基本的操作习惯。nginx 的反向代理配置要同时处理两个问题前端页面请求用try_files解决路由刷新问题API 请求用proxy_pass转发到后端的 8081 端口。核心配置长这样server { listen 80; server_name your-domain.com; location / { root /var/www/apartment-frontend/dist; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8081/; proxy_set_header Host $host; } }注意proxy_pass的末尾带了/这个斜杠代表把/api前缀剥掉再转发到后端端口。如果后端接口路径本身包含/api前缀那这个斜杠就不能加加了反而 404。这是最容易配错的一个点。4.4 答辩时项目讲解的加分思路项目代码写完只是完成了 50%答辩讲得好不好直接影响成绩。根据我帮人模拟答辩的经验同一个项目讲得好的和讲得差的分数能差一个档次。讲项目时不要从头到尾念功能列表而是用“遇到问题—分析问题—解决问题”的叙事结构。比如讲到 JWT 登录鉴权不要只说“我用了 JWT 做登录”要说“因为我做的是前后端分离项目Session 在跨域场景下处理 cookie 比较麻烦而且后端无法方便地水平扩展所以我调研后选择了 JWT 的无状态方案。具体实现上我在拦截器里统一解析 token把用户信息放到 ThreadLocal 里业务层可以直接取用。这样做的优点是登录态校验统一、接口无状态缺点也有token 无法主动失效后面可以通过引入 Redis 黑名单机制来改进。”这段讲完老师至少知道你不仅是调包而是真的理解了这个方案。项目亮点不要只准备一个。除了登录鉴权还可以讲讲数据库查询优化加上索引前后的执行计划对比、接口统一返回体设计排查问题时的效率提升、前端路由懒加载首屏加载速度的优化等等。亮点要和你简历上写的技能一一对应才显得可信。有一点基本的心理建设要提前做好被老师问住了不要慌千万不要现场编答案。诚实说“这块我还没有深入了解但我在文档的待改进项里已经写了后续计划”比硬着头皮扯一通强得多老师更看重的是你对自己项目边界的认知。5. 文档编写与项目交付的整体建议源码包里带了文档这是很多课程设计评分表里的必选项。但我在帮人检查项目的过程中发现大部分文档都是应付式的写个系统概述、写个功能列表、贴几张截图就交差了。其实一份合格的课程设计文档评分老师真正想看的是“你做了什么决策”“你为什么这么设计”“你踩了什么坑怎么解决的”这是区分“搬运工”和“真正做过项目”的核心。建议文档按这个结构写第一章写系统的需求分析和可行性分析第二章写技术选型论证为什么用 Spring Boot 而不是 SSM为什么用 Vue 而不是 JQuery不要写“大家都用”要写技术对比第三章写数据库设计附上 E-R 图和每张表的核心字段说明第四章写系统详细设计与核心代码实现重点讲登录鉴权、合同状态机、账单生成策略这三个模块第五章写系统测试和性能优化情况附上 Postman 接口测试截图和前端页面录屏最后一章写总结与展望坦诚写出项目的不足和后续迭代计划。数据库文件建议不只给一份init.sql可以额外给一份apartment_backup.sql带完整数据的备份。这样老师在本地导入时可以直接看到有数据的运行效果不需要为了一条测试数据在系统里各种录入。同理文档里配几张核心页面运行截图省去老师自己启动项目点来点去的时间体验会好很多。项目交付时源码结构要干净。不要把你实验过程中产生的乱七八糟的测试文件、临时截图、未完成的组件全部保留。目录结构保持清晰backend和frontend分开放根目录放README.md、docs文件夹和数据库脚本。README 里写清楚项目简介、技术栈、目录结构、如何初始化数据库、如何启动后端、如何启动前端、测试账号列表管理员/房东/租客各一个、常见问题问答。这份 README 就是整个项目的门面读者能不能顺利跑起来就看它。最后再说一个细节项目包名的命名规范。很多人的后端主包名喜欢用com.example一看就是脚手架自动生成的。建议改成com.apartment.admin、com.apartment.web这种有意义的命名方式并且把不同角色的模块拆到不同的包里。这种规范性的改动虽然不影响功能运行但阅卷老师和面试官打开代码的第一眼印象就是从这些细节建立的。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑