From 2d826474bb6bcddd1b4ceadaa4b13b84ddf9a54d Mon Sep 17 00:00:00 2001 From: Codex Date: Tue, 24 Mar 2026 12:28:16 +0800 Subject: [PATCH] feat: enhance learning dashboard visuals --- web/WEB-INF/views/index.jsp | 213 +++++++++++++++++++++++++++++++++++- 1 file changed, 211 insertions(+), 2 deletions(-) diff --git a/web/WEB-INF/views/index.jsp b/web/WEB-INF/views/index.jsp index 43c7831..4e4c517 100644 --- a/web/WEB-INF/views/index.jsp +++ b/web/WEB-INF/views/index.jsp @@ -216,6 +216,79 @@ color: var(--muted); text-align: center; } + .learning-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 14px; + margin-top: 18px; + } + .learning-panel { + border: 1px solid var(--line); + border-radius: 20px; + padding: 18px; + background: rgba(255,255,255,0.65); + box-shadow: inset 0 4px 12px rgba(18,32,51,0.06); + } + .learning-panel h3 { + margin: 0 0 6px; + font-size: 18px; + } + .learning-panel p { + margin: 0; + color: var(--muted); + line-height: 1.6; + } + .flow-steps { + margin-top: 12px; + display: flex; + flex-direction: column; + gap: 10px; + } + .flow-step { + padding: 10px; + border-radius: 14px; + border: 1px solid rgba(20,100,199,0.25); + background: rgba(13,143,124,0.06); + } + .flow-step strong { + display: block; + font-size: 14px; + } + .chain-pill { + display: inline-flex; + padding: 6px 10px; + border-radius: 999px; + border: 1px solid var(--line); + background: #ffffff; + font-size: 12px; + margin-right: 6px; + margin-top: 6px; + } + .insight-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + gap: 16px; + margin-top: 16px; + } + .insight-card { + border-radius: 20px; + padding: 18px; + border: 1px solid var(--line); + background: linear-gradient(135deg, rgba(255,255,255,0.9), rgba(255,255,255,0.7)); + min-height: 200px; + position: relative; + } + .insight-card strong { + display: block; + margin-top: 10px; + font-size: 22px; + color: var(--brand); + } + .insight-card ul { + margin: 10px 0 0 16px; + color: var(--muted); + line-height: 1.6; + } @media (max-width: 1100px) { .layout { grid-template-columns: 1fr; } .grid, .pipeline, .metrics { grid-template-columns: 1fr 1fr; } @@ -395,6 +468,78 @@ + +
+
可视化学习
+

Struts2 请求与鉴权流程图

+

通过时序卡片展示请求到达、拦截、执行和结果之间的关系,并把登录保护链路具体化,增强讲解能力。

+
+
+
请求生命周期
+

请求进入 → Action → 结果

+

Struts2 将 URL 映射到 Action,执行之前先跑拦截器,再决定返回的 JSP 或 JSON。

+
+
+ 1. 请求进来 +

Dispatcher 解析 namespace 与 action,构造参数并执行

+
+
+ 2. 拦截器链 +

`AuthInterceptor` 检测 Session,其他拦截器做参数/校验/文件准备

+
+
+ 3. 结果输出 +

Action 返回 SUCCESS/INPUT,Struts 渲染 JSP 或 JSON,浏览器读取响应

+
+
+
+
+
Action → Interceptor → Result
+

链式控制:操作 → 鉴权 → 渲染

+

每个请求都必须穿过这个三段式,理解它能帮助你解释 Struts2 的核心执行模型。

+
Action
+
Interceptor
+
Result
+

Action 负责业务,拦截器负责验证/鉴权,Result 负责视图渲染或 JSON 返回。

+
+
+
+ +
+
学习洞察
+

关键链路 & 实验对照

+
+
+
登录保护链路
+

Session 登录 + 拦截器

+

运用 `LoginAction`、`AuthInterceptor` 和 `DashboardAction` 来完成端到端登录和受保护导航。

+
    +
  • 输入 admin / 123456 写入 Session
  • +
  • `AuthInterceptor` 拦截未登录访问
  • +
  • 登录后跳转到专属仪表盘再进实验
  • +
+
+
+
表单绑定 & 校验
+

数据绑定观察卡片

+

从 `userFormPage` 到 `submitUser`,展示字段绑定、校验触发和成功结果的行为差异。

+
    +
  • 字段名:Action 属性与表单 `name` 一一对应
  • +
  • 验证逻辑:`UserAction#submit` 里点亮不同结果
  • +
  • 成功后跳转 `user/success.jsp` 显示绑定概览
  • +
+
+
+
JSON 对照模块
+

AJAX vs REST

+

并列演示 `ajax.action`(AJAX JSON)和 `api/users.action`(REST JSON)的输出差异,便于讲解 Struts 如何扩展接口。

+
    +
  • `ajax.action` 面向浏览器交互,返回 `success` + data
  • +
  • `api/users.action` 保持 REST 语义,便于讲解 JSON 策略
  • +
+
+
+
@@ -489,7 +634,39 @@ cardJsonTitle: "AJAX 与 REST 风格返回", cardJsonText: "保留 JSON 动作和 REST 风格示例,用来说明经典 MVC 项目如何逐步演进到接口输出。", cardJsonAjax: "打开 AJAX JSON", - cardJsonRest: "打开 REST JSON" + cardJsonRest: "打开 REST JSON", + learningBoardEyebrow: "可视化学习", + learningBoardTitle: "Struts2 请求与鉴权流程图", + learningBoardDesc: "用时序卡片展示请求穿越 Action、拦截器和 Result 的全链路,让讲解更直观。", + timelineEyebrow: "请求生命周期", + timelineTitle: "请求进入 → Action → 结果", + timelineDesc: "Struts2 先解析 action,再跑拦截器,最后决定 JSP 或 JSON 的渲染。", + timelineStep1: "1. 请求进来", + timelineStep1Text: "Dispatcher 解析 namespace、action,注入参数并准备执行。", + timelineStep2: "2. 拦截器链", + timelineStep2Text: "`AuthInterceptor` 检查 Session,其它拦截器做校验/上传处理。", + timelineStep3: "3. 结果输出", + timelineStep3Text: "Action 返回 SUCCESS/INPUT,Struts 渲染 JSP 或 JSON 回应。", + chainEyebrow: "Action → Interceptor → Result", + chainTitle: "链式控制:操作 → 鉴权 → 渲染", + chainDesc: "中间拦截器决定请求是否通过,结果决定渲染视图或接口响应。", + chainExplain: "Action 负责业务,Interceptor 掌握鉴权细节,Result 才真正交给浏览器。", + insightEyebrow: "学习洞察", + insightTitle: "关键链路与实验对照", + loginCardTitle: "Session 登录 + 拦截器", + loginCardDesc: "用 `LoginAction`、`AuthInterceptor` 和仪表盘串起端到端链路。", + loginCardItem1: "输入 admin / 123456 写入 Session", + loginCardItem2: "`AuthInterceptor` 拦截未登录访问", + loginCardItem3: "登录后跳转仪表盘再进入实验页", + bindingCardTitle: "表单绑定观察卡片", + bindingCardDesc: "从用户表单到 `submitUser`,看字段绑定与校验行为如何变化。", + bindingCardItem1: "字段名与 Action 属性一一对应", + bindingCardItem2: "`UserAction#submit` 根据校验返回不同结果", + bindingCardItem3: "成功后跳转 `user/success.jsp` 显示汇总", + jsonCardTitle: "AJAX vs REST JSON", + jsonCardDesc: "对照 `ajax.action` 与 `api/users.action` 的输出,讲解 Struts JSON 扩展。", + jsonCardItem1: "`ajax.action` 面向浏览器交互,返回 success + 数据", + jsonCardItem2: "`api/users.action` 保持 REST 格式,便于接口讲解" }, html: { helperList: "
  • 先看登录和仪表盘,理解最经典的 Session 鉴权链路。
  • 再看表单、校验、上传,理解 Action 如何接收与处理输入。
  • 最后再看 AJAX 和 REST 风格返回,理解 Struts2 的扩展能力。
  • " @@ -562,7 +739,39 @@ cardJsonTitle: "AJAX and REST responses", cardJsonText: "Keeps JSON and REST-style samples to show how a classic MVC project can evolve into API output.", cardJsonAjax: "Open AJAX JSON", - cardJsonRest: "Open REST JSON" + cardJsonRest: "Open REST JSON", + learningBoardEyebrow: "Visual learning", + learningBoardTitle: "Struts2 request & auth flow", + learningBoardDesc: "Timeline cards highlight how requests traverse Action, Interceptor and Result so the flow is easier to explain.", + timelineEyebrow: "Request lifecycle", + timelineTitle: "Inbound → Action → Result", + timelineDesc: "The dispatcher resolves the action, runs interceptors, then chooses which JSP or JSON should render.", + timelineStep1: "1. Request arrives", + timelineStep1Text: "Dispatcher maps namespace/action, binds parameters, prepares execution.", + timelineStep2: "2. Interceptor chain", + timelineStep2Text: "`AuthInterceptor` enforces session while others handle validation/uploads.", + timelineStep3: "3. Result output", + timelineStep3Text: "Action returns SUCCESS/INPUT and Struts renders JSP or JSON back to the browser.", + chainEyebrow: "Action → Interceptor → Result", + chainTitle: "Control chain: ops → auth → render", + chainDesc: "Interceptors decide if the request passes; the result determines view or API output.", + chainExplain: "Action owns business logic, Interceptor handles guardrails, Result delivers the final payload.", + insightEyebrow: "Learning insights", + insightTitle: "Key links & lab comparison", + loginCardTitle: "Session login + interceptor", + loginCardDesc: "`LoginAction`, `AuthInterceptor`, and the dashboard string together a safe auth chapter.", + loginCardItem1: "Submit admin / 123456 to write session", + loginCardItem2: "`AuthInterceptor` blocks unauthenticated access", + loginCardItem3: "Successful login lands on dashboard before labs", + bindingCardTitle: "Form binding snapshot", + bindingCardDesc: "Observe how the user form, validation, and result respond to field binding and checks.", + bindingCardItem1: "Form field names mirror Action properties", + bindingCardItem2: "`UserAction#submit` routes based on validation", + bindingCardItem3: "Success page shows a structured summary", + jsonCardTitle: "AJAX vs REST JSON", + jsonCardDesc: "Line up `ajax.action` and `api/users.action` to explain Struts JSON modes.", + jsonCardItem1: "`ajax.action` targets browser interactions with success + payload", + jsonCardItem2: "`api/users.action` stays RESTy for API teaching" }, html: { helperList: "
  • Start with login and the dashboard to understand the classic session-auth path.
  • Move to forms, validation, and upload to see how actions receive and process input.
  • Finish with AJAX and REST-style responses to explain Struts2 extension points.
  • "