1. 概述与系统背景 (Overview & Background)

在浙江万里学院的本科人才培养方案中,除正方教务管理系统(JWGLXT)负责的主修培养方案、通识选修与专业排课外,第二课堂的实践创新、学科竞赛、科研课题与军训社会实践均纳入独立的素质拓展项目管理平台(下称“素质特质/素拓系统”,访问域名:http://sztz.zwu.edu.cn)。

该系统负责学生在校期间 4.0 基准毕业素质学分 的全生命周期管理,包括项目申报、学生选报、审核通过、中期检查、结题考核与最终学分认定。传统 Web 页面采用较为老旧的表格排版,缺乏全局达成度进度分析、筛选排序能力薄弱且缺少移动端自适应。

本篇文档系统记录针对 sztz.zwu.edu.cn 的抓包逆向过程、架构技术栈特征、鉴权机制、全业务 URL 路由映射(URL Route Map)以及基于 Python/Flask 构建现代化看板与自动化选修客户端的工程实践。


2. 目标系统技术栈画像 (System Architecture & Footprint)

通过探测重定向链与响应头,确认目标系统的核心技术栈组成:

  • 网关路由与重定向链 (Redirect Chain):
    http://sztz.zwu.edu.cn ➔ 302 重定向至 https://sztz.zwu.edu.cn/ ➔ 302 重定向至 /a ➔ 302 重定向至 /a/login;JSESSIONID=...。
  • 后端框架架构:
    经典 JeeSite (v3.x / v4.x 演进版) 快速开发平台,基于 Spring MVC + Apache Shiro + MyBatis 架构,Servlet 上下文统一以 /a(代表 Admin/Application)作为根路径。
  • 前端渲染技术:
    采用 jQuery 1.9.1 + jQuery EasyUI 1.5 (easyui-datagrid) + Bootstrap 3 + Metronic Theme。页面为服务端 JSP 渲染骨架,主体表格数据通过 EasyUI DataGrid 异步以 AJAX POST 请求 JSON 填充。
  • 会话 Cookie 标识:
    session.id(32位十六进制字符串,Apache Shiro 默认的会话管理器 sessionIdCookie 名称)。

3. 鉴权机制与会话生命周期 (Authentication & Session Lifecycle)

3.1 登录机制逆向分析 (Login Analysis)

与正方教务系统强制跳转金智 CAS 单点登录(pass.zwu.edu.cn)不同,素质拓展系统采用独立的 Shiro 表单认证网关(FormAuthenticationFilter),但后端用户凭据与学校统一身份认证账号库实时互通:

  1. 会话握手:
    首次请求 GET https://sztz.zwu.edu.cn/a/login,服务端在响应头写入:

    Set-Cookie: session.id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; Path=/; HttpOnly
  2. 表单凭据提交:

    POST /a/login HTTP/1.1
    Host: sztz.zwu.edu.cn
    Content-Type: application/x-www-form-urlencoded
    Referer: https://sztz.zwu.edu.cn/a/login
    
    username=<学号>&password=<统一认证密码>&rememberMe=false
  3. 认证结果校验:

    • 登录成功:服务端返回 302 Found,Location: /a;JSESSIONID=...,并更新 session.id Cookie。
    • 登录失败:服务端返回 302 Found,Location: /a/login(重定向回登录页),或直接在页面渲染错误提示。
    • 验证码机制:系统默认初次提交不启用验证码;仅在同一 IP 连续登录失败次数超过安全阈值后,才会动态唤醒 /servlet/validateCodeServlet。自动化客户端在初次登录阶段无需处理验证码 OCR。

4. 核心业务接口映射 (Core Business Endpoints & URL Map)

系统所有核心业务数据接口均采用标准 JSON 格式进行输入与输出,总结路由表如下:

4.1 学生学分画像与个人档案 (Student Profile & Credit Statistics)

  • 接口路径:POST /a/business/qualityDevCourseStatistics/getStuScoreInfo
  • 请求类型:application/x-www-form-urlencoded(无参数,从当前 Session 获取主体)
  • 返回结构 (JSON):

    {
      "userid": "947931",
      "loginName": "2025013540",
      "name": "谢凯旋",
      "departmentName": "信息与智能工程学院",
      "majorName": "电子信息工程",
      "className": "电子25A1",
      "grade": "2025",
      "js": "0.5",
      "ky": "0",
      "pxkz": "0",
      "sjcx": "0",
      "zh": "0",
      "jl": "0",
      "zz": "0",
      "yj": "0",
      "defaultscore": "4"
    }
  • 字段语义说明:

    • defaultscore: 毕业基准学分要求(通常为 4.0 学分)。
    • js: 军事技能与军事理论模块学分。
    • ky: 科研创新类项目学分。
    • pxkz: 培训考证类学分。
    • sjcx: 实践创新类学分。
    • zh: 综合素质拓展类学分。
    • jl: 奖励加分(各级学科竞赛等)。
    • zz: 组织活动与志愿服务学分。
    • yj: 预警扣分项。

4.2 素质项目选修列表检索 (Course Catalog Query)

  • 接口路径:POST /a/business/qualityDevCourse/grid
  • 请求类型:application/x-www-form-urlencoded
  • 请求参数:

    • page: 当前页码(从 1 开始)。
    • rows: 每页条数(如 15、20、50)。
    • unit: 开课学院 ID(可选,如 "10246" 代表信息与智能工程学院,空字符串代表全部)。
    • searchWord: 模糊检索关键词(支持匹配项目名称、主讲教师姓名、项目编号)。
  • 返回结构 (JSON):

    {
      "total": 197,
      "rows": [
        {
          "id": "21837",
          "name": "单片机应用开发",
          "unitString": "大数据与软件工程学院",
          "teacherString": "毕春跃",
          "typeString": "综合",
          "maxscore": "2",
          "minscore": "0",
          "pnumber": "30",
          "npnumber": "0",
          "startDateString": "2026-2027/1",
          "purpose": "立项目的与意义...",
          "content": "主要建设与教学内容...",
          "plan": "实施计划与时间表...",
          "astandard": "考核与评分细则...",
          "autojoin": "1"
        }
      ]
    }
  • 技术亮点:
    服务端在 grid 列表中已经直接附带了每个项目的完整立项书内容(purpose、content、plan、astandard),客户端无需二次发起详情请求即可完整渲染项目详情大纲与给分细则。

4.3 学生已选与认定档案穿透 (My Courses & Credit History)

  • 接口路径:POST /a/business/qualityDevStatistics/gridForStudent
  • 请求类型:application/x-www-form-urlencoded
  • 请求参数:

    • condition: 查询状态条件标识:

      • creditConfirm: 学分已确认认定项目(已正式计入毕业学分档案)。
      • preSelect: 选修待通过项目(处于教师审核或管理员初审阶段)。
      • elective: 选修已通过项目(已获准修读、正在进行中的项目)。
    • page: 页码。
    • rows: 分页容量。

4.4 已认定课程明细 (Certified Course Breakdown)

  • 接口路径:POST /a/business/qualityDevCourseStatistics/courseDetail
  • 请求类型:application/json; charset=utf-8
  • 请求体:

    { "stuid": "947931" }
  • 返回结构 (JSON):包含每门已锁定认定项目的完整信息(如竞赛获奖项目名称、指导老师、修读学期、认领得分)。

4.5 项目选修申请与退选 (Enrollment & Revocation)

  • 选修提交接口:

    • 路径:POST /a/business/qualityDevCourse/submit
    • 请求头:Content-Type: application/json; charset=utf-8
    • 请求体:

      { "qdid": "<项目ID>" }
    • 响应:{"success": true, "msg": "已成功提交选课"} 或 {"success": false, "msg": "..."}。
  • 退选 / 撤销申请接口:

    • 路径:POST /a/business/qualityDevCourse/revoke
    • 请求头:Content-Type: application/json; charset=utf-8
    • 请求体:

      { "qdid": "<项目ID>" }
    • 响应:{"success": true, "msg": "已成功取消选修该项目"}。

4.6 基础字典数据 (Metadata Endpoints)

  • 开课学院列表:POST /a/business/qualityDevCreate/getTeacherDepartments(返回全校11个开课学院与部门 ID/名称映射)。
  • 项目分类列表:POST /a/business/qualityDevCreate/getQDType(JSON Payload: {"isspec": 0},返回科研、竞赛、综合、实践创新、培训考证等类别)。
  • 学期列表:POST /a/business/qualityDevCreate/getTermList。

5. 核心选课规则与机制深度分析 (Business Rules)

在逆向分析 endpoint_quality_course.html 与 endpoint_quality_surplus.html 的前端逻辑时,发现了素质拓展系统特有的选课学分分流机制:

// 前端选课限制逻辑
var needscore = parseFloat("4");
var currentscore = parseFloat(".5"); // 当前已获学分
if (currentscore >= needscore) {
    confirmword = "您的素质学分已经满足毕业要求, 若继续选课将按额外超额修读收费...";
}
  1. 常规选修区间 (currentscore < 4.0):
    学生所修读学分属于本科培养方案基本学分,直接在“可选修项目”中报名,免收额外学分学费。
  2. 额外收费区间 (currentscore >= 4.0):
    当学生已修满 4.0 学分后,系统前端菜单将导向“额外收费选修项目(surplus)”,选修将按超额学分进行结算。
  3. 名额容量实时监控:
    每个项目具备 pnumber(计划招收人数)与 npnumber(当前已报名人数)。自动化脚本可通过对比两者差值实现对热门项目(如单片机实训、算法科研)的余量监控与补选探测。

6. 工程化实现与架构设计 (Engineering Implementation)

基于上述逆向成果,在 zwu-sztz-tools 中实现了全套自动化工具链:

  1. sztz_client.py (SDK 核心层):

    • 封装 Shiro Cookie 状态保持、超时自愈重登。
    • 严格类型标注,结构化封装八大分类学分画像计算器。
    • 统一 JSON/Form-data 序列化与异常捕获。
  2. cli.py (终端交互层):

    • 基于 rich 库构建终端看板,设置 legacy_windows=False 与 sys.stdout.reconfigure(encoding='utf-8') 解决 Windows 中文控制台编码冲突。
    • 提供 profile、my-courses、search、info、select、revoke 等子命令。
  3. web_app.py & index.html (现代 WebUI 看板):

    • 基于轻量级 Flask 后端(运行于 http://127.0.0.1:8001)。
    • 单页响应式前端(Tailwind CSS + FontAwesome + 无外部重型框架依赖)。
    • 具备进度条环形达成度展示、分学院/类别实时过滤、项目立项大纲与给分细则弹窗、选课安全二次核验机制。

7. 踩坑与经验总结 (Lessons Learned & Pitfalls)

序号现象 / 踩坑点根本原因 (Root Cause)最佳解决方案 (Resolution)
1requests.post 请求 /getQDType 报错 HTTP 400 Bad Request服务端 Spring Controller 使用 @RequestBody 注解,仅接受 application/json 且必须包含 {"isspec": 0}设置 headers={'Content-Type': 'application/json'} 并传入 JSON 体
2Windows 控制台打印 Rich 进度条报 UnicodeEncodeError: 'gbk' codec can't encode character '\u2591'Windows 早期控制台默认代码页为 CP936,无法编码 Unicode 渐变阴影字符脚本入口增加 sys.stdout.reconfigure(encoding='utf-8'),Rich Console 显式配置 legacy_windows=False
3无法找到单独的项目立项详情 API平台设计为在 EasyUI datagrid 的 grid 接口中一次性吐出项目全量富文本字段直接在列表数据中提取 purpose、content、plan、astandard,减少网络请求往返
4多系统并行运行端口冲突教务系统 WebUI 默认监听 8000 端口,若同时启动素质拓展 WebUI 会产生端口占用将素质拓展 WebUI 端口固定为 8001,实现两套工具链无缝并行工作


本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/Web