首页/新闻资讯/正文详情

JSP+Servlet+MySQL图书馆管理系统:从源码到超期提醒改造

发布时间:2026/9/25 13:23:20 来源:云帆数科 栏目:资讯中心
JSP+Servlet+MySQL图书馆管理系统:从源码到超期提醒改造
简介这是一套基于JSP、Servlet与MySQL的图书馆图书管理系统源码适合Java Web初学者、在校学生及毕业设计开发者可用于快速搭建图书管理项目并理解分层架构与角色权限设计。系统内置管理员、游客、学生三类角色管理员可完成用户管理、图书管理、罚款缴纳等操作学生可进行图书借阅、图书归还、借阅记录查看及密码修改游客能浏览全部图书与图书详情覆盖图书馆日常管理的典型业务流程。资源压缩包共包含112个文件核心是45个Java源文件对应控制层与数据访问层实现另有24个JSP页面用于前端展示37张PNG图片与2个GIF可用于界面参考还带有说明文档与参考手册整体大小仅1.76MB下载后即可解压查看。代码中包含登录过滤、验证码生成、图片处理、借阅数据访问等常见功能模块并配合文档和截图便于读者对照实际页面理解前后端交互也适合迁移到课程设计或毕业设计中使用。目前已有263人学习下载是在深入学习框架之前巩固Servlet/JSP基础、了解小型管理系统完整开发流程的一份实用参考。1. 这套 JSP 图书馆系统是 JavaWeb 课程设计里最值得先跑通的项目如果你正在找 jspmysqlservlet 方向的毕设或课设源码大概率会撞见这个标题图书馆图书管理系统。它几乎是 JavaWeb 课程设计案例源码里最经典的一类功能边界清楚图书入库、读者管理、借书还书、逾期查询数据量不大但 JSP、Servlet、JDBC、MySQL 全都用上了。很多人下载之后卡在第一步——不知道这个项目该怎么导入、该用什么版本的 Tomcat、MySQL 密码改了之后连不上怎么办。这篇文章以这套图书管理系统为载体从表结构讲到最后能跑通、能改造你照着做就能把项目从压缩包变成能在浏览器里点开的系统。2. 系统骨架JSP、Servlet、MySQL 各管哪一段2.1 为什么是 JSP Servlet而不是 Spring Boot这个项目对应的技术栈是 JSP 做页面展示、Servlet 做请求控制、MySQL 存业务数据这是典型的 JavaWeb 三层结构在课程设计里的呈现方式。放在今天看Spring Boot 集成 JSP 的坑比这个多得多反而是这套组合逻辑最直白浏览器发请求给 ServletServlet 调 DAO 查 MySQL拿到结果转发给 JSP 渲染页面。理解整个读源码的顺序就会很顺先把 web.xml或者 Servlet 3.0 的注解里的 URL 映射摸清楚再看每个 Servlet 的 doGet/doPost 里做了什么然后顺着 DAO 层找到 SQL 语句。这套系统的可改造空间也在这里想加功能就是在 Servlet 里加一个分支再补一张表JSP 里加个表单不用理解 Spring 的 IoC 和 AOP。2.2 必须先建好的三张核心表不管拿到的源码包里有没有 SQL 文件我建议你先把数据库表结构手敲一遍因为表结构是这套系统里最值得抄的作业。图书管理系统的核心表通常就三张图书表、读者表、借阅表外加一张管理员表用于登录。下面是常见的表结构CREATE DATABASE IF NOT EXISTS library DEFAULT CHARSET utf8mb4; USE library; CREATE TABLE t_book ( id INT PRIMARY KEY AUTO_INCREMENT, book_name VARCHAR(100) NOT NULL COMMENT 书名, author VARCHAR(50) COMMENT 作者, publisher VARCHAR(100) COMMENT 出版社, price DECIMAL(6,2) COMMENT 定价, stock INT DEFAULT 1 COMMENT 库存, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; CREATE TABLE t_reader ( id INT PRIMARY KEY AUTO_INCREMENT, reader_no VARCHAR(20) UNIQUE NOT NULL COMMENT 借书证号, reader_name VARCHAR(50) NOT NULL, phone VARCHAR(20), max_borrow INT DEFAULT 5 COMMENT 最大可借数量 ) ENGINEInnoDB; CREATE TABLE t_borrow ( id INT PRIMARY KEY AUTO_INCREMENT, book_id INT NOT NULL, reader_id INT NOT NULL, borrow_time DATETIME DEFAULT CURRENT_TIMESTAMP, due_time DATETIME COMMENT 应还时间, return_time DATETIME NULL COMMENT 实际归还时间, FOREIGN KEY (book_id) REFERENCES t_book(id), FOREIGN KEY (reader_id) REFERENCES t_reader(id) ) ENGINEInnoDB;在建表时参数有讲究。DEFAULT CHARSET utf8mb4必须写在库级别否则插入中文书名时很可能报Incorrect string value错误。AUTO_INCREMENT是 MySQL 8.0 前后的标准写法MySQL 5.7 同样兼容。DECIMAL(6,2)表示价格最大 9999.99对图书定价够用除非你要存那种上万的绝版书。借阅表里用外键约束关联图书和读者这样删数据时有约束兜底不会出现在借书记录还在、书却没了的情况。2.3 JDBC 连接串里最容易出错的三个参数系统的 DAO 层全部通过 JDBC 访问 MySQL连接串一般写在db.properties或DBUtil.java里。很多新手拿到源码后报Communications link failure问题不在代码而在连接串参数// DBUtil.java 中的关键连接参数 String url jdbc:mysql://localhost:3306/library ?useSSLfalse serverTimezoneAsia/Shanghai characterEncodingutf8; String user root; String password 你自己的密码;useSSLfalse是必须的本地开发没配证书MySQL 8.0 默认开了 SSL 校验不关就会握手失败。serverTimezone必须指到具体时区MySQL 8.x 的驱动要求显式时区否则报The server time zone value错误。characterEncodingutf8要和表结构的 utf8mb4 配套这样查询结果返回中文时才不会乱码。另外提醒一点mysql-connector-java 的版本要和 MySQL 服务端对应MySQL 8.0 配 8.0.x 驱动5.7 配 5.1.49 也未尝不可但 8.0 的服务端配合 5.1.x 的老驱动会有认证协议问题。3. 把源码跑起来本地环境的完整操作路径3.1 从 zip 解压到 IDEA 项目导入拿到的是.zip源码包里面的目录结构一般是src/源码目录、web/或者WebContent/页面目录、.sql数据库脚本、README.txt说明文档。用 IDEA 导入时不要直接 Open 这个解压后的文件夹而是新建一个空项目然后把源码目录拷进去这样能避免 IDEA 把压缩包目录当成普通文件夹处理。我一般习惯这么做先解压 zip确认里面有 pom.xml 还是 .classpath 文件。如果项目里有 pom.xml那说明是 Maven 工程直接用 IDEA 的 Open 选择 pom.xml 即可如果只有.classpath和.project说明是传统 Eclipse 工程IDEA 里选择 Import Project勾选 Eclipse 格式。很多课程设计源码是没接 Maven 的靠的是 WEB-INF/lib 下直接放了一堆 jar 包这时候要检查lib目录里有没有 servlet-api.jar、mysql-connector-java.jar没有就要手动补。3.2 Tomcat 版本和 Artifact 配置导入之后就是配置 Tomcat。JSP 图书管理系统这类老项目最稳妥的组合是 Tomcat 8.5 JDK 8不需要上 Tomcat 10。因为 Tomcat 10 把javax.servlet换成了jakarta.servlet老源码里的import javax.servlet.*全部编译不过除非你会批量替换包名否则别在环境上给自己找麻烦。IDEA 里配置 Tomcat 的步骤固定Run → Edit Configurations → 点 号选 Tomcat Server → Local → 在 Application server 里选择你本机 Tomcat 路径。然后切到 Deployment 页签点 选 Artifact注意要选带war exploded后缀的那个效果是热部署改了 JSP 刷新页面就生效不用重新构建整个 war 包。这里要专门提一下“传统jsp项目打包war”的问题等你调试好了想交付可以在 IDEA 的 Build → Build Artifact 里选 war 包打出来的包丢到 Tomcat 的 webapps 目录就能用。但对课程设计来说war exploded 模式更实际。3.3 数据库初始化的两种途径拿到手的源码要么带.sql脚本要么让你手动建表。我的建议是先执行项目的.sql再对照第 2 节的表结构检查缺不缺字段因为不同版本的系统表结构差异很大有的带t_book_type图书分类表有的把管理员和读者混在一张表里。mysql -u root -p library.sql执行完之后用show tables;确认表建好了再插几条测试数据INSERT INTO t_book (book_name, author, publisher, price, stock) VALUES (数据库系统概论, 王珊, 高等教育出版社, 45.00, 10);测试数据的意义在于你启动项目后立刻就能验证列表页有内容而不是对着空页面怀疑自己配错了。3.4 从启动到浏览器看见登录页Tomcat 配置好、数据库就绪之后按 ShiftF10 启动 Tomcat。日志出现Server startup in [xxx] milliseconds代表启动成功控制台没有报错不代表项目部署成功你得确认日志里有Deployment of web application archive这段IDEA 里还要检查 Artifact 是否成功 exploded。浏览器访问http://localhost:8080/项目名/login.jsp看到登录页就说明跑通了。如果出现 404检查 URL 里的项目名是不是和 Artifact 名称一致如果出现 500去 IDEA 控制台看异常栈这个阶段 90% 的错误都是数据库连接问题按第 2.3 节的参数改完再重启即可。4. 读懂核心流程从登录到借书的一条完整链路4.1 Servlet 生命周期在这个系统里的实际表现刚才在环境阶段提到了 Servlet这个系统就是理解 servlet 生命周期最直观的教材。Servlet 从创建到销毁要经历 init、service、destroy 三个阶段。在项目里LoginServlet被第一次请求时Tomcat 创建实例并调用init()每次请求都走service()内部根据 method 分发到doGet()或doPost()Tomcat 关闭时调用destroy()。你在源码里检查一下如果 Servlet 用了WebServlet(/login)注解这走的是 Servlet 3.0 规范如果要在 web.xml 里配servlet-mapping那是老写法。两种方式共存时注解的优先级高于 web.xml但很多源码两个都有且路径不一样这时候要留意实际生效的是哪个。我的判断方法是启动后访问注解里的路径能通就说明注解起作用web.xml 里的死配置不用管。4.2 登录功能的代码走读JSP 表单到数据库验证现在走一遍登录流程这是最典型的 JSP Servlet MySQL 配合。JSP 页面负责呈现表单Servlet 拿到参数调用 DAO 层查询数据库。下面是核心代码// LoginServlet.java 核心逻辑 WebServlet(/login) public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(utf-8); String username request.getParameter(username); String password request.getParameter(password); AdminDao dao new AdminDao(); Admin admin dao.findByUsernameAndPassword(username, password); if (admin ! null) { request.getSession().setAttribute(admin, admin); response.sendRedirect(request.getContextPath() /book/list); } else { request.setAttribute(msg, 用户名或密码错误); request.getRequestDispatcher(/login.jsp).forward(request, response); } } }这套代码占了老 JavaWeb 项目的八成写法几个关键点要理解。setCharacterEncoding必须在getParameter之前调用否则表单里提交的中文用户名在 Tomcat 8 以下会乱码。登录成功用sendRedirect而不是forward因为 forward 停留在当前请求刷新页面会重复提交表单重定向会发起新请求URL 变成 book/list逻辑上才是跳转后的正确状态。登录失败用forward是刻意为之这样登录页能拿到msg属性在表单上方显示错误提示。4.3 借书操作事务边界是手写代码最容易翻车的地方借书这个功能看着简单插入一条借阅记录把图书库存减一。但在 JDBC 里这是两个数据库操作中间任何一个失败都会造成数据不一致。不少源码直接两条 SQL 一写就完事没包事务你能跑通是运气好并发一上来借阅记录插进去了、库存没减下来。// BorrowDao.java 借书事务处理 Connection conn DBUtil.getConnection(); try { conn.setAutoCommit(false); // 关闭自动提交事务开始 String sqlBorrow INSERT INTO t_borrow (book_id, reader_id, due_time) VALUES (?, ?, DATE_ADD(NOW(), INTERVAL 30 DAY)); PreparedStatement ps1 conn.prepareStatement(sqlBorrow); ps1.setInt(1, bookId); ps1.setInt(2, readerId); ps1.executeUpdate(); String sqlStock UPDATE t_book SET stock stock - 1 WHERE id ? AND stock 0; PreparedStatement ps2 conn.prepareStatement(sqlStock); ps2.setInt(1, bookId); int rows ps2.executeUpdate(); if (rows 0) { conn.rollback(); // 库存不足回滚借阅记录 throw new RuntimeException(库存不足); } conn.commit(); } catch (Exception e) { conn.rollback(); throw e; } finally { conn.setAutoCommit(true); DBUtil.close(conn, ps1, ps2); }这是你可以在原系统基础上动手改的第一处把原来的两条裸 SQL 包进事务。注意UPDATE ... AND stock 0这个条件很关键它不是简单减一而是带库存校验的原子操作在并发场景下比先查库存再更新安全得多。养成这个习惯之后你去看很多课程设计源码都会发现这块是虚的。5. 运行这套系统时最常见的 5 个坑从现象到解决办法5.1 Tomcat 能启动但访问页面 404现象Tomcat 启动无报错http://localhost:8080/能开但加上项目名后访问不到登录页。原因排查顺序一是 Artifact 没部署成功打开 IDEA 的 Deployment 页签确认是否有一条记录二是项目名不对URL 里的路径必须和 Artifact 输出的名字一致比如 Artifact 叫library_war_explodedURL 就得是/library_三是 web.xml 里欢迎页没有配置访问根路径不显示 login.jsp。解决先访问http://localhost:8080/项目名/login.jsp绕过欢迎页问题如果这个地址能开说明部署没问题只是默认页没配这个地址也开不了就去 Tomcat 的 catalina 日志里找SEVERE: Error deploying。5.2 500 错误数据库连接失败的常见报错变体现象页面报 500控制台异常是Cannot create PoolableConnectionFactory或者Access denied for user rootlocalhost。原因一般有三个MySQL 服务没启动Windows 下用net start mysql启动服务Linux 下是systemctl start mysqld密码不对源码的 db.properties 里写的密码是自己本机 MySQL 的 root 密码很多人下载后没改MySQL 服务端口不是 3306。解决先用命令mysql -u root -p测试能不能本地连接连不上的问题在 MySQL 侧连得上再去改 db.properties 里的用户名密码和端口。注意还有一类隐蔽原因项目里的 mysql-connector-java.jar 版本和 MySQL 版本差太多。MySQL 8.0 环境配 5.1.x 驱动会报Public Key Retrieval is not allowed这时要么换 8.0.x 驱动要么在连接串后面追加allowPublicKeyRetrievaltrue。5.3 JSP 页面中文全是问号现象浏览器里显示的是???或者乱码数据库里存的中文也是问号。原因一定在“三段统一”没做到页面编码、请求编码、数据库编码要一致。JSP 页面顶部要写% page contentTypetext/html;charsetUTF-8 languagejava %这个不能少。请求参数编码在前面第 4.2 节说过必须在 getParameter 之前设置 characterEncoding。数据库层面建库时用了 utf8mb4但连接串没带 characterEncodingutf8会导致驱动用默认编码传输。还有一个细节IDEA 的文件编码设置里Global Encoding 和 Properties Files 都要改成 UTF-8否则源码里的中文注释在编译后就是乱码。5.4 数据库中文能显示但页面日期格式刺眼现象借书时间显示成2025-01-15 14:23:56.0带着小数点尾巴看着不像正式系统。原因MySQL DATETIME 到了 Java 的 ResultSet.getTimestamp()toString 的默认格式就是这种。JDBC 操作里可以用resultSet.getTimestamp(borrow_time)后 SimpleDateFormat 格式化或者直接在 SQL 里格式化输出。更推荐的改法是在 SQL 里处理不要动 Java 代码SELECT DATE_FORMAT(b.borrow_time, %Y-%m-%d %H:%i:%s) AS borrowTimeStr FROM t_borrow b%Y是四位年份%y是两位%i是分钟%s是秒这些大小写写错就不会格式化返回原始值。整个系统的 JSP 页面上只要把硬编码的日期输出改成这个别名页面展示问题全部解决。5.5 明明配置了连接池代码里用的还是 DriverManager现象源码里明明有 dbcp 或 c3p0 的配置文件但一运行还是每隔一段时间就报Connections could not be acquired日志里提示连接超时。原因项目里那套连接池配置是“国产式摆设”Service 层根本没有经过连接池拿连接还是DriverManager.getConnection()直连。解决这个问题就得把 DBUtil.getConnection() 改成从连接池取连接这是系统改造里的一个大动作。临时的捷径是调大 MySQL 的wait_timeout但治标不治本。我的建议是既然是课程设计不要求你引入连接池框架你只需要把 DBUtil 里的连接管理做成单例、用完必关即可比连接池更不容易在答辩时被问倒。6. 从能跑到能答辩给系统加上一个“超期未还”提醒这个改造难度不高但答辩时的演示效果非常好在首页放一张表把逾期未还的借阅记录直接列出来规则是return_time IS NULL AND due_time NOW()。SELECT r.reader_name, b.book_name, br.due_time, DATEDIFF(NOW(), br.due_time) AS overdue_days FROM t_borrow br JOIN t_reader r ON br.reader_id r.id JOIN t_book b ON br.book_id b.id WHERE br.return_time IS NULL AND br.due_time NOW() ORDER BY br.due_time ASC;DATEDIFF算出来的overdue_days就是逾期天数。在 JSP 首页用 jstl 的c:forEach循环渲染这张表即可。如果源码没有引入 JSTL那就把这个 SQL 结果用普通的while (rs.next())循环输出成表格行。这个改造的聪明之处在于没有改动核心表结构只加了查询没有改 Servlet 映射只动了查询数据源数据库函数用的是 MySQL 5.7 和 8.0 都兼容的日期函数不会因为你换了 MySQL 版本就翻车。做完之后你的系统就从“能登录、能借还”变成了“能发现业务异常”这在答辩时的描述是“逾期管理模块”分量立刻不一样。做 JavaWeb 项目这几年我最大的习惯是每次拿到一个源码不管多急都先把数据库脚本看懂再启动环境。因为代码可以骗人表结构不会它把整个业务边界画得清清楚楚。希望这篇笔记能帮你把这个经典课设项目跑通、看懂再上手改出属于你自己的功能点。本文还有配套的精品资源点击获取

相关推荐

Atlas 300V 24G推理卡部署YOLO实战:从环境配置到性能调优
Atlas 300V 24G推理卡部署YOLO实战:从环境配置到性能调优

1. 先聊清楚:Atlas 300V 24G到底是个什么卡先说结论:是的,Atlas 300V 24G就是一块推理加速卡,但它和很多人熟悉的GPU不是一类东西。我在第一次拿到这块卡的时候,也花了不少时间才彻底搞明白它的定位。Atlas 300V 24G在… · 2026/9/25 13:23:02

Win10日历显示节假日全攻略:官方订阅与ICS调休补班
Win10日历显示节假日全攻略:官方订阅与ICS调休补班

先问个扎心的问题:你上一次在电脑上正经打开Windows日历,是什么时候?我猜大多数人的答案都是“就没怎么用过”。这不能怪大家,因为Win10自带的日历应用默认状态实在太素了,打开之后只能看到光秃秃的星期和日期&#xf… · 2026/9/25 13:22:56

HTTP响应体被截断?详解skipped与truncated日志的排查方法
HTTP响应体被截断?详解skipped与truncated日志的排查方法

“http://www.xxx.com/ skipped. Content of size 67099 was truncated to 59363”这行日志,我猜搞过爬虫、写过后端网关或者天天跟 HTTP 接口打交道的人,多少都见过类似的东西。我第一次遇到时也是一脸懵:好好的 URL 怎么说跳过就跳过了&… · 2026/9/25 13:22:49

QualityInspector 无监督异常检测(UAD)实战指南:PaDiM / PatchCore / STFPM 训练、评估与预测
QualityInspector 无监督异常检测(UAD)实战指南:PaDiM / PatchCore / STFPM 训练、评估与预测

人工智能计算机视觉预训练 【免费下载链接】PaddleSeg Easy-to-use image segmentation library with awesome pre-trained model zoo, supporting wide-range of practical tasks in Semantic Segmentation, Interactive Segmentation, Panoptic Segmentation, Image Matting,… · 2026/9/25 15:01:50

GSD-Core 修复 `total_phases` 误计:非阶段章节标题不再污染里程碑阶段计数
GSD-Core 修复 `total_phases` 误计:非阶段章节标题不再污染里程碑阶段计数

【免费下载链接】gsd-core Git. Ship. Done - Core 项目地址: https://gitcode.com/gh_mirrors/ge/gsd-core 点击查看 免费下载 本篇文章聚焦 GSD-Core 中一个极具代表性的计数一致性修复(changeset #549):当 ROADMAP.md 中出现形… · 2026/9/25 15:01:44

ESPnet2 CMU ARCTIC TTS Recipe 实战指南:单说话人训练与 Pretrain-Finetune 微调全流程
ESPnet2 CMU ARCTIC TTS Recipe 实战指南:单说话人训练与 Pretrain-Finetune 微调全流程

人工智能语音音频深度学习NLP 【免费下载链接】espnet End-to-End Speech Processing Toolkit 项目地址: https://gitcode.com/gh_mirrors/es/espnet 点击查看 免费下载 CMU ARCTIC 是语音合成领域经典的英文单说话人朗读语料库,本指南围绕 ESPnet2 为其… · 2026/9/25 15:01:44

aws-doc-sdk-examples 的 premium-ex.md 解读:AWS SDK for Go V2 高质量示例清单与核心实现剖析
aws-doc-sdk-examples 的 premium-ex.md 解读:AWS SDK for Go V2 高质量示例清单与核心实现剖析

示例工程教程后端 【免费下载链接】aws-doc-sdk-examples Welcome to the AWS Code Examples Repository. This repo contains code examples used in the AWS documentation, AWS SDK Developer Guides, and more. For more information, see the Readme.md file below. 项目地… · 2026/9/25 15:01:38

rpcx 方法级服务注册:用 RegisterWithMethods 白名单只暴露指定方法
rpcx 方法级服务注册:用 RegisterWithMethods 白名单只暴露指定方法

后端微服务 【免费下载链接】rpcx Best microservices framework in Go, like alibaba Dubbo, but with more features, Scale easily. Try it. Test it. If you feel its better, use it! 𝐉𝐚𝐯𝐚有𝐝𝐮&… · 2026/9/25 15:01:38

ng-zorro-antd 实验性 Image 组件:基于 Loader 与 srcset 的图片加载优化实战指南
ng-zorro-antd 实验性 Image 组件:基于 Loader 与 srcset 的图片加载优化实战指南

UI组件前端 【免费下载链接】ng-zorro-antd Angular UI Component Library based on Ant Design 项目地址: https://gitcode.com/gh_mirrors/ng/ng-zorro-antd 点击查看 免费下载 导读 components/experimental-image/doc/index.en-US.md 是 ng-zorro-antd 提供的… · 2026/9/25 15:01:20

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

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

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

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

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

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

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码