Flutter for OpenHarmony:postgrest 直接访问 PostgreSQL 数据库的 RESTful 客户端(Supabase 核心驱动) 深度解析与鸿蒙适配指南

Flutter for OpenHarmony:postgrest 直接访问 PostgreSQL 数据库的 RESTful 客户端(Supabase 核心驱动) 深度解析与鸿蒙适配指南

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net

请添加图片描述

前言

如果你不想写复杂的 Java/Node.js 后端服务,只想直接增删改查数据库,PostgREST 是一个神奇的后端工具 —— 它能把从 PostgreSQL 数据库自动生成一套 RESTful API。而 postgrest (Dart库) 正是这一服务的官方客户端。

这也是 Supabase(Firebase 的开源替代品)的核心组件之一。通过它,你可以在 Flutter App 中像写 SQL 一样流畅地操作远程数据,既安全又高效。

一、概念介绍/原理解析

1.1 基础概念

  • Filter: eq('id', 1), gt('age', 18) 等,对应 SQL 的 WHERE
  • Select: 指定返回字段,支持关联查询(如 *, posts(*))。
  • Order: 排序规则。
  • RPC: 调用存储过程(Stored Procedures)。

HTTP 请求

SQL 语句

结果集

JSON 数据

Flutter 移动应用

PostgREST 接口网关

后台数据库

1.2 进阶概念

虽然看起来是直连数据库,但实际上通过 PostgREST 的 RLS (Row Level Security) 机制,你可以非常精细地控制每个用户只能读写自己的数据,无需担心越权。

二、核心 API/组件详解

2.1 基础用法

查询数据。

import'package:postgrest/postgrest.dart';final client =PostgrestClient('https://your-project.supabase.co/rest/v1');voidmain()async{// SELECT * FROM countries WHERE name = 'China'final data =await client .from('countries').select().eq('name','China');print(data);// List<Map<String, dynamic>>}
在这里插入图片描述

2.2 插入与更新

// INSERT INTO users (name, status) VALUES ('Tom', 'active')await client.from('users').insert({'name':'Tom','status':'active'});// UPDATE users SET status = 'inactive' WHERE id = 1await client.from('users').update({'status':'inactive'}).eq('id',1);
在这里插入图片描述

三、常见应用场景

3.1 场景 1:无后端 App

基于 Supabase 或自建 PostgREST,直接开发 CMS 或简单的社交应用。

// 获取文章列表及作者信息final posts =await client.from('posts').select('*, author:users(*)');
在这里插入图片描述

3.2 场景 2:实时排行榜

虽然 postgrest 主要是 REST,但结合 Realtime 功能(Supabase),可实现实时数据同步。

// 仅使用 postgrest 获取快照final top10 =await client.from('scores').select().order('score', ascending:false).limit(10);
在这里插入图片描述

3.3 场景 3:调用复杂业务逻辑

通过 RPC 调用数据库函数。

// 调用名为 "reset_password" 的函数await client.rpc('reset_password', params:{'email':'[email protected]'});
在这里插入图片描述

四、OpenHarmony 平台适配

4.1 网络请求库

postgrest 内部默认使用 http 库。在 OpenHarmony 上,这完全没问题。如果你需要自定义(比如加 Token 拦截器或使用 Dio),可以通过构造函数传入自定义 Client。

4.2 权限声明

同样别忘了在鸿蒙 config.json/module.json5 中声明 ohos.permission.INTERNET

五、完整示例代码

本示例列出所有任务 (Todos),并支持点击切换完成状态。

import'package:flutter/material.dart';import'package:postgrest/postgrest.dart';// 请替换为你自己的 PostgREST 服务地址constString _url ='https://my-project.supabase.co/rest/v1';constString _anonKey ='your-anon-key';// 如果有的话voidmain(){runApp(constMaterialApp(home:TodoPage()));}classTodoPageextendsStatefulWidget{constTodoPage({super.key});@overrideState<TodoPage>createState()=>_TodoPageState();}class _TodoPageState extendsState<TodoPage>{ late finalPostgrestClient _client;List<Map<String,dynamic>> _todos =[]; bool _loading =true;@overridevoidinitState(){super.initState(); _client =PostgrestClient( _url, headers:{'apikey': _anonKey},// 公钥);_fetchTodos();}Future<void>_fetchTodos()async{try{final res =await _client.from('todos').select().order('id');setState((){ _todos =List<Map<String,dynamic>>.from(res asList); _loading =false;});}catch(e){print('Error: $e');setState(()=> _loading =false);}}Future<void>_toggle(int id, bool current)async{// 乐观更新 UIfinal index = _todos.indexWhere((t)=> t['id']== id);if(index !=-1){setState((){ _todos[index]['is_complete']=!current;});}try{await _client.from('todos').update({'is_complete':!current}).eq('id', id);}catch(e){// 失败回滚..._fetchTodos();}}@overrideWidgetbuild(BuildContext context){returnScaffold( appBar:AppBar(title:constText('PostgREST Todos')), body: _loading ?constCenter(child:CircularProgressIndicator()):ListView.builder( itemCount: _todos.length, itemBuilder:(context, index){final todo = _todos[index];final isDone = todo['is_complete']as bool???false;returnCheckboxListTile( title:Text(todo['task']asString), value: isDone, onChanged:(_)=>_toggle(todo['id']as int, isDone),);},), floatingActionButton:FloatingActionButton( onPressed: _fetchTodos, child:constIcon(Icons.refresh),),);}}
在这里插入图片描述

六、总结

postgrest 极大地降低了全栈开发的门槛。前端开发者只需专注于 UI 和数据查询,复杂的后端逻辑交给强大的 PostgreSQL 数据库去处理。

最佳实践

  1. 安全性:永远不要在客户端使用 service_role 密钥(超级管理员权限)。始终使用 anon 密钥配合 RLS。
  2. 类型生成:手动解析 Map<String, dynamic> 很累且容易出错,建议使用 supabase_flutter 配合代码生成工具。

Read more

Fold Craft Launcher:安卓设备上的Minecraft Java版终极启动方案

Fold Craft Launcher:安卓设备上的Minecraft Java版终极启动方案 【免费下载链接】FoldCraftLauncherFold Craft Launcher, an Android Minecraft : Java Edition launcher. 项目地址: https://gitcode.com/gh_mirrors/fo/FoldCraftLauncher 在移动设备上畅玩Minecraft Java版曾经被认为是不可能实现的目标,直到Fold Craft Launcher的出现彻底改变了这一局面。这款专为Android平台设计的启动器让玩家能够在手机和平板上享受完整的PC版Minecraft体验。 为什么选择Fold Craft Launcher? 全版本兼容支持 Fold Craft Launcher原生支持Minecraft所有版本,从经典的老版本到最新的快照版本都能完美运行。支持多种模组加载器,包括Forge、NeoForge、LiteLoader、OptiFine、Fabric、Quilt等主流平台,让您的游戏体验更加丰富多彩。

By Ne0inhk
JAVA 多线程编程:从基础原理到实战应用

JAVA 多线程编程:从基础原理到实战应用

JAVA 多线程编程:从基础原理到实战应用 1.1 本章学习目标与重点 💡 掌握线程的核心概念,理解进程与线程的区别和联系。 💡 熟练掌握线程的三种创建方式,理解线程的生命周期及状态转换。 💡 掌握线程同步与锁机制,解决多线程并发安全问题。 💡 了解线程池的核心原理与使用方法,提升多线程程序性能。 ⚠️ 本章重点是 线程同步机制 和 线程池的实战应用,这是多线程开发中的核心难点和高频考点。 1.2 多线程核心概念 1.2.1 进程与线程的区别 💡 进程是操作系统进行资源分配和调度的基本单位,每个进程都有独立的内存空间和系统资源。比如打开一个 Java 程序,就会启动一个进程。 💡 线程是进程的执行单元,是 CPU 调度和执行的基本单位。一个进程可以包含多个线程,这些线程共享进程的内存空间和资源。 对比维度进程线程资源分配拥有独立的内存空间和资源共享所属进程的内存和资源开销成本创建和销毁开销大创建和销毁开销小调度方式由操作系统内核调度由进程内部调度独立性进程之间相互独立线程之间共享资源,依赖性强 ✅ 核心结论:线程是轻量级的进程,多线程编程可以充分利

By Ne0inhk
在家玩 AI 绘图还能远程协作?ComfyUI+Flux.1结合cpolar的实用技巧

在家玩 AI 绘图还能远程协作?ComfyUI+Flux.1结合cpolar的实用技巧

文章目录 * 前言 * 1. 本地部署ComfyUI * 2. 下载 Flux.1 模型 * 3. 下载CLIP模型 * 4. 下载 VAE 模型 * 5. 演示文生图 * 6. 公网使用 Flux.1 大模型 * 6.1 创建远程连接公网地址 * 7. 固定远程访问公网地址 前言 ComfyUI 是一款灵活的 AI 绘图工具,搭配 Flux.1 模型能实现文本生成图像的功能,适合设计师、创作者用来制作图片素材。它的优点是可以通过节点拖拽搭建绘图流程,能精细控制生成效果,而且开源免费,适合需要自定义绘图过程的用户。 使用时感觉 Flux.1 模型的生成效果不错,尤其是色彩和场景合理性方面表现较好。不过要注意,不同版本的模型对电脑配置要求不同,比如有些版本需要较大显存,

By Ne0inhk
JAVA 异常处理:从原理到实战最佳实践

JAVA 异常处理:从原理到实战最佳实践

JAVA 异常处理:从原理到实战最佳实践 1.1 本章学习目标与重点 💡 掌握异常的分类与核心概念,理解异常处理的设计思想。 💡 熟练运用 try-catch-finally、throws、throw 处理异常。 💡 掌握自定义异常的编写与使用场景,规范异常处理流程。 ⚠️ 本章重点是 异常处理的最佳实践 和 避免常见误区,这是提升代码健壮性的核心技能。 1.2 异常的核心概念与分类 1.2.1 什么是异常 💡 异常是指程序运行过程中出现的非正常情况,它会中断程序的正常执行流程。 比如文件找不到、数组下标越界、空指针访问等,这些情况都会触发异常。 Java 中所有异常都是 Throwable 类的子类,异常处理的本质是捕获并处理这些非正常情况,保证程序可以继续运行或优雅退出。 1.2.2 异常的分类 Java 中的异常体系分为三大类,它们的父类都是 Throwable: * 是 JVM 内部的严重错误,

By Ne0inhk