ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Java房屋租赁系统开发:基于Spring Boot与MyBatis Plus的全流程实战

Java房屋租赁系统开发:基于Spring Boot与MyBatis Plus的全流程实战 简介面向计算机专业毕业设计场景的基于Java的房屋租赁系统设计与实现文档可帮助读者掌握B/S架构下利用JSP、MySQL开发租赁平台的核心流程。内容涵盖需求调研、可行性分析、数据库实体及表设计、管理员与用户功能模块实现、系统测试等章节并附有目录和摘要适合用作课程设计或毕业设计的直接参考。资源为单个docx文件包体大小3.86MB文档结构清晰、内容紧凑。目前已有51人学习浏览说明该方案具备一定参考价值。通读后可系统理解房屋租赁平台从需求分析到落地测试的完整开发思路对撰写规范的系统设计文档亦具有借鉴意义。1. 基于 Java 的房屋租赁系统这个题目到底在考察什么如果你正在纠结毕业设计选题又不想碰那些烂大街的商城系统房屋租赁系统是个很稳的中间档业务规模不大但该有的东西一样不少——用户角色、房源管理、合同流转、账单统计、状态变更。它用 Java 技术栈实现时恰好能把 Spring Boot、MyBatis Plus、MySQL 这些主流工具串成一条完整的链路。做这个题不是在写 CRUD而是在练「把真实业务翻译成代码结构」的能力。适合 Java 基础尚可但没做过完整项目的人也适合想给简历里补一个能讲清楚业务闭环的项目的人。这个题做下来你对 Maven 依赖冲突、数据库外键设计、接口参数校验的理解会比你刷十套面试题都实在。2. 拆解房屋租赁系统的核心业务从需求文档到模块划分拿到题目先别急着建项目很多人的第一个误区就是直接打开 IDEA 生成 Spring Boot 项目然后开始写实体类。你连「租客退房之后合同要不要留底」「房源下架之后历史订单怎么显示」都没想清楚写出来的代码大概率会在答辩时被问垮。做系统设计第一步永远是先把业务流程掰碎了看。2.1 房屋租赁系统必备的六大功能模块我一般会按角色和业务对象两条线去切。角色线上系统至少要分成管理员、房东、租客三种账号。管理员管审核和全局统计房东管房源发布和合同签署租客管找房、预约看房和支付房租。业务对象线上核心是房源、合同、账单这三张王牌再加上用户、看房记录、公告通知这三张辅助表。具体到功能页面六个模块不能少用户管理注册、登录、角色分配、房源管理发布、编辑、上架下架、条件搜索、签约管理生成合同、状态流转、退租、账单管理生成房租账单、缴费记录、逾期统计、看房管理租客预约、房东确认、后台统计出租率、收入汇总、到期提醒。这里有一个选型理由为什么非要六个而不是四个因为合同和账单是租赁系统区别于普通二手交易平台的关键——合同管理训练你处理状态机账单管理训练你处理金额和时间计算这两块恰好是 Java 后端面试最爱深挖的点。2.2 用用例图和状态机把租赁流程固化下来设计阶段我会先在草稿纸上画两个图一个是用例图一个是合同状态机。用例图不用画得太规范但要把「谁、通过什么功能、达成了什么目的」标清楚。比如「租客通过搜索房源、发起预约、线下看房、线上签合同」这条链路画完你就知道 controller 层要暴露哪些接口了。合同状态机是这题的灵魂。我的习惯是给合同定义五个状态待签署、生效中、待退租、已结束、已作废。这五个状态之间的跳转关系必须用代码约束住合同待签署时租客能取消生效中时不能改价格待退租时系统要自动生成退租账单。很多人的实现里合同状态是随便更新的前端传个 status 字段就把状态改了这等于把业务规则漏洞摆给答辩老师看。用枚举加状态转换方法来实现每次变更都走同一个校验入口比到处写 if 判断靠谱得多。2.3 技术选型为什么 Spring Boot MyBatis Plus 是这类毕设的默认答案技术栈这块常见做法是 Spring Boot MyBatis Plus MySQL前端用 Vue 或者直接把 Thymeleaf 和 Bootstrap 拼一拼。Spring Boot 的好处是自动配置省心你不需要去折腾 Spring 的 XML 配置MyBatis Plus 则是为单表 CRUD 省了大量手写 SQL 的时间让你把精力集中在业务逻辑上。我给这套选型排个优先级如果你是急着自己做Spring Boot 3.x 配 MyBatis Plus 3.5.x 起步最快如果你想稳一点避免版本坑Spring Boot 2.7 MyBatis Plus 3.5.3 也是经典组合。为什么不推荐纯 JPA因为 JPA 对多表关联和复杂查询的学习成本更高而且很多 java 面试官默认你用的是 MyBatis你用 JPA 写出来的代码他们还得现问现看。为什么不推荐 SSHStruts 和 Hibernate 在现在的生产环境里已经很少见了学了属于给自己挖坑。记住毕设选题讲究的是一个「稳」字把主流工具链跑通比标新立异重要。3. 数据库设计是租赁系统的命门建表、关系和三范式实践如果你去问做过这类项目的老工程师十个里有九个会告诉你房屋租赁系统的代码写得好不好看是次要的数据库设计一塌糊涂那就全完了。房源、用户、合同、账单这几张表的关联关系决定了你后续写 SQL 是顺手还是痛苦。租房业务有大量「哪个房源已出租、哪个合同未付款、哪个租客逾期」的查询表结构建歪了这些问题每个都要多写两百行 Java 代码。3.1 核心表结构用户、房源、合同、账单、看房记录我挑五张核心表给你拆开看。第一张是用户表 user字段除了 username、password、phone 之外必须有一个 role 字段区分管理员、房东、租客。第二张是房源表 house包含 title、address、area、price_month、status 字段status 我用 tinyint 存 0 下架 / 1 上架 / 2 已出租不用字符串省空间还快。第三张是合同表 contract这是最核心的要存 house_id、tenant_id、owner_id、start_date、end_date、rent_month、deposit、status而且 start_date 和 end_date 必须用 DATE 类型后面我要专门讲为什么。第四张是账单表 bill存 contract_id、period_start、period_end、amount、status0 未缴 / 1 已缴 / 2 逾期、pay_time。第五张是看房表 visit存 house_id、user_id、visit_time、status0 待确认 / 1 已确认 / 2 已完成 / 3 已取消。这里有个容易犯的错误——看房记录看起来像日志有人就草率地不设外键结果查「某个租客看过哪些房」时要靠 Java 代码一层层循环慢得不行。正确姿势是给 visit 表的 house_id 和 user_id 建普通索引加外键约束让数据库帮你做完整性校验。3.2 用 MyBatis Plus 根据实体类生成建表 SQL 的加速姿势很多人在入门时被 Maven 依赖搞得心烦但 MyBatis Plus 有个特别好用的自动生成 SQL 的功能只要你的实体类写好了它能直接根据 Java 类的字段生成创建表的 SQL 语句。这个姿势在热词里被频繁搜到实际做起来也真能提速。先定义一个标准的房源实体类Data TableName(house) public class House { TableId(type IdType.AUTO) private Long id; private String title; private String address; private BigDecimal priceMonth; private Integer status; TableField(fill FieldFill.INSERT) private Date createTime; }这段代码里有几个点说一下。TableName(house)是 MyBatis Plus 用来把实体类和表名映射起来的如果你不想手动写映射注意表名默认会把驼峰转下划线所以类名 House 对应表名 house 没问题。TableId(type IdType.AUTO)表示主键自增适合 MySQL。TableField(fill FieldFill.INSERT)配合 MyBatis Plus 的 MetaObjectHandler 可以实现 createTime 自动填充省掉手动 set 那一行。写好实体类之后MyBatis Plus 有一个代码生成器插件它能读取你的实体类然后生成对应的建表 SQL。实际项目里我更推荐的方式是直接用mybatis-plus-generator反向生成但那是从表到代码的方向。如果你是从实体类到表MyBatis Plus 3.x 也提供了db-helper相关的能力不过最常见、最可控的做法是写一个测试类用DbTools或者直接通过BaseMapper配合db包下的工具获取建表语句。// 通过 MyBatis Plus 的 Db 工具获取实体对应的建表语句 public void generateCreateTableSql() { String sql DbTool.getCreateTableSql(House.class); System.out.println(sql); }DbTool这个组件在 MyBatis Plus 的com.baomidou.mybatisplus.extension.toolkit包里3.5.x 版本可用。执行完会在控制台打出一条完整的CREATE TABLE语句字段类型、长度、主键约束都帮你配好。这样做的价值在于你改实体类字段时不用再手工同步去改 SQL 脚本两者永远对得上。但要注意这种自动生成默认用的类型映射是通用规则比如 LocalDate 会映射成 dateBigDecimal 会映射成 decimal(10,2)如果你的业务需要 decimal(12,2) 或 varchar(128)得手动修改生成的 SQL不要迷信自动生成。3.3 关键业务字段的约束设计状态枚举、金额精度与时间戳状态字段我建议用数字枚举而不是字符串理由很简单数字比较快而且防止手滑把字符串写错。但数字的可读性太差你需要在 Java 端定义一个枚举类来对应比如HouseStatusEnum里面有OFFLINE(0), ONLINE(1), RENTED(2)。数据库里写注释Java 里写枚举双保险。金额精度是血泪经验集中区。price_month、deposit、amount 统统用decimal(10,2)Java 端用 BigDecimal绝不能用 float 或 double。浮点数在二进制里没法精确保存 0.1累计到几十条账单时误差就会暴露答辩时被问「为什么账单总额差了一分钱」就彻底翻车了。时间戳字段要区分两种用途业务时间用 DATE 存比如合同开始和结束日期记录时间用 DATETIME 存比如创建时间、支付时间。如果混用会有问题合同的开始日期 2025-06-01 你存成 DATETIME 也没毛病但查询 「今天到期的合同」 时边界值判断就麻烦了 — 23:59:59 和 00:00:00 要来回换算。用 DATE 类型Java 端对应 LocalDate逻辑清晰索引性能也好。4. 从零跑通项目Spring Boot 环境配置与最小可运行代码前面把设计说透了这一章直接动手。我不会带你从 Spring Initializr 点网页开始那个太慢。我给你的路径是建一个空目录用 Maven 骨架生成项目然后一步步把配置文件、启动类、实体、Mapper、Service、Controller 全部跑通。目标是让房子能发布、能搜索、能签约形成一个最小闭环。4.1 环境配置与项目骨架你已经装好了 JDK 1.8 或 JDK 17这没问题。用 IDEA 新建一个 Maven 项目然后在pom.xml里引入四个核心依赖spring-boot-starter-web、mybatis-plus-boot-starter注意版本要和 Spring Boot 匹配、mysql-connector-j、lombok。如果你是 Spring Boot 2.7.xMyBatis Plus 用 3.5.3如果你直接 Spring Boot 3.xMyBatis Plus 要换成最新版里的mybatis-plus-spring-boot3-starter坐标这是个很常见的坑。parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version /parent dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies配置文件的重点在application.yml下面这套是我反复验证过的spring: datasource: url: jdbc:mysql://localhost:3306/rent_house?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0serverTimezoneAsia/Shanghai必加不然 JDBC 连 MySQL 时会报时区错误。map-underscore-to-camel-case开了之后数据库的price_month才能自动映射到 Java 的priceMonth。logic-delete-field是配置逻辑删除的这样房源「删除」操作实际是 UPDATE deleted1还能保留订单历史这招在答辩时很加分。4.2 编写 Room 实体的增删改查接口房间实体其实就是前面定义的 House 类这里直接用 MyBatis Plus 的 BaseMapper 快速获得增删改查能力public interface HouseMapper extends BaseMapperHouse { // 自定义多表查询也写在这里 ListHouseVO selectHouseWithOwner(Param(status) Integer status); }Service 层我建议别直接用 IService自己写一个干净的接口Service public class HouseService { private final HouseMapper houseMapper; public HouseService(HouseMapper houseMapper) { this.houseMapper houseMapper; } public PageHouse searchHouse(String keyword, int page, int size) { LambdaQueryWrapperHouse wrapper new LambdaQueryWrapper(); wrapper.like(StringUtils.hasText(keyword), House::getTitle, keyword) .eq(House::getStatus, 1) .orderByDesc(House::getCreateTime); return houseMapper.selectPage(new Page(page, size), wrapper); } }LambdaQueryWrapper是 MyBatis Plus 的查询神器用方法引用代替字符串拼 SQL编译期就能发现字段名写错的问题。.like(...)的第一个参数是条件开关keyword 为空时这个条件自动忽略比手动拼 if 优雅很多。Page 对象是 MyBatis Plus 自带的分页模型传 page 和 size 就能自动 limit前提是你要在项目里配置一个分页插件Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }忘了配这个插件selectPage 返回的 total 永远是 0这是 MyBatis Plus 新手最容易碰到的玄学 bug。4.3 租房合同生成与状态流转接口实现合同生成不是一个简单的 insert它要做几件事校验房源状态必须是上架且未被租走校验租客和合同起止日期合法性然后写入 contract 表最后把 house 的状态改成已出租。这些操作必须放在同一个事务里否则合同建成了而房源状态没改系统就出现脏数据了。Transactional public ContractVO createContract(ContractCreateRequest req) { House house houseMapper.selectById(req.getHouseId()); if (house null || house.getStatus() ! 1) { throw new BizException(该房源不可出租); } if (!req.getStartDate().isBefore(req.getEndDate())) { throw new BizException(起止日期不合法); } // 计算押一付三的初始账单 BigDecimal firstBill req.getRentMonth() .multiply(new BigDecimal(3)) .add(req.getDeposit()); Contract contract new Contract(); contract.setHouseId(house.getId()); contract.setStatus(ContractStatus.PENDING_SIGN.getValue()); contractMapper.insert(contract); house.setStatus(2); // 已出租 houseMapper.updateById(house); // 返回合同号和首期账单金额 return new ContractVO(contract.getId(), firstBill); }注意Transactional一定不能少。很多同学写了这个方法但忘了加事务注解一旦 houseMapper.updateById 失败contract 已经 insert 成功房源被锁死这就是典型的「合同已建、房子也显示已租、但租客根本没签」 的生产事故。接口返回前生成首期账单把金额逻辑放在 Java 里而不是 SQL 里是为了方便做单元测试也方便以后调整计费规则。5. 房屋租赁系统避坑指南我在这类项目里踩过的 5 个雷这部分我直接把我做同类项目时翻过车的地方写出来按「现象 → 原因 → 解决」的格式给到你。每一条都是真金白银的教训提前看一眼能帮你省下好几个通宵。5.1 乱用 BigDecimal 导致金额计算翻车现象每月账单金额打印出来是 1199.999999999合同页面上金额显示成一长串小数。原因把 BigDecimal 和 double 做了混合运算比如rentMonth.multiply(BigDecimal.valueOf(price))里面混进了 double 变量。解决全链路统一 BigDecimal数据库字段 decimal(10,2)Java 属性用 BigDecimal前端传参用字符串或数字类型不要用双精度去过渡。BigDecimal.valueOf(0.1)才是 0.1new BigDecimal(0.1)是二进制近似值这两个坑要分清。5.2 时间比较用 String 造成合同到期判断失误现象合同到期提醒永远不触发或者提前好几天提醒。原因合同时间在数据库中建的 varchar 字段Java 端也用 String 比较比如2025-06-01.compareTo(2025-06-30)字符串比较在日期格式不统一时2025-6-1 vs 2025-06-01结果完全错乱。解决数据库 DATEJava 用 LocalDate查询到期合同时用SELECT ... WHERE end_date #{today}或end_date BETWEEN start AND end让数据库比较日期而不是字符串。5.3 级联删除把历史合同删没了现象管理员在后台删除一个房源结果这个房源相关的几十条历史合同全部消失了。原因外键设置了 ON DELETE CASCADE删除 house 时连带把 contract 删除。解决业务系统禁止物理删除一律逻辑删除。MyBatis Plus 配置 logic-delete-field 后deleted1 表示已删除这样合同表还能保留历史记录做统计。如果真要设计外键建议 ON DELETE RESTRICT让数据库拒绝删除有合同关联的房源。5.4 图片上传路径写死导致部署后房源图全部 404现象本地测试图片显示正常打包部署到服务器后所有房源图片打不开。原因代码里写了File.save(E:/upload/)或者static/upload/这种硬编码路径Windows 路径和 Linux 路径不兼容而且 Spring Boot 的 static 目录打 jar 后是只读的。解决文件上传路径做成配置项file.upload-dir用相对路径或绝对路径都行但一定要让外部存储目录和项目目录分开。对外访问用 WebMvcConfigurer 增加资源映射把/upload/**映射到本地目录。上传时只用 UUID 重命名别用用户原始文件名否则同名覆盖和中文乱码都能折腾你半天。5.5 分页查询没处理租期状态导致数据错乱现象搜索「可租房源」时已经过期但状态还是「上架」的房子也出现在结果里。原因只查了 house.status1没有关联查询合同时间导致合同已到期但房东没手动下架的房子一直挂着。解决搜索条件里加一个「合同未生效或已到期且没有未结束合同」用 NOT EXISTS 子查询把那些存在生效中合同的房源排除掉。这个坑在答辩时特别容易被当成「业务理解不深」的证据建议你早点写进需求分析里。6. 把毕设做成亮点接口性能优化与答辩前的验证清单做完基本功能之后如果你想让自己在毕设答辩里脱颖而出重点不在功能多而在于你能说出「为什么这么设计」。下面给两个能落地的加分技巧以及一套十分钟验证清单。6.1 用缓存扛住房源搜索的高频查询房源搜索是租赁系统流量最大的接口每次查询都要 join 几张大表压力全在数据库。我通常在搜索关键词变化不频繁的场景下给搜索结果加 Redis 缓存把搜索条件和分页参数拼成 key缓存搜索结果 5 分钟搜完直接走缓存数据库的压力瞬间降下来。public PageHouseVO searchWithCache(String keyword, int page, int size) { String key house:search: keyword : page : size; String cached stringRedisTemplate.opsForValue().get(key); if (cached ! null) { return JSON.parseObject(cached, Page.class); } PageHouseVO result houseMapper.searchPage(keyword, page, size); stringRedisTemplate.opsForValue().set(key, JSON.toJSONString(result), 5, TimeUnit.MINUTES); return result; }加了缓存之后要注意一致性房源下架、新发布房源时要主动删除相关缓存否则会出现「房东已经下架了租客还能搜到」的逻辑矛盾。我常用的方式是在 HouseService 的更新方法里调用redisTemplate.delete(key)删除对应 key宁可删除缓存让下次重建也不要把缓存数据写得太复杂。6.2 数据库索引设计这四条索引能让查询快一个数量级房屋租赁系统的查询瓶颈往往是复合条件索引设计要有针对性。我给 house 表加了这四条索引效率提升很明显索引名称字段用途idx_status_createtimestatus, create_time前台搜索可用房源并按时间排序idx_address_keywordaddress地域筛选时加速idx_owner_idowner_id房东后台查看自己的房源idx_price_statusprice_month, status价格区间筛选给 contract 表加idx_house_id、idx_tenant_id、idx_end_date合同到期提醒的批量查询直接走end_date索引。这里有个经验不要在每一列上都建索引写入会变慢存储也会膨胀。索引建立后用 EXPLAIN 看执行计划重点观察 type 字段如果出现 ALL全表扫描赶紧调整索引。6.3 答辩前必做的 10 分钟冒烟验证清单项目交付前我会用一个笔记本按下面的顺序撸一遍哪一步不行就立刻修注册一个租客账号登录修改个人信息退出再登录。用管理员账号创建一套房源数据上传一张本地图片确认图片能正常显示。用租客账号搜索该房源发起看房申请再切到房东账号确认申请。创建 3 天后的合同确认合同状态变为生效中房源状态变为已出租。缴一次房租确认账单状态变为已缴金额精确到分。退租后确认合同状态变为已结束、房源恢复为可出租、押金账单自动生成。这套清单走下来如果全绿你的项目至少是逻辑完整的。最后说一句我的习惯每做一个模块我都会留一份「当时为什么这么设计」的笔记答辩时老师问「为什么这里用枚举」「为什么合同不用外键级联」你直接说出当时比较过的方案和翻车经历比背概念分数高得多。希望帮到你做完这个系统你会对 Java 后端项目有一个完整的操作手感后面不管做商城还是做管理后台踩坑能力都是通用的。本文还有配套的精品资源点击获取
返回列表