资讯动态

美容院管理系统毕设资源解析:微信小程序+Java后端+Vue管理端全链路

发布时间:2026/10/26 22:44:57 来源:尧图企业网站定制
简介这是面向毕业设计、课程设计与项目实战的微信小程序美容院管理系统完整项目包采用小程序前端与 Java 后端分层实现围绕美容院日常管理场景设计适合计算机相关专业学生参考、复现与二次开发。包内共 1404 个文件压缩后约 15.86MBJava、Vue、JS 覆盖后端接口与前端业务逻辑WXML/WXSS 与 PNG/SVG 提供小程序页面结构和界面素材SQL 脚本用于初始化数据库还包含说明文档、启动脚本及备份配置目录划分清晰。压缩包内附带 3 个一键安装、运行、构建的 bat 脚本和 .classpath 等工程配置可从零开始搭建调试环境快速验证完整业务流程。已有 318 人学习使用。对于需要完成美容行业管理系统选题、理解前后端联调或搭建可用原型的学习者这份资源能提供一套可直接落地的参考方案。1. 从一坨“跑不起来的项目”到能答辩的美容院系统这份资源到底给了什么毕业设计最怕的不是不会写代码而是拿到手的项目缺数据库、缺依赖、前后端对不上。基于微信小程序java后端的美容院管理系统把源码、数据库、说明文档三样东西打包在一起补齐了一条能完整跑通的小程序预约→后端接口→管理端维护的链路。它能解决的是从“有一堆文件”到“能演示、能答辩、能按评委要求改”的整个过程。这套资源适合计算机专业准备毕设的学生也适合课程设计小组快速拿来做前后端分离项目的底子。下面我从文件结构、启动脚本、常见坑、答辩优化四个角度把它拆开。2. 系统结构拆解小程序端、Vue管理端、Java后端各自管哪一块2.1 从文件命名倒推项目结构资源包里有一串带 .bak 后缀的文件IndexMain.vue.bak、IndexAsideStatic.vue.bak、BreadCrumbs.vue.bak、IndexHeader.vue.bak。从命名就能看出管理端是 Vue 单页应用页面被拆成了头部IndexHeader、侧边栏IndexAsideStatic、面包屑BreadCrumbs和主内容区IndexMain这套布局骨架在若依一类的后台管理模板里非常常见。.bak 是开发过程中的备份文件也就是说原工程在改样式或功能时保留了上一版方便随时回滚。项目里同时出现1-install.bat、2-run.bat、3-build.bat三个脚本说明交付方已经把运行顺序安排明白了先装依赖再启动后端然后构建前端。这个顺序和多数 Spring Boot Vue 的前后端分离项目一致。微信小程序端负责给顾客用浏览服务项目、预约、查看会员信息Java 后端负责提供 REST 接口和数据库读写Vue 管理端给美容院员工用录入会员、排班、处理预约。2.2 后端接口链路从小程序请求到数据库返回后端主体是 Java常见做法是 Spring Boot MyBatis Plus。以会员管理为例小程序里顾客登录后要查自己的余额和卡项请求会先落到 Controller再走到 Service最后通过 Mapper 操作数据库。下面是一段接口示意RestController RequestMapping(/api/member) public class MemberController { GetMapping(/info) public ResultMemberInfo getMemberInfo(RequestHeader(token) String token) { MemberInfo member memberService.getInfoByToken(token); return Result.success(member); } }逻辑说明RequestHeader(token)要求请求头必须带上令牌小程序端在wx.request的header里放token管理端在 axios 拦截器里放同样的 token。这样一套后端接口可以同时被两端复用不用各写一套。参数说明真实项目里token一般取wx.login的 code 换来的 openid 后生成的会话标识不要直接把 openid 当 token 用否则泄露到前端会有安全风险。这里返回的是统一封装Result包含 code、msg、data 三个字段前端判断 code 是 0 才取 data。再往下看MyBatis Plus 的 Mapper 通常长这样public interface MemberMapper extends BaseMapperMember { Select(SELECT * FROM member WHERE phone #{phone}) Member selectByPhone(String phone); }这个BaseMapper已经提供了selectById、selectList、insert等常用方法只要实体类字段和表字段映射好大部分增删改查都不用写 SQL。需要注意TableName标注表名TableField标注字段名比如TableField(card_expire_time) private LocalDate cardExpireTime;驼峰转下划线是默认规则但如果你改了默认配置就一定要显式标注否则运行时报字段不存在。参数说明Select注解适合简单查询复杂统计建议写到resource/mapper/MemberMapper.xml里避免 SQL 字符串拼接。2.3 数据表设计美容院系统最少需要这几张表数据库是 MySQL初始化脚本里通常会建六张核心表会员表、员工表、服务项目表、预约表、订单表、卡项套餐表。表格如下表名关键字段用途memberid, name, phone, balance, level会员基础信息和余额staffid, name, position, status美容师/理疗师档案service_itemid, name, duration, price, status可预约的项目appointmentid, member_id, staff_id, item_id, start_time, end_time, status预约排班记录orderid, order_no, member_id, amount, pay_type消费订单member_cardid, member_id, card_type, balance, expire_time储值卡/套餐卡设计要点预约表里一定要有start_time和end_time两个字段不要只存一个日期或时段否则后面做冲突检测非常痛苦。appointment.status建议取值范围是 0 待确认、1 已确认、2 已完成、3 已取消这个状态枚举要和小程序端、管理端的下拉框保持一致。建表脚本示例SQLCREATE TABLE appointment ( id bigint(20) NOT NULL AUTO_INCREMENT, member_id bigint(20) NOT NULL COMMENT 会员ID, staff_id bigint(20) NOT NULL COMMENT 员工ID, item_id bigint(20) NOT NULL COMMENT 服务项目ID, start_time datetime NOT NULL, end_time datetime NOT NULL, status tinyint(4) NOT NULL DEFAULT 0, remark varchar(255) DEFAULT NULL, PRIMARY KEY (id), KEY idx_member (member_id), KEY idx_staff_time (staff_id, start_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;逻辑说明联合索引(staff_id, start_time)是给冲突检测查询用的MySQL 会快很多。注意status用tinyint不用varchar避免枚举值写错。时间字段统一datetime不要混用timestamp。2.4 管理端页面与接口怎么对拍前后端分离项目里页面显示空数据的原因大多不是没数据而是字段名对不上。管理端的服务项目表格列绑定的是propserviceName但后端返回的是name页面就空白。我一般打开浏览器 F12 看 Network 里的响应 JSON再和表格列的 prop 逐个对。比如前端请求GET /api/service/list返回值长这样{ code: 0, data: [ { id: 1, serviceName: 深层清洁, duration: 60, price: 268 } ] }那后端 VO 里就必须有serviceName这个字段名否则用name就会翻车。管理端 Vue 页面怎么发请求在api/service.js里常见写法是import request from /utils/request export function listService(params) { return request({ url: /service/list, method: get, params }) }然后在service.vue的created()里调用listService({ page: 1, size: 10 })把返回的data.records赋值给表格的tableData。逻辑说明这里request就是 axios 实例统一设置 baseURL 和 token。参数说明分页参数尽量用page和size和后端 PageHelper 或 MyBatis Plus 的分页参数保持一致避免管理端页数对不上。这个对拍过程是联调工作量的主要来源。拿到资源包后建议优先把服务列表、预约列表、会员列表这三个接口和页面都过一遍能跑通这套其他模块基本是一样的套路。3. 本地环境搭建install、run、build 三件套怎么落地3.1 环境检查与初始化拿到资源包后我习惯先看1-install.bat干什么。这类项目一般需要 JDK8、Maven3.6、Node.js 14、MySQL 5.7/8.0。先检查java -version mvn -v node -v mysql --version如果哪一项提示“不是内部或外部命令”就去对应的环境变量里补。这里最常见的坑是电脑里装了多个 JDK 版本JAVA_HOME指向了 JDK17但项目用的是 JDK8启动报UnsupportedClassVersionError。解决方式是把JAVA_HOME切到 JDK8 路径或者在 IDE 里指定 Project SDK。这类问题属于环境问题不把环境理顺后面每一步都会被连累。提示优先把解压路径和目标文件夹全部改成英文Maven 和 Node 在中文路径下偶尔会抽风报错也看不出原因。3.2 数据库导入先把地基打好数据库脚本一般在sql目录或根目录下名字类似db_beauty.sql。导入命令mysql -u root -p -e source /你的路径/db_beauty.sql导入后进 MySQL 确认表数量和种子数据USE db_beauty; SHOW TABLES; SELECT COUNT(*) FROM member;如果SELECT COUNT(*) FROM member返回 0说明脚本里只有表结构没有数据管理端页面会空。我一般会至少造五到十条会员记录方便后面演示预约流程。这里的坑在后面专章讲先记住一个判断标准导入脚本后能查到种子数据才算这一步做完。3.3 后端启动脚本跑还是 IDE 跑2-run.bat内部大概率是这两条之一mvn spring-boot:run java -jar target/beauty-system.jar我一般建议先试1-install.bat它会对后端执行mvn install把依赖拉下来再试2-run.bat。如果你在 IDE 里跑直接在Application类的main方法上点运行。启动成功后控制台会出现Tomcat started on port(s): 8080然后访问http://localhost:8080/api/member/info看是否返回 JSON。如果出现Unable to find Spring Boot之类的错误检查 pom.xml 里的 parent 版本和本地 Maven 仓库是否一致。后端配置集中在application.yml或application-druid.yml。一个典型的数据库连接配置server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/db_beauty?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver逻辑说明serverTimezoneAsia/Shanghai必须加不加会出现第 4 章那个时区问题。useSSLfalse避免本地连 MySQL 报 SSL 警告。参数说明如果你用 MySQL 5.7驱动可以换成com.mysql.jdbc.Driver但 8.x 之后推荐用cj驱动。3.4 管理端前端跑起来管理端是 Vue 工程3-build.bat是打包用的本地调试不要先 build而是先装依赖再起 dev servernpm install npm run dev启动后看http://localhost:8089如果页面出来了但接口报 401 或跨域需要在vue.config.js里配代理module.exports { devServer: { port: 8089, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }逻辑说明devServer.proxy把前端发的/api开头的请求转发到后端 8080这样浏览器看到的就是同源请求不会触发 CORS。参数说明changeOrigin设为 true 很重要它会把请求的 Host 头改成 target 的域名否则后端若校验 Host 会拒绝。3.5 小程序端导入与请求地址用微信开发者工具导入小程序目录第一次导入会提示“未注册 AppID”选择测试号即可。然后打开config.js或utils/request.js把全局接口地址改成const BASE_URL http://localhost:8080说明模拟器里 localhost 指向你的电脑所以能通。真机预览时手机和电脑要在同一 Wi-Fi把BASE_URL改成电脑的局域网 IP比如http://192.168.1.5:8080同时后端启动时加上--server.address0.0.0.0防火墙放行 8080 端口。这一步卡住的人很多主要原因是只改了前端没改后端绑定地址。注意还要在微信开发者工具右上角详情里勾选“不校验合法域名”否则请求接口直接被拦截。这个开关只在开发调试阶段有效真机预览时同样要开除非你已经在小程序后台配置了业务域名。4. 避坑手册这五个问题最容易让答辩现场翻车4.1 个人小程序拿不到授权手机号现象小程序端点“微信一键登录”模拟器能弹窗但真机一直报错或者压根没有获取手机号按钮。原因微信官方接口getPhoneNumber要求小程序为企业认证主体个人开发者无权调用。2023 年后获取手机号还改成了动态验证码模式必须在用户开通时填验证码。解决答辩演示不要依赖这个接口改成账号密码登录手机号做成表单里的可编辑字段后端存进 member 表。如果想要“微信登录”的体验用wx.login拿 code 去后端换 openid再拿 openid 关联本地账号。这样既避开了资质限制也演示了微信登录流程。4.2 管理端跨域报错小程序反而没事现象Vue 管理端在浏览器里请求后端Console 报Access-Control-Allow-Origin而小程序端同样请求后端却很顺畅。原因小程序不是浏览器环境没有同源策略限制浏览器管理端才需要服务端返回 CORS 头。很多新手在前端修来修去其实问题在后端。解决在后端加一个全局过滤器统一加三个响应头。参考代码Component public class CorsFilter implements Filter { Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) { HttpServletResponse response (HttpServletResponse) res; response.setHeader(Access-Control-Allow-Origin, *); response.setHeader(Access-Control-Allow-Methods, GET, POST, PUT, DELETE, OPTIONS); response.setHeader(Access-Control-Allow-Headers, Content-Type, Authorization, token); chain.doFilter(req, res); } }逻辑说明OPTIONS预检请求需要直接放行避免浏览器拦截 PUT/DELETE。参数说明Access-Control-Allow-Headers里必须包含你前端实际用到的所有自定义头最常见的就是token漏了就报“Request header field token is not allowed”。4.3 MyBatis Plus 自动建表把数据表搞乱现象后端启动后数据库自动生成几十张表字段和 .sql 脚本里的对不上原来的数据也查不到了。原因项目里开了spring.jpa.hibernate.ddl-auto或 MyBatis Plus 的auto-ddl自动建表配置。自动生成的表结构是实体类推出来的字段顺序和注释都丢了。解决关闭自动建表手动执行 .sql 脚本。Spring Boot 配置里加一行spring.jpa.hibernate.ddl-autononeMyBatis Plus 则在application.yml里去查auto-ddl相关配置。更简单的方式是把 .sql 脚本导出的库名改成另一个库名确保自动建表不影响手动数据。4.4 .bak 文件到底是备份还是主文件现象改页面时习惯性打开IndexMain.vue.bak改了半天发现不是生效的那个文件页面没有变化。原因.bak是开发时留的备份IDE 和编辑器默认不会把它当源码编译。有些交付方会把最终版命名为 .bak主文件反而被覆盖造成“打开的能跑正常文件跑不了”。解决先看同目录下是否有不带 .bak 的同名文件有就以不带 .bak 的为准如果只有 .bak复制一份去掉后缀名再打开。第二步是搜索入口文件里import或src引用路径确认当前真正加载哪个文件。4.5 预约时间少了 8 小时现象管理端看到的预约时间是 14:00数据库存的却是 06:00差了一整个白天。原因JDBC 连接时区没设置MySQL 默认用系统时区Java 进程用北京时区串了。解决在 jdbc url 加serverTimezoneAsia/Shanghai同时检查 Java 的 Jackson 配置spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8参数说明time-zone: GMT8是固定 8 小时比写Asia/Shanghai更直白不会受系统时区策略影响。改完重启后用一条 SQL 查SELECT start_time, CONVERT_TZ(start_time, 00:00, 08:00)验证是否恢复。5. 进阶优化把系统调到能答辩、能加分的水准5.1 小程序自定义导航栏高度适配资源包里的小程序可能用了系统默认导航栏但你拿到手做二次开发时难免要改成自定义导航栏。自定义顶部导航栏高度在不同机型上不一致iPhone X 系列的刘海屏和 Android 主流机型相差几十像素。适配代码Page({ data: { statusBarHeight: 20, navBarHeight: 44 }, onLoad() { const windowInfo wx.getWindowInfo() const menuRect wx.getMenuButtonBoundingClientRect() this.setData({ statusBarHeight: windowInfo.statusBarHeight, navBarHeight: (menuRect.top - windowInfo.statusBarHeight) * 2 menuRect.height }) } })逻辑说明wx.getWindowInfo()返回statusBarHeightwx.getMenuButtonBoundingClientRect()拿到胶囊按钮的位置用它计算自定义导航栏高度能保证右侧按钮不重叠。参数说明计算方式是胶囊顶部减去状态栏高度得到导航栏上下内边距再乘以 2 加上胶囊高度这是官方社区里最常见的公式。在app.json里同时设置navigationStyle: custom否则页面的胶囊按钮会重复出现。5.2 预约冲突校验一个条件查询就够了预约模块最容易被评委追问“并发怎么办”。哪怕你项目里只有单机也要把 SQL 写成能防冲突的形状。核心查询SELECT COUNT(*) FROM appointment WHERE staff_id #{staffId} AND status IN (0, 1) AND start_time #{endTime} AND end_time #{startTime}逻辑说明查询同一员工在目标时间段内是否已有状态为待确认或已确认的预约。两个区间交叠的判断是start_time 新结束时间 AND end_time 新开始时间这个条件把包含、交叉、邻接都覆盖了。参数说明status IN (0,1)排除了已取消和已完成避免旧记录阻塞新预约。在 Service 里包一层Transactional然后先做查询再做插入防止两个请求同时进来。还可以给 appointment 表加一个唯一约束但 MySQL 对范围唯一不好做面试时能说出“用排它锁或唯一预约号”就算过关。不过最稳妥的还是事务 SQL 条件查询。5.3 操作日志给“毕业设计”加一层管理员的底管理端录入数据之后评委很可能问“怎么知道是谁改的”。加一个操作日志比想象中简单。用 Spring AOP 切Log注解记录模块、操作类型、操作人、IP、耗时。简化版切面Aspect Component public class LogAspect { AfterReturning(annotation(operLog)) public void saveLog(JoinPoint joinPoint, Log operLog) { String module operateLog.module(); String username getCurrentUsername(); logService.save(module, username, LocalDateTime.now()); } }逻辑说明AfterReturning定位到被Log注解标注的方法方法正常返回后写入一条日志。参数说明module()是注解里的元数据比如“会员管理”“预约管理”这样日志表能按模块过滤。这个切面不用侵入业务代码只要在 Controller 方法上加Log(module 会员管理)就行。日志表结构大概是id, module, username, action, ip, create_time字段不用多够看即可。注意不要记录密码等敏感字段切面里要对入参做脱敏。另外建议把Log放在 Controller 层不要放 Service 层因为 Controller 能拿到完整的用户上下文。写完这层系统就有了“谁在什么时间改了哪些数据”的审计链路。答辩时讲到这一节比单纯重复“增删改查”有说服力得多。三块都落地后系统就从小程序的单点演示变成一个前后端能闭环、能应对追问的完整项目。6. 交付前的验证清单五步确认系统没白跑拿到这套美容院管理系统后我每次都会强制自己走一遍最小验证流程第一步清空数据库重新导入 .sql避免依赖之前手动插入的临时数据第二步用 Postman 把登录、服务列表、创建预约、会员查询四个核心接口跑一遍确认返回格式统一第三步启动 Vue 管理端走一次“登录→新增服务项目→编辑→删除”重点看 F12 的 Network 有没有红色报错第四步在微信开发者工具里走一遍“登录→选项目→选时间→提交预约→在管理端确认”第五步把数据库 binlog 关掉重新从一个干净的 .sql 导出为db_beauty_final.sql交付。这里最容易被忽略的是第二步和第四步的接口字段一致性。我自己的习惯是拿一个小程序端的请求参数直接复制到 Postman 里发发现参数名不一致就立刻改后端 VO 或前端提交体不要等到联调再改。改完再跑一遍直到两边完全一致。另一个后悔药技巧是初始化 Git 版本管理。拿到资源包后先不要急着改代码第一步就做git init并提交原始版本。之后每完成一个功能点就 commit 一次。这样后面无论是改崩了 Vue 页面还是把 application.yml 改坏都能用git checkout回到上一个能跑的版本。我见过太多人把项目改崩后只能求朋友重新发一份压缩包其实一份 Git 历史就是最好的“后悔药”。从那以后我每次接触别人的毕业设计项目都会先跑通最小验证流程、建立版本基线再动业务代码。这个习惯让我省下了大量重复排查时间。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑