尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Spring Boot在线视频教育平台:视频上传、转码、鉴权播放全链路实战
简介这套基于Java与Spring Boot的在线视频教育平台毕业设计资源包面向高校计算机相关专业毕业生及初入行的Java开发者完整覆盖从选题开题、系统设计到编码测试的毕业设计全流程。包体约154MB内含项目源代码、数据库脚本db.sql、毕业设计论文、答辩PPT、演示录像、运行教学指南及常用开发工具下载说明含idea、eclipse、tomcat、mysql、Navicat等可帮助用户快速搭建开发环境并复现视频播放、用户注册登录、课程选择、在线互动等核心功能。代码结构清晰配合演示录像与运行教学能有效降低环境配置门槛论文部分则详细给出了技术选型、系统架构及关键难点解决方案便于理解整个项目的设计思路。目前已有67人学习下载适合需要完整参考方案、动手实践或快速搭建在线教育平台的开发者学习使用。1. 在线视频教育平台的毕业设计难题不在 CRUD 而在资源链路把“在线视频教育平台”当毕业设计课题来做的同学第一反应通常是写一个课程管理后台再加一个视频播放页面就交差。但评审老师的关注点往往不在这里视频怎么上传、怎么防盗链、付费课程凭什么只有购买用户能看、同时在线几百人时学习记录表会不会被写爆。这些问题全部指向同一条资源链路上传 - 存储 - 转码 - 鉴权 - 播放 - 学习记录。这篇博文就按这条链路把 Spring Boot 后端、MySQL 数据库和 Nginx 点播配置完整过一遍附带可以直接抄走的建表 SQL、接口代码和部署步骤。适合 Java 基础过关、Spring Boot 能跑 starter 但没做过完整视频业务的同学也适合需要靠这些材料支撑论文和答辩的熟人。2. Spring Boot 骨架先行在线视频教育平台的模块划分与依赖取舍2.1 按业务模块分包而不是按 controller/service 分包日常公司项目里按层分包很常见但毕业设计不建议这么做。原因是中期答辩时老师会问一句“课程模块和订单模块的接口分别在哪里”如果你是 com.example.controller 这种扁平结构得翻半天。在线视频教育平台的业务边界其实非常清晰用户、课程、订单、视频、学习记录。我一般用 maven 多模块工程拆成 backend 和 commonbackend 内再按业务分包com.example.edu ├── common # 统一返回、异常、工具类 ├── member # 用户登录注册、讲师资料 ├── course # 课程增删改查、章节管理 ├── video # 视频上传、转码信息、播放签名 ├── order # 订单、支付回调 └── study # 学习记录、播放进度这种分包方式有个额外好处写论文的功能模块图可以直接按包名画不用重新整理逻辑。代码结构即业务结构。2.2 一套能过中期检查的 pom.xml 依赖清单版本选择上先解决一个问题JDK 版本。Spring Boot 3.x 强制要求 JDK 173.2 之后的版本对 JDK 21 也有支持如果电脑里装的是 JDK 8硬追 Spring Boot 3.x 会在创建项目时就报编译错误。常见做法是JDK 8 配 Spring Boot 2.7.xJDK 17 再考虑 3.2。不要因为“版本要高”就选最新毕业设计的重点是能跑、能演示。parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version /parent dependencies !-- Web 基础 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- 数据库访问用 MyBatis-Plus 减少手写 SQL 量 -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.5/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency !-- JWT 鉴权 -- dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-api/artifactId version0.11.5/version /dependency !-- 热部署演示时改代码不用重启 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-devtools/artifactId scoperuntime/scope /dependency /dependencies这段依赖里需要注意两个版本关联MyBatis-Plus 3.5.x 对 Spring Boot 2.x 兼容良好但如果你换用 3.5.3 以下的旧版本和 Spring Boot 3 的 jakarta 命名空间会冲突mysql-connector-java 8.0 驱动类名是com.mysql.cj.jdbc.Driver不是老项目里的com.mysql.jdbc.Driver。2.3 第一个可运行接口课程分页查询骨架搭好后我习惯先写一个分页查询接口验证数据库链路通不通总比一上来就写视频上传要容易排错。RestController RequestMapping(/api/course) public class CourseController { Resource private CourseService courseService; GetMapping(/page) public ResultIPageCourseVO page( RequestParam(defaultValue 1) long current, RequestParam(defaultValue 10) long size, RequestParam(required false) String category) { PageCourse page new Page(current, size); LambdaQueryWrapperCourse wrapper new LambdaQueryWrapper(); wrapper.eq(StringUtils.hasText(category), Course::getCategory, category); wrapper.orderByDesc(Course::getSort); IPageCourseVO result courseService.selectWithChapterCount(page, wrapper); return Result.success(result); } }current和size是 MyBatis-Plus 分页插件的两个标准参数defaultValue保证前端不传参数时不会报错。StringUtils.hasText只做有值过滤避免 category 为空字符串时拼进 SQL。这里的selectWithChapterCount是自定义方法返回的 CourseVO 里额外带一个章节数量字段让课程列表页不用再发一遍明细查询。3. 数据库设计才是论文核心E-R 图、建表 SQL 与字段约束3.1 从 E-R 图反推表结构而不是先建表再画图数据库课程设计评分里最重要的一项就是 E-R 图。很多同学是先写 SQL 建表再去画 E-R 图结果图画出来关系对不上答辩时圆不回来。正确顺序反过来先把实体和关系列出来。在线视频教育平台最少要有 6 张表用户表、课程表、课程章节表、视频资源表、订单表、学习记录表。关系如下一个用户可以是学员也可以是讲师用角色字段区分一个课程属于一个讲师包含多个章节一个章节对应一个视频资源一个学员可以购买多个课程产生订单一个学员学习一个课程产生多条学习记录。3.2 核心建表 SQL字段名和注释一次写对下面是论文级别的建表脚本字段命名统一用下划线注释写完整评审老师会直接看这几项。CREATE TABLE edu_user ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 用户ID, username VARCHAR(50) NOT NULL COMMENT 登录名, password VARCHAR(100) NOT NULL COMMENT BCrypt密文, real_name VARCHAR(30) DEFAULT NULL COMMENT 真实姓名, role TINYINT NOT NULL DEFAULT 2 COMMENT 角色1讲师,2学员, avatar VARCHAR(255) DEFAULT NULL COMMENT 头像地址, status TINYINT NOT NULL DEFAULT 1 COMMENT 状态1正常,0禁用, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB COMMENT用户表; CREATE TABLE edu_course ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 课程ID, teacher_id BIGINT NOT NULL COMMENT 讲师用户ID, title VARCHAR(100) NOT NULL COMMENT 课程标题, category VARCHAR(50) DEFAULT NULL COMMENT 分类, cover VARCHAR(255) DEFAULT NULL COMMENT 封面图URL, price DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT 价格0为免费, status TINYINT NOT NULL DEFAULT 0 COMMENT 状态0待审核,1已上架,2已下架, sort INT NOT NULL DEFAULT 0 COMMENT 排序权重, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_teacher (teacher_id) ) ENGINEInnoDB COMMENT课程表;剩下四张表的字段核心逻辑我列成对照关系课程章节表(edu_chapter) 用course_id关联课程用sort_no控制章节顺序包含video_id指向视频资源表视频资源表(edu_video) 记录原始文件名、存储路径、转码状态、时长和文件大小转码状态用0待转码 1转码中 2转码完成 3失败四个数字订单表(edu_order) 用唯一订单号order_no金额字段必须用 DECIMAL不能用 FLOAT学习记录表(edu_learning_record) 用course_id user_id作为联合唯一索引每次播放暂停时更新last_position。这个数据模型覆盖了 8 成以上同类论文的必需查询按讲师找课程、按课程找章节、按用户找购买记录、按学习记录断点续播。3.3 三个表设计防坑点第一外键约束能不用就不用。毕业设计论文里画 E-R 图标注关系即可物理外键在数据导入和删除时会制造麻烦建议只在逻辑层维护关系。第二用户表密码字段长度设 100不要只给 20BCrypt 加密后固定 60 字符但后续升级加密算法需要余量。第三price用 DECIMAL(10,2)答辩时如果被问到“为什么不用 double”直接回答“double 在金额计算上有精度丢失DECIMAL 是定点数”。这个问题几乎是数据库必问。4. 视频上传、转码切片与鉴权播放把资源链路落到 Spring Boot 和 Nginx4.1 存储方案本地磁盘还是对象存储在线视频教育平台里视频是核心资产。对象存储适合生产环境但毕业设计没有云资源预算本地磁盘更现实。做法是视频文件存/data/edu/video目录封面图存/data/edu/image用 Nginx 直接挂这两个目录做静态访问。后端只负责把文件写进磁盘并记录路径。这里要提前在application.yml里把路径抽成配置项edu: video: storage-path: /data/edu/video image-path: /data/edu/image play-domain: https://your.domain.com把路径抽出来有实际意义开发环境用/Users/xxx/edu服务器上用/data/edu换环境时只改配置不用动代码。很多同学把绝对路径写死在 Controller 里答辩部署换路径后到处找硬编码非常被动。4.2 大视频分段上传前端切片后端按序号合并普通MultipartFile接口只适合传小文件项目演示时上传一个 1GB 的教学视频HTTP 连接随时可能断所以视频上传要做校验“进度条”。标准的实现是前端把文件切成 5MB 一个的块按块上传全部传完后通知后端合并。RestController RequestMapping(/api/video) public class VideoUploadController { Resource private VideoResourceMapper videoResourceMapper; PostMapping(/chunk) public ResultString uploadChunk(RequestParam String uploadId, RequestParam Integer chunkIndex, RequestParam MultipartFile file) { String chunkDir /data/edu/tmp/ uploadId; File dir new File(chunkDir); if (!dir.exists()) { dir.mkdirs(); } try { String chunkName String.format(%05d, chunkIndex); file.transferTo(new File(chunkDir, chunkName)); } catch (IOException e) { return Result.error(分片上传失败 e.getMessage()); } return Result.success(ok); } }uploadId由前端在开始上传时生成推荐直接取UUID保证同一文件的所有分片归组chunkIndex从 0 开始编号后端用%05d格式化成固定位数的文件名这样合并时按文件名排序就是正确顺序。全部上传完成后前端再调/api/video/merge?uploadIdxxfileNamexx后端把分片依次写入目标文件并删除临时目录。合并接口还需要做一件事把完整文件的 MD5 写入视频资源表后续做秒传比对用。4.3 FFmpeg 转码切片Nginx 输出 HLS 流视频传完不能直接播原始 MP4。浏览器解码能力有限而且 MP4 的 moov 元数据如果放在文件尾部必须等整个文件下载才能开始播放。毕业设计里最稳的做法是转成 HLS 流用 FFmpeg 把视频切成一段一段的.ts文件生成一个.m3u8索引文件播放器只拉需要的片段。ffmpeg -i input.mp4 \ -c:v libx264 -c:a aac \ -hls_time 10 \ -hls_list_size 0 \ -hls_segment_filename /data/edu/video/lesson01_%03d.ts \ /data/edu/video/lesson01.m3u8参数含义-c:v libx264和-c:a aac指定视频和音频编码保证所有浏览器能解-hls_time 10表示每个切片约 10 秒-hls_list_size 0让 m3u8 索引保留全部分片列表而不是默认只留最近几个-hls_segment_filename定义切片命名规则。转码时间取决于机器性能教学视频 720p 转码耗时约为视频时长的一半演示前要留出时间。Nginx 配置一个静态目录来输出这些文件server { listen 443 ssl; server_name your.domain.com; # 视频目录alias 会替换 /video/ 前缀后拼接路径 location /video/ { alias /data/edu/video/; add_header Cache-Control public, max-age3600; types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } } }alias和root的区别是这里最大的坑root会把完整 URL 路径拼在根目录后面而alias用后面的路径替换掉 location 前缀。add_header Cache-Control加快重复播放的速度types里有的是让浏览器识别 m3u8 和 ts 的 MIME 类型不加这两个类型Chrome 可能直接下载而不是播放。4.4 播放签名让视频 URL 不能直接复制分享HLS 地址暴露之后任何人拿到 m3u8 都能直接播放付费课程等于白给。常见的做法是给播放地址加一个带时效的签名参数public String buildSignedM3U8Url(Long courseId, String m3u8Path) { long expire System.currentTimeMillis() / 1000 3600; String secret edu-secret-key; String raw expire : m3u8Path : secret; String sign DigestUtils.md5DigestAsHex(raw.getBytes()).substring(0, 16); return /video/ courseId /index.m3u8?expire expire sign sign; }签名规则并不复杂把过期时间、文件路径、密钥拼在一起算 MD5取前 16 位连同过期时间一起放在 URL 上。Nginx 里的校验可以通过 Lua 脚本做也可以在后端加一个拦截器先校验再重定向到真实地址。毕业论文里把这个逻辑写成“防盗链签名设计”是一个独立的技术亮点很多同学的论文根本没有这一节。播放端用 video.js 的 HLS 插件就能承接link hrefhttps://cdn.jsdelivr.net/npm/video.js/dist/video-js.min.css relstylesheet script srchttps://cdn.jsdelivr.net/npm/video.js/dist/video.min.js/script video idplayer classvideo-js vjs-big-play-centered controls preloadauto width800 height450 source src/api/video/play?courseId1chapterId1 typeapplication/x-mpegURL /video这里的src指向后端接口后端校验完订单后返回签名后的 m3u8 地址播放器再发起请求。顺序是页面 - 后端校验 - 重定向到签名地址 - 拉取 m3u8 切片这样未购买用户在第一层就被拦截。5. Spring Security JWT STOMP付费课程的鉴权与在线课堂互动5.1 为什么用 Spring Security 而不是 Shiro在线视频教育平台需要管两类资源接口级权限如只有讲师能上传课程和资源级权限如只有购买者能播放视频。Shiro 的标签式权限在小型后台里够用但 Spring Security 的过滤器链机制对接口级权限控制更干净。毕业答辩问“为什么选 Spring Security”标准回答是它和 Spring Boot 是同族产品自动配置完善BCrypt 密码加密、方法级权限注解都内置了。5.2 JWT 认证过滤器直接抄进去就能跑Component public class JwtAuthenticationFilter extends OncePerRequestFilter { Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { String header request.getHeader(Authorization); if (header ! null header.startsWith(Bearer )) { String token header.substring(7); try { Claims claims Jwts.parserBuilder() .setSigningKey(secretKey) .build() .parseClaimsJws(token) .getBody(); Long userId Long.valueOf(claims.get(uid).toString()); Integer role (Integer) claims.get(role); // 把用户信息放入上下文后续 Controller 里直接取 request.setAttribute(userId, userId); request.setAttribute(role, role); } catch (JwtException e) { response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.setContentType(application/json;charsetUTF-8); response.getWriter().write({\code\:401,\msg\:\登录已过期\}); return; } } chain.doFilter(request, response); } }OncePerRequestFilter保证一个请求只过滤一次避免嵌套转发时重复解析。header.substring(7)是因为标准的 Authorization 头是Bearer xxxxx格式从第 7 个字符开始才是 token 本体。JWT 解析失败时直接返回 401不再往下传递这样没带 token 或 token 过期立即被拦截。要注意secretKey需要用Keys.hmacShaKeyFor生成且密钥长度必须大于 32 字节否则运行时会报错。配置里把放行路径和拦截路径分开http.csrf().disable() .authorizeHttpRequests() .antMatchers(/api/auth/login, /api/course/page, /video/**).permitAll() .antMatchers(/api/teacher/**).hasRole(TEACHER) .anyRequest().authenticated();登录接口和课程列表不需要登录就能访问这是 C 端正常流程/api/teacher/**限定了讲师角色其他接口一律要求有效 token。homework 里容易出问题的点是忘记配置antMatchers顺序Spring Security 按声明顺序匹配权限精确的规则必须写在anyRequest前面。5.3 用 STOMP 做实时弹幕和在线人数“在线”两个字在答辩时的权重比普通 CRUD 高。想给平台加实时互动又不想引入重型中间件可以走 WebSocket STOMP。Spring Boot 的 STOMP 支持消息广播代码量不大。Configuration EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.enableSimpleBroker(/topic); registry.setApplicationDestinationPrefixes(/app); } Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint(/ws).setAllowedOriginPatterns(*).withSockJS(); } }前端订阅/topic/danmaku/{courseId}发送消息到/app/danmaku后端收到后把消息原文、发送者昵称、时间戳一起广播回订阅频道。这样所有正在观看同一课程的用户都能实时看到弹幕。简单消息代理enableSimpleBroker是内存实现适合单机部署的课程设计论文里可以提一句“生产环境可替换为 RabbitMQ 或 Kafka”但不要展开。5.4 答辩加分项yml 里的密钥配置成密文JWT 密钥、数据库密码明文写在application.yml里是评审最容易挑的毛病。常见的加固方式是引入 jasypt-spring-boot-starter把配置值写成ENC(密文)形式实际启动时自动解密。密钥本身通过环境变量传入不进代码仓库。jasypt: encryptor: password: ${JASYPT_PASSWORD} algorithm: PBEWithMD5AndDES生成密文的命令是java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI inputroot passwordyour-key algorithmPBEWithMD5AndDES。改完配置后源码里哪怕被看到了也只是密文这个点在答辩时讲出来非常提分而且实现成本只有十分钟。6. 部署交付与答辩演示宝塔 Nginx、SSL 与演示录像的录制顺序6.1 打包与数据库初始化别在演示现场捏把汗后端打包前先把测试环境的配置改过来数据库地址、存储路径、日志级别。用mvn clean package -DskipTests打出 jar 包放到服务器/opt/edu目录下。数据库初始化用 Navicat 导入上一章提供的建表脚本然后插入一条讲师账号和一条学员账号并给讲师账号绑定一个已上架课程。初始化数据的操作要在部署当天早上完成不要拖到答辩前一小时。6.2 宝塔面板的 Nginx 反代配置服务器用宝塔面板的话先在软件商店装好 Nginx 和 MySQL。创建站点后配置反向代理把 API 请求转发到 Spring Boot 进程server { listen 443 ssl; server_name your.domain.com; # API 反向代理到本地 8080 端口 location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } # 视频文件由 Nginx 直出不经过 Java location /video/ { alias /data/edu/video/; types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } } # 前端静态页面直接指向 dist 目录 location / { root /www/wwwroot/edu-front; index index.html; try_files $uri $uri/ /index.html; } }proxy_pass后面的 URL 带不带路径是有讲究的这里不带/api/完整路径传给后端后端 Controller 用/api前缀对应如果proxy_pass http://127.0.0.1:8080/;路径会被替换掉两端对不上就会 404。另一个常见问题是 IDEA 里启动不了项目多半是端口被占用或者 JDK 版本不对先lsof -i:8080查端口再确认java -version。6.3 演示录像按这个顺序录答辩老师跟着思路走演示录像总时长控制在 8 到 10 分钟顺序要比操作逻辑更“讲评分点”。打开已经跑起来的前端页面后先示范学员注册登录如果 JWT 逻辑写好了这个阶段就展示接口返回的 token随后用讲师账号进入后台走一遍课程创建、章节添加、视频上传的完整流程停在播放页展示 HLS 播放和弹幕互动再换回学员账号购买课程重点展示下单后播放器可用、未下单时提示无权限的对比画面。中间穿插展示数据库中订单表和学习记录表的新增数据说明前后端数据是真实打通的。PPT 里每一页只放一个截图配三行文字技术架构图用第二章节的模块分包结构E-R 图直接截用数据库设计工具生成的图。运行教学视频不用重录把当前这版演示录像的旁白文案改写成“从零到部署”的步骤说明即可。答辩最后被追问性能时就讲 Learning Record 表的分页查询和 Nginx 静态加速这两个点比空谈“系统很稳定”有说服力。本文还有配套的精品资源点击获取
RELATED

相关推荐

猪源分泌素多肽定制:从序列解析到C端酰胺化的关键点

猪源分泌素多肽定制:从序列解析到C端酰胺化的关键点

一看到 “Secretin (porcine) ;HSDGTFTSERLSRLLRDSARLQRLGQGLV-NH₂” 这种订单式标题,做过多肽定制的人多半都会心一笑。这是从固相合成供应商那边复制出来的产品名:前半段告诉你是猪源分泌素,后半段是它的氨基酸单字母序列&…

📅 2026/9/10 7:39:35
2026 科普:Work Agent 品类概念、核心能力与代表性产品

2026 科普:Work Agent 品类概念、核心能力与代表性产品

近一年很多职场人能感知到一个明显变化:AI 的使用场景正在跳出单纯问答。过去遇到问题,输入关键词拿到一段文字回复,后续整理资料、转成文件、交叉核对、发给同事仍然要由人分步完成;现在不少工具可以顺着一个工作目标&#xff0c…

📅 2026/9/10 7:39:35
magnitude不是CLI工具:轻量向量检索库的核心原理与实战

magnitude不是CLI工具:轻量向量检索库的核心原理与实战

1. 项目概述:一个被误读的“magnitude”——它不是CLI工具,而是向量检索的底层基石最近在多个技术社区和开发者群聊里,频繁看到有人搜索“magnitude CLI”“magnitude inference server”“magnitude local models”,甚至混搭出“…

📅 2026/9/10 7:39:35
MORE NEWS

更多资讯

📰

OpenAI与Anthropic的AI硬件定义权之争:芯片、入口与生态

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

📰

10分钟跑通LightGBM R包银行营销梯度提升预测:AUC超0.85,安装到部署约百行代码

10分钟跑通LightGBM R包银行营销梯度提升预测:AUC超0.85,安装到部署约百行代码 【免费下载链接】LightGBM A fast, distributed, high performance gradient boosting (GBT, GBDT, GBRT, GBM or MART) framework based on decision tree algorithms, use…

📰

上市全解析:从股改到IPO,公司上市的流程、门槛与避坑指南

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

📰

基于Spring Boot的教师评价系统:从设计到部署全实践

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

📰

如何安装并加载 Prettier 插件,让 Prettier 格式化 PHP 等核心包之外支持的语言

如何安装并加载 Prettier 插件,让 Prettier 格式化 PHP 等核心包之外支持的语言 【免费下载链接】prettier Prettier is an opinionated code formatter. 项目地址: https://gitcode.com/gh_mirrors/pr/prettier Prettier 核心 prettier 包内置了 JavaScript…

📰

跑通 Flipper Zero 中文显示:U8g2 自定义字体挂载与 locale 机制拆解

跑通 Flipper Zero 中文显示:U8g2 自定义字体挂载与 locale 机制拆解 【免费下载链接】flipperzero-firmware Flipper Zero firmware source code 项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware Flipper Zero 固件刷进第三方 FAP …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬