ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

SpringBoot+Vue前后端分离房屋租赁系统:从数据库设计到联调避坑指南

SpringBoot+Vue前后端分离房屋租赁系统:从数据库设计到联调避坑指南

简介:面向高校计算机专业毕业设计的房屋租赁系统全套资料包,基于SpringBoot+Vue+MySQL前后端分离架构开发,完整覆盖个人中心、房屋类型管理、房屋信息发布、预约看房、合同信息归档、房屋报修、房屋评价、我要当房东、留言板、系统管理等业务模块,适合毕业设计选题参考,也适合希望入门主流Java全栈开发的读者对照练习。压缩包共879个文件、约73.96MB,文件类型涵盖162个Java后端源码、56个Vue组件、150个JS脚本、HTML/CSS/SVG静态页面与图标资源、SQL数据库脚本、XML与mapper映射配置,以及doc论文、pptx答辩PPT、mp4演示视频和bat一键启动脚本,从代码到文档均有完整交付。所有前后端接口与业务流程相互衔接,拿到后可按SQL脚本初始化数据库、对照源码理解预约看房与合同管理闭环,再借助论文和PPT直接整理开题、答辩材料,节省大量从零搭建与排版时间。目前已有208人浏览学习,适合正在准备毕设答辩或想快速跑通SpringBoot+Vue项目的同学。

1. 房屋租赁系统值不值得做:先看清这套毕设的完整交付物

如果你正在找选题,大概率已经刷到过“基于SpringBoot+Vue+MySQL的房屋租赁系统”这类标题。第一反应可能是“太普通了”,但我想说:普通恰恰是它作为毕业设计最值钱的地方。CRUD 业务闭环完整、前后端分离思路清楚、论文里有 ER 图可画、答辩时有流程可讲,这些正是评审老师最关心的。这套方向通常配套源码、数据库脚本、论文、答辩 PPT 和演示视频五样东西,真正落地时你会发现:跑通系统只占 30% 时间,把它讲成一篇能自圆其说的论文占 70%。本文按我实际搭过的方案,把业务拆解、表结构、前后端代码链路和最容易翻车的几个现场完整讲一遍,适合手里有一个 SpringBoot 基础、但没独立做过完整前后端项目的同学照抄。

2. 业务拆解先行:三种角色与一条租房主流程

很多同学拿到项目第一件事是建表,这是典型的顺序错误。房屋租赁系统的核心不是房源表怎么写,而是“谁在用、怎么流转”。先把角色和流程理顺,表结构自然就长出来了。

2.1 三种角色决定权限边界

房屋租赁系统里最常见的角色划分是管理员、房东、租客三类。管理员管后台:审核房源、管理用户、看订单统计;房东发房源、维护房源状态、处理租客的租住申请;租客浏览、搜索、收藏房源、发起租赁并签合同。角色不拆表,用 user 表里一个 role 字段区分,毕业设计完全够用,也方便展示权限控制。

以我见过的多数同类型毕设为例,权限控制一般做到“前端路由守卫 + 后端接口拦截”两层。前端没登录不能进首页,登录了但角色不对不能访问管理页面;后端对 /api/admin/** 这类路径做拦截,避免有人绕开前端直接调接口。这两层都做上,答辩时讲“权限设计”就有东西可说。

2.2 一条主流程串起所有模块

把主流程写出来,你会发现整个系统的表结构其实就是这条流程的投影。最典型的租赁闭环是九步:租客注册登录、浏览房源、收藏意向房源、提交租住申请、房东确认申请、生成合同与首期账单、租客缴费、入住、退租结算。每一步都对应一个表或一个状态字段,流程图里画出来,论文的三层数据流图也就有了。

这条流程里最容易被忽略的是“状态流转”。订单不是一步到位的,从待确认、已签约、已拒绝到已退租,每个状态都要能落到字段上。评审老师最爱问的一句话就是“用户取消了订单你怎么办”,如果你在订单表里设计了一个 status 字段并且代码里有对应分支,这个问题就答上了。

2.3 功能清单先对齐再动手

动手写代码前,先列一张功能清单,把每个功能点对应到角色、表、页面,避免写着写着才发现某张表少字段。下面是我常用的一张表,属于最常见的房屋租赁系统功能范围。

模块使用角色功能点对应数据表
用户认证全部注册、登录、个人信息查看user
房源管理房东发布房源、编辑、上下架house
房源浏览租客列表分页、按城市/价格筛选、收藏house、house_favorite
租住申请租客提交申请、取消申请house_order
订单确认房东确认、拒绝租住申请house_order
合同账单租客/房东生成账单、缴费、查看合同house_order、bill
后台管理管理员房源审核、用户禁用、订单总览house、user、house_order

这张表做完,你会发现两个隐藏要点:一是收藏功能需要一张独立的关联表 house_favorite,因为它是多对多关系;二是订单表和合同表可以做进同一张表,因为一个订单确认后就转成合同,拆两张表反而让状态同步变麻烦。这些判断写进论文的“数据库设计”一章,比堆概念扎实得多。

3. MySQL 数据模型:四张核心表撑起租赁业务闭环

业务清单定好后,表结构基本就定格了。我通常在落库时遵循一条原则:先保证主流程的表能自洽,再考虑加字段。以下是四张最核心的表,几乎每个房屋租赁系统都会有,字段命名也保持了前后端统一。

3.1 用户表与房源表

用户表负责登录和角色区分,需要注意的细节有三个:密码存散列值而不是明文、role 用整数不用字符串、登录名建唯一索引。很多新人把密码直接塞 varchar 存明文,答辩一问你密码安全性就露馅。加一个 UNIQUE KEY 是顺手的事,不值得在这上面丢分。

CREATE TABLE `user` ( `id` bigint NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL COMMENT '登录名', `password` varchar(100) NOT NULL COMMENT 'BCrypt 散列后的密码', `real_name` varchar(50) DEFAULT NULL COMMENT '真实姓名', `phone` varchar(20) DEFAULT NULL COMMENT '手机号', `role` tinyint NOT NULL DEFAULT 2 COMMENT '0=管理员 1=房东 2=租客', `avatar` varchar(255) DEFAULT NULL COMMENT '头像地址', `status` tinyint NOT NULL DEFAULT 0 COMMENT '0=正常 1=禁用', `create_time` datetime NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uk_username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

密码字段我特意写了 100 的长度,是因为 BCrypt 散列出来的字符串本身就接近 60 位,给 50 会被截断。这个坑我在实际项目里踩过,当时一登录就报密码错误,查了半天才发现是字段长度不够,BCrypt 值被 MySQL 静默截断。如果你是跟着教程改造源码,第一件事就是检查 user 表 password 字段长度够不够。

房源表是系统里字段最多的一张表,核心点是区域信息的拆分。把省、市、区单独建字段,比塞进一个 address 里更好,因为前端筛选“按城市搜”时不用 LIKE 匹配,SQL 性能也有保障。价格和面积用 DECIMAL,不要用 FLOAT,涉及金额精度时浮点数会出问题,这个属于基本功。

CREATE TABLE `house` ( `id` bigint NOT NULL AUTO_INCREMENT, `owner_id` bigint NOT NULL COMMENT '房东用户ID', `title` varchar(100) NOT NULL COMMENT '房源标题', `cover` varchar(255) DEFAULT NULL COMMENT '封面图URL', `images` text COMMENT '多图URL,JSON数组字符串', `province` varchar(50) DEFAULT NULL, `city` varchar(50) DEFAULT NULL, `district` varchar(50) DEFAULT NULL, `address` varchar(200) DEFAULT NULL COMMENT '详细地址', `rent` decimal(10,2) NOT NULL COMMENT '月租金', `deposit` decimal(10,2) DEFAULT NULL COMMENT '押金', `bedroom` tinyint DEFAULT NULL COMMENT '卧室数', `living_room` tinyint DEFAULT NULL, `bathroom` tinyint DEFAULT NULL, `area` decimal(10,2) DEFAULT NULL COMMENT '面积(平米)', `orientation` varchar(20) DEFAULT NULL COMMENT '朝向', `description` text COMMENT '房源描述', `status` tinyint NOT NULL DEFAULT 0 COMMENT '0=待审核 1=上架 2=已下架 3=已出租', `create_time` datetime NOT NULL, PRIMARY KEY (`id`), KEY `idx_owner` (`owner_id`), KEY `idx_status_city` (`status`, `city`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='房源表';

这里说一个容易被忽略的设计:status 里的“已出租”状态。很多系统删除房源用 DELETE,但真实业务里房源下架后订单记录还要能查到,所以我用状态字段代替物理删除。同理,用户禁用也是 status 字段,而不是删行。这个思路可以在论文“数据设计”一节单独写一段,属于能加分的细节。

3.2 订单表与账单表:状态流转是核心

订单表同时承担合同的功能,所以我叫它 house_order。字段上冗余了 owner_id,因为查询“房东名下的订单”高频,不冗余就得每次 join user 表。一个订单里同时有租客 ID 和房东 ID,是典型的一对多关系冗余存储,空间换查询效率,面试和答辩都偏好这个设计,实现也直白。

CREATE TABLE `house_order` ( `id` bigint NOT NULL AUTO_INCREMENT, `order_no` varchar(32) NOT NULL COMMENT '订单编号,业务唯一', `house_id` bigint NOT NULL COMMENT '房源ID', `tenant_id` bigint NOT NULL COMMENT '租客用户ID', `owner_id` bigint NOT NULL COMMENT '房东用户ID,冗余存储', `monthly_rent` decimal(10,2) NOT NULL COMMENT '成交月租', `deposit` decimal(10,2) NOT NULL COMMENT '押金', `lease_start` date DEFAULT NULL COMMENT '租期开始日', `lease_end` date DEFAULT NULL COMMENT '租期结束日', `status` tinyint NOT NULL DEFAULT 0 COMMENT '0=待确认 1=已签约 2=已拒绝 3=已退租 4=已取消', `create_time` datetime NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uk_order_no` (`order_no`), KEY `idx_tenant` (`tenant_id`), KEY `idx_house` (`house_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单/合同表';

账单表是很多同学会漏掉的设计,但它恰恰是论文里凑 ER 图的好素材。每一笔账单都挂在订单下面,type 区分首期租金、押金、后续租金,status 区分待支付、已支付、已退款。这样设计的好处是:房租是一笔一笔收的,不是一单一次付清,拆成账单表才符合现实租赁逻辑。

CREATE TABLE `bill` ( `id` bigint NOT NULL AUTO_INCREMENT, `order_id` bigint NOT NULL COMMENT '所属订单/合同ID', `bill_no` varchar(32) NOT NULL COMMENT '账单编号', `amount` decimal(10,2) NOT NULL COMMENT '账单金额', `type` tinyint NOT NULL DEFAULT 0 COMMENT '0=首期租金 1=押金 2=后续租金', `status` tinyint NOT NULL DEFAULT 0 COMMENT '0=待支付 1=已支付 2=已退款', `due_date` date DEFAULT NULL COMMENT '缴费截止日', `pay_time` datetime DEFAULT NULL COMMENT '实际支付时间', `create_time` datetime NOT NULL, PRIMARY KEY (`id`), KEY `idx_order` (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='账单表';

四张表的关系一句话就能讲清:用户 1 对多房源,用户 1 对多订单,房源 1 对多订单,订单 1 对多账单。把这张关系图画出来,就是论文里最好看的一页 ER 图。如果你还想要收藏功能,加一张 house_favorite(id, user_id, house_id, create_time) 关联表即可,属于多对多关系的标准解法,这里不再展开。

4. 前后端代码链路:从 JWT 登录到房源发布的第一个闭环

表结构落定后,要做的第一个闭环不是“查列表”,而是登录。登录链路把后端签发 token、前端保存 token、路由守卫校验打通了,后面的所有业务接口都是在这个链路上复制粘贴。我按最常见的实现方案来讲。

4.1 SpringBoot 后端:登录签发与拦截

后端最核心的类是 JwtUtil,它负责生成 token 和解析 token。生成时把 userId、username、role 三个信息塞进 token,过期时间设 24 小时。解析时如果 token 被篡改或过期,直接抛异常让拦截器返回 401。

@Component public class JwtUtil { // 实际项目中这段密钥建议放到 application.yml 里 private String secret = "your-secret-key-change-me"; private long expire = 24 * 60 * 60 * 1000; // 24小时 public String generateToken(Long userId, String username, Integer role) { return Jwts.builder() .setSubject(username) .claim("userId", userId) .claim("role", role) .setExpiration(new Date(System.currentTimeMillis() + expire)) .signWith(SignatureAlgorithm.HS256, secret) .compact(); } public Claims parseToken(String token) { return Jwts.parser().setSigningKey(secret) .parseClaimsJws(token).getBody(); } }

signWith 用的是 HS256 对称加密,毕业设计足够。如果你跟着做,唯一要改的是 secret,换成自己的随机字符串。expire 也可以按需调整,比如调试期改 7 天免得每天重新登录。

登录接口的逻辑按三步走:根据 username 查用户、用 BCrypt 校验密码、签发 token 返回。密码匹配不要自己写 MD5,Spring Security 里自带 BCryptPasswordEncoder,密码散列时加盐,安全性比 MD5 高一个量级,这属于论文里能写进“系统安全设计”的加分点。

@RestController @RequestMapping("/api/auth") public class AuthController { @PostMapping("/login") public Result login(@RequestBody LoginDTO dto) { // 1. 根据用户名查用户 User user = userService.getByUsername(dto.getUsername()); if (user == null || !encoder.matches(dto.getPassword(), user.getPassword())) { return Result.error("用户名或密码错误"); } if (user.getStatus() == 1) { return Result.error("账号已被禁用"); } // 2. 签发 token 并返回用户基础信息 String token = jwtUtil.generateToken(user.getId(), user.getUsername(), user.getRole()); return Result.success(token, user); } }

注意这里的 status 判断,很多教程会漏掉“禁用用户”这个分支。虽然只是一行 if,但答辩时讲“我对恶意账号做了禁用处理”就能体现完整性。我当年第一次做这套系统也忘了这个分支,直到后台管理功能做完才补上,补完后发现论文里“用户管理”模块的描述也顺了。

有了 token 机制,还需要拦截器来保护接口。拦截器从请求头的 Authorization 字段取 token,解析失败就返回 401,解析成功就把 userId 塞进 request 属性,后面对业务接口直接取值。

public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 放行登录等公开接口 String uri = request.getRequestURI(); if (uri.startsWith("/api/auth/")) { return true; } String token = request.getHeader("Authorization"); // 去掉 Bearer 前缀后校验 if (token != null && token.startsWith("Bearer ")) { token = token.substring(7); } try { Claims claims = jwtUtil.parseToken(token); request.setAttribute("userId", claims.get("userId")); return true; } catch (Exception e) { response.setStatus(401); response.getWriter().write("{\"code\":401,\"msg\":\"未登录或token过期\"}"); return false; } } }

接口层写完后,我用一个小技巧验证:先直接跳过前端,用浏览器访问一个受保护接口,不带 token 应该返回 401,带上 token 应该返回正常数据。这一步能分清是后端问题还是前端问题,省去前后端联调时互相甩锅的时间。

4.2 Vue 前端:Axios 封装与登录态保持

前端这边最重要的不是页面长什么样,而是把 token 保存和携带的机制做好。我习惯在 src/utils/request.js 里封装一个 axios 实例,请求拦截器统一往 header 里塞 token,响应拦截器统一处理 401 跳登录页。

import axios from 'axios' import router from '../router' const request = axios.create({ // 走 Vite 开发代理,避免跨域 baseURL: '/api', timeout: 10000 }) request.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }) request.interceptors.response.use( res => res.data, err => { if (err.response && err.response.status === 401) { localStorage.removeItem('token') router.push('/login') } return Promise.reject(err) } ) export default request

baseURL 写成 /api 而不是完整地址,是因为 Vite 开发服务器配置了 proxy,把 /api 开头的请求转发到 SpringBoot 的 8080 端口。这是目前前后端分离开发最省心的跨域方案,前端不需要开启 CORS,后端也不用额外配置跨域过滤器。

登录页拿到 token 后存 localStorage,同时把用户信息存一份。刷新页面后 localStorage 还在,所以登录态不会丢。很多系统喜欢用 sessionStorage,一刷新就没了,用户体验差,答辩演示时也很尴尬,倒是能用“刷新后要重新登录”作为安全策略来圆场,但没必要给自己找这个麻烦。

路由守卫是保护页面的关键,在 router/index.js 里加一个全局前置守卫。meta 里标记了 requiresAuth 的路由,没有 token 一律踢回 /login。管理员页面加一个 role 判断,租客想访问管理员页面就重定向到首页。

router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') if (to.meta.requiresAuth && !token) { next('/login') return } if (to.meta.requiresAdmin) { const role = localStorage.getItem('role') if (role != 0) { next('/') return } } next() })

角色判断这里有个细节:role 从 localStorage 取出来是字符串 "0",和数字 0 比较要用 == 或者先用 parseInt 转一下。我第一次写的时候用了 ===,管理员永远进不去后台,页面白屏还没任何报错,差点以为后端接口出问题了。

4.3 房源发布:第一个完整 CRUD 闭环

登录打通后,第二个推荐做的闭环是房源发布。房东填表单、提交、后端存库、在列表页回显。这个过程把后端的 Controller、Service、Mapper 三层结构,和前端的表单、接口调用、列表渲染都覆盖到了。

后端的房源发布接口逻辑很直白:从 token 里取 userId 作为 owner_id,其余字段从请求体接收,status 默认 0 待审核。之所以强调从 token 取 userId,而不是让前端传 owner_id,是为了防止伪造他人房源,这也是“后端不信任前端”的典型体现。

@PostMapping("/api/house") public Result addHouse(@RequestBody House house, HttpServletRequest request) { Integer userId = (Integer) request.getAttribute("userId"); house.setOwnerId(userId.longValue()); house.setStatus(0); // 新发布房源默认待审核 house.setCreateTime(new Date()); houseService.save(house); return Result.success(null); }

查列表接口用 MyBatis-Plus 的分页插件,Page 参数从 URL 里取。注意过滤 status 和 city,否则前端筛选就白了。

@GetMapping("/api/house") public Result listHouse(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size, @RequestParam(required = false) String city, @RequestParam(required = false) Integer status) { LambdaQueryWrapper<House> wrapper = new LambdaQueryWrapper<>(); if (city != null && !city.isEmpty()) { wrapper.eq(House::getCity, city); } if (status != null) { wrapper.eq(House::getStatus, status); } wrapper.orderByDesc(House::getCreateTime); Page<House> result = houseService.page(new Page<>(page, size), wrapper); return Result.success(result); }

LambdaQueryWrapper 是 MyBatis-Plus 的常规写法,优势是列名在编译期就能检查,不会出现写错字符串字段名导致运行时报错的情况。defaultValue 一定不要省,前端漏传 page 参数时后端不至于 500。我在教学时会特意让学生把后端的入参校验当一回事,把“接口的容忍度”打磨好,演示时怎么点都不容易爆炸。

这个闭环跑通后,再往上涨收藏、下单、账单就是重复劳动。所以毕设项目的进度管理也可以这样拆:第一周跑通登录闭环,第二周跑通房源闭环,第三周把订单和账单接上,最后留一周给论文和演示视频,完全来得及。

5. 联调勿踩五个坑:从跨域、时区到刷新 404 的现场排查

前后端分离项目的 80% 翻车现场都集中在联调阶段,而且大概率都是小问题。我把高频踩坑整理成五条,每一条都按“现象 → 原因 → 解决”的顺序写,你逐条对照能省下大量时间。

5.1 登录请求一直 401,控制台报跨域

现象是前端登录按钮点了没反应,浏览器控制台出现 CORS error 或 401。查后端日志发现请求根本没到 Controller。原因往往是前端开发服务器和 SpringBoot 端口不同,浏览器限制了跨域请求。解决方法是给 Vite 配置开发代理,把 /api 前缀转发到 http://localhost:8080,前后端联调从此不用再碰跨域。

// vite.config.js export default { server: { port: 5173, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } }

一个更隐蔽的 401 原因是拦截器没有放行预检请求。浏览器在跨域 POST 请求前会先发一个 OPTIONS 请求,如果拦截器直接拦截 OPTIONS 而不放行,预检失败,前端表现为请求 401。解决是在拦截器里加一行判断:如果是 OPTIONS 直接返回 200。用了 Vite proxy 后这个坑自动没了,但如果你是完全分离部署,就必须处理。

5.2 后端连不上 MySQL,报通信链路异常

现象是 SpringBoot 启动时一大堆红色堆栈,最后一行的关键字是 Communications link failure。原因有两个最集中:一是 MySQL 服务没启动或密码不对;二是 JDBC 连接串缺少时区参数,MySQL 8 默认时区不允许的不明时区。解决方法是先确认 MySQL 能本机登录,再把 JDBC URL 带全参数。

spring.datasource.url=jdbc:mysql://localhost:3306/house_rent?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=你的密码

时区参数 serverTimezone=Asia/Shanghai 是必填的。我记得第一次搭这套环境时没有带这个参数,报错信息很抽象,百度一圈才找到答案。现在我把这段连接串当成模板用,新项目直接复制改库名。

5.3 登录成功跳转后刷新页面就 404

现象是页面在站内点着没问题,一按 F5 就出现白底黑字的 404 页面。原因是 Vue Router 用的 history 模式,前端路由是虚拟路径,刷新时浏览器把 /house/list 当成后端接口去请求,SpringBoot 没有这个路径就 404。解决有两个方案:后端把所有非 /api 的请求统一返回 index.html,或者把 Vue Router 改成 hash 模式。

@Controller public class PageController { @RequestMapping(value = {"/", "/login", "/register", "/house/**", "/order/**", "/admin/**"}) public String forward() { return "forward:/index.html"; } }

对毕业设计,我建议直接改 hash 模式,改一行代码的事,演示时不会因为有人手滑刷新而翻车。history 模式留给生产环境去折腾,毕设没必要在这个地方冒险。

5.4 图片上传后列表页不显示

现象是图片上传接口返回了成功,但页面上的 img 标签一片空白,控制台显示图片 URL 404。原因是文件保存到了本地磁盘目录,但 SpringBoot 没有把那个目录暴露成静态资源。解决是加一个资源映射配置。

@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // /upload/** 转发到本地磁盘 D:/house-rent-upload/ 目录 registry.addResourceHandler("/upload/**") .addResourceLocations("file:D:/house-rent-upload/"); } }

这个坑的特点是“接口返回正常,图片就是不显示”,非常容易让人怀疑是前端问题。排查方法其实很笨:浏览器单独打开图片地址,看状态码。404 就是资源映射问题,200 但空白就是代码问题。记住这一条,以后遇到所有静态资源问题都能用同样思路定位。

5.5 端口被占用,第二次启动起不来

现象是 spring-boot 启动时提示 Port 8080 was already in use。原因通常是上一次运行没退出,或者电脑里有别的进程占了端口。解决方法是查进程后杀掉,或者换个端口。换端口的副作用是前端 proxy 的 target 也要同步改,忘改就等于没换。

# 查出占用 8080 的进程 PID lsof -i :8080 # 杀掉指定进程 kill -9 PID

这个问题虽然基础,但几乎每个同学都遇到过。我的习惯是启动前先看一眼端口占用,属于成本极低但收益极高的自我保护。另一个相关的坑是 npm run dev 和 java -jar 同时跑着多个实例,改完代码没生效就以为是代码问题,结果发现浏览器连的是另一个进程,属于纯折腾,遇一次就长记性了。

6. 答辩前必做的一项验证:把演示流程录成一条完整故事线

代码全部跑通后,离交付还剩最后一步:演示视频与论文的一致性问题。我见过太多这类项目,论文里写的流程和实际系统演示路径对不上,评审老师一点就穿帮。我的做法是先把一条主流程脚本写死在纸上,照它录视频、照它画论文图。

这条脚本建议从管理员身份开始而不是租客。管理员登录后台审核一个房源,这个动作展示了房态从“待审核”到“上架”的状态变化;然后切到房东端确认租住申请,展示订单状态从“待确认”到“已签约”;再切到租客端缴费,展示账单从“待支付”到“已支付”。一条线走完三种角色、四张表的状态流转,比零散演示十个页面更有说服力。

录视频时有个习惯我一直保留:留一个“恢复初始数据”的 SQL 脚本,录之前先跑一遍,保证演示数据处于可复现状态。我第一次录演示视频时没做这步,录到一半发现待审核列表里混着几十条测试垃圾数据,只能重录,后来索性把初始化数据脚本写成了固定工具。评审老师问“数据从哪里来”,你回答“有初始化脚本一键生成演示数据”,也是加分项。

论文的时序图直接照着演示脚本画一条:租客发起申请、房东确认、系统生成账单、租客支付,四步一个来回。ER 图则用第 3 章的四张核心表,把外键关系标清楚。答辩 PPT 翻到这一页时,你就可以说“整个系统围绕一条租赁主流程展开,四个实体支撑了从找房到退租的完整闭环”,这句话十几秒讲完,但比念十页 PPT 都管用。

希望这一套拆解能帮到正在和毕设搏斗的你。黑白盒测试用例表也别忘了做,把这条主流程的每个操作对应到输入、输出、预期结果,一张 Excel 表就能让论文的“测试”章节显得完整。做完整套流程你会发现,这类系统最难得的不是某个炫技功能,而是“把自己讲圆”的能力。技术部分照抄没难度,把业务逻辑吃透再落到论文,才是真正拉开差距的地方。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

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