Flutter串接restful api练习

Flutter串接restful api

创建新专案

架构:

img1

package
1ee475de531d52b522cf5857249957db.png

使用JSONPlaceholder测试:
JSONPlaceholder

使用quicktype将json档案转承我们要的形式:
quicktype

测试使用posts:

1a9290a4d1078a54868fd2369e4cd6b0.png


建立Model

在models里新增post_model:

import 'dart:convert';class PostModel {  PostModel({    this.userId,    this.id,    this.title,    this.body,  });  int userId;  int id;  String title;  String body;  factory PostModel.fromJson(String str) => PostModel.fromMap(json.decode(str));  String toJson() => json.encode(toMap());  factory PostModel.fromMap(Map<String, dynamic> json) => PostModel(        userId: json["userId"] == null ? null : json["userId"],        id: json["id"] == null ? null : json["id"],        title: json["title"] == null ? null : json["title"],        body: json["body"] == null ? null : json["body"],      );  Map<String, dynamic> toMap() => {        "userId": userId == null ? null : userId,        "id": id == null ? null : id,        "title": title == null ? null : title,        "body": body == null ? null : body,      };}

稍微修改(with null-safety):

import 'dart:convert';class PostModel {  PostModel({    this.userId,    this.id,    this.title,    this.body,  });  int? userId;  int? id;  String? title;  String? body;  factory PostModel.fromJson(String str) => PostModel.fromMap(json.decode(str));  String toJson() => json.encode(toMap());  factory PostModel.fromMap(Map<String, dynamic> json) => PostModel(        userId: json["userId"] ?? json["userId"],        id: json["id"] ?? json["id"],        title: json["title"] ?? json["title"],        body: json["body"] ?? json["body"],      );  Map<String, dynamic> toMap() => {        "userId": userId ?? userId,        "id": id ?? id,        "title": title ?? title,        "body": body ?? body,      };}

models.dart:

export './post_model.dart';

建立service

在services里新增post_service:

import 'dart:convert';import 'dart:developer';import 'package:flutter_restful/core/models/models.dart';import 'package:http/http.dart' as http;class PostService {  Future<PostModel?> findById(String id) async {    PostModel post;    try {      var headers = {'content-type': 'application/json'};      var url = Uri.parse('https://jsonplaceholder.typicode.com/posts/$id');      final response = await http.get(url, headers: headers);      if (response.statusCode == 200) {        post = PostModel.fromJson(response.body);        return post;      } else {        log('请求失败');      }    } catch (err) {      log('post fetch and set catch error', error: err);    }  }  Future<List<PostModel>> findAll() async {    try {      var headers = {'content-type': 'application/json'};      var url = Uri.parse('https://jsonplaceholder.typicode.com/posts');      final response = await http.get(url, headers: headers);      final extractedData = json.decode(response.body);      final List<PostModel> loadedposts = [];      for (var data in extractedData) {        loadedposts.add(PostModel(          id: data['id'],          userId: data['userId'],          title: data['title'],          body: data['body'],        ));      }      return loadedposts;    } catch (err) {      log('posts fetch and set catch error', error: err);      return [];    }  }  Future<PostModel> create(PostModel post, [String token = '']) async {    try {      var headers = {        'content-type': 'application/json',        'Authorization': token,      };      var url = Uri.parse('https://jsonplaceholder.typicode.com/posts');      final response = await http.post(        url,        headers: headers,        body: json.encode({          'id': post.id,          'userId': post.userId,          'title': post.title,          'body': post.body,        }),      );      log(response.body);      return PostModel.fromJson(response.body);    } catch (err) {      log('Add error, ', error: err);      throw Exception(err);    }  }  Future<PostModel> delete(String postId, [String token = '']) async {    try {      var headers = {        'content-type': 'application/json',        'Authorization': token,      };      var url = Uri.parse('https://jsonplaceholder.typicode.com/posts/$postId');      final response = await http.delete(        url,        headers: headers,      );      log(response.body);      if (response.statusCode == 200) {        return PostModel.fromJson(response.body);      } else {        throw Exception('Failed to delete post');      }    } catch (err) {      log('Delete error, ', error: err);      throw Exception(err);    }  }  Future<PostModel> edit(String postId, PostModel post,      [String token = '']) async {    try {      var headers = {        'content-type': 'application/json; charset=UTF-8',        'Authorization': token,      };      var url = Uri.parse('https://jsonplaceholder.typicode.com/posts/$postId');      final response = await http.put(        url,        headers: headers,        body: json.encode({          'id': post.id,          'userId': post.userId,          'title': post.title,          'body': post.body,        }),        // body: post.toJson()      );      log(response.body);      if (response.statusCode == 200) {        return PostModel.fromJson(response.body);      } else {        throw Exception('Failed to edit post');      }    } catch (err) {      log('Edit error, ', error: err);      throw Exception(err);    }  }}

services.dart:

export './post_service.dart';

UI

home_screen.dart:

import 'package:flutter/material.dart';import 'package:flutter_restful/core/models/models.dart';import 'package:flutter_restful/core/services/post_service.dart';import 'package:flutter_restful/ui/post_detail_screen.dart';class HomeScreen extends StatefulWidget {  const HomeScreen({Key? key}) : super(key: key);  @override  _HomeScreenState createState() => _HomeScreenState();}class _HomeScreenState extends State<HomeScreen> {  final _formKey = GlobalKey<FormState>();  final TextEditingController _titleController = TextEditingController();  final TextEditingController _contentController = TextEditingController();  PostService post = PostService();  PostModel model = PostModel();  List<PostModel> _posts = [];  @override  void initState() {    // TODO: implement initState    super.initState();    post.findAll().then((value) {      setState(() {        _posts = value;      });    });  }  @override  Widget build(BuildContext context) {    return Scaffold(      body: ListView.builder(        itemCount: _posts.length,        itemBuilder: (context, index) {          PostModel _post = _posts[index];          return ListTile(            title: Text(_post.title ?? ''),            dense: true,            onTap: () {              Navigator.push(                  context,                  MaterialPageRoute(                      builder: (context) => PostDetailScreen(                            post: _post,                          )));            },            trailing: Wrap(              spacing: 12, // space between two icons              children: <Widget>[                IconButton(                  onPressed: () {                    post.delete(index.toString());                    setState(() {                      _posts.removeAt(index);                    });                  },                  icon: const Icon(Icons.delete),                ),                IconButton(                  onPressed: () {                    showDialog(                        context: context,                        builder: (BuildContext context) {                          return AlertDialog(                            content: Stack(                              clipBehavior: Clip.none,                              children: <Widget>[                                Positioned(                                  right: -40.0,                                  top: -40.0,                                  child: InkResponse(                                    onTap: () {                                      Navigator.of(context).pop();                                    },                                    child: const CircleAvatar(                                      child: Icon(Icons.close),                                      backgroundColor: Colors.red,                                    ),                                  ),                                ),                                Form(                                  key: _formKey,                                  child: Column(                                    mainAxisSize: MainAxisSize.min,                                    children: <Widget>[                                      const Text('Edit Post'),                                      Padding(                                        padding: const EdgeInsets.all(8.0),                                        child: TextFormField(                                          decoration: const InputDecoration(                                            labelText: "title",                                          ),                                          initialValue: _posts[index].title,                                          onSaved: (value) {                                            model.title = value;                                          },                                        ),                                      ),                                      Padding(                                        padding: const EdgeInsets.all(8.0),                                        child: TextFormField(                                          decoration: const InputDecoration(                                            labelText: "content",                                          ),                                          initialValue: _posts[index].body,                                          onSaved: (value) {                                            model.body = value;                                          },                                        ),                                      ),                                      Padding(                                        padding: const EdgeInsets.all(8.0),                                        child: ElevatedButton(                                          child: const Text("Edit"),                                          onPressed: () {                                            if (_formKey.currentState!                                                .validate()) {                                              _formKey.currentState!.save();                                              model.userId = 1;                                              model.id = _posts[index].id;                                              post                                                  .edit(                                                      _posts[index]                                                          .id                                                          .toString(),                                                      model)                                                  .then(                                                (value) {                                                  setState(() {                                                    _posts[index] = value;                                                  });                                                },                                              );                                              Navigator.of(context).pop();                                            }                                          },                                        ),                                      )                                    ],                                  ),                                ),                              ],                            ),                          );                        });                  },                  icon: const Icon(Icons.edit),                ),              ],            ),          );        },      ),      floatingActionButton: FloatingActionButton(        child: const Icon(Icons.add),        onPressed: () {          showDialog(              context: context,              builder: (BuildContext context) {                return AlertDialog(                  content: Stack(                    clipBehavior: Clip.none,                    children: <Widget>[                      Positioned(                        right: -40.0,                        top: -40.0,                        child: InkResponse(                          onTap: () {                            Navigator.of(context).pop();                          },                          child: const CircleAvatar(                            child: Icon(Icons.close),                            backgroundColor: Colors.red,                          ),                        ),                      ),                      Form(                        key: _formKey,                        child: Column(                          mainAxisSize: MainAxisSize.min,                          children: <Widget>[                            const Text('Add Post'),                            Padding(                              padding: const EdgeInsets.all(8.0),                              child: TextFormField(                                controller: _titleController,                                decoration: const InputDecoration(                                  labelText: "title",                                ),                                onSaved: (value) {                                  model.title = value;                                },                              ),                            ),                            Padding(                              padding: const EdgeInsets.all(8.0),                              child: TextFormField(                                controller: _contentController,                                decoration: const InputDecoration(                                  labelText: "content",                                ),                                onSaved: (value) {                                  model.body = value;                                },                              ),                            ),                            Padding(                              padding: const EdgeInsets.all(8.0),                              child: ElevatedButton(                                child: const Text("Add"),                                onPressed: () {                                  if (_formKey.currentState!.validate()) {                                    _formKey.currentState!.save();                                    model.userId = 1;                                    post.create(model).then(                                      (value) {                                        setState(() {                                          _posts.add(value);                                        });                                      },                                    );                                    Navigator.of(context).pop();                                  }                                },                              ),                            )                          ],                        ),                      ),                    ],                  ),                );              });        },      ),    );  }}

post_detail_screen.dart:

import 'package:flutter/material.dart';import 'package:flutter_restful/core/models/models.dart';class PostDetailScreen extends StatefulWidget {  final PostModel post;  const PostDetailScreen({    Key? key,    required this.post,  }) : super(key: key);  @override  _PostDetailScreenState createState() => _PostDetailScreenState();}class _PostDetailScreenState extends State<PostDetailScreen> {  @override  Widget build(BuildContext context) {    return Scaffold(      appBar: AppBar(        title: Text(widget.post.title ?? ''),      ),      body: Column(        children: [          Text(widget.post.body ?? ''),        ],      ),    );  }}

main.dart:

import 'package:flutter/material.dart';import 'ui/home_screen.dart';void main() {  runApp(const MyApp());}class MyApp extends StatelessWidget {  const MyApp({Key? key}) : super(key: key);  // This widget is the root of your application.  @override  Widget build(BuildContext context) {    return MaterialApp(      title: 'Flutter Demo',      theme: ThemeData(        primarySwatch: Colors.blue,      ),      home: const HomeScreen(),    );  }}

Test

app-test.gif


欢迎大家来我的Blog看:

1.Blog: 文章连结


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章