房屋租赁管理小程序毕业设计:SSM+MySQL全流程实战
简介这是一份面向计算机相关专业毕业设计的房屋租赁管理小程序完整项目资料基于微信小程序SSMMySql开发涵盖前后端完整源码、数据库脚本、毕业论文及操作演示视频。系统按角色划分功能管理员可管理用户、中介、房屋信息、租房订单与账单等中介负责房源与订单用户可浏览房屋、租房并查看账单整体具备较好的实用性与展示价值。压缩包共891个文件约59.15MB主要包括Java后台源码、Vue管理端页面、微信小程序前端wxml/wxss/js/json、SQL数据库脚本、论文文档及mp4演示视频png/svg等图片资源用于界面素材与说明文档目录结构清晰便于二次开发与答辩讲解。目前已有200人浏览学习适合毕业设计选题、课程项目复现或希望掌握SSM小程序整合开发流程的学习者参考。1. 房屋租赁管理小程序毕业设计做到哪一步才算能交付先说结论以房屋租赁管理小程序作为毕业设计真正的难点不在“写代码”而在把微信小程序端、SSM 后端、MySQL 数据库这条完整链路跑通并能在答辩现场用五分钟把业务讲清楚。我见过太多同学拿着源码在本地能启动换一台电脑、换一个微信开发者工具版本就各种翻车。这个题目的聪明之处在于它同时覆盖移动端、后端、数据库三块内容工作量可展示、效果直观非常适合需要结合移动端场景的毕业设计。这篇文章会按一个可复现的毕业设计方案拆解技术选型、数据库设计、SSM 后端实现、小程序端联调最后落到部署和答辩演示的避坑技巧适合正在做或打算选这个题目的同学。2. 技术选型与工程结构为什么是微信小程序 SSM MySQL2.1 技术选型毕业设计里最“稳”的组合没有之一这个题目选微信小程序做前端本质上是想避开安卓和 iOS 双端开发的成本。微信小程序自带用户体系和登录能力不需要自己搭一套账号系统租客、房东、管理员三类角色都能在同一个小程序里承载。后端的 SSM 是 Spring SpringMVC MyBatis 的组合虽然现在新项目多用 Spring Boot但 SSM 在课程设计、毕业设计里仍然有大量现成代码和文档可以参考遇到问题搜索引擎随便一翻就有答案。MySQL 做数据库是因为它免费、跨平台、GUI 工具多而且 8.0 版本对 JSON、窗口函数的支持足够应付一个租赁管理系统的全部需求。技术组件本题中的角色选择理由替代方案微信小程序租客/房东端界面免安装、自带登录授权、演示直观H5 网页但少了移动端亮点SpringMVC后端接口层请求路由、参数绑定、JSON 返回Spring Boot更省配置MyBatis数据持久层SQL 可控、动态 SQL 方便JPA但 SQL 调优不够直观MySQL数据存储成熟、开源、生态大PostgreSQL功能更强但文档少这套组合的劣势也明显SSM 的 XML 配置量比较大第一次搭容易漏配导致启动失败。所以工程结构一定要一开始就清晰避免后面排错无从下手。2.2 工程结构一个能满足前后端联调的目录划分我一般会把项目按三个模块组织backend放 SSM 后端miniapp放微信小程序sql放数据库脚本。docs放毕业论文和答辩 PPT。第一次上手时建议完全照这个结构来不要自己发明目录否则后面写论文梳理模块会花两倍时间。rent-miniapp/ ├── sql/ # 数据库初始化脚本与测试数据 ├── backend/ # SSM 后端工程 │ ├── pom.xml │ └── src/main/ │ ├── java/com/example/rent/ │ │ ├── controller/ # SpringMVC 接口层 │ │ ├── service/ # 业务逻辑层 │ │ ├── dao/ # MyBatis Mapper 接口 │ │ ├── entity/ # 与表结构对应的实体类 │ │ └── common/ # 统一返回体、异常处理、工具类 │ └── resources/ │ ├── mapper/ # MyBatis 的 XML SQL 映射 │ ├── spring/ # Spring、MyBatis 配置 │ ├── springmvc/ # SpringMVC 配置 │ └── jdbc.properties ├── miniapp/ # 微信小程序 │ ├── pages/ │ │ ├── index/ # 房源列表 │ │ ├── house/ # 房源详情与签约入口 │ │ ├── lease/ # 我的租约 │ │ ├── user/ # 个人中心 / 房东后台 │ │ └── login/ # 登录授权页 │ ├── utils/request.js # wx.request 封装 │ └── app.js └── docs/ # 毕业论文、答辩讲稿、演示视频脚本com.example.rent是包名占位实际创建时改成你们学校要求的包名格式即可。注意mapper目录下的 XML 文件路径必须与 Spring 配置里的mapperLocations一致否则启动就会报找不到statement。2.3 数据库连接与 ORM 选型先避开两个经典坑第一坑是 MySQL 8.0 默认的认证插件是caching_sha2_password而老项目的驱动还停留在com.mysql.jdbc.Driver会导致登录数据库报认证失败。第二个坑是时区问题连接串不写serverTimezoneAsia/Shanghai查询出来的时间字段会差 8 小时。jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://127.0.0.1:3306/rent_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai jdbc.usernameroot jdbc.password你的数据库密码驱动必须用com.mysql.cj.jdbc.Driver这是 MySQL 8.0 之后的驱动全类名。useUnicodetruecharacterEncodingutf8保证中文不乱码serverTimezoneAsia/Shanghai解决时区差。如果你还在用 5.7驱动名可以用旧版但建议统一切到 8.0教程和社区遇到问题更好查。实体类和表字段的映射建议开启 MyBatis 的驼峰自动映射就不用为每个字段写繁琐的resultMap。3. 数据库先行房屋租赁核心表设计与关键 SQL3.1 业务梳理先定状态机再建表房屋租赁管理的核心就两个对象房源和租约。房源有“下架、上架、已租出”三种状态租约有“申请中、生效中、已到期、已退租、已拒绝”五种状态。这两组状态决定了所有接口的行为逻辑。比如房源上架时不能有人正在申请租约租约生效时房源必须从“上架”变成“已租出”。很多毕业设计把表建了、CRUD 写完但状态之间没有联动答辩时被老师一问就露馅。建表之前先把状态流转图画在草稿纸上比直接写 SQL 更重要。这套业务的表不需要太多用户表、房源表、租约表、账单表、收藏表五张就够其中前四张是核心。3.2 用户表与房源表字段、索引和约束的设置用户表不用存密码因为微信小程序登录走的是wx.login拿 code后端再向微信接口换 openid。表里只需要 openid 作为唯一标识再冗余昵称、手机号和角色字段。角色用TINYINT存数字不要用字符串省空间且查询快。CREATE TABLE user ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 用户ID, openid VARCHAR(128) NOT NULL UNIQUE COMMENT 微信openid, nickname VARCHAR(64) DEFAULT COMMENT 昵称, phone VARCHAR(20) DEFAULT COMMENT 联系电话, role TINYINT NOT NULL DEFAULT 1 COMMENT 角色: 1租客 2房东 3管理员, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;openid设置UNIQUE是必须的同一个人反复登录不能产生多条记录。update_time使用ON UPDATE CURRENT_TIMESTAMP可以让每次更新自动刷新时间。utf8mb4一定要用utf8mb3存不了 Emoji也会让少量生僻字乱码。房源表要区分“面积”和“租金”用十进制不要用FLOAT避免浮点误差。CREATE TABLE house ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 房源ID, landlord_id BIGINT NOT NULL COMMENT 房东用户ID, title VARCHAR(100) NOT NULL COMMENT 房源标题, address VARCHAR(200) NOT NULL COMMENT 地址, area DECIMAL(6,2) DEFAULT 0 COMMENT 面积(㎡), rent DECIMAL(10,2) NOT NULL COMMENT 月租金(元), deposit DECIMAL(10,2) DEFAULT 0 COMMENT 押金(元), status TINYINT NOT NULL DEFAULT 0 COMMENT 状态: 0下架 1上架 2已租出, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, KEY idx_status (status), KEY idx_landlord (landlord_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT房源表;status字段加索引是有意义的因为房源列表页最常用的查询就是WHERE status 1。landlord_id也加索引因为“我发布的房源”是房东端的核心列表。这里故意不建外键约束而是用逻辑外键。毕业设计阶段经常要批量造测试数据物理外键会在删除数据时带来不必要的麻烦但在论文里要把逻辑外键关系画清楚。3.3 租约表与初始化数据给答辩准备一套“会说话”的数据租约表是整个系统的业务核心也是答辩时最有的聊的一张表。它把房东、租客、房源、租金、起止日期、状态串在一起。注意start_date和end_date用DATE类型不要用DATETIME租约按天计算带时分秒没有意义反而增加校验成本。CREATE TABLE lease ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 租约ID, house_id BIGINT NOT NULL COMMENT 房源ID, tenant_id BIGINT NOT NULL COMMENT 租客用户ID, start_date DATE NOT NULL COMMENT 起租日期, end_date DATE NOT NULL COMMENT 到期日期, monthly_rent DECIMAL(10,2) NOT NULL COMMENT 月租金(元), deposit DECIMAL(10,2) NOT NULL COMMENT 押金(元), status TINYINT NOT NULL DEFAULT 0 COMMENT 状态: 0申请中 1生效中 2已到期 3已退租 4已拒绝, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, KEY idx_house_status (house_id, status), KEY idx_tenant (tenant_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT租约表;idx_house_status是联合索引因为最常见的查询是查某套房源当前生效的租约。初始化数据不要只造几条我给学生演示时一般造 12 套左右的房源租约覆盖“申请中、生效中、已到期、已退租”四种状态。这样演示“房东处理申请”“租客查看账单”“退租后房源自动恢复上架”时都有现成数据可点不用现场输入。INSERT INTO user (id, openid, nickname, phone, role) VALUES (1, mock_openid_1, 张三, 13800000001, 2), (2, mock_openid_2, 李四, 13800000002, 1);造测试数据时注意模拟的 openid 随便写一串不重复的字符串就行只要和后端登录逻辑的测试账号保持一致即可。4. SSM 后端实现租约状态流转是核心链路4.1 统一返回体与登录接口从前端 code 换 openid 的完整链路后端接口要做成什么格式我强烈建议所有接口统一返回同一个结构code表示业务状态msg给提示data放数据。前端拿到后统一判断code 200而不是去猜不同的字段名。public class ResultT { private Integer code; private String msg; private T data; public static T ResultT success(T data) { ResultT r new Result(); r.code 200; r.msg ok; r.data data; return r; } public static T ResultT error(Integer code, String msg) { ResultT r new Result(); r.code code; r.msg msg; return r; } // getter/setter 省略 }Result泛型类可以让列表、对象、空值都走同一套返回逻辑。前端utils/request.js里只需要对code做一次判断就能决定是提示还是静默处理。登录接口是前端传code过来后端拿着code去微信的code2Session接口换openid。这里同学们最容易踩的坑是本地调试时没有真实的小程序 AppID导致换不到 openid。解决方法是后端的登录接口做一个“模拟模式”本地联调时直接拿前端传过来的一个测试标识当 openid。RestController RequestMapping(/api/user) public class UserController { Autowired private UserService userService; PostMapping(/login) public ResultUser login(RequestBody LoginDTO dto) { // 本地联调阶段: 不调用微信接口, 直接把测试标识当 openid String openid userService.resolveOpenid(dto.getCode()); User user userService.getOrCreateByOpenid(openid); return Result.success(user); } }resolveOpenid方法里用if (test.equals(code))区分模拟环境和真实环境。真实环境用 HttpClient 调微信接口模拟环境直接返回mock_openid_ code。这个开关一定要留到答辩前因为答辩现场的投影机器没有微信开发者工具的登录态你永远不知道什么时候网络会出问题。4.2 房源发布与租约创建Service 层业务规则租约创建不是简单的 INSERT它要连带检查房源状态。如果房源已经下架或已租出就不能再接新的租约。这个逻辑必须放在 Service 层而不是写在前端。Service 层的方法加Transactional事务注解保证“检查状态 创建租约 更新房源状态”这三步要么全成功要么全失败。Service public class LeaseServiceImpl implements LeaseService { Autowired private HouseMapper houseMapper; Autowired private LeaseMapper leaseMapper; Transactional(rollbackFor Exception.class) public void applyLease(LeaseApplyDTO dto) { House house houseMapper.selectById(dto.getHouseId()); if (house null || house.getStatus() ! 1) { throw new BizException(房源不存在或不可租); } // 同一个租客同一房源不能重复申请 int count leaseMapper.countActiveByHouseAndTenant(dto.getHouseId(), dto.getTenantId()); if (count 0) { throw new BizException(已有进行中的租约申请); } Lease lease new Lease(); lease.setHouseId(dto.getHouseId()); lease.setTenantId(dto.getTenantId()); lease.setStartDate(dto.getStartDate()); lease.setEndDate(dto.getEndDate()); lease.setMonthlyRent(house.getRent()); lease.setDeposit(house.getDeposit()); lease.setStatus(0); // 申请中 leaseMapper.insert(lease); } }applyLease里先查房源再查重复申请最后插入租约。这三步缺一不可尤其“重复申请”的校验在正式项目里是高频踩坑点。房东端处理申请是另一个事务方法房东点击“同意”后租约状态从“申请中”变成“生效中”同时房源状态从“上架”变成“已租出”。4.3 状态流转与并发控制为什么不能直接 UPDATE房源被租出去的那一刻如果两个租客同时提交申请后端可能同时读到房源“上架”同时写出两条“生效中”的租约。这个问题在答辩时非常容易被老师追问。解决办法是状态流转使用条件 UPDATE而不是先 SELECT 判断再 UPDATE。!-- HouseMapper.xml -- update idupdateStatusWithCondition UPDATE house SET status #{newStatus}, update_time NOW() WHERE id #{id} AND status #{oldStatus} /updateint rows houseMapper.updateStatusWithCondition(houseId, 2, 1); if (rows 0) { throw new BizException(房源已被人租走请刷新后再试); }updateStatusWithCondition的WHERE里带上了旧状态UPDATE 的返回值是受影响行数。如果为 0说明执行 UPDATE 之前房源状态已经不是“上架”就说明发生了并发竞争。这种写法叫乐观锁毕业设计里能写出这一步说明你真正理解了并发控制而不是只会 CRUD。4.4 MyBatis 配置与 XML 映射让 SQL 与 Java 解耦MyBatis 的 XML 映射文件是 SSM 项目里代码量最大、也最容易出错的部分。建议所有 mapper XML 放在resources/mapper目录下namespace必须与 DAO 接口全限定名一致。!-- resources/mapper/LeaseMapper.xml -- mapper namespacecom.example.rent.dao.LeaseMapper select idselectListByTenant resultTypecom.example.rent.entity.Lease SELECT l.*, h.title AS houseTitle, h.address AS houseAddress FROM lease l LEFT JOIN house h ON l.house_id h.id WHERE l.tenant_id #{tenantId} ORDER BY l.create_time DESC /select /mapperselectListByTenant用LEFT JOIN把房源的标题和地址冗余到租约列表结果里。#{tenantId}是预编译参数能防 SQL 注入。注意resultType写实体类全限定名实体类里要额外加houseTitle、houseAddress这两个非表字段否则 MyBatis 映射会直接忽略页面上的房源信息就是空的。5. 避坑与排查把“源码能跑”变成“换台电脑也能跑”5.1 微信开发者工具报错“不在以下 request 合法域名列表中”现象小程序端请求后端接口控制台报错request:fail url not in domain list页面数据死活加载不出来。原因微信小程序对请求域名有白名单限制本地开发时如果直接请求http://127.0.0.1:8080不在合法域名列表中就会被拦截。很多同学不知道这个限制以为是代码问题折腾半天。解决开发调试阶段在微信开发者工具右上角“详情 - 本地设置”里勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”。这个选项只对开发工具有效真机预览时如果还要调接口可以临时在预览页面勾选“预览时校验合法域名”并关闭或者把后端接口配成 HTTPS 并加到小程序管理后台的白名单里。毕业设计答辩通常用开发者工具的模拟器勾选后即可正常演示。5.2 租约状态更新了小程序端列表不刷新现象房东在后台把租约状态从“申请中”改成“生效中”租客端返回列表页再进来看到的还是“申请中”。原因小程序页面默认只在onLoad里请求一次数据从列表页跳详情页再返回时不会重新触发onLoad而是触发onShow。接口调用函数写在onLoad里返回页面时自然不会重新拉数据。解决把拉取列表的函数抽出来在onShow里调用。注意onShow会比onLoad更早触发一次函数内部要加防重复请求的判断。Page({ onShow() { this.fetchLeaseList(); }, async fetchLeaseList() { const res await request({ url: /api/lease/list, method: GET }); if (res.code 200) { this.setData({ leaseList: res.data }); } } });onShow里重新请求保证从详情页返回、从支付页返回时列表都是最新状态。如果页面有分页记住把page重置为 1否则翻页数据会重叠。5.3 时间字段显示差 8 小时或者序列化成一串数字现象租约的create_time在小程序端显示成 16:00实际是 00:00 创建的更诡异的是有时数据库里是2025-06-01 00:00:00接口返回却变成1748716800000。原因差 8 小时是 MySQL 连接串没配serverTimezoneAsia/Shanghai而驱动用了默认的 UTC 时区。变成一串数字是 JSON 序列化工具把Date类型转成了时间戳毫秒值前端没有做格式化。解决连接串加上serverTimezoneAsia/Shanghai。JSON 序列化配置全局日期格式SpringMVC 的MappingJackson2HttpMessageConverter里设置objectMapper.setDateFormat(new SimpleDateFormat(yyyy-MM-dd HH:mm:ss))。如果用的是JsonFormat注解记得timezone GMT8也要显式声明否则注解只管格式不管时区。5.4 换一台电脑部署时数据库连不上现象整套源码从 U 盘拷到另外一台电脑Tomcat 正常启动但一登录就报Access denied for user或Communications link failure。原因jdbc.properties里写的是原机器的数据库 IP、端口、账号密码换机器后这些全变了。另外如果原机器用的 MySQL 5.7新机器装的是 MySQL 8.0而驱动还是老版本的com.mysql.jdbc.Driver就会报认证插件错误。解决换机器部署时第一步改jdbc.properties里的jdbc.url、jdbc.username、jdbc.password把你当前机器的实际值填进去。第二步确认驱动 jar 是mysql-connector-java8.0 以上版本jdbc.driver改成com.mysql.cj.jdbc.Driver。第三步检查 MySQL 服务确实启动了。这三步按顺序做90% 的“换电脑就跑不起来”问题能解决。5.5 Tomcat 启动成功但所有接口返回 404现象后端启动日志没有报错浏览器访问http://localhost:8080/api/house/list却返回 404控制台也没有任何映射日志。原因SpringMVC 的DispatcherServlet没有拦截到/api/*路径。常见错误是web.xml里url-pattern误配成了/*或者项目没有正确部署到 Tomcat 的webapps目录导致访问的是 Tomcat 自带的 ROOT 应用。解决检查web.xml中DispatcherServlet的url-pattern是否配置为/这样才会进入 SpringMVC 处理。还要确认部署方式用 IDEA 的 Tomcat 集成部署时看 “Deployment” 里的 Application context 是否设成了/如果是/rent那访问路径就应该是http://localhost:8080/rent/api/house/list。6. 交付前最后三件事造数据、定演示动线、准备被追问6.1 给演示准备一份“有故事”的测试数据数据不要只造几条“成功”的要覆盖业务流程的各种分支。我会在数据库里放 12 套房源、6 个用户、10 条租约其中至少包含一条“申请中”、一条“生效中”、一条“已到期”、一条“已退租”。这样演示时每个按钮点了都有对应反馈老师不会看到你现场临时填表。6.2 演示动线从登录到退租一条线走完演示建议按这个顺序走先打开数据库看一眼核心表数据量再打开后端接口用浏览器访问房源列表接口然后切换到小程序端登录、浏览房源、提交租约申请回到后端接口确认租约已创建再到数据库执行一条查询展示租约表状态变化。这条动线能把“前后端 数据库 业务逻辑”一次性讲清楚比只在小程序里点来点去有力得多。6.3 答辩最可能被追问的三个点第一为什么用 SSM 不用 Spring Boot答题目要求基于 SSM 理解三层架构SpringMVC 做控制层、MyBatis 做持久层的分工更明确适合展示基础功底。第二两个租客同时申请同一套房怎么办答乐观锁条件更新受影响行数为 0 时拒绝后到的请求。第三openid 是什么答微信用户在小程序内的唯一标识后端通过 code 调用微信接口获取用于区分用户身份。这三个点准备充分答辩环节基本不会卡壳。最后说个我的习惯每次改完数据库表结构或者后端接口我都会先在微信开发者工具里完整跑一遍核心流程再提交记录避免遗留“能编译但跑不通”的代码。做毕业设计最怕的不是功能少而是自己都说不清每一段代码在干什么。把状态流转、并发控制、时区处理这几个细节想明白这个题目的收获会比想象中大得多。希望这篇笔记能帮到你祝你顺利通过答辩。本文还有配套的精品资源点击获取