ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

SpringBoot+微信小程序家政服务与互助平台毕设源码跑通与二次开发指南

SpringBoot+微信小程序家政服务与互助平台毕设源码跑通与二次开发指南

简介:这份资源是面向高校计算机相关专业毕业设计的完整项目包,围绕微信小程序家政服务与互助平台展开,适合需要完成毕设、课程设计或想学习小程序全栈开发的学生与开发者。压缩包共883个文件,约40.81MB,以Java源码、SVG与PNG图片、JS脚本、WXSS与WXML小程序页面、Vue组件、JSON配置及SQL脚本为主,另附PPT演示文稿与MP4演示视频,覆盖后端接口、前端页面、数据库与答辩材料。项目后端采用Spring Boot框架与Java语言开发,结合MySQL实现数据管理,前端融合HTML、CSS、JavaScript与Vue.js构建交互界面,功能涵盖家政服务浏览预约、订单提醒、服务记录追踪、评价分享、家政员个人中心管理以及帖子互助社区等模块。已有64人学习下载,读者可据此获得一套可直接运行参考的完整源码、数据库脚本与演示视频,便于快速理解项目结构、梳理功能实现思路并用于答辩展示。

1. 家政服务与互助平台:从一份毕设源码里拆出能跑通的落地路径

每年毕业季,总有一批同学拿着「基于 SpringBoot 后端 + 微信小程序的家政服务与互助平台」这类题目来找我,问的无非是同一件事:这套东西到底能不能跑起来、能不能改成自己的、答辩时会不会被老师问穿。我见过太多人把源码包解压完就卡在第一步——后端启动报错、小程序连不上接口、数据库表对不上号。这个标题背后其实是一套非常典型的「SpringBoot 做服务端 + 微信小程序做用户端」的双端架构,核心业务是家政服务的下单、接单、评价,外加一个互助模块让用户之间互相帮忙。它适合两类人:一是拿它当毕设底稿、需要快速跑通并做二次开发的学生;二是想用一套完整案例练手 SpringBoot 接口设计和微信小程序页面联调的开发者。接下来我不讲空话,直接按「环境怎么搭、接口怎么写、小程序怎么连、坑在哪」的顺序,把这套东西拆到你能照着复现的程度。

2. 环境搭建与项目结构:把 SpringBoot 后端和微信小程序前端同时跑起来

2.1 后端技术选型与依赖版本确认

拿到源码第一步不是急着点运行,而是先看pom.xml里的 SpringBoot 版本。热搜词里「springboot版本太高」是真实高频问题——很多毕设源码写的时候用的是 2.7.x,你本地 IDEA 默认拉 3.x,一启动就报jakarta.servlet找不到或者javax.annotation被移除。我一般会先把版本锁死,再动其他配置。

<!-- pom.xml 关键依赖,版本按源码实际调整 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.18</version> <!-- 不要盲目升到3.x,javax→jakarta迁移会炸 --> <relativePath/> </parent> <dependencies> <!-- Web 层,提供 REST 接口给小程序调用 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- MyBatis-Plus,家政订单、用户、服务类目表的 CRUD 全靠它 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <!-- MySQL 驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> <!-- JWT,小程序登录后签发 token 用 --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> </dependencies>

这段依赖里最容易被忽略的是 MyBatis-Plus 和 SpringBoot 的版本匹配。3.5.3.1 配 2.7.x 是稳的,如果你把 SpringBoot 升到 3.2,MyBatis-Plus 得换 3.5.5 以上,否则启动时SqlSessionFactory注入失败。JWT 用 0.9.1 是因为它依赖javax.xml.bind,在 JDK 11 以上需要额外加jaxb-api,否则签 token 时抛NoClassDefFoundError。我一般会在pom.xml里补上:

<dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.1</version> </dependency>

参数上,spring-boot-starter-parent的版本决定了整个项目的基线,不要为了「用新特性」去动它。数据库连接池默认 HikariCP,连接数在application.yml里配maximum-pool-size: 10就够毕设场景用,调大了反而在低配机器上启动慢。

2.2 数据库建表与初始数据导入

源码包里一般会带一个.sql文件,但很多人导入时只导了结构没导数据,结果小程序首页服务列表是空的,还以为接口写错了。我习惯先确认三张核心表:user(用户,含微信 openid)、service_item(家政服务类目,比如保洁、月嫂、维修)、order(订单,含状态字段)。互助模块通常再加一张help_request表。

-- 建库,字符集必须 utf8mb4,否则微信昵称里的 emoji 存进去变问号 CREATE DATABASE housekeeping DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; -- 服务类目表,小程序首页列表就查这张 CREATE TABLE service_item ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(64) NOT NULL COMMENT '服务名称,如日常保洁', price DECIMAL(10,2) NOT NULL COMMENT '单价', cover_img VARCHAR(255) COMMENT '封面图URL', status TINYINT DEFAULT 1 COMMENT '1上架 0下架' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 订单表,状态机是答辩必问点 CREATE TABLE `order` ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, service_id BIGINT NOT NULL, status TINYINT DEFAULT 0 COMMENT '0待接单 1已接单 2已完成 3已取消', create_time DATETIME DEFAULT CURRENT_TIMESTAMP, remark VARCHAR(255) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

导入顺序是先建库、再建表、最后插初始数据。初始数据至少给service_item插 5 条,否则小程序首页wx:for渲染出来是空白,你会误以为请求没发出去。order表的status字段用数字而不是字符串,是为了后面做状态流转判断时少写if,直接比大小。注意order是 MySQL 关键字,建表时必须加反引号,查询时也要加,否则报语法错误。

2.3 微信小程序端项目导入与域名配置

小程序端用微信开发者工具打开,导入时选源码包里的miniprogram目录。导入后第一件事是改app.js里的baseUrl,指向你本地后端地址。这里有个高频翻车点:微信开发者工具默认校验合法域名,你填http://localhost:8080会报「不在以下 request 合法域名列表中」。

// app.js App({ globalData: { // 本地调试用局域网IP,不要用 localhost,真机预览连不上 baseUrl: 'http://192.168.1.100:8080', userInfo: null, token: '' }, onLaunch() { // 启动时检查本地是否有 token,有就跳过登录 const token = wx.getStorageSync('token') if (token) { this.globalData.token = token } } })

baseUrl必须写你电脑的局域网 IP,因为手机预览时localhost指向手机自己。获取 IP 用ipconfig(Windows)或ifconfig(Mac)。然后在开发者工具右上角「详情」→「本地设置」里勾上「不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书」,这一步是本地调试的后悔药,不勾后面所有请求都发不出去。正式上线才需要备案域名和 HTTPS,毕设阶段不用管。

3. 核心接口开发:家政下单、接单与互助模块的 SpringBoot 实现

3.1 微信登录换 openid 与 JWT 签发

小程序端wx.login()拿到 code,传给后端换 openid,这是整个用户体系的入口。很多源码在这里写死了 appid 和 secret,你直接跑会报invalid appid,得去微信公众平台申请自己的测试号或者用源码作者留的。

@RestController @RequestMapping("/api/auth") public class AuthController { @Value("${wx.appid}") private String appid; @Value("${wx.secret}") private String secret; @Autowired private UserService userService; @PostMapping("/login") public Result login(@RequestBody LoginDTO dto) { // 1. 用 code 换 openid,这里用 RestTemplate 调微信接口 String url = "https://api.weixin.qq.com/sns/jscode2session" + "?appid=" + appid + "&secret=" + secret + "&js_code=" + dto.getCode() + "&grant_type=authorization_code"; ResponseEntity<String> resp = new RestTemplate().getForEntity(url, String.class); JSONObject json = JSON.parseObject(resp.getBody()); String openid = json.getString("openid"); if (openid == null) { return Result.fail("微信登录失败:" + json.getString("errmsg")); } // 2. 查库,没有就注册 User user = userService.getByOpenid(openid); if (user == null) { user = new User(); user.setOpenid(openid); user.setNickname(dto.getNickname()); userService.save(user); } // 3. 签发 JWT,过期时间 7 天 String token = JwtUtil.sign(user.getId(), 7 * 24 * 3600); return Result.ok(token); } }

appid和secret放在application.yml里,不要硬编码进 Java 文件,否则你提交代码时泄露了还得去重置。jscode2session接口返回的openid是用户唯一标识,session_key不要存数据库,它只是解密用的临时密钥。JWT 的过期时间设 7 天是因为毕设演示周期短,设太长有安全风险,设太短你每次调试都要重新登录。JwtUtil.sign里 payload 只放 userId,不要放昵称头像,那些从数据库查。

3.2 家政服务列表分页与小程序加载更多

热搜词里「微信小程序页面列表加载更多」是高频需求,家政服务列表、订单列表都要用。后端用 MyBatis-Plus 的分页插件,前端用onReachBottom触底加载。

@GetMapping("/list") public Result list(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size) { // MyBatis-Plus 分页,Page 对象直接传给 mapper Page<ServiceItem> p = new Page<>(page, size); LambdaQueryWrapper<ServiceItem> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(ServiceItem::getStatus, 1) // 只查上架的 .orderByDesc(ServiceItem::getId); serviceItemMapper.selectPage(p, wrapper); return Result.ok(p.getRecords(), p.getTotal()); }
// 小程序端 pages/service/list.js Page({ data: { list: [], page: 1, hasMore: true }, onLoad() { this.loadData() }, loadData() { if (!this.data.hasMore) return wx.request({ url: getApp().globalData.baseUrl + '/api/service/list', data: { page: this.data.page, size: 10 }, success: (res) => { const records = res.data.data this.setData({ list: this.data.list.concat(records), page: this.data.page + 1, // 返回条数小于 size 说明到底了 hasMore: records.length === 10 }) } }) }, onReachBottom() { this.loadData() } })

后端Page对象的page从 1 开始,不是 0,传 0 会返回空列表。前端hasMore判断用records.length === 10,如果后端返回的 total 和 records 不一致,以 records 长度为准。onReachBottom在页面滚动到底部 50px 内触发,如果列表没撑满一屏它不会触发,所以首次加载后要判断list.length < 10就直接设hasMore: false。

3.3 订单状态流转与互助请求的接单逻辑

订单状态机是答辩老师最爱问的:待接单→已接单→已完成,中间不能跳。互助模块的help_request类似,但多一个「求助者确认完成」的环节。

@Transactional @PostMapping("/accept/{orderId}") public Result accept(@PathVariable Long orderId, @RequestAttribute Long userId) { Order order = orderMapper.selectById(orderId); // 状态必须是 0 待接单,否则不允许接 if (order == null || order.getStatus() != 0) { return Result.fail("订单状态不允许接单"); } // 不能接自己发的单 if (order.getUserId().equals(userId)) { return Result.fail("不能接自己的订单"); } order.setStatus(1); order.setAcceptUserId(userId); orderMapper.updateById(order); return Result.ok(); }

@Transactional必须加,因为接单可能涉及扣减接单人的接单次数或者更新用户积分,两步操作要么都成功要么都回滚。@RequestAttribute Long userId是从拦截器里取的,拦截器解析 JWT 后把 userId 塞进 request,这样每个接口不用重复解析 token。状态判断用!= 0而不是== 1,因为未来可能加「已取消」状态,用不等于待接单更稳。

4. 联调与部署:把本地跑通的项目放到服务器上演示

4.1 前后端联调的三个必查项

本地联调时接口 404、跨域、token 失效是三大拦路虎。404 先看@RequestMapping路径和前端url拼出来的是否一致,注意baseUrl结尾不要带/,接口路径开头要带/。跨域在 SpringBoot 里加配置类:

@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") // 用 patterns 不用 origins,否则带 cookie 时报错 .allowedMethods("GET", "POST", "PUT", "DELETE") .allowCredentials(true) .maxAge(3600); } }

allowedOriginPatterns是 SpringBoot 2.4 以后的新写法,用allowedOrigins("*")配合allowCredentials(true)会抛异常。token 失效先看请求头有没有带Authorization,小程序端要在wx.request的header里手动加,不会自动带。

4.2 打包部署到服务器的最小步骤

毕设演示一般用云服务器,把 SpringBoot 打成 jar 包,用nohup后台跑。

# 1. 本地打包,跳过测试,否则测试用例连不上数据库会失败 mvn clean package -DskipTests # 2. 上传 jar 到服务器 scp target/housekeeping-0.0.1-SNAPSHOT.jar root@你的服务器IP:/opt/app/ # 3. 服务器上后台启动,日志输出到 nohup.out nohup java -jar /opt/app/housekeeping-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod > /opt/app/nohup.out 2>&1 & # 4. 看日志确认启动成功 tail -f /opt/app/nohup.out

-DskipTests必须加,因为很多毕设源码的测试类写死了本地数据库连接,服务器上跑测试会卡住。--spring.profiles.active=prod指定生产配置,application-prod.yml里数据库地址改成服务器内网地址。nohup后面的2>&1把错误流也重定向到日志,不然报错你看不到。小程序端baseUrl改成服务器公网 IP 加端口,微信开发者工具里勾选「不校验合法域名」依然有效。

5. 避坑与排查:这套源码跑不起来时先看这五条

5.1 启动报Table 'xxx' doesn't exist

现象:SpringBoot 启动成功但一调接口就报 SQL 异常,提示表不存在。原因:数据库连上了但没建表,或者建表语句里的库名和application.yml里配的不一致。解决:先确认application.yml的url里库名,再进 MySQL 执行use 库名; show tables;,没有就重新导.sql。注意.sql文件里如果有CREATE DATABASE语句,导入时可能建了新库,你连的还是旧库。

5.2 小程序请求返回request:fail url not in domain list

现象:开发者工具里请求发不出去,控制台报域名不合法。原因:没勾选「不校验合法域名」。解决:详情→本地设置→勾选不校验。如果勾了还报,检查baseUrl是不是https开头但服务器没配证书,本地调试统一用http。

5.3 登录后其他接口返回 401

现象:登录接口正常返回 token,但调订单接口提示未授权。原因:前端没把 token 放进请求头,或者后端拦截器路径配错了。解决:在小程序wx.request的header里加Authorization: 'Bearer ' + token,后端拦截器excludePathPatterns里要放行/api/auth/**,否则登录接口本身也被拦。

5.4 订单列表分页第二页数据重复

现象:上拉加载后列表出现重复项。原因:后端分页page从 0 开始传了,或者前端page没自增。解决:确认后端new Page<>(page, size)的page从 1 开始,前端每次加载后page + 1,并且用concat而不是直接赋值。

5.5 打包后 jar 启动报no main manifest attribute

现象:java -jar提示没有主清单属性。原因:pom.xml里没配spring-boot-maven-plugin。解决:在build节点加插件配置,重新mvn package。注意插件版本要和 SpringBoot 版本一致,2.7.x 用 2.7.18。

6. 从能跑到能答辩:三个让老师眼前一亮的改造技巧

第一,把订单状态流转做成可视化。小程序端用wx:if根据status渲染不同按钮,后端加一个/api/order/timeline/{id}接口返回状态变更记录,答辩时演示「待接单→已接单→已完成」的完整链路,比干讲代码有说服力。第二,互助模块加一个简单的信用分机制,用户完成一次互助加 1 分,接单时优先展示高分用户,这个改动只涉及user表加一个credit字段和查询时orderByDesc,但能体现你对业务的理解。第三,把application.yml里的敏感配置抽到环境变量,演示时用--wx.appid=xxx启动,说明你知道生产环境不能把密钥写死在代码里。

// 信用分加分的实现,放在订单完成接口里 @Transactional @PostMapping("/finish/{orderId}") public Result finish(@PathVariable Long orderId) { Order order = orderMapper.selectById(orderId); if (order.getStatus() != 1) return Result.fail("状态不对"); order.setStatus(2); orderMapper.updateById(order); // 接单人信用分 +1 User acceptUser = userMapper.selectById(order.getAcceptUserId()); acceptUser.setCredit(acceptUser.getCredit() + 1); userMapper.updateById(acceptUser); return Result.ok(); }

我自己的习惯是,每次改完一个模块就用 Postman 把相关接口全跑一遍,确认返回结构和前端预期一致再动下一块。毕设最怕的就是改到后面忘了前面,最后联调时一堆接口对不上。这套源码的价值不在于它多完美,而在于它给了你一个能跑通的骨架,你往里面填自己的业务逻辑就行。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表