ToolJet 实战:基于 AWS S3 构建文件上传与下载界面(完整 Queries 与 Widgets 配置指南)
【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 🚀项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet
本文是一份基于 ToolJet 官方 how-to 指南整理与源码扩充的实战教程,讲解如何在不写任何后端代码的前提下,使用 ToolJet 的 App Builder 组合 Dropdown、Table、Text Input、File Picker 与 Button 等组件,配合 AWS S3 数据源的 4 条核心查询(getBuckets、listObjects、uploadToS3、download),快速搭建一个可浏览 Bucket、列出对象、上传文件并生成下载链接的 S3 文件管理界面。读完本文,你将掌握 ToolJet 查询与组件之间的数据绑定、事件驱动刷新以及 base64 文件上传的标准写法,并了解底层 S3 查询服务的实现原理。
前置条件:先接入 AWS S3 数据源
在开始搭建 UI 之前,必须先完成 AWS S3 数据源(Data Source)的接入。ToolJet 官方文档在 AWS S3 数据源指南 中详细说明了配置方式,这里提炼关键步骤作为实战前置:
- 点击查询面板(Query Panel)左下角的+ 添加新数据源(Add new Data source)按钮,或从 ToolJet 仪表盘的数据源(Data Sources)页面进入;
- 选择Amazon AWS S3数据源;
- 根据你的运行环境选择认证方式,ToolJet 支持以下三种:
| 认证方式 | 需要提供的参数 | 适用场景 |
|---|---|---|
| IAM Access Keys | Region、Access key、Secret key | 最常见的长期凭证方式,官方建议为此创建专用 IAM 用户,便于控制 ToolJet 的访问权限级别 |
| AWS Instance Credentials | Region(勾选 Use AWS Instance Credentials) | ToolJet 运行在 EC2/ECS 上时,直接复用实例绑定的 IAM 角色 |
| AWS ARN Role | Region、Role ARN | 需要跨账号或按角色授权时,通过 STS AssumeRole 换取临时凭证 |
:::tip 如果使用的是非 AWS 的 S3 兼容存储,还可以通过自定义 endpoint 连接不同的 S3 Host,详见 S3 Custom Endpoints 指南(本文主题不展开)。 :::
从源码角度看,上述三种认证方式在 S3 插件中有对应的实现分支。以 插件实现 中的getConnection方法为例:
- 选择AWS Instance Credentials时,使用 AWS SDK 的
fromInstanceMetadata()创建S3Client,其内部通过timeout: 5000与maxRetries: 1控制元数据服务的访问超时与重试; - 选择AWS ARN Role时,插件会调用 getAssumeRoleCredentials,通过 STS 的
AssumeRoleCommand换取临时凭证(AccessKeyId、SecretAccessKey、SessionToken)后再创建客户端; - 使用IAM Access Keys时,直接以
access_key/secret_key构造凭证。
构建 UI:五个 Widgets 各司其职
接入数据源后,在 App Builder 画布上拖入以下组件,构成整个 S3 文件管理界面的骨架:
| Widget | 作用 |
|---|---|
| Dropdown | 用于选择 S3 存储桶(Bucket),其选项来自getBuckets查询结果 |
| Table | 用于列出所选 Bucket 内的全部对象(文件),数据来自listObjects查询结果 |
| Text Input | 用于输入文件上传的目标路径(前缀目录) |
| File Picker | 用于选择要上传的本地文件 |
| Button | 用于触发上传查询(uploadToS3) |
这 5 个组件分别承担"选桶 → 看文件 → 定路径 → 选文件 → 触发上传"的完整交互链路。下图是搭建完成后的界面效果:
四条核心 Queries 的完整配置
本次实战共需要创建 4 条查询,分别完成"列桶、列对象、生成下载链接、上传文件"四项能力。接下来逐一讲解每条查询的创建方式与参数绑定。
getBuckets:拉取全部存储桶
操作(Operation):选择List buckets(列出所有桶),该操作不需要任何参数。
步骤:新建查询 → 选择 AWS S3 数据源 → 操作选择List buckets→ 将查询命名为getBuckets→ 点击Save保存。
从源码看,ListBuckets操作最终由 listBuckets 函数 执行:构造一个空的ListBucketsCommand({})并发送给 S3 客户端,返回的响应结构为{ Buckets: [...], Owner: {...} },其中Buckets是对象数组,每个元素含Name(桶名)、CreationDate(创建时间)等字段。这正是下一步 Dropdown 数据绑定的依据。
配置 Dropdown 绑定桶列表
选中画布上的Dropdown组件,进入其属性面板,做如下配置:
- Label(标签):设置为
Bucket,作为界面上的提示文案; - Option values(选项值):设置为
{{queries.getBuckets.data.Buckets.map(bucket => bucket['Name'])}}将查询返回的
Buckets对象数组映射为桶名字符串数组; - Option label(选项标签):同样设置为
{{queries.getBuckets.data.Buckets.map(bucket => bucket['Name'])}}让界面显示的标签与底层值保持一致(显示桶名、值也是桶名)。
:::info{{ }}是 ToolJet 的表达式语法(类似模板字符串),可以在任意属性中输入 JavaScript 表达式,并直接引用queries.<查询名>.data与components.<组件名>等全局对象。这里的map操作是因为Buckets是对象数组,而 Dropdown 的选项值需要的是字符串数组。 :::
事件衔接:可以给 Dropdown 添加事件处理器(Event Handler),当用户从下拉框选中某个桶时,自动触发运行listObjects查询,从而联动刷新表格数据。这个联动是后续所有动态行为的基础。
listObjects:列出选中桶内的全部对象
操作(Operation):选择List objects in a bucket(列出桶中的对象)。
参数配置:在Bucket字段中输入
{{components.dropdown1.value}}这样查询执行时,会动态取 Dropdown 当前选中的桶名,而不是写死某个桶。
从源码可以更深入地理解这个操作的行为。在 listObjects 函数 中,插件将查询参数映射为 AWS SDK v3 的ListObjectsV2CommandInput:
| ToolJet 查询参数 | SDK 字段 | 说明 |
|---|---|---|
| Bucket | Bucket | 桶名(必填) |
| Prefix | Prefix | 可选,按前缀过滤,例如只列出images/下的对象 |
| Max keys | MaxKeys | 可选,单次最多返回的对象数量 |
| Offset | StartAfter | 可选,从某个键名之后开始列举(等效于按前缀起始位置列举) |
| Next Continuation Token | ContinuationToken | 可选,当结果被截断时,用响应中的令牌取下一页 |
列表操作返回的响应中,Contents字段是对象数组,每个元素包含Key(对象键,即文件路径)、LastModified(最后修改时间)、Size(大小,字节)、ETag、StorageClass等元数据,这些字段将直接用于 Table 组件的列绑定。
配置 Table 展示对象列表
选中Table组件,按以下方式配置其属性:
- Table data(表数据):
{{queries.listObjects.data['Contents']}}将表格数据源绑定到
listObjects查询返回的对象数组。注意这里用data['Contents']而不是data.Contents,两种写法等价,但后者在某些包含特殊字符的字段名场景下更稳妥; - 添加列(Add Columns):
| 列 | Column Name(列名) | Key(数据键) |
|---|---|---|
| 第 1 列 | Key | Key |
| 第 2 列 | Last Modified | LastModified |
| 第 3 列 | Size | Size |
- 添加操作按钮(Action button):添加一个按钮,按钮文本设为Copy signed URL,并为其添加事件处理器:事件选择On Click,动作(Action)选择Copy to clipboard,在文本字段中输入
{{queries.download.data.url}}这样点击按钮时,会把
download查询生成的签名下载 URL 复制到剪贴板。
download:为选中对象生成签名下载 URL
操作(Operation):选择Signed URL for download(生成下载签名 URL)。
参数配置:
- Bucket:
{{components.dropdown1.value}} - Key:
{{components.table1.selectedRow.Key}}使用 Table 组件当前选中行的
Key字段,实现"点哪行、签哪行"的动态绑定。
事件衔接:回到 Table 组件的属性面板,添加一个事件处理器:Event选择Row clicked(行点击),Action选择Run query,Query选择download。这样每当用户点击表格中的任意一行,都会触发download查询,为该行对象生成新的签名下载 URL。
:::info 签名 URL(Signed URL / Presigned URL)是对象所有者用自己的安全凭证为他人生成的、带时间限制的下载链接。其关键特性是"临时有效",过期后链接失效,从而在不暴露 AWS 凭证的前提下安全共享对象。 :::
从源码看,该操作由 signedUrlForGet 函数 实现:插件构造GetObjectCommand后,调用 AWS SDK 的getSignedUrl()方法生成 URL,其中expiresIn参数控制有效期,默认值为 3600 秒(1 小时),查询面板中可通过Expires in参数覆盖默认值。返回结构为{ url: "https://..." },这就是上文中"Copy signed URL"按钮绑定queries.download.data.url的来源。
uploadToS3:将本地文件上传到指定路径
操作(Operation):选择Upload object(上传对象)。
参数配置(这是本教程中信息密度最高、也最容易踩坑的一组绑定):
| 参数字段 | 表达式 | 含义 |
|---|---|---|
| Bucket | {{components.dropdown1.value}} | 目标桶名,动态取 Dropdown 当前选中值 |
| Key | {{ components.textinput1.value + '/' + components.filepicker1.file[0].name }} | 上传路径:Text Input 输入的目录 +/+ 文件名 |
| Content type | {{components.filepicker1.file[0].type}} | 文件的 MIME 类型,由 File Picker 自动读取 |
| Upload data | {{components.filepicker1.file[0].base64Data}} | 文件的 base64 编码内容 |
| Encoding | base64 | 告知数据源上传数据是 base64 编码,需要解码后写入 |
这里的几个绑定点值得展开说明其底层逻辑:
components.filepicker1.file是文件对象数组。ToolJet 的 File Picker 组件在useFilePicker钩子中(frontend/src/AppBuilder/Widgets/FilePicker/hooks/useFilePicker.js)通过FileReader的readAsDataURL读取文件,将结果拆出 base64 部分存入base64Data字段,同时保留name(文件名)、type(MIME 类型)、sizeBytes(大小)等元数据。因此file[0]表示第一个文件,file[0].name、file[0].type、file[0].base64Data分别对应文件名、类型与内容。这也是为什么Max file count要设为 1——保证file[0]就是唯一且确定的文件。Encoding为base64时,服务端会做解码。在 uploadObject 函数 中,插件用Buffer.from(data, encoding)将Upload data按指定编码转换成二进制Buffer,再作为PutObjectCommand的Body发送;ContentEncoding也会被一并设置。若你的文件内容不是 base64 编码,则保持默认的utf8即可。- Content type 会被写入对象的元数据。
ContentType参数会传给 S3 的PutObjectCommand,决定对象下载时的响应 Content-Type 头,因此建议从 File Picker 动态读取文件真实类型,而不是写死。
配置 File Picker:限定文件类型与数量
点击 File Picker 组件的属性手柄(widget handle),进入属性面板进行以下配置:
- Accept file types(接受的文件类型):
- 只接受 PDF:
{{"application/pdf"}} - 只接受图片:
{{"image/*"}} - 接受任意类型:留空
- 只接受 PDF:
- Max file count(最大文件数):
{{1}},因为每次只上传 1 个文件。
:::infoAccept file types必须是符合 input 元素规范的合法 MIME 类型(如application/pdf、image/*)或合法的文件扩展名。要接受任意类型文件,将该属性设为空值即可。 :::
从组件定义看,该属性在 File Picker 组件定义 中对应validation.fileType字段,默认值为'image/*';而maxFileCount的默认值为2(见 filepicker.js),并且仅在启用多文件模式(enableMultiple)时才渲染显示。useFilePicker钩子中同样以maxFileCount作为上限校验依据(useFilePicker.js),超出数量会提示 "You can select a maximum of N files."。因此本次实战将两个值分别设为application/pdf与{{1}},既限定了类型,也限定了数量。
收尾:上传成功后自动刷新对象列表
最后一步是让整个流程"闭环"。进入uploadToS3查询的Advanced(高级)选项卡,添加一个成功事件处理器(On Success):
- Event:
Query Success - Action:
Run query - Query:
listObjects
这样,每当文件上传成功,listObjects查询会自动重新执行,Table 中的数据随即刷新,新上传的文件立刻出现在列表中,无需手动点击任何刷新按钮。
至此,整个 S3 文件管理应用的核心链路就完整了:
- 页面加载时运行
getBuckets,Dropdown 填充全部桶名; - 用户选择桶,触发
listObjects,Table 列出桶内所有对象; - 用户点击某一行,触发
download,生成该对象的签名下载 URL,可通过"Copy signed URL"按钮复制; - 用户在 Text Input 输入目标目录、用 File Picker 选择文件,点击 Button 触发
uploadToS3上传; - 上传成功后自动重跑
listObjects,表格即时刷新。
延伸:还能做哪些扩展
基于同样的"查询 + 组件 + 事件"模式,结合 S3 数据源支持的操作清单(其底层实现均可参考 operations.ts),你可以很方便地扩展更多能力:
- Read object(读取对象):直接读取对象内容并返回字符串,适合预览文本类文件;
- Remove object(删除对象):可在 Table 中再添加一个"删除"操作按钮,绑定
{{components.table1.selectedRow.Key}}后触发删除查询; - Signed URL for upload(上传签名 URL):如果希望让不具备 AWS 凭证的外部用户直接向桶内上传,可以生成上传签名 URL 交给客户端直传;
- Create a new bucket(新建桶):结合 Text Input 输入桶名,即可在界面内完成建桶操作。
此外,S3 插件还支持allow_dynamic_connection_parameters开关(默认开启),它决定查询中的 Bucket 参数是采用查询级动态值还是回退到数据源配置的默认桶名(见 插件入口),在多环境、多桶切换场景下非常实用。
如果需要更完整的可运行示例,仓库中还提供了官方 S3 浏览应用的教程链接与配套截图,可结合本文逐步复现。整个方案的实现思路同样适用于 ToolJet 支持的其他对象存储数据源(如 GCS、MinIO 等),一通百通。
【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 🚀项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考