ARTICLE DETAIL

资讯详情

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

基于SpringBoot+Vue的租售一体房源系统毕设全链路指南

基于SpringBoot+Vue的租售一体房源系统毕设全链路指南 如果你最近正在为计算机毕业设计选题头疼应该已经刷到过大量基于SpringBoot的XX商城系统了。商城都快被写烂了评委一眼扫过去根本分不清谁是谁。相比之下基于SpringBoot的房源出租信息系统这个方向要聪明得多——它不是简单的增删改查而是把租和售两条业务线装进同一个平台再靠租赁撮合这种带点智能味道的逻辑撑起亮点。技术栈正好落在最稳妥的SpringBootVue组合上无论是实现难度、演示效果还是答辩深度都处在一个非常适合本科生拿高分的区间。这篇文章我会从一个完整做完这个项目的人的角度把从选题、数据库设计、后端接口、前端页面到部署演示、答辩准备的整个链路拆开讲。不整虚的每一步都是能直接抄作业的干货同时也把那些网上搜不到的设计理由和踩坑心得一并交代清楚。不管你打算自己从零写还是已经搭了一半卡住了这篇文章应该都能帮上忙。1. 项目定位为什么租售一体化比普通管理系统更容易出彩1.1 这个系统本质上在做一件什么事先把业务逻辑说透。房源出租信息系统听名字像是个信息展示网站但真正做完你会发现它的核心不是展示而是撮合。房东手上有多余房源租客或买家有居住或购房需求平台要做的就是把双方高效拉通房东发房源、平台审核、租客检索、系统根据用户偏好推荐、在线下单、模拟支付、生成合同、确认成交。这一整套流程走下来一个真实的交易闭环就成型了。一体化三个字也不白加。它意味着系统里同时包含租赁和销售两条线路。租赁走租金、押金、租期、续租逻辑销售走总价、首付、产权状态逻辑。两条线共用一套用户体系、一套房源基础表但在字段设计和流程处理上各走各的。这种同一平台、双业务线的结构比单一租赁系统或者单一二手房展示系统在复杂度和展示面上高出一个档次。智慧二字则是加分项。它不一定要求你上深度学习算法而是可以用简单的匹配置信度逻辑实现系统根据用户的预算区间、期望区域、户型偏好、租期长度对每一套房源打分排序把最可能成交的房源推到用户面前。这一点做出来答辩时就可以名正言顺地说这个系统实现了基于多维度匹配的房源推荐机制——评委很吃这一套。1.2 SpringBoot Vue稳妥组合背后的具体版本选择这个项目我强烈建议用SpringBoot 2.7.x JDK 8而不是SpringBoot 3.x JDK 17。虽然SpringBoot 3已经发布很久了但对毕业设计来说不是越新越好。维度SpringBoot 2.7.x JDK 8SpringBoot 3.x JDK 17启动速度与内存轻量稳定低配笔记本很友好相对更吃资源国内教程数量占绝对多数报错容易搜到相对少很多老教程不可用第三方依赖兼容MyBatis-Plus、jwt、swagger等完全兼容部分starter的javax命名空间需要迁移到jakarta毕业设计够用性完全够用能做但没必要给自己加难度后端ORM选MyBatis-Plus而不是纯MyBatis理由很现实毕设周期内大部分操作是单表CRUDMyBatis-Plus自带的BaseMapper直接省掉几十个XML文件分页用PaginationInnerInterceptor几行搞定。也别迷信手写SQL显得有水平在答辩老师眼里能解释清楚为什么选MyBatis-Plus减少样板代码、专注业务逻辑本身就是一种工程意识。前端选Vue 3 Vite Element Plus Pinia Vue Router。Vue 2已经停止维护新项目完全没必要再踩进去。Vite比Webpack更轻更快启动项目是秒级体验。Element Plus是Element UI的Vue 3版本表格、表单、弹窗、分页这些后台管理界面组件现成就有做管理端能省一大半时间。状态管理用Pinia比Vuex语法更简洁TypeScript支持也更好。如果你连TypeScript都用不顺直接写JavaScript也别有压力毕设阶段能跑通就是胜利。流程走通之后你会发现这套选型组合在国内的社区活跃度极高任何报错基本是百度一搜就有人踩过同款坑的状态。最怕的不是报错是报错搜不到解决方案。选这套组合等于给自己买了一份最便宜也最全面的保险。2. 功能模块拆解租、售、撮合三条主线怎么划分2.1 三种角色与权限边界系统用户分成三类管理员、房东、租客/买家。不搞复杂的RBAC权限框架用一张用户表加一个role字段就够后端拦截器根据角色判断接口访问权限。功能管理员房东租客/买家注册/登录支持支持支持发布房源否支持否审核房源上下架支持提交后等待审核否浏览搜索房源支持支持支持收藏/在线咨询支持支持支持下单租赁/购买否否支持接单确认否支持否合同查看支持支持支持用户管理/数据统计支持否否这里有个容易被忽略的设计点房东也可以作为租客去租房租客也可以发布房源出售。所以不要把角色和功能做成一刀切的硬绑定权限判断应该放在操作层面而非用户类型层面。比如发布房源这个接口只要是登录用户且通过了实名信息补全就给开放审核接口才严格限制管理员角色。这样后端角色校验代码更灵活也能避免答辩时被问如果房东也想租别人房子怎么办。2.2 出租和出售的字段差异房源基础信息是共用的标题、描述、所在省份/城市/区域、详细地址、户型几室几厅、面积、朝向、楼层、装修情况、配套设置、图片列表、出租/出售标签。但业务字段必须得拆出租房源rent_house多出的字段月租金、押金金额、最短租期、最长租期、出租方式整租/合租、起租日期、当前是否已出租。出售房源sale_house多出的字段总价、首付比例要求、是否满五、产权类型商品房/公寓/自建房、是否唯一住房、看房预约时间。数据库设计时我建议不拆分这两张表而是在统一的house表上增加一个purpose字段1出租2出售再设计一张可选的house_rent_detail和house_sale_detail做一对一扩展。理由很简单首页列表、搜索、收藏这些最常用的场景都要同时捞两类房源拆成两张表会让查询逻辑重复且麻烦。一对一的扩展表方式既保持基础字段的干净又在特殊业务字段上留了足够空间。2.3 交易闭环中的状态流转一体化平台在流程上和普通信息发布网站最大的区别是它有交易状态。按下单前、下单后、签约后分三个环节房源状态待审核 → 已上架 → 租赁中/已预订卖出→ 已下架。订单状态租赁订单/销售订单待付款 → 待确认 → 进行中/已完成 → 已取消。合同状态草稿 → 已签署 → 执行中 → 已到期/已终止。三个状态是联动的。比如租客对某套房源下单并付款后房源状态立刻切到已预订其他用户再打开详情页只能看到已被预订而不能重复下单房东确认接单之后系统自动生成合同草稿双方在线确认签署后合同状态变为已签署。答辩的时候把这条联动链路演示一遍项目完整度直接拉满因为你不再是展示信息而是跑通业务。3. 数据库设计最容易被评审老师追问的一环3.1 八张核心表的关联关系数据库设计是答辩时最容易被追着问的部分因为它直接反映你对业务实体关系的理解。我最终落地的表结构如下user用户表存放账号、密码BCrypt加密存储、昵称、手机号、角色标识、注册时间。house房源主表存放基础信息、发布人ID、房源用途租/售、价格字段统一用分为单位存整数、房源状态、审核状态、浏览量。house_image房源图片表一个房源多条图片记录。house_rent_detail出租扩展字段表。house_sale_detail出售扩展字段表。favorite收藏表用户ID 房源ID的联合唯一索引避免重复收藏。order订单表通过order_type区分租赁订单/销售订单关联用户ID、房源ID、订单金额、状态、创建时间、支付时间。contract合同表关联订单ID、租客ID、房东ID、合同编号、起止日期、租金金额、双方电子签名状态、合同PDF文件路径。外键我建议不做物理外键只保留逻辑关联字段。理由有二一是MyBatis-Plus关联查询本身不依赖数据库外键物理外键还会拖慢插入、更新性能二是不少答辩老师自己就反对物理外键认为在真实企业开发中外键约束由业务层保证是更常见的做法。你只要把house.user_id对应user.id、order.house_id对应house.id这套关系在类里面写得清清楚楚回答时说明用逻辑外键保证灵活性和性能反而能加分。3.2 金额字段和状态字段的取舍细节几个容易翻车的细节提前说清楚金额一律用整数分存储不用decimal/double。这是行业共识原因就是浮点数精度问题。你展示房源列表时把3500000单位分除以100转换为元输出页面答辩提到为了避免浮点运算误差金额字段在存储层面统一以分为单位这句话本身就是亮点。状态字段用tinyint只用0、1、2、3、4这类枚举值不用字符串描述。一是省空间二是索引效率高三是避免已出租/已被预订/租赁中这种口语化描述带来的数据不一致。后端用一个HouseStatusEnum、OrderStatusEnum统一映射数字和中文含义前端拿到状态码后自己转文案。这里注意枚举值一旦上线不要改数字含义否则历史数据全乱。设计枚举时把趋势想清楚再定。house建表的关键语句大致长这样CREATE TABLE house ( id bigint(20) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL COMMENT 房东用户ID, title varchar(100) NOT NULL COMMENT 房源标题, purpose tinyint(1) NOT NULL COMMENT 1出租 2出售, province varchar(50) DEFAULT NULL, city varchar(50) NOT NULL, district varchar(50) NOT NULL, address varchar(200) NOT NULL, house_type varchar(20) DEFAULT NULL COMMENT 户型3室2厅1厨1卫, area decimal(10,2) DEFAULT NULL COMMENT 面积平米, price int(11) NOT NULL COMMENT 价格单位分租金/总价, deposit int(11) DEFAULT NULL COMMENT 押金单位分出租用, status tinyint(1) NOT NULL DEFAULT 0 COMMENT 0待审核 1已上架 2已预订 3已下架, view_count int(11) NOT NULL DEFAULT 0, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_city_district (city,district), KEY idx_price (price), KEY idx_purpose_status (purpose,status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT房源主表;注意索引的设计按城市区域检索、按价格区间检索、按用途状态筛选是房源平台最核心的三种检索路径对应的联合索引都安排上。另外MySQL 8.0默认字符集乱码问题在utf8mb4下彻底解决create_time、update_time这类公共字段用DEFAULT CURRENT_TIMESTAMP自动维护省心。4. SpringBoot后端从登录鉴权到租赁撮合的落地路径4.1 JWT鉴权与拦截器配置前后端分离项目里JWT是目前最主流也最容易讲的方案。流程是登录成功后后端签发token返回给前端前端每次请求带在Authorization请求头里后端拦截器校验token并解析出用户身份。核心配置类有这几个// JwtUtil负责生成和解析token public class JwtUtil { private static final String SECRET_KEY your-secret-key-please-change; public static String generateToken(Long userId, String role) { return Jwts.builder() .setId(userId.toString()) .claim(role, role) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() 7 * 24 * 3600 * 1000)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); } }// 拦截器解析token把用户信息放入ThreadLocal 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 )) { throw new BusinessException(未登录或登录已过期); } Long userId JwtUtil.parseToken(token.replace(Bearer , )); UserContext.set(userId); return true; } }这里有一个新手很容易踩的坑拦截器注册时一定要排除登录、注册、房源列表、房源详情这些匿名可访问的接口。否则你自己调试时会发现还没登录就列表都打不开了。用WebMvcConfigurer的addInterceptors方法显式添加excludePathPatterns比注解式拦截器好排查得多。另外token有效期建议设7天太短会导致用户频繁重新登录影响演示体验。4.2 房源发布与多条件检索的关键实现房源发布的核心接口围绕house主表 house_rent_detail或house_sale_detail两张扩展表事务注解Transactional保证基础信息扩展信息同时写入成功。检索是房源平台的重头戏。毕设量级的数据量几百条到几千条房源完全用不到ElasticsearchMySQL索引加动态SQL是最合理的解。用MyBatis-Plus的LambdaQueryWrapper拼接条件public PageHouseVO searchHouse(HouseSearchDTO dto) { LambdaQueryWrapperHouse wrapper new LambdaQueryWrapper(); wrapper.eq(House::getStatus, HouseStatusEnum.ON_SHELF.getCode()); if (StrUtil.isNotEmpty(dto.getKeyword())) { wrapper.and(w - w.like(House::getTitle, dto.getKeyword()) .or().like(House::getAddress, dto.getKeyword())); } if (dto.getPurpose() ! null) { wrapper.eq(House::getPurpose, dto.getPurpose()); } if (dto.getCity() ! null) { wrapper.eq(House::getCity, dto.getCity()); } if (dto.getPriceMin() ! null) { wrapper.ge(House::getPrice, dto.getPriceMin()); } if (dto.getPriceMax() ! null) { wrapper.le(House::getPrice, dto.getPriceMax()); } // 默认按发布时间倒序也可以按价格升序 wrapper.orderByDesc(House::getCreateTime); PageHouse page houseMapper.selectPage( new Page(dto.getPageNum(), dto.getPageSize()), wrapper); return transferToVO(page); }搜索接口注意几个细节关键词搜索建议同时匹配标题和地址命中率更高城市和区域是下拉选择而不是自由输入避免脏数据分页参数pageNum从0还是从1开始前后端要对齐——很多联调问题都出在这个差一错误上。再提一个热词里有人问的springboot定时任务房源平台里天然用得上。我加了一个简单的Scheduled(cron 0 0 2 * * ?)定时器每天凌晨两点把租期已到的房源自动释放为已上架状态顺便清理三个月前已删除的图片记录。这个功能代码量不大却是一个非常好的系统思考加分点答辩时可以讲我用了Spring Scheduled做整点状态巡检。4.3 租赁撮合的核心多阈值打分排序这才是标题里智慧房源租赁撮合真正落地的部分。我的实现思路不复杂但对毕设来说非常够用写一个MatchService接收用户携带的需求参数预算区间、期望区域、户型、租期和每套房源的属性做逐项匹配打分总分高者优先展示在为你推荐列表中。public int calculateMatchScore(House house, UserDemand demand) { int score 0; // 预算匹配月租金在预算区间内加40分超出但不超过20%加10分 if (demand.getBudgetMin() ! null demand.getBudgetMax() ! null) { if (house.getPrice() demand.getBudgetMin() house.getPrice() demand.getBudgetMax()) { score 40; } else if (house.getPrice() demand.getBudgetMax() * 1.2) { score 10; } } // 区域匹配完全命中加30分 if (StrUtil.equals(house.getDistrict(), demand.getExpectDistrict())) { score 30; } // 户型匹配期望的室数一致加20分 if (parseRoomCount(house.getHouseType()).equals(demand.getExpectRoomCount())) { score 20; } // 租期匹配接受最短租期加10分 if (house.getMinRentMonth() ! null demand.getRentMonths() house.getMinRentMonth()) { score 10; } return score; }这套评分规则按权重排序是预算 区域 户型 租期。为什么预算权重最大因为租房决策中价格是首要制约因素这个逻辑本身说人话就能理解。我在推荐页对得分≥70的房源标记为高匹配60~69标记为较匹配低于60不进入推荐列表只出现在全量列表。推荐结果用Redis缓存10分钟没有Redis就存本地缓存避免每次刷首页都全量计算。如果你想让这块更高级一点可以再加一个简单的用户行为加权用户收藏过某区域房源那么该区域的匹配分上浮5分。这个逻辑加进去后智慧二字就不仅仅体现在静态匹配上还有了一点动态学习的感觉——而实现成本不过是在收藏表上多一条count统计。5. Vue前端页面骨架、权限路由与地图找房5.1 项目目录结构与基础搭建Vue前端我用Vite初始化npm create vitelatest house-front -- --template vue cd house-front npm install npm install element-plus axios pinia vue-router目录结构是开发前就规划好的这对后续写页面非常关键src/ ├── api/ # 接口请求封装按业务模块拆分 │ ├── user.js │ ├── house.js │ └── order.js ├── assets/ # 静态资源 ├── components/ # 公共组件房源卡片、上传组件等 ├── router/ # 路由配置与守卫 ├── stores/ # Pinia状态管理 ├── views/ # 页面组件 │ ├── home/ # 首页、房源列表、房源详情 │ ├── publish/ # 发布房源 │ ├── manage/ # 后台管理 │ └── user/ # 个人中心 └── utils/ # 公共工具request.js封装等Element Plus按需引入还是全量引入毕设别纠结全量引入写起来最快按需引入省体积那是生产环境的优化需求不是毕设阶段的优先级。在main.js里app.use(ElementPlus)完事。5.2 Axios封装与动态路由守卫Axios封装是所有请求的管理中枢。我在utils/request.js里统一做了三件事设置baseURL /api、请求拦截器携带token、响应拦截器统一处理后端错误码并跳转登录。import axios from axios import { ElMessage } from element-plus import router from ../router const request axios.create({ 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( response { const res response.data if (res.code ! 200) { ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) } return res.data }, error { if (error.response error.response.status 401) { localStorage.removeItem(token) localStorage.removeItem(userInfo) router.push(/login) } ElMessage.error(网络异常请稍后重试) return Promise.reject(error) } ) export default request路由守卫这部分关键词里有人提vue动态路由其实毕设很多动态路由需求本质上就是根据角色显示不同菜单。用前端静态路由加上meta.roles字段就够了动态路由是后端返回菜单树那是大型后台管理系统的玩法毕设过度设计反而容易被问住。router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.path /login || to.path /register) { next() return } if (!token) { next(/login) return } const userInfo JSON.parse(localStorage.getItem(userInfo) || {}) if (to.meta.roles !to.meta.roles.includes(userInfo.role)) { ElMessage.warning(没有权限访问该页面) next(/) return } next() })这套守卫逻辑有一个必须同步落实的点前端的角色控制只是体验层面的约束真正权限校验必须写在后端接口上。或者说前端隐藏菜单只是不做无谓请求后端拦截器校验才是安全底线。答辩时老师如果问前端路由守卫和后端权限谁更重要标准回答是缺一不可但安全意义上后端是兜底。5.3 首页、详情页与发布页的实现要点首页是给评委第一印象的页面必须做到看起来像个真正的平台。我分了几个区域顶部导航轮播图/搜索框、分类筛选栏区域、户型、租金区间、房源卡片瀑布流、右侧的为你推荐列表。地图找房我接入的是高德地图JS API左侧地图根据当前视野经纬度加载房源标记点右侧列表同步刷新视野内的房源。这里要注意地图API的key需要自己在控制台申请本地开发用开发版key会有域名限制配置securityJsCode后基本没有太大问题。地图标注点建议用高德提供的覆盖物Marker点击弹出房源小卡片。房源详情页是撮合逻辑最终的落点。布局轮播图 基本信息 右侧价格卡片 房东信息 底部操作按钮收藏、在线咨询、立即下单。详情页里有一个容易被忽略的细节看清自己是在售/在租还是已预订状态不对时下单按钮要置灰禁止点击否则用户疯狂点击就会触发后面说的并发重复下单问题。发布房源页要处理的是表单联动的业务逻辑。选中出租时展示租金、押金、租期字段选中出售时展示总价、产权信息。这里可以用Vue的v-if配合watch也可以直接用Element Plus的动态表单校验规则。注意图片上传组件里要限制图片数量比如最多10张、大小2MB以内和格式上传前做个前端校验能省掉不少后端判空逻辑。发布成功后按钮状态改为提交审核中引导用户去个人中心看审核进度。Vue这里还有个容易困惑的点热词里有人问vue打包放进springboot中。原理很简单前端npm run build之后生成一个dist目录把里面的内容复制到SpringBoot的src/main/resources/static下后端直接就能启动访问。不过开发期建议别这么干前端跑8080、后端跑8081通过Vite的proxy配置转发/api请求热更新体验好得多// vite.config.js server: { port: 8080, proxy: { /api: { target: http://localhost:8081, changeOrigin: true } } }6. 部署、演示与答辩让评委一眼看到工作量6.1 从零到跑通的三步操作项目打包发给别人看的时候最容易出幺蛾子。我的建议是准备一个一键启动说明文档把环境依赖和启动步骤写得清清楚楚安装MySQL 8.0执行项目根目录下的init.sql创建一个叫house_rent的数据库初始数据中包含10个账号、20套房源、3份订单和2份合同。初始化数据是必须做的空数据库演示效果会大打折扣。导入SpringBoot项目修改application.yml中的数据库账号密码运行HouseApplication主类。后端默认端口8081。前端项目控制台执行npm install然后npm run dev浏览器访问http://localhost:8080用预设的租客账号13800000001/123456登录即可。这里提一句application.yml配置MySQL连接时最好加上useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai三个参数否则中文乱码和时区报错会让你怀疑人生。6.2 八分钟演示脚本把链路讲成故事我建议演示时不要按页面菜单顺序平铺直叙而是沿着一条业务故事线走登录页切入先讲三种角色演示租客账号登录。首页展示演示搜索筛选、按地域切换地图找房点开一套高匹配房源。翻到为你推荐对比推荐列表和普通列表的区别引出撮合模块的打分逻辑。收藏 在线咨询展示交互功能强调用户行为会影响推荐权重。下单 模拟支付跑一遍租赁订单支付流程。切换房东账号房东收到新订单确认接单。合同生成系统自动生成电子合同双方确认签名。切管理员账号演示房源审核、用户管理、订单总览、统计分析图表。这个演示顺序的精髓是一个业务故事讲到底评委跟着故事走比看你来回切菜单印象深得多。每一步操作之前说一句接下来我们看XX把上下文交代清楚整个答辩的节奏感就出来了。6.3 高频答辩问题与参考应答根据我自己模拟答辩和实际被问到的经验整理几个高频问题你项目里的智慧撮合和普通条件搜索有什么区别答普通搜索是用户主动输入条件、系统做刚性过滤比如价格只能选3000以下还是3000~5000。我的撮合系统是用户只需要提供一个大致的需求描述预算范围、偏好的几个区域、想要的户型系统为每一套房源计算综合匹配分并允许价格超预算10%以内但地段极佳这类房源浮上来给用户提供的是柔性排序结果而非刚性过滤。房源下单时怎么防止两个人同时租同一套房答数据库层面使用了乐观锁house表有一个version字段更新为已预订时带上WHERE id ? AND version ?更新失败说明已经被别人抢先。同时在业务层对同一房源的订单创建加分布式锁或synchronized按房源ID加锁防止并发创建重复订单。你的权限是怎么做的前端控制还是后端控制答两层都有。前端通过路由守卫控制页面可见性改善交互体验后端通过拦截器校验JWT中的角色信息对管理员接口进行权限拦截。并且后端以角色判断为准因为前端可能被绕过直接构造请求打到接口上。系统如果数据量达到百万级哪些地方会出问题答目前MySQL的LIKE %关键词%检索和单表查询在百万级会出现性能瓶颈。第一title和address的模糊搜索会退化为全表扫描需要引入Elasticsearch做全文检索第二推荐列表的实时计算会变慢需要把匹配结果预计算并缓存或者引入离线计算任务第三图片访问需要用独立的对象存储和CDN分流。这些都属于可以谈的优化思路知道瓶颈在哪比已经做了优化在某些老师眼里更值钱。7. 开发过程中踩过的坑与后续优化方向7.1 三个必踩的坑Long类型主键传给前端精度丢失。后端主键用bigint如果使用雪花算法或者自增超过JavaScript的Number.MAX_SAFE_INTEGER9007199254740991前端拿到的ID末尾会变成...0000导致详情页打开失败。解决方案很简单在Jackson配置里把Long类型统一转为字符串输出或者用JsonSerialize(using ToStringSerializer.class)标注主键字段。这个问题有多隐蔽你本地测试数据ID都是个位数永远不会发现等导入大量初始化数据后才会炸。提前处理别赌。前后端时间字段格式对不上。后端LocalDateTime默认序列化出来是一串数字时间戳前端Element Plus的日期组件却习惯接收yyyy-MM-dd HH:mm:ss字符串。在application.yml里配置spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8同时数据库连接串里加serverTimezoneAsia/Shanghai三处时区对齐后基本不会再出问题。并发下单的脏数据。用户快速点击立即下单按钮前端没有做防抖后端也没有做并发控制的话同一个人可能创建出好几条相同内容的订单严重破坏演示效果。我在后端下单接口上用synchronized (String.valueOf(houseId).intern())锁住房源ID同时在order表加(user_id, house_id)的前缀条件来保证同用户同房源未完成的订单只有一条。前端的提交按钮也做了loading状态防重复点击。两层防护稳妥。7.2 这几点优化可以做但不着急项目主体完成、答辩PPT做完之后如果还有富余时间性价比最高的几个扩展方向把MySQL的LIKE搜索升级为全文索引方案用WebSocket给房东推送新订单提醒管理端增加ECharts成交趋势、房源价格分布等可视化报表页面引入Redis缓存房源详情页的访问热点数据。这几个方向每个都有明确的应用场景和实现方案写在论文系统展望与不足一节里比干巴巴写进一步提高系统性能要有说服力得多。另外部署到云服务器时有一个非常好的可选项——用宝塔面板的Docker功能部署SpringBoot和MySQL。热词里有人搜宝塔docker部署springboot确实是个省心方案后端打成jar包写个Dockerfile映射宿主机端口MySQL也用容器起一个前端打包后的静态文件放在Nginx容器里并配置代理转发到后端接口。整个过程一小时左右能跑通弄完之后你从任何一台电脑访问服务器IP都能看到项目在运行答辩时随手打开手机展示的效果远强于只能在我的电脑上跑。最后说点我个人的感受。做这类毕设项目最值钱的收获往往不在最终代码量而在于你亲手把一条房东发布 - 平台审核 - 租客搜索 - 系统推荐 - 在线下单 - 合同签署的完整业务链跑通了一遍。你会第一次真正感觉到框架不是背概念背出来的而是用来解决一个个具体问题的JWT是为了让API认得你是谁状态机是为了不让房源被重复下单匹配分是为了让用户少翻几页就能看到合适的房子。带着这种每个设计都有它存在的理由的状态走进答辩教室你说的每一句话都会比背稿子自信得多。
返回列表