Java校园打印预约系统:高并发场景下的事务与状态管理实战
简介本资源是一份完整的Java毕业设计文档面向计算机专业本科生及Java初学者聚焦校园场景下的数字化服务痛点解决传统打印排队耗时长、资源调度不均等实际问题。文档详细阐述了基于B/S架构的在线打印预约系统的设计与实现全过程涵盖用户端登录、文件上传、订单查询、共享管理与管理员端订单处理、设备与文件管理双角色功能模块并说明了VueSpring BootMySQL的技术选型逻辑、IDEA与Navicat开发环境配置及系统灵活性、高效性与可扩展性优势。资源为单个2.63MB的Word文档.docx内容包含中英文摘要、原创声明、目录、引言、需求分析、技术实现说明等标准毕业论文结构含完整系统设计思路与关键技术实现要点。目前已有185人学习下载适合用于毕业设计参考、Java Web项目复现、课程设计选题拓展及B/S架构实践学习。1. 校园打印预约系统为什么不能只靠微信接单Java后端如何扛住课间10分钟并发洪峰某高校信息中心曾用企业微信群手动接单学生发“张三-23号楼-3页双面”管理员手敲Excel、再U盘拷到打印机。结果每到考试周群消息999漏单率超35%打印室门口排长队学生投诉“交了钱却打不出论文”。这暴露了三个硬伤身份无法自动核验谁是本校师生、订单状态不可追溯我的文件卡在哪一步、资源调度全靠人盯哪台打印机空闲纸张余量多少。而“基于Java校园在线打印预约系统”正是为解决这类高频、低容错、强事务场景设计的落地方案——它不是炫技的微服务Demo而是用Spring BootMyBatisMySQL在真实机房里跑满一学期的生产级系统。核心价值很朴素学生扫码即约、实时查进度、失败自动退费管理员看一张大屏就掌握全校27台打印机的负载、耗材、故障财务按日生成对账单误差趋近于零。如果你正被类似需求压得喘不过气或正在写课程设计/毕设需要可演示、可答辩、可上线的Java项目这篇笔记就是你跳过90%弯路的实操地图。2. 从零搭起可运行骨架Spring Boot 2.7 MyBatis Plus最小可行工程2.1 初始化工程用官方脚手架避坑JDK版本冲突提示务必用JDK 11非8或17Spring Boot 2.7.x对JDK 17支持不完善本地调试时出现java.lang.NoClassDefFoundError: javax/xml/bind/JAXBContext即为典型症状。访问 start.spring.io 注意非国内镜像站避免依赖包缺失勾选以下模块Spring WebSpring Data JDBC替代JPA轻量且兼容老MySQL驱动Lombok减少getter/setter代码量Validation用于预约表单校验MySQL Driver生成ZIP后解压用IDEA打开关键操作# 在项目根目录执行强制指定JDK 11编译 ./gradlew build --no-daemon -Dorg.gradle.java.home/Library/Java/JavaVirtualMachines/jdk-11.0.2.jdk/Contents/Home2.2 数据库建模三张表撑起核心业务流不追求过度设计按“预约-打印-计费”主链路建表。实际部署中某高校实验室用此结构支撑日均1200订单无锁表现象表名字段精简关键字段说明t_userid(BIGINT PK),student_id(VARCHAR 16),name(VARCHAR 20),campus_code(CHAR 2)campus_code存ABA校区/B校区避免跨校区预约无效t_printerid(BIGINT PK),ip_addr(VARCHAR 15),location(VARCHAR 50),status(TINYINT)status0空闲/1忙/2缺纸/3卡纸不用轮询用MQ通知变更t_orderid(BIGINT PK),user_id(BIGINT FK),printer_id(BIGINT FK),file_path(VARCHAR 255),page_count(INT),is_double_sided(TINYINT),status(TINYINT),create_time(DATETIME)status0待处理/1已分发/2打印中/3完成/4失败状态机必须用数据库行锁更新执行建表SQL含索引优化CREATE TABLE t_order ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, printer_id BIGINT NOT NULL, file_path VARCHAR(255) NOT NULL, page_count INT NOT NULL DEFAULT 1, is_double_sided TINYINT NOT NULL DEFAULT 0, status TINYINT NOT NULL DEFAULT 0, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_user_status (user_id, status), -- 学生查自己订单快 INDEX idx_printer_status (printer_id, status) -- 打印机任务队列快 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;2.3 配置文件YAML里藏了80%的线上稳定性application-prod.yml生产环境关键配置spring: datasource: url: jdbc:mysql://192.168.1.100:3306/print_db?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: print_app password: Pssw0rd2024 # 生产环境必须用密文此处仅为示意 hikari: maximum-pool-size: 20 # 并发峰值预估27台打印机×2线程54但数据库连接池20足够 minimum-idle: 5 connection-timeout: 30000 validation-timeout: 3000 idle-timeout: 600000 max-lifetime: 1800000 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开发期开上线关 global-config: db-config: id-type: assign_id # Snowflake ID避免MySQL自增ID暴露业务量3. 预约流程的原子性保障分布式事务不是银弹数据库行锁才是3.1 “选打印机-传文件-扣余额”三步必须在一个事务内完成学生点击“预约”按钮后前端提交JSON{ studentId: 20221001, printerId: 15, fileBase64: JVBERi0xLjQKJeLjz9MKMyAwIG9iago8PCAvVHlwZSAvUGFnZQovUGFyZW50IDQgMCBSCi9Db250...省略, pageCount: 5, isDoubleSided: true }后端Controller层严格校验PostMapping(/api/v1/order) Transactional(rollbackFor Exception.class) public ResultOrderVO createOrder(RequestBody OrderRequest request) { // 1. 校验学生身份查t_user表 User user userMapper.selectOne(new QueryWrapperUser().eq(student_id, request.getStudentId())); if (user null) throw new BizException(学号不存在请联系教务处); // 2. 检查打印机状态行锁 Printer printer printerMapper.selectById(request.getPrinterId()); if (printer null || printer.getStatus() ! 0) { // 0空闲 throw new BizException(打印机暂不可用请换一台); } // 3. 扣费前检查余额假设用独立账户表此处简化为伪代码 if (!accountService.deductBalance(user.getId(), calculateFee(request))) { throw new BizException(余额不足); } // 4. 创建订单此时才插入t_order Order order new Order(); order.setUserId(user.getId()); order.setPrinterId(request.getPrinterId()); order.setPageCount(request.getPageCount()); order.setIsDoubleSided(request.getIsDoubleSided() ? (byte)1 : (byte)0); order.setStatus((byte)0); // 待处理 order.setFilePath(saveFileToNFS(request.getFileBase64())); // 存到网络文件系统非本地磁盘 orderMapper.insert(order); // 5. 更新打印机状态为忙关键用UPDATE ... WHERE status0防止并发覆盖 int updated printerMapper.update(null, new UpdateWrapperPrinter() .eq(id, request.getPrinterId()) .eq(status, 0) // 只有空闲状态才允许更新 .set(status, 1)); if (updated 0) { throw new BizException(打印机已被占用请重试); } return Result.success(new OrderVO(order.getId(), 预约成功)); }3.2 为什么不用Seata/XA真实场景下的取舍逻辑某公司曾用Seata管理“扣费下单发MQ”三阶段结果课间高峰时TCTransaction Coordinator节点CPU飙到95%订单创建延迟超8秒。复盘发现扣费与下单本质是强一致性必须同库同事务否则出现“扣了钱但没下单”的资损发MQ通知打印服务是最终一致性哪怕MQ短暂不可用后台定时任务也能补偿MySQL行锁粒度够用UPDATE t_printer SET status1 WHERE id? AND status0这条语句在InnoDB下是行锁条件锁比分布式事务轻量10倍。所以本系统放弃分布式事务框架用“数据库本地事务幂等MQ”组合// 订单创建成功后发MQRabbitMQ通知打印服务 rabbitTemplate.convertAndSend(print.exchange, order.created, new PrintTask(order.getId(), order.getFilePath(), order.getPageCount()));注意MQ消息体必须含唯一业务ID如order.id打印服务消费时先查t_order确认状态避免重复打印。4. 打印机状态同步的玄学为什么轮询是反模式MQ心跳才是正解4.1 打印机端Agent的设计哲学轻量、自愈、无状态每台打印机旁部署一个树莓派或Windows PC运行Java Agent程序其核心逻辑只有三件事每5秒向服务器POST心跳携带printer_id、paper_level纸张余量百分比、error_code0正常/1卡纸/2缺墨监听MQ队列收到print.task消息后调用CUPS命令行打印Linux或ShellExecuteWindows打印完成后回调APIPUT /api/v1/order/{id}/status?status3更新订单状态。Agent心跳接口Controller层PutMapping(/api/v1/printer/{id}/heartbeat) public ResultVoid updateHeartbeat( PathVariable Long id, RequestBody PrinterHeartbeatDTO dto) { // 用Redis做高频写入缓冲防刷每台打印机1分钟最多更新12次 String key heartbeat: id; Long count redisTemplate.opsForValue().increment(key, 1); redisTemplate.expire(key, 60, TimeUnit.SECONDS); if (count 12) { throw new BizException(心跳频率超限); } // 更新数据库非高频操作仅当状态变化时才更新 Printer printer new Printer(); printer.setId(id); printer.setPaperLevel(dto.getPaperLevel()); printer.setErrorCode(dto.getErrorCode()); printer.setStatus(calculateStatus(dto)); // 根据error_code和paper_level算出0/1/2/3 printerMapper.updateById(printer); return Result.success(); }4.2 前端实时状态看板用WebSocket替代Ajax轮询学生查订单进度、管理员看大屏若用setInterval(() axios.get(/api/v1/order/123), 2000)1000个用户同时在线将产生500QPS无效请求。改用WebSocket后端启用WebSocketpom.xml加spring-boot-starter-websocket建立连接时前端传userId或printerId后端存入ConcurrentHashMapString, Session当订单状态变更如status3完成服务端精准推送// 订单完成时触发 public void notifyOrderComplete(Long orderId) { Order order orderMapper.selectById(orderId); String userIdKey user: order.getUserId(); Session session sessionMap.get(userIdKey); if (session ! null session.isOpen()) { session.getAsyncRemote().sendText( JSON.toJSONString(new OrderStatusUpdate(orderId, 3))); } }玄学提示某次部署后发现WebSocket连接数暴涨但无推送排查发现是Nginx未配置WebSocket升级头需在nginx.conf中加入location /ws/ { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; }5. 避坑指南那些让系统在凌晨2点报警的5个血泪经验5.1 现象学生上传PDF后显示“解析失败”但同一文件在本地测试正常原因前端用FileReader.readAsDataURL()读取大文件5MBBase64编码后体积膨胀33%且部分老旧浏览器IE11对长字符串截断。更致命的是后端RequestBody默认最大接收4MB。解决前端改用FormData分块上传axios.post(/upload, formData)后端application.yml增加spring: servlet: context-path: /print web: resources: static-locations: classpath:/static/ http: multipart: max-file-size: 50MB max-request-size: 50MB5.2 现象高峰期MySQL CPU 100%SHOW PROCESSLIST显示大量UPDATE t_printer ...阻塞原因打印机心跳更新未加WHERE条件每次都是全表扫描更新。原始SQLUPDATE t_printer SET status1 WHERE id15看似正确但缺少AND status!1条件。解决心跳更新必须带状态过滤UPDATE t_printer SET status?, paper_level?, error_code? WHERE id? AND (status!? OR paper_level!? OR error_code!?)对t_printer.status字段加索引ALTER TABLE t_printer ADD INDEX idx_status (status);5.3 现象管理员后台导出Excel报表时Tomcat直接OOM原因用Apache POI的XSSFWorkbook基于DOM加载万行数据内存占用达300MB。解决改用SXSSFWorkbook基于流式写入SXSSFWorkbook workbook new SXSSFWorkbook(100); // 每100行刷入磁盘 Sheet sheet workbook.createSheet(订单报表); // 写入数据... try (OutputStream out response.getOutputStream()) { workbook.write(out); } finally { workbook.dispose(); // 关键释放临时文件 }5.4 现象学生反馈“预约成功但没打印”查数据库status1已分发却无后续原因MQ消息发送后打印Agent因网络问题未消费但后端未设置死信队列DLX消息直接丢弃。解决RabbitMQ声明队列时启用DLXBean public Queue printTaskQueue() { MapString, Object args new HashMap(); args.put(x-dead-letter-exchange, dlx.exchange); args.put(x-dead-letter-routing-key, dlx.print.task); return QueueBuilder.durable(print.task.queue).withArguments(args).build(); }死信队列绑定到告警服务超30分钟未消费则短信通知管理员。5.5 现象跨校区预约时A校区学生能预约B校区打印机但文件传输超时原因文件存储用本地路径/data/print/files/未考虑多校区网络隔离。B校区打印机Agent无法访问A校区服务器的NFS路径。解决文件存储抽象为FileStorageService接口实现类根据campus_code路由Service public class FileStorageService { public String save(String campusCode, byte[] content) { if (A.equals(campusCode)) { return nfsA.save(content); // A校区NFS } else if (B.equals(campusCode)) { return nfsB.save(content); // B校区NFS } throw new BizException(校区代码错误); } }6. 真实压测与上线技巧用200行脚本摸清系统瓶颈6.1 用JMeter模拟课间并发定位第一个断点不迷信“支持1000QPS”的宣传亲手压测下载JMeter 5.6新建线程组线程数200模拟200学生同时点预约、Ramp-Up10秒10秒内启动完、循环次数1HTTP请求配置Path:/api/v1/orderBody DataJSON{ studentId: ${__RandomString(8,abcdefghijklmnopqrstuvwxyz0123456789)}, printerId: ${__Random(1,27)}, fileBase64: ${__base64Encode(${__RandomString(10000,a)})}, pageCount: ${__Random(1,10)}, isDoubleSided: ${__Random(0,1)} }添加“聚合报告”监听器重点关注90% Line90%请求响应时间和Error %。某次实测结果并发数90%响应时间错误率瓶颈定位100320ms0%无瓶颈2001250ms0.3%MySQL连接池打满active203003800ms12%JVM Full GC频繁堆内存不足对策将hikari.maximum-pool-size从20调至30Tomcat启动参数加-Xms1024m -Xmx1024m -XX:UseG1GC再压测200并发90%响应时间降至410ms错误率归零。6.2 上线前必做的3个验证动作数据库连接泄漏检测在application-prod.yml中开启HikariCP监控hikari: leak-detection-threshold: 60000 # 60秒未归还连接即告警上线后观察日志若出现Connection leak detection triggered说明某处try-with-resources未关闭SqlSession。文件存储路径权限验证# 在部署服务器执行确保应用用户可读写 sudo -u printapp ls -ld /data/print/files/ sudo -u printapp touch /data/print/files/test.tmp sudo -u printapp rm /data/print/files/test.tmpMQ消息积压预警编写Python脚本定时检查RabbitMQ队列深度import requests import json # 调用RabbitMQ Management API res requests.get(http://localhost:15672/api/queues/%2F/print.task.queue, auth(guest, guest)) if res.json()[messages] 1000: send_alert(print.task.queue积压超1000条)我带过的几个学生团队最常翻车的不是代码写错而是上线前没做这三件事——尤其是文件权限某次因/data/print/files/属主是root应用以printapp用户运行导致所有上传失败排查了6小时才发现。现在我的习惯是任何涉及IO的操作上线前必用目标用户身份手动执行一遍最小流程。比如sudo -u printapp java -jar app.jar启动然后curl发个预约请求看日志是否报Permission denied。这种土办法比读十篇文档都管用。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

AI清洗数据的误判风险:异常值不是错误而是业务信号

AI清洗数据的误判风险:异常值不是错误而是业务信号

1. 项目概述:为什么“清洗数据”正在变成一场高风险认知手术“用AI清洗数据,最危险的不是漏掉异常值,而是把异常当成错误”——这句话我第一次在某高校数据科学实验室的白板上看到时,手里的咖啡杯停在半空。它没讲技术参数&#x…

2026/10/10 10:43:06 阅读更多 →
数据脱敏工具从0到1实战:算法选型、系统架构与工程落地

数据脱敏工具从0到1实战:算法选型、系统架构与工程落地

数据脱敏这件事,我之前在某个公司内部折腾过整整一个季度。当时业务方天天来问"测试环境的数据什么时候能到位",安全合规那边又卡着不让生产数据直接同步,两边扯皮,最后倒霉的都是我们做平台的。后来干脆自己动手&#…

2026/10/10 10:43:06 阅读更多 →
Redis主从复制全解析:从全量同步到增量续传与双缓冲区配置

Redis主从复制全解析:从全量同步到增量续传与双缓冲区配置

1. 主从复制是Redis集群数据一致性的底座Redis主从复制,也就是通过replicaof命令在节点之间建立的数据同步关系,是整个Redis高可用体系里最基础也最关键的一块。很多人平时只关注读写性能和缓存命中率,却很少在意主节点后面的从节点是不是跟得…

2026/10/10 10:43:06 阅读更多 →

最新新闻

高通 IQ9075 大模型 Benchmark 全维度实测:从算力基准到场景落地,TaoToken 统一 Key 打通评测链路

高通 IQ9075 大模型 Benchmark 全维度实测:从算力基准到场景落地,TaoToken 统一 Key 打通评测链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 15:59:48 阅读更多 →
同一数据库中两个表间复制数据:用 TaoToken 统一 Key 打通 AI 辅助 SQL 生成与校验

同一数据库中两个表间复制数据:用 TaoToken 统一 Key 打通 AI 辅助 SQL 生成与校验

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 15:59:48 阅读更多 →
5 分钟用 Ollama 跑 DeepSeek Coder 33B:VS Code 自动补全 + Gradio 本机 Web Chat 全流程

5 分钟用 Ollama 跑 DeepSeek Coder 33B:VS Code 自动补全 + Gradio 本机 Web Chat 全流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 15:59:48 阅读更多 →
FRFT做LFM参数估计:原理、离散实现与工程避坑指南

FRFT做LFM参数估计:原理、离散实现与工程避坑指南

简介:这份资源面向雷达、通信与信号处理方向的学习者和研究人员,聚焦线性调频(LFM)信号的参数估计问题,借助分数阶傅里叶变换(FRFT)在时频域上揭示信号时变频率特性,从而提取中心频率…

2026/10/10 15:59:48 阅读更多 →
YOLOv8-pose本地部署实战:从环境搭建到跌倒检测

YOLOv8-pose本地部署实战:从环境搭建到跌倒检测

简介:本资源是一套开箱即用的人体姿势识别实战方案,面向人工智能初学者、计算机视觉开发者及教学实践者,解决图片与视频中人体关键点检测与姿态分析的快速落地问题。压缩包共4个文件(31.33MB),含YOLOv8s-po…

2026/10/10 15:59:47 阅读更多 →
从零打造Linux无线热点:hostapd配置实战与排错指南

从零打造Linux无线热点:hostapd配置实战与排错指南

聊到把一台普通Linux设备变成无线热点,绕不开的工具就是hostapd。我在实际项目里用它把一台旧笔记本和一张USB无线网卡改造成了机房临时调试用的接入点,说实话,这个工具配置起来不算难,但坑确实不少,尤其是初学者容易卡…

2026/10/10 15:58:46 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:25 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →