尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Java C/S架构进销存系统:从需求文档到二次开发的完整实践
简介这是一份面向Java初、中级开发者及课程设计/毕业设计场景的进销存系统C/S架构完整资料包覆盖采购、销售、库存、财务等核心业务模块同时包含需求文档与详细设计文档能帮助读者理解企业级业务流转与Java桌面应用开发全流程。压缩包共252个文件约1.63MB主要包含Java源码.java、编译后class文件、Swing界面类、数据库脚本.sql/.db、设计文档.doc以及工程配置.properties/.project/.classpath等可按MVC结构查看controller/model/view分层实现。目前已有199人学习下载。资料的价值在于既有可直接运行与改造的Java工程代码也有配套的需求分析、用例图、ER图、表结构等设计文档还包括开发日志与测试记录适合作为课程设计、项目实训或自学进阶时的参考蓝本便于对照业务模块梳理完整落地方案。1. 先说结论这套 Java C/S 进销存是拿来就能跑的完整闭环某个做日用品批发的朋友账上库存和实物差了三百多件进销存全靠 Excel采购单散落在三个人的电脑里。后来我接手排查给他落地了这套 Java C/S 进销存——Java 写客户端MySQL 做存储C/S 架构一头客户端一头服务端还齐整地附带了需求文档和详细设计文档。它不是一个只能演示登录的玩具采购、销售、库存、报表、权限都有完整的单据流SQL 脚本导入即用。适合刚学完 Java SE、想拿真实管理系统练手的开发者也适合小团队做内部工具时直接改造。文档能让你看得懂每一步设计源码能让你改得动每一个模块。下面我会按「它是什么 → 文档怎么拆 → 代码长什么样 → 怎么跑 → 怎么改」一路讲透。2. 项目定位与技术选型为什么是 C/S 而不是 B/S2.1 这套进销存到底做了什么进销存三个字拆开进是采购入库销是销售出库存是库存变化。围绕三个核心动作系统把单据、往来单位、库存流水和报表串成一条完整的链。采购管理维护供应商档案做采购单、采购入库单入库时自动增加库存并记录应付账款。销售管理维护客户档案做销售单、销售出库单出库时自动扣减库存并记录应收账款。库存管理库存查询、库存上下限预警、盘点单、报损报溢上报。报表统计采购汇总、销售汇总、库存明细、往来账款对账。系统管理用户账号、角色权限、操作日志。数据流的规则很朴素一切库存变动都产生库存流水报表不直接查商品表的当前库存而是按流水统计。需求文档把这条写成了硬性约束——禁止业务代码直接 UPDATE 商品的库存字段而不写流水。这个约束后来值了不少钱它保证任何时候导出的库存明细都能追溯到源头单据。C/S 和 B/S 的选择是这个项目最早定下来的。B/S 要部署 Web 服务器要考虑浏览器兼容对只在局域网里跑的中小仓库来说太重C/S 客户端直连数据库界面响应快单据录入体验接近桌面软件。仓管员不用开浏览器输地址双击图标就能开单。缺点是升级要每个客户端重新分发但这套系统把客户端做成了解压即用分发成本很低。2.2 技术栈拆解Java Swing MySQL JDBC 的经典组合客户端用 Java Swing 基于 JDK 8没有引入 Spring 全家桶。数据访问层用 JDBC 封装成工具类连接信息放在配置文件里。界面层用 JFrame、JTable、JDialog 搭建后台管理界面表格负责数据展示弹窗负责录单。数据库连接配置长这样jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/erp_db?useSSLfalsecharacterEncodingutf8 jdbc.usernameroot jdbc.password123456参数说明characterEncodingutf8 必须带上否则中文乱码从登录页就开始useSSLfalse 是 MySQL 5.7 的常见配置避免 SSL 告警刷屏。如果是 MySQL 8驱动换成 com.mysql.cj.jdbc.DriverURL 再加 serverTimezoneAsia/Shanghai。数据库访问的核心类长这样public class DbUtil { private static final Properties props new Properties(); private static ThreadLocalConnection holder new ThreadLocal(); static { try (InputStream in DbUtil.class.getResourceAsStream(/db.properties)) { props.load(in); Class.forName(props.getProperty(jdbc.driver)); } catch (Exception e) { throw new ExceptionInInitializerError(e); } } public static Connection getConnection() throws SQLException { Connection conn holder.get(); if (conn null || conn.isClosed()) { conn DriverManager.getConnection( props.getProperty(jdbc.url), props.getProperty(jdbc.username), props.getProperty(jdbc.password)); holder.set(conn); } return conn; } }这段代码的作用getConnection 第一次调用时从配置加载驱动并建立连接之后同一线程复用同一条连接事务提交或回滚由上层控制。ThreadLocal 是这个项目事务一致性的关键少了它采购单主表和明细表就可能出现一个成功一个失败。选 JDBC 而不选 MyBatis原因很现实核心表就十来张SQL 写在 DAO 里反而好排查。MyBatis 的映射配置在这种规模下是额外负担。如果你更熟 MyBatis改成 XML 映射也顺手后面二次开发章节会提改造思路。Swing 界面有一个必须注意的点所有数据库查询不能在事件分发线程里执行否则窗口拖拽会卡死。这套系统的常见做法是启动一个线程池把耗时的列表查询丢给后台线程查询完成再通过 SwingUtilities.invokeLater 回到 EDT 刷新表格。改造时如果发现某个窗口一打开就转圈先检查是不是直接在按钮事件里查了数据库。2.3 目录结构与工程分层拿到源码后先看目录结构能少踩一半坑。整个工程是标准 Maven 布局erp-system/ ├── sql/ │ ├── erp_db.sql 建表脚本 │ └── erp_data.sql 演示数据 ├── doc/ │ ├── 需求文档.md │ ├── 详细设计文档.md │ └── 接口说明.md ├── src/main/ │ ├── java/com/erp/ │ │ ├── model/ 实体类 │ │ ├── dao/ 数据访问 │ │ ├── service/ 业务逻辑 │ │ ├── view/ Swing 界面 │ │ ├── controller/ 界面与服务桥接 │ │ └── util/ 工具类 │ └── resources/db.properties └── pom.xml分层是经典的三层view 只管界面绘制controller 接收界面事件并调用 serviceservice 管事务和业务规则dao 只做 SQL 读写。model 里的实体类对应数据库表字段命名一一对应。不少进销存源码会犯同一个毛病——把 SQL 直接写在界面类里。线程一多界面卡死、连接泄漏全来了。这套工程把依赖方向压成单向改动一个模块时不用在工程里到处搜索。doc 目录下的两份文档不是凑数的需求文档写清了每个模块的业务规则详细设计文档画了 ER 图和调用链二次开发时先查文档再动手效率比直接读源码高得多。3. 需求文档拆解七个核心模块的边界与数据流3.1 采购入库与供应商对账需求文档开篇是角色和权限然后进入功能描述。采购入库是里面最完整的一条链路仓管员打开采购入库界面选择供应商选择商品填数量和单价保存后库存增加供应商的应付余额同步增加。需求文档对采购入库的定义一张入库单包含一个主表和一到多行明细主表存供应商、单据号、日期、总金额、经手人明细行存商品、数量、单价、金额保存时主表明细一起落库任何一个明细行校验失败整单失败。这个「整单事务」的要求直接决定了 service 层必须开手工事务。这里有个容易被忽略的规则暂估入库还是正式入库这套需求文档采用了「入库即确认」的简单方案不搞暂估冲回。财务如果需要应付账款入库单确认时同步生成应付流水。对中小贸易公司来说少一个暂估流程能降低大量使用成本但代价是没有在途入库的概念如果你要给客户做代销入库这块得自己扩展。供应商对账部分是一张「供应商对账单」报表按供应商汇总期间内的采购金额、已付金额、应付余额。设计文档特别注明余额不 join 采购入库表去算而是从应付流水表累加。原因是采购单可能被红冲、被作废直接汇总主表金额会得出错误的欠款数。3.2 销售出库与客户信用管理销售出库是采购入库的镜像但多两个业务规则。第一价格取价策略商品档案里预设销售价开单时自动带出允许手工修改第二信用额度客户档案里有 credit_limit 字段出库单保存时计算该客户当前应收余额加本单金额超过额度不允许保存。信用额度在需求文档里是硬限制写在 service 层而不是界面层。原因很简单界面可以被绕过service 才是最后一道关。很多进销存只在前端做了 toast 提醒后端不校验业务员换个端口连数据库直接就把单保存了。销售单据还有一个红冲需求。出库单录错了不能直接删除而是做红冲——生成一张负数金额的红字单据库存反向变动流水里留下审计痕迹。需求评审时「删除」和「红冲」讨论了很久最后定的是只有未审核单据能删除已审核单据只能红冲。这个 audit_status 字段贯穿所有核心单据二次开发加新单时最好也沿用。另外销售退货在需求文档里被设计成一张独立的退货单而不是红冲的简写。退货单带原销售单号可以只退部分数量库存加回应收余额同步减少。如果只依赖红冲做退货客户退货原因没法记录统计退货率时要自己从流水里猜。3.3 库存盘点与预警盘点功能是仓库用得最多的。流程是新建盘点单、选择盘点仓库、录入实盘数量、保存后系统自动计算盘盈盘亏、生成库存调整记录。需求文档对盘点有一个硬约束盘点期间该商品禁止出入库操作防止并发修改把盘点结果搞乱。实现上用了一张临时盘点表配合行锁。库存预警是另一个高频需求商品档案设置 min_stock 和 max_stock每次库存变动后 service 层检查是否越界越界则写预警记录。需求文档要求预警在主界面快捷提醒区展示点击跳转到对应商品。这套机制不复杂但对商贸公司来说可能比炫酷的数据大屏更实用。3.4 需求文档里容易被忽略的约束条件下面几条从需求文档里摘出来的业务约束是实施时最容易漏的单据号生成规则前缀加日期加流水号比如 RK202501150001并发下必须靠唯一索引或数据库序列防重。负库存控制默认不允许但不强制。销售出库库存不足时给提示但允许超卖具体看客户能不能接受负库存。软删除基础资料不能物理删除只能停用因为历史单据还要关联它们。金额精度单价金额统一用 BigDecimal禁止 double 运算否则月底对账会出现 0.01 的差异。我见过最典型的翻车是没注意软删除规则直接写 DELETE 把被历史单引用的商品删了报表 join 出一堆空行排查了两天才发现是物理删除惹的祸。所以我会建议二次开发前先通读一遍需求文档的「业务规则」段落那部分字数不多但全是坑。读文档的正确姿势不是从第一章念到最后一章而是先找「不得」「必须」「禁止」这些词这些地方才是业务真正的边界。4. 详细设计文档从表结构到核心代码实现的完整链路4.1 数据库设计八张核心表的关系详细设计文档从 ER 图开始。核心表可以归成四组基础资料、单据主表、单据明细、流水账务。中等规模进销存有十几张表这里挑八张核心的讲。表名关键字段说明sys_userid, username, password, role, status用户与角色base_productid, code, name, category_id, spec, unit, min_stock, max_stock, status商品档案base_supplierid, name, contact, phone, payable_balance供应商及应付余额base_customerid, name, contact, credit_limit, receivable_balance客户及信用额度purchase_docid, doc_no, supplier_id, total_amount, audit_status, creator采购单主表purchase_itemid, doc_id, product_id, qty, price, amount采购单明细stock_flowid, product_id, biz_type, biz_no, qty, balance_qty, create_time库存流水payable_flowid, supplier_id, biz_no, amount, direction, create_time应付流水stock_flow 的 balance_qty 是个关键设计每次变动时计算该商品的最新结存并写入流水行查当前库存直接取最后一条流水即可省去反复 SUM 的开销。代价是并发下可能出现余额错位所以库存变动操作都要用数据库行锁或服务层同步块保护。表之间用的是逻辑外键而不是物理外键。设计文档里说明了原因历史数据要归档迁移物理外键在导入数据时容易卡住逻辑外键让导出导入更灵活。实际查询全部用 JOIN 完成影响不大。4.2 核心代码采购入库的完整调用链从界面点保存开始一次采购入库的调用链是PurchaseView.save - PurchaseController.save - PurchaseService.save - PurchaseDao.insertDoc - PurchaseDao.insertItems - ProductDao.changeStock - StockFlowDao.insert - PayableFlowDao.insertservice 保存的简化代码public void savePurchase(PurchaseDoc doc, ListPurchaseItem items) throws Exception { Connection conn DbUtil.getConnection(); boolean oldAutoCommit conn.getAutoCommit(); try { conn.setAutoCommit(false); String docNo DocNoGenerator.next(RK); doc.setDocNo(docNo); docDao.insert(doc); for (PurchaseItem item : items) { item.setDocId(doc.getId()); itemDao.insert(item); // 库存增加 productDao.changeStock(item.getProductId(), item.getQty()); // 写库存流水 stockFlowDao.insert(item.getProductId(), PURCHASE, docNo, item.getQty()); } // 写应付流水 payableFlowDao.insert(doc.getSupplierId(), docNo, doc.getTotalAmount()); conn.commit(); } catch (Exception e) { conn.rollback(); throw e; } finally { conn.setAutoCommit(oldAutoCommit); DbUtil.close(conn); } }逻辑说明先关闭自动提交保证主表、明细、库存、流水在同一个事务里DocNoGenerator.next(RK) 生成唯一单据号productDao.changeStock 执行的是 UPDATE base_product SET stock_qty stock_qty ? WHERE id ?影响行数为 0 说明商品已被逻辑停用要抛异常回滚stockFlowDao.insert 里会重新查询当前库存并写入 balance_qty保证流水余额和商品库存一致。参数说明items 由界面表格逐行拼出来qty 用 BigDecimaltotalAmount 在 service 里重新求和覆盖前端传值防止人为改价。这条在详细设计文档里是重点标注是从「能用」到「敢用」的差别。红冲操作的代码和保存对称生成新单据号数量取负数库存变动是负数方向。负数量的单据在报表里单独标记月底对账时一正一负自然抵消。4.3 登录与权限控制实现sys_user 表带 role 字段角色分管理员、仓管员、业务员。登录时校验用户名密码密码用 MD5 加固定盐登录成功把用户对象放进 SessionManager 内存容器。public User login(String username, String password) { String sql SELECT * FROM sys_user WHERE username ? AND password ? AND status 1; User user userDao.findByUsernameAndPwd(sql, username, md5WithSalt(password)); if (user ! null) { SessionManager.put(user.getUsername(), user.getRole()); } return user; }权限控制分成菜单级和按钮级。菜单级在 view 层根据角色隐藏窗口按钮级在 controller 判断当前用户是否有操作权限。这样业务员登录后看不到系统管理菜单能看入库单查询按钮保存按钮是否可见由权限决定。登录这块有一个遗留问题MD5 加盐只是防同事看明文不是防外部攻击。系统定位是内网工具这个强度够用但一旦要公网部署密码哈希要换成 BCrypt登录接口要做失败次数锁定。二次开发清单里我会把这条放在第一位。5. 避坑指南环境搭建与运行期最常翻车的 5 个点5.1 环境准备JDK 与数据库版本怎么配建议组合是 JDK 8 MySQL 5.7 IDEA 2020 以上。JDK 8 是 Swing 时代最稳的组合JDK 9 之后模块化对老代码偶有兼容问题。MySQL 8 也能用但要改驱动类和 URL 参数不换的话启动直接抛 ClassNotFoundException。MySQL 5.7 环境下建库时字符集选 utf8mb4。utf8mb4 和 utf8 的差别是前者能存 emoji 和生僻字对进销存影响不大但统一用 utf8mb4 可以避免后续导入商品名带特殊字符时报错。版本选择这件事没有玄学就是把组合固定住。我一般会先确认本机有没有多个 JDK 版本IDEA 里 Project Structure 的 SDK 和 Modules 的 Language Level 都要指到 JDK 8。很多诡异报错其实是编译用的 JDK 版本和运行用的不一致造成的。5.2 数据库初始化与配置文件修改用 Navicat 新建数据库 erp_db字符集选 utf8mb4然后依次执行 sql 目录下的两个脚本。erp_data.sql 里带了演示账号和演示数据登录进去就能看到商品、供应商和几张历史单据。接着改 src/main/resources/db.properties把密码换成自己的。改完后先跑一次 com.erp.util.DbUtilTest 的 main 方法测连接打印「连接成功」再启动界面能省下大量排查时间。这个测试入口不是每个进销存都有有的话优先用。执行完脚本可以顺手验证一下数据SELECT COUNT(*) FROM base_product如果返回几条演示商品说明导入成功。如果表存在但没数据多半是只执行了建表脚本演示数据脚本被漏了。演示数据对排查问题很有用尤其是做报表联调时空库看不出汇总逻辑对错。注意登录账号默认是 admin/123456连真实局域网数据库前先去系统管理里改掉。5.3 启动客户端与黑匣子排查启动类在 com.erp.Main运行 main 方法会弹出登录窗口。如果闪退看控制台异常九成是数据库连不上或驱动类不对。Swing 老项目在部分 Linux 上还会遇到字体显示不全给 JVM 加 -Dfile.encodingutf-8 参数一般能解决。如果双击 jar 包没反应不要反复点用命令行跑一次java -jar erp-client.jar命令行会直接打印异常堆栈比双击黑匣子靠谱得多。这一步实际上是所有 Java 桌面项目排错的第一动作。登录进去之后如果发现某些按钮点了没反应先别怀疑代码坏了检查当前账号的角色权限。管理员角色通常有全部权限业务员角色被菜单级权限挡住是预期行为。这种「没反应」最坑因为它不报错看起来像死锁实际上只是判断条件在 controller 里提前返回了。5.4 踩坑记录现象、原因、解决第一条导入 SQL 报错。现象是 Navicat 执行脚本到一半中断。原因通常是脚本头部带了 CREATE DATABASE 语句和当前连接冲突。解决删掉文件头部的 CREATE DATABASE 和 USE 语句再在已建好的库里执行。第二条中文乱码。现象是登录后商品名称显示为问号。原因是连接 URL 没带字符集参数。解决把 db.properties 的 URL 改成带 characterEncodingutf8 的完整写法重启客户端。第三条保存采购单卡住然后报锁等待。现象是两个窗口同时操作同一个商品一个保存时另一个转圈超时。原因是 Swing 多窗口各持连接MySQL 行锁竞争。解决在 service 层对同商品加同步块或者调大 innodb_lock_wait_timeout。第四条修改密码后登录失败。现象是管理员在数据库里直接改了用户表的密码字段然后怎么都登不进去。原因是密码存的是 MD5 加盐后的值手动更新的明文和登录校验逻辑不匹配。解决用界面提供的修改密码功能不要直接 UPDATE 数据库。第五条报表金额对不上。现象是采购汇总和应付余额差了几分钱。原因是某处用了 double 计算金额。解决全局搜索 double 类型在金额字段的使用全部替换成 BigDecimal然后重新跑一遍流水表的数据校验。这五条是我和同事在这类 C/S 项目上真实踩过的坑前三条属于环境配置后两条属于业务逻辑。如果你能在一开始就避开软删除和 BigDecimal 这两个雷后面省下的时间足够你再做一个模块。6. 二次开发实战给系统加一个「借还货管理」模块给客户借一批展示样货过几天还回来这是商贸公司很常见的业务但标准进销存主流程里没有这一项。我拿这个模块演示一遍从需求到表到代码的完整改造路径你会发现这套分层结构加模块比想象中顺手。先加两张表一张主表一张明细CREATE TABLE borrow_doc ( id BIGINT PRIMARY KEY AUTO_INCREMENT, doc_no VARCHAR(32) NOT NULL UNIQUE, customer_id BIGINT NOT NULL, borrow_date DATE NOT NULL, return_date DATE, creator VARCHAR(32), status TINYINT DEFAULT 0 COMMENT 0 借出 1 已还, remark VARCHAR(200) ); CREATE TABLE borrow_item ( id BIGINT PRIMARY KEY AUTO_INCREMENT, doc_id BIGINT NOT NULL, product_id BIGINT NOT NULL, qty DECIMAL(12,2) NOT NULL, return_qty DECIMAL(12,2) DEFAULT 0 );第二步写 DAO 和 Service借出时扣减库存归还时加回库存库存变动全部复用 StockFlowDao流水类型新增「BORROW」「RETURN」两种。复用流水表的好处是库存报表依然能从流水追溯不用单独维护一套借还统计。第三步加界面在 view 包新增 BorrowView参考 PurchaseView 的「表格 弹窗」结构在 MainFrame 的菜单里注册入口。Swing 改造不需要动框架复制一个现有 view 改字段绑定即可这也是当初选三层结构省下的时间。验证方法借出 10 个商品 A库存查询里 A 减少 10提交归还单 10 个库存恢复原值borrow_doc 的 status 变成 1同时 stock_flow 表能看到两条方向相反、类型清晰的流水记录。这一步验证的不只是界面而是整个事务链路是否闭合。最后补一句月底对账用的「未归还清单」SQL方便业务方催还SELECT bd.doc_no, c.name AS customer_name, bi.product_id, bi.qty FROM borrow_doc bd JOIN base_customer c ON bd.customer_id c.id JOIN borrow_item bi ON bi.doc_id bd.id WHERE bd.status 0;我自己的习惯是每加一个模块都走一遍这个流程先读需求文档确认规则再写表再写 DAO再写 Service最后补视图。从那以后我每次动这类老系统都会强制在文档里补一笔模块改动记录还要把验证 SQL 一起存进 doc 目录。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

instagram-private-api 响应类型解析:TopicalExploreFeedResponseFriendship_status 友谊状态结构详解

instagram-private-api 响应类型解析:TopicalExploreFeedResponseFriendship_status 友谊状态结构详解

后端 【免费下载链接】instagram-private-api NodeJS Instagram private API SDK. Written in TypeScript. 项目地址: https://gitcode.com/gh_mirrors/in/instagram-private-api 点击查看 免费下载 TopicalExploreFeedResponseFriendship_status 是 instagram-pri…

📅 2026/10/16 1:51:30
易语言数组操作实战:重定义数组与复制数组的用法、避坑与案例

易语言数组操作实战:重定义数组与复制数组的用法、避坑与案例

/* 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 1:51:30
markdownlint 规则实战:用 MD044/proper-names 强制统一专有名词大小写

markdownlint 规则实战:用 MD044/proper-names 强制统一专有名词大小写

开发工具代码质量Lint静态分析 【免费下载链接】markdownlint A Node.js style checker and lint tool for Markdown/CommonMark files. 项目地址: https://gitcode.com/gh_mirrors/ma/markdownlint 点击查看 免费下载 本篇文章围绕 markdownlint 仓库中的测试用例…

📅 2026/10/16 1:51:30
MORE NEWS

更多资讯

📰

SAP Fiori Elements实战:从CDS注解到RAP应用开发全解析

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

📰

实训5指纹设置全解析:从传感器原理到实操与安全

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

📰

语音特征提取全流程:从原始波形到MFCC特征向量

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

📰

Java线程start()方法原理与线程生命周期解析

1. 线程生命周期与start()方法本质当面试官抛出"为什么线程start()不能重复调用"这个问题时,实际上是在考察你对Java线程生命周期的理解深度。让我们先看一个典型的错误示例:Thread thread new Thread(() -> System.out.println("Run…

📰

Spring Cloud Gateway GatewayFilter 源码解析与责任链机制

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

📰

粒子群算法优化LQR的二级倒立摆控制设计与避坑实践

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

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

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

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

📞 💬