简介这是一套面向高校数据库与Java课程设计初学者的游泳馆管理系统实战项目聚焦中小型场馆日常运营痛点提供会员管理、在线预约、场地调度与收费记账四大核心功能模块助力学生将ER建模、SQL设计、Java Swing/FX界面开发及事务处理等理论知识落地为可运行系统。资源包共1286个文件含28个核心Java源码文件如VIP.java、ManagerDao.java、29个编译后class文件、1132个htm页面构成完整前端界面辅以sql数据库脚本、css/js样式逻辑及gif/png界面资源整体3.81MB结构清晰、模块边界明确便于分层学习与调试。已有1537人学习下载读者可直接导入运行获取完整可执行工程、分模块源码注释、数据库表结构说明及典型业务场景如预约冲突校验、会员等级计费的实现逻辑是理解B/S或C/S架构下业务系统开发流程的优质实践样本。1. 游泳馆管理系统一个能当天部署、次日上线的 Java Web 实战项目专治「人多、场次乱、排班糊、账目不清」的中小型场馆运营痛点某游泳馆老板在微信里发来一张截图前台手写登记表密密麻麻教练排班靠微信群接龙会员续费靠Excel手动对账月底结账花了三天还漏了7个私教课时。这不是段子是真实踩坑现场。这个「游泳馆管理系统」就是为这类场景量身写的——它不堆高大上的微服务架构不用 Docker/K8s 做包装核心功能就四块会员全生命周期管理注册/充值/冻结/退卡、课程与场次智能排程含时段冲突校验、教练排班与课时统计自动关联课消与工资、收银财务流水日结报表支持现金/微信/支付宝三通道。技术栈干净利落Spring Boot 2.7 MyBatis-Plus Thymeleaf Bootstrap 5 H2开发默认 MySQL生产可切JDK 11 编译Maven 管理。整套源码包解压即跑连数据库初始化脚本都封装进src/main/resources/sql/下新手照着 README 里的三行命令就能看到登录页。它不是教学 Demo而是某高校实验室团队为本地三家社区泳馆落地迭代过 5 个版本的真实系统——你拿到手的是删掉客户定制模块、保留主干逻辑、加了完整注释和调试断点的「可交付精简版」。2. 环境准备与一键启动从 JDK 到浏览器登录页全程 12 分钟内完成2.1 开发环境最低要求与验证清单这个项目对环境极其友好但恰恰因为“太简单”新手最容易栽在 JDK 版本或 Maven 配置上。我建议你先执行这三步验证比直接mvn spring-boot:run更省时间提示不要用 JDK 17 或更高版本Spring Boot 2.7 官方仅支持到 JDK 11LTSJDK 17 会触发java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRequest.getHttpServletMapping()这类玄学报错——这是 Spring Boot 2.x 和 Servlet 4.0 的兼容性黑匣子不是你代码的问题。# 1. 检查 JDK 版本必须输出 11.x java -version # 2. 检查 Maven3.6.3 即可推荐 3.8.6 mvn -v # 3. 检查本地是否已占用 8080 端口项目默认端口 netstat -ano | findstr :8080 # Windows lsof -i :8080 # macOS/Linux如果java -version输出的是17.0.1或21.0.2请立刻切换 JDK 11。IntelliJ IDEA 用户可在 Project Structure → Project → Project SDK 中下拉选择命令行用户需配置JAVA_HOME指向 JDK 11 根目录并确保PATH中java命令指向它。别信网上“加-Dspring.mvc.servlet.path/就能硬扛 JDK 17”的偏方——那是给 Spring Boot 3.x 准备的后悔药对本项目无效。2.2 数据库初始化H2 内存库开箱即用MySQL 切换只需改两行项目默认使用 H2 内存数据库好处是零安装、零配置适合快速验证业务逻辑。所有建表语句、初始数据如管理员账号admin/123456、测试会员、默认泳道信息都封装在src/main/resources/sql/schema-h2.sql和># 第一步清理旧编译产物尤其当你之前用错 JDK 编译过 mvn clean # 第二步编译并跳过测试测试用例未覆盖全部跳过不影响功能验证 mvn compile -Dmaven.test.skiptrue # 第三步启动默认激活 h2 配置 mvn spring-boot:run等待控制台输出类似Tomcat started on port(s): 8080 (http)后在浏览器打开http://localhost:8080/login。你应该看到一个蓝白配色、带泳镜图标的登录页。输入默认账号admin/123456点击登录——如果跳转到「仪表盘」页面顶部显示「欢迎回来管理员」且左侧菜单栏有「会员管理」「课程排程」「教练排班」「财务管理」四个主项恭喜你的系统已活了。注意首次登录后系统会自动跳转至/dashboard该页面调用DashboardController.index()它会查询今日预约数、未处理订单、教练出勤率三个聚合指标。如果页面空白或报 500 错大概率是数据库连接失败请回看 2.2 节检查application.yml配置。3. 核心模块拆解从会员注册到课时核销一条请求的完整链路3.1 会员管理模块注册、充值、状态机驱动的生命周期控制会员是整个系统的起点。MemberController是入口但真正决定业务边界的是MemberService中的状态机设计。它没用复杂的状态模式框架而是用枚举 switch 实现轻量级状态流转// src/main/java/com/swim/system/service/impl/MemberServiceImpl.java public boolean recharge(Long memberId, BigDecimal amount) { Member member memberMapper.selectById(memberId); if (member null || !MemberStatus.ACTIVE.equals(member.getStatus())) { throw new BusinessException(会员不存在或已冻结); } // 关键余额不能为负且单次充值上限 5000 元防误操作 if (amount.compareTo(BigDecimal.ZERO) 0 || amount.compareTo(new BigDecimal(5000)) 0) { throw new BusinessException(充值金额需大于0且不超过5000元); } BigDecimal newBalance member.getBalance().add(amount); member.setBalance(newBalance); member.setUpdatedAt(LocalDateTime.now()); return memberMapper.updateById(member) 0; }逻辑说明member.getStatus()返回MemberStatus枚举包含ACTIVE正常、FROZEN冻结、CLOSED销户三种状态recharge()方法强制校验状态冻结会员无法充值这是业务强约束金额校验用compareTo()而非避免 BigDecimal 精度陷阱updatedAt字段由代码显式更新而非依赖数据库ON UPDATE CURRENT_TIMESTAMP保证 Java 层可审计。参数说明memberId路径变量来自PathVariable(id)前端路由/member/recharge/{id}amount请求体 JSON 字段{ amount: 300.00 }经RequestBody绑定抛出BusinessException会被全局异常处理器GlobalExceptionHandler捕获返回统一格式{ code: 400, msg: 充值金额需大于0且不超过5000元, data: null }。3.2 课程排程模块时段冲突检测与泳道资源锁定「课程排程」是高频并发场景。用户选「7月10日 19:00-20:00 儿童蛙泳班」时系统必须同时校验① 该时段该泳道是否已被其他课程占用② 教练在该时段是否有空档③ 班级人数是否超限。核心逻辑在CourseScheduleService.checkConflict()// src/main/java/com/swim/system/service/impl/CourseScheduleServiceImpl.java public boolean checkConflict(LocalDateTime start, LocalDateTime end, Long poolLaneId, Long coachId) { // 1. 查该泳道在 [start, end) 区间内是否有其他课程 QueryWrapperCourseSchedule laneQw new QueryWrapper(); laneQw.eq(pool_lane_id, poolLaneId) .ge(start_time, start) .lt(end_time, end) .ne(status, ScheduleStatus.CANCELLED); // 忽略已取消的排程 if (courseScheduleMapper.selectCount(laneQw) 0) { return false; // 冲突 } // 2. 查该教练在 [start, end) 区间内是否有其他课程含待确认 QueryWrapperCourseSchedule coachQw new QueryWrapper(); coachQw.eq(coach_id, coachId) .ge(start_time, start) .lt(end_time, end) .ne(status, ScheduleStatus.CANCELLED); return courseScheduleMapper.selectCount(coachQw) 0; }逻辑说明使用ge和lt构建左闭右开区间[start, end)这是时间冲突检测的标准做法避免19:00-20:00和20:00-21:00被误判为冲突ne(status, ScheduleStatus.CANCELLED)过滤掉已取消的排程它们不占用资源两次selectCount()是原子操作但未加数据库锁——因为本系统预设并发量 50 QPS用应用层校验 乐观锁version字段足够若你接入高并发场馆需在insert时加SELECT ... FOR UPDATE。参数说明start/endLocalDateTime类型来自前端传入的字符串2024-07-10T19:00经 Spring MVC 自动转换poolLaneId泳道 ID对应pool_lane表主键coachId教练 ID来自coach表。3.3 教练排班模块课时统计与自动出勤标记教练端最关心「我今天上了几节课多少钱」。CoachAttendanceService每日凌晨 2 点触发一次定时任务扫描昨日所有statusCONFIRMED的课程生成出勤记录// src/main/java/com/swim/system/service/impl/CoachAttendanceServiceImpl.java Scheduled(cron 0 0 2 * * ?) // 每天凌晨2点执行 public void generateYesterdayAttendance() { LocalDate yesterday LocalDate.now().minusDays(1); LocalDateTime start yesterday.atStartOfDay(); LocalDateTime end yesterday.plusDays(1).atStartOfDay(); // 查询昨日所有已确认课程 QueryWrapperCourseSchedule qw new QueryWrapper(); qw.between(start_time, start, end) .eq(status, ScheduleStatus.CONFIRMED); ListCourseSchedule confirmedCourses courseScheduleMapper.selectList(qw); for (CourseSchedule course : confirmedCourses) { // 检查是否已存在出勤记录防重复执行 if (attendanceMapper.selectOne( new QueryWrapperCoachAttendance() .eq(coach_id, course.getCoachId()) .eq(schedule_id, course.getId()) ) null) { CoachAttendance attendance new CoachAttendance(); attendance.setCoachId(course.getCoachId()); attendance.setScheduleId(course.getId()); attendance.setDate(yesterday); attendance.setStatus(AttendanceStatus.PRESENT); attendance.setCreatedAt(LocalDateTime.now()); attendanceMapper.insert(attendance); } } }逻辑说明Scheduled注解启用 Spring 定时任务无需 Quartzbetween查询昨日 00:00:00 到今日 00:00:00 的课程覆盖所有跨午夜的晚班插入前selectOne检查是典型的「先查后插」防重逻辑比INSERT IGNORE更可控AttendanceStatus.PRESENT是默认状态教练可登录后手动改为ABSENT或LEAVE。参数说明yesterdayLocalDate用于生成date字段日期类型非时间戳schedule_id关联course_schedule表实现课时与出勤强绑定createdAt记录系统生成时间用于审计。4. 避坑指南那些让我重启三次 IDE 才定位到的典型问题4.1 现象登录页 CSS 加载失败页面纯白无样式原因Thymeleaf 默认开启缓存spring.thymeleaf.cachetrue开发时修改templates/layout.html后未重启浏览器仍加载旧版本导致link th:href{/css/app.css}解析为 404。解决在application-dev.yml中添加spring.thymeleaf.cachefalse并确保启动时激活devprofilemvn spring-boot:run -Dspring.profiles.activedev。4.2 现象会员充值成功但余额未更新数据库字段仍为 NULL原因Member实体类中balance字段用了BigDecimal但数据库member表对应列为DECIMAL(10,2)而 MyBatis-Plus 默认的 TypeHandler 对null值处理异常——当balance为null时updateById()会忽略该字段不执行SET balance ?。解决在Member实体类的balance字段上加TableField(updateStrategy FieldStrategy.NOT_NULL)强制非空才更新或初始化时设private BigDecimal balance BigDecimal.ZERO;。4.3 现象课程排程保存时报org.hibernate.exception.ConstraintViolationException原因course_schedule表有联合唯一索引uk_pool_coach_time泳道教练开始时间但前端传参时start_time是字符串2024-07-10 19:00后端未做格式化MyBatis 插入时因时区或精度问题导致索引失效。解决在CourseScheduleController.save()中用DateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm)显式解析字符串并存为LocalDateTime同时在application.yml中加spring.jackson.date-formatyyyy-MM-dd HH:mm统一 JSON 时间格式。4.4 现象H2 控制台能连但http://localhost:8080/h2-console页面空白原因Spring Boot 2.7 默认禁用 H2 控制台的 Web 资源spring.h2.console.settings.web-allow-othersfalse且 Chrome 98 对localhost的SameSite策略更严格。解决在application-h2.yml中添加spring.h2.console.settings.web-allow-otherstrue并确保访问地址是http://localhost:8080/h2-console不能少/。4.5 现象MySQL 切换后member表中文名显示为?原因MySQL 服务端字符集非utf8mb4或 JDBC URL 缺少characterEncodingutf8mb4serverTimezoneAsia/Shanghai参数。解决检查 MySQL 配置my.cnf中collation-server utf8mb4_unicode_ci和init-connectSET NAMES utf8mb4JDBC URL 改为jdbc:mysql://localhost:3306/swimdb?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/Shanghai。5. 二次开发实战如何快速接入微信支付并生成对账单 PDF5.1 微信支付接入替换收银模块三步嵌入现有流程原系统收银只支持现金和模拟支付。要接入微信支付你不需要重写整个PaymentController只需聚焦三个点统一下单、回调验签、状态同步。第一步在pom.xml引入微信官方 SDK推荐com.github.wechatpay-apiv3!-- 微信支付 v3 SDK -- dependency groupIdcom.github.wechatpay-apiv3/groupId artifactIdwechatpay-apache-httpclient/artifactId version0.4.9/version /dependency第二步创建WechatPayService封装统一下单逻辑。关键在于构造HttpClient时注入平台证书// src/main/java/com/swim/system/service/WechatPayService.java public String createOrder(Long orderId, BigDecimal amount, String description) { // 1. 构建 HttpClient需提前加载平台证书 PrivateKey merchantPrivateKey PemUtil.loadPrivateKey( new FileInputStream(cert/apiclient_key.pem)); AutoUpdateCertificatesVerifier verifier new AutoUpdateCertificatesVerifier( new WechatPay2Credentials(your_mch_id, new PrivateKeySigner(your_serial_no, merchantPrivateKey)), new FileInputStream(cert/wechatpay_cert.pem)); CloseableHttpClient httpClient WechatPayHttpClientBuilder.create() .withMerchant(your_mch_id, your_serial_no, merchantPrivateKey) .withValidator(new WechatPay2Validator(verifier)) .build(); // 2. 构造下单请求体 JsonObject json new JsonObject(); json.addProperty(appid, wx1234567890abcdef); json.addProperty(mchid, your_mch_id); json.addProperty(description, description); json.addProperty(out_trade_no, SWIM orderId); json.addProperty(time_expire, LocalDateTime.now().plusMinutes(15).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); json.add(amount, new JsonObject().addProperty(total, amount.multiply(new BigDecimal(100)).longValue()).addProperty(currency, CNY)); json.add(payer, new JsonObject().addProperty(openid, oABC1234567890abcdef)); // 3. 发起 POST 请求 HttpPost httpPost new HttpPost(https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi); httpPost.setEntity(new StringEntity(json.toString(), UTF-8)); httpPost.setHeader(Accept, application/json); try (CloseableHttpResponse response httpClient.execute(httpPost)) { String body EntityUtils.toString(response.getEntity()); JsonObject result JsonParser.parseString(body).getAsJsonObject(); return result.getAsJsonObject(prepay_id).get(prepay_id).getAsString(); // 返回 prepay_id 供前端调起支付 } }逻辑说明AutoUpdateCertificatesVerifier自动轮询更新微信平台证书避免手动更新time_expire设为 15 分钟符合微信支付超时规则amount.total必须为分单位整数所以amount.multiply(100).longValue()返回prepay_id前端调用wx.requestPayment()时传入。第三步在PaymentController.pay()中根据支付方式路由PostMapping(/pay) public Result pay(RequestBody PaymentRequest request) { if (wechat.equals(request.getPayType())) { String prepayId wechatPayService.createOrder(request.getOrderId(), request.getAmount(), 游泳馆课程支付); return Result.success(Map.of(prepayId, prepayId)); } else if (cash.equals(request.getPayType())) { // 原有现金逻辑 } return Result.fail(不支持的支付方式); }5.2 对账单 PDF 生成用 iText7 替代 JasperReports轻量又可控原系统财务报表只有 HTML 表格。要导出 PDF 对账单我弃用重量级 JasperReports改用 iText7 —— 因为它的 API 直接操作 PDF 元素调试方便且能精准控制每行高度、字体、边框。在FinancialReportService中新增方法// src/main/java/com/swim/system/service/FinancialReportService.java public byte[] generateDailyReport(LocalDate date) throws IOException { ByteArrayOutputStream baos new ByteArrayOutputStream(); PdfWriter writer new PdfWriter(baos); PdfDocument pdfDoc new PdfDocument(writer); Document document new Document(pdfDoc); // 设置中文字体需提前下载 simsun.ttc PdfFont font PdfFontFactory.createFont(fonts/simsun.ttc,0, PdfEncodings.IDENTITY_H); document.setFont(font).setFontSize(10f); // 标题 document.add(new Paragraph(游泳馆日结对账单 - date).setBold().setFontSize(14f).setTextAlignment(TextAlignment.CENTER)); // 表格列宽按内容比例分配 Table table new Table(UnitValue.createPercentArray(new float[]{1, 2, 1, 1, 1})); table.setWidth(UnitValue.createPercentValue(100)); table.addHeaderCell(new Cell().add(new Paragraph(序号).setBold())); table.addHeaderCell(new Cell().add(new Paragraph(会员姓名).setBold())); table.addHeaderCell(new Cell().add(new Paragraph(消费项目).setBold())); table.addHeaderCell(new Cell().add(new Paragraph(金额(元)).setBold())); table.addHeaderCell(new Cell().add(new Paragraph(支付方式).setBold())); // 查询当日流水简化版实际应分页 ListFinancialRecord records financialRecordMapper.selectList( new QueryWrapperFinancialRecord().eq(date, date) ); for (int i 0; i records.size(); i) { FinancialRecord r records.get(i); table.addCell(new Cell().add(new Paragraph(String.valueOf(i 1)))); table.addCell(new Cell().add(new Paragraph(r.getMemberName()))); table.addCell(new Cell().add(new Paragraph(r.getItem()))); table.addCell(new Cell().add(new Paragraph(r.getAmount().toString()))); table.addCell(new Cell().add(new Paragraph(r.getPayType()))); } document.add(table); document.close(); return baos.toByteArray(); }逻辑说明PdfFontFactory.createFont()加载宋体解决中文乱码Table构造时用PercentArray动态分配列宽比固定像素更适应不同长度文本document.add()直接追加元素无模板引擎学习成本返回byte[]Controller 中用ResponseEntitybyte[]直接响应前端可window.open(URL.createObjectURL(blob))预览。参数说明dateLocalDate来自RequestParam(date)FinancialRecord财务流水实体含memberName、item如“儿童蛙泳班 1节”、amount、payTypefonts/simsun.ttc需将字体文件放入src/main/resources/fonts/目录。从那以后我每次接入第三方支付都强制走一遍「沙箱环境全流程」从下单 → 支付 → 回调 → 状态更新 → 通知会员哪怕只是模拟也要让日志里出现完整的SUCCESS链路。因为线上环境一旦漏掉验签或异步通知钱就真进了黑洞。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
Jev框架解析:类型安全的LLM交互与API Key管理实践 1. 从一个让人摸不着头脑的名字说起第一次看到“Jev”这三个字母,我脑子里蹦出来的第一反应是某个开源库的缩写,或者是某位开发者的ID。直到我在几个技术群里反复看到有人问“jev模型官网在哪”“jev密钥怎么申请”“jev在codex里怎么用”,才… · 2026/11/2 17:33:25
悬挂指针与野指针全解析:从use-after-free排查到防御性编码 1. 悬挂指针不是"野指针":先把概念拆开揉碎我见过不少初学者把这两个词混着用,结果在排查问题时方向就偏了。悬挂指针(dangling pointer)指的是那块内存曾经属于你、你确实拥有过它、后来你把它还回去了,但指… · 2026/11/2 17:33:25
TreeSizeFree:DBA必备的磁盘空间分析利器 1. 磁盘空间告急:DBA运维的日常痛点凌晨三点,服务器告警短信又一次把我从睡梦中惊醒。磁盘空间不足的红色警告在监控大屏上闪烁,而距离早高峰业务流量到来只剩四个小时。这已经是本月第三次了——我熟练地SSH登录服务器,开始逐层执… · 2026/11/2 17:33:25
219行代码手写Playwright元素拾取器:自动生成稳定选择器 1. 从零造一个元素拾取器:为什么我要自己动手浏览器里点一下页面元素,就能自动生成稳定的选择器,这个需求做自动化测试和爬虫的人应该都不陌生。Chrome DevTools 自带的那个拾取工具,用过的人都知道,生成的选择器经常是… · 2026/11/3 5:33:04
219行JS元素拾取器:快速生成Playwright定位信息 1. 一个 219 行脚本的由来先说清楚这东西是什么。它是一个浏览器端的元素拾取器,总共 219 行 JavaScript,跑在 Chrome DevTools 的 Console 里或者通过 Playwright 的page.evaluate()注入,作用就一件事:你在页面上移动鼠标&#x… · 2026/11/3 5:33:04
RISC-V与AI融合:编译器优化技术解析 1. 项目概述:RISC-V与AI融合的技术革命在2025年全球C及系统软件技术大会上,一个名为"从开放指令集到开源算子和编译器:RISC-VAI的全栈软件生态突破路径"的主题演讲引起了广泛关注。这个主题直指当前计算架构领域最前沿的两个技术方… · 2026/11/3 5:33:04
219行纯JS元素拾取器:自动化测试选择器生成实战 1. 一个 219 行的“小轮子”,为什么值得单独写一篇先说清楚这篇要聊的东西是什么。元素拾取器(element-picker)本质上是一个跑在浏览器里的交互脚本:你打开一个页面,点一下某个按钮,它就能把你点中的那个 D… · 2026/11/3 5:33:04
单向链表核心操作与高级应用全解析 1. 单向链表基础概念与核心特性单向链表作为最基础的链式数据结构,由一系列节点组成,每个节点包含两个部分:数据域和指针域。数据域存储实际数据,指针域存储下一个节点的内存地址。这种结构决定了单向链表在内存中不必连续存储&am… · 2026/11/3 5:33:04
WorkBuddy技能体系全解析:15个必装技能与配置指南 1. 为什么这份技能清单值得你花三分钟看完先说结论:WorkBuddy是那种典型的“下崽容易、吃透难”的效率工具。我见过不少人装了它,然后因为不知道怎么把技能串起来用,最后当普通聊天窗口使。这其实挺亏的。所谓Skills,在WorkBuddy里… · 2026/11/3 5:32:04
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18