又是一年毕设季,后台看到不少人在问“Spring Boot项目做什么课题好”“租房系统这种题还有没有得做”。说实话,[基于springboot大学生租房系统]这个题目我前后带过几届学生落地,每次都能碰到新的坑,也总结出一套比较完整的实现路径。这篇文章就把整个选题、设计、开发、排错、答辩的思路完整拆开,从需求分析到表结构,从核心代码到部署细节,一次性说清楚。不管你是正在选毕设课题的在校生,还是想快速搭一套租房类业务原型的开发者,这篇都能直接拿来当参考。
1. 项目立项:为什么这门课题能成为精选
1.1 课题背景与核心需求解读
大学生租房这件事,需求一直很真实。每年新生入学、实习季、考研季,都有大量学生需要在校园周边租房子,但传统的租房平台鱼龙混杂,信息真实性、中介费、房东直租渠道等问题让很多学生踩坑。做一个专属大学生的租房系统,核心不是做一个“大而全”的房产平台,而是把“学生身份认证、房东直租、房源信息透明、线上预约看房”这些场景做扎实。
从课题含金量的角度看,它的业务链路足够完整:用户体系、房源管理、订单流转、收藏评论、后台统计,基本把Web开发里的常见业务都覆盖到了。难度又刚好卡在“不是玩具级,但也够得着”的区间,非常适合用Spring Boot这样的成熟框架去落地。你别小看这类课程设计性质的选题,真正做得好的系统,拿出去给企业看,也能证明你具备独立完成一个完整业务闭环的能力。
1.2 技术选型的底层逻辑:为什么非Spring Boot不可
很多人在选型时会纠结,做毕设到底用SSM还是Spring Boot。我的建议很明确:直接Spring Boot。原因不是Spring Boot“更高级”,而是它把Spring家族里那些繁琐的XML配置、依赖管理、第三方集成全部收编了,核心思想就是约定大于配置。
理解这点很重要,尤其面试或答辩时经常被问“Spring Boot自动装配原理”。简单说,Spring Boot在启动时会扫描META-INF/spring.factories或AutoConfiguration.imports里的自动配置类,根据当前Classpath下有没有对应的依赖、有没有用户自定义的配置,决定要不要创建对应的Bean。比如你引入了spring-boot-starter-web,它就自动帮你配置Tomcat和SpringMVC;你引入了mybatis-spring-boot-starter,它就自动帮你注册SqlSessionFactory。这就是你只需要写少量配置就能跑起来的原因。
Spring Boot本身覆盖了大量生产级功能:内嵌服务器、外部化配置、监控端点、多环境Profile、统一的依赖管理,生态成熟度极高。再加上“面试题常客”的属性,做完这个项目,你对Spring Boot的理解会直接变成简历上能聊的实战经验。
1.3 环境准备:版本搭配和工具清单
环境这块我踩过最大的坑就是版本。Spring Boot版本选择直接决定后续开发是舒服还是折腾,这里我按两年内反复验证过的稳定组合给你列一份清单:
| 组件 | 推荐版本 | 说明 |
|---|---|---|
| JDK | 1.8 / 11 | 如果选Spring Boot 2.7.x,JDK1.8完全够;选3.x就需要JDK17 |
| Spring Boot | 2.7.18 | 这是2.x的最后一个维护版本,稳定,坑最少 |
| Maven | 3.6.3及以上 | 依赖管理,别用太老的版本 |
| MySQL | 5.7 或 8.0 | 生产建议8.0,字符集统一utf8mb4 |
| MyBatis-Plus | 3.5.x | 做CRUD效率极高,适合快速开发 |
| Redis(可选) | 5.x/6.x | 用于验证码、热点房源缓存 |
| IDEA | 2023.x | 自带Spring Initializr,新建项目方便 |
| Node.js | 16.x/18.x | 前端Vue项目构建用 |
这里单独说一句版本的事。Spring Boot 3.0以后有一个大变化:javax.*包名迁移成了jakarta.*,很多老教程里的import javax.servlet.*直接编译不过。如果你对Spring Boot不熟,建议直接锁死2.7.x,别追新。网上搜主题的时候,搜“springboot版本太高”能看到大量“启动报错找不到XXX类”的问题,大部分就是版本迁移导致的。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统总体架构与技术方案设计
2.1 前后端分离还是传统模板方案
做这类系统,第一个要拍板的问题就是前后端是不是要分离。我推荐选择前后端分离架构,也就是Spring Boot做纯后端接口,前端用Vue + Element-UI(或Element Plus)搭建页面。
为什么?两个层面的考虑。第一是开发效率。前端组件库帮你把UI框架搭好,你只需要关注页面组件编写和数据交互,比在JSP里拼接HTML、再纠缠Thymeleaf模板语法舒服得多。第二是答辩和面试的含金量。前后端分离的系统能体现你懂接口设计、懂跨域、懂Token鉴权,这些是当前企业开发的主流形态,比传统的单体模板方案更有说服力。
两者对比大概是这样:
| 维度 | 传统单体模板(JSP/Thymeleaf) | 前后端分离(Vue + REST API) |
|---|---|---|
| 开发效率 | 前端代码和后端耦合,改样式要重启 | 前后端可并行,接口联调即可 |
| 项目体量 | 相对较小 | 多一个前端工程,内容更充实 |
| 答辩/面试加分 | 较弱 | 强,能展示更多技能点 |
| 部署成本 | 一个包搞定 | 需要分别部署前端静态资源和后端服务 |
需要提醒的是,选了前后端分离,就要接受“两个项目”的事实。前端用Vue CLI或Vite创建工程,配好vue-router路由和axios请求封装;后端按接口规范输出JSON。联调阶段经常会遇到跨域、Token过期、字段名对不上这类问题,这些我会在后面“常见问题”章节详细讲。
2.2 角色体系与功能模块梳理
租房的业务里天然有三种角色:学生(租客)、房东、管理员。设计系统时,最好把这三种角色从用户表开始就区分开,用角色字段控制权限,而不是各建一套表,否则后面要改权限模型会非常痛苦。
- 学生端:注册登录、浏览房源、搜索筛选、收藏房源、在线预约看房、提交订单、评论评分、个人信息管理。
- 房东端:注册登录、发布房源、管理房源上下架、查看预约、处理看房申请、确认租房订单、查看自己房源的被收藏和评论情况。
- 管理员端:用户管理(禁用/启用)、房源审核、公告发布、订单监管、数据统计(房源数、订单数、成交金额、新增用户等)。
功能模块拆开就是经典的“用户-房源-订单”三大核心域,加上收藏、评论、公告三个辅助域。订单模块是整个业务的闭环核心,学生看中房子后,线上预约提交订单,房东确认,然后双方线下看房或直接签约。系统里不需要设计太复杂的支付流程,但必须把订单状态流转设计清楚。
2.3 后端工程结构与代码规范
项目结构直接决定你后期维护和答辩讲代码时的心情。推荐按以下包结构组织后端工程:
text复制com.example.houserent
├── config // 配置类:WebMvc、Cors、MybatisPlus分页
├── controller // 接口层,只做参数接收和结果封装
├── service // 业务层,核心逻辑都在这里
│ └── impl
├── mapper // MyBatis-Plus的Mapper接口
├── entity // 数据库实体类
├── dto // 接收前端参数的传输对象
├── vo // 返回给前端的视图对象
├── common
│ ├── Result // 统一结果封装
│ ├── ResultCode // 状态枚举
│ ├── exception // 全局异常、业务异常
│ └── utils // JWT工具、密码加密工具等
└── interceptor // 登录拦截器、管理员权限拦截器
写这套系统的时候,从一开始就要统一返回格式。我习惯用Result对象包裹所有接口返回值,结构如{ code: 200, message: "success", data: {...} },每个接口的code有明确含义。这样前端处理逻辑可以统一,不需要每个接口单独判断。
可能有人觉得,毕设而已,不搞这些花里胡哨的行不行?我的意见是,代码规范不是花架子。答辩时,你有没有规范化的异常处理、统一的返回结构、清晰的分层,评委一眼就能看出来。而这些习惯也是你以后进团队协作的基本要求。
3. 数据库设计:一张房源表如何撑起整个业务
3.1 数据表整体规划与关联关系
租房系统的核心表我认为是这几张:用户表(sys_user)、房源表(house)、订单表(house_order)、收藏表(favorite)、评论表(house_comment)、公告表(notice),以及前端的轮播图表可选。
这几张表的关系一句话概括:一个用户(房东)可以发布多套房源,一个用户(学生)可以收藏多套房源、提交多个订单、发表多条评论。所以house表通过user_id关联房东,favorite表是用户和房源的多对多中间表,house_order表通过user_id和house_id关联双方,house_comment同理。设计时可以画一张简单的ER图,但这个图用文字描述清楚关系即可,答辩时能讲明白表之间为什么要这样关联,一定加分。
3.2 核心表结构:房源表与订单表的设计细节
房源表是系统里字段最多的表,直接决定检索功能的体验。我建一个核心版本的建表SQL给你参考,标注了每个关键字段的设计意图:
sql复制CREATE TABLE `house` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) NOT NULL COMMENT '房东用户ID',
`title` varchar(100) NOT NULL COMMENT '房源标题',
`cover` varchar(255) DEFAULT NULL COMMENT '封面图URL',
`images` text COMMENT '详情图,逗号分隔或JSON',
`province` varchar(50) DEFAULT NULL COMMENT '省',
`city` varchar(50) DEFAULT NULL COMMENT '市',
`district` varchar(50) DEFAULT NULL COMMENT '区/县',
`address` varchar(255) DEFAULT NULL COMMENT '详细地址',
`rent_type` tinyint(1) DEFAULT '0' COMMENT '出租方式:0整租 1合租',
`house_type` varchar(20) DEFAULT NULL COMMENT '户型,如2室1厅',
`area` decimal(10,2) DEFAULT NULL COMMENT '面积(平方米)',
`price` decimal(10,2) NOT NULL COMMENT '月租金(元)',
`deposit` decimal(10,2) DEFAULT NULL COMMENT '押金',
`status` tinyint(1) DEFAULT '0' COMMENT '状态:0待审核 1已上架 2已下架 3已出租',
`description` text COMMENT '房源描述',
`view_count` int(11) DEFAULT '0' COMMENT '浏览次数',
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除标记',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_city_price_status` (`city`, `price`, `status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='房源表';
这里有几个关键设计细节,我做项目时踩过坑才体会到重要性:
第一,状态字段必须明确枚举含义,0待审核、1已上架、2已下架、3已出租,前端和后端都要用常量或枚举统一,不要散落在代码里写魔法值。第二,经纬度字段可以先不建,但如果后续想接地图,建议预留lat和lng。第三,逻辑删除字段deleted必加,用户、房源这类核心数据不要物理删,方便回溯,也避免外键问题。第四,idx_city_price_status这个联合索引很有用,因为租房场景最常见的就是“某城市+价格区间+上架中”组合筛选,这个索引能直接命中。
订单表是另一个需要特别注意的表。订单不只是记录一次交易,它其实是“预约看房/达成租房意向”的凭证,所以建议包含:订单号、订单类型、关联房源ID、房东ID、学生ID、期望看房时间、订单状态、定金或成交价快照、备注。这里最容易被忽略的是“快照”字段。比如学生在今天看中一套房并下单,价格是1500元/月;房东明天把价格改成1800元/月,如果订单里只关联外键不存快照,历史订单展示时价格就乱了。所以订单表里要冗余一份house_title和house_price,后续无论房源如何改动,订单都能按照当时的交易快照展示。
3.3 查询优化与常见性能陷阱
租房系统的数据量在毕设阶段不大,但SQL习惯得从一开始就对。最容易出问题的点是模糊搜索。比如一个搜索“XX大学附近房源”的功能,如果直接写LIKE '%关键字%',当表里数据量涨到几万条时,查询会明显变慢,因为%关键字%没法走索引。
我的做法是,标题和描述这类文本用LIKE可以接受,但必须搭配其他等值条件(比如城市)先把数据范围缩小;如果真要支持全文搜索,可以引入Elasticsearch或者MySQL全文索引,但课题阶段没必要。另一个常见问题是查询返回大量字段但没有分页,直接在Mapper上selectList就算了。设计接口时,列表页统一用MyBatis-Plus的分页插件PaginationInnerInterceptor,每次分页返回,既省流量又省内存。代码就两步:
java复制@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
4. 核心功能模块实现:从登录到订单的完整闭环
4.1 用户注册登录与JWT权限控制
登录模块是系统的门面,也是最容易在答辩时被追问的地方。我建议密码加密直接使用Spring Security自带的BCryptPasswordEncoder,或者集成Jasypt做更复杂的加密处理。BCrypt的好处是每次加密生成的hash都不同,自带盐值,即使两个用户密码相同,密文也不同,比MD5加盐安全得多,而且使用简单:
java复制@Configuration
public class SecurityConfig {
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
存储时调用passwordEncoder.encode(rawPassword),校验时调用passwordEncoder.matches(rawPassword, encodedPassword)即可。需要说明的是,这里我并没有引入整套Spring Security框架,因为它的过滤链和配置对新手来说过于复杂,课题阶段用“拦截器 + JWT”的方式就能达到同样的权限控制效果,而且逻辑更直观。
JWT的流程是:用户登录成功后,后端用用户ID和角色生成一个Token,设置过期时间,返回给前端;前端每次请求在Header里带上Authorization: Bearer <token>;后端定义一个拦截器,对需要登录的接口校验Token合法性,再从Token里解析出用户信息放入ThreadLocal或请求上下文。放行白名单包括注册、登录、主页房源列表、房源详情等公开接口。这里有一个网上问得非常多的问题:“Spring Boot集成JWT后Swagger接口文档也报401”。这类场景排查一下就清楚:Swagger的静态资源路径和认证接口没有被放行。解决办法是在拦截器配置里加入/swagger-resources/**、/v3/api-docs/**、/webjars/**、/doc.html等路径地址。
拦截器的核心代码大概是这样:
java复制@Component
public class JwtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 放行预检请求和放行白名单
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7);
}
// 校验失败则返回401
if (!StringUtils.hasText(token) || !JwtUtil.verify(token)) {
response.setStatus(401);
return false;
}
// 解析用户ID并放入request属性
Claims claims = JwtUtil.parse(token);
request.setAttribute("userId", claims.get("userId"));
return true;
}
}
注册功能还有一个容易被忽略的细节:同一个手机号或邮箱不能重复注册,要在设计表时加唯一索引,同时注册接口里先查一次。这里也顺带说一下验证码,可以用Redis存一个5分钟有效期的短信或邮箱验证码,前端输入后先校验再落库用户,能显著提升系统完整度。
4.2 房源发布与多条件检索
房源发布是房东端的核心功能。前端是一个表单页,包含标题、图片上传、地址、户型、租金和描述等字段;后端接收后先做参数校验,把当前登录用户ID写入user_id,然后设置初始状态为待审核,落库。图片上传我建议先存到服务器本地目录,再通过一个/images/**的资源映射把图片URL返回给前端;不推荐存到数据库的BLOB字段,查询会拖慢性能。
Spring Boot做本地资源映射有两种常见方式,一种是在application.yml里配置虚拟路径,一种是写WebMvcConfigurer。前者简洁,适合毕设:
yaml复制spring:
mvc:
static-path-pattern: /images/**
resources:
static-locations: file:E:/upload/ # Windows本地路径,Linux改路径即可
这样上传后的文件放入E:/upload目录,前端访问http://localhost:8080/images/xxx.jpg就能直接加载图片。但注意生产部署到Linux后,这个路径要改成服务器上的绝对路径,并创建对应的目录,否则图片404。
多条件检索是学生端房源列表页的核心,通常包含:城市/区域、出租方式(整租/合租)、户型和价格区间、关键字搜索。用MyBatis-Plus的LambdaQueryWrapper构造动态条件非常顺手:
java复制public Page<HouseVO> searchHouse(HouseQueryDTO query) {
LambdaQueryWrapper<House> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(House::getStatus, 1); // 只看已上架
wrapper.eq(StringUtils.hasText(query.getCity()), House::getCity, query.getCity());
wrapper.eq(StringUtils.hasText(query.getDistrict()), House::getDistrict, query.getDistrict());
wrapper.eq(query.getRentType() != null, House::getRentType, query.getRentType());
wrapper.between(query.getMinPrice() != null && query.getMaxPrice() != null,
House::getPrice, query.getMinPrice(), query.getMaxPrice());
// 关键字匹配标题或描述
if (StringUtils.hasText(query.getKeyword())) {
wrapper.and(w -> w.like(House::getTitle, query.getKeyword())
.or().like(House::getDescription, query.getKeyword()));
}
wrapper.orderByDesc(House::getCreateTime);
return houseMapper.selectPage(new Page<>(query.getPageNum(), query.getPageSize()), wrapper);
}
这套代码写出来,基本覆盖了毕设阶段90%的筛选场景。如果后续要优化搜索体验,可以考虑引入hanlp分词,先把用户输入的分词拆开再拼接检索条件,但那是锦上添花的事。回到课题本身,把基础检索做好、排序清晰、前端筛选联动做好,已经是令人满意的完成度。
4.3 预约看房与订单状态流转
订单这块建议先画清楚状态机再写代码。我设计的订单状态是:0待确认,学生提交预约后生成;1待看房,房东确认预约生效;2已完成,看房签约或直接租房成功;3已取消,任何一方取消;4已拒绝,房东拒绝预约。
核心流程是“学生发起预约 → 房东确认/拒绝 → 学生按约定时间看房 → 双方线下确定 → 状态完成”。系统不需要做在线支付,但可以在订单详情里展示定金金额和租金快照。状态流转的权限控制要特别注意:只有房东能操作自己的房源订单的待确认和拒绝,只有学生能发起预约和取消。实现时先把订单查出,校验订单里的houseId是否属于当前登录房东,再更新状态,顺序不能反,否则可能出现越权操作。
状态更新这里必须加事务和乐观锁控制。比如说,学生提交订单的一瞬间,正好房东把房源下架了,如果没有校验,就会生成一个对已下架房源的订单。所以下单接口要加事务,查询房源状态、创建订单、扣减库存(如果有房源库存概念)要保证原子性。Spring Boot中在Service方法上加@Transactional即可,同时注意自调用时事务会失效,这个坑我放到下一节详细说。
4.4 管理后台的统计看板
管理后台是展示系统完整度的重要一环,也能体现你对Spring Boot常用组件的掌握程度。统计看板可以包含:用户总数、房源总数、订单总数、成交总额、今日新增用户数、待审核房源数量。实现方式简单,Mapper里写几个聚合SQL,比如:
java复制@Select("SELECT COUNT(*) FROM house WHERE status = 0")
Long countPendingHouse();
@Select("SELECT IFNULL(SUM(price), 0) FROM house_order WHERE status = 2")
BigDecimal countTotalAmount();
然后一个接口一次性返回这些统计项,前端用ECharts画饼图和折线图,观感会非常好。我见过很多学生做后台只是简单的CRUD,如果能把管理员的统计看板做出来,整体完成度立刻提升一个档次。
5. 开发过程中踩过的典型问题与排查技巧
5.1 Spring Boot版本过高导致的环境连环坑
这是这几年我带项目过程中遇到频率最高的问题。很多朋友打开IDEA用Spring Initializr初始化项目,默认会拉最新版Spring Boot,然后跑起来就报错。最常见的几类:
javax.servlet不存在:Spring Boot 3.x全部迁移到jakarta.servlet,所有导入javax开头的依赖类全部编译失败。- 配置项变更:比如
spring.redis.*变成了spring.data.redis.*,springfox的Swagger在Spring Boot 2.6以后会因为路径匹配策略改变而失败。 - 第三方starter版本不兼容:很多教学用的依赖(比如某些旧版MyBatis-Plus、旧版Shiro)没跟上Spring Boot 3,直接启动异常。
排查思路是:先看spring-boot-starter-parent版本号,和代码里import包名对照。发现jakarta开头的,说明是3.x;发现javax开头的,说明是2.x。网上搜代码示例时,先确认对方的Spring Boot版本再复制,否则很容易越改越乱。我的建议是直接统一使用2.7.18,这个版本是2.x的最终版,稳定、资料多,配合JDK1.8,几乎不会在这个层面卡壳。如果学校老师要求用新版本,那建议一开始就完整系统的学习一下Spring Boot 3的知识点,不要新旧混着查资料。
5.2 事务失效场景与循环依赖问题
事务失效是Spring Boot面试高频题,也是项目实践里容易踩的坑。最常见的失效场景有三个。
第一个是同类内部调用。比如OrderServiceImpl里有一个createOrder方法,它调用同类的updateHouseStatus方法,而updateHouseStatus上标了@Transactional,看起来有事务,实际不会生效。原理是Spring的事务是通过AOP代理实现的,内部调用绕过代理,直接调用了目标对象的方法,事务拦截器根本没机会介入。解决办法是把内部方法拆到另一个Service里调用,或者自己注入代理对象,最省事的做法是把两段逻辑合并到同一个事务方法中。
第二个是异常被吞。事务方法里写了try-catch把异常捕获了,没抛出,事务判定“方法正常执行完毕”,于是不会回滚。正确的做法是捕获到业务异常后继续抛出RuntimeException,或者用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()手动标记回滚。
第三个是方法不是public。Spring默认只对public方法做事务代理,如果你把@Transactional标在private方法上,完全没有效果。遇到这种情况就把方法改成public,或者调整调用层级。
循环依赖问题也很常见。场景一般是两个Service互相注入,比如HouseService里注入OrderService,OrderService里又注入HouseService。Spring Boot 2.6以后默认禁止循环依赖,启动时会报The dependencies of some of the beans in the application context form a cycle。解决思路有三个:一个是重构代码,把互相调用的逻辑抽出来放到新的Service层;第二个是使用@Lazy注解延迟注入打破循环;第三个是用@Autowired加@DependsOn调整初始化顺序。我最推荐的是第一种,虽然改起来麻烦,但后期维护最舒服,而且答辩时可以顺便讲清楚了依赖设计的原则。
5.3 前后端联调中的跨域、时间格式与字段映射问题
前后端分离后,跨域是第一个见面礼。前端在8081端口,后端在8080端口,浏览器默认拦截跨域请求。很多人一开始用前端代理解决,但调试不方便,我建议后端直接配置全局CORS。Spring Boot里最简洁的方式是写一个CorsFilter的Bean,或者实现WebMvcConfigurer的addCorsMappings方法:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
注意:allowedOrigins("*")配合allowCredentials(true)在某些版本会报错,建议用allowedOriginPatterns("*")替代。
时间格式的坑也很隐蔽。后端返回LocalDateTime默认是数组或者带T的格式,前端拿到后要么解析出错,要么显示不友好。解决方案是在application.yml里统一全局时间格式:
yaml复制spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
实体里的LocalDateTime字段如果不想全局影响,可以加@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")。另外前端拿到的返回JSON里字段命名不一致会导致数据显示不出来,常见问题是Java的camelCase和前端snake_case混用。我的做法是后端统一用驼峰,前端也统一用驼峰,不做任何转换,避免各套一套规则越弄越乱。如果你用MyBatis-Plus,它默认开启驼峰映射,所以数据库字段用下划线、实体用驼峰,这个配置天然解决映射问题。
5.4 Docker部署与文件路径映射
最后部署环节,推荐用Docker把Spring Boot项目打包成镜像,发布到Docker Desktop上跑。打包步骤很清晰:先用Maven把项目打成JAR,然后在项目根目录创建Dockerfile:
dockerfile复制FROM openjdk:8-jre-alpine
WORKDIR /app
COPY target/houserent-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
然后执行docker build -t houserent:latest .,再执行docker run -d -p 8080:8080 -v /data/upload:/data/upload --name houserent houserent:latest。这里有一个特别关键的细节:上传图片保存在宿主机的/data/upload目录,如果你不打这个-v卷映射,容器一删图片全没了,因为容器内部的文件系统是临时的。所以发布到Docker环境时,application.yml里的static-locations必须指向容器内的路径,同时把这个路径挂载到宿主机目录,才能持久化图片数据。
6. 答辩与二次开发:如何把项目做出差异化
6.1 让评委眼前一亮的几个小细节
同一个毕设题,不同人做出来的分差可以非常大。除了把功能和页面做完整,还有很多“印象分”值得花半天时间去做。
定制一个专属启动Banner。Spring Boot启动时的那个“Spring”字样也可以用banner.txt替换,你可以在网上搜springboot banner生成器,把自己的学号、项目名、或者一句专业话术做成字符画放到resources/banner.txt里。启动项目后第一眼看到的就是你的名字,这个小细节在答辩演示时非常讨巧。
统一异常处理和参数校验。定义一个@RestControllerAdvice全局异常处理器,把业务异常、空指针异常、参数校验异常统一转换成Result对象返回,而不是把默认的错误堆栈抛给前端。再配合@Validated和@NotNull这类校验注解,可以让代码看起来非常“企业级”。
接口文档建议用knife4j,它是Swagger的增强版,界面比原生Swagger好看很多,集成也简单。把每个接口写上一两句话说明,演示时对着文档讲接口设计,比现场调代码清爽得多。再配合数据填充脚本,用CommandLineRunner在项目启动时往数据库里插入一批带真实感的测试数据,演示效果会好很多。
6.2 项目后续的扩展方向
一个课题交出去不是终点,这个项目完全可以做成一个持续演进的项目,提升简历含金量。
可以引入Flowable做租房审批流程。比如房源的发布审核、学生的租房申请审批,这些场景本质上是流程审批,用Flowable定义BPMN流程,后端发起流程、完成任务、查询待办,系统的复杂度和竞争力都直接上一个台阶,面试时聊“工作流引擎”也是很大的加分项。
可以做消息通知模块。预约状态变化时,通过WebSocket给用户推送站内信;或者集成一个简单邮件接口,状态变化发送邮件提醒。不过考虑到多数课程设计没有真实的短信服务,用Redis存通知记录,在站内做“我的消息”列表就可以了。
可以做数据可视化。ECharts接上订单趋势、区域热度、价格区间分布等统计图表,这部分其实就是把后台看板做成一个真正的数据分析页面,也会让系统显得更完整。
还可以接入地图组件,展示房源地理分布位置。如果做了这个,请务必在地理编码字段上提前设计好经纬度。这个功能的体验感和落地性都很强,也是我说为什么在房源表设计时强调要预留经纬度字段的原因。
最后再分享一个个人经验,如果你准备把这套项目作为求职项目,一定不要只背“用什么技术”,而要能把“为什么这么设计”讲出来。比如订单表为什么存快照、状态为什么要枚举、房源为什么要有状态机、跨域为什么要配置OriginPatterns。面试官问的往往不是你会不会写这个页面,而是你对业务细节和技术决策的思考深度。这也是这篇文章花了大量篇幅讲底层逻辑和踩坑排查的原因——这些东西,才是真正让你从“会做”变成“会讲”的关键。
