
简介面向家政服务行业信息化管理场景这是一套基于Java与SSM框架Spring、SpringMVC、MyBatis开发后端、MySQL数据库存储、微信小程序作为前端入口的家政服务系统毕业设计项目涵盖预约、订单、服务展示等核心业务适合计算机专业学生作为毕业设计、课程设计或期末大作业直接参考。资源包共1213个文件压缩后约16.41MB内部以Java源码119个、Vue组件134个、JavaScript脚本175个、微信小程序wxml/wxss/json页面文件及图片素材为主同时包含2个SQL数据库脚本、论文Word文档和批量运行/安装bat脚本前后端代码与配套论文一应俱全。已有85人学习下载。项目是经导师指导并通过的高分毕业设计经过严格调试下载导入即可稳定运行结合Maven、MySQL及Navicat可完成从数据库初始化到系统部署的全流程界面简洁、功能完善能帮助读者直观理解家政管理系统的架构与业务逻辑有效缩短开发周期。1. 一套能直接拿去答辩的家政小程序到底值不值得你打开如果你正在找毕业设计选题看到“基于javassmmysql微信小程序的家政项目小程序 源码数据库论文”这类包第一反应应该是这套东西拿过来能不能跑通、能不能讲清楚、老师追问会不会露馅。答案是能但前提是你别只把它当成一个“点击就送”的压缩包。它的核心价值在于技术栈完整且传统小程序做用户端交互SSM 做接口和业务MySQL 负责落库论文可以照三层架构画图。适合计算机相关专业本科毕设、以及想快速搭一套前后端闭环作品去面试的开发者。家政业务的难度适中订单状态流转、服务人员调度、评价闭环这些点既好实现又有足够的答辩话术可讲。2. SSM 微信小程序的家政项目先拆技术栈再定数据库2.1 为什么是 SSM 而不是 Spring Boot传统三件套的答辩优势“SSM”是 Spring SpringMVC MyBatis 的缩写。Spring 管对象生命周期和事务SpringMVC 负责把小程序发来的 HTTP 请求路由到 Java 方法并把返回值序列化成 JSONMyBatis 专注 SQL 与 Java 对象的映射。一句话描述分工就是小程序要数据SpringMVC 接单Spring 派活MyBatis 跑腿去 MySQL 取数。很多人在选型时会纠结都 2024 年了为什么不直接上 Spring Boot我的看法是毕业设计场景里 SSM 反而更稳。原因有二一是网上论文模板和参考资料极多答辩 PPT 里画分层架构图、写“基于 IOC 的解耦设计”这类描述非常顺手二是 java 面试题里关于 SSM 的提问频率一直没降你亲手配过 applicationContext.xml、理解过一个 Transactional 怎么拦截面试被问到“Spring 的 Bean 生命周期”时不至于空泛。Spring Boot 是省事但它把太多细节包成了黑匣子毕业论文的“系统设计”章节反而难写。2.2 家政业务的数据库设计六张表撑起完整闭环家政小程序的核心业务是用户浏览服务类型保洁、月嫂、家电清洗选择一个家政人员提交预约订单家政人员接单后上门服务完成后用户评价。围绕这条链路我一般建议至少设计六张表表名作用核心字段user小程序用户id, openid, nickname, phone, avatarworker家政服务人员id, name, sex, service_type_id, work_status, scoreservice_type服务类型id, name, price, price_unit, detailorders预约订单id, order_no, user_id, worker_id, service_date, address, status, pay_amountcomment服务评价id, order_id, user_id, score, content, create_timeadmin后台管理员id, username, password订单表是整个库的核心。status 字段我在项目里习惯用 tinyint 表示状态机0 待接单、1 已接单、2 服务中、3 已完成、4 已取消。用状态机而不是拆成多张订单状态表是为了减少联表查询和事务复杂度——这也是论文里可以写的一个亮点“基于状态机的订单流转设计保证了订单生命周期的一致性与可追溯性。”注意 user 表里的 openid 字段要加唯一索引。因为微信登录是通过 wx.login 拿 code 换 openid同一个用户反复登录时如果没做唯一约束很容易插入重复账号。这个坑在联调阶段才会暴露后面第 5 章我会单独讲。2.3 后端工程结构与 MyBatis 配置的关键参数源码包的典型结构是标准的 Maven Web 项目controller 包放接收请求的类service 包放业务逻辑mapper 包放 MyBatis 的接口resources 下放着 applicationContext.xml、spring-mvc.xml、mybatis-config.xml 和 db.properties。拿到项目先别急着跑打开 db.properties 看一眼数据库连接这是第一个要动的地方jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/housekeeping?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai jdbc.usernameroot jdbc.password123456url 里必须带useUnicodetruecharacterEncodingutf8否则小程序端传入的中文地址会乱码serverTimezoneAsia/Shanghai是给 MySQL 8.0 用的5.7 不加也能跑加上更保险。password 改成你自己的数据库密码。用 MySQL 5.7 还是 8.0驱动类名不同我在第 3 章会说清楚。MyBatis 的全局配置里有一个容易被忽略但直接影响结果的开关settings setting namemapUnderscoreToCamelCase valuetrue/ /settings这个配置开启后数据库的user_name会自动映射到 Java 属性的userName不用为每个实体写一遍 resultMap。如果不开你会发现所有的 user 相关字段查出来都是 null日志里又没有任何报错——这种问题排查起来最耗时。3. 用本地环境跑通项目从数据库导入到小程序出数据3.1 版本对照JDK、Maven、Tomcat、MySQL 怎么配才不打架这套项目最稳妥的环境组合我用下表说明。版本号不必完全一致但大版本别跳组件推荐版本说明JDK1.8不建议用 11部分 SSM 旧工程在 JDK 11 下会报模块访问错误Maven3.6.x3.8 以上也能用但镜像源有时不稳定Tomcat8.5支持 Servlet 3.1SSM 项目的 web.xml 一般按 2.5 或 3.0 写MySQL5.7 或 8.05.7 驱动是 com.mysql.jdbc.Driver8.0 是 com.mysql.cj.jdbc.Driver微信开发者工具稳定版即可调试时基础库选 2.30 以上我第一次带人做这个选题的时候在 MySQL 8.0 上翻过车驱动类名没改启动 Tomcat 时数据源初始化直接抛ClassNotFoundException。如果你的压缩包里 db.properties 写的是com.mysql.jdbc.Driver而你本机装的是 MySQL 8.0记得改成com.mysql.cj.jdbc.Driver。mysql 安装教程里的默认端口、账号密码设置在这里直接影响项目能否启动。3.2 导入数据库脚本和初始化数据压缩包里通常带一个 .sql 文件可能是 housekeeping.sql 或 db_housekeeping.sql。用命令行导入最快# 登录 MySQL 后创建数据库 mysql -u root -p CREATE DATABASE IF NOT EXISTS housekeeping DEFAULT CHARSET utf8mb4; USE housekeeping; SOURCE /path/to/housekeeping.sql;导入完成后用SHOW TABLES;验证六张表是否齐了。如果表名带前缀比如t_user、t_order说明作者有多表前缀习惯后端 Mapper 里的表名也得对应这一步先确认好不然后面启动能过但查询全报“Table doesnt exist”。注意项目里的订单表叫orders而不是order因为 order 是 MySQL 的保留字直接建表会报语法错误。3.3 后端打包部署与接口自测导入成功后打开 IDEA 或 Eclipse用 Maven 方式导入工程等依赖下载完执行打包mvn clean package -DskipTests打包产物是 war 文件出现在 target 目录下。把 war 复制到 Tomcat 的 webapps 目录然后启动# Linux / Mac ./bin/startup.sh # Windows bin\startup.bat启动后先看日志tail -f logs/catalina.out确认没有BeanCreationException或数据库连接异常。然后用浏览器访问后端接口验证curl http://localhost:8080/housekeeping/api/service/list这个接口应该返回 JSON 数组内容是家政服务类型列表。如果返回 404看 war 包解压后的目录名——Tomcat 的访问路径默认是 war 包文件名比如 housekeeping.war 对应/housekeeping。如果接口路径带/api前缀但答不上来去 spring-mvc.xml 里看context:component-scan和mvc:annotation-driven有没有配置。3.4 微信开发者工具导入小程序端并改 baseUrl小程序端一般是独立的目录里面是pages/、utils/、app.js、app.json这样的结构。在微信开发者工具里选择“导入项目”把目录指过去AppID 用测试号即可。最关键的一步是找到 request 封装文件通常是utils/request.js或config.js把 baseUrl 从作者的服务器地址改成你自己的// utils/request.js const BASE_URL http://localhost:8080/housekeeping; function request(url, method, data) { return new Promise((resolve, reject) { wx.request({ url: BASE_URL url, method: method || GET, data: data || {}, header: { Content-Type: application/json }, success: resolve, fail: reject }); }); }为什么推荐写 Promise 封装因为页面里要用 async/await 串起“登录→拉数据”的逻辑回调地狱在业务稍微复杂后就很难读。模拟器里 localhost 能通真机预览必须改成电脑的局域网 IP比如http://192.168.31.80:8080/housekeeping。微信开发者工具里如果提示“不在以下合法域名列表中”点“详情→本地设置→勾选不校验合法域名”。4. 从下单到入库走查一条核心业务链路的完整实现4.1 接口清单先明确小程序端要调哪些后端方法家政项目微信小程序端的页面不外乎首页服务列表、服务详情、下单页、订单列表、个人中心、评价页。这些页面对应的后端接口我按模块列在下面接口方法请求参数返回/api/user/loginPOSTcodetoken 用户信息/api/service/listGET无服务类型列表/api/worker/listGETserviceTypeId该类型下的家政人员/api/order/createPOSTuserId, workerId, serviceDate, address订单 id/api/order/listGETuserId, page, size分页订单列表/api/comment/addPOSTorderId, score, content评价 id这套接口设计的思路是用户登录后拿到 token后续所有请求在 header 里带上 token后端用一个拦截器校验。很多高分毕业设计会在论文里写这一点因为它涉及了“会话保持”和“权限控制”两个常见考点。不过如果你的源码里没有 token 机制只有简单的 openid 查询也不用急着加——答辩时口头说清楚即可改动小一点风险更小。4.2 用户登录用 wx.login 的 code 换 openid微信小程序登录流程是固定的前端调wx.login()拿到临时 code然后把 code 传给后端后端用 code 调微信的jscode2session接口拿到 openid 和 session_key。openid 是用户在小程序里的唯一身份标识。Controller 里对应的写法Controller RequestMapping(/api/user) public class UserController { Autowired private UserService userService; ResponseBody PostMapping(/login) public Result login(RequestBody MapString, String params) { String code params.get(code); if (StringUtils.isBlank(code)) { return Result.error(code不能为空); } String openid userService.exchangeOpenid(code); User user userService.findOrCreateByOpenid(openid); user.setToken(UUID.randomUUID().toString().replaceAll(-, )); return Result.success(user); } }RequestBody接收前端传过来的 JSON 体ResponseBody把返回值序列化成 JSON 响应给小程序。precise 说PostMapping是 Spring 4.3 以后的简写等价于RequestMapping(value/login, methodRequestMethod.POST)。SSM 常用注解里这两个是最高频的答辩时如果老师问“SpringMVC 怎么处理 HTTP 请求”就把这两个注解 DispatcherServlet 的执行流程说一遍基本就过关了。4.3 下单服务为什么必须加事务下单是整个项目里业务逻辑最密集的环节。用户选了家政人员和上门时间后后端要做的操作有两步写入一条订单记录把该家政人员的状态改成“已预约”。这两步必须保证同时成功或同时失败。我在 Service 里的写法如下Transactional(rollbackFor Exception.class) public Long createOrder(OrderDTO dto) { // 1. 校验家政人员是否存在且空闲 Worker worker workerMapper.selectById(dto.getWorkerId()); if (worker null || worker.getWorkStatus() 1) { throw new BizException(该家政人员已被预约); } // 2. 创建订单初始状态为待接单 Order order new Order(); order.setOrderNo(HK System.currentTimeMillis()); order.setUserId(dto.getUserId()); order.setWorkerId(worker.getId()); order.setServiceDate(dto.getServiceDate()); order.setAddress(dto.getAddress()); order.setStatus(0); order.setPayAmount(worker.getPrice()); order.setCreateTime(new Date()); orderMapper.insert(order); // 3. 占用阿姨 workerMapper.updateWorkStatus(worker.getId(), 1); return order.getId(); }Transactional(rollbackFor Exception.class)的作用是方法内任一步抛异常整个事务回滚数据库回到方法执行前的状态。这里必须写rollbackFor因为 Spring 默认只回滚 RuntimeException而BizException是自定义异常继承自 Exception不加这个参数就会出现在“订单插入失败但阿姨状态被改了”的脏数据。订单号生成我用的是时间戳前缀简单但有一定概率重复。改进方案是加一个随机数或者用数据库 sequence但这个项目没有 sequence所以推荐写法是HK System.currentTimeMillis() RandomUtil.randomNumbers(4)这样演示时生成连串订单号看起来更真实。4.4 MyBatis 的 insert 和分页查询两个关键参数别写错Mapper 层是 SQL 落地的地方。订单插入的 XML 写法要注意useGeneratedKeysinsert idinsert parameterTypecom.housekeeping.entity.Order useGeneratedKeystrue keyPropertyid INSERT INTO orders (order_no, user_id, worker_id, service_date, address, status, pay_amount, create_time) VALUES (#{orderNo}, #{userId}, #{workerId}, #{serviceDate}, #{address}, #{status}, #{payAmount}, #{createTime}) /insertuseGeneratedKeystrue让 MySQL 自增主键在 insert 后回填到传入对象的 id 属性上这样 Controller 里能直接拿到订单号返回给小程序。keyProperty对应的是 Java 实体的属性名不是数据库列名写keyPropertyid不是keyPropertyorder_id。订单列表分页是另一个必写功能。小程序端“订单列表”页不能一次加载全部数据几十条时看不出问题数据量到几百条时 setData 会造成明显卡顿。分页 SQL 用 limit 实现select idselectPageByUserId resultTypecom.housekeeping.entity.Order SELECT * FROM orders WHERE user_id #{userId} ORDER BY create_time DESC LIMIT #{offset}, #{size} /selectORDER BY create_time DESC是 MySQL 排序的标准写法让最新的订单排在最前面。LIMIT #{offset}, #{size}是经典的分页语法offset 从 0 开始。如果换了 PageHelper 插件则不需要手动算 offset但毕业设计项目里手写 limit 反而更好讲——老师让你现场写 SQL 时你直接说“我用 limit 加 offset 实现物理分页避免一次加载全表数据”这句话就是得分点。4.5 小程序端发起请求防重复点击和加载态处理后端接口就绪后小程序页面的调用方式要注意一个实战细节下单按钮要防止用户连点导致重复订单。常见做法是加一个 submitting 标记submitOrder() { if (this.data.submitting) return; this.setData({ submitting: true }); request(/api/order/create, POST, { userId: this.data.userInfo.id, workerId: this.data.workerId, serviceDate: this.data.serviceDate, address: this.data.address }).then(res { wx.showToast({ title: 下单成功, icon: success }); }).finally(() { this.setData({ submitting: false }); }); }这个submitting标记是实战里防止重复下单的常见做法比在弹窗里加“确定”按钮更稳。按钮的 loading 态可以配合wx.showLoading一起用交互上更友好。注意.finally()要确认小程序基础库版本支持一般 2.10 以上都支持 Promise如果不支持就改成.then().catch().then()的手动结尾。5. SSM 小程序联调常见问题五条血泪排查记录5.1 MySQL 驱动报错和 SSL 连接异常现象Tomcat 启动时报ClassNotFoundException: com.mysql.jdbc.Driver或数据库连接时抛出The server time zone value Öйú±ê׼ʱ¼ä is unrecognized又或者出现SSL connection error。原因分两种驱动类版本不对或 URL 缺少时区和 SSL 参数。MySQL 5.7 的驱动类是com.mysql.jdbc.DriverMySQL 8.0 变成了com.mysql.cj.jdbc.Driver后者必须配serverTimezone否则 JDBC 拿不到默认时区直接报错SSL 参数不写MySQL 8.0 默认开启 SSL 校验本地环境没有证书就会报SSL connection error。解决先确认本机 MySQL 版本SELECT VERSION();看一眼再改 db.properties。统一建议jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/housekeeping?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai这个配置组合在 5.7 和 8.0 下都能跑。排查时先用客户端工具如 Navicat 或命令行确认账号密码能连上 MySQL别让代码背锅——数据库本身没启动才是最常见的“启动失败”原因。5.2 小程序请求全部 fail后端 curl 却正常现象微信开发者工具里发送请求全部走 fail 回调控制台报url not in domain list或request:fail。但同一个接口用 curl 在终端请求完全正常。原因微信小程序出于安全策略默认不允许请求http://或者非白名单域名。开发者工具里可以临时关闭校验但很多人不知道在哪。真机预览时如果没有配置 HTTPS 域名请求也会失败。解决开发者工具界面点“详情→本地设置”勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”。真机调试时手机和电脑连同一个 Wi-Fi把 baseUrl 改成电脑内网 IP。如果要在正式环境发布后端必须上 HTTPS不然小程序发布审核会卡住。5.3 查出来的对象全是 null但 SQL 没报错现象orders表查出来订单列表字段名比如 createTime 有值但 userName、workerName 这种关联字段是 null日志也没任何异常。原因MyBatis 的自动映射默认要求数据库列名和 Java 属性名完全一致。数据库里user_name和小程序端 Java 实体里的userName中间差一个下划线映射不上。这就是第 2 章提到的mapUnderscoreToCamelCase开关没打开。解决在 mybatis-config.xml 里加setting namemapUnderscoreToCamelCase valuetrue/。注意这个只对 MyBatis 的自动映射有效如果你写了 resultMapresultMap 里的column和property还得自己对应好。之前我遇到一个案例同学开了开关但还是 null最后发现是 resultMap 里 column 写成了实体类属性名反过来能不 null 才怪。5.4 中文乱码写入数据库变问号现象小程序端提交的地址是“北京市朝阳区”存到 MySQL 里变成“??????????”。原因两层乱码叠加。第一层是 Tomcat 接收 POST 请求时默认用 ISO-8859-1 解码第二层是 JDBC 连接串没带characterEncodingutf8。只改一端都不完整。解决JDBC URL 加useUnicodetruecharacterEncodingutf8上面已写过同时在 web.xml 里配置 Spring 的编码过滤器filter filter-nameencodingFilter/filter-name filter-classorg.springframework.web.filter.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param init-param param-nameforceEncoding/param-name param-valuetrue/param-value /init-param /filter filter-mapping filter-nameencodingFilter/filter-name url-pattern/*/url-pattern /filter-mappingCharacterEncodingFilter 必须放在所有过滤器的最前面forceEncodingtrue表示把请求和响应的编码都强制成 UTF-8。如果你的项目还用了 shiro 拦截器注意这个 filter 的url-pattern要覆盖所有路径包括静态资源。5.5 订单列表越滚越卡一次请求把所有历史订单全拉下来现象小程序订单列表页数据量到两三百条时上下滚动明显卡顿甚至白屏。原因前端一次性调接口把全部订单返回小程序 setData 塞了两三百条记录渲染层扛不住。有的项目后端还真的没分页查全表返回。解决前后端同时改。后端加LIMIT #{offset}, #{size}第 4 章讲过小程序端用onReachBottom做“加载更多”。核心代码onReachBottom() { if (this.data.page this.data.totalPage) return; this.setData({ page: this.data.page 1 }); this.loadOrders(); }, loadOrders() { const { page, size } this.data; request(/api/order/list?page page size size, GET) .then(res { this.setData({ orders: this.data.orders.concat(res.data.list), totalPage: res.data.totalPage }); }); }注意concat是追加而不是覆盖: orders是this.data.orders的简写。总页数totalPage由后端返回算法是(totalCount size - 1) / size。这个“微信小程序页面列表加载更多”的用法是所有列表页的通用解法答辩现场演示列表流畅加载数据比讲一堆理论更能加分。6. 让项目从“能跑”到“高分”三个必做的进阶打磨毕业设计拿高分关键不在代码量在于演示时有完整的验证链条。我先给你三个立竿见影的打磨方向。第一把订单状态流转做成可视化步骤条。小程序端订单详情页用status字段渲染“待接单→已接单→服务中→已完成”四个节点的进度条每步对应一个图标和说明文字。这样做既不需要写额外接口又能在答辩演示时每次刷新页面都展示状态变化——老师很容易看出你对业务状态设计的理解。// 订单状态映射 const STATUS_MAP { 0: { text: 待接单, step: 0 }, 1: { text: 已接单, step: 1 }, 2: { text: 服务中, step: 2 }, 3: { text: 已完成, step: 3 }, 4: { text: 已取消, step: -1 } };第二处理微信小程序的顶部导航栏高度适配。这个坑几乎人人都会踩iPhone X 以后的机型有刘海导航栏高度不是固定的 64px。如果你自定义了导航栏用wx.getMenuButtonBoundingClientRect()动态计算const menu wx.getMenuButtonBoundingClientRect(); const statusBarHeight wx.getSystemInfoSync().statusBarHeight; const navBarHeight (menu.top - statusBarHeight) * 2 menu.height;menu.top - statusBarHeight是胶囊按钮距离状态栏的间距navBarHeight算出来之后再动态设置自定义导航栏的高度这样在不同机型上页面布局都不会错位。答辩时把手机递给老师看一屏说明你有适配意识这比“用了默认导航栏”加分得多。第三准备一个“一键演示数据”的 SQL 脚本。答辩前最怕演示到一半发现阿姨列表是空的或者在现场临时手动插数据翻车。我的习惯是准备一个demo_data.sql里面插好三五个用户、七八个家政人员、几条状态不同的订单和对应的评价演示前跑一遍保证每进入一个页面都有内容可看。这些年带过的毕业设计里SSM 加微信小程序这个组合最稳只要把数据库设计讲透、把事务边界讲明白、把列表分页做成真分页基本不会被挂。反而是那些追求“看起来高级”却跑不通的炫技项目最容易在答辩现场失控。你拿到这个源码包后别急着删改功能先按第 3 章的步骤跑通再把第 5 章的几个坑提前排掉最后用第 6 章的技巧润色一遍这套流程走下来你手里的就是一个答辩能展示、面试能讲清、代码能改动的作品。希望帮到你。本文还有配套的精品资源点击获取