资讯动态

SpringBoot+Android房屋租赁系统从零开发全攻略:避坑指南与实战解析

发布时间:2026/10/4 2:26:28 来源:尧图企业网站定制
从零复刻一套Java SpringBoot Android房屋租赁系统我踩过的那些坑全在这了最近不少同学在问“Java SpringBoot基于Android的房屋租赁系统”这套毕设/项目怎么做正好我手里这套完整跑通过源码、文档、运行视频、讲解视频都齐的就借着这次机会把整个项目的核心逻辑和实操细节拆开聊一聊。先说清楚这套系统是干什么的。它本质上是一个全栈移动应用项目后端用SpringBoot提供RESTful接口管理数据、处理业务逻辑前端是一个原生Android App负责展示房源、下单租房、管理订单等操作数据库用MySQL存用户、房源、订单、合同这些核心数据。适合的人群很明确——正在做毕业设计的计算机专业学生或者想从零跑通一个完整前后端项目的转行开发者。网上这类项目的资料其实不少但很多要么只有残缺源码要么文档对不上代码真正能让你从环境搭建到部署上线全程无坑跑通的其实不多。这篇文章不会去复制粘贴那些官话文档而是把这个项目拿到手之后从需求分析到数据库设计、从后端接口到Android端联调一层层拆开揉碎了讲包括我自己实际操作中踩过的那些坑和解决办法你直接照着做就能少走很多弯路。1. 需求梳理与系统整体设计先搞清楚要做什么再动手写代码1.1 核心用户角色与业务场景拆解很多人拿到题目上来就写代码写到一半发现功能缺胳膊少腿数据库表改来改去。这种项目第一个动作永远是理清角色和业务链路。房屋租赁系统的用户角色通常分为三类租客、房东、系统管理员。租客的使用路径是“注册登录 → 搜索浏览房源 → 查看房源详情 → 收藏或预约看房 → 下单租赁 → 管理自己的租约”房东的使用路径是“注册登录 → 发布房源 → 管理房源上下架 → 查看订单和租客信息 → 处理合同”管理员的路径是“后台登录 → 审核房源 → 管理用户 → 处理投诉或反馈”。这里有一个很关键的细节要不要做管理员端很多简化版的项目把管理员后台砍掉但这会让整个系统的业务闭环不够完整答辩的时候很容易被老师问住——比如“房东发布的违规房源谁来审核用户纠纷怎么处理”所以我的建议是管理员功能不需要做得很复杂但必须要有而且最好放在Web端或者直接做成后端接口用Postman测试即可不需要额外开发一个管理后台App。1.2 功能模块划分与系统架构选型功能模块按照“谁能做什么”来划分整个系统大致可以拆成下面几个模块用户模块注册、登录JWT令牌认证、个人信息维护、头像上传房源模块房源发布、房源列表分页查询、按价格/区域/房型筛选、房源详情、房源上下架订单模块创建租赁订单、订单状态流转待付款 → 已付款 → 已生效 → 已退租、取消订单收藏模块收藏房源、取消收藏、收藏列表合同模块根据订单生成租赁合同、合同查看管理模块用户管理封禁/解封、房源审核、数据统计房源数量、订单数量这套架构是很典型的移动端 服务端分层架构。Android端只负责UI展示和用户交互所有业务逻辑统统交给后端API。这么做的好处是Android端不需要直接连数据库安全性大大提升如果以后想扩展微信小程序或者Web端后端接口可以直接复用而且答辩的时候导出接口定义文档整个项目结构会显得很规范。1.3 为什么选SpringBoot Android而不是其他组合我做技术选型的时候没有纠结太久一个原因这个组合是目前校园项目里最成熟、参考资料最丰富、容错率最高的搭配。SpringBoot的优势在于“约定大于配置”——你不用像早期Spring那样写一大堆XML配置文件一个SpringBootApplication注解就能启动一个内嵌Tomcat的Web服务配合Spring MVC实现RESTful API非常顺手再集成MyBatis-Plus处理数据库操作比原生JDBC代码量少一半以上。Android端用原生Java或Kotlin开发生态里网络请求有Retrofit OkHttp这套黄金组合图片加载有GlideJSON解析有Gson几乎每个模块都有成熟方案可以照葫芦画瓢。相比之下如果后端用Node.js虽然写起来轻快但很多学校老师更认Java技术栈如果前端用WebApp套壳而不是原生Android又会在“原生开发能力”这个维度上被扣分。所以SpringBoot Android原生双端是综合了答辩评分、学习成本、资料丰富度之后的最优解。2. 数据库设计这套系统的数据地基到底怎么打2.1 核心表结构与字段说明数据库是整个系统最容易翻车的地方。我第一版草草设计了5张表结果做到合同模块发现字段不够用又回炉重造反而更浪费时间。这里直接把最终跑通的表结构核心设计思路讲清楚。用户表user主键id用户名username唯一索引密码passwordBCrypt加密存储手机号phone角色role0表示租客/1表示房东/2表示管理员头像avatar创建时间create_time状态status0正常/1封禁。房源表house主键id房东ID landlord_id外键关联user表标题title描述description价格price注意用Decimal别用Float面积area户型layout地址address区域region图片列表images用JSON字符串格式存储多个图片URL状态status0待审核/1已上架/2已下架/3已出租发布时间create_time。订单表order主键id订单编号order_no用时间戳随机数生成不用自增id做单号租客ID tenant_id房源ID house_id起始日期start_date结束日期end_date总金额total_amount状态status0待付款/1已付款/2已生效/3已退租/4已取消创建时间create_time。合同表contract主键id订单ID order_id合同编号contract_no合同内容content建议用模板 占位符动态生成签约时间sign_time。收藏表favorite联合主键user_id, house_id收藏时间create_time。2.2 表关系与外键设计要点表和表之间的关系面试和答辩时最容易问到的点是“为什么这里要加外键”或者“为什么这里不用外键”。我的做法是逻辑外键为主物理外键为辅。也就是说在实体类里会写private Long landlordId这种逻辑关联字段但MySQL层面不一定真的去建FOREIGN KEY约束因为物理外键在删除、更新时会带来连锁限制项目阶段没必要给自己找麻烦靠应用层保证数据一致性就够了。房源和订单是一对多关系一个房源能被下单多次但同一时间只能有一个“生效中”的订单——这里就需要在订单表设计时加一个逻辑判断创建订单前必须校验该房源当前没有状态为“已付款”或“已生效”的订单。这个校验逻辑我会在后端Service层写是很容易漏掉的关键点。2.3 初始化数据的重要性有个很多人不重视但特别影响演示效果的操作sql脚本里一定要带初始化数据。我见过太多项目导入数据库后列表页一片空白演示时极其尴尬。至少准备10条房源数据、3个测试账号租客test_user / 房东test_landlord / 管理员test_admin密码统一用123456的BCrypt密文。这样App一跑起来就有内容可看接口测试也有数据支撑文档里也建议写明这些预置账号方便答辩老师体验。3. SpringBoot后端实现从项目搭建到RESTful接口开发3.1 项目快速搭建与依赖配置我用的开发环境是IDEA JDK 1.8 SpringBoot 2.7.x MyBatis-Plus 3.5.x MySQL 8.0。没有直接从零手写配置而是通过Spring Initializr生成基础工程然后在pom.xml里加关键依赖。要重点提一下SpringBoot版本别选太高3.x需要JDK 17很多同学本机还跑着JDK 8哪怕好不容易装好了后面整合MyBatis-Plus、druid连接池也可能遇到兼容性问题。所以稳妥起见就锁在2.x版本。核心依赖就这几组dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency dependency groupIdcom.auth0/groupId artifactIdjava-jwt/artifactId version4.4.0/version /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /dependency3.2 分层架构与核心目录设计后端代码的组织方式我推荐标准的Controller → Service → Mapper三层结构分包示例如下controller接收HTTP请求参数校验返回结果封装service业务逻辑层处理事务、判断条件mapperMyBatis-Plus接口继承BaseMapperT就能获得大部分CRUD能力entity数据库实体类dto数据传输对象用于接口入参和返回值的封装config配置类跨域、拦截器、静态资源映射等utils工具类JWT工具、统一返回结果封装、异常处理这里要特别强调统一返回结果的重要性。定义一个Result类字段包含code200成功/500失败/401未登录、message、data所有接口都返回这个结构。刚开始写代码的时候会嫌麻烦但联调阶段就会感谢自己——Android端拿到返回结果后只要先看code再解析data整个数据解析逻辑会异常清爽。3.3 注册登录与JWT令牌认证实现登录认证模块是几乎所有接口的前置依赖也是答辩时的高频考点。我用的是JWT 拦截器方案而不是简单的session。思路是这样的用户注册时密码不是明文存库而是用BCryptPasswordEncoder加密后存储。登录成功以后后端根据用户ID和角色生成一个有效期为24小时的JWT Token返回给Android端。Android端把Token保存到SharedPreferences里之后每次请求都在Header里带Authorization: token字符串。后端这边在WebMvcConfigurer里注册一个自定义拦截器专门拦截需要登录才能访问的接口路径比如/api/order/**、/api/user/**。拦截器职责很简单拿到Header里的Token调用JWT工具类解析解析成功就把用户ID放到RequestContext里解析失败直接返回401错误码提示“登录已过期请重新登录”。这段代码是整个项目里最值得反复看的贴一个JWT工具的核心方法public static String generateToken(Integer userId, String role) { Algorithm algorithm Algorithm.HMAC256(your-secret-key); return JWT.create() .withClaim(userId, userId) .withClaim(role, role) .withExpiresAt(new Date(System.currentTimeMillis() 24 * 60 * 60 * 1000)) .sign(algorithm); } public static Integer parseToken(String token) { Algorithm algorithm Algorithm.HMAC256(your-secret-key); DecodedJWT jwt JWT.require(algorithm).build().verify(token); return jwt.getClaim(userId).asInt(); }踩过的坑提醒密钥不要硬编码在代码里最好放配置文件application.yml中否则源码一公开Token就能被伪造属于明显的安全隐患。另外JWT的expiresAt别设太长24小时足够演示时万一过期了重新登录也就几秒钟的事。3.4 房源接口与文件上传映射房源模块的接口大致有以下几个GET /api/house/list?page1size10keywordregionminPricemaxPrice分页查询房源支持关键词模糊匹配和条件筛选GET /api/house/detail/{id}查看房源详情同时返回房东信息POST /api/house/publish房东发布房源PUT /api/house/status/{id}房东上下架房源POST /api/house/upload上传房源图片返回图片URL分页查询用MyBatis-Plus的Page对象非常方便mapper.selectPage(page, wrapper)一行代码就能搞定。这里有个细节列表页不要返回房源的全部字段比如描述description可能很长一个房源卡片在RecyclerView里只需要标题、价格、区域、封面图、面积、户型这几个字段就够了把字段裁剪到HouseVO再返回能明显减少流量消耗也让列表加载更快。图片上传这块SpringBoot默认只能上传1MB文件需要在配置里调大同时配置静态资源映射。我的做法是本地建一个upload/目录图片上传后保存为yyyyMMddHHmmss_随机数.png的文件名然后配置addResourceHandlers把URL路径/images/**映射到本地磁盘目录。这样房源表里只需要存http://ip:8080/images/xxx.png这种字符串不需要折腾云存储项目阶段完全够用。3.5 订单与合同的事务处理订单模块涉及资金相关字段一旦出错影响很大所以事务控制格外重要。我创建订单的方法上加了Transactional注解逻辑顺序是校验用户身份和房源状态校验当前房源没有冲突的生效订单生成订单编号并计算总金额单价 × 天数插入订单记录返回订单ID订单状态流转的接口也比较关键比如“确认付款”接口需要把订单状态从“待付款”改成“已付款”同时把对应房源的状态改成“已出租”这两个操作必须在同一个事务里完成否则可能出现钱付了房源却还挂着可租的脏数据。这也是答辩时老师最喜欢深挖的点之一写代码时就把事务边界想清楚讲项目时就会很有底气。4. Android客户端实现从项目创建到页面联调4.1 Android项目结构与核心依赖配置Android端我用的是Java语言不是KotlinJava的参考资料对初学者更友好集成开发环境选Android Studio并且确认支持到API 30。build.gradlemodule级别里的核心依赖这样加implementation com.squareup.retrofit2:retrofit:2.9.0 implementation com.squareup.retrofit2:converter-gson:2.9.0 implementation com.squareup.okhttp3:okhttp:4.12.0 implementation com.github.bumptech.glide:glide:4.16.0 implementation com.android.support:design:28.0.0 implementation androidx.recyclerview:recyclerview:1.3.2 implementation com.google.android.material:material:1.9.0项目分包结构上建议按功能分层而不是按页面堆类model放实体类、network放Retrofit接口定义和网络工具、ui放Activity和Adapter、utils放SharedPreferences工具等。我见过不少新手把所有类平铺在一个包下面项目一大了找代码能翻半天从现在开始养成习惯按职责分包。4.2 Retrofit OkHttp网络层封装Android端与后端交互全靠HTTP接口网络层封装得好不好直接决定了后续页面的开发效率。这套项目里网络层我做了三件事。第一定义统一的BaseUrl。要注意这是个天坑Android模拟器访问本机后端服务不能用localhost或127.0.0.1必须用http://10.0.2.2:8080/这是模拟器为宿主机设置的特殊地址。如果用的是真机调试则填电脑的局域网IP而且手机和电脑必须在同一个WiFi网络下。第二建立Retrofit客户端单例。创建时通过OkHttpClient设置连接超时一般设为10秒并添加一个拦截器这个拦截器里统一往Header写入Token。代码如下OkHttpClient client new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .addInterceptor(chain - { Request request chain.request().newBuilder() .header(Authorization, TokenManager.getToken()) .build(); return chain.proceed(request); }) .build(); Retrofit retrofit new Retrofit.Builder() .baseUrl(http://10.0.2.2:8080/) .client(client) .addConverterFactory(GsonConverterFactory.create()) .build();第三定义api接口并调用形如public interface ApiService { GET(api/house/list) CallResultHouseListVO getHouseList(Query(page) int page); }4.3 关键页面实现首页列表与房源详情首页是用户进入App后看到的第一屏核心是RecyclerView 上下拉刷新加载分页。逻辑是这样的第一次进入加载第1页每页10条RecyclerView滑动到底部自动加载第2页下拉刷新则重新回到第1页。数据解析用Gson把ResultHouseListVO里的data.records转成房源实体列表交给Adapter渲染。Adapter里绑定图片时用Glide的placeholder占位图和error错误图避免网络慢的时候出现空白块。这是一个很提升体验的小细节。给每个房源卡片设置点击事件跳转到详情页时带上房源的id详情页再根据id调用GET /api/house/detail/{id}获取完整信息。详情页布局包含图片轮播多个房源图片、价格、标题、面积、户型、房东信息和底部操作按钮。操作按钮按角色区分如果是租客登录显示“收藏”和“立即下单”如果是房东本人查看自己的房源就显示“编辑”和“上下架”。这里的角色判断逻辑是Android端根据本地保存的用户角色字段来判断的虽然真正的安全控制必须靠后端但客户端做这层呈现优化会让整个App看起来专业很多。4.4 订单流程的客户端实现订单流程的页面交互是我认为整个客户端最核心的部分。用户从详情页点“立即下单”会先弹出一个日期选择对话框这步用两个DatePicker分别选开始日期和结束日期选好日期后根据房源每天价格算出总价展示给用户确认。确认后创建订单调POST /api/order/create携带房源ID、开始日期、结束日期后端返回订单ID。接着跳转到订单详情页页面展示订单信息和支付按钮。这里的“支付”是模拟的——项目阶段不需要真的对接支付宝或微信支付点击“确认付款”按钮直接调POST /api/order/pay/{orderId}后端把订单状态更新成已付款即可。别为了追求真实支付绞尽脑汁去申请商户接口既麻烦又没必要模拟支付在毕设场景完全说得通。订单列表页则用TabLayout Fragment实现分类展示分为“全部 / 进行中 / 已完成 / 已取消”内部同样是RecyclerView加载列表。5. 常见问题排查与避坑实录5.1 环境与联调阶段的典型问题这个项目从搭建到跑通的过程中我整理了以下几个最容易卡住的问题以及对应解决办法很多都是查了半天才找到原因。第一Android端请求接口报CLEARTEXT communication not permitted。这是Android 9之后默认禁止HTTP明文请求导致的。解决办法有几种最简单的在AndroidManifest.xml的application节点加上android:usesCleartextTraffictrue更规范的做法是创建res/xml/network_security_config.xml并在配置中允许特定域名明文访问。建议直接用第一种省事且不动其他配置。第二后端能正常访问但Android模拟器连不上。典型原因是BaseUrl写成了localhost或127.0.0.1必须改成10.0.2.2。如果是真机测试还要确认手机和电脑在同一局域网Windows防火墙需要放行8080端口。第三图片上传后访问返回404。明明文件上传成功了但是通过URL访问不到图片。这个大概率是静态资源映射没有配置成功。需要在WebMvcConfigurer里加上资源映射代码Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/images/**) .addResourceLocations(file: uploadDir); }这里有个小坑uploadDir最后必须以/结尾否则文件路径拼接会出错这是我当时排查了挺久才发现的。第四数据库连接报Public Key Retrieval is not allowed。这个报错源于MySQL 8.0的认证插件特性解决办法是在application.yml的数据库JDBC连接串加上allowPublicKeyRetrievaltrue参数同时设置useSSLfalse两条参数缺一不可。5.2 业务逻辑中的隐蔽Bug除了环境问题业务代码里也有几个很隐蔽的逻辑坑。订单金额算错。这个Bug非常经典——金额计算用的是浮点类型。最典型的情况是用户在详情页看到的床位价格是66.66下单时服务端按66.66 * 天数计算总价由于浮点运算误差会出现66.66这类金额计算后变成一堆奇怪的小数。正确的做法是数据库字段用DECIMALJava实体用BigDecimal所有金额运算都用BigDecimal禁止用float/double。这是后端开发的基本素养但恰恰是很多初学项目里最常见的错误。房源重复下单。如果并发场景下两个租客同时创建同一房源的订单后端没有做状态校验或事务控制就可能导致房源被重复出租。解决的关键在于创建订单的Service方法必须加事务并且在下单前严格校验房源状态——这里还可以升级一下用select ... for update行锁来防止并发问题但项目阶段做好“查状态 更新状态”在同一事务内基本就够用了。RecyclerView图片加载闪烁。列表页每次刷新数据时图片会先加载占位图再替换成网络图肉眼看起来就是图片“闪了一下”。解决办法是给Glide配置diskCacheStrategy缓存策略或者在刷新时不要直接notifyDataSetChanged全部重排而是用DiffUtil计算出差异后再更新。5.3 答辩环节的加分小技巧做完了项目最后一步就是要把这套系统讲出去。根据我指导过不少同学的经验答辩时有几个点非常加分主动讲清楚JWT认证的流程而不是只说“用了Token”说出表设计的合理性尤其要讲为什么同一个房源在某个时间段内只能有一个有效订单演示时准备两条路径——租客怎么从浏览到下单房东怎么发布房源到接单这两条主流程必须要顺如果老师问到“为什么不用Session”可以从分布式、多端复用、扩展等角度简短回答体现你的思考深度还有一个非常实用的技巧项目文档里附上接口清单。我把所有接口按模块整理成一个表格写明请求方式、请求路径、入参说明、返回示例这份接口清单在写文档、答辩、甚至以后扩展功能时都能用上一开始花半小时整理后面能省很多时间。6. 部署运行与收尾让系统在别人电脑上也能秒跑很多人把系统开发完就以为结束了但项目交付的时候往往还要面临一个问题换一台电脑、换一个环境还能不能顺利跑起来这里分几点说。数据库脚本要提供init.sql包含建库建表语句和初始化数据。我在实践中喜欢把数据库编码统一设成utf8mb4因为房源描述、合同内容里可能还有特殊字符和表情符号utf8mb4才能正确存储。MySQL新建数据库的时候就得指定好CREATE DATABASE IF NOT EXISTS house_rental DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;启动后端时第一次接手这个项目的同学最常见的问题就是配置文件里的数据库账号密码不是你本机的。所以application.yml里要把数据库用户名、密码、端口等做成显眼的配置项并且在文档里单独用一段“环境配置说明”写清楚。Android端的打包也值得多说一句开发的时候都是Android Studio直接点运行通过USB连接调试。但交付演示时往往需要直接给老师一个APK安装包让他装到手机上。操作路径是Build → Build Bundle(s) / APK(s) → Build APK(s)打包完成后APK文件路径会显示在底部提示里。拿到APK后装到手机同时让后端服务运行在局域网内可访问的电脑上手机通过局域网IP访问后端接口这一整套联调我前面提到过是演示环节的重中之重。最后再分享一个我个人的习惯收尾阶段千万不要直接删掉运行视频和讲解视频这类素材。我见过很多同学项目代码写完就把这些交付材料扔在一边等到答辩前一晚才发现视频打不开、演示数据被清空了。运行视频可以覆盖App从启动到核心功能演示的完整路径讲解视频则用来解释整体架构和关键代码逻辑它们跟源码和文档一个等级都是整个项目的一部分。说到底SpringBoot Android房屋租赁系统这类全栈项目和以后实际工作里的“前后端分离开发”思路是一致的——后端专注业务逻辑和数据处理端侧专注交互和展示中间通过明确的接口契约协作。你把这个项目的每个细节都吃透了不仅是在完成一个毕设更是提前走了一遍真实项目开发的完整流程。我在做这个项目的过程中最大的体会是数据库设计和事务控制这两块才是这类业务系统真正考验人的地方界面做得再花哨数据错乱一次就前功尽弃。如果你也正在做类似的系统建议先把房子表、订单表的关系理顺再动手写代码后面会顺很多。这套项目里的源码、文档、运行视频和讲解视频留在手里反复对照着看每一轮都会发现值得优化的细节这个过程中积累的调试思维和工程习惯比代码本身值钱得多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑