FEATURED · 精选文章

家政服务微信小程序+Java后端开发实战:从登录到订单状态机

发布时间 / 2026/9/12 22:26:53
来源 / 创域科博编辑部
栏目 / 资讯中心
家政服务微信小程序+Java后端开发实战:从登录到订单状态机 简介这是一份面向高校毕业设计场景的家政服务微信小程序项目源码聚焦 Java 方向选修/毕设需求适合正在做课程设计或毕业项目的学生参考。项目以微信小程序原生前端为主包含完整页面与交互流程下载后按说明配置对应运行环境即可本地演示能为答辩和功能展示提供现成蓝本。压缩包共 169 个文件js、wxml、wxss 分别负责逻辑、结构与样式json 管理项目及页面配置jpg/png/gif 提供界面图与动效素材整体约 2.33MB轻量且目录清晰。源码按 pages、utils、images、server 等模块组织从内容预览可看到覆盖首页、登录、订单、我的、会员、城市选择、保洁擦窗、支付、设置等典型家政业务页面方便快速定位并扩展新功能。目前已有 337 人学习下载功能经老师认可适合作为毕业设计参考或二次开发起点。1. 家政服务微信小程序.zip一套能直接跑完答辩的项目骨架拿到这个压缩包的人大多数是奔着“毕业设计 Java 微信小程序”去的。包里没有炫技的组件库也没有复杂到需要看半天架构图的微服务它就是把上门保洁、家电清洗这类家政业务做成了一个微信小程序前端加 Java 后端接口的完整闭环。解压之前先说结论目录里那些_index、_home、_order、_cleanwindow不是乱码是小程序页面文件的命名习惯用下划线前缀把页面类型和功能区分开阅读代码时会非常省力。这个项目适合三类人需要一份能演示、能答辩的毕业设计源码的学生想快速搞懂原生小程序页面组织方式的后端开发以及准备做同城生活服务类小程序、想抄作业找起点的个人开发者。后端跑在本地前端用微信开发者工具导入前后端一对接就能看到完整业务流。2. 从 _pages 目录看小程序前端组织原生四件套与页面映射2.1 目录名即功能把 zip 里的目录还原成页面清单先别急着开 IDE花五分钟把 zip 里的顶层目录列一遍整个业务模块就浮出来了。_index和_home是首页的两种入口形态_cleanwindow对应保洁服务_order是订单列表与详情_my是个人中心_login承载登录_city处理城市定位与切换_logs存放日志相关的展示或调试页。这套命名虽然不像官方模板那么规整但在毕业设计这种体量的项目里反而直观——看到目录名就能定位到功能代码。对应到微信小程序原生开发每个页面是一个目录目录内包含四个文件.js写页面逻辑、.wxml写页面结构、.wxss写样式、.json写页面配置。这也是原生小程序和 uni-app 这类跨端框架最大的区别没有经过编译层写什么就是什么调试时可以直接定位到真实运行的代码。下表是从目录结构映射出的最小功能清单也可以作为答辩时的功能列表目录对应页面核心功能_index首页入口页展示服务类目、轮播图、快捷入口_cleanwindow保洁服务详情页服务项选择、价格展示、预约入口_order订单列表与详情订单状态查看、取消、评价_city城市选择页定位当前城市、手动切换城市_login登录页微信登录授权、用户信息绑定_my个人中心用户信息、我的预约、设置_logs日志页操作记录、版本信息辅助调试2.2 原生小程序页面四件套结构与启动逻辑2.2.1 app.json 把页面串成一张路由表原生小程序所有页面的注册都集中在全局配置文件app.json里。pages数组中第一项就是小程序冷启动后进入的首页其余页面的跳转则通过wx.navigateTo或navigator组件完成。家政服务的包不大页面数量在 10 个左右用单包模式足够暂时不需要考虑分包加载。{ pages: [ pages/_index/index, pages/_login/login, pages/_cleanwindow/cleanwindow, pages/_order/order, pages/_my/my, pages/_city/city ], window: { backgroundTextStyle: light, navigationBarBackgroundColor: #fff, navigationBarTitleText: 家政服务, navigationBarTextStyle: black }, tabBar: { list: [ { pagePath: pages/_index/index, text: 首页 }, { pagePath: pages/_order/order, text: 订单 }, { pagePath: pages/_my/my, text: 我的 } ] } }pages数组的注册顺序决定路由层级tabBar里配置的是底部导航页最多五个这里放了首页、订单和个人中心三个主入口。navigationBarTitleText是顶部导航栏标题家政服务类小程序一般建议改成品牌名比如“XX家政”方便用户在小程序列表里识别。2.2.2 首页 _home 与 _index 的分工逻辑这个项目里同时存在_home和_index很多初次接触的人会困惑。常见做法是_index作为 tabBar 直连的落地页负责整体框架_home作为首页内容组件被_index引用。页面级文件夹中直接放子页面组件是原生小程序比较常见的组织方式——不需要引第三方组件库只需要在自定义组件的.json文件里声明component: true然后在页面的usingComponents字段里注册路径即可。2.3 WXML 数据绑定页面与逻辑层交互的最小模式小程序的数据流是单向的JS 层通过setData修改数据WXML 层响应式渲染。以首页服务列表为例后端接口返回一组保洁服务前端拿到后渲染成卡片列表。下面是_index.js中的核心片段。Page({ data: { serviceList: [], loading: true }, onLoad() { this.fetchServiceList(); }, fetchServiceList() { const that this; wx.request({ url: http://localhost:8080/api/service/list, method: GET, success(res) { if (res.data.code 0) { that.setData({ serviceList: res.data.data.list, loading: false }); } } }); } });对应_index.wxml里的渲染片段view classservice-list view classservice-item wx:for{{serviceList}} wx:keyid bindtapgoDetail text classname{{item.name}}/text text classprice{{item.price}}/次/text /view /viewwx:for是列表渲染指令item是默认的循环变量名wx:key绑定列表项的唯一标识这里用服务 ID 做 key 可以减少 diff 成本。bindtap绑定点击事件goDetail在 JS 层定义通过wx.navigateTo携带id参数跳转到详情页。注意wx.request的url本地调试时指向http://localhost:8080但真机预览必须改成 HTTPS 域名微信对 request 合法域名的限制在开发工具里可以临时关闭在真机上却绕不过去。3. 登录与用户体系wx.login 到 Java Token 的完整链路3.1 微信登录的规范流程先登录微信再登录业务后端家政服务小程序里的_login目录承载的是完整登录态这一步是几乎所有微信小程序的起点。用户打开小程序后前端先调用wx.login拿到一个短期有效的code这个code只能使用一次有效期五分钟然后由后端拿code去微信的jscode2session接口换取openid和session_key。核心逻辑是小程序端不能直接调用微信接口换取 openid必须由后端转发避免把appsecret暴露在小程序包里。// pages/_login/login.js handleLogin() { wx.login({ success: (res) { if (res.code) { wx.request({ url: http://localhost:8080/api/auth/wxlogin, method: POST, data: { code: res.code }, success: (resp) { if (resp.data.code 0) { const { token, userInfo } resp.data.data; wx.setStorageSync(token, token); wx.setStorageSync(userInfo, userInfo); wx.switchTab({ url: /pages/_index/index }); } } }); } } }); }wx.login的返回值code是临时登录凭证业务后端拿到code后才能向微信换openid。这里用wx.setStorageSync把token和用户信息缓存到本地后续所有需要登录态的请求都从 storage 读取。wx.switchTab是跳转到 tabBar 页面的专用方法跳转普通页面应该用wx.navigateTo两者不能混用。3.2 Java 后端code 换 openid 与 Token 签发后端接口是典型的 Spring Boot 结构。核心逻辑分三步接收code调用微信接口换取openid然后根据openid查表——用户不存在就注册存在就签发新的token返回给前端。下面是一个简化但可运行的 Controller 代码。RestController RequestMapping(/api/auth) public class AuthController { Autowired private UserService userService; PostMapping(/wxlogin) public Result wxLogin(RequestBody LoginRequest req) { // 1. 用 code 向微信换取 openid String url https://api.weixin.qq.com/sns/jscode2session ?appid appid secret secret js_code req.getCode() grant_typeauthorization_code; String resp restTemplate.getForObject(url, String.class); JSONObject json JSONObject.parseObject(resp); String openid json.getString(openid); if (openid null) { return Result.error(code 已失效); } // 2. 根据 openid 查用户不存在则注册 User user userService.findByOpenid(openid); if (user null) { user new User(); user.setOpenid(openid); user.setNickname(微信用户); user.setAvatarUrl(https://xxx/default-avatar.png); userService.register(user); } // 3. 签发 token 并返回 String token UUID.randomUUID().toString().replace(-, ); userService.saveToken(token, user.getId()); return Result.ok().data(token, token).data(userInfo, user); } }js_code对应前端的code参数grant_type固定为authorization_code。openid是每个微信用户在当前小程序下的唯一标识同一用户在不同小程序下openid不同做跨小程序账号打通才需要用到unionid。token用 UUID 生成简单可靠毕业设计级别不需要引入 JWT把它存到 Redis 并设置过期时间或者直接存数据库都行。3.3 登录态的保持与常见坑点3.3.1 请求头携带 token 的封装方式登录成功后前端拿到了token后续每个接口的请求都要带上它。推荐统一封装一个request.js把token注入 header这样页面里不需要重复写鉴权逻辑。下面是简化版封装。const request (url, method, data) { const token wx.getStorageSync(token); return new Promise((resolve, reject) { wx.request({ url, method, data, header: { Authorization: token || }, success: (res) { if (res.data.code 401) { // token 过期重新走登录逻辑 wx.navigateTo({ url: /pages/_login/login }); reject(res); } else { resolve(res.data); } }, fail: reject }); }); };后端对需要鉴权的接口用一个拦截器读取Authorization头解析 token 后把用户 ID 写入ThreadLocal供后续业务逻辑获取。token 过期时间建议 2 到 7 天家政服务的用户登录频率不会太高太短会导致用户频繁重登太长有安全隐患。很多毕业设计项目在这里偷懒直接把openid当作 token 用这相当于把身份标识明文暴露在请求里答辩时如果被问到安全性会很难圆回来。3.3.2 获取用户昵称和头像的现状老版本小程序可以直接用wx.getUserInfo弹窗拿头像昵称2022 年后微信改为头像昵称填写能力wx.getUserProfile也不再有弹窗授权默认返回灰色头像和“微信用户”昵称。家政项目在_login和_my里要做的是首次登录用openid建立账号然后在个人中心引导用户主动填写昵称、上传头像拿到wx.chooseMedia选择的图片后调用后端上传接口存 OSS。答辩时主动解释这个限制会让评审觉得你对微信生态的更新有跟进。4. 保洁预约与订单状态机把业务需求写成可维护的代码4.1 订单状态流转从“待接单”到“已完成”家政服务小程序的业务核心是_cleanwindow页面的预约入口和_order页面的订单管理。订单不只是 CRUD它需要一套清晰的状态机。下面是我在这个项目里常用的状态枚举定义直接用整型存库可读性靠常量类保证。状态值状态名含义可能的后续动作0待接单用户提交预约平台尚未处理接单、取消1进行中保洁员已接单/已上门完成、用户取消2已完成服务结束评价、复购3已取消用户主动取消或超时未接单无4待支付部分场景先下单后付款支付、关闭状态流转的规则是只允许从当前状态跳到下表中允许的状态禁止跳级禁止逆向。比如“已完成”不能改回“进行中”“待接单”可以直接“已取消”但“进行中”取消需要区分是用户取消还是平台取消。把这些规则写成代码里的校验逻辑而不是全靠前端判断是后端设计是否成熟的直接体现。4.2 预约下单接口的参数设计与校验以下单接口为例前端从_cleanwindow页面携带服务 ID、城市、预约时间、地址等信息提交到后端。参数校验放在 Controller 层完成业务规则放在 Service 层检查。PostMapping(/api/order/create) public Result createOrder(RequestBody OrderCreateReq req) { // 参数校验 if (req.getServiceId() null) { return Result.error(服务项不能为空); } if (StringUtils.isBlank(req.getAddress())) { return Result.error(服务地址不能为空); } if (req.getServiceTime() null || req.getServiceTime().isBefore(LocalDateTime.now())) { return Result.error(预约时间必须晚于当前时间); } Order order new Order(); order.setUserId(LoginContext.getUserId()); order.setServiceId(req.getServiceId()); order.setCityId(req.getCityId()); order.setAddress(req.getAddress()); order.setServiceTime(req.getServiceTime()); order.setStatus(0); // 初始状态待接单 order.setOrderNo(OrderNoGenerator.generate()); orderService.create(order); return Result.ok().data(orderId, order.getId()); }下单的校验分两层。第一层是基础参数校验比如地址为空、服务项为空、预约时间在过去这些直接返回错误码不必进入业务逻辑。第二层是业务规则校验比如同一个用户在同一时间段是否已经存在未完成的订单这个在 Service 层通过查询数据库判断。OrderNoGenerator.generate()这里建议用日期时间加随机数的方式生成订单号例如2025011016350001方便后续对账不要直接用数据库自增 ID 裸奔给前端。4.3 城市定位、服务列表与查询优化4.3.1 城市定位的两种实现思路_city目录解决的是“用户从哪个城市来”的问题。第一种实现是前端定位调用wx.getLocation拿到经纬度再通过腾讯地图 WebService API 逆地址解析成城市名。这种方式体验好但需要在小程序后台申请地理位置接口权限并且个人主体的小程序在2022年后对wx.getLocation的审核非常严格。第二种是退而求其次的做法进入_city页面弹窗让用户手动选择常见城市再把这个城市 ID 存入wx.setStorageSync后续所有接口请求都带上cityId。家政服务场景下二线城市以下用户对城市列表选择接受度很高很多成品项目都采用后者省去地图 SDK 的接入成本。4.3.2 服务列表查询与索引设计首页服务列表和订单列表的后端查询在真实数据量下要注意索引设计。服务表t_service里city_id和status是最常见的过滤条件这组查询应该建立联合索引(city_id, status)。-- 服务列表按城市与上架状态查询 SELECT id, name, price, icon_url, sales_count FROM t_service WHERE city_id #{cityId} AND status 1 ORDER BY sales_count DESC LIMIT 20;ORDER BY sales_count DESC用于按销量排序这个字段如果后续数据量大可以考虑把sales_count也并入联合索引。订单表的查询按user_id和status过滤索引设计成(user_id, status, create_time)原因是订单列表页需要按用户拉取数据并按时间倒序展示三个字段同时命中索引可以避免回表。很多项目的接口在数据量小的时候毫无问题上线半年后变慢根子就是这些索引没提前设计。5. 上线前检查与调试技巧把下载的 zip 变成可发布的版本5.1 导入开发者工具的完整步骤与域名配置拿到 zip 后先本地解压注意微信开发者工具直接导入的是解压后的前端目录不是 zip 文件本身。导入时需要选择项目根目录如果项目里包含project.config.json工具会自动识别 appid如果没有需要手动填一个测试号或个人主体 appid。本地调试阶段在开发者工具的“详情 - 本地设置”里勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”这样才能用http://localhost:8080访问后端接口。真机预览时这个勾选不生效必须在小程序管理后台的“开发 - 开发管理 - 服务器域名”里配置 request 合法域名而且必须是 HTTPS 并经过 ICP 备案。5.2 启动加载页与顶部导航栏的适配小程序冷启动时用户看到的第一个页面是app.json的pages数组中第一项。如果你希望先展示品牌加载页可以把加载页放到数组第一位在onLoad里等待 1 到 2 秒后通过wx.reLaunch跳转到首页。顶部导航栏高度在不同机型上不一致需要靠胶囊按钮位置动态计算这是“微信小程序顶部导航栏高度”搜索热度居高不下的原因。常见做法是封装一个工具函数。// utils/navbar.js function getNavBarInfo() { const menu wx.getMenuButtonBoundingClientRect(); const system wx.getSystemInfoSync(); const statusBarHeight system.statusBarHeight; const navBarHeight (menu.top - statusBarHeight) * 2 menu.height; return { statusBarHeight, navBarHeight, menu }; }wx.getMenuButtonBoundingClientRect()返回右上角胶囊按钮的坐标与尺寸通过胶囊顶部与状态栏底部的差值乘 2 加上胶囊高度就能得到一个在所有机型上都对齐的导航栏高度。表情符号不适合出现在生产环境这个代码片段注意复制时把注释里的描述词改成正常文字。5.3 素材的存放策略为什么不该依赖 zip 内部资源家政服务场景的图片资源通常比较大保洁项目样图、服务详情页 banner、用户头像。一个常见误会是小程序可以直接从资源包里读取_images目录下的图片实际上小程序代码包上传后是编译产物图片要么放进项目根目录被打进代码包要么上传到 CDN 或云存储后用 URL 引用运行时无法动态解压 zip。解决方案分两步项目开发阶段图片放在_images目录下随包发布注意单个分包不超过 2MB、整个包不超过 20MB 的限制图片总量超过阈值后把服务项图片切换到 OSS 或腾讯云 COS 存储数据库t_service表中的icon_url字段直接存完整 URL后台上传接口用MultipartFile接收文件后返回 URL。调试时在开发者工具的 Network 面板观察哪些请求耗时最长优先压缩首屏接口和首屏图片比盲目优化后端代码更有效。本文还有配套的精品资源点击获取
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻