
1. 为什么房产租赁管理系统值得自己动手写一套先说句实在话市面上现成的房产租赁管理系统不少有开源的也有商业的但多数要么太重、要么太老真到了课程设计、毕业设计或者个人项目练手的时候你会发现还是自己从零搭一套更靠谱。我写这套基于Spring Boot的房产租赁管理系统最核心的出发点就三个技术栈主流、业务场景清晰、可扩展性强。Spring Boot在Java领域是什么地位不用多讲几乎所有Java岗位的招聘要求里都有它而房产租赁这个业务天生就带着房源管理租客管理合同管理账单管理这几大核心模块拿来练手再合适不过了。这套系统做完之后你手里能拿到的东西是完整的可运行的源码、初始化好的数据库脚本、以及一份能讲清楚设计思路的项目文档。换句话说它不是给你看个Demo就完了而是能让你顺着代码把整个业务逻辑捋一遍然后有能力自己改、自己扩。适合谁来看如果你是正在做Java课程设计的学生或者准备毕业设计想选个实用性强的题目再或者刚学完Spring Boot想找个完整项目练手巩固这篇文章都值得你花几分钟读完。我会把系统设计、数据库建模、核心功能实现、部署运行、文档编写这些环节全部拆开讲顺带把我实际开发中踩过的坑也一并说清楚。2. 项目整体架构与核心模块划分2.1 技术选型为什么是Spring Boot MyBatis Plus MySQL这套系统的技术栈我选了三个主力Spring Boot 2.x作为基础框架MyBatis Plus作为ORM框架MySQL作为存储数据库。前端用的是Thymeleaf模板引擎加AdminLTE后台模板这套组合在做管理类系统时真的非常顺手。选Spring Boot的原因不用多说自动配置、起步依赖、内嵌Tomcat这三个特性就能省掉一大堆繁琐的配置。以前用Spring MVC写项目光配置文件就能写一上午Spring Boot直接靠注解和约定就解决了。MyBatis Plus则是MyBatis的增强工具它最大的价值就是单表操作不用写SQL。房产租赁系统里有大量的单表CRUD比如房源信息的增删改查、租客信息的管理用MyBatis Plus的IService接口和BaseMapper基本就是调用现成方法的事。复杂查询再自己写XML灵活性一点没丢。MySQL不多讲了个人项目、中小型系统的最佳选择免费、稳定、资料多。三层架构上我用的是标准的Controller-Service-Mapper分层清晰每层职责单一这在新手写项目时特别重要因为一旦出了bug你能快速定位问题出在哪一层。2.2 功能模块拆解七大模块覆盖租赁业务全流程这套系统在功能设计上不是随便凑的而是按照房产租赁业务的真实流程来规划的。整个系统我拆成了七个模块每个模块都有明确的业务边界用户管理模块负责登录用户的账号管理包括管理员和普通操作员两种角色用不同权限区分操作范围。密码加密用的是MD5加盐虽然不是最强的方案但在这个场景下够用且实现简单。房源管理模块房产租赁的核心数据源包括房源编号、所在小区、楼栋、房号、面积、户型、朝向、租金单价、房源状态待租/已租/下架。这里我额外加了一个房源图片字段保存的是图片上传后的访问路径前端列表页可以直接展示缩略图。租客管理模块管理租客的基础信息和联系方式。这里有个设计细节我把租客表和租赁合同表分开设计因为一个租客理论上可以有多条租住历史记录如果混在同一张表里数据会非常冗余。合同管理模块租赁业务的核心环节涵盖合同编号、起止日期、租金、押金、付款方式等关键字段。合同状态我设计了待生效、生效中、已到期、已退租四种方便运营人员跟踪每份合同的实时状态。账单管理模块根据合同自动生成租金账单支持手动录入水费、电费、物业费等附加费用并记录每笔账单的缴纳状态。这里的核心逻辑是生成账单时自动带上当前时间并和合同的起止日期关联。报修管理模块租客发起报修管理员进行派单、处理、反馈结果。这个模块虽然不算核心但它在业务流程上补齐了租后服务的闭环让整个系统看起来更完整。统计报表模块对房源出租率、租金收入、合同到期提醒等数据进行统计并在首页以图表形式展示。我用的是ECharts通过接口返回JSON数据前端动态渲染。模块拆完之后整个项目的代码包结构也顺势确定了controller、service、mapper、entity、dto、vo、config、common、utils九个包每个包职责明确新人拿到代码后能很快找到对应的位置。3. 数据库设计的核心细节与建模思路3.1 核心表结构十张表怎么覆盖整个租赁业务数据库是这套系统的地基。我设计的时候一共建了十张表表结构直接决定了业务逻辑能跑多顺。这里拿几张核心表重点说一下。用户表(sys_user)字段包括用户ID、用户名、密码、真实姓名、手机号、角色类型、创建时间。角色类型我用的是tinyint类型0代表管理员1代表操作员比用字符串存admin这种方式更省空间查询效率也更高。房源信息表(house_info)这个是整个系统数据量最大的表。核心字段包括房源编号、小区名称、楼栋号、单元号、房号、建筑面积、户型几室几厅、朝向、所在楼层、总楼层、租金月、押金、房源状态、备注、创建时间。很多新手设计时会忽略所在楼层/总楼层这种字段但真实租房场景里这是很关键的筛选条件必须拆成两个字段存。租客信息表(customer_info)字段包括租客ID、姓名、性别、身份证号、手机号、紧急联系人、紧急联系人电话、备注。身份证号我建议加上唯一索引因为同一个租客如果重复录入后面合同和账单都会乱套。租赁合同表(lease_contract)这是业务逻辑最复杂的表。字段包括合同ID、合同编号、房源ID、租客ID、起租日期、结束日期、租金月、押金、付款方式月付/季付/半年付/年付、合同状态、备注、创建时间。合同编号我用的是业务规则生成HT 年月日 三位流水号比如HT20250115001这样光看编号就能知道合同的签订日期。另外几张表——账单表、报修表、操作日志表、菜单权限表、角色权限表和数据字典表也都按同样的规范设计。每张表我都统一加了create_time和update_time两个字段并设置自动填充这块用MyBatis Plus的MetaObjectHandler就能实现后面代码部分会细说。3.2 表关系与索引设计外键要不要建索引怎么加先说外键的问题。我在这套系统里没有建立任何物理外键约束而是通过逻辑外键也就是普通的索引字段来维护表间关系。原因有两层一是物理外键在删除数据时约束太多比如你要删一个房源如果它有合同关联外键会直接报错打断操作这在真实的业务系统里体验很差二是物理外键在数据量大后会影响写入性能。所以在实际开发中绝大多数团队都会选择逻辑外键靠代码层面控制数据的完整性。索引方面我给每张表都加了必要的索引原则很简单查询条件里经常出现的字段就建索引。比如房源信息表的小区名称房源状态组合索引、租赁合同表的房源ID合同状态组合索引、租客表的身份证号唯一索引。组合索引的顺序也很讲究区分度高的字段放前面这样才能最大化索引效率。数据库脚本我写了两份一份是结构脚本建表SQL一份是初始化数据脚本插入管理员账号、房源类型字典、菜单数据等。第一次部署时先执行结构脚本再执行数据脚本系统就能直接跑起来了。初始化数据里我造了二十来套房源和几个租客的模拟数据方便前端页面展示效果。3.3 字典表设计状态值不硬编码后期改起来才不痛苦这里分享一个我踩过坑后的经验教训。最初写系统时房源状态、合同状态这类字段我直接在代码里用数字硬编码0代表待租、1代表已租页面上用switch-case去判断显示中文。后来需求调整要给状态加一个已下架就得改Java代码、改页面、重新部署非常被动。第二版我引入了数据字典表(sys_dict)专门存这类枚举值。表结构很简单字典ID、字典类型编码、字典项名称、字典项值、排序号。比如字典类型编码是house_status下面就有三条记录待租0、已租1、已下架2。查询页面时先用字典类型编码查出所有状态项再渲染成下拉框或标签。改状态值只需要改数据库重启都不用重启配合缓存的话这才是租务系统该有的灵活度。4. 核心功能实现登录鉴权、房源管理与租赁流程闭环4.1 登录鉴权拦截器加Session为什么没上Spring Security登录鉴权这块我做了个取舍。Spring Security当然更专业功能也更强但对这个体量的系统来说有点重而且配置门槛高新手容易懵。所以我选择了拦截器 Session 自定义注解这套轻量方案。具体实现逻辑是用户提交用户名和密码Service层先按用户名查出用户再用MD5加盐的方式校验密码比对通过后把用户信息放进Session同时写一条操作日志。然后注册一个WebMvcConfigurer配置拦截路径和放行路径。放行路径包括登录页面、静态资源CSS/JS/图片、以及登录接口本身其余所有路径都走拦截器。拦截器里做的事很简单从Session里取用户信息取不到就重定向到登录页。为了防止静态资源被拦截导致页面样式丢失我特地在配置里把/static/**、/templates/**这种路径加了排除。不用Spring Security还有一个考虑如果后面前后端分离Spring Security那套SecurityFilterChain跟JWT配合起来才有优势而单体应用内用Session天然就安全简单直接完全够用。这套系统定位就是单体应用所以没有必要给自己增加不必要的复杂度。4.2 房源管理的完整实现从列表查询到上下架房源管理模块是纯CRUD但写起来也有讲究。列表页我用了分页查询加条件筛选支持按小区名称、房源状态、户型、租金区间四个维度组合查询。这里用MyBatis Plus的LambdaQueryWrapper来构造动态条件代码清爽得多LambdaQueryWrapperHouseInfo wrapper Wrappers.lambdaQuery(); wrapper.like(StringUtils.isNotBlank(communityName), HouseInfo::getCommunityName, communityName); wrapper.eq(houseStatus ! null, HouseInfo::getHouseStatus, houseStatus); wrapper.eq(StringUtils.isNotBlank(houseType), HouseInfo::getHouseType, houseType); wrapper.between(minRent ! null maxRent ! null, HouseInfo::getRent, minRent, maxRent); wrapper.orderByDesc(HouseInfo::getCreateTime); PageHouseInfo page houseInfoService.page(new Page(pageNum, pageSize), wrapper);这套写法的好处是条件不传时自动忽略不用写一堆if判断再手动拼SQL。新增和编辑共用同一个表单页面提交时用DTO接收参数通过BeanUtils.copyProperties转成实体类再入库。房源状态改变的操作我单独设计了接口比如下架操作会把房源状态置为2并且会检查该房源是否存在未到期的有效合同如果有就不允许下架提示该房源有生效中合同无法下架。这个业务校验很关键因为一个正在出租的房子是不能被随意下架或删除的。4.3 租赁流程闭环合同创建如何联动房源状态与账单生成租赁业务的核心闭环我个人认为是合同模块。它牵一发动全身影响房源状态、账单数据和统计报表。签一份新合同时的完整流程是这样的第一前端选择房源时只能选sale_status0待租的房源已经租出去的在选择列表里根本不会出现这从入口上就堵住了房源冲突的可能。第二提交合同信息时Service层开启事务Transactional注解先插入合同记录再更新房源状态从待租变成已租状态变更直接通过UpdateById完成。第三根据付款方式自动生成账单。这一步是账务管理的核心逻辑。比如合同是季付租期一年就生成4条租金账单每条的金额等于月租金乘以3。账单的应缴日期按合同起租日期逐期累加三个月。生成的账单状态统一为待缴纳随合同一起生效。退租流程正好相反先校验是否存在未缴纳的账单有的话提示先结清费用然后把合同状态改成已退租对应房源状态改回待租。整套流程下来每笔房屋的出租历史和每笔收款记录都有据可查这是系统查漏补缺的基本功。4.4 统计报表接口出租率如何计算图表怎么渲染统计报表模块我用ECharts做了首页看板。出租率的计算逻辑在Service层实现已出租房间数除以总房间数再乘以100考虑到部分房源可能下架分母只算上架中的房源数量这样数字才更有参考意义。近期租金收入则是把账单表中近六个月的实收金额按月份分组求和返回一个月份数组加金额数组的结构给前端。这里有个小坑必须提醒SQL里按月份分组统计时数据库字段是datetime类型一定要用DATE_FORMAT函数转成%Y-%m格式再分组否则同样的月份因为时间不同会被拆成多组数据就对不上了。这个Bug我第一次写时排查了半个多小时最后发现是分组粒度的问题。首页的统计卡片我放了四块在租房源数、待租房源数、本月应收租金、本月实收租金。下面接一张近六个月租金趋势折线图和一个不同户型房源占比的饼图。后端提供JSON接口前端用AJAX拉数据ECharts初始化渲染整个过程非常标准以后要扩展其他图表也就照这个路子走。5. 部署运行全流程与文档编写要点5.1 从源码到跑起来一条龙部署说明这套系统的部署我按本地开发环境来说明因为绝大多数人拿到源码后第一件事就是在自己电脑上跑通。前提准备好三样东西JDK 1.8、Maven 3.6、MySQL 5.7。第一步导入数据库。用Navicat或者命令行执行源码目录下sql/文件夹里的housing_db.sql这个脚本包含建库建表和数据初始化。注意脚本开头有CREATE DATABASE IF NOT EXISTS housing_db所以会自动建库不用手动先建库这点对新手特别友好。第二步改配置。打开application.yml把数据源部分改成你自己的spring: datasource: url: jdbc:mysql://localhost:3306/housing_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 你的数据库密码配置文件里做了多环境切换默认走dev环境。第三步启动项目。IDEA里直接运行HousingApplication.java的main方法控制台出现 Started HousingApplication 字样就代表启动成功。浏览器访问http://localhost:8080默认管理员账号是 admin密码 123456。整个过程顺利的话不到十分钟。如果启动报错九成概率是数据库密码写错或MySQL版本不兼容注意MySQL 8.0以上需要修改驱动为com.mysql.cj.jdbc.Driver同时pom里引的驱动版本也要跟着升级。5.2 后端统一返回格式与全局异常处理提升调试效率为了让前后端配合更顺畅我封装了一个统一的返回对象Result包含code、message、data三个字段。成功时code为200失败时code为500。所有Controller接口都返回这个对象前端的AJAX就统一在success回调里判断code再做后续处理。代码风格保持一致接口调错一眼就能从code看出问题在哪。全局异常处理用的是RestControllerAdvice配合ExceptionHandler。业务异常统一抛出自定义的BizException然后由一个全局异常处理器兜底返回错误信息。这样写的最大好处是Service层不用每个方法都try-catch包裹代码干净太多了。数据库异常、参数校验异常也分别有对应的处理器确保任何情况下前端拿到的都是一个格式完整的JSON不会出现直接把500错误页甩给页面的尴尬情况。5.3 文档怎么写才算合格从需求分析到接口文档项目文档的价值很多人低估了。源码写得再清晰没有文档辅助别人接手时还是要花大量的时间去读代码。我这份文档包含了五大部分项目概述与需求分析、数据库设计说明、核心功能实现说明、部署运行指南、接口文档。需求分析这块重点写清楚系统的使用角色和每个角色的核心业务流程数据库设计这块除了表结构说明要画出ER图哪怕是用ProcessOn画的简版都行有图比纯文字直观一百倍核心功能说明按模块写每个模块描述业务逻辑和数据流转接口文档我用的是Apifox导出的格式包含URL、请求方式、请求参数、返回示例四个要素比手写表格省事得多而且改动后重新导出就行。写文档有个经验之谈边开发边写不要等项目完工再补。项目开发到一半时的记忆是最鲜活的等所有功能做完了再回头补文档很多设计初衷和细节你已经想不起来了写出来的东西质量会大打折扣。6. 实操避坑指南我踩过的那些坑希望你绕开6.1 日期时间字段的时区问题这是Spring Boot项目最常见的坑之一。数据库连接串里不加serverTimezoneAsia/Shanghai在MySQL 8.0版本下默认会使用服务器时区如果你的系统时区不是东八区查询出来的时间会差八个小时。我第一次部署在云服务器上所有账单日期显示都比实际早八小时排查了半天才想到是时区问题。解决方案就在连接URL上加serverTimezoneAsia/Shanghai同时在实体类日期字段上使用JsonFormat(patternyyyy-MM-dd HH:mm:ss, timezoneGMT8)注解双保险确保无论后端还是前端时间展示都不会出错。6.2 MyBatis Plus自动填充失效需要手动指定填充策略MyBatis Plus的字段自动填充比如自动维护create_time和update_time是个非常好用的功能但很多新手会遇到我配置了却不管用的问题。原因基本有两个一是实体类字段上忘了加TableField(fill FieldFill.INSERT)和TableField(fill FieldFill.INSERT_UPDATE)注解二是自定义的MetaObjectHandler实现类没有交给Spring管理漏加了Component注解。我在代码里把这两处都补齐了实体类注解加策略声明MetaObjectHandler类注成Spring Bean同时关闭了Banner输出启动日志就清爽多了。踩过这个坑之后我再写新项目都会第一时间检查这两处配置省了不少调试的时间。6.3 文件上传大小限制与前台无法访问的问题房源图片上传这块Spring Boot默认上传大小限制是1MB动不动就报Max upload size exceeded。我在配置里把它调大到了10MBspring: servlet: multipart: max-file-size: 10MB max-request-size: 10MB同时要注意上传文件保存到本地磁盘路径后要用虚拟路径映射才能让前端直接通过URL访问到图片。我配置了/upload/**映射到file:D:/housing/upload/Windows环境示例这样前端就可以直接用 http://localhost:8080/upload/xxx.jpg 访问到图片不需要再写文件流输出的接口配置成本低效果立竿见影。6.4 数据库连接池耗尽Tomcat默认值为啥要改系统刚上线时跑得很顺畅但压测之后发现偶尔有请求卡死的情况查日志发现是数据库连接池没连上。Spring Boot 2.x内置的HikariCP默认maximum-pool-size是10并发上来后会不够用。我把它改成了30同时设置了最小空闲连接数5连接超时时间30秒。spring: datasource: hikari: minimum-idle: 5 maximum-pool-size: 30 connection-timeout: 30000这个参数很多人开发时根本感觉不到因为本地开发并发量低够用就行但一旦上了服务器被多个人同时访问问题就会暴出来。建议做项目时直接把参数调到一个合理范围免得到时候被人问系统卡了怎么办再回来查。7. 源码使用指南与二次开发扩展思路7.1 拿到源码后从哪个入口开始读拿到源码后不要急着到处点按我的阅读顺序来效率会高很多先读数据库脚本搞清楚有哪些表和哪些关键字段再读实体类字段和表对应上接着读Controller层了解对外开放了哪些接口然后读Service层理解每个接口背后的业务逻辑最后读配置类和前端页面把前后端串联起来。这套顺序的本质是从数据到接口再到业务的自顶向下方式跟很多人习惯的从Controller开始点进去看完全不同。先掌握数据模型就能快速理解为什么接口要这么设计。比如合同模块要新建合同你在数据库里看到lease_contract表和house_info表有关联字段自然会想到代码里大概会怎么处理房源状态再去看代码就有的放矢了。源码里我也写了比较详细的注释关键业务方法都有中文注释说明逻辑。包名和类名也按规范命名不会有那种看了半天不知道是干什么用的类。7.2 可以往哪些方向扩展让项目更有竞争力如果你拿这套系统做毕业设计只做基础功能说实话竞争力不够面试官问你有什么亮点时回答会很苍白。这里我给你几个可落地的扩展方向工作量可控但加分明显方向一接入消息提醒。合同到期前7天自动给管理员发送提醒邮件或短信通知。可以用Spring Task写个定时任务每天扫一遍合同表把即将到期的合同查出来发送提醒。技术点涉及定时任务、异步处理、邮件发送都能往简历上写。方向二做数据可视化大屏。把出租率、租金收入、房源分布等信息用ECharts做成看板比普通列表页直观太多。这种可视化在答辩和面试时展示效果很好。方向三改成前后端分离架构。基于现有的API接口再写一套Vue Element UI的管理前端做成前后端分离部署时Nginx托管前端静态资源Spring Boot只提供JSON接口。这一步最贴近生产环境实际模式也是面试官最看重的能力。方向四引入Redis缓存。把数据字典、热门房源列表这些读多写少的数据缓存到Redis降低数据库压力。可以记录缓存命中率、设计缓存更新策略这一套思路本身就是面试常考题。扩展的方向取决于你的目标和时间我建议至少做一个扩展让项目有差异化亮点光靠能登录、能增删改查是很难在众多项目中让人眼前一亮的。8. 最后再分享一点体会做这套系统前后加起来我断断续续花了两周多周末集中写代码平时晚上改改Bug、调调样式。最大的感受是写一个能跑的项目容易写一个结构清晰、别人看得懂、自己也愿意扩展的项目靠的是规范和耐心。如果你现在刚拿到这套源码我建议你不要只想着把项目跑起来交差而是花一个晚上把所有代码通读一遍改掉一些你不喜欢的地方比如加个字段、换个展示样式这个过程才是真正长本事的时候。数据库设计文档里的设计说明也值得认真读一遍那是整套系统里最能体现设计思维的部分。真正把这个项目吃透之后你会发现Spring Boot的套路就那些配置、实体、Mapper、Service、Controller、页面万变不离其宗。以后再接到新的管理系统需求对你来说就是换一套业务字段而已。这套认知比源码本身值钱得多。