ARTICLE DETAIL

资讯详情

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

基于Spring Boot和Android的房屋租赁系统设计与实现全解析

基于Spring Boot和Android的房屋租赁系统设计与实现全解析 搞过毕业设计或者课程设计的同学应该都清楚房屋租赁系统算是Java Web方向很经典的一个选题了。市面上能搜到的相关项目不少但大多数要么只有后端、要么只有前端能把Spring Boot后端和Android客户端串起来还附带完整源码、文档、运行视频和讲解视频的确实不多。我最近刚好完整过了一遍这套基于Java Spring Boot Android的房屋租赁系统从环境搭建到功能实现、从本地调试到打包部署都跑通了。这篇文章就围绕这套系统的技术选型、核心模块拆解、实操过程和踩坑记录来写给正在做类似项目或者想自己从零搞一套全栈项目的同学一个参考。1. 项目整体设计与思路拆解1.1 需求分析房东、租客和管理员三种角色的边界划分房屋租赁这个业务场景说白了就是三拨人在里面打交道房东要把房子挂出去租客要找房子、看房、下单平台方管理员要做审核和运营管理。很多同类项目把三种角色糊在一起做权限结果后期改需求的时候越改越乱。这套系统的思路很清晰从一开始就按角色把功能边界切开了。租客端的核心操作是浏览房源、搜索筛选、收藏、发起租赁订单、支付订金或者租金、发表评价。房东端的核心操作是发布房源、管理自己名下的房源上下架、处理租客提交的订单、查看成交记录和收益。管理员端则负责用户管理、房源审核、订单监管、公告发布、数据统计这些后台操作。三种角色对应到Android客户端上实际上就是登录后根据用户类型动态渲染不同的功能入口。比如同样是一套房源详情页租客看到的是申请看房立即预订按钮房东看到的是编辑房源下架房源按钮管理员看到的是审核通过删除房源按钮。这套设计的好处是业务边界清晰后期维护每个模块的时候不会互相牵连。Android端采用单应用多角色的方案不管什么用户登录都进入同一个App只是功能菜单根据角色动态变化。这样比做三个独立App的方案要省事得多对于毕设级别的项目来说一套代码解决所有角色的需求不用维护多套客户端工作量也相对可控。1.2 为什么选Spring Boot Android技术选型背后的逻辑现在做Java Web方向的毕设后端框架基本就是在Spring Boot、SSM、Spring Cloud这几类里面选。这套系统用Spring Boot而不用传统的SSM最关键的原因是Spring Boot大大降低了配置成本和部署门槛内置Tomcat、自动配置、约定优于配置一个注解就能启动整个应用。Spring Boot对于这种单体架构的毕设项目来说是恰到好处的选择。SSM需要手动配置大量的XML文件、数据源、事务管理器光是环境搭建就能劝退不少人。Spring Boot则把这些繁琐的配置用自动配置机制取代了只需要在pom.xml里引入依赖、在application.yml里写几行配置就能跑起来。Android端选择原生开发而不是H5套壳或者跨平台框架主要是因为原生Java代码和后端Java语言栈统一在校生对Android的原生组件体系Activity、Fragment、RecyclerView、OkHttp一般都有基础出问题也好排查。而且这套项目配套了运行视频和讲解视频老师或者评委看到的是一个真机运行的原生App演示效果比H5套壳要扎实得多。1.3 系统功能架构从信息流看全貌这套系统从信息流的角度看就一条主线房源信息从房东的手里发布出来经过管理员审核展示在租客的App上租客下单后生成订单交易完成后产生评价。所有的功能模块都是围绕这条主线展开的。用户模块注册、登录、身份切换租客/房东、个人信息维护房源模块房源发布、图片上传、列表展示、条件筛选、详情查看、收藏管理订单模块创建订单、订单状态流转待支付、待确认、已生效、已完成、已取消评价模块租客对房源和房东进行评分和文字评价管理模块用户封禁/解封、房源审核、订单监管、统计分析公告模块管理员发布平台公告用户端轮播展示这六个模块之间的耦合度控制得比较好。房源模块和订单模块是核心用户模块提供基础支撑管理模块和评价模块则是辅助延伸。对于毕设答辩来说这个功能体量足够展示工作量又不会大到一个人做不完。2. 核心细节解析与实操要点2.1 数据库设计六张表怎么撑起整个业务数据库设计是这套系统的基础表设计得是否合理直接决定了后续代码好不好写。这套系统的核心表大概是这样的t_user用户表字段包括id、username、password、phone、role、status、create_time。角色用int类型区分比如0代表管理员、1代表房东、2代表租客比直接用字符串存角色更节省空间、查询效率也更高。t_house房源表字段包括id、landlord_id、title、description、price、area、address、cover_image、images、status、create_time。status字段很关键0代表待审核、1代表已上架、2代表已下架、3代表审核不通过这个字段串起了整个审核流程。t_order订单表字段包括id、house_id、tenant_id、landlord_id、start_date、end_date、total_price、status、create_time。订单状态用int存储0待支付、1待确认、2已生效、3已完成、4已取消、5已退款不同的业务操作触发不同的状态迁移。t_favorite收藏表字段包括id、user_id、house_id、create_time。用户和房源关联的时候必须用唯一约束防止用户对同一套房源重复收藏。t_comment评价表字段包括id、order_id、house_id、user_id、content、rating、create_time。评价表关联order_id可以防止有人没交易过就乱评价。t_announcement公告表字段包括id、title、content、create_time、update_time。表结构的核心设计原则是主外键关系清晰尽量用状态机字段而不是物理删除。比如用户删除房源实际是把房源status改成已下架而不是从数据库里DELETE掉这样能保留审计痕迹后面即使出问题也好回溯。2.2 后端接口设计RESTful API和统一返回体Spring Boot后端和Android客户端的数据交互走的是HTTP接口接口设计规范直接关系到前端开发的效率。这套系统在接口设计上遵循了RESTful风格按资源命名URL、通过HTTP方法区分操作类型。接口统一返回格式是JSON并且定义了一个通用的返回体类ResultTpublic class ResultT { private Integer code; private String message; private T data; // 省略构造方法和getter/setter }所有接口的返回都包一层Resultcode200表示成功code401表示未登录code500表示服务器异常。这样的好处是Android端只需要解析一次这个结构统一处理异常不用每个接口单独判断。接口的URL设计大概是这样POST /api/user/register注册POST /api/user/login登录GET /api/house/list?page1size10房源列表GET /api/house/{id}房源详情POST /api/house发布房源房东PUT /api/house/{id}修改房源房东DELETE /api/house/{id}下架房源房东POST /api/order创建订单GET /api/order/my我的订单POST /api/comment发表评价GET /api/admin/user/list管理员获取用户列表分页参数、筛选条件都通过query参数传递例如GET /api/house/list?keyword两室priceMin1000priceMax3000areaType整租服务端用MyBatis Plus的Wrapper条件构造器实现动态拼接查询。PC端管理后台和Web管理端可以通过AdminLTE或者Vue等模板进行构建而Android端作为主要的业务操作端使用这些接口。2.3 Android端架构MVP模式与网络层封装Android端的架构选择的是MVPModel-View-Presenter模式跟MVC相比MVP最大的优势是业务逻辑和界面展示完全解耦。Activity只负责界面渲染和事件回传具体的业务逻辑放在Presenter里面数据获取放在Model层。Android端的网络层基于OkHttp Retrofit封装Retrofit用注解定义接口省去了写大量网络请求代码的重复劳动。登录后服务端返回Token客户端把Token存在SharedPreferences里每次请求在拦截器中自动携带Token实现会话保持。界面层比较核心的是房源列表使用的是RecyclerView CardView组合每个卡片展示房源封面图、标题、价格、面积、地址等核心信息整体视觉效果比ListView时代要好看不少。图片加载用的是Glide支持占位图、圆角、图片裁剪加载网络图片体验比较流畅。3. 实操过程与核心环节实现3.1 环境准备一套能直接跑起来的配置清单跑这套系统的步骤其实不复杂难点主要在一些细节配置容易出错。我列一下完整的踩坑后的环境配置清单本机环境建议如下我用的是这套完全不冲突JDK 1.8Spring Boot 2.x系列对JDK 8支持最友好Maven 3.6.3MySQL 5.78.0也可以但注意驱动依赖要换成com.mysql.cj.jdbc.DriverAndroid Studio 4.x以上AGP版本必须和你手里的源码保持一致最好直接用项目自带的gradle wrapperNavicat或者IDEA自带的数据库工具用来建库导数据后端启动步骤用Navicat新建数据库导入项目中的sql/house_rent.sql脚本修改application.yml中的数据源配置server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/house_rent?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver redis: host: localhost port: 6379 servlet: multipart: max-file-size: 10MB max-request-size: 10MB在IDEA中打开项目等待Maven依赖下载完成运行HouseRentApplication.java后端启动成功后通过http://localhost:8080/api/user/test这个测试接口验证接口是否正常返回JSON。Android端启动步骤Android Studio打开根目录下的android文件夹等待Gradle同步完成修改项目中的网络配置找到ApiConstants.java或者类似的基础配置类把本机IP地址填进去public class ApiConstants { // 模拟器访问本机后端地址必须是10.0.2.2不能写localhost public static final String BASE_URL http://10.0.2.2:8080/api; }连接真机或者启动模拟器点击Run按钮运行App注册一个租客账号和一个房东账号分别登录验证首页和发布房源流程这套配置跑下来前后端端口不冲突、数据库连接正常基本就是一套完整的可运行状态。3.2 后端核心模块登录鉴权与房源全生命周期管理登录鉴权是整个后端最基础的模块。这套系统没有引入SpringSecurity采用的是JWTJSON Web Token技术。用户登录成功后服务端生成一个Token返回给客户端后续的请求里带着这个Token就能识别用户身份。Token的生成用Java的JWT库public class JwtUtil { private static final String SECRET_KEY house_rent_secret_key; private static final long EXPIRE_TIME 7 * 24 * 60 * 60 * 1000; // 7天有效期 public static String createToken(Integer userId, String username, Integer role) { return Jwts.builder() .claim(userId, userId) .claim(username, username) .claim(role, role) .setExpiration(new Date(System.currentTimeMillis() EXPIRE_TIME)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); } public static Claims parseToken(String token) { return Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody(); } }前端每次请求在拦截器中读取Token然后通过ThreadLocal把用户信息传递到Service层这样就可以知道当前登录用户是谁、他的角色是什么对应不同角色做不同的操作权限校验。比如修改房源接口服务端先判断当前登录用户是不是这间房子的房东如果不是直接返回无权操作错误码这个判断逻辑虽然简单但是很实用。房源模块的核心是发布流程。房东在前端Android端填好房源标题、描述、价格、面积、地址选择封面图片后提交后端接收请求后存储房源记录房源status默认为0待审核。管理员在后台列表中看到待审核房源点击通过后status变为1房源才会在前端的房源列表中展示出来。这里涉及一个多文件上传的处理Spring Boot接收MultipartFile数组保存到服务器本地的uploads目录PostMapping(/api/house/upload) public ResultListString upload(RequestParam(files) MultipartFile[] files) { ListString urls new ArrayList(); for (MultipartFile file : files) { String originalFilename file.getOriginalFilename(); String suffix originalFilename.substring(originalFilename.lastIndexOf(.)); String fileName UUID.randomUUID().toString() suffix; File dest new File(uploadDir fileName); file.transferTo(dest); urls.add(/uploads/ fileName); } return Result.success(urls); }这里有一个比较重要的参数细节Spring Boot默认上传文件大小限制为1MB上传房源图片时非常容易出现超出限制的报错需要在配置中调整参数spring: servlet: multipart: max-file-size: 10MB max-request-size: 10MB3.3 Android端核心界面从列表页到下单流程的完整实现Android端最核心的一个功能链路是浏览房源 → 查看详情 → 创建订单 → 支付 → 评论这个链路覆盖了房源、订单、支付、评价四个模块也是演示时最能体现系统完整性的一段操作。首页的房源列表用的是RecyclerViewLinearLayoutManager数据从接口GET /api/house/list里拉取。这里的列表不仅是简单的数据渲染还支持下拉刷新和上拉加载更多public class HouseListActivity extends AppCompatActivity { private ListHouse houseList new ArrayList(); private HouseAdapter adapter; private int currentPage 1; private boolean isLastPage false; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_house_list); RecyclerView recyclerView findViewById(R.id.recyclerView); LinearLayoutManager layoutManager new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); adapter new HouseAdapter(houseList); recyclerView.setAdapter(adapter); // 下拉刷新 SwipeRefreshLayout refreshLayout findViewById(R.id.refreshLayout); refreshLayout.setOnRefreshListener(() - getHouseList(true)); // 上拉加载更多监听滚动事件判断滑到最后一个item时加载下一页 recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { int visibleItemCount layoutManager.getChildCount(); int totalItemCount layoutManager.getItemCount(); int firstVisibleItemPosition layoutManager.findFirstVisibleItemPosition(); if (!isLastPage (visibleItemCount firstVisibleItemPosition) totalItemCount) { getHouseList(false); } } }); } }房源详情页的展示比较直接用ViewPager做图片轮播展示房源多张图片下面是房源的基本信息、房东信息、价格区间和房屋描述。底部固定两个操作按钮左边是联系房东弹出底部的Dialogs右边是立即预订跳转到订单确认页面。下单页面的核心逻辑包括选择租期起止日期、系统自动计算总价、展示押金和中介费规则。金额计算必须放在后端做Android端只负责传入日期参数防止客户端被轻易篡改。这个设计虽然看起来不复杂但确实是很多半路出家的项目容易漏掉的关键点。3.4 管理员端业务逻辑审核流程与数据看板管理员端的功能其实不需要单独做一个App因为管理员通常用的是后台系统。这套系统里管理员的功能嵌入在Web管理端或者Android的特定角色入口核心操作是审核房源和管理用户。房源审核的页面就是一个列表展示所有status0的待审核房源管理员点击审核通过或者驳回后更新状态。对应的后端代码逻辑很简单PutMapping(/api/admin/house/{id}/audit) public Result? auditHouse(PathVariable Integer id, RequestParam Integer status) { House house houseMapper.selectById(id); if (house null) { return Result.error(房源不存在); } house.setStatus(status); houseMapper.updateById(house); return Result.success(); }数据统计模块可以用来做柱状图和饼图展示比如统计每个月的成交订单数、不同类型房源的占比、各区域房源数量等。这个模块在答辩时是比较加分的展示点老师一般都会很感兴趣。4. 常见问题与排查技巧实录4.1 Android连不上后端WebView和模拟器的网络坑这个绝对是遇到频率最高的问题。Android模拟器里访问宿主机有一个特殊的IP地址规则localhost指的是模拟器自己而不是你的电脑。模拟器访问宿主机必须用10.0.2.2public static final String BASE_URL http://10.0.2.2:8080/api;如果你是用真机调试就必须把IP地址改成电脑在局域网内的IP。可以在命令行敲ipconfig查看Windows或者ifconfigMac然后填上类似192.168.1.5的地址。另外Android 9.0及以上系统默认禁止HTTP明文请求虽然你的Retrofit地址写对了依然会报CLEARTEXT communication not permitted错误。解决办法有两个一个是在AndroidManifest.xml里配置android:usesCleartextTraffictrue另一个是写一个network_security_config.xml配置文件。真机调试还有一个坑电脑防火墙默认会拦截Android真机发来的请求。我第一次用真机调试时后端接口怎么都访问不了关了Windows防火墙就好了。如果不想关防火墙可以单独开放8080端口。注意在同一个局域网环境下Android设备和后端服务所在的电脑必须处于同一网段。用公司或者校园网时要特别留意ACL隔离和Wi-Fi用户隔离这种情况下怎么都连不上的话换个手机热点测试是最快的排查方式。4.2 Spring Boot版本兼容性最容易翻车的隐性问题Spring Boot版本选错会导致一堆莫名其妙的依赖冲突。我建议大家认准Spring Boot 2.5.x到2.7.x这个版本区间不管系统的pom里已经锁定了什么版本尽量不要去手动升级成Spring Boot 3.x版本。Spring Boot 3对JDK版本要求变成了17而且很多第三方组件的API有变化如果项目里用了旧的依赖一升级整个项目就跑不起来了。MyBatis Plus版本也要特别注意。当前项目的写法用的可能是3.4.x或者3.5.x的API如果你换了一个版本selectPage和Wrapper构造器的行为可能都有变化。最稳妥的办法是直接用项目自带的pom.xml和Maven仓库不要自己动手改版本号。另外MySQL 8.0和MySQL 5.7的驱动类也不一样。5.7用com.mysql.jdbc.Driver8.0用com.mysql.cj.jdbc.Driver。如果用的是高版本数据库但配置的是旧驱动启动报错会提醒你换驱动类直接改配置就行。4.3 图片上传失败权限和大小限制的双重问题房源发布时图片上传失败的频率非常高分为两种情况。第一种是没配权限Windows服务器上如果没有给uploads目录设置写入权限文件保存时会抛出Permission denied。第二种是大小超限这在前端容易被忽略因为Android端选图时手机照片动辄几MB但Spring Boot的默认上传限制是1MB。解决的常规操作是两步在后端application.yml调整大小限制到10MB或者更大在Android端加一个图片压缩处理用BitmapFactory.Options的inSampleSize来压缩大图。以下是一个标准的图片压缩代码片段public static File compressImage(Context context, Uri uri, int targetWidth) { try { BitmapFactory.Options options new BitmapFactory.Options(); options.inJustDecodeBounds true; BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri), null, options); int width options.outWidth; int sampleSize 1; while (width / sampleSize targetWidth) { sampleSize * 2; } options.inSampleSize sampleSize; options.inJustDecodeBounds false; Bitmap bitmap BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri), null, options); File file new File(context.getCacheDir(), System.currentTimeMillis() .jpg); FileOutputStream fos new FileOutputStream(file); bitmap.compress(Bitmap.CompressFormat.JPEG, 85, fos); fos.flush(); fos.close(); return file; } catch (IOException e) { e.printStackTrace(); return null; } }4.4 JWT用户登录丢失问题误区与排气顺序Android端登录成功后后端返回的Token会保存在本地每次请求在拦截器里统一添加Authorization头。如果出现了用户未登录报错排查顺序先看Token在本地有没有存下来再看请求头有没有正确添加最后看服务端解析的时候有没有报异常。我遇到过一种比较隐蔽的情况用户登录成功但隔了一天再来访问接口就报401。排查后发现是JWT过期时间设置成了12小时而用户刚好是前一天晚上登录的过了一天就一定过期了。解决办法是把过期时间拉长到7天同时在前端做Token失效的拦截处理收到401或者特定的业务码就跳回登录页提示用户重新登录。这个方案既能保持良好的用户体验也不会让会话无限期有效。4.5 常见的报错速查表现象根本原因解决方案后端启动失败报端口被占用8080端口被其他进程占用换个端口改成8090或者杀掉占用进程Android连不上接口一直转圈模拟器用了localhost改成10.0.2.2或真机用局域网IP上传图片提示文件过大Spring Boot默认1MB限制配置文件上传大小到10MB数据库中文乱码JDBC连接没有指定字符集URL加characterEncodingutf8访问接口报CLEARTEXT错误Android 9拦截明文HTTP启用usesCleartextTraffic刷新列表出现重复数据分页页码没有正确加一检查loadMore时的page增量逻辑注册时提示用户名已存在查询条件写错检查selectOne的Wrapper条件是否正确5. 这套源码附带资源包的使用建议这套项目附带的内容不只是一堆代码文件源码压缩包里通常包含四类东西完整的Java后端源码、Android客户端源码、数据库SQL脚本和说明文档PDF、演示视频和讲解视频。很多人拿到手就急着跑代码其实先花一点时间梳理包内结构会更高效。建议的浏览顺序是先看doc目录下的需求分析文档和数据库设计文档理清系统是干什么的、表关系怎么样 → 再看项目的接口文档和部署说明搞清楚接口和数据流向 → 然后按照部署文档把环境跑起来 → 最后再看演示和讲解视频对照视频里的操作流程复现功能。这样从文档到运行再到理解效率比直接看代码高得多。讲解视频通常是讲解员边操作边讲解内容会覆盖系统登录流程、各功能模块的操作演示、源码的目录结构和核心代码逻辑、数据库的导入步骤。这些视频的价值在于能快速告诉你哪里是重点、哪里可能问什么在答辩前看一遍非常有帮助。其实这个项目的文档资料做得比较完整从需求分析、数据库设计、接口设计到测试用例都有覆盖。这对写自己的毕业论文或者设计报告有直接的参考价值不需要全部照搬但完全可以参照它的结构和表达方式来组织自己的章节逻辑。6. 项目扩展思路改造成更有竞争力的项目如果一个基本完整的房屋租赁系统不足以让你在答辩中脱颖而出可以考虑在它的基础上做一些低成本高回报的功能扩展。这些扩展不会改动系统的基本架构但能在功能丰富度和技术深度上提升一个档次。一个比较适合的扩展方向是引入Redis做房源浏览量的缓存和热门房源的排序。Spring Boot整合Redis的成本很低引入spring-boot-starter-data-redis依赖然后对访问量高的接口做缓存处理。比如房源的详情数据用Redis缓存每次访问先查缓存、再查数据库可以明显提升接口的响应速度答辩的时候解释起来也很好懂我用了Redis做热点数据缓存压测QPS提升了X倍。另一个方向是做简单的推荐算法。根据用户的浏览记录和收藏记录用基于类别的协同过滤思想推荐类似的房源。虽然实现不了太复杂的算法模型但用SQL或者简单的Java逻辑就能实现看了又看的推荐效果。还可以把管理员后台从简单的页面升级成Vue ElementUI开发的管理系统通过前后端分离的方式调用后端接口。这个扩展也很有吸引力技术点从Spring Boot Android升级成了Spring Boot Vue Android前后端分离全栈架构。如果你准备把系统部署到服务器上让外部访问注意三个点服务器安全组放行8080端口、MySQL的远程访问权限、后端接口的跨域配置。CORS跨域可以在后端写一个WebMvcConfigurer实现addCorsMappings方法允许前端访问。7. 实操总结从拿到项目到顺利演示的关键经验整套系统从零开始跑通我自己走了一遍下来最大的体会是比起代码本身跑通环境和理清数据流是更花时间的事。如果你拿到这套源码请一定严格按照文档里写的环境版本来配置不要凭感觉用最新的JDK、最新的Spring Boot版本否则各种隐性问题会消耗掉大量没必要的时间。另外建议所有演示前先自己做一遍完整的演示流程登录、发布房源、管理员审核、租客看房下单、评论、数据统计。不要觉得步骤熟了就可以跳过实操模拟真实演示环境下的卡顿和Bug往往都是因为跳过了准备步骤。说到底毕业设计做得精不精彩关键不在于用了多高级的技术栈而是你把一个完整的问题用可运行、可维护、有文档、可演示的方式进行了解答。这套Spring Boot Android的房屋租赁系统技术路线不算花哨但是胜在扎实、完整、能跑配合它的文档和视频确实是一个值得推荐的参考项目。
返回列表