SpreadJS ReportSheet 与 DataManager 实现 Token 鉴权:全流程详解与代码解析

SpreadJS ReportSheet 与 DataManager 实现 Token 鉴权:全流程详解与代码解析

在 Web 应用开发中,接口安全是核心需求之一,基于 Token 的身份验证是保障接口不被未授权访问的主流方案。SpreadJS 作为专业的前端表格控件,其报表插件(ReportSheet)常需从后端接口拉取数据展示,但默认请求未内置 Token 传递能力。

本文将基于 GrapeCity 官方示例,详细梳理 "后端鉴权服务搭建→前端 Token 配置→报表数据渲染→Token 动态更新" 的全流程,并为关键代码添加逐行解释,帮助开发者快速理解并落地 Token 鉴权功能。

一、前置准备:搭建支持 Token 鉴权的后端服务

首先需要创建一个 Node.js + Express 后端服务,核心目标是:提供需 Token 鉴权的学生数据接口,并模拟鉴权逻辑。

环境与依赖配置

后端服务依赖 3 个核心库:express(搭建 Web 服务)、cors(解决跨域,因前端 SpreadJS 与后端端口不同)、body-parser(解析 JSON 格式请求体)。

步骤 1:初始化项目与依赖
  1. 新建项目文件夹(如 spreadjs-token-backend),执行 npm init -y 生成默认 package.json
  2. 替换 package.json 内容(指定入口文件、脚本命令与依赖):

json

JavaScript 复制代码
{
  "name": "spreadjs-token-demo",
  "version": "1.0.0",
  "main": "student.js", // 后端入口文件
  "scripts": {
    "start": "node student.js", // 启动服务的命令
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
    "body-parser": "^1.20.2", // 解析JSON请求体
    "cors": "^2.8.5", // 允许跨域请求
    "express": "^4.18.1" // 搭建Web服务的核心库
  }
}

1.执行 npm install 安装所有依赖。

编写后端服务代码(student.js)

核心功能:定义学生数据源、配置跨域、实现 "无鉴权测试接口" 与 "Token 鉴权接口"。

JavaScript 复制代码
// 1. 引入依赖库
const express = require("express"); // 引入Express库,用于创建Web服务
const cors = require("cors"); // 引入CORS库,解决跨域问题
const bodyParser = require('body-parser'); // 引入body-parser,解析JSON请求体

// 2. 初始化Express实例(创建服务对象)
const app = express();

// 3. 配置服务中间件
app.use(cors()); // 启用CORS中间件:允许所有跨域请求(生产环境可限制域名)
app.use(bodyParser.json()); // 启用JSON解析中间件:将请求体转为JSON格式

// 4. 定义数据源:学生列表(模拟数据库数据,实际项目需连接真实数据库)
const studentList = [
  { id: 1, name: "张三", age: 18, sex: 1, classId: 1, grade: "高一" },
  { id: 2, name: "李四", age: 17, sex: 1, classId: 1, grade: "高一" },
  { id: 3, name: "王五", age: 18, sex: 0, classId: 2, grade: "高二" },
  { id: 4, name: "赵六", age: 17, sex: 0, classId: 2, grade: "高二" },
  { id: 5, name: "孙七", age: 16, sex: 1, classId: 3, grade: "高三" }
];
// 数据优化说明:年龄调整为16-18岁(符合高中学生身份),新增grade字段(丰富数据维度)

// 5. 接口1:无鉴权接口(用于测试服务是否正常运行)
app.get("/student", (req, res) => {
  // req:请求对象(包含请求参数、头信息等);res:响应对象(用于返回数据)
  res.json(studentList); // 直接返回所有学生数据(JSON格式)
});

// 6. 接口2:Token鉴权接口(ReportSheet实际调用的接口)
app.get("/studentByToken", (req, res) => {
  // 6.1 从请求头中获取Token(前端需将Token放在Authorization头中)
  const token = req.headers["authorization"]; 
  console.log("当前请求Token:", token); // 打印Token到控制台(便于调试)

  // 6.2 模拟鉴权逻辑(实际项目需用JWT/OAuth2验证Token有效性)
  // 逻辑:仅返回"学生id与Token匹配"的数据(模拟"不同Token对应不同用户权限")
  const authorizedStudents = studentList.filter(item => item.id == token);

  // 6.3 返回鉴权后的结果(若Token无效/不匹配,返回空数组)
  res.json(authorizedStudents);
});

// 7. 启动服务(监听3000端口)
app.listen(3000, () => {
  console.log("后端服务已启动:http://localhost:3000"); // 服务启动成功的提示
});

测试后端服务

确保服务正常运行,避免前端联调时因后端问题阻塞:

  1. 执行 npm run start 启动服务;
  2. 通过浏览器 / Postman 测试两个接口:
    1. 访问 http://localhost:3000/student:返回所有学生数据(无鉴权,验证服务可用性);
    2. 访问 http://localhost:3000/studentByToken(需手动添加请求头 Authorization: 1):返回 "张三" 数据(验证鉴权逻辑);
    3. 若不添加 Authorization 头:返回空数组(验证鉴权拦截逻辑)。

二、前端实现:用 DataManager 配置 Token 并渲染 ReportSheet

前端核心逻辑:通过 SpreadJS 的 DataManager 配置 Token 请求头,结合 ReportSheet 渲染鉴权后的数据,并支持 Token 动态更新。

引入 SpreadJS 依赖

需在 HTML 中引入 SpreadJS 核心库、ReportSheet 插件(通过 CDN 引入,无需本地下载):

HTML 复制代码
<!-- SpreadJS 核心CSS -->
<link rel="stylesheet" href="https://cdn.grapecity.com/spreadjs/16.2.4/css/gc.spread.sheets.excel2013white.css">

<!-- SpreadJS 核心JS -->
<script src="https://cdn.grapecity.com/spreadjs/16.2.4/scripts/gc.spread.sheets.all.min.js"></script>
<!-- ReportSheet 插件JS -->
<script src="https://cdn.grapecity.com/spreadjs/16.2.4/scripts/plugins/gc.spread.sheets.reportdesigner.min.js"></script>

    <button id="reset">更新token</button>
    <div id="gc-designer-container" style="width:100%; height: 100vh"></div>

前端核心逻辑代码

前端代码分 4 个核心步骤:初始化 SpreadJS 工作簿、配置带 Token 的数据源、创建 ReportSheet 报表、实现 Token 动态更新。

JavaScript 复制代码
// 等待页面DOM加载完成后执行(避免操作未渲染的元素)
document.addEventListener("DOMContentLoaded", async function () {
  // ===================== 步骤1:初始化SpreadJS设计器与工作簿 =====================
  // 1.1 创建SpreadJS设计器(Designer):包含工作簿(Workbook),支持可视化操作
  const designer = new GC.Spread.Sheets.Designer.Designer(
    document.getElementById("gc-designer-container") // 绑定容器元素
  );
  
  // 1.2 从设计器中获取工作簿(Workbook是SpreadJS的核心对象,管理所有工作表)
  const spread = designer.getWorkbook();


  // ===================== 步骤2:用DataManager配置带Token的数据源 =====================
  // 2.1 创建DataManager实例(用于管理数据源,处理数据请求/同步)
  const dataManager = spread.dataManager();

  // 2.2 定义初始Token(实际项目中可从LocalStorage/Cookie读取,如用户登录后存储的Token)
  const initialToken = "1";

  // 2.3 向DataManager添加"student"数据表(关联后端鉴权接口)
  // await:等待数据加载完成(因fetch(true)是异步操作)
  await dataManager.addTable("student", {
    remote: { // 远程数据源配置(表示数据来自后端接口)
      read: { // read:配置"读取数据"的请求参数
        url: 'http://localhost:3000/studentByToken', // 后端鉴权接口地址
        // options:类似Fetch API的RequestInit配置,用于设置请求头/方法等
        options: { 
          headers: { 
            "Authorization": initialToken // 关键:将Token添加到请求头
          }
        }
      }
    }
  }).fetch(true); // fetch(true):添加表后立即拉取数据(true表示强制刷新)


  // ===================== 步骤3:创建ReportSheet报表并绑定数据 =====================
  // 3.1 添加ReportSheet工作表(类型为reportSheet,区别于普通表格)
  const reportSheet = spread.addSheetTab(
    0, // 工作表索引(0表示第一个工作表)
    '学生报表', // 工作表名称
    GC.Spread.Sheets.SheetType.reportSheet // 工作表类型(报表类型)
  );

  // 3.2 获取报表的"模板工作表"(TemplateSheet):用于配置报表结构(表头、数据绑定)
  const templateSheet = reportSheet.getTemplate();

  // 3.3 定义报表列:对应学生数据的字段(与后端返回字段一致)
  const columns = ['id', 'name', 'age', 'sex', 'classId', 'grade'];

  // 3.4 渲染报表模板(循环生成表头与数据绑定单元格)
  columns.forEach((columnName, index) =&gt; {
    // 3.4.1 设置表头(第0行,第index列):显示字段的中文名称
    const headerMap = { // 字段名与中文表头的映射(提升报表可读性)
      id: "学生ID",
      name: "姓名",
      age: "年龄",
      sex: "性别(1=男/0=女)",
      classId: "班级ID",
      grade: "年级"
    };
    templateSheet.setValue(0, index, headerMap[columnName] || columnName);

    // 3.4.2 设置数据绑定(第1行,第index列):将单元格与"student"表的字段关联
    templateSheet.setTemplateCell(1, index, {
      type: "List", // 绑定类型:List(表示列表数据,适合报表展示)
      binding: `student[${columnName}]` // 绑定规则:"表名[字段名]"
    });
  });

  // 3.5 刷新报表:确保数据加载后立即渲染到页面
  reportSheet.refresh();


  // ===================== 步骤4:实现Token动态更新与数据刷新 =====================
  // 4.1 给"更新Token"按钮绑定点击事件
  document.getElementById('reset').addEventListener('click', async function () {
    // 4.2 获取已创建的"student"数据表(从DataManager中获取)
    const myTable = spread.dataManager().tables["student"];

    // 4.3 修改数据表的请求配置:更新Token为2(实际项目可从用户输入/状态管理中获取新Token)
    const newToken = "2";
    const options = myTable.options; // 获取当前表的配置
    options.remote.read = { // 重写read配置(替换新Token)
      url: 'http://localhost:3000/studentByToken', // 保持接口地址不变
      options: { 
        headers: { "Authorization": newToken } // 新Token
      }
    };
    myTable.options = options; // 重新赋值配置(触发DataManager更新)

    // 4.4 重新拉取数据(强制刷新,使用新Token)
    await myTable.fetch(true);

    // 4.5 刷新当前报表:展示新Token对应的鉴权数据
    spread.getActiveSheetTab().refresh();
  });
});

三、功能验证与结果

初始化状态

页面加载完成后,DataManager 用初始 Token=1 请求接口,报表仅展示 "张三"(id=1)的数据:

学生 ID 姓名 年龄 性别(1 = 男 / 0 = 女) 班级 ID 年级
1 张三 18 1 高一

更新 Token 后

点击 "更新 Token 为 2(获取李四数据)" 按钮,DataManager 用新 Token=2 重新请求,报表刷新后展示 "李四"(id=2)的数据:

学生 ID 姓名 年龄 性别(1 = 男 / 0 = 女) 班级 ID 年级
2 李四 17 1 高一

四、关键说明与扩展建议

1.RequestInit 配置的灵活性

DataManagerremote.read.options 与 Fetch API 的 RequestInit 完全兼容,除了 headers,还可配置:

  • method: "POST":若后端接口为 POST 类型,可添加该配置;
  • body: JSON.stringify({ param: "value" }):若需传递请求体(如筛选参数),可通过 body 配置;
  • credentials: "include":若需携带 Cookie(如单点登录场景),可添加该配置。

2.实际项目的 Token 优化

示例中 Token 为固定值,实际项目需优化为:

  • Token 存储:将用户登录后的 Token 存储在 LocalStorageSessionStorage(如 localStorage.setItem("token", "xxx"));
  • Token 读取:初始化 / 更新 Token 时,从存储中读取(如 const token = localStorage.getItem("token"));
  • Token 过期处理:在 DataManager 请求失败回调中捕获 401 状态码,跳转至登录页。

3.全局 Token 管理

若项目中有多个 DataManager 请求,可封装全局请求拦截器,避免重复配置 Token:

JavaScript 复制代码
// 封装全局请求配置函数function getRequestOptions(token) {return {headers: {"Authorization": token,"Content-Type": "application/json"}};}// 多个表复用该函数
dataManager.addTable("student", {remote: {read: { url: "xxx", options: getRequestOptions(token) }}});
dataManager.addTable("teacher", {remote: {read: { url: "xxx", options: getRequestOptions(token) }}});

通过以上步骤,可完整实现 SpreadJS ReportSheet 与 DataManager 的 Token 鉴权功能,兼顾安全性与灵活性,适配实际项目的接口访问需求。

扩展链接

可嵌入您系统的在线Excel

相关推荐
勤劳打代码2 小时前
触类旁通 —— Flutter 与 React 对比解析
前端·flutter·react native
Mintopia2 小时前
🧠 可解释性AIGC:Web场景下模型决策透明化的技术路径
前端·javascript·aigc
Mintopia2 小时前
⚙️ Next.js 事务与批量操作:让异步的世界井然有序
前端·javascript·全栈
若梦plus2 小时前
多端开发之React-Native原理浅析
前端·react native
新兵蛋子02 小时前
基于 vue3 完成领域模型架构建设
前端
今禾2 小时前
Git完全指南(中篇):GitHub团队协作实战
前端·git·github
Tech_Lin2 小时前
前端工作实战:如何在vite中配置代理解决跨域问题
前端·后端