☰
基于Java+Vue的小型房屋租赁系统设计:从数据库到前后端部署全解析
2026/10/21 21:27:52 网站建设 项目流程

每年四五月份,总有大批计算机专业的学生在深夜改代码。如果你点开了这篇文章,大概率也是被“毕业设计”这几个字压得喘不过气。今天要聊的这个项目——基于Java + Vue的小型房屋租赁系统,可以说是毕业设计里的常青树了。它不复杂,但五脏俱全,刚好卡在“工作量足够”和“难度可控”这个甜点上,而且作为前后端分离的典型项目,拿来写简历、跑答辩、甚至后续扩展成商业项目都很合适。

这篇内容会把这套系统的完整设计思路、数据库表结构、前后端核心实现、从0到1的部署过程、常见报错排查,以及毕业设计文档和答辩的实用建议一次讲清楚。项目用到的核心料就是一套Spring Boot后端、一套Vue前端、一份MySQL数据库脚本和全套文档。无论你现在是刚拿到题目毫无头绪,还是已经写了一半但在某个功能上卡住,这篇文章都能给你提供一份可以直接参考的作业。

1. 项目概述与需求拆解

1.1 项目定位与技术栈总览

“基于Java + Vue的小型房屋租赁系统”这个题目,核心不是要做一个像大型房产平台那样功能多到爆炸的系统,而是要完整地走通一条业务链路:用户注册登录、房东发布房源、租客浏览搜索、在线下单租赁、管理员审核监管。说白了,就是要把房屋租赁这个场景里的前后端交互、数据库设计、角色权限和业务流程都体现出来。

技术栈我推荐的是比较经典也最稳的组合:后端用Spring Boot 2.7 + MyBatis Plus + MySQL,前端用Vue 2 + Element UI + Axios。为什么不用Spring Boot 3或Vue 3?不是不能用,而是对大多数毕业生来说,Spring Boot 2和Vue 2的资料最全,遇到问题随便一搜都能找到答案,而且对JDK版本和Node版本的要求更宽松,不容易在环境配置上翻车。如果你愿意折腾,用Spring Boot 3 + Vue 3 + Element Plus也是可以的,但前提是你有足够的时间去解决可能出现的兼容性问题。

这套组合里,Spring Boot负责提供RESTful接口,MyBatis Plus负责简化数据库操作,Vue负责页面渲染和用户交互,Axios负责前后端的数据通信。整个架构是标准的前后端分离模式,前端通过HTTP请求调用后端接口,后端返回JSON数据。这样做的好处是职责清晰、便于调试,也符合当前企业级项目的开发习惯,答辩的时候也比较好讲。

1.2 角色划分与核心需求

房屋租赁系统的核心角色有三个:租客(普通用户)、房东和管理员。这三种角色的需求差异非常明显,系统设计的时候必须分清楚。

租客看房、找房,需要浏览房源列表,按价格、面积、区域筛选,看到合适的收藏起来,然后下单租房,租完还能评价。房东要发布房源、管理自己的房源上下架、查看订单、处理租客的租房请求。管理员则是整个系统的超级管家,负责审核房源是否合规、管理用户账号、监控所有订单的状态,必要的时候还要能下架违规房源。

我见过很多同学做这个题目的时候,一上来就闷头写代码,结果做出来的系统三个角色的功能混在一起,房东能下单,租客能审核,整个权限乱成一团。这是答辩时最容易被老师挑刺的地方。正确的做法是先梳理清楚每个角色需要什么功能,再据此设计表结构和接口权限。

从业务流程上看,核心链路是:房东登录后发布房源 → 管理员审核通过 → 租客浏览到房源 → 租客收藏或下单 → 下单后生成租赁订单 → 房东确认或系统自动确认 → 租客入住期满评价。简化版可以去掉房东确认环节,做成下单即生效,但那样业务感会弱一些,我建议还是保留。

1.3 为什么这套方案值得选

这个题目在毕业设计里受欢迎,不只是因为代码好写,更是因为它是一个“麻雀虽小五脏俱全”的完整业务系统。做这个项目,你能体现出来的能力包括:数据库设计能力(多表关联、状态流转、唯一约束)、后端接口设计能力(RESTful风格、JWT鉴权、参数校验)、前端页面交互能力(列表渲染、表单校验、状态切换)以及项目管理能力(分模块开发、文档整理)。这些能力项恰好是评审老师最看重的。

而且,这套系统后续扩展空间极大。你可以加地图找房、加在线支付模拟、加聊天沟通、加数据统计分析,每一个扩展点都可以拿出来作为论文里的“创新点”或者“系统亮点”。相比之下,那些纯管理系统的题目(比如学生管理系统、图书管理系统)扩展性就差很多,翻来覆去都是普通的增删改查,答辩讲不出花来。

所以我一直认为,房屋租赁系统是性价比极高的毕设选题。做之前看着觉得有难度,做起来会发现每个难点都是能攻坚下来的,等做完回头看,你的编程能力和对项目的整体把控能力都会有明显的提升。

2. 数据库设计与表结构解析

2.1 核心表清单

数据库是整个系统的地基,地基打不好,后面写代码全是坑。这个系统最少需要五张表:用户表、房源表、租赁订单表、收藏表、评论表。如果需要做一些辅助功能,还可以加房屋类型字典表、公告表之类的,但我不建议一上来就铺太多表,先保证核心链路完整,再考虑扩展。

表名用途关键字段
sys_user用户信息id、username、password、role、phone
house_info房源信息id、landlord_id、title、price、status
rent_order租赁订单id、order_no、house_id、tenant_id、status
favorite收藏记录id、user_id、house_id
house_comment评论记录id、house_id、user_id、content、rating

这五张表就能支撑起整条业务链路。用户表区分角色,房源表关联房东,订单表关联房源和租客,收藏表和评论表关联用户和房源。表之间的外键关系要用好,但不需要真的在数据库层面建物理外键——逻辑外键就够,MyBatis Plus里通过字段关联查询就行,物理外键反而会给后续的数据操作带来麻烦。

2.2 关键表字段设计详解

先看用户表sys_user。id用自增主键,username是登录名,唯一约束不能少。password字段要存加密后的密文,不要明文存储,这一点在答辩时经常被问到,建议用BCrypt加密,Spring Security里有现成的工具类。role字段用tinyint类型,1代表管理员、2代表房东、3代表租客,后续在接口层做权限判断。

房源表house_info是信息量最大的表。除了基本的主键和关联字段,比较重要的字段有:house_type(整租、合租、短租)、area(面积,decimal类型)、price(月租金,decimal类型,单位元)、province和city和district(省市区,用字符串存行政区划代码或名称都可以)、address(详细地址)、cover_image(封面图)、detail_images(详情图,可以用JSON字符串存多个图片地址)、view_count(浏览量)、status(状态:0待审核、1上架中、2已出租、3已下架)。这里有个细节,landlord_id一定要建立索引,因为房东查看“我的房源”时是按这个字段查询的。

租赁订单表rent_order的字段设计要稍微花点心思。order_no(订单编号)要保证唯一,可以用时间戳加随机数生成,或者用数据库自增序列。start_date和end_date用date类型,最后加一个months(租期月数)字段,方便前端展示“租期X个月”这样的信息。status字段是这个表的灵魂,我用0待支付、1已支付、2已取消、3已完成,这套状态流转要在代码里严格控制,不能让订单从待支付直接跳到已完成。

收藏表和评论表就相对简单了,主要注意联合唯一约束。比如收藏表,user_id和house_id不应该重复,可以在建表时加上UNIQUE约束,从数据库层面防止重复收藏。评论表加一个rating字段,也保证了评价维度。这些细节虽然小,但都是加分项:数据库设计要经得起推敲。

2.3 表关系与设计心得

表关系其实很清楚,但我还是建议你画一张ER图,放进论文里。用户表和房源表是一对多,一个房东能发多套房源;房源表和订单表是一对多,一个房源可能有多次租赁记录;用户和房源也是多对多,通过收藏表来关联。画清楚这张图,你的论文数据库设计那一章就成功了一半。

这里说一个我踩过的坑:如果要展示“真实项目”的复杂感,不要硬塞进几十张表。评审老师看重的是你是否真的理解了系统的业务逻辑和数据关系,而不是表数量多不多。五张精华表加上清晰的逻辑关系,比二十张没用的表要好得多。如果真的想扩展,我建议加一张“房屋类型字典表”或者“区域字典表”,让系统在可维护性上更有说服力,但不要为了好看而加一些根本用不上的表。

3. 核心技术实现拆解

3.1 前后端交互与接口设计

前后端分离项目里,接口设计就是前后端之间的“契约”。我推荐用RESTful风格来写接口,资源用名词表示,操作用HTTP方法区分。比如GET代表查询,POST代表新增,PUT代表更新,DELETE代表删除。

系统核心接口大致如下:

  • POST /api/user/login 用户登录
  • POST /api/user/register 用户注册
  • GET /api/house/page 分页查询房源
  • GET /api/house/detail/{id} 房源详情
  • POST /api/house/save 发布或更新房源
  • POST /api/house/delete/{id} 删除房源
  • POST /api/order/create 创建订单
  • POST /api/order/cancel 取消订单
  • GET /api/order/my 查询我的订单
  • GET /api/favorite/my 查询我的收藏
  • POST /api/comment/add 添加评论

这里要重点说一下统一返回结果的问题。我建议定义一个Result类,包含code、message、data三个字段,所有接口都返回这个结构。这样前端处理起来非常统一,错误提示也方便。代码可以这样写:

public class Result { private Integer code; private String message; private Object data; public static Result success(Object data) { Result result = new Result(); result.code = 200; result.message = "操作成功"; result.data = data; return result; } public static Result error(String message) { Result result = new Result(); result.code = 500; result.message = message; return result; } }

这个类就是前后端通信的“信封”,所有接口的返回都会装进这个信封里。前端拿到响应后统一判断code是否为200,不是的话弹出message提示用户。别小看这个设计,到答辩的时候,老师问你“系统的异常是怎么处理的”,你就可以很自然地回答“我们有统一的返回结果封装,所有异常都被捕获并转换成标准错误信息返回给前端”。

3.2 后端登录鉴权模块实现

登录鉴权我推荐用JWT(JSON Web Token),不需要在服务端存session,对前后端分离项目非常友好。用户登录成功后,后端生成一个令牌返回给前端,前端把令牌存在localStorage里,之后每次请求都在请求头里带上,后端拦截器校验令牌是否有效。

核心逻辑是这样的:用户提交用户名密码 → 后端校验密码 → 密码正确则生成JWT令牌 → 返回给前端。密码校验这里特别注意,数据库里存的是BCrypt加密后的密文,所以校验要用BCryptPasswordEncoder的matches方法去比对,而不是直接equals。

拦截器实现可以参考这个思路:

public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 放行登录、注册等接口 if (request.getRequestURI().contains("/login") || request.getRequestURI().contains("/register")) { return true; } // 从请求头获取token String token = request.getHeader("Authorization"); if (token != null && JwtUtil.validateToken(token)) { return true; } response.setStatus(401); return false; } }

配好拦截器后,需要再写一个WebMvcConfig把拦截器注册进去,并设置好放行路径和拦截路径。这里有个小坑:前端在跨域请求时会先发一个OPTIONS预检请求,这个请求也得放行,否则你在前端会看到请求报了403。我在配置里通常是直接放行所有OPTIONS请求,这样省很多事。

JWT生成的核心代码是这样:

public static String generateToken(Long userId, String role) { return Jwts.builder() .setSubject(String.valueOf(userId)) .claim("role", role) .setExpiration(new Date(System.currentTimeMillis() + 1000L * 60 * 60 * 24)) .signWith(SignatureAlgorithm.HS256, "your-secret-key") .compact(); }

这里要用一个固定且足够复杂的密钥,不能是太简单的字符串。实际开发中这个密钥应该放在配置文件里,不要在代码中硬编码。我在做这个项目时是把密钥放进了application.yml里,后续想改配置不用重新编译代码,这也是一个值得在文档里写出来的细节。

3.3 前端房源列表与筛选实现

Vue前端的重点难点,一个是路由和权限控制,另一个就是列表页的交互体验。

先看路由。我建议把页面拆成:登录页、注册页、首页(房源列表)、房源详情页、个人中心、我的订单、我的收藏、后台管理。后台管理页面需要管理员权限才能进入,所以要在路由守卫里做判断。Vue Router的全局前置守卫写法不复杂,但逻辑要清晰:从localStorage里取到token就代表已登录,取到用户角色为管理员才能跳后台。

房源列表页是用户打开系统后第一个看到的页面,信息量大、交互多,最能体现你的前端基本功。页面结构无非是:顶部搜索栏(关键词搜索)、筛选条件栏(房屋类型、价格区间、面积区间、区域选择)、房源卡片列表(封面图、标题、价格、面积、区域)、分页器。这些用Element UI组件很快就能拼出来。

前端的搜索请求代码:

getHouseList() { const params = { pageNum: this.currentPage, pageSize: this.pageSize, keyword: this.keyword, houseType: this.houseType, minPrice: this.minPrice, maxPrice: this.maxPrice } houseApi.getHousePage(params).then(res => { if (res.code === 200) { this.houseList = res.data.records this.total = res.data.total } }) }

对应后端的查询接口用MyBatis Plus的LambdaQueryWrapper来处理动态条件,根据前端传来的参数拼接条件:

LambdaQueryWrapper<HouseInfo> wrapper = new LambdaQueryWrapper<>(); wrapper.like(StringUtils.hasText(keyword), HouseInfo::getHouseTitle, keyword) .eq(houseType != null, HouseInfo::getHouseType, houseType) .between(minPrice != null && maxPrice != null, HouseInfo::getPrice, minPrice, maxPrice) .eq(HouseInfo::getStatus, 1) .orderByDesc(HouseInfo::getCreateTime);

这段代码的逻辑很直观:传了关键词就查询标题模糊匹配,传了房屋类型就查对应类型,传了价格区间就用between,没传的字段就不拼这个条件。这种“动态条件拼接”是MyBatis Plus的拿手好戏,也是项目里必须要展示的亮点:用了LambdaQueryWrapper避免拼接SQL带来的注入风险,同时让代码更优雅。

3.4 订单流程闭环实现

订单模块是整个系统业务逻辑最核心的地方。租客在房源详情页点击“立即租房”,填写租期起止日期,前端会计算总租金并展示确认支付金额。前端确认后,调用后端的创建订单接口,后端先生成订单号并保存订单,状态为待支付。

这里有个妙处:创建订单时,应该把租金单价、租期、总价一起冗余保存到订单表中。这个问题答辩时经常被问,为什么要冗余?因为房源价格可能被修改,如果订单表不保存当时成交的价格快照,后续对账和查看历史订单会出现金额对不上的情况。这就是业务设计里常说的“数据快照”思想,说出来会显得你考虑问题很周全。

支付环节在毕业设计里一般做模拟支付就够了,毕竟接真实支付没有商户资质也搞不了。我这里的做法是前端调用支付接口后,后端直接把订单状态改为已支付。等租期到了,用户可以主动点击“确认入住完成”,或者管理员在后台标记完成。这样订单的状态流转就是:待支付 → 已支付 → 已完成,加上一个待支付状态时可以取消订单,就构成了完整闭环。

public synchronized boolean createOrder(OrderCreateDTO dto) { HouseInfo house = houseInfoMapper.selectById(dto.getHouseId()); if (house == null || house.getStatus() != 1) { throw new RuntimeException("房源不存在或不可租"); } RentOrder order = new RentOrder(); order.setOrderNo(generateOrderNo()); order.setHouseId(house.getId()); order.setTenantId(dto.getTenantId()); order.setLandlordId(house.getLandlordId()); // 关键:保存价格快照 order.setPrice(house.getPrice()); order.setMonths(dto.getMonths()); order.setTotalPrice(house.getPrice().multiply(new BigDecimal(dto.getMonths()))); order.setStatus(0); rentOrderMapper.insert(order); return true; }

下单后还要考虑并发问题。同一套房源,两个用户同时下单怎么办?这里当然不需要做太复杂的分布式锁,但至少要用synchronized或数据库乐观锁保证同一房源不能被同时创建两个未取消的有效订单。我在项目里给house_info表加了个lease_status字段,下单时先更新这个字段为“已锁定”,更新失败说明被别人抢先了,就返回“房源已被预订”的提示。这种并发处理的思路写在论文里,会是一个很不错的亮点:你在毕业设计里就已经有意识地处理数据一致性问题了。

4. 从0到1实操部署记录

4.1 环境准备清单

我做到现在,帮不少同学排查过环境问题。环境出错的概率远高于代码本身,所以这块一定不能马虎。以下是经过验证的软硬件环境建议。

依赖项版本建议说明
JDK1.8 或 11Spring Boot 2.x对JDK 8支持最好
Maven3.6+用IDEA自带Maven也行,但建议单独装
MySQL5.7 或 8.05.7最稳,8.0注意驱动版本
Node.js14.x 或 16.xVue 2项目不要在Node 18以上跑,容易出问题
开发工具IDEA + VS Code后端用IDEA,前端用VS Code即可

这套环境组合是我实际验证过兼容性最好的。特别提醒一下,Node版本是最容易出问题的环节:很多同学装了个最新的Node 20,结果npm install的时候各种警告报错,网上搜也搜不明白。我的建议是直接用nvm管理Node版本,把Node 14装好用来跑Vue 2项目,省心很多。

4.2 数据库初始化与导入脚本

数据库脚本是整个项目的“地基文件”,最开始就要写好。我习惯把建库、建表、初始化数据分开放在三个文件里,也可以合成一个init.sql。正式导入步骤非常简单:

  • 打开MySQL命令行或图形化工具
  • 执行CREATE DATABASE house_rental DEFAULT CHARACTER SET utf8mb4;
  • 选中数据库,导入house_rental.sql脚本
  • 确认五张表都建立成功,再检查一下初始化数据是否插入

这里有一个字符集的问题必须告诉你:数据库排序规则一定要选择utf8mb4_general_ci,而不是utf8mb4_unicode_ci或默认的utf8。utf8mb4支持完整的Unicode字符,可以存储emoji,在租房系统里用户评论可能带表情,用utf8mb4就完全没问题。如果建库的时候选错了字符集,后续改起来很麻烦,表里中文还可能变乱码。

初始化数据建议至少准备一套:一个管理员账号、一个房东账号、一个租客账号、若干条测试房源数据。这样项目一启动,前端就能看到数据,不用从头创建。管理员的用户名和密码需要在文档里写明,我一般固定用admin和admin123,方便测试。

4.3 后端启动与接口自测

后端启动前,先检查application.yml里的数据库连接配置:

server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/house_rental?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai username: root password: 123456 jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8 mybatis-plus: mapper-locations: classpath*:/mapper/**/*.xml configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

注意看,日志配置了StdOutImpl,这样在控制台能看到每条SQL的完整输出,方便排查。map-underscore-to-camel-case这个配置很重要:数据库字段是下划线命名(如user_name),Java属性是驼峰命名(userName),开启这个配置后MyBatis Plus会自动完成映射,省掉大量写resultMap的时间。

启动Spring Boot应用,看到"Started Application in xxx seconds"就算成功了。然后先用Postman或者直接在浏览器里测试几个关键接口,先测登录接口拿token,再带着token测查询接口,确认鉴权正常。很多同学一上来就写前端,结果后端半成品状态就拿着调,两边互相干扰,出问题了也不知道是哪边的错。正确做法是后端接口全部自测通过后,再开始写前端页面。

4.4 前端启动与联调

前端项目clone下来后,先执行npm install安装依赖。这一步有两个很大的坑:

第一个是npm源的问题,默认源在国外,下载速度极慢甚至直接失败。解决方法是一劳永逸地切换为国内镜像源,执行npm config set registry https://registry.npmmirror.com,之后再install速度会快很多。

第二个是依赖版本冲突。建议直接复制项目里已有的package-lock.json,如果项目没提供,那就锁定Element UI版本为2.15.14左右,不要装最新版。我有一次给自己调试项目,随手装了个最新的Element UI,结果好几个组件的样式和预期不一致,排查了很久才发现是版本升级导致的兼容问题。

依赖装好后,npm run serve启动开发模式。浏览器打开localhost:8081,如果页面上能正常请求到后端的接口,说明联调成功。

这里还要处理一个经常被忽略的问题:跨域。前端地址是localhost:8081,后端是localhost:8080,端口不同就存在跨域。如果后端没配跨域支持,前端所有请求都会被拦截。最简单的配置是写一个CORS配置类:

@Configuration public class CorsConfig { @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.addAllowedOriginPattern("*"); config.addAllowedMethod("*"); config.addAllowedHeader("*"); config.setAllowCredentials(true); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } }

注意这里我用的是addAllowedOriginPattern而不是addAllowedOrigin,因为后者在allowCredentials为true时不允许使用通配符,而前者是Spring专门为这种情况提供的替代方案。这个细节很少有人注意,但关键时刻能救你一命。

4.5 打包与最终交付

毕业设计最终要上交一个可运行的项目,所以打包部署流程不能少。

后端打包:在项目根目录执行mvn clean package,会生成一个jar包。运行时用java -jar xxx.jar启动,注意指定数据库配置,也可以用命令行参数覆盖,比如java -jar xxx.jar --server.port=9000。

前端打包:npm run build生成dist静态文件目录。这里有个选择:你可以把dist里的文件直接扔给Nginx部署,也可以把dist目录作为静态资源放进Spring Boot里,实现单机部署。我比较推荐前者,因为Nginx部署更接近真实生产环境,而且答辩的时候你可以说“系统支持前后端分离部署,也有静态资源合并部署的能力”。

数据库部分,导出最新的SQL脚本,确保里面包含完整的建表语句和测试数据。文档部分,我建议按下面这样的结构整理:开题报告(可选)、需求分析文档、数据库设计文档、系统详细设计文档、用户操作手册、演示视频说明。记住,文档不是凑字数的,每个配置项、每一张表、每个接口都要能和源代码对应上,答辩老师可能会随机抽查。

5. 常见问题与排查技巧实录

5.1 高频报错速查表

做这个项目,有几个报错几乎每三个人里就会有两个人遇到,我直接把解决方案列出来。

报错场景可能的报错信息原因与解决方案
后端启动失败Access denied for user 'root'@'localhost'数据库密码错误或授权不足,检查application.yml密码,确认该用户有访问权限
前端启动失败Syntax Error: Error: No matching version found for vue@xxxNode版本太高导致依赖解析失败,切换Node 14/16再试
登录请求返回401Request failed with status code 401Token缺失或过期,重新登录或检查拦截器是否放行了登录接口
中文乱码楼ç连接URL未加characterEncoding=utf8mb4,或数据库字符集不是utf8mb4
MyBatis Plus报Table doesn't existTable 'xxx' doesn't exist表名映射问题,检查实体类@TableName注解或数据库表名是否正确
npm install卡住idealTree:xxx: sill idealTree buildDeps切换国内镜像源,删除node_modules后重新安装

这中间,最容易被忽略的是“Nginx配置导致前端刷新404”。如果你用了history路由模式,在Nginx里没配try_files,刷新就会报404。解决方法是在server块里加上:

location / { try_files $uri $uri/ /index.html; }

这点放到答辩演示时特别重要:很多同学演示的时候按了F5刷新,页面直接白屏,非常尴尬。配置好这一条就不会出问题。

5.2 几个必须提前避开的坑

除了报错之外,还有几个我在项目中实际踩过的坑,属于“不报错但结果不对”的类型,排查起来更花时间。

第一个是时间字段的时区问题。MySQL默认的时区可能和国内时区不同,如果不配置serverTimezone=Asia/Shanghai,订单创建时间会有8小时的偏差。这个在数据库连接URL里加上就行,但我见过很多同学漏掉这一项,导致订单时间显示“明天”或“昨天”,演示时很难解释清楚。

第二个是前端表单校验的坑。Vue项目里表单校验一般在blur或change事件触发,如果你在测试时发现填写完邮箱但一直提示格式错误,检查一下校验规则是写在data里还是写在rules里,Element UI要求校验规则必须放在rules中并且通过prop属性绑定。很多时候页面不生效就是因为rules里的字段名和v-model绑定的字段名没对应上。

第三个是上传图片后页面不显示的坑。商品图片或房源图片上传后,如果图片路径是相对路径(比如/uploads/x.jpg),需要确认前端页面是否能正确拼出完整路径。最简单的解法是后端返回绝对URL,或者前端统一加一个baseURL前缀。我一般是在后端配置一个静态资源映射:

WebMvcConfigurer 配置 addResourceHandlers("/uploads/**", "file:D:/project/uploads/")

这样图片请求就能被Spring Boot静态资源处理器接管。配置好之后,在上传图片时要留意返回的路径,如果图片还是打不开,可以先用浏览器直接访问图片URL,判断是存储问题还是展示问题。

第四个坑是订单取消后的库存恢复。很多同学做了“下单”功能,但忘了做“取消后释放房源状态”。我见过有同学测试时连续下几次单,房源状态变成“已出租”后就没有任何办法再变回可租了,只能改数据库。正确的实现是在取消订单的方法里,同时把对应房源的租用状态改回可租,并在事务里保证这两个操作的原子性。

5.3 自查清单:提交前的最后检查

我把之前带过的学生项目中常见的问题汇总成了一份自查清单,提交之前照着走一遍,能少很多麻烦:

  • 数据库编码是否统一为utf8mb4,中文和emoji是否正常显示
  • 前端页面刷新是否正常,登录态是否保留
  • 三个角色的权限是否都验证过(租客不能进后台、房东只能管理自己的房源)
  • 核心链路是否完整(注册→登录→发布房源→审核→下单→支付→评价)
  • 订单状态流转是否合法(不能从待支付直接跳到已完成)
  • 图片上传和展示是否正常,路径没有写死
  • 项目打包后能否在另一台电脑上干净地跑起来
  • 文档中描述的账号密码、默认数据是否和实际项目一致
  • 演示前是否做过一次完整的走场,特别是网络波动的情况下接口超时怎么办

这份清单如果全部通过,你的项目基本就稳了。

6. 文档撰写与答辩经验

6.1 毕设文档结构建议

源码能跑是毕业设计的基础,但最终的评分往往由文档和答辩表现决定。项目文档不是流水账,要有逻辑、有层次、有重点。

我的建议是,需求分析章节不要直接复制网上的模板,要结合自己做出来的系统功能一行行梳理。比如“系统目标”里写三条就够了:提高租房信息匹配效率、规范化线上租赁流程、提供管理员监管手段。系统用例图、功能结构图、ER图,这几张图一定要自己画一遍,画图的过程其实就是梳理逻辑的过程,图能画明白,说明你的系统设计是清晰的。

数据库设计章节,把每个表的每个字段都列清楚,类型、长度、是否为空、默认值、注释一应俱全。这最能暴露你对系统的理解程度,所以不要偷懒。接口设计章节,列出每个接口的请求方式、请求参数、返回值。这些内容你写代码的时候心里都有,只是需要花时间整理成文字。如果你的时间紧张,我建议把精力优先投入到需求分析、数据库设计和核心流程说明上,因为这些是答辩时老师最爱问的。

6.2 答辩演示的节奏与话术

答辩时间一般只有五到十分钟,所以演示一定要抓重点,不要一开始就从注册登录慢慢走流程——那样容易在基础操作上浪费掉大部分时间。

我的建议是先花一分钟介绍系统角色和技术架构,然后直接演示核心链路:租客登录后找房、下单,房东登录后发房、接单,管理员登录后审核、管理。每个环节点一下就行,不要长时间停留在列表页讲解页面布局,线上老师更想看的是业务逻辑流转。

如果被问到“这里的并发是怎么解决的”或者“订单状态怎么保证一致”,就把事务和锁的细节讲出来。如果被问到“系统的亮点是什么”,除了说前后端分离和JWT鉴权,还可以说你注意到了价格快照这个业务细节、用枚举来管理订单状态、用拦截器做统一鉴权。这些点都是实际做过的,讲出来就不会心虚。

最容易被忽视的一点,是提前准备一个“如果演示翻车怎么办”的后备方案。我在现场见过太多学生演示到一半项目崩了,然后只能尴尬地盯着屏幕。我的做法是提前打开一个已登录的浏览器窗口、提前准备好测试账号数据清单,万一系统卡顿,直接用截图或预先录好的视频演示。这些小细节准备一下不费多少时间,却能让整场答辩从“手忙脚乱”变成“稳如泰山”。

我个人做完这个项目后最深的一个体会是:毕业设计这东西,难度不在于某一个技术点有多高深,而在于你能不能把一堆分散的小功能像拼图一样完整地拼成一个能跑、能演示、能说得清楚的整体。不管你是从零开始还是拿着别人的源码改造,最后都要经历那个“把它当成自己的系统去看懂、去讲明白”的过程。这也正是这个题目真正的价值所在。

如果你正计划做或者正在做这个房屋租赁系统,我给你最实在的建议是:先花两天时间把数据库表和接口设计理清楚,不要急着写页面。地基打好了,后面的代码速度会翻倍。祝你顺利拿下答辩。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询