ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

基于SpringBoot的房屋租赁系统设计与实现:从需求拆解到部署避坑

基于SpringBoot的房屋租赁系统设计与实现:从需求拆解到部署避坑 如果你正在为毕业设计选型发愁“基于SpringBoot的房屋租赁系统”绝对是计算机专业近五年最高频的选题之一。我之前带过不少学弟学妹做这类项目自己也亲手写过一个“基于SpringBoot的在线租房交易平台”所以对这个题目的坑和亮点都很有发言权。这类系统一般要覆盖租客、房东、管理员三类角色业务闭环包括房源发布、搜索浏览、预约看房、签约、账单支付等。它的好处在于业务场景足够真实技术栈主流SpringBoot MySQL 权限框架就能完整落地答辩时无论是功能演示还是技术解释都有充足发挥空间。这篇文章我就把从需求拆解、架构设计、核心模块实现到部署避坑的完整过程讲一遍就算你上半年刚开始学Java也能照着做出一个拿得出手的项目。1. 项目概览与需求拆解1.1 这个项目到底在解决什么问题一看标题里“智慧房屋出租管理系统”这种词感觉很高大上实际抽象出来就是个典型的租赁中介平台。租客想找房房东想租房平台负责撮合、担保和监督。抛开营销话术真正要做的核心事情有三件房源信息的管理、租赁流程的状态推进、租客房东之间的订单和账单流转。很多人做毕设只做了一堆增删改查却忽略了这个项目真正能体现后端能力的部分状态机、权限控制、并发下的房源锁定、合同快照。比如一套房子被租客发起签约另一套租客同时能否再抢房子出租后还能不能被下架这些边界问题才是答辩评委喜欢深挖的地方。所以做项目之前不要急着写代码先把业务规则想清楚这才是“智慧的”部分。1.2 三类角色的需求边界租客侧的核心动作是注册登录、搜索房源、收藏房源、发起预约看房、在线签约、缴纳押金和房租、提交报修、查看合同和账单。房东侧的核心动作是入驻成为房东、发布房源、管理自己名下房源、处理租客的看房预约、查看签约结果和收款账单。管理员侧的核心动作是用户管理、房源审核、处理租客举报和投诉、统计整体平台数据、发布平台公告。很多新手容易漏掉的其实是“房源审核”环节。房东发布房源后房源不能立刻上架必须经过管理员审核。这个需求在真实的租房平台上非常关键没有它系统很容易因为虚假房源而失去信任。答辩时老师最爱问“你如何避免恶意房源”如果你把审核状态机做进去了这个问题就迎刃而解。1.3 业务闭环怎么串起来一个完整的业务闭环大致是这样的租客注册 → 搜索房源 → 发起预约咨询 → 房东确认 → 线下看房 → 双方在线签约 → 支付押金和首期租金 → 合同生效 → 租客按月缴费/续租/退租 → 房源重新上架。这个链路里你至少需要四个核心实体用户、房源、预约/订单、合同。账单和支付可以挂在合同下也可以独立成表。关键在于业务状态要能流转而不是每个字段各自为政。比如房源状态有“待审核 / 可租 / 已出租 / 已下架”订单状态有“待受理 / 已确认 / 已取消 / 已完成”合同状态有“执行中 / 已到期 / 已解约”。这些状态的变化必须由后台逻辑控制不能随意跳转。2. 技术选型与架构设计方案2.1 为什么选Spring Boot作为项目地基Spring Boot的核心优势是“约定优于配置”。它对Spring生态做了一次巨大的简化以前写Spring MVC需要一堆XML配置现在一个SpringBootApplication注解就能启动。对于房屋租赁这种中小型系统它能在几分钟内搭好可运行的骨架非常适合学生在有限时间内完成。另一个很重要的原因是社区生态成熟。遇到任何报错搜索引擎上基本都有现成的解决方案。Spring Boot自带内嵌Tomcat部署时打成一个jar包就能跑这对想省事的同学来说非常友好。再加上它和Spring Security、Spring Data JPA的整合度极高实现权限和数据库操作几乎不需要额外配置开发效率拉满。2.2 配套技术栈怎么选不踩坑这是做毕设时最纠结的部分。我先给出一套稳妥的组合JDK 1.8 / OpenJDK 17均可但建议用1.8资料多Spring Boot 2.7.x别用最新的3.x作为学习项目迁移成本高MySQL 5.7/8.0不建议用Oracle环境太重持久层Spring Data JPA 或 MyBatis-Plus两者二选一前端Vue 2 Element UI或者用Thymeleaf做服务端渲染权限方案Spring Security JWT或自己写拦截器 Redis缓存Redis可选作为加分项如果你更看重快速开发和实体映射选Spring Data JPA它可以通过方法名直接生成SQL开发效率是真的高。如果你熟悉SQL想精确控制复杂查询用MyBatis-Plus更顺手。我的建议是时间紧就用JPA时间充裕想展示SQL功底就用MyBatis-Plus。答辩时只要你能说清楚为什么选它至少不会在这个环节失分。2.3 数据实体关系与关键字段设计数据库设计是这类项目的灵魂。我见过太多人把房源价格用double存结果算费用时出现0.30000000000000004这类精度问题非常尴尬。我们来看一套比较合理的核心表结构表名关键字段说明userid, phone, password, role, status用户表role区分租客/房东/管理员houseid, owner_id, title, city, address, price, area, status房源表status表示待审核/可租/已出租/下架bookingid, house_id, tenant_id, status, appoint_time预约看房订单表contractid, house_id, tenant_id, owner_id, rent_start, rent_end, deposit, rent, status合同表存业务快照billid, contract_id, amount, due_date, pay_status账单表按月生成需要注意几个细节价格字段建议用BigDecimal数据库中对应decimal(10,2)如果不想用BigDecimal可以统一转成“分”存储用Long类型展示时再转换。手机号、用户名必须加唯一索引。房源表要建city和status联合索引因为搜索时经常按城市状态过滤。合同表里最好保存一份“快照”就是把签约那一刻的房价、面积、房东信息、租客信息都冗余存进去。因为以后房源可能改价、下架甚至删除但历史合同不能跟着变。这个快照设计是很多商业系统的通用做法提前做了答辩时绝对能加分。3. 核心功能模块的实现思路3.1 房源发布、审核与搜索排序逻辑房源发布不是一个简单的表单提交。房东填完信息后系统要校验字段比如标题长度、面积是否为正、价格是否合理、地址是否完整。校验通过后房源状态设为“待审核”只有管理员审核通过后房源才在C端展示。搜索功能看起来简单但要做得舒适还是有不少细节。我建议先实现最基础的过滤条件城市、区域、租金区间、户型、面积。有了这些之后可以再考虑排序比如按价格升序、按发布时间降序。如果想更进一步提升搜索体验可以考虑用MySQL全文索引但要注意中文分词的问题。暂时用LIKE %关键词%做模糊搜索也完全够用。房源的上下架逻辑要注意和合同状态关联处于“执行中”合同下的房源不能被房东简单下架。我写过一个版本房东点击下架时后台检查该房源是否有未结束的合同如果有就拒绝并提示“当前有生效合同无法下架”。这个逻辑非常容易被追问做进去了就是亮点。3.2 预约订单状态机与签约流程设计预约看房建议单独建一张booking表状态有待受理、已确认、已取消、已完成。租客发起预约后房东点击确认双方确定看房时间。这个流程中取消操作可以由租客发起也可以由房东发起但已完成的预约不能再取消。签约流程要复杂一些。租客确认要租这套房可以先创建一张合同草稿合同里写入租赁时间、租金、押金、付款方式。然后进入“待租客确认”状态之后“待房东确认”双方确认后进入“待付款”状态。租客支付押金和首月房租后合同状态变为“执行中”。这一步相当于把电商里的“订单确认收货”搬到了租房场景中。我踩过一个坑直接用合同表去更新状态结果被并发请求重复提交生成了两条相同的合同。解决办法有两个一是前端按钮防止重复点击二是给合同表增加唯一业务编号例如“租客ID房源ID起租日期”在数据库层面做唯一约束插入时捕获异常。第二种才是真正可靠的方案。3.3 支付、押金与账单周期管理租房交易平台不能真的接入微信支付宝但不妨碍你把支付的流程设计完整。我建议用“模拟支付”租客点击支付后弹出一个支付确认框点击“确认支付”就把账单状态置为“已支付”同时写一条支付流水记录。这样既展示了业务完整性又避开了真实支付网关的复杂操作。押金和首期房租在合同生效后一次性生成账单之后每个月按照合同起止日期自动生成租金账单。自动生成可以用定时任务Scheduled每天凌晨检查一遍合同列表把还没生成的当期账单补上。账单逾期怎么办我加了一个“逾期标记”超过截止日期仍未支付就自动把账单状态改为“已逾期”同时更新租客的信用分。这里有一个小技巧账单金额计算使用BigDecimal不要直接double相加减。比如房租是3000元/月租期从9月15日到12月14日可能出现不满一个月的情况。最简单的方法是按月固定生成不处理天级分摊如果坚持要计算可以统一按月30天折算但一定要在代码里写清楚计算规则。3.4 用户权限与后台管理设计权限这块我的建议是在Spring Boot中使用Spring Security JWT或者自己写一个基于拦截器的Session方案。选择前者的好处是现代感强前后端分离时前端拿到Token后可以很自然地在请求头携带选择后者的好处是代码门槛更低容易理解。我自己的项目采用的是Spring Security JWT核心思路是用户登录成功后签发一个带角色信息的Token后续请求通过信息安全过滤器校验。接口上用PreAuthorize(hasRole(ADMIN))限制管理员接口。需要注意的是JWT不包含过期时间会变成永久令牌我一般设置24小时过期并在Redis中记录Token状态注销时把Token加入黑名单。后台管理模块不需要单独建一个SpringBoot工程而是可以复用相同的后端接口前端根据角色来显示不同的菜单。比如管理员能看到“房源审核待办”房东看不到。这里最怕有人把审核接口写漏了权限校验直接暴露在公网上任何人调用都能把房源偷偷上架。这类问题在代码审查时就要重点盯住。4. 实操步骤从0到1搭建与实现4.1 初始化项目结构与依赖配置在IDEA里打开Spring InitializrGroup填com.exampleArtifact填renting依赖选择以下这几个Spring Web、Spring Data JPA、MySQL Driver、Validation、Lombok、Spring Boot DevTools、Spring Security。如果不想用JPA就把Spring Data JPA换成MyBatis-Plus。这里我展示用JPA的版本。创建完工程后第一步改pom.xml里Spring Boot版本为2.7.x确保稳定性。然后修改application.ymlserver: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/renting?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: ddl-auto: update show-sql: trueddl-auto: update在开发时挺好用但上线前建议改为validate或使用Flyway管理建表语句。4.2 核心代码片段实体与业务接口建一个House实体我习惯用Lombok省略getter/setterEntity Table(name house) Data public class House { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; Column(nullable false) private Long ownerId; Column(nullable false, length 100) private String title; Column(nullable false) private BigDecimal price; Column(nullable false) private Integer area; Column(nullable false, length 50) private String city; private Integer status; }再写一个Service方法处理房东发布房源。注意状态默认为0待审核同时要做几个简单的参数校验Service RequiredArgsConstructor public class HouseService { private final HouseRepository houseRepository; Transactional public House publish(HouseRequest request, Long ownerId) { if (request.getPrice().compareTo(BigDecimal.ZERO) 0) { throw new BizException(租金必须大于0); } if (request.getArea() 0) { throw new BizException(面积必须大于0); } House house new House(); house.setOwnerId(ownerId); house.setTitle(request.getTitle()); house.setPrice(request.getPrice()); house.setCity(request.getCity()); house.setArea(request.getArea()); house.setStatus(0); return houseRepository.save(house); } }这样就完成了最基础的发布逻辑。实际项目中还需要把request里的字段全部映射进去尤其要注意地址、户型和描述信息不能少。4.3 联调、打包与本地部署前后端分离时后端需要开启跨域。可以写一个配置类Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE) .allowedHeaders(*); } }联调时统一返回结构体我用的是{ code, message, data }并配合全局异常处理器RestControllerAdvice这样前端处理逻辑会舒服很多。部署很简单本地项目根目录执行mvn clean package然后在target目录下得到一个jar包运行java -jar renting-0.0.1-SNAPSHOT.jar。注意要先启动MySQL同时确认数据库renting存在。如果想给答辩老师在线演示可以把jar包部署到云服务器上但要注意配置数据库的连接地址并把ddl-auto改为validate。5. 常见问题与坑点实录5.1 数据库字段设计的典型坑我见过无数同学在金额字段上踩坑直接用double不算还喜欢把日期存成varchar结果排序一塌糊涂。建议如下金额用BigDecimal或整型分日期统一用LocalDateTime状态值用Integer并配套枚举类。还有一点不要把所有表的主键都叫id又到处用ManyToOne级联删除。租房系统里房源和合同之间应该保持逻辑关联不能因为删除房源而导致历史合同被删掉。所以外键关系最好“弱化”用houseId这种普通字段保存关联而不是JPA里强关联关系。这样删除数据时更安全也更容易理解。5.2 订单状态更新中的并发问题系统一旦上线并发问题就来了。最典型的是同一套房被两个租客同时签约。解决方法有很多我推荐最简单的在Service方法上加Transactional并在查询房源时使用悲观锁也就是SELECT ... FOR UPDATE。在Spring Data JPA里可以这么写Lock(LockModeType.PESSIMISTIC_WRITE) Query(select h from House h where h.id :id) House findByIdForUpdate(Param(id) Long id);这样这两个租客同时进来时第二个就会等到第一个事务提交后再读取房源状态已经被改为“已出租”于是失败。这种方法虽然会导致数据库行锁但对毕设级别的并发量来说完全足够。另一个问题是重复创建合同。我最终方案是在contract表里加了一个biz_no字段定义为tenant_id house_id rent_start的唯一索引。插入时捕获重复异常并提示“您已预约过该房源”这样逻辑上非常干净。5.3 答辩时容易被追问的边界场景老师经常会问“租客退租之后房源状态什么时候恢复”如果你只设计了合同状态没有联动房源状态就答不上来。建议在处理退租逻辑时显式地把house.status改为“可租”并且做一次数据校验确保该合同确已归于终止状态。还会问“房东可以删除已经签约的房源吗”答案是不行。需要做关联检查任何后端接口中删除房源前先判断该房源是否存在执行中的合同若存在则抛出异常。这个判断逻辑尽量写在Service层不要依赖前端隐藏删除按钮。最后我建议增加一些提升体验的小功能登录验证码、房源图片上传、后台统计报表、操作日志记录。哪怕只是最简单的“最近浏览记录”也会让系统显得完整。图片上传可以存本地目录再配置静态资源映射不要真把图片存进数据库变成byte[]那是很经典的反模式。我个人做了这么多年毕业设计辅导最大的感受是房屋租赁系统虽然不算复杂但它是少有的能把Web开发的方方面面都串起来的题目。它迫使你思考权限设计、业务状态流转、数据一致性甚至还有一点并发控制。把这些点都打磨好不仅能让毕业设计顺利通过甚至会对后续工作面试都有帮助。最后再分享一个小技巧答辩前把数据库里预置的房源数据做得丰富一点图片尽量用真实风格的然后保持测试环境干净演示时只走一条完整流程比临时乱敲数据或者现场整理数据的效果好太多。
RELATED READING

延伸阅读

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