ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于SpringBoot的房屋租赁系统毕业设计全解析

基于SpringBoot的房屋租赁系统毕业设计全解析 做毕业设计选“房屋租赁系统”这个题目我是非常支持的。原因很简单它是一个有业务深度、有完整流程、能展示技术栈、又不会复杂到做不完的典型业务系统。尤其是基于 SpringBoot 来搞前后端分离也好、服务端渲染也好都能找到非常成熟的开源方案和参考资料。这篇内容我把当年带学生做类似项目时踩过的坑、总结的经验、还有整个系统的拆解思路都写出来希望能给正在挠头的同学一些实在的参考。我带的毕业生里选这个课题的每年都有好几个。一开始我以为大家是因为懒才选这个后来发现这题目其实是“看起来简单、做起来有料”的那一类。表面上是增删改查实际上牵扯到用户角色权限、房源状态流转、交易订单生成、支付回调处理、检索排序、后台审核这一整条业务链每一块都能讲出不少东西。花同样的时间做一个小商城可能答辩时三两句就没话说了但租赁系统你能讲的东西多得多。1. 项目整体设计与思路拆解1.1 为什么选这个课题它能解决什么问题先说说这个项目到底是干嘛的。传统租房场景里房东发布房源靠中介或者贴小广告租客找房靠跑腿或者碰运气信息既不透明也不对称。线上租赁平台就是把“房源发布、房源检索、在线预约看房、合同签订、账单管理”这一串动作全部搬到线上让信息流转效率高起来。从毕业设计的角度这个业务场景覆盖了一个商业系统的大部分核心环节多用户角色前端有房东和租客后台有平台管理员三者权限天然隔离适合做权限设计。核心数据是房源信息和订单信息这个过程中牵扯状态流转有业务逻辑在里面。会涉及文件上传房源图片、复杂条件检索价格、区域、户型、朝向筛选、订单生成与状态管理这些功能最能体现一个学生的综合能力。这几点合在一起意味着你项目的技术复杂度和业务完整度都是够的答辩时不怕没内容说也方便老师顺着你的业务追问你能答得出来就有亮点。从实用性来说做一个“能跑起来、流程能走通”的线上租房平台基本就是一个小型分类信息平台的项目内核后续你想扩展二手房交易、车位租赁甚至换成二手书交易平台底层架构都是通用的。也就是说做这一个题目的经验可以做多种复用不亏。1.2 功能模块划分与核心业务流程我做这个系统时从来没有一上来就急着写代码。业务建模花的时间永远值得尤其是学校里做项目很多人一上来就建表结果表建到一半发现业务模型有问题又删了重来白白浪费许多时间。我建议把这个系统画成四个大模块用户端租客侧注册、登录含手机号验证逻辑房源浏览与关键词检索支持按区域、价格区间、户型筛选房源详情查看多图展示、配套设施、位置地图收藏房源预约看房生成租赁订单、在线签约确认账单查看与在线支付退租申请用户端房东侧房源发布含图片上传、基本信息填写房源上下架管理租客预约看房处理合同确认与签署账单催缴查看租务明细与收益统计管理后台平台管理员侧用户信息管理封号、解封房源审核发布审核、违规下架订单管理跟踪所有订单状态投诉与反馈处理数据看板注册用户量、房源量、成交订单量、租金总额公共服务模块登录鉴权与权限控制文件上传服务统一异常处理与日志记录这里最核心的流程是租赁交易的完整链路。很多人做得稀里糊涂就是因为订单状态没定义好。常规的做法是把订单状态设计成一个状态机大概是这样当签约确认已完成后生成待支付账单支付成功之后订单变为已生效状态此时开始正常履约。租期到期时租客申请退租完成退租检查和费用核算后订单最终进入已完成状态。另一条分支是租客在任意未生效阶段取消订单订单立即变为已取消不会再进入后续流程。1.3 技术选型背后的考量这个题目我觉得选 SpringBoot 做主体框架是很合理的基本上也是当前主流的选择。SpringBoot 让项目搭建、配置、部署都大大简化了你写业务代码的时间能多出不少而框架本身在企业里用得非常多学它不止是为了应付毕业设计。技术上我通常这样搭配核心框架SpringBoot 2.x持久层MyBatis-Plus数据库MySQL 5.78.0 也没问题注意驱动和连接配置要对应缓存Spring Data Redis用来做验证码存储、热点房源缓存权限认证JWT无状态登录方案配合拦截器做权限控制前端Vue Element UI或者 Thymeleaf Bootstrap构建工具Maven文件存储本地存储路径 Nginx 静态映射生产环境可以换 OSS有一个细节我想多说一下。选择 MyBatis-Plus 而不是传统 MyBatis是因为它对单表 CRUD 做了封装写代码效率高很多而且内置了分页插件对毕业设计这种规模的项目来说非常合适。不过要注意的是多表联查的时候还是要手写 SQL你在答辩时完全可以说“简单场景用封装复杂查询手写 SQL两者结合既保证开发效率又保留灵活性”这一句话就能让对方感受到你是认真思考过的。2. 数据库设计与核心表结构2.1 用户、房源、订单三大实体的表设计凡是做业务系统数据库设计做得扎实后面都省心设计做得烂后面业务逻辑全都得迁就表设计越写越痛苦。租赁系统我通常设计成九张核心表每张表的作用都很明确。用户表保存的是账号密码、手机号、昵称、身份类型和账号状态信息。密码字段必须加密存储我这边直接用 BCrypt把明文密码转换为不可逆的密文再入库这样即使数据库泄露了也不会直接暴露用户密码算是安全性上的基本要求。角色划分这里我用了一个小技巧用字段区分身份比如 0 表示管理员1 表示房东2 表示租客。一个身份为房东的用户同时也可能租别人的房子他可以在个人中心里切换身份本质上就是不限制单一身份业务上比较灵活。房源表是信息核心包括标题、描述、户型、面积、朝向、楼层、租金、押金、所在区域、地址、经纬度、房东ID、审核状态、上下架状态、浏览量字段。这里把“审核状态”和“上下架状态”分开是很重要的审核是管理员对内容合法性的检查上下架是房东自己的运营动作两者不能混在一个枚举里。房源图片用了关联表存多条记录一条房源对应多张图片保存相对路径不要用 base64 直接存库。订单表相关联的是租客在房源详情页发起租赁形成的记录包含订单编号、房源ID、租客ID、房东ID、起止日期、租金合计、押金、状态、创建时间。订单编号生成时我用了日期加随机数的方式格式比如 20250114123000 加四位随机数既能看出时间又能避免太容易被人猜出来。如果用了自增主键直接作为订单号会比较容易在地址栏里改参数时被猜到其他订单有一定风险。表结构里最容易遗漏的是账单表。我觉得这个设计很有必要尤其是合同到期中途解约的情况没有账单明细财务核算就是一笔糊涂账。每笔应收的租金都生成一条账单记录关联到订单ID上记录期数、金额、支付状态、支付时间、支付流水号。支付的功能可以接入第三方支付沙箱环境如果担心复杂度也可以做一个模拟支付页面点了按钮直接回调成功。2.2 租赁状态机的设计与实现订单状态流转是这个项目的业务灵魂也是答辩时老师最喜欢问的点。我用一张表来记录订单的所有状态变化避免状态混乱丧失可追溯性。哈上面废话这么多其实核心逻辑就是几个状态待支付、已支付生效中、履约中、已完成、已取消。有人喜欢把“已支付”和“履约中”合并成一个状态但我更倾向拆开。待支付是在线签约后生成的账单还没付款成功已支付是钱到了平台但租期还没开始履约中表示租期正式开始。三个状态对应三种不同的业务操作比如已支付阶段可以申请退款取消履约中阶段只能走退租流程如果合并的话这里的判断逻辑就会很绕。数据库层面有一个点很多人会忽略就是并发更新下的状态检查。比如用户重复提交退租申请或者管理员同时在后台改订单状态可能造成状态跳变。我一般使用乐观锁在订单表加一个 version 字段更新时要求版本号匹配更新成功后版本加一。实际代码里用一条UPDATE ... WHERE id ? AND status ? AND version ?做个条件判断更新影响行数为 0 说明状态已经被别人改了就不允许这次操作执行。2.3 索引设计与查询优化经验毕业设计的数据量通常不大字段少的表你随便查询都不会有性能问题但索引设计是基本功在设计表时就应该想清楚而不是等到卡了才去补救。我这边常用的索引设计经验有三个第一登录校验用的手机号字段建唯一索引。这点不光防性能差还能在数据库层面保证同一个手机号只能注册一个账号应用层判断只是第一道防线数据库唯一约束才是硬兜底。第二房源表里检索条件涉及的字段可以建组合索引。比如“区域租金”的组合查询很常见可以建一个(area_id, rent_amount)联合索引。但这里注意如果查询里只按租金一个条件筛那这个联合索引就用不上了联合索引的最左前缀原则在数据库基础面试里也经常问到。第三订单表里(user_id, status)的联合索引可以让用户查看“我的订单”时直接走索引查找避免全表扫。由于订单数据随时间不断增长这个索引也算有长远意义。页面上如果要展示“最近浏览房源”或“为你推荐”一版来说不需要额外搞推荐引擎直接取用户收藏记录里最好的一批数据格式化展示就行。这个功能做出来容易解释起来也没负担。3. 核心功能实现与实操过程3.1 系统架构分层与工程结构搭建SpringBoot 工程我习惯用标准的三层结构Controller、Service、Mapper。多一个 DTO/VO 层用于参数接收和结果返回以及一个 config 包放配置类比如 WebMvcConfig、RedisConfig、MybatisPlusConfig。没有搞很复杂的 DDD 分层对毕设来说分层太深反而是负担。项目工程结构大概这样组织com.example.rental ├── controller // 控制层接收前端请求 ├── service // 业务层写核心业务逻辑 │ └── impl // 业务实现类 ├── mapper // 数据访问层 ├── entity // 数据库实体类 ├── dto // 入参对象 ├── vo // 出参对象 ├── config // 配置类 ├── common // 公共类统一返回结果、异常处理等 │ └── exception // 自定义异常 └── utils // 工具类JWT工具、日期处理等有一个细节对新手很友好就是controller层只做参数接收和结果包装不写任何业务代码业务判断全部放到service层。比如发布房源时校验用户是不是房东身份、审核房源时校验房源状态这些逻辑放在 service 里controller 只是简单调 service 方法并返回统一响应结果。如果将来接口变了controller 改动即可不会动到业务逻辑的核心。统一返回结果类我习惯用一个泛型类ResultT包含 code、message、data 三个字段。成功返回 code200业务失败 code400未登录或权限不足 code401服务器异常 code500。前端拿到 code 就统一处理不用每个接口都单独写错误逻辑。前后端联调时会省很多事。异常处理这块我强烈建议写一个全局异常处理器用RestControllerAdvice注解捕获所有异常针对自定义的业务异常返回友好提示针对未知异常返回通用错误。这是我每次都会给学生强调的一个点。否则前端一旦拿到的响应不符合约定格式整个页面就都报错了。3.2 登录认证与角色权限的实现方案登录这块我推荐直接上 JWT。JWT 是无状态的服务端不存登录信息客户端每次请求带上 Token服务端验签后从 Token 里解析用户信息。毕业设计做这个方案能省掉 Session 管理和共享的复杂度也贴合现在企业里前端分离项目的常见做法。实现起来也不算复杂步骤大概如下用户输入手机号和密码UserService根据手机号查出用户用 BCrypt 校验密码。密码校验通过后生成 JWT把用户ID、身份类型放进去设置过期时间比如24小时。前端把 Token 存到 localStorage每次请求在请求头加Authorization: Bearer token。后端写一个AuthInterceptor拦截器校验请求头里的 Token没带或过期就返回 401让前端跳到登录页。权限控制用拦截器做就可以了。比如只有房东管理员能访问的后台接口在接口上写自定义注解拦截器里解析注解判断身份不满足就返回 403。密码加密这一块值得多说一嘴。用 BCrypt 算法加盐散列同一个明文密码每次生成的哈希串都不一样安全性比 MD5 高很多个档次。写的时候不要图省事去用 MD5、SHA1 搞简单加密答辩时也会给老师留下好印象。有时候毕设会用手机验证码登录的方案。如果做到这一步最合理的设计是让用户发送验证码请求后生成随机四位数字存到 Redis 里有效期五分钟同时调短信接口发给用户。开发环境没有真实的短信服务可以先把验证码打印在日志里方便测试本地用 0000、1234 这种固定码跑通流程。但注意答辩时一定要说明“这只是模拟实现正式上线时需要替换成真实的短信服务商接口”。3.3 房源发布与检索的核心逻辑房源发布是另一个功能大头。前端表单的字段会比较多设计时需要注意一个关键问题房源图片上传与基本信息填写是分步进行的。我的常用做法是先让表单请求一个“创建草稿”的接口把基本信息提交上去返回房源ID拿到 ID 后再上传图片。也就是说发布不再是一次性提交所有数据的而是“先建主记录再补图片”完全避免了大事务和临时文件堆积的问题。很多新手一上来就让图片和数据放在同一个接口提交结果图片处理有问题时整条数据都保存不下来或者出现半条记录非常麻烦。分步创建还有个额外的好处就是“暂存草稿”功能变得很简单保存基本信息不提交审核等图片都传完再点击“提交审核”管理员才会审核。房源检索是用户端用得最多的功能。条件筛选组合多如果用拼接 SQL 的方式要在 Service 里判断参数是否为空再拼条件容易出错且无法复用。这里更推荐 MyBatis-Plus 的QueryWrapper用.like()、.eq()、.between()按条件逐个追加代码清晰也有复用性。几个检索时的细节要特别注意租金区间查询用between下界可以为空上界可以为空两个都不为空时走区间。整租合租分开搜索。合租房和整租房在租金、租赁方式等字段上差别很大前端筛选要区分开。视野包含了“房源所在区域”下拉选择区域列表时用区域名称字段存储还是关联区域表我建议关联区域表省得房源表里同一区域文字抄来抄去出现不一致的情况。3.4 在线签约与账单生成流程在线签约是租赁系统的核心交易动作也是业务复杂度最高的地方。流程上我是这样设计的租客在房源详情页点“立即签约”系统判断房源状态必须为“已上架且审核通过”再判断租客身份不能与房东相同自己不能租自己的房子然后创建一个订单进入待支付状态。这里可以考虑同时生成首期账单防止订单生成了但账单迟迟没人建。这里有一个比较重要的业务细节房源在订单生效期间不能再被其他人下单。所以创建订单时需要锁定房源的出租状态用一条带条件的 UPDATE 来保证原子性。比如UPDATE house SET status 1 WHERE id #{houseId} AND status 0如果影响行数为 0说明房源已被抢走或不在可租状态这时直接返回友好提示“该房源已被其他用户下单”比先 SELECT 再 UPDATE 更可靠因为 SELECT 不是原子的中间可能被其他请求插进来。这种带条件的更新在实际开发里是常见技巧也是能体现出对并发问题理解的地方。支付环节按常规接入第三方沙箱需要申请商户号过程比较繁琐。做毕设完全可以用“模拟支付”替代前端弹出一个确认支付窗口用户点“确认支付”后后端把订单状态改为“已支付”生成一条支付流水记录。到了答辩环节如果你说“这里我调了沙箱接口来做支付”其实也很好但前提是你真的把沙箱申请和安全链路都搞明白如果只是调用一个不正规的第三方接口反而有风险。租期开始后房东可以定期生成账单收款。这里不要做得太复杂用一个定时任务补充管理员配置系统每天跑一次检查所有履约中的订单按其租金周期自动生成下一期账单。如果嫌定时任务有点复杂也可以在租客登录时检查有没有待生成的账单一次性生成。这两种方案我都写过个人更推荐定时任务逻辑更干净也不会因为用户长时间不登录导致账单生成滞后。4. 开发过程中的坑与排查技巧4.1 常见Bug与解决方案开发这种项目有一些坑是会反复踩到的我按踩中频率和杀伤力排个序404 排查不出来经常是 Controller 里的RequestMapping路径写错或者类上注解忘记加。建议大家先访问最简单的接口确认框架没问题REST 风格建议配一个spring.mvc.servlet.path之类的统一前缀。还有就是RequestParam和RequestBody混用前端传的是 JSON后端用RequestParam接收就永远接不到值这种情况排查代价很高。所以我一般建议POST 请求携带有嵌套结构的数据时用RequestBody接收一个 DTO 对象GET 请求的查询参数用普通参数或RequestParam别混。跨域问题前后端分离的项目前端跑在 8080后端跑在 8081直接请求就会被同源策略挡住。解决方案是写一个CorsConfig或者使用CrossOrigin注解配置允许的来源来源。注意实际部署的时候跨域配置和前端代理两种方式要选一个否则线上又会出现同样的跨域问题。日期格式化不一致MySQL 里面日期字段是datetime类型后端返回 JSON 时默认格式可能不是前端想要的yyyy-MM-dd HH:mm:ss。最简单的做法是用spring.jackson.date-format配置全局格式加上spring.jackson.time-zone。如果哪天前端非要 ISO 格式再用JsonFormat单独处理。空指针异常NPE这个快成了毕设代码里第一大类 Bug 来源原因就是查询数据库得到 null 后直接去 get 字段。我教学生的习惯是Service 层凡是查询单记录的接口马上判断结果是否为 null为空就抛自定义业务异常不要让他往下传到前端。文件上传失败本地磁盘路径没建好或者路径写的是相对路径导致实际目录对不上。比较好的做法是配置一个绝对路径作为上传根目录并加上目录自动创建逻辑。同时注意限制文件类型和大小防止前端传个超大文件导致服务器磁盘被塞满。4.2 性能优化心得毕业设计阶段谈性能优化确实容易让人怀疑。但有些优化既简单又能体现你有工程意识推荐顺手做了。第一个是 Redis 缓存热点房源数据。房源详情页是最频繁的读取路径可以将房源基本信息包括主图、租金、押金、户型等信息缓存到 Redis缓存 key 设计成house:detail:{houseId}首次访问查库并写缓存后续访问直接取缓存设置了过期时间比如30分钟。房东修改房源后主动删除对应缓存下次访问重新加载。这样一个简单的缓存策略就能让详情页的响应时间从几十毫秒降到几毫秒而且你还能在答辩中说自己考虑了缓存一致性问题很加分。第二个是列表页的分页。MyBatis-Plus 自带Page分页配合内置分页插件很容易实现。不做分页的话数据量一大页面就卡死。注意在分页时返回的总记录数要从Page对象里拿而不是额外写一个 count 查询。第三个是图片的压缩处理。上传房源图片时前端传的图往往是手机原图又大又占空间。后端可以在保存原图的同时生成一个缩略图列表页只加载缩略图详情页再加载大图。Java 里用Thumbnails库能几行代码完成。这个看你自己取舍不写也没关系但写了绝对是一个亮点。第四个是数据库连接池的配置。SpringBoot 默认的连接池参数对毕设来说够用不过可以顺手把最大连接数调大一点比如 20 个以及连接超时时间设置合理。这个细节在部署到服务器上时还挺管用的。4.3 答辩与文档准备建议很多人花大量时间写代码结果最后一两周才仓促写文档和准备答辩这是本末倒置。代码只是你项目能力的部分体现而文档和答辩表现才真正决定你和同样情况的其他人之间的区分度。毕业设计说明书我建议按这个顺序准备摘要与关键词一两句话描述系统做了什么用了什么技术达到了什么效果。绪论研究背景与意义从线下租房痛点切入谈线上平台的优势。需求分析功能需求、非功能需求、可行性分析附用例图。系统设计架构图、功能模块划分、数据库设计ER图、表结构说明。系统实现核心模块的截图 关键代码 文字说明。系统测试功能测试用例和结果性能测试结论尽量附一些测试截图。总结与展望写你做了什么哪个地方可以继续优化。论文里要避免只贴大段代码而应该集中讲清楚“为什么这么做”。每张表要有字段说明表每个核心模块要有流程图或业务时序描述配图要清晰。答辩 PPT 我的建议是 15 页左右顺序大致是封面、背景与意义、技术路线、系统模块功能图、数据库设计、核心模块截图房源检索、订单流程、后台审核、测试结果、总结与致谢。PPT 不是用来念的是你讲的时候的提纲每页列要点即可不需要把所有细节都堆上去。答辩现场老师们最常问的问题我预先列几个以备不时之需如何防止同套房源被多人同时下单回答思路就是上前面的条件更新方式只有影响行数为 1 时下单才成功。登录状态如何保持JWT 校验方式包含过期时间、拦截器校验。密码是怎么加密的BCrypt 加盐散列不可逆。检索条件多的时候怎么处理MyBatis-Plus 条件构造器或动态 SQL 拼接。缓存和数据库怎么保一致更新房源时主动删除缓存下次访问重新加载。支付失败怎么办账单状态保持待支付允许重新支付记录支付流水审计更清晰。这些问题如果提前准备好答辩就不会怯场。很多同学不是做得不好而是不知道怎么把自己的工作讲清楚这一点确实值得提前演练一番。5. 项目扩展方向与个人实践心得如果做完了基础版本还觉得学有余力或者想在答辩里有更多亮点下面这几个扩展方向你完全可以深入研究引入消息队列。比如用户下单成功、房东收到新预约这些场景系统可以发通知消息或站内信。设计时可以考虑用 RabbitMQ 做一个简单的异步通知把发通知和主流程解耦体现你对异步解耦的理解。增加地图找房功能。房源位置字段存经纬度前端集成高德地图或百度地图 SDK展示地图标点按距离筛房、查看周边配套。这块功能视觉效果好答辩时展示特别拉风。数据分析看板。管理员后台展示平台整体运营数据比如各区域房源分布图、租金趋势、热门小区排行。可以用前端图表库来画图数据接口用分组统计 SQL 来实现。引入 Elasticsearch 做房源搜索。按关键词全文检索、按区域做聚合统计。不过这个对毕设来说有点超纲了而且部署运维成本高量力而行就好。说实在的我做了不少类似的系统最大的感想是这类管理系统能值钱的地方并不在于会写多少种框架而在于你懂不懂业务流程、能不能把复杂流程落到具体的数据流转和技术判断上。房屋租赁系统看起来平平无奇但“订单状态机”、“库存原子性”、“权限隔离”、“缓存一致性”这些关键词随便拿一个出来都能说明你是懂业务逻辑的而不只是会调用代码生成器。最后再分享一个小技巧。很多同学喜欢用代码生成器把表的 CRUD 全自动生成出来这个我支持效率确实高。但有一个禁区控制器不要用自动生成的那一套。自动生成的代码往往缺少业务判断和自定义返回结构。我建议你把 service 接口和实现、DTO、VO、Mapper 自动生成Controller 自己手写至少保证控制器的风格和你的业务是一套逻辑连贯的东西避免一眼就被看出来是机械代码。如果你正准备答辩或者正在写代码希望这篇文章能帮到你。项目不在大而在于你是否真正理解自己写下的每一行代码背后的业务含义。把这些都搞明白了毕业设计这只拦路虎也就不难对付了。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进