Flutter如何展示Node.js服务端返回的MySQL查询结果列表
错误原因
你的解析逻辑预期接收根结构为Map<String, dynamic>的JSON对象,但Node.js服务端返回的MySQL查询结果是根结构为List<dynamic>的JSON数组,类型不匹配导致抛出cast异常。
代码重构步骤
1. 修正数据请求与实体解析逻辑
原有请求方法大概率是直接将返回结果传入Subject.fromJson,需要调整为遍历JSON数组的每一项,逐个转换为Subject实体,最终返回List<Subject>类型:
import 'dart:convert'; import 'package:http/http.dart' as http; // 修正后的请求方法,返回科目列表 Future<List<Subject>> fetchSubjectList() async { final response = await http.get(Uri.parse('替换为你的后端接口地址')); if (response.statusCode == 200) { // 先将返回内容解析为List类型 final List<dynamic> jsonArray = jsonDecode(response.body); // 遍历数组每一项转换为Subject实体 return jsonArray.map((item) => Subject.fromJson(item)).toList(); } else { throw Exception('请求接口失败,状态码:${response.statusCode}'); } }
2. 调整FutureBuilder渲染逻辑
根据你的展示需求,可选择列表或表格两种实现方式:
列表展示实现
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('科目列表')), body: FutureBuilder<List<Subject>>( future: fetchSubjectList(), builder: (context, snapshot) { // 加载中状态 if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } // 加载出错状态 if (snapshot.hasError) { return Center(child: Text('加载失败:${snapshot.error}')); } // 加载成功状态 if (snapshot.hasData) { final subjectList = snapshot.data!; return ListView.builder( itemCount: subjectList.length, itemBuilder: (context, index) { final subject = subjectList[index]; return ListTile( title: Text(subject.title), // 替换为你的Subject实体对应字段 subtitle: Text('科目ID:${subject.id}'), // 可自定义添加更多字段展示 ); }, ); } // 无数据状态 return const Center(child: Text('暂无科目数据')); }, ), ); }
表格展示实现
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('科目表格')), body: FutureBuilder<List<Subject>>( future: fetchSubjectList(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } if (snapshot.hasError) { return Center(child: Text('加载失败:${snapshot.error}')); } if (snapshot.hasData) { final subjectList = snapshot.data!; return SingleChildScrollView( // 横向滚动适配多列表格 scrollDirection: Axis.horizontal, child: DataTable( columns: const [ DataColumn(label: Text('科目ID')), DataColumn(label: Text('科目标题')), DataColumn(label: Text('学分')), DataColumn(label: Text('课时')), ], rows: subjectList.map((subject) { return DataRow(cells: [ DataCell(Text(subject.id.toString())), DataCell(Text(subject.title)), DataCell(Text(subject.credit.toString())), DataCell(Text(subject.classHour.toString())), ]); }).toList(), ), ); } return const Center(child: Text('暂无科目数据')); }, ), ); }
注意事项
- 确保
Subject.fromJson方法的入参为Map<String, dynamic>类型,且字段映射和后端返回的单条科目结构完全匹配 - 若后端可能返回空数组,可添加长度判断做自定义空态展示
内容的提问来源于stack exchange,提问作者Irwin
相关产品推荐
相关产品推荐

