公司动态

Spring Boot租房平台实战:从零搭建Web应用完整指南

📅 2026/7/21 23:24:41
Spring Boot租房平台实战:从零搭建Web应用完整指南
最近在辅导学生做毕业设计时发现很多同学对如何将Spring Boot技术栈落地到一个完整的、有业务逻辑的Web项目感到迷茫。网上虽然有很多零散的教程但往往只讲某个技术点缺乏一个贯穿前后端、数据库、页面交互的完整案例。本文将以一个基于Spring Boot的租房平台为例带你从零开始手把手搭建一个具备房源发布、浏览、搜索、用户管理等核心功能的Web应用。通过这个项目你将系统性地掌握如何使用Spring Boot整合Maven、Thymeleaf、MyBatis-Plus、MySQL以及Ajax等技术并理解它们在一个真实业务场景中是如何协同工作的。无论你是正在寻找毕设项目的学生还是希望巩固Spring Boot实战技能的开发者这篇文章都能为你提供一份清晰、可复现的“保姆级”指南。1. 项目背景与核心需求分析在开始编码之前明确我们要做什么以及为什么选择这些技术至关重要。一个租房平台的核心目标是连接房东房源提供方与租客需求方实现房源信息的有效管理和高效匹配。1.1 业务场景与功能模块典型的租房平台包含以下核心功能模块用户模块用户注册、登录、个人信息管理。区分普通用户租客和管理员。房源模块这是核心。包括房源的发布、编辑、删除、上架/下架。房源信息应包含标题、描述、地址、租金、户型、面积、配套设施、图片等。信息展示与搜索模块首页展示房源列表支持按价格、户型、区域等多条件筛选和关键词搜索。交互模块租客可以收藏感兴趣的房源或通过站内信、联系方式需授权与房东沟通。1.2 技术选型与架构说明为什么选择这套技术栈Spring Boot作为项目基石它极大地简化了Spring应用的初始搭建和开发过程通过自动配置和起步依赖让我们能快速构建独立运行、生产级别的应用。Maven项目构建和依赖管理工具。通过pom.xml文件统一管理项目所需的所有库Jar包解决依赖冲突规范项目结构。Thymeleaf服务端模板引擎。它允许我们在HTML中直接使用Spring表达式语言来动态渲染数据如显示房源列表并且与Spring Boot集成度极高语法自然。MyBatis-Plus强大的MyBatis增强工具。它内置了通用Mapper和Service只需简单继承即可实现单表的大部分CRUD操作极大减少SQL编写量提高开发效率。MySQL成熟稳定的关系型数据库用于持久化存储用户、房源、收藏等所有业务数据。Ajax异步JavaScript和XML技术。用于实现页面的局部刷新提升用户体验。例如在搜索房源时无需刷新整个页面即可更新列表收藏房源时按钮状态可以即时改变。这套组合是当前Java Web开发中非常经典和流行的选择兼顾了开发效率、性能和维护性。2. 开发环境与项目初始化工欲善其事必先利其器。确保你的开发环境已就绪。2.1 环境与工具准备操作系统Windows 10/11, macOS 或 Linux 均可。JDK版本 8 或 11推荐11长期支持版本。安装后配置好JAVA_HOME环境变量。IDEIntelliJ IDEA社区版或旗舰版。它对Spring Boot的支持非常友好。数据库MySQL 5.7 或 8.0。建议使用图形化管理工具如Navicat、MySQL Workbench或IDEA自带的数据库工具。构建工具Maven 3.6。IDEA通常自带也可独立安装。浏览器Chrome 或 Firefox用于调试前端和Ajax请求。2.2 使用Spring Initializr创建项目这是最快捷的方式。你可以通过 start.spring.io 在线生成也可以在IDEA中直接创建。在IDEA中选择File - New - Project。选择Spring Initializr选择合适的JDK版本。填写项目元数据Group:com.rental(示例可按需修改)Artifact:rental-platformType: MavenJava Version: 8 或 11Packaging: Jar在Dependencies中添加初始依赖搜索并添加Spring Web,Thymeleaf,MyBatis Framework,MySQL Driver。Lombok用于简化实体类代码也强烈建议添加。点击完成IDEA会自动创建项目并下载依赖。2.3 初始项目结构与pom.xml调整项目创建后结构如下rental-platform ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ └── rental │ │ │ └── RentalPlatformApplication.java (启动类) │ │ └── resources │ │ ├── static (存放静态资源css, js, images) │ │ ├── templates (存放Thymeleaf模板HTML文件) │ │ └── application.properties (配置文件) │ └── test (测试目录) └── pom.xml (Maven依赖配置文件)我们需要手动将MyBatis Framework依赖替换为功能更强大的MyBatis-Plus。打开pom.xml找到mybatis-spring-boot-starter依赖项将其替换为!-- MyBatis-Plus 起步依赖 -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version !-- 请查看官网使用最新稳定版 -- /dependency !-- Lombok (已在Initializr添加确认存在) -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency !-- MySQL驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency !-- Spring Web -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- Thymeleaf -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-thymeleaf/artifactId /dependency修改后点击IDEA右侧Maven面板的刷新按钮下载新的依赖。3. 数据库设计与核心配置在编写代码前先设计好数据库表结构。3.1 数据库表设计我们创建数据库rental_db并设计三张核心表-- 1. 用户表 CREATE TABLE user ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键ID, username varchar(50) NOT NULL COMMENT 用户名, password varchar(255) NOT NULL COMMENT 密码加密存储, email varchar(100) DEFAULT NULL COMMENT 邮箱, phone varchar(20) DEFAULT NULL COMMENT 手机号, avatar varchar(500) DEFAULT NULL COMMENT 头像URL, role varchar(20) DEFAULT USER COMMENT 角色USER, ADMIN, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表; -- 2. 房源信息表 CREATE TABLE house ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 房源ID, title varchar(200) NOT NULL COMMENT 房源标题, description text COMMENT 详细描述, price decimal(10,2) NOT NULL COMMENT 月租金, area decimal(6,2) DEFAULT NULL COMMENT 面积平方米, room int(11) DEFAULT 1 COMMENT 室, hall int(11) DEFAULT 0 COMMENT 厅, bathroom int(11) DEFAULT 1 COMMENT 卫, address varchar(500) NOT NULL COMMENT 详细地址, city varchar(50) DEFAULT NULL COMMENT 城市, district varchar(50) DEFAULT NULL COMMENT 区县, cover_image varchar(500) DEFAULT NULL COMMENT 封面图URL, status int(11) DEFAULT 1 COMMENT 状态0-下架1-上架, landlord_id bigint(20) NOT NULL COMMENT 房东用户ID, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), KEY idx_landlord (landlord_id), KEY idx_city_district (city,district), KEY idx_price (price) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT房源信息表; -- 3. 收藏表用户与房源的多对多关系 CREATE TABLE favorite ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键, user_id bigint(20) NOT NULL COMMENT 用户ID, house_id bigint(20) NOT NULL COMMENT 房源ID, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 收藏时间, PRIMARY KEY (id), UNIQUE KEY uk_user_house (user_id,house_id), -- 防止重复收藏 KEY idx_user (user_id), KEY idx_house (house_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT收藏表;3.2 应用配置文件接下来配置Spring Boot连接数据库和MyBatis-Plus。编辑src/main/resources/application.properties文件# 服务器端口 server.port8080 # 数据库连接配置 spring.datasource.urljdbc:mysql://localhost:3306/rental_db?useUnicodetruecharacterEncodingutf-8useSSLfalseserverTimezoneAsia/Shanghai spring.datasource.usernameroot spring.datasource.passwordyour_password # 替换为你的数据库密码 spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver # MyBatis-Plus 配置 mybatis-plus.configuration.log-implorg.apache.ibatis.logging.stdout.StdOutImpl # 控制台打印SQL开发环境使用 mybatis-plus.global-config.db-config.id-typeauto # 主键策略数据库自增 mybatis-plus.global-config.db-config.logic-delete-fielddeleted # 逻辑删除字段名如果启用 mybatis-plus.global-config.db-config.logic-delete-value1 # 逻辑已删除值 mybatis-plus.global-config.db-config.logic-not-delete-value0 # 逻辑未删除值 mybatis-plus.configuration.map-underscore-to-camel-casetrue # 自动驼峰命名转换 # Thymeleaf 配置 spring.thymeleaf.cachefalse # 开发时关闭缓存修改HTML即时生效 spring.thymeleaf.prefixclasspath:/templates/ spring.thymeleaf.suffix.html spring.thymeleaf.modeHTML spring.thymeleaf.encodingUTF-84. 核心功能模块实现我们将按照MVCModel-View-Controller分层架构来组织代码。4.1 实体类Model与数据访问层Mapper首先创建与数据库表对应的实体类。使用Lombok的Data注解可以自动生成getter、setter等方法。// 文件路径src/main/java/com/rental/entity/User.java package com.rental.entity; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.time.LocalDateTime; Data TableName(user) // 指定对应表名 public class User { TableId(type IdType.AUTO) // 主键自增 private Long id; private String username; private String password; private String email; private String phone; private String avatar; private String role; TableField(fill FieldFill.INSERT) // 插入时自动填充 private LocalDateTime createTime; TableField(fill FieldFill.INSERT_UPDATE) // 插入和更新时自动填充 private LocalDateTime updateTime; }// 文件路径src/main/java/com/rental/entity/House.java package com.rental.entity; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; Data TableName(house) public class House { TableId(type IdType.AUTO) private Long id; private String title; private String description; private BigDecimal price; private BigDecimal area; private Integer room; private Integer hall; private Integer bathroom; private String address; private String city; private String district; private String coverImage; private Integer status; // 0-下架1-上架 private Long landlordId; // 关联用户ID TableField(fill FieldFill.INSERT) private LocalDateTime createTime; TableField(fill FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; }接着创建对应的Mapper接口。MyBatis-Plus的强大之处在于对于单表的基础CRUD我们只需要创建一个空接口继承BaseMapper即可。// 文件路径src/main/java/com/rental/mapper/UserMapper.java package com.rental.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.rental.entity.User; import org.apache.ibatis.annotations.Mapper; Mapper // 标识为MyBatis的MapperSpring Boot会自动扫描 public interface UserMapper extends BaseMapperUser { // 无需编写任何方法即可拥有增删改查等基础方法 }// 文件路径src/main/java/com/rental/mapper/HouseMapper.java package com.rental.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.rental.entity.House; import org.apache.ibatis.annotations.Mapper; Mapper public interface HouseMapper extends BaseMapperHouse { // 如果需要复杂的多表查询可以在这里定义方法并在对应的XML文件中编写SQL }为了让createTime和updateTime自动填充生效我们需要配置一个元对象处理器。// 文件路径src/main/java/com/rental/config/MyMetaObjectHandler.java package com.rental.config; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import java.time.LocalDateTime; Component public class MyMetaObjectHandler implements MetaObjectHandler { Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, createTime, LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, updateTime, LocalDateTime.class, LocalDateTime.now()); } Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, updateTime, LocalDateTime.class, LocalDateTime.now()); } }4.2 业务逻辑层ServiceService层负责处理业务逻辑。我们可以使用MyBatis-Plus提供的IService和ServiceImpl来快速构建。// 文件路径src/main/java/com/rental/service/IHouseService.java package com.rental.service; import com.baomidou.mybatisplus.extension.service.IService; import com.rental.entity.House; import java.util.List; public interface IHouseService extends IServiceHouse { // 定义业务相关的方法例如条件查询房源列表 ListHouse searchHouses(String keyword, String city, String district, BigDecimal minPrice, BigDecimal maxPrice); }// 文件路径src/main/java/com/rental/service/impl/HouseServiceImpl.java package com.rental.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.rental.entity.House; import com.rental.mapper.HouseMapper; import com.rental.service.IHouseService; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.util.List; Service public class HouseServiceImpl extends ServiceImplHouseMapper, House implements IHouseService { Override public ListHouse searchHouses(String keyword, String city, String district, BigDecimal minPrice, BigDecimal maxPrice) { LambdaQueryWrapperHouse queryWrapper new LambdaQueryWrapper(); queryWrapper.eq(House::getStatus, 1); // 只查询上架的房源 if (keyword ! null !keyword.trim().isEmpty()) { queryWrapper.and(wrapper - wrapper .like(House::getTitle, keyword) .or() .like(House::getDescription, keyword) .or() .like(House::getAddress, keyword) ); } if (city ! null !city.isEmpty()) { queryWrapper.eq(House::getCity, city); } if (district ! null !district.isEmpty()) { queryWrapper.eq(House::getDistrict, district); } if (minPrice ! null) { queryWrapper.ge(House::getPrice, minPrice); // ge: greater than or equal to } if (maxPrice ! null) { queryWrapper.le(House::getPrice, maxPrice); // le: less than or equal to } queryWrapper.orderByDesc(House::getCreateTime); // 按发布时间倒序 return this.list(queryWrapper); } }4.3 控制层Controller与页面交互Controller负责接收HTTP请求调用Service处理并返回视图HTML页面或数据JSON。4.3.1 首页与房源列表展示首先创建一个简单的首页控制器并展示房源列表。// 文件路径src/main/java/com/rental/controller/IndexController.java package com.rental.controller; import com.rental.entity.House; import com.rental.service.IHouseService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import java.math.BigDecimal; import java.util.List; Controller RequiredArgsConstructor // Lombok注解自动注入final字段 public class IndexController { private final IHouseService houseService; GetMapping({/, /index}) public String index(RequestParam(required false) String keyword, RequestParam(required false) String city, RequestParam(required false) BigDecimal minPrice, RequestParam(required false) BigDecimal maxPrice, Model model) { // 调用Service进行条件查询 ListHouse houseList houseService.searchHouses(keyword, city, null, minPrice, maxPrice); model.addAttribute(houseList, houseList); model.addAttribute(keyword, keyword); model.addAttribute(city, city); model.addAttribute(minPrice, minPrice); model.addAttribute(maxPrice, maxPrice); return index; // 对应 templates/index.html } }接下来创建Thymeleaf模板页面index.html。!-- 文件路径src/main/resources/templates/index.html -- !DOCTYPE html html langzh-CN xmlns:thhttp://www.thymeleaf.org head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title租房平台 - 首页/title link relstylesheet hrefhttps://cdn.jsdelivr.net/npm/bootstrap5.1.3/dist/css/bootstrap.min.css style .house-card { margin-bottom: 20px; transition: transform .2s; } .house-card:hover { transform: translateY(-5px); box-shadow: 0 4px 15px rgba(0,0,0,.1); } .price { color: #ff6b6b; font-weight: bold; font-size: 1.2em; } /style /head body !-- 导航栏 -- nav classnavbar navbar-expand-lg navbar-light bg-light div classcontainer a classnavbar-brand href/租房平台/a !-- 搜索框 -- form classd-flex ms-auto action/ methodget input classform-control me-2 typesearch namekeyword placeholder搜索房源... th:value${keyword} input classform-control me-2 typetext namecity placeholder城市 th:value${city} input classform-control me-2 stylewidth: 100px; typenumber nameminPrice placeholder最低价 th:value${minPrice} input classform-control me-2 stylewidth: 100px; typenumber namemaxPrice placeholder最高价 th:value${maxPrice} button classbtn btn-outline-success typesubmit搜索/button /form !-- 用户相关链接 -- div classnavbar-nav a classnav-link href/login登录/a a classnav-link href/register注册/a a classnav-link href/publish发布房源/a /div /div /nav !-- 房源列表 -- div classcontainer mt-4 h2 classmb-4房源列表/h2 div classrow th:if${#lists.isEmpty(houseList)} div classcol-12 div classalert alert-info暂无房源信息快去发布第一个房源吧/div /div /div div classrow !-- 使用Thymeleaf循环渲染房源卡片 -- div classcol-md-4 col-lg-3 th:eachhouse : ${houseList} div classcard house-card img th:src${house.coverImage ! null} ? ${house.coverImage} : /images/default-house.jpg classcard-img-top alt房源封面 styleheight: 180px; object-fit: cover; div classcard-body h5 classcard-title th:text${house.title}房源标题/h5 p classcard-text text-muted th:text${house.address}房源地址/p p classcard-text span th:text${house.room} 室 ${house.hall} 厅 ${house.bathroom} 卫/span | span th:text${house.area} ㎡/span /p p classcard-text price th:text¥ ${#numbers.formatDecimal(house.price, 1, 2)}价格/p a th:href{/house/detail/{id}(id${house.id})} classbtn btn-primary btn-sm查看详情/a button classbtn btn-outline-danger btn-sm float-end onclickaddFavorite([[${house.id}]])收藏/button /div /div /div /div /div script srchttps://cdn.jsdelivr.net/npm/bootstrap5.1.3/dist/js/bootstrap.bundle.min.js/script script srchttps://cdn.jsdelivr.net/npm/jquery3.6.0/dist/jquery.min.js/script script // 使用Ajax实现收藏功能 function addFavorite(houseId) { // 这里需要先判断用户是否登录为简化示例假设已登录 $.ajax({ url: /api/favorite/add, type: POST, contentType: application/json, data: JSON.stringify({ houseId: houseId }), success: function(response) { if (response.success) { alert(收藏成功); } else { alert(收藏失败 response.message); } }, error: function() { alert(网络请求失败请检查登录状态。); } }); } /script /body /html4.3.2 实现Ajax交互的收藏功能上面页面中调用了/api/favorite/add接口我们需要实现它。这通常是一个返回JSON的RESTful接口。首先创建一个数据传输对象DTO来接收前端JSON数据。// 文件路径src/main/java/com/rental/dto/FavoriteDTO.java package com.rental.dto; import lombok.Data; import javax.validation.constraints.NotNull; Data public class FavoriteDTO { NotNull(message 房源ID不能为空) private Long houseId; // 用户ID可以从会话(Session)或安全上下文中获取无需前端传递 }然后创建对应的Controller。为了简化这里假设用户已登录并从Session中获取用户ID。// 文件路径src/main/java/com/rental/controller/api/FavoriteApiController.java package com.rental.controller.api; import com.rental.dto.FavoriteDTO; import com.rental.service.IFavoriteService; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpSession; import javax.validation.Valid; import java.util.HashMap; import java.util.Map; RestController // RestController Controller ResponseBody直接返回JSON RequestMapping(/api/favorite) RequiredArgsConstructor public class FavoriteApiController { private final IFavoriteService favoriteService; PostMapping(/add) public ResponseEntityMapString, Object addFavorite(Valid RequestBody FavoriteDTO favoriteDTO, HttpSession session) { MapString, Object result new HashMap(); // 模拟从Session获取当前用户ID实际项目中应使用Spring Security等安全框架 Long userId (Long) session.getAttribute(userId); if (userId null) { result.put(success, false); result.put(message, 用户未登录); return ResponseEntity.status(401).body(result); // 401 Unauthorized } try { boolean success favoriteService.addFavorite(userId, favoriteDTO.getHouseId()); if (success) { result.put(success, true); result.put(message, 收藏成功); } else { result.put(success, false); result.put(message, 已收藏过该房源); } return ResponseEntity.ok(result); } catch (Exception e) { result.put(success, false); result.put(message, 服务器内部错误); return ResponseEntity.status(500).body(result); } } }对应的Service实现// 文件路径src/main/java/com/rental/service/impl/FavoriteServiceImpl.java package com.rental.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.rental.entity.Favorite; import com.rental.mapper.FavoriteMapper; import com.rental.service.IFavoriteService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; Service public class FavoriteServiceImpl extends ServiceImplFavoriteMapper, Favorite implements IFavoriteService { Override Transactional(rollbackFor Exception.class) public boolean addFavorite(Long userId, Long houseId) { // 检查是否已收藏 LambdaQueryWrapperFavorite queryWrapper new LambdaQueryWrapper(); queryWrapper.eq(Favorite::getUserId, userId).eq(Favorite::getHouseId, houseId); long count this.count(queryWrapper); if (count 0) { return false; // 已收藏 } // 新增收藏记录 Favorite favorite new Favorite(); favorite.setUserId(userId); favorite.setHouseId(houseId); return this.save(favorite); } }5. 项目运行与测试5.1 启动应用确保MySQL服务已启动并且rental_db数据库及表已创建。在IDEA中找到主启动类RentalPlatformApplication右键点击Run。观察控制台日志如果没有报错看到类似Tomcat started on port(s): 8080的信息说明启动成功。5.2 功能测试访问首页打开浏览器访问http://localhost:8080。你应该能看到导航栏和空的房源列表因为数据库还没有数据。测试数据插入可以通过编写一个简单的单元测试或者直接使用数据库工具向house表插入几条测试数据。再次刷新首页房源卡片应该被渲染出来。测试搜索功能在搜索框输入关键词、城市或价格范围点击搜索页面会刷新并展示筛选后的结果。测试Ajax收藏点击房源卡片的“收藏”按钮浏览器会发起一个Ajax POST请求。你需要先实现一个简单的登录功能并在登录后将用户ID存入Session (session.setAttribute(userId, user.getId()))收藏功能才能正常工作。你可以先注释掉Controller中的登录检查逻辑进行测试。6. 常见问题与排查思路在开发过程中你可能会遇到以下典型问题问题现象可能原因排查思路与解决方案启动报错Failed to configure a DataSource数据库连接配置错误或数据库服务未启动。1. 检查application.properties中的url,username,password。2. 确认MySQL服务是否运行 (net start mysql)。3. 确认数据库rental_db是否存在。访问页面报错Whitelabel Error Page或4041. Controller的请求路径映射错误。2. Thymeleaf模板文件位置或名称错误。3. 静态资源路径错误。1. 检查Controller中GetMapping或PostMapping的路径。2. 确认HTML文件是否在resources/templates/目录下且返回的视图名称与之匹配不含后缀。3. 检查静态资源CSS, JS, images是否在resources/static/下。页面能访问但Thymeleaf表达式不生效显示为[[${...}]]1. HTML文件没有引入Thymeleaf命名空间。2. 模型Model中没有添加对应的属性。1. 确保HTML的html标签有xmlns:thhttp://www.thymeleaf.org。2. 在Controller方法中使用model.addAttribute(key, value)传递数据。MyBatis-Plus 查询不到数据或报错1. 实体类字段名与数据库列名映射失败。2. Mapper接口未被Spring扫描到。3. 查询条件构造错误。1. 检查实体类TableName、TableField注解或开启驼峰命名转换。2. 确认Mapper接口上有Mapper注解或在启动类加了MapperScan。3. 在application.properties中开启SQL日志 (mybatis-plus.configuration.log-impl)查看生成的SQL是否正确。Ajax请求返回404或4051. 请求的URL路径错误。2. 请求方法GET/POST与Controller定义不匹配。3. 未添加ResponseBody或未使用RestController。1. 检查浏览器开发者工具F12的Network面板确认请求URL和Method。2. 确保Controller方法使用了正确的GetMapping、PostMapping等注解。3. 确保返回JSON的Controller类有RestController注解。7. 项目扩展与最佳实践建议至此一个具备基础功能的租房平台骨架已经完成。要将其完善为一个真正的项目还需要考虑以下方面7.1 功能扩展方向用户认证与授权集成Spring Security或Sa-Token实现完整的注册、登录、登出、密码加密、角色权限控制如只有管理员能审核房源只有房东能发布房源。图片上传实现房源封面图和多图上传功能。可以使用本地存储或集成阿里云OSS、腾讯云COS等对象存储服务。分页查询房源列表数据量大时必须使用分页。MyBatis-Plus提供了强大的分页插件只需简单配置即可。// 在配置类中配置分页插件 Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } // 在Service中使用Page对象 PageHouse page new Page(current, size); IPageHouse housePage houseService.page(page, queryWrapper);缓存优化对于首页房源列表等不常变化的热点数据可以集成Redis进行缓存减轻数据库压力。站内信/聊天实现租客与房东的沟通功能。可以使用WebSocket实现简单的实时聊天或使用消息队列处理通知。7.2 工程化与最佳实践项目结构分层清晰严格遵循controller-service-mapper/dao-entity的分层。DTO用于前后端数据传输VO用于页面渲染。统一响应封装为所有API接口设计统一的JSON响应格式如包含code,message,data字段便于前端处理。全局异常处理使用ControllerAdvice和ExceptionHandler捕获并处理各类异常返回友好的错误信息而不是暴露堆栈信息。参数校验在DTO中使用javax.validation注解如NotNull,Size进行参数校验并在Controller方法参数前添加Valid注解。日志记录使用SLF4J Logback记录详细的业务日志和错误日志便于线上排查问题。配置文件分离将application.properties拆分为application-dev.properties开发环境、application-prod.properties生产环境通过Spring Profile激活不同配置。API文档集成Swagger或Knife4j自动生成和测试API接口文档。单元测试为Service层和Controller层编写单元测试使用JUnit和Mockito保证核心逻辑的正确性。这个基于Spring Boot的租房平台项目就像一辆组装好的汽车框架你已经拥有了发动机Spring Boot、车轮MySQL、Thymeleaf和方向盘Controller。要让它跑得更稳、更快、更安全就需要不断地为它添加“功能配件”和“安全措施”。建议你以当前代码为基础选择一两个扩展方向深入实践例如先把Spring Security集成进去实现登录再实现图片上传。每一步的实践都会让你对Spring Boot生态的理解更加深刻。