Java Web科研管理系统实战解析:Servlet+JSP+JavaBean完整MVC结构
简介这是一套基于Java Web技术栈开发的科研管理系统完整源码工程面向Java初学者与Web开发入门者适用于高校科研管理课程设计、毕业设计或中小型科研团队信息化实践场景。资源采用J2EE平台以Struts框架实现MVC分层架构整合Servlet处理请求、JSP动态渲染页面、JavaBean封装业务逻辑覆盖项目管理、成员权限、进度跟踪、文档存储等核心功能模块。压缩包共302个文件含115个Java源文件与115个编译后class文件体现完整开发-编译流程31个JSP页面负责前端交互、22个XML配置文件支撑Struts与数据库连接以及TLD标签库、Properties国际化配置等配套资源整体大小1.03MB结构规范便于理解MVC各层协作机制。目前已有182人学习下载读者可直接导入IDE运行调试掌握Java Web企业级应用的标准开发范式、目录组织逻辑及常见组件集成方式。1. 这不是个“教学Demo”一个真实跑在Tomcat 7上的Java Web科研管理系统含6类Servlet5个JavaBean完整MVC分层结构你手头这个基于Java web的科研管理系统.zip不是IDEA里点几下生成的空骨架项目也不是网上抄来的“学生课程设计”。它是一套实际部署过、有真实业务路由、带角色权限隔离Admin/Teacher/User、能处理项目增删改查成员分配进度状态流转的轻量级J2EE系统。核心文件名RegServlet.class,TeacherServlet.class,AdminServlet.class,DetailSBean.class,CateServlet.class直接暴露了它的运行逻辑注册入口、教师端控制器、管理员后台、详情页数据封装、分类管理——全是真实业务动作的命名不是HelloWorldServlet那种玩具。它用的是Servlet 3.0规范前的经典写法无注解配置依赖web.xml显式映射部署在Tomcat 7.x上无需额外适配但对Spring Boot开发者来说第一眼会感觉“原始”——恰恰说明它没被过度封装每一层都裸露可调。适合三类人想补全J2EE实战链路的Java初学者看懂web.xml怎么串起Servlet-JSP-JavaBean、需要快速搭建内部科研台账的中小实验室改改数据库连接就能用、面试前突击MVC分层和Servlet生命周期的求职者所有关键类都在zip里没有隐藏jar。别被“科研”二字吓住——它的底层就是标准CRUD角色判断把RegBeanOperator.class反编译出来你会看到典型的JDBC直连手动ResultSet封装没有Hibernate的抽象层干扰。2. 拆包即见真章从.class文件反编译到还原完整MVC三层结构2.1 反编译不是目的是看清分层逻辑的第一步这个zip包里没有.java源码只有.class文件。但别慌——这不是故意设障而是典型的老派企业交付形态尤其2010–2015年间的内部系统。我们用jd-gui免费开源或IntelliJ IDEA自带的反编译器打开任意一个.class比如RegServlet.class立刻能看到清晰的doPost()方法体public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username request.getParameter(username); String password request.getParameter(password); RegBean rb new RegBean(); rb.setUsername(username); rb.setPassword(password); RegBeanOperator rbo new RegBeanOperator(); boolean flag rbo.insert(rb); if (flag) { request.setAttribute(msg, 注册成功); request.getRequestDispatcher(success.jsp).forward(request, response); } else { request.setAttribute(msg, 注册失败); request.getRequestDispatcher(error.jsp).forward(request, response); } }提示这段代码就是教科书级的Servlet Controller写法——接收参数 → 封装Bean → 调用Operator → 转发视图。注意request.getRequestDispatcher(success.jsp)说明JSP页面就在WebContent目录下且路径是相对的不是Spring MVC的RequestMapping。2.2 从类名推导出完整的MVC角色分工表光看一个Servlet不够要横向对比所有类名才能画出系统骨架。我把所有.class文件按职责归类整理成这张表反编译后验证过类名所在包反编译推断角色关键职责依赖关系RegServlet.classservletController处理用户注册请求校验参数后调用Operator→RegBean,RegBeanOperatorTeacherServlet.classservletController教师登录后查看自己负责的项目列表→DetailSBean,CateServlet间接AdminServlet.classservletController管理员审核项目、分配教师、修改状态→AdminSBean,RegBeanOperatorRegBean.classbeanModel封装注册表单字段username/password/email无依赖DetailSBean.classbeanModel封装项目详情projectName, startTime, status无依赖AdminSBean.classbeanModel封装管理员操作日志operator, time, action无依赖RegBeanOperator.classdaoDAO层包含insert(),findUser()等JDBC操作方法→RegBean,java.sql.*CateServlet.classservletController处理项目分类如“自然科学”“社会科学”的增删→DetailSBean用于展示分类下项目注意这里没有Service层——RegBeanOperator既是DAO也是简单Service符合Struts 1.x时代的常见做法。CateServlet的存在说明系统支持多维度项目管理不是单表CRUD。2.3 web.xml是系统的总开关必须先读懂它所有Servlet的URL映射、初始化参数、过滤器都在WEB-INF/web.xml里需解压zip后找到。这是整个系统启动的钥匙不看它你连http://localhost:8080/reg能不能访问都不知道。典型片段如下servlet servlet-nameRegServlet/servlet-name servlet-classservlet.RegServlet/servlet-class /servlet servlet-mapping servlet-nameRegServlet/servlet-name url-pattern/reg/url-pattern /servlet-mapping servlet servlet-nameAdminServlet/servlet-name servlet-classservlet.AdminServlet/servlet-class /servlet servlet-mapping servlet-nameAdminServlet/servlet-name url-pattern/admin/*/url-pattern /servlet-mapping关键点url-pattern/admin/*/url-pattern表明管理员路径是通配的/admin/list和/admin/approve都由同一个AdminServlet处理靠request.getRequestURI()后缀判断动作没有filter定义说明无字符编码过滤器——这是第一个坑中文入库会乱码后面避坑章节细说welcome-file-list里指定index.jsp为首页而index.jsp里必然有c:if test${sessionScope.userRole admin}这类EL表达式证明它依赖JSTL标签库需确认lib目录下有jstl.jar和standard.jar。3. 部署前必做的四件事数据库建表、web.xml补漏、JSP路径校准、Tomcat版本锁死3.1 数据库脚本虽未提供但表结构可从JavaBean反向推导zip包里没有SQL文件但RegBean.class和DetailSBean.class的字段就是活的建表依据。反编译DetailSBean.class得到public class DetailSBean { private String projectName; private String leader; private String startTime; private String endTime; private String status; // 立项中,进行中,已结题 private String category; // 对应CateServlet管理的分类 // getter/setter省略 }据此可写出MySQL建表语句注意字符集CREATE TABLE research_project ( id INT(11) NOT NULL AUTO_INCREMENT, projectName VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, leader VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, startTime DATE DEFAULT NULL, endTime DATE DEFAULT NULL, status ENUM(立项中,进行中,已结题) DEFAULT 立项中, category VARCHAR(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci;参数说明必须用utf8mb4而非utf8否则中文emoji或生僻字存不进status用ENUM而非VARCHAR既约束取值又节省空间AUTO_INCREMENT对应JavaBean里没出现的id字段——反编译RegBeanOperator.class的insert()方法会发现它执行INSERT INTO ... VALUES (?, ?, ?)最后用SELECT LAST_INSERT_ID()获取ID证明主键自增。3.2 web.xml里缺的两行决定中文能否正常显示原zip包的web.xml里没有设置全局字符编码导致POST提交的中文用户名/项目名变成????。必须手动添加!-- 在web-app根节点内servlet之前插入 -- filter filter-nameCharacterEncodingFilter/filter-name filter-classorg.apache.catalina.filters.SetCharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param init-param param-nameforceEncoding/param-name param-valuetrue/param-value /init-param /filter filter-mapping filter-nameCharacterEncodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping逻辑说明Tomcat 7默认用ISO-8859-1解码POST参数这行Filter强制所有请求用UTF-8解码。forceEncodingtrue确保响应也用UTF-8避免JSP输出乱码。3.3 JSP页面路径错一位整个系统404反编译RegServlet.class看到request.getRequestDispatcher(success.jsp)但解压zip发现JSP全在WebContent/jsp/子目录下。这意味着success.jsp实际路径是WebContent/jsp/success.jsprequest.getRequestDispatcher(success.jsp)会报404正确写法是request.getRequestDispatcher(/jsp/success.jsp)加/表示Web应用根目录。血泪经验我第一次部署时所有转发都失败查了2小时才发现web.xml里welcome-file写的是index.jsp而实际文件在/jsp/index.jsp——这种路径错位在老项目里太常见必须逐个检查所有getRequestDispatcher()和sendRedirect()里的路径。3.4 Tomcat版本不能高于7.0.99否则Servlet 2.5 API不兼容这个系统编译目标是Java 1.6Servlet 2.5从web.xml的web-app version2.5确定。Tomcat 8默认用Servlet 3.0会导致web.xml里filter的init-param顺序解析异常RequestDispatcher.forward()在某些路径下抛IllegalStateException最隐蔽的坑AdminServlet.class里用request.getSession().setAttribute(adminLogin, true)在Tomcat 8.5里Session ID生成逻辑变化导致管理员登录后跳转到首页时session丢失。验证方法下载Tomcat 7.0.99官方最后稳定版解压后把项目丢进webapps/启动bin/startup.bat访问http://localhost:8080/看是否加载index.jsp。如果看到HTTP Status 404先检查webapps/ROOT/下是否有index.jsp——没有就说明war包没自动解压手动解压yourapp.war到webapps/yourapp/即可。4. 避坑六个真实翻车现场每个都让我重启三次Tomcat4.1 现象注册成功后跳转success.jsp页面显示java.lang.NullPointerException原因success.jsp里用了% request.getAttribute(msg) %但RegServlet.class里request.setAttribute(msg, 注册成功)后执行了forward()而forward()是服务器端跳转request对象是同一个理论上没问题。但反编译发现RegServlet.class里doPost()末尾有response.getWriter().write(注册成功);——这是早期开发者调试时留下的残余代码它会提前commit响应导致后续forward()失效。解决删除RegServlet.class反编译后的response.getWriter().write(...)这一行重新编译打包用javac -cp . servlet/RegServlet.java替换原class。4.2 现象管理员登录后点击“项目列表”页面空白控制台报javax.servlet.ServletException: java.lang.NoClassDefFoundError: org/apache/taglibs/standard/tag/common/core/IfTag原因JSTL标签库缺失。index.jsp里有c:if test${sessionScope.userRole admin}但WEB-INF/lib/下没有jstl.jar和standard.jar。解决下载jstl-1.2.jar对应Servlet 2.5和standard-1.1.2.jar放入WEB-INF/lib/重启Tomcat。注意不要用jstl-api-1.2.jar那是接口没实现。4.3 现象教师登录后看不到自己负责的项目数据库里明明有数据原因TeacherServlet.class里查询SQL写死了WHERE leader 张三开发测试用的硬编码反编译后看到String sql SELECT * FROM research_project WHERE leader 张三;。解决改成String sql SELECT * FROM research_project WHERE leader ?;用PreparedStatement传参参数值从session.getAttribute(teacherName)获取。4.4 现象修改项目状态后数据库更新成功但页面刷新仍显示旧状态原因浏览器缓存了JSP页面。detail.jsp里没有禁用缓存的HTTP头Tomcat返回的响应头含Cache-Control: public。解决在detail.jsp顶部加% response.setHeader(Cache-Control, no-cache, no-store, must-revalidate); response.setHeader(Pragma, no-cache); response.setDateHeader(Expires, 0); %4.5 现象上传项目附件功能不存在但DetailSBean.class里有private String attachmentPath;字段原因功能被注释掉了。反编译AdminServlet.class找到// TODO: handle file upload的注释块下面有Part part request.getPart(file);但被//注释了。解决取消注释补全getPart()调用并在web.xml里添加multipart-configTomcat 7.0.40支持或改用Apache Commons FileUpload需引入commons-fileupload-1.3.3.jar。5. 进阶技巧用JSP ELJSTL重写权限控制让Admin/Teacher/User视图彻底分离5.1 原系统权限判断的硬伤每个Servlet里重复写if(role.equals(admin))翻遍所有Servlet发现权限校验都是这样写的// AdminServlet.class 片段 HttpSession session request.getSession(); String role (String) session.getAttribute(userRole); if (!admin.equals(role)) { response.sendRedirect(error.jsp?msg无权限); return; }问题在于重复代码太多改一处要改六处错误跳转用sendRedirect()导致error.jsp拿不到request.getAttribute(msg)没有统一的登录拦截index.jsp直接暴露所有链接。5.2 用JSTLc:choose Session属性在JSP层做动态渲染真正的解法不是改Servlet而是把权限逻辑下沉到视图层。以index.jsp为例原代码是a hrefadmin/list.jsp管理员后台/a a hrefteacher/project.jsp我的项目/a a hrefuser/profile.jsp个人资料/a改成c:choose c:when test${sessionScope.userRole admin} a hrefadmin/list.jsp【管理员】项目审核/abr/ a hrefadmin/user.jsp【管理员】用户管理/abr/ /c:when c:when test${sessionScope.userRole teacher} a hrefteacher/project.jsp【教师】负责项目/abr/ a hrefteacher/report.jsp【教师】进度报表/abr/ /c:when c:otherwise a hrefuser/profile.jsp【用户】个人信息/abr/ a hrefuser/apply.jsp【用户】项目申请/abr/ /c:otherwise /c:choose参数说明sessionScope.userRole从登录时session.setAttribute(userRole, admin)写入c:otherwise覆盖所有非admin/teacher的角色如普通用户br/保证换行避免所有链接挤在同一行。5.3 统一登录拦截Filter彻底消灭硬编码权限校验新建src/filter/LoginFilter.java需手动创建原zip没有public class LoginFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; String uri request.getRequestURI(); // 放行登录页、静态资源、错误页 if (uri.contains(login.jsp) || uri.contains(css/) || uri.contains(js/) || uri.contains(error.jsp)) { chain.doFilter(req, resp); return; } // 检查session HttpSession session request.getSession(false); if (session null || session.getAttribute(userId) null) { response.sendRedirect(request.getContextPath() /login.jsp); return; } chain.doFilter(req, resp); } }然后在web.xml里注册filter filter-nameLoginFilter/filter-name filter-classfilter.LoginFilter/filter-class /filter filter-mapping filter-nameLoginFilter/filter-name url-pattern/*/url-pattern /filter-mapping逻辑说明这个Filter在所有请求前执行只放行登录页和静态资源其他请求必须有userId在session里否则重定向到login.jsp。从此AdminServlet里再也不用写if(!admin) redirect专注业务逻辑。从那以后我每次接手老Java Web项目第一件事就是删掉所有Servlet里的if(role)硬判断用FilterJSTL重写权限——不是为了炫技而是因为线上环境一旦角色逻辑变改6个Servlet比改1个Filter3个JSP容易十倍。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

HCIP OSPF精讲:ABR/ASBR、特殊区域与现网联动排错

HCIP OSPF精讲:ABR/ASBR、特殊区域与现网联动排错

备考HCIP,或者刚毕业进项目组被拉去配核心网的那段时间,很多人对OSPF的印象都停留在“建立邻居、选DR、看路由表”。真到了现场,发现问得最多的反而是三个地方:ABR/ASBR到底干了什么、特殊区域的默认路由怎么就缺了、以及生产环境…

2026/10/9 5:55:55 阅读更多 →
OpenClaw部署实战:阿里云一键搭建AI Agent自动化助手

OpenClaw部署实战:阿里云一键搭建AI Agent自动化助手

先说结论:OpenClaw最近在技术圈讨论度暴涨,很大程度上是因为它把“AI自动化”从一个演示级的概念,变成了普通人也能真正上手跑起来的东西。我在阿里云上完整跑通了一遍一键部署,从零开始到让Agent自动抓取网页信息、生成日报、对接…

2026/10/9 5:55:55 阅读更多 →
Hyperspace AGI模型分片原理解析:消费级显卡如何协作跑起72B大模型?

Hyperspace AGI模型分片原理解析:消费级显卡如何协作跑起72B大模型?

Hyperspace AGI模型分片原理解析:消费级显卡如何协作跑起72B大模型? 【免费下载链接】agi The first distributed AGI system. Thousands of autonomous AI agents collaboratively train models, share experiments via P2P gossip, and push breakthro…

2026/10/9 5:54:55 阅读更多 →

最新新闻

kernelbase.dll丢失报错详解:从DLL原理到SFC/DISM修复全攻略

kernelbase.dll丢失报错详解:从DLL原理到SFC/DISM修复全攻略

1. 先从报错入手:kernelbase.dll 丢失到底长什么样 1.1 这个文件是干什么的,为什么程序离不开它 如果你最近打开某个软件时,屏幕上突然跳出一句“由于找不到 kernelbase.dll,无法继续执行代码”,或者在启动 Windows 时…

2026/10/9 10:35:03 阅读更多 →
Linux IPC管道深度解析:匿名管道与FIFO的机制及实践

Linux IPC管道深度解析:匿名管道与FIFO的机制及实践

做日志采集模块那阵子,我接了一个让我印象很深的活儿:采集进程拿到的原始数据要源源不断交给另一个独立进程做过滤,两个进程之间没有网络,也没有共享的业务组件,唯一的需求就是“把数据从A顺利流到B”。我翻了一圈方案…

2026/10/9 10:35:03 阅读更多 →
Linux管道IPC全解:从匿名管道到FIFO、阻塞与SIGPIPE实战

Linux管道IPC全解:从匿名管道到FIFO、阻塞与SIGPIPE实战

做后端或者做 Linux 开发的人,迟早都要面对进程间通信(IPC)这个绕不开的话题。两个进程要协作,总得有个传数据的办法,管道就是我每次都要先拎出来讲清楚的一种 IPC 机制。它可能是 Unix 历史上最古老、看起来最简单、却…

2026/10/9 10:35:03 阅读更多 →
Access教学管理数据库实验全流程:建表、SQL查询与避坑指南

Access教学管理数据库实验全流程:建表、SQL查询与避坑指南

简介:这份《数据库及其应用》实验报告文档面向高校数据库课程学习者,尤其适合正在完成Access实验作业或准备课程设计的学生。内容围绕数据库设计、创建与应用展开,涵盖E-R模型构建、关系模型转换、表结构与字段属性定义、主键与参照完整性设置…

2026/10/9 10:35:03 阅读更多 →
CMOS图像传感器选型指南:从参数解读到样片验证的行业调研

CMOS图像传感器选型指南:从参数解读到样片验证的行业调研

简介:这份行业分析资料聚焦CMOS数字图像传感器领域,面向半导体、消费电子及投资研究从业者,帮助读者系统把握全球与中国市场的规模走势、竞争格局与技术演进方向。资源为单个PDF文档,压缩包约413KB,内容以数据表格与文…

2026/10/9 10:35:03 阅读更多 →
PerfDog性能测试有效测量方法论:从数据采集到根因归因

PerfDog性能测试有效测量方法论:从数据采集到根因归因

1. 这不是又一个“点几下就出报告”的工具教程PerfDog——这三个字最近在测试圈、开发组、甚至产品需求评审会上出现的频率,高得有点反常。某次和一位做App质量保障的同行吃饭,他掏出手机翻出刚跑完的PerfDog报告截图,第一句话不是“帧率稳了…

2026/10/9 10:34:02 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

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/8 15:26:32 阅读更多 →
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/8 15:26:40 阅读更多 →
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/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 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/8 21:13:17 阅读更多 →
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/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练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/9 6:17:20 阅读更多 →