尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Java毕设实战:Spring Boot健身房会员管理系统开发全流程

Java毕设实战:Spring Boot健身房会员管理系统开发全流程 又到一年毕业设计季Java 方向的同学十有八九都在纠结同一个问题做什么题目既能轻松通过答辩又能真正把 Spring Boot、MyBatis、MySQL 这套技术栈练熟这次我们就来看一个非常经典的 Java 练手项目——健身房会员管理系统。先给结论这个项目的重点不在于业务多复杂而在于它覆盖了 Java 后端开发的完整链路数据库设计、接口开发、前端页面联调、部署答辩。技术栈主流功能点清晰演示效果好。你不需要搞懂多高深的理论只要把会员管理、续费、课程预约这几个核心流程跑通再配合一套完整的 SQL 脚本毕设通过基本没问题顺手还能把 Java 基础再夯实一遍。这篇文章会从零开始带你过一遍整个项目的技术选型、数据库设计、后端接口、前端页面和部署验证流程。包括用 IDEA 创建项目、配置 MySQL 数据库、编写会员增删改查和续费接口、设计前端管理页面最后给出完整的测试流程和常见坑的排查方法。如果你正在做毕设或者想找个 Java 项目实战练手这篇可以直接收藏。1. 核心能力速览在动手之前先把项目的画像整理清楚。这个系统从功能边界、技术栈到部署方式都是典型的 Java Web 管理后台项目。能力项说明项目类型Java Web 管理系统 / 毕设项目 / 练手项目核心业务会员信息管理、会员卡办理、续费、课程管理、私教预约、统计分析后端技术栈Spring Boot Spring MVC MyBatis或 MyBatis-Plus前端技术栈Vue Element UI / 管理后台模板或 Thymeleaf 服务端渲染数据库MySQL 5.7 或 8.0开发工具IntelliJ IDEA、Navicat / DataGrip、Postman / Apifox启动方式IDEA 启动 Spring Boot 主类 前端 npm run dev或直接访问模板页面接口能力RESTful API支持 JSON 数据交互批量任务支持批量导入会员、批量续费、Excel 导出按实际实现为准适合场景Java 课程设计、毕业设计、Java 基础巩固、本地练手这里的“是否支持批量任务”需要特别注意如果你实现的版本里加了 Excel 导入导出和批量续费答辩时是明显的加分项如果只做基础 CRUD也能通过但亮点会少一些。下面的实操部分会讲清楚怎么把批量任务加进去。2. 适用场景与使用边界这个系统适合谁来用从题目定位来看目标人群非常明确正在准备 Java 毕设的学生、想通过项目实战巩固 Java 基础的自学者、以及需要一套完整项目源码作为参考的开发者。它能解决的问题也很直接提供一条完整的 Java Web 开发路线。从建表开始到实体类、Mapper、Service、Controller再到前端页面渲染整个过程能让你理解一个管理系统是怎么从零跑起来的。业务场景贴近真实健身房管理需求会员开卡、续费、课程预约这些流程在答辩演示时非常直观。但也要说清楚它的边界。这个项目定位是教学和毕设它不是一套生产级 SaaS 系统。真要拿到商业健身房去用还缺很多模块支付对接、复杂的权限管理比如店长、教练、前台不同角色、多门店支持、硬件设备对接门禁、闸机。所以别指望它能直接商用它的核心价值是让你学会 Spring Boot 开发的基础能力。还有一个合规问题必须提醒系统里会涉及会员手机号、身份证号、生日等个人敏感信息。做毕设和本地演示没问题但如果上线或展示给别人要注意脱敏处理不要明文展示完整身份证号涉及真实用户数据时必须获得授权。代码里也要做好参数校验防止 SQL 注入和非法数据写入。3. 环境准备与前置条件开始写代码之前先把环境跑通。下面是一套通用的 Java Web 毕设环境清单版本号不是死规定但建议保持主流版本避免依赖冲突。3.1 开发环境清单软件建议版本说明JDK8 或 11Spring Boot 2.x 用 JDK 8 最稳Spring Boot 3.x 需要 JDK 17Maven3.6 以上统一管理依赖IDEA 自带也可MySQL5.7 或 8.0建库建表、存储业务数据IDEA2021.x 及以上旗舰版支持 Spring Initializr社区版也能用但需手动建项目Navicat / DataGrip任意导入 SQL 脚本、查看数据Postman / Apifox任意测试后端接口Node.js可选16 以上如果使用 Vue 独立前端需要 Node 环境3.2 本地检查清单装完软件后先别急着写代码打开终端确认环境java -version mvn -version mysql --version node -v npm -v如果命令都能正常输出版本号说明环境基本可用。如果提示“无法识别命令”大概率是环境变量没配好先去配置 JDK、Maven 和 Node 的环境变量。数据库这边还需要准备一个空的 schema建议命名gym_member字符集选择utf8mb4排序规则选择utf8mb4_general_ci或utf8mb4_unicode_ci否则后面插入中文数据可能出现乱码。CREATE DATABASE IF NOT EXISTS gym_member DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;3.3 端口占用检查Spring Boot 默认端口是 8080。启动项目前检查一下端口是否被占用尤其是电脑上之前跑过其他 Java 项目的情况# Windows 查看端口占用 netstat -ano | findstr 8080 # macOS / Linux 查看端口占用 lsof -i :8080如果端口被占用可以在application.yml里改端口server: port: 80814. 项目初始化与依赖配置环境就绪后用 IDEA 创建一个 Spring Boot 项目并准备好核心依赖。4.1 创建 Spring Boot 项目IDEA 操作路径File - New - Project - Spring Initializr。填写 Group 和 ArtifactJava 版本根据本机 JDK 选择依赖这里先勾选Spring WebMyBatis FrameworkMySQL DriverLombok没有在初始化界面勾选 MyBatis 也没关系后面手动往pom.xml里加依赖即可。4.2 pom.xml 核心依赖下面是一份适用于 Spring Boot 2.x 的依赖模板。实际使用时版本号可以放在pom.xml的parent或properties中统一管理按你本地的 Spring Boot 版本为准。dependencies !-- Web 支持 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- MyBatis 整合 -- dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.3.1/version /dependency !-- MyBatis-Plus简化 CRUD可选 -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency !-- Lombok 简化实体类代码 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency !-- MySQL 驱动 -- dependency groupIdcom.mysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency !-- 参数校验 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-validation/artifactId /dependency /dependencies如果你用的是 MyBatis-Plus可以少写很多 XML Mapper 里的基础 CRUD 语句对于毕设项目来说效率更高。如果想让项目显得更“传统”也可以只用原生 MyBatis看你自己对哪个更熟。我的建议是时间紧就上 MyBatis-Plus精力充裕就手写 Mapper XML两种都能学到东西。4.3 application.yml 配置在src/main/resources/application.yml里配置数据源和 MyBatis 相关参数server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/gym_member?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: yourpassword driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.gym.entity configuration: map-underscore-to-camel-case: true这里重点提醒serverTimezoneAsia/Shanghai不能省否则 MySQL 8.x 下连接会报时区错误。map-underscore-to-camel-case: true能把数据库member_name自动映射到实体类的memberName少写很多 resultMap。5. 数据库设计与建表 SQL健身房会员管理系统的核心数据表大概有 5 张会员表、卡种表、会员卡表、课程表、预约记录表。下面给出一套通用建表脚本字段命名用下划线风格后面配合 MyBatis 驼峰映射使用。5.1 会员表 memberCREATE TABLE member ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键, member_no varchar(32) NOT NULL COMMENT 会员编号, name varchar(50) NOT NULL COMMENT 姓名, phone varchar(20) NOT NULL COMMENT 手机号, id_card varchar(18) DEFAULT NULL COMMENT 身份证号, gender tinyint DEFAULT NULL COMMENT 性别 1男 2女 0未知, birthday date DEFAULT NULL COMMENT 生日, member_level varchar(20) DEFAULT 普通会员 COMMENT 会员等级, status tinyint DEFAULT 1 COMMENT 状态 1正常 0停用, remark varchar(255) DEFAULT NULL COMMENT 备注, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), UNIQUE KEY uk_member_no (member_no), UNIQUE KEY uk_phone (phone) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT会员信息表;会员编号建议用规则生成比如前缀M加时间戳避免自增主键暴露在业务层。手机号加唯一索引防止重复录入。5.2 卡种表 card_typeCREATE TABLE card_type ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键, type_name varchar(50) NOT NULL COMMENT 卡种名称, duration_days int NOT NULL COMMENT 有效天数, price decimal(10,2) NOT NULL COMMENT 价格, remark varchar(255) DEFAULT NULL COMMENT 备注, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT会员卡种类表;卡种可以预置几类数据月卡 30 天、季卡 90 天、年卡 365 天。这样会员办卡和续费都有依据不用每次手输价格。5.3 会员卡表 member_cardCREATE TABLE member_card ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键, member_id bigint NOT NULL COMMENT 会员ID, card_type_id bigint NOT NULL COMMENT 卡种ID, card_no varchar(32) NOT NULL COMMENT 卡号, balance decimal(10,2) DEFAULT 0.00 COMMENT 账户余额, start_time datetime DEFAULT NULL COMMENT 开卡时间, end_time datetime DEFAULT NULL COMMENT 到期时间, status tinyint DEFAULT 1 COMMENT 状态 1有效 0失效, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_card_no (card_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT会员卡表;这里推荐会员卡和会员表分开存储。一个会员可以拥有多张卡比如一张年卡加一个私教课程包。如果业务简单也可以把卡信息合并到会员表里按自己需求选择。5.4 课程表 courseCREATE TABLE course ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键, course_name varchar(100) NOT NULL COMMENT 课程名称, coach_name varchar(50) DEFAULT NULL COMMENT 教练姓名, class_time datetime DEFAULT NULL COMMENT 上课时间, max_students int DEFAULT 20 COMMENT 最大人数, current_students int DEFAULT 0 COMMENT 已报名人数, remark varchar(255) DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT课程表;5.5 预约记录表 appointmentCREATE TABLE appointment ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键, member_id bigint NOT NULL COMMENT 会员ID, course_id bigint NOT NULL COMMENT 课程ID, appointment_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 预约时间, status tinyint DEFAULT 1 COMMENT 1已预约 2已取消 3已完成, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT课程预约表;这张表是典型的关联表用来记录会员预约了哪节课。答辩时重点介绍这张表的外键关系和联表查询逻辑能体现你的数据库设计能力。6. 后端接口开发数据库建好后开始写后端代码。项目结构建议按功能分包这样代码清晰答辩时也好讲。6.1 项目包结构com.example.gym ├── GymApplication.java # 启动类 ├── controller # 控制层 │ ├── MemberController.java │ ├── CourseController.java │ └── AppointmentController.java ├── service # 业务层 │ ├── MemberService.java │ └── MemberServiceImpl.java ├── mapper # 数据访问层 │ ├── MemberMapper.java │ └── MemberMapper.xml ├── entity # 实体类 │ ├── Member.java │ ├── Course.java │ └── Appointment.java ├── common # 通用类 │ ├── Result.java # 统一返回结果 │ └── PageResult.java # 分页返回结果 └── vo # 视图对象entity里的实体类用 Lombok 注解简化 getter/setter代码量会少很多。import lombok.Data; import java.time.LocalDateTime; Data public class Member { private Long id; private String memberNo; private String name; private String phone; private String idCard; private Integer gender; private String birthday; private String memberLevel; private Integer status; private String remark; private LocalDateTime createTime; private LocalDateTime updateTime; }6.2 统一返回结果开发接口时建议定义一个统一的返回对象前端解析时不需要处理各种奇怪的返回结构。Data public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(操作成功); result.setData(data); return result; } public static T ResultT error(String message) { ResultT result new Result(); result.setCode(500); result.setMessage(message); return result; } }6.3 会员管理接口以会员管理为例写一套基础的增删改查接口。RestController RequestMapping(/api/member) public class MemberController { Resource private MemberService memberService; GetMapping(/list) public ResultPageResultMember list(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, RequestParam(required false) String keyword) { PageResultMember page memberService.page(pageNum, pageSize, keyword); return Result.success(page); } GetMapping(/{id}) public ResultMember getById(PathVariable Long id) { return Result.success(memberService.getById(id)); } PostMapping(/add) public Result? add(RequestBody Validated Member member) { memberService.add(member); return Result.success(null); } PutMapping(/update) public Result? update(RequestBody Member member) { memberService.update(member); return Result.success(null); } DeleteMapping(/delete/{id}) public Result? delete(PathVariable Long id) { memberService.delete(id); return Result.success(null); } }Service 实现里要处理几件关键逻辑会员编号生成、手机号重复校验、删除前判断是否有未到期的会员卡。这些业务规则是答辩提问的高频点建议提前想清楚。6.4 会员续费接口续费是健身房系统最核心的业务逻辑。当会员购买新卡或续费时需要更新会员卡到期时间和卡状态。Service public class MemberCardServiceImpl implements MemberCardService { Resource private MemberCardMapper memberCardMapper; Resource private CardTypeMapper cardTypeMapper; Override Transactional(rollbackFor Exception.class) public void renew(Long memberId, Long cardTypeId) { CardType cardType cardTypeMapper.selectById(cardTypeId); if (cardType null) { throw new RuntimeException(卡种不存在); } MemberCard memberCard memberCardMapper.selectByMemberId(memberId); LocalDateTime newEndTime; if (memberCard null) { memberCard new MemberCard(); memberCard.setMemberId(memberId); memberCard.setCardTypeId(cardTypeId); memberCard.setCardNo(generateCardNo()); memberCard.setStartTime(LocalDateTime.now()); newEndTime LocalDateTime.now().plusDays(cardType.getDurationDays()); } else { LocalDateTime currentEndTime memberCard.getEndTime(); if (currentEndTime.isAfter(LocalDateTime.now())) { // 卡未到期在原到期时间上累加 newEndTime currentEndTime.plusDays(cardType.getDurationDays()); } else { // 卡已过期从当前时间重新计算 newEndTime LocalDateTime.now().plusDays(cardType.getDurationDays()); } } memberCard.setEndTime(newEndTime); memberCard.setStatus(1); // 如果是新卡则插入否则更新 if (memberCard.getId() null) { memberCardMapper.insert(memberCard); } else { memberCardMapper.updateById(memberCard); } } private String generateCardNo() { return C System.currentTimeMillis(); } }这里用Transactional保证续费操作的原子性如果后续要加余额扣费、积分增加等操作都在同一个事务里完成。卡未到期累加时间、卡到期重新计算的逻辑是业务上的关键细节答辩时能讲清楚会很加分。6.5 课程预约接口预约接口需要判断课程是否满员。如果current_students max_students直接拒绝预约。Service public class AppointmentServiceImpl implements AppointmentService { Resource private AppointmentMapper appointmentMapper; Resource private CourseMapper courseMapper; Override Transactional(rollbackFor Exception.class) public void book(Long memberId, Long courseId) { Course course courseMapper.selectById(courseId); if (course null) { throw new RuntimeException(课程不存在); } if (course.getCurrentStudents() course.getMaxStudents()) { throw new RuntimeException(课程已满员); } Appointment appointment new Appointment(); appointment.setMemberId(memberId); appointment.setCourseId(courseId); appointment.setStatus(1); appointmentMapper.insert(appointment); // 已报名人数加一 course.setCurrentStudents(course.getCurrentStudents() 1); courseMapper.updateById(course); } }预约成功后课程表的current_students要同步加一。这里涉及到两张表的更新操作放在同一个事务里避免预约记录写入成功但人数没更新的脏数据问题。7. 前端页面设计前端部分有两种主流做法。如果时间紧直接用一套开源的后台管理模板配合 Vue Element Plus 写页面如果不想前后端分离直接用 Thymeleaf 模板引擎渲染页面。这里重点讲前后端分离方式。7.1 创建前端项目# 使用 Vue CLI 创建项目 vue create gym-web # 或使用 Vite 创建项目 npm create vitelatest gym-web -- --template vue进入项目目录后安装 Element Plus 和 Axiosnpm install element-plus axios7.2 配置 Axios 请求在src/utils/request.js里封装统一的请求工具设置 baseURL 和后端地址并加上请求拦截器和响应拦截器。import axios from axios import { ElMessage } from element-plus const request axios.create({ baseURL: http://localhost:8080/api, timeout: 10000 }) request.interceptors.response.use( response { const res response.data if (res.code ! 200) { ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) } return res }, error { ElMessage.error(error.message || 网络错误) return Promise.reject(error) } ) export default request注意如果前端项目和后端不在同一个端口需要处理跨域问题。可以在后端加一个CorsConfig也可以在前端配置 devServer 的代理。7.3 会员列表页面用 Element Plus 的el-table展示会员列表配合el-pagination分页组件。下面是一个简单的会员列表页结构template div classmember-page el-card el-form :inlinetrue el-form-item label关键词 el-input v-modelquery.keyword placeholder姓名/手机号 clearable / /el-form-item el-form-item el-button typeprimary clickloadData查询/el-button el-button typesuccess clickopenAddDialog新增会员/el-button /el-form-item /el-form el-table :datalist border stripe el-table-column propmemberNo label会员编号 width140 / el-table-column propname label姓名 width100 / el-table-column propphone label手机号 width130 / el-table-column propmemberLevel label等级 width100 / el-table-column propstatus label状态 width80 template #defaultscope el-tag :typescope.row.status 1 ? success : danger {{ scope.row.status 1 ? 正常 : 停用 }} /el-tag /template /el-table-column el-table-column label操作 template #defaultscope el-button sizesmall clickopenEditDialog(scope.row)编辑/el-button el-button sizesmall typedanger clickhandleDelete(scope.row)删除/el-button /template /el-table-column /el-table el-pagination v-model:current-pagequery.pageNum v-model:page-sizequery.pageSize :totaltotal layouttotal, prev, pager, next current-changeloadData / /el-card /div /template script setup import { ref, reactive, onMounted } from vue import request from ../utils/request import { ElMessage, ElMessageBox } from element-plus const list ref([]) const total ref(0) const query reactive({ pageNum: 1, pageSize: 10, keyword: }) async function loadData() { const res await request.get(/member/list, { params: query }) list.value res.data.list total.value res.data.total } function handleDelete(row) { ElMessageBox.confirm(确定删除会员 ${row.name} 吗, 提示, { type: warning }).then(async () { await request.delete(/member/delete/${row.id}) ElMessage.success(删除成功) loadData() }) } onMounted(loadData) /script前端页面不需要写得多炫酷重点是功能完整、交互清晰、布局整洁。会员管理、卡种管理、课程管理、预约管理、统计首页这几个页面做出来整个系统的演示效果就够了。8. 接口测试与批量任务验证系统开发完成后要形成一套自己的“验收流程”。先用接口工具把后端 API 全部测通再跑前端页面联调最后验证批量任务和导出功能。8.1 接口测试用例用 Postman 或 Apifox 建立接口集合按下面的顺序测试接口路径方法参数预期结果/api/member/listGETpageNum1, pageSize10返回分页会员列表/api/member/addPOSTname张三, phone138xxxx返回操作成功/api/member/updatePUTid1, name李四返回操作成功/api/member/delete/{id}DELETEid1返回操作成功/api/card/renewPOSTmemberId1, cardTypeId1会员卡到期时间累加/api/appointment/bookPOSTmemberId1, courseId1预约成功课程人数加一测试时要注意边界情况重复添加相同手机号应该返回错误删除不存在的会员应该返回错误提示预约已满员的课程应该返回“课程已满员”。这些异常分支是答辩老师最喜欢问的点。8.2 批量导入会员如果想让项目在答辩时更有亮点可以加一个批量导入功能前端上传 Excel 文件后端解析并批量写入数据库。用 EasyExcel 或 Apache POI 都能实现下面是一个通用思路PostMapping(/import) public Result? importMembers(RequestParam(file) MultipartFile file) { ListMember memberList ExcelUtils.readMembers(file); for (Member member : memberList) { // 校验手机号是否重复重复则跳过或覆盖按业务需要处理 member.setMemberNo(generateMemberNo()); memberMapper.insert(member); } return Result.success(null); }批量导入的重点是校验逻辑手机号格式不正确、身份证号长度不对、必填字段为空都要给出明确提示。建议先读取整个 Excel校验通过后再批量写入避免一条错误数据导致全部失败。8.3 导出会员列表导出功能同样常用。后端生成 Excel 文件前端直接下载答辩时演示“查询会员列表 - 一键导出 Excel”的效果会非常直观。GetMapping(/export) public void export(HttpServletResponse response) throws IOException { ListMember list memberMapper.selectList(null); response.setContentType(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet); response.setCharacterEncoding(utf-8); String fileName URLEncoder.encode(会员列表, UTF-8).replaceAll(\\, %20); response.setHeader(Content-Disposition, attachment;filename fileName .xlsx); // 使用 EasyExcel 或 POI 写入数据 EasyExcel.write(response.getOutputStream(), Member.class).sheet(会员列表).doWrite(list); }8.4 通用接口调用示例如果你的项目只提供后端接口其他前端或小程序需要对接可以用 curl 做个快速验证# 分页查询会员列表 curl -X GET http://localhost:8080/api/member/list?pageNum1pageSize10 \ -H Content-Type: application/json # 新增会员 curl -X POST http://localhost:8080/api/member/add \ -H Content-Type: application/json \ -d {name:王五,phone:13912345678,gender:1}后端返回的 JSON 结构统一为{code, message, data}前端或其他系统对接时只需要解析data字段即可。9. 部署运行与答辩演示准备项目开发完成后部署运行的稳定性直接影响答辩演示效果。这里给出一套稳妥的启动流程和答辩前的检查清单。9.1 本地启动流程启动 MySQL 服务确认数据库gym_member已创建并执行建表 SQL 和初始数据脚本。用 IDEA 打开后端项目等待 Maven 依赖下载完成。修改application.yml里的数据库账号密码。启动GymApplication.java控制台出现Started GymApplication表示启动成功。启动前端项目在终端执行npm install安装依赖再执行npm run dev。浏览器访问http://localhost:5173Vite 默认端口或http://localhost:3000。9.2 答辩演示清单答辩前建议按下面的顺序完整走一遍流程登录页面输入管理员账号密码能够正常跳转到首页。首页展示会员总数、本月新增会员、课程数量等统计卡片。进入会员列表演示分页查询、搜索、新增、编辑、删除。新增一个会员填写手机号、姓名、开卡卡种保存后能在列表第一页看到。给这个会员续费查看会员卡到期时间是否正确累加。进入课程管理新增一节课程用刚才的会员预约查看课程人数变化。尝试预约一个已满员的课程界面弹出“课程已满员”提示。导出会员列表检查 Excel 文件内容。全程建议用一条演示数据走完不要中途换账号。展示过程尽量顺畅每个操作之间不要停留太久。10. 资源占用与性能观察健身会员管理系统是典型的 Java Web 应用资源占用不会很高但有一些地方值得观察。10.1 内存占用Spring Boot 应用启动后默认 JVM 堆内存可能在 512MB 到 1GB 之间。如果本机内存紧张可以在 IDEA 的运行配置里调整 JVM 参数-Xms256m -Xmx512m10.2 数据库连接池Spring Boot 默认使用 HikariCP 连接池。如果连接池配置太小并发请求多的时候会出现连接等待。本地开发用默认配置基本够用出现connection is not available时再调大参数spring: datasource: hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 3000010.3 端口与进程残留本地开发常见的坑是上次运行的程序没停干净端口被占用导致新项目起不来。如果遇到Port 8080 was already in use先查占用进程再杀掉。Windows 下的排查命令netstat -ano | findstr 8080 taskkill /F /PID 进程号macOS / Linux 下的排查命令lsof -i :8080 kill -9 进程号11. 常见问题与排查方法Java 毕设项目开发过程中最容易踩的坑集中在依赖、数据库连接、前端跨域这几个方面。整理成一张排查表遇到问题直接对照检查。问题现象可能原因排查方式解决方案Maven 依赖下载失败本地仓库缺包或网络问题检查 IDEA 控制台报错信息配置阿里云镜像删除本地仓库后重新下载启动报 ClassNotFoundException依赖没有正确引入查看pom.xml依赖树执行mvn clean install重新加载依赖数据库连接失败账号密码错误或数据库未启动检查application.yml配置用 Navicat 测试连接确认账号密码Access denied for userMySQL 账号无权限查看 MySQL 用户权限授权GRANT ALL PRIVILEGES ON gym_member.* TO rootlocalhost中文乱码数据库字符集不对检查表字符集建库时使用utf8mb4连接 URL 加characterEncodingutf8Page 页面打不开端口被占用查看控制台日志netstat查端口杀掉占用进程前端请求接口报 403跨域问题打开浏览器开发者工具查看 Network后端添加跨域配置或前端配置代理接口返回 JSON 格式不对实体类字段与数据库字段不匹配查看 MyBatis 映射日志打开map-underscore-to-camel-case新增会员报手机号重复唯一索引冲突查看异常堆栈先查询手机号是否存在再插入表格翻页后数据为空分页参数没传对检查请求参数和 SQL调整 pageNum 起始值和 limit 语句项目启动慢IDE 索引或首启动下载依赖查看启动日志第二次启动就会快换 SSD 效果明显Lombok 注解不生效未安装 Lombok 插件或版本不兼容检查 IDEA 插件列表安装 Lombok 插件开启 Annotation Processing里面最常见也最容易忽视的是 Lombok 的问题。IDEA 社区版需要手动安装 Lombok 插件且需要开启Annotation Processing否则实体类编译时会报找不到 getter/setter 方法。另外再提一个 MyBatis 大坑如果实体类里有createTime字段数据库里是create_time但没有开启驼峰映射查询结果里这个字段就是 null。所有用下划线命名的字段都会踩这个坑务必确认配置mybatis: configuration: map-underscore-to-camel-case: true12. 最佳实践与项目扩展建议到这里整个健身会员管理系统的开发链路已经走完了。最后再给几条实践建议照着做可以让项目质量明显高于普通毕设。12.1 代码规范建议包名按功能分层controller、service、mapper、entity不要全部堆在一个包下面。接口统一返回ResultT结构前端处理逻辑简单一致。数据库操作事务统一管理涉及多条 SQL 的业务方法加Transactional(rollbackFor Exception.class)。参数校验用注解完成比如NotBlank、Pattern避免在业务代码里写一堆 if 判断。敏感字段做脱敏展示手机号列表页显示138****1234身份证号只显示后四位。12.2 项目扩展方向如果想让项目增加亮点以下几个扩展点可以选一两个动手添加登录注册功能使用 Spring Security 或 Sa-Token 做简单权限控制。增加充值账户余额功能对接“余额扣费”场景和续费逻辑构成完整闭环。增加统计报表使用 ECharts 展示每月新增会员趋势、课程预约热度、收入统计。增加 Excel 导入导出能力批量导入会员、导出对账报表。部署到云服务器使用 Docker Compose 一键启动 MySQL 和 Spring Boot 项目展示运维能力。12.3 上线和商用合规提醒如果你后续要把这个系统部署到公网或者商用必须补充几个安全点修改默认数据库账号密码不使用 root 直连。增加登录认证和接口鉴权避免接口裸奔。手机号、身份证号等个人信息需要加密或脱敏存储。定期备份数据库防止数据丢失。如果使用真实健身房的数据必须获得明确授权不得私自收集和展示个人信息。这些内容不一定写进项目代码里但答辩或项目展示时如果能主动讲出来会给评委留下规范意识很强的印象比单纯背八股文有用得多。13. 总结与下一步行动综合来看健身房会员管理系统是一个性价比很高的 Java 毕设选题。它的功能边界清晰不会像电商系统那样复杂到做不完技术深度的可调节空间又不错基础版做 CRUD 能过进阶版加上批量导入导出、数据统计图表也能成为亮点。最先应该验证的功能是会员的增删改查和续费逻辑这是整个系统的核心闭环。把这两条链路跑通再补课程预约项目骨架就完整了。最容易踩的坑是数据库连接配置和 Lombok 插件问题启动前建议先把这两项检查完。如果你正在弄毕设建议按照这篇文章的顺序一步步把代码敲一遍不要直接拿源码跑一下就算完成任务。亲手写完一套 CRUD你对 Spring Boot 的请求流转、MyBatis 的映射关系、MySQL 的建表设计都会有一个直观的理解这份手感写简历和面试时都能用得上。后续可以继续扩展的方向包括接入 Sa-Token 做登录权限、用 ECharts 做首页数据统计大屏、用 Docker Compose 打包部署到服务器。每一步的代码量都不大但能让你的项目和大多数同学的版本拉开差距。这套系统的数据库脚本、后端接口和前端页面代码建议分目录归档后面写简历或做二次开发时可以直接复用。
返回列表