资讯详情

基于Spring Boot和Vue的家政服务系统设计与实现

📅 2026/10/10 22:50:06 | 华诺云谱 👁 阅读
基于Spring Boot和Vue的家政服务系统设计与实现
最近在整理自己做过的一个家政服务系统项目正好把整套东西从技术选型到落地细节重新过了一遍。这个项目是基于 Java 和 Vue 做的完整前后端分离应用配套源码、数据库脚本和开发文档都齐全适合正在准备毕设、或者想找一个完整项目练手的前端/后端学习者。老规矩先把项目关键信息放前面后端用的 Spring Boot前端是 Vue 全家桶数据库是 MySQL整套系统覆盖用户、家政人员、管理员三个角色包含服务预约、订单管理、支付对接、评价反馈、后台数据统计这些常规模块。这篇文章不打算照搬 README而是把项目设计时为什么要这么选型、数据库表怎么拆、前后端联调时最容易踩的坑以及实际部署时要注意的配置问题一条一条讲清楚。1. 项目背景与技术选型思考1.1 家政服务系统到底解决什么问题家政服务这个行业线上化的核心痛点是信息不透明和调度效率低。用户找不到靠谱的阿姨阿姨找不到稳定订单中介机构又没法实时掌握服务质量。这套系统要做的就是把这三点打通用户端能浏览服务项目、查看阿姨资料、在线预约和支付家政人员端能接收订单、管理日程、查看评价管理后台则负责审核阿姨入驻、配置服务价格、处理用户投诉和退款申请。整个业务链路从用户下单开始到阿姨接单、上门服务、用户评价结束中间每一个环节都需要有状态记录和权限控制这也就是为什么要有独立的订单状态机和三套登录体系。我见过太多把这种系统做成简单增删改查的案例最后交上去被老师或者面试官一问“订单并发怎么办”、“阿姨时间冲突怎么处理”就卡壳。所以这个项目在设计时特意把业务规则前置到数据库和接口层而不是塞在页面里。举个例子同一个家政阿姨同一个时间段只能有一个有效订单这个约束在数据库层面就要通过唯一索引和订单状态共同保证而不是靠前端按钮灰不灰来判断。1.2 为什么选 Java Vue 这套组合技术栈选择一定不是为了追新而是为了稳。Java 生态里 Spring Boot 做后端接口开发效率极高内置了 Tomcat、数据源管理、参数校验、AOP 切面等一堆常用的东西配合 Maven 管理依赖写业务代码时能少掉很多环境配置工作。而且 Java 类型严谨对于订单金额、时间区间这类业务数据编译期就能发现一部分低级错误这在线下服务业系统里很重要——订单状态丢一个字符串整个状态的流转就会乱掉。前端选择 Vue 而不是其他框架核心原因是 Vue 的上手曲线平缓模板语法对后端开发同学也很友好。配合 Vue Router 做页面路由、Axios 做 HTTP 请求、Element UI 做后台管理界面一套代码同时覆盖用户端 H5 和后台管理页面不需要维护两套前端工程。而且 Vue 的组件化开发方式非常适合这种按功能模块拆分的项目比如预约表单、阿姨卡片、订单列表都可以做成独立组件后面对接小程序或者 App 时甚至可以直接复用业务逻辑层。注意选型时别盲目追求微服务。这个项目的体量用单体应用加前后端分离完全足够拆成微服务只会增加部署和维护成本。起步阶段先把业务闭环跑通比分布式架构好看更重要。2. 核心功能模块设计与拆解2.1 三类角色的权限划分与功能边界系统的用户权限一共分三种普通用户、家政阿姨服务者、系统管理员。权限模型直接用基于 Token 的认证方式实现后端在每次请求时解析请求头里的 Token然后根据角色 ID 去访问对应的功能模块。这里不用传统的 Session 是因为前端部署和后端服务可能不在同一个域名下跨域场景下 Session 的处理很麻烦而 Token 通过 HTTP 头传递天然适合前后端分离的架构。普通用户的功能入口主要有浏览服务项目、搜索家政阿姨按服务类型、价格、评分、区域筛选、查看阿姨详情页带证件照片、服务经历、历史评价、创建预约单、在线支付、查看订单进度、对完成订单进行评价和投诉。家政阿姨端的功能就完全不同了主要是接收系统派单、查看自己的日程表、设置可接单时间段、确认开始服务/完成服务、查看用户评价和收入统计。管理员后台则承担了系统运营的职责家政人员入驻审核、服务类目管理、价格调整、订单人工干预退款、改期、取消、用户留言管理、基础数据统计日订单量、用户数、交易额走势。权限控制落在后端接口层面具体做法是给每个接口配置注解或者拦截规则。比如/api/user/**只允许用户角色访问/api/worker/**只允许家政人员角色访问/api/admin/**只允许管理员访问。对于少数跨角色的接口比如查询订单详情用户和家政人员都可以调用那就单独配置成多角色可访问然后在代码里做数据隔离确保用户只能看到属于自己的订单数据。2.2 从预约到结算的完整订单流订单是整个系统的核心我在设计时画了一条完整的状态链路待支付 - 待接单 - 已接单 - 服务中 - 已完成 - 已评价额外还有两个异常状态已取消和已退款。用户创建预约单后先进入待支付状态只有支付成功才会释放给家政人员去接单这样能避免恶意占单。支付成功之后进入待接单队列系统支持广播到所有符合地理位置和服务类目的家政人员终端谁先抢到订单就绑定谁绑定后状态变为已接单。接下来是上门服务阶段。这里有一个容易被忽略的细节实际家政服务经常会出现迟到或者提前完成的情况所以系统在订单里额外记录了两个时间点——预计开始时间和实际开始时间。家政人员点击开始服务后订单状态变成服务中直到他点击完成服务状态才变为待评价。用户有 7 天时间进行评价逾期系统会自动默认好评。结算逻辑相对简单粗暴订单金额在下单时根据服务时长和单价计算冻结服务完成后从用户预支付款中扣除平台抽成剩余部分计入家政人员的可提现余额。2.3 服务评价与评分体系设计评价模块看起来不起眼实际上对平台来说非常重要因为家政服务的决策高度依赖口碑。数据库里评价表的核心字段包括订单 ID、用户 ID、家政人员 ID、服务等级评分1~5 星、态度评分、专业评分、评价内容、匿名标识、晒图 URL 列表。这里我把评分拆成了两个维度——专业度和服务态度比单独一个总分更能在列表页给用户提供多维参考。评分最终要聚合到家政人员的总评分上这里没有用简单的平均分而是在计算时加入了时间衰减因子。简单说就是最近三个月的评分权重更高半年前的评分权重逐渐降低这样能防止老师傅靠早期高分“躺平”。实现方式也很基础查询评价列表时在 Service 层按时间窗口加权计算即可不需要引入额外组件。此外如果用户评价低于三星系统自动触发管理员的客服回访待办及时处理潜在投诉。3. 数据库设计与关键表结构3.1 核心表拆分与关联关系数据库设计是整个项目的地基我把整套系统的表分成三组用户组、交易组、运营组。用户组包括user用户基本信息、worker家政人员扩展信息、worker_cert阿姨证件照片和工作经历交易组是核心包括service_category服务类目、service_item具体服务项目、order订单主表、order_item订单明细、payment_record支付流水、refund_record退款记录、evaluation评价运营组包括banner首页轮播图、notice公告、worker_audit_log入驻审核日志、admin_user管理员账号。关键的外键关系遵守一个原则订单表只保存最小必要信息其他信息通过 ID 去关联。比如订单表里存储user_id、worker_id、service_item_id但不存用户手机号和阿姨名字的冗余字段。查询时通过 JOIN 获取上下文信息。这样做的好处是当用户或者阿姨资料变更时不会污染历史订单数据。唯一的冗余是订单表里的service_start_time和service_end_time这两个字段由下单时的预约时间拷贝而来避免之后修改服务时长影响历史订单。3.2 订单表的状态机设计订单表是业务最复杂的表光状态字段就值得单独讲。状态字段我用的是一个整型枚举order_status取值规则是0 待支付、1 待接单、2 已接单、3 服务中、4 已完成、5 已评价、6 已取消、7 已退款。整型在索引和日志排查上都比字符串高效而且防手滑打错单词。除了状态还有一个status_history字段JSON 类型用来记录每一次状态变更的时间点和操作者这个在排查纠纷时非常管用。状态机的流转规则不能只写在代码里还必须通过数据库约束兜底。比如用户只能取消状态为 0 或 1 的订单正在服务中的订单要取消必须先走管理后台申诉。实现上用了一个比较简单的状态机引擎把不同角色允许执行的操作和对应的迁移状态定义成一个二维映射表每次更新订单时先从映射表里查有没有这条迁移路径没有就直接抛异常。这个方法比到处写 if-else 清晰很多后期加需求比如改期、加钟时只需要改映射表。3.3 数据库索引与优化经验这套系统数据量在同体量项目里不算大但查询条件却非常杂所以索引设计不能乱来。订单表我建了联合索引(user_id, order_status)和(worker_id, order_status)分别支撑“我的订单列表”和“家政人员的接单列表”两个高频查询。另外单独为(create_time)建了索引因为后台统计报表经常按天聚合。支付流水表的(order_id)加了唯一索引确保同一个订单不会关联两条成功支付的流水。有一个真实踩坑的例子一开始做订单列表分页时排序字段用的order_status结果数据量上了十万之后明显变慢。后来发现因为排序字段没有和 WHERE 条件里的字段联合起来建索引导致 MySQL 走了文件排序。解决方案是把排序字段改成create_time并调整索引顺序为(user_id, create_time)查询时间从 300ms 降到了 20ms 以内。这个经验告诉我索引不是建得越多越好而是要对齐高频查询的完整路径。4. 前后端实现与关键代码片段4.1 后端接口的通用设计模式后端接口统一使用 RESTful 风格返回格式用了一个自定义的Result类包装结构是{ code, message, data }。code为 0 表示成功非 0 表示业务异常比如 1001 参数错误、1002 未登录、2001 订单状态不允许当前操作。这种封装最大的好处是前后端约定简单前端 Axios 响应拦截器只需要判断 code 是不是 0不是 0 就直接弹 Message 提示不用每个页面都写一套错误处理。数据校验这一块我直接在实体类字段上加了注解比如NotBlank、NotNull、Min、Pattern等配合全局异常处理类捕获MethodArgumentNotValidException能在进入 Service 层之前就把脏数据拦下来。这里有个细节开发阶段要把 Spring Boot 的server.error.include-message配成always不然前端只能看到一句“服务器内部错误”排查问题会非常痛苦。4.2 Vue 项目里怎么封装请求和路由守卫前端工程用 Vue CLI 初始化核心目录结构就是src/views放页面、src/components放公共组件、src/api放接口定义、src/router路由配置、src/store放用户状态。所有接口请求统一走src/api/request.js里封装的 Axios 实例这个实例配置了基础 URL、超时时间、以及请求/响应拦截器。请求拦截器负责在每一次请求头里附带 Token响应拦截器负责统一处理 401 跳转登录、非 0 状态码弹错误提示。路由守卫是 Vue 项目里必须做的事不然用户在没登录状态下直接访问/order/list页面就能看到接口报错。我在router.beforeEach里判断目标路由的meta.requiresAuth字段如果需要登录并且 store 里没有用户信息就跳转到登录页并带上 redirect 参数登录成功后再返回原页面。还顺便处理了角色控制不同角色登录后能进入的页面路由不同比如家政阿姨不能访问 admin 前缀的页面这个也是通过路由 meta 配置实现的。4.3 文件上传与服务图片管理家政系统里涉及大量的图片上传场景用户头像、阿姨身份证照片、服务资质证书、评价晒图等。文件上传接口用的是 Spring Boot 的MultipartFile上传后把文件保存到服务器指定目录同时将访问 URL 存进数据库。为了不拖垮应用服务器我在上传接口里做了几个限制单个文件最大 5MB、只允许 jpg/png/webp 三种格式、文件名用 UUID 重命名避免冲突。严格说一个完善的系统应该把文件存到 OSS 或者 MinIO但单体项目里先落本地磁盘也没问题关键是把上传目录配置到application.yml中方便后续换存储服务。部署时还需要在 Nginx 里加一条静态文件访问映射把/upload/**前缀转到一个专门的磁盘路径别把图片塞进 jar 包里面去。注意图片访问路径不能保存成浏览器地址栏里的完整 URL因为后端环境切换时本地、测试、生产域名和端口都不一致。正确做法是数据库只存相对路径/upload/xxx.jpg前端拼接当前环境的 baseURL 来显示。5. 真实项目里的坑与排查手册5.1 跨域问题别再傻傻加注解了前后端分离项目十有八九会遇到跨域我见过不少人直接在 Controller 上写CrossOrigin解决。这么做虽然本地联调能通但只要后端环境切换或者请求头加了自定义 Token 字段大概率还有坑。我的统一方案是在后端写一个WebMvcConfigurer配置类通过addCorsMappings方法统一配置允许的源、方法、请求头和凭证。注意allowCredentials(true)时allowedOrigins不能填*必须写死前端域名否则浏览器会拦截。另一个坑是前端本来 BaseURL 写错了打了半天跨域问题的怪最后发现是端口没对上。所以排查跨域的第一步永远是用浏览器开发者工具看 Network 面板确认请求发了没有、返回了什么状态码。如果响应头里没有Access-Control-Allow-Origin才是真正走到了后端 CORS 配置这一步。5.2 订单超时未支付自动取消怎么实现需求是待支付订单超过 15 分钟自动取消并把库存家政人员的时间段释放掉。很多人第一反应是 Timer 定时扫描这种做法在大数据量下容易出问题扫描一批订单要好几秒而且服务重启就丢任务。我的方案是用延迟队列的思路下单时创建一个OrderTimeoutMessage里面记录订单 ID 和过期时间投递到一个延迟队列消费者收到消息后先查一下订单当前状态如果还是待支付就执行取消逻辑不是就丢弃消息。实现上没有引入额外中间件而是直接用了 Redis 的过期键监听配合一个死信队列兜底。下单时执行SET orderTimeout_{orderId} 1 EX 900订单支付成功后手动删除这个 keykey 过期后自动触发监听器执行订单取消。但 Redis 过期监听有延迟抖动所以同时在数据库里加了一个定时任务每小时扫描一次超时订单做二次补偿保证不会因为 Redis 抖动导致订单永不取消。5.3 部署上线时的配置清单项目部署我建议直接用 Docker Compose 编排一条命令把 MySQL、Redis、后端服务、前端 Nginx 全部拉起来。这里给出一份经过实测的配置清单你直接抄作业就行组件关键配置备注MySQL 8.x字符集 utf8mb4排序规则 utf8mb4_general_ci不设置 utf8mb4 存不了 Emoji 评价内容Redis关闭 RDB 持久化开启 AOF过期事件和缓存场景不需要 RDB 快照后端 JVM-Xms256m -Xmx512m单机跑测试完全够用别给多了浪费内存Nginxclient_max_body_size 10m默认上传限制 1m不调大图传不上来定时任务单独配置 cron 表达式用Scheduled时要给线程池设大小单个任务卡住会阻塞后续任务部署时最容易忘的一个细节是 MySQL 的lower_case_table_name参数。如果在 Linux 服务器上刚建好数据库就导入 SQLWindows 本地开发时表名可能全是小写Linux 上区分大小写导致表找不到。这个可以在导入前统一把 SQL 脚本里的表名改成小写或者建库时直接指定lower_case_table_name1提前规避掉这种低级问题。说到数据库项目自带的init.sql里已经包含全套建表和初始化数据但你拿到手后照样需要手动改两处一是管理员初始账号密码二是每个服务项目的默认图片 URL。线上环境不能直接裸奔使用默认密钥这就像新买的路由器不改 WiFi 密码一样心大。6. 一些实用的小建议最后再分享一个我自己觉得特别顺手的小经验在写这种全栈项目时先把接口文档定义好再动手写前后端任何一行代码。你不需要用什么重型工具在项目根目录放一个api.md把每个接口的路径、参数、返回示例都写上。前后端联调时各自按文档开发遇上字段对不上直接在文档里改一版比反复口头沟通高效得多。别小看这个习惯实际项目交付时这份文档往往是答辩和评审中的加分项。另外如果还打算在这个项目上做扩展我建议优先加一个消息推送模块就是订单状态变更时通过站内信或者短信通知用户。这块并不复杂Spring Boot 里用 WebSocket 就能写个简易的站内信系统但业务上和订单状态机紧密相关你只需要在每次状态迁移之后广播一个事件就好。加上之后整套系统才真正具备了线上产品的完整闭环。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑