SpringBoot+Vue3在线文档管理系统:权限、版本与部署实战
说到在线文档管理系统不少人第一反应是装一个现成的开源 Wiki 完事。但真去企业里做一轮知识库整合之后你会发现项目最难的地方根本不是“把文档传上去”而是怎么把权限、版本、分类、检索和在线编辑这些看似零散的能力收进同一套框架里。我这段时间维护的一套源码就是干这个的Java SpringBoot Vue3 MyBatisMySQL 做存储前后端完全分离目录、权限、版本、富文本编辑、附件管理全部走 REST 接口前端只负责展示和交互后端只负责业务和数据。这套源码很适合两个群体。一个是打算做全栈项目练手的人通过它可以把用户认证、增删改查、文件上传、前端路由守卫这些“面试高频点”串成一条完整链路另一个是刚接手企业信息化项目、需要快速搭一个文档中心或者知识库的团队直接把骨架拿过去改业务能省掉不少从零开始的成本。下面我会从需求设计、数据库结构、后端接口、前端页面的顺序拆解最后再把部署联调中踩过的高频坑列一遍希望能让想复现这套系统的人少走弯路。1. 在线文档管理系统核心需求与整体设计先搞清楚要做什么1.1 典型业务场景与需求痛点所谓在线文档管理系统本质上解决的是“文件被到处乱放”的问题。企业内部常见的场景很直白合同、方案、说明书、培训资料散落在个人电脑、即时通讯软件聊天记录、共享网盘各个角落同事要找一个文件可能得问三个人。更麻烦的是同一个文档经常出现“最终版”“最终版2”“打死也不再改版”这种重复文件时间一长根本分不清哪个才是有效版本。所以一个及格的系统至少要覆盖这些需求文档统一入库文档不再以文件流形式散落而是沉淀成一条条记录有标题、分类、归属人、状态。分类与检索支持目录树、标签、关键字搜索让使用者能按业务线找到文档。版本管理每次编辑保留历史版本随时可以对比和回滚防止改坏了没法恢复。权限控制不同角色看不同内容管理员、编辑者、访客各有所能涉及敏感文档时必须做隔离。在线预览与编辑把“传文件”变成“写文档”富文本编辑、自动保存是基本操作。这个需求列表看起来普通真正落地时每一条都会牵扯出前后端各个模块的配合。比如“分类”不是简单的下拉框而是递归的目录树要处理父子层级带来的数据查询复杂度“版本管理”不是存一个 update_time 字段而是要有独立的历史内容表“权限”不只是前端隐藏按钮后端接口也必须做同样校验否则绕过页面直接调接口就能越权。1.2 为什么选 SpringBootVue3MyBatisMySQL 这套组合先别急着堆新技术这套组合能成为很多业务系统的默认选项原因是它足够“稳”且招聘市场接受度高。Java Spring Boot 的服务端生态非常成熟适合做权限、事务、复杂业务逻辑Vue3 在前端开发效率和组件生态上已经非常完善配合 Vite 启动又快写后台管理类页面很顺手MyBatis 保留手写 SQL 的自由度项目后期遇到复杂查询不至于被 ORM 的抽象限制住MySQL 则适合绝大多数中小型系统的数据量运维成本也低。有人会问为什么不直接用 JPA我的习惯是如果查询场景比较固定、实体关系简单JPA 确实省事但文档管理系统里充满了动态条件搜索、批量插入、多表关联统计这类需求用 MyBatis 手写 SQL 反而更好控制性能。比如文档列表要做“标题模糊搜索 分类过滤 发布时间区间 分页”这种动态 SQL 在 MyBatis 里写得很清晰换 JPA 要么写 Specification要么拼 JPQL可读性都要差一些。再聊前后端分离。很多老项目还在用 Thymeleaf 模板渲染页面不是不能做而是当你要做多端复用、页面交互复杂度变高时服务端和前端被绑在同一个工程里联调、发布、分工都很别扭。前后端分离之后后端只提供 JSON 数据接口前端单独部署到 Nginx团队可以并行开发减少大量互相等待的时间。这套系统源码也明确分成了 frontend 和 backend 两个工程两个端口、两套启动方式互不依赖。1.3 系统模块拆分与源码结构我在整理源码时把后端拆成了标准的三层结构Controller 负责接收请求、参数校验和响应包装Service 负责业务逻辑、事务控制和权限校验Mapper 只管 SQL 映射不掺杂业务判断。前端则按页面维度组织文档模块、用户模块、目录模块各自独立不搞一个“Vue 单文件组件里写几千行”的坏味道。后端主目录大致是这样backend ├── pom.xml ├── src/main/java/com/example/docms │ ├── DocmsApplication.java │ ├── common │ │ ├── Result.java │ │ ├── ResultCode.java │ │ └── GlobalExceptionHandler.java │ ├── config │ │ ├── CorsConfig.java │ │ ├── JwtInterceptor.java │ │ └── MybatisPlusConfig.java │ ├── controller │ │ ├── AuthController.java │ │ ├── DocumentController.java │ │ ├── CategoryController.java │ │ └── UserController.java │ ├── service │ │ ├── impl │ │ └── ... │ ├── mapper │ │ ├── UserMapper.java │ │ ├── DocumentMapper.java │ │ └── ... │ └── entity │ ├── User.java │ ├── Document.java │ └── ... └── src/main/resources ├── application.yml └── mapper ├── UserMapper.xml └── DocumentMapper.xml前端主目录frontend ├── index.html ├── package.json ├── vite.config.js ├── src │ ├── main.js │ ├── App.vue │ ├── api │ │ ├── auth.js │ │ └── document.js │ ├── router │ │ └── index.js │ ├── stores │ │ ├── user.js │ │ └── document.js │ ├── views │ │ ├── Login.vue │ │ ├── Layout.vue │ │ ├── document │ │ └── user │ └── components │ └── CategoryTree.vue └── src/utils ├── axios.js └── auth.js从目录能看出来这套代码没有把“系统管理”和“文档管理”混在一起Controller 分层清晰改某个模块不会动到其他模块这也是我强调“源码可以接着改”的原因。2. 后端实现SpringBoot MyBatis MySQL 的骨架搭建2.1 数据库表结构先设计好文档、目录、用户、权限的主表后端开发最忌讳上来就写代码数据库设计才是地基。我设计这套系统时并没有把所有字段堆进一张大表而是拆出了几张职责明确的表核心包括用户表、角色表、目录分类表、文档信息表、文档内容表、附件表以及用户角色关联表、角色权限关联表。先看用户和权限相关的基础表CREATE TABLE sys_user ( id bigint NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL, password varchar(120) NOT NULL, nickname varchar(50) DEFAULT NULL, status tinyint DEFAULT 1 COMMENT 1启用 0禁用, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ); CREATE TABLE sys_role ( id bigint NOT NULL AUTO_INCREMENT, role_key varchar(50) NOT NULL, role_name varchar(50) NOT NULL, PRIMARY KEY (id) ); CREATE TABLE sys_user_role ( user_id bigint NOT NULL, role_id bigint NOT NULL, PRIMARY KEY (user_id, role_id) );用户表和角色表采取标准的多对多关联因为一个用户可能既是管理员又是某几个业务部门的审核员。密码字段我建议存 BCrypt 加密后的字符串不要在数据库里出现明文密码这是底线。再看文档核心表CREATE TABLE doc_category ( id bigint NOT NULL AUTO_INCREMENT, parent_id bigint DEFAULT 0, name varchar(100) NOT NULL, sort_order int DEFAULT 0, status tinyint DEFAULT 1, PRIMARY KEY (id) ); CREATE TABLE doc_info ( id bigint NOT NULL AUTO_INCREMENT, title varchar(255) NOT NULL, category_id bigint DEFAULT NULL, owner_id bigint NOT NULL, version int DEFAULT 1, status tinyint DEFAULT 1 COMMENT 1正常 0草稿, view_count int DEFAULT 0, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id) ); CREATE TABLE doc_content ( id bigint NOT NULL AUTO_INCREMENT, doc_id bigint NOT NULL, version int NOT NULL, content_html longtext, content_text longtext, update_by bigint DEFAULT NULL, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_doc_id (doc_id) );这里的关键设计是doc_info和doc_content拆开各自分工明确。doc_info只存文档的属性比如标题、分类、作者、当前版本号这样列表页查询时就非常快不会因为加载全文导致接口卡顿。doc_content按版本存正文内容每次保存会写入一条新记录旧的正文保留下来形成可回滚的历史版本。注意正文为什么要拆出来而不直接放在doc_info我实测过如果文档正文和标题放在同一张表列表查询会频繁读取大量长文本字段MySQL 需要加载到内存的数据量翻了十倍不止同一张表分页查询的响应时间明显变长。拆表之后列表页根本不查内容表性能数据稳定很多。2.2 MyBatis Mapper 与动态 SQL构造灵活查询的关键MyBatis 的核心配置在于 Mapper 接口和对应的 XML 文件。这里我以文档分页查询为例展示动态 SQL 的写法Mapper public interface DocumentMapper { ListDocumentVO selectDocumentPage(Param(keyword) String keyword, Param(categoryId) Long categoryId, Param(status) Integer status, Param(offset) int offset, Param(pageSize) int pageSize); Long countDocumentPage(Param(keyword) String keyword, Param(categoryId) Long categoryId, Param(status) Integer status); }select idselectDocumentPage resultTypecom.example.docms.vo.DocumentVO SELECT d.id, d.title, d.version, d.view_count, d.create_time, d.update_time, c.name AS category_name, u.nickname AS owner_name FROM doc_info d LEFT JOIN doc_category c ON d.category_id c.id LEFT JOIN sys_user u ON d.owner_id u.id where if testkeyword ! null and keyword ! AND d.title LIKE CONCAT(%, #{keyword}, %) /if if testcategoryId ! null AND d.category_id #{categoryId} /if if teststatus ! null AND d.status #{status} /if /where ORDER BY d.update_time DESC LIMIT #{offset}, #{pageSize} /select有人会把分页逻辑写进 Service 层把当前页码转成 SQL 里的偏移量这没问题。但更高效的做法是利用现成的分页插件比如 PageHelper这样 Controller 和 Service 里只需要写一个 pageNum 和 pageSize插件会帮我们算好 limit 参数。我在这套源码里两种方式都保留了一版初学者建议先从手写 LIMIT 理解原理再切换到插件减少重复代码。动态 SQL 里最需要注意的是注入问题。关键字搜索时一定要使用#{keyword}让 MyBatis 帮你生成预编译参数而不是用${keyword}否则用户输入一个%或者单引号就可能造成 SQL 注入。这条规矩适用于所有查询条件。2.3 统一返回结构、全局异常处理与登录认证前后端分离项目最忌讳前后端各写一套响应格式前端不知道后端什么时候返回成功、什么时候返回失败。我统一规定后端所有接口返回一个标准结构public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.code 200; result.message 操作成功; result.data data; return result; } public static T ResultT error(String message) { ResultT result new Result(); result.code 500; result.message message; return result; } }有了统一结构再做全局异常处理就顺理成章。我在GlobalExceptionHandler里拦截参数校验异常、业务异常、未知异常分别转成对应错误码和提示信息前端只要判断code 200即可不需要每个接口单独写一段try-catch。认证部分采用 JWT 令牌。登录接口校验用户名密码成功后生成 token后续请求在请求头携带Authorization: Bearer xxx后端通过拦截器统一解析把当前用户信息放入 ThreadLocal 或者从 Redis 里读取。不建议把用户信息全部塞进 token因为 token 本身有大小限制而且一旦用户被禁用已发放的 token 可能无法立刻失效。如果要做到严格失效控制最好引入 Redis 做 token 黑名单这是上线前需要考虑的。3. Vue3 前端实现从登录鉴权到在线编辑完整链路3.1 初始化 Vue3 工程Vite、Router、Pinia 一条龙前端工程我选择 Vite 构建创建项目时直接使用官方脚手架npm create vitelatest frontend -- --template vue cd frontend npm install npm install vue-router pinia axios路由设计上采用经典的前后端分离布局。Layout.vue是最外层框架左侧放目录树右侧放内容区通过嵌套路由挂载文档列表和编辑页面。使用 Vue Router 时我习惯把目录树和文档列表设计成带参数的动态路由类似/doc/category/:categoryId这样刷页面时 URL 还能保持住当前所在分类。Pinia 负责管理前端全局状态最典型的是当前登录用户信息。用户刷新页面后token 还在 localStorage 里但用户昵称、角色列表这类资料可能已经丢了这时可以在stores/user.js里定义一个函数在应用启动时调用后端接口重新拉取用户信息避免频繁读取后端造成不必要的请求。3.2 Axios 请求封装与登录态管理axios 一定不能直接在组件里到处写否则后面处理 token、错误提示、401 跳转时你会发现改一处要动几十个文件。我通常封装到src/utils/axios.js用拦截器统一处理两件事import axios from axios; const service axios.create({ baseURL: /api, timeout: 15000 }); service.interceptors.request.use(config { const token localStorage.getItem(access_token); if (token) { config.headers.Authorization Bearer ${token}; } return config; }); service.interceptors.response.use( response { if (response.data.code ! 200) { // 弹窗提示错误比如“文档标题不能为空” return Promise.reject(new Error(response.data.message)); } return response.data.data; }, error { if (error.response error.response.status 401) { localStorage.removeItem(access_token); window.location.href /login; } return Promise.reject(error); } );这样封装完业务代码里调用接口就非常干净import { getDocumentPage } from /api/document; const list await getDocumentPage({ keyword: 需求, categoryId: 1 });登录态管理的关键在于路由守卫。没有 token 的人不允许进任何业务页面统一踢回登录页router.beforeEach((to) { const token localStorage.getItem(access_token); if (!token to.path ! /login) { return /login; } if (token to.path /login) { return /; } return true; });3.3 文档目录树与在线编辑实现文档目录树的实现不算复杂但要注意递归组件。CategoryTree.vue接收后端返回的目录数组每个节点可能包含children组件内部用v-for循环渲染遇到子节点继续调用组件本身。后端返回数据时一般设计成父子嵌套结构比较方便前端渲染。在线编辑我用的是轻量级富文本编辑器核心交互是自动保存。自动保存不能每敲一个字符就发一次请求否则数据库压力很大。我的做法是利用防抖用户停止输入 3 秒后再触发保存接口同时显示“正在保存”或“已保存”状态。这样既保证内容不会丢失也不会产生无意义的接口请求。在新建文档时我会先在doc_info表插入一条记录拿到文档 ID然后再把编辑器内容写入doc_content后续每次保存则是再次插入一条新版本内容同时更新doc_info.version。不要把每次保存都做成 UPDATE 原记录否则历史版本就不存在了。3.4 权限控制落地路由守卫与按钮级权限权限控制是文档系统绕不开的环节。前端要做两层路由级和按钮级。路由级权限通过路由元信息控制比如{ path: /system/user, component: UserManage, meta: { roles: [admin] } }然后在路由守卫中判断当前用户角色是否包含admin不满足就跳转 403 页面。按钮级权限更简单封装一个自定义指令v-permission指定按钮需要的权限标识如果没有权限就移除对应 DOM 节点。但必须明确前端权限只是体验优化真正安全的后端必须对每个接口做权限校验否则攻击者直接调 API 就能绕过页面限制我见过不止一个项目在这里翻车。4. 部署联调与常见问题把源码真正跑起来4.1 本地环境准备与配置先把环境搞定JDK 建议用 17 以上版本Maven 配置阿里云镜像加速依赖下载Node 建议 18 以上npm 或者 pnpm 都行MySQL 建议 8.0 版本注意默认认证插件和驱动版本Spring Boot 3.x 需要配置对应的 mysql-connector-j 依赖。后端配置文件application.yml里最容易出错的是数据库连接部分spring: datasource: url: jdbc:mysql://localhost:3306/docms?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.docms.entity如果忘记配置serverTimezone本地连接 MySQL 8 经常会报时区错误。这是一个看似简单但几乎每个人都会踩的坑。4.2 前端代理与接口联调一次性解决跨域前后端分离开发时前端请求地址一般是http://localhost:5173后端接口是http://localhost:8080直接请求必然跨域。我的处理方式是优先使用 Vite 代理而不是在后端放开跨域// vite.config.js export default defineConfig({ server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true, rewrite: path path.replace(/^\/api/, ) } } } });这样前端代码里所有请求都写成/api/xxx代理会把请求转发到后端同时去掉/api前缀后端不需要额外处理跨域配置。用代理的好处是正式部署时前端和后端如果在同一台服务器上可以继续沿用当前地址结构改造量很小。当然如果前端和后端域名确实不同就需要在后端启用 CORS 配置二选一即可不用同时配防止请求头冲突。4.3 高频问题速查从后台报错到前端白屏的排障清单我做一个常见问题速查表方便对照排错。现象常见原因解决建议MyBatis 提示 Invalid bound statementMapper XML 没有被扫描到检查mapper-locations路径是否匹配 XML 位置确保 XML 的 namespace 和接口全限定名一致数据库连接报 Public Key Retrieval is not allowedMySQL 8 驱动参数问题JDBC 连接串加allowPublicKeyRetrievaltrue中文写入数据库乱码连接字符集或表字符集不一致数据库表统一使用utf8mb4连接串加characterEncodingutf8前端登录成功后刷新页面就跳登录用户信息没有持久化到 Pinia应用初始化时根据 token 重新拉取用户信息而不是只在登录页保存登录接口报 401 但网络请求里有 token拦截器取 token 的 key 不一致检查 localStorage 里存的 key 和 axios 头读取的 key 是否一致上传大文件超时前后端超时时间设置过短调整 axios timeoutSpring Boot 配置文件设置了 multipart 大小限制也要检查打包后 Vue Router 刷新出现 404静态服务器未做 history 回退Nginx 配置try_files $uri $uri/ /index.html;文档内容保存后版本号没变Service 层没有更新 doc_info.version每次保存成功后执行update_version或者在插入 content 记录时同时更新版本字段我在实际排错时还有个习惯不要同时怀疑三个地方。先抓后端日志看接口是否被访问到再看 SQL 是否执行成功最后看前端有没有把返回值正确处理。很多问题其实发生在“后端接口正常但 axios 不小心又包了一层 response.data”这种低级错误排查起来最费时间。4.4 上线前安全与性能加固我常做的几件事如果这套系统要正式部署不是“能跑”就完事了。我至少会做这几件事密码加密统一升级为 BCrypt并且登录接口增加失败次数限制防止暴力破解。JWT 密钥不要硬编码在代码里放配置中心或者环境变量过期时间不要设置太长生产环境我一般控制在 2 小时左右。所有涉及删除、更新的接口后端都要校验操作者的创建人身份或角色权限不能只依赖前端传参数。数据库加慢查询日志定期排查文档列表、搜索接口有没有出现全表扫描或者大段 text 字段回表。文档正文的查询走 LongText 字段时尽量只 select 需要的列不要随手SELECT *。如果要支持全文检索可以引入 Elasticsearch或者至少用 MySQL 的全文索引配合ngram分词而不是靠LIKE %关键词%扛所有流量。性能层面的另一个重点是千万不能忽略文档内容表的增长。版本历史越多longtext字段堆积得越快。上线前建议写一个定时任务只保留最近 N 个历史版本或者把 N 天前且未被手动标记为重要的历史记录统一清理否则数据库会越来越胖。最后说点个人体会这套系统从设计到跑通我最大的感触是“在线文档”没有想象中那么简单也没有想象中那么难。难在模块之间的耦合目录、权限、内容、版本、搜索任何一个功能单独拎出来都不复杂但合在一起时如果数据库没设计好、接口职责没分清楚改一个功能就会牵动一片。简单在只要你把基础分层做扎实所有功能都是顺着业务逻辑堆出来的。如果你正在复现这套 SpringBoot Vue3 MyBatis 的文档管理系统我建议先把数据库建好再写后端接口最后才动前端页面顺序不要乱。还有一个非常实用的小技巧开发前先说好接口文档哪怕用文本先写一份也行前后端各自按约定开发能少吵很多架。等整套系统能跑起来你再往里面加全文搜索、在线表格、多人协同这类高级功能都会顺滑很多。

相关新闻

Flink SQL自定义Connector开发:从零实现数据源接入

Flink SQL自定义Connector开发:从零实现数据源接入

做 Flink 实时计算的同学迟早会遇到一个场景:官方提供的 JDBC、Kafka、File 等连接器都试了一遍,发现某类业务数据源官方根本没适配。要么是自研消息队列只能通过 API 硬编码拉数据,要么是某内部存储系统需要以 Source 方式接入 SQL 作业&…

2026/10/18 10:08:39 阅读更多 →
Flink SQL自定义Connector实战:实现数据源扩展的完整指南

Flink SQL自定义Connector实战:实现数据源扩展的完整指南

经常有朋友问我,Flink SQL 里想接入一个内部系统,结果官方连接器里根本没有,要怎么搞?我的回答一直是:自己写一个自定义 Connector,别等官方。这篇文章就来聊聊 Flink SQL Connector 开发里最实用的一条链路…

2026/10/18 10:08:39 阅读更多 →
告别熬夜改稿:AI辅助PPT制作全流程效率提升实战指南

告别熬夜改稿:AI辅助PPT制作全流程效率提升实战指南

凌晨两点十七分,我对着同一页公司介绍已经改了第九遍,只因为上面那条业务模块的配图怎么摆都差那么点意思。这不是我第一次为PPT熬夜,也大概率不会是最后一次——如果我没在那个周末试过那款叫PaperXieAIPPT的工具的话。真正让我把标题写成“…

2026/10/18 10:07:39 阅读更多 →

最新新闻

KAN与六种神经网络架构结合实战:图像分类与时间序列预测对比

KAN与六种神经网络架构结合实战:图像分类与时间序列预测对比

最近一直在做时间序列预测和图像分类的实验,发现朋友圈里聊天总绕不开KAN(Kolmogorov-Arnold Network)这个词。有同学拿"KAN全面吊打MLP"的截图来问我是不是真能替换掉手头的模型,也有同学问KAN跟CNN、LSTM、TCN、Transformer这些经典结构组合之后到底效果怎么样、代…

2026/10/18 10:46:50 阅读更多 →
用AI Agent聊聊天就能完成数据抓取与报告生成?一文讲透原理与实战

用AI Agent聊聊天就能完成数据抓取与报告生成?一文讲透原理与实战

以前我做数据汇总,流程基本是:先写一个爬虫脚本,跑完看一眼结果,再打开表格工具手动清洗,最后复制粘贴写总结。这套流程干久了你会发现,真正费时间的不是“抓”,而是“改”——页面结构变一下&a…

2026/10/18 10:46:50 阅读更多 →
规格管理工具实测与自建方案:从文档混乱到自动化校验

规格管理工具实测与自建方案:从文档混乱到自动化校验

1. 为什么会盯上规格工具这条赛道先讲个我自己的翻车现场。去年在某团队做一套跨平台业务系统,代码还没写几行,光是对需求就吵了三轮。产品说这个流程要支持灰度开关,开发说设计文档里根本没提这个状态位,测试拿着旧版用例对不上新…

2026/10/18 10:46:50 阅读更多 →
EarlGrey iOS UI自动化测试实战:同步机制、元素匹配与工程接入

EarlGrey iOS UI自动化测试实战:同步机制、元素匹配与工程接入

1. EarlGrey是什么:先搞清楚它解决什么问题做iOS测试的同学应该都有同感:UI自动化这块,选择一直很纠结。Appium、XCUITest、KIF各有一批拥趸,但对原生iOS项目来说,EarlGrey是一个绕不开的名字。它由一家大型科技公司的…

2026/10/18 10:46:50 阅读更多 →
智能UI逆向工程:解构ChatGPT交互状态与行为逻辑

智能UI逆向工程:解构ChatGPT交互状态与行为逻辑

1. 这不是“破解”,而是对智能界面交互逻辑的系统性解构“ChatGPT Intelligent UI 的逆向工程”这个标题,乍看容易让人联想到代码层的暴力拆包或协议嗅探——但实际操作中,我反复验证过:真正有价值的逆向,从来不在二进…

2026/10/18 10:46:50 阅读更多 →
手写现代C++ Web服务器:从socket到HTTP响应的完整闭环

手写现代C++ Web服务器:从socket到HTTP响应的完整闭环

如果你点进这篇文章,多半已经受够了那种“框架搭好、回调填完、项目跑通”的开发方式。业务代码写了好几年,浏览器地址栏敲下回车之后,数据到底在操作系统里经过哪几条路、HTTP 请求是怎么被解析成一个个字段的,大多数人其实说不清…

2026/10/18 10:45:50 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 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/18 0:55:02 阅读更多 →
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/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练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/16 14:23:36 阅读更多 →