利用 Dio 完成數據更新的 Patch 請求

前言

這是 Dio 網絡請求的第三篇,我們將從淺到深完成 Dio 的學習。本篇介紹表單更新請求,利用 Patch 請求更新動態數據,需要做得準備工作如下:

  • 拉取後臺新的代碼,項目地址:後臺源碼,拉到本地後,在項目目錄運行 node seed.js 生成測試數據。
  • 運行後臺應用:在項目目錄node index.js 即可運行後臺接口應用,項目默認接口地址爲:http://localhost:3900/api/

整理代碼

回顧一下上一篇的代碼,發現上一篇的提醒錯誤代碼和業務無關,可以抽離爲一個公共的方法,方便後面在其他地方調用,新建一個 utils/dialogs.dart 文件,將錯誤提示方法移到裏面:

import 'package:flutter/material.dart';

class Dialogs {
  static void showInfo(BuildContext context, String info) {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(
      content: Text(info),
    ));
  }
}

之前我們在列表是在 initialState 方法裏主動刷新請求數據的,實際上 EasyRefresh 本身提供了一個屬性firstRefresh來設置首次是否自動刷新,因此我們可以移除之前的主動刷新代碼,將 firstRefresh 設置爲 true 即可。

編輯頁面實現

首先新增一個 dynamic_edit.dart 文件,裏面有三個表單和一個按鈕,分別對應的是標題、內容和圖片鏈接地址(這裏我們暫時不考慮圖片上傳)。表單利用的是我們之前封裝的通用表單組件,可以參考之前的:Flutter 入門與實戰(十):封裝一個通用的文本輸入框。這裏在沒有請求到數據的時候我們顯示“加載中...”,若請求成功則顯示實際的表單內容,構建界面的代碼如下:

_getFormWidgets() {
  if (_formData == null)
    return Center(
      child: Text('加載中...'),
    );
  return Container(
    child: Column(
      children: [
        FormUtil.textField(
          'title',
          _formData['title']['value'] ?? '',
          controller: _formData['title']['controller'] ?? null,
          hintText: '請輸入標題',
          prefixIcon: Icons.title,
          onChanged: _handleTextFieldChanged,
          onClear: _handleClear,
        ),
        FormUtil.textField(
          'content',
          _formData['content']['value'] ?? '',
          controller: _formData['content']['controller'] ?? null,
          hintText: '請輸入內容',
          prefixIcon: Icons.content_paste,
          onChanged: _handleTextFieldChanged,
          onClear: _handleClear,
        ),
        FormUtil.textField(
          'imageUrl',
          _formData['imageUrl']['value'] ?? '',
          controller: _formData['imageUrl']['controller'] ?? null,
          hintText: '請輸入圖片鏈接',
          prefixIcon: Icons.image,
          onChanged: _handleTextFieldChanged,
          onClear: _handleClear,
        ),
        ButtonUtil.primaryTextButton('保存', () {
          _handleSubmit();
        }, context),
      ],
    ),
  );
}

在列表項的長按彈層中我們增加了一個編輯按鈕,點擊後跳轉到編輯頁面,具體參考源碼即可。

獲取詳情數據

在編輯前,我們要通過 id 請求後臺數據來填充表單,這裏使用之前講過的 get 請求,方法如下。若請求成功,返回狀態碼200時,構建表單的_formData數據,也就是表單所需要的數據,同時更新界面。如果請求失敗則調用封裝的信息提示方法,顯示錯誤信息。

void _getDynamic(String id) async {
    try {
      var response = await DynamicService.get(id);
      if (response.statusCode == 200) {
        dynamicEntity = DynamicEntity.fromJson(response.data);
        setState(() {
          _formData = {
            'title': {
              'value': dynamicEntity.title,
              'controller': TextEditingController(text: dynamicEntity.title),
              'obsecure': false,
            },
            'content': {
              'value': dynamicEntity.content,
              'controller': TextEditingController(text: dynamicEntity.content),
              'obsecure': false,
            },
            'imageUrl': {
              'value': dynamicEntity.imageUrl,
              'controller': TextEditingController(text: dynamicEntity.imageUrl),
              'obsecure': false,
            },
          };
        });
      } else {
        Dialogs.showInfo(this.context, response.statusMessage);
      }
    } on DioError catch (e) {
      Dialogs.showInfo(this.context, e.message);
    } catch (e) {
      Dialogs.showInfo(this.context, e.toString());
    }
  }

提交更新數據

在提交數據前我們需要做校驗,這裏爲了簡單起見,只是保證數據不爲空即可,後續我們可以校驗工具來對各個字段進行準確的校驗。校驗通過後,從_fromData中提取實際要提交的表單數據。

_handleSubmit() async {
  if ((_formData['title']['value'] as String).trim() == '') {
    Dialogs.showInfo(this.context, '標題不能爲空');
    return;
  }

  if ((_formData['content']['value'] as String).trim() == '') {
    Dialogs.showInfo(this.context, '內容不能爲空');
    return;
  }

  if ((_formData['imageUrl']['value'] as String).trim() == '') {
    Dialogs.showInfo(this.context, '圖片鏈接不能爲空');
    return;
  }

  try {
    Map<String, String> newFormData = {};
    _formData.forEach((key, value) {
      newFormData[key] = value['value'];
    });
    var response = await DynamicService.update(dynamicEntity.id, newFormData);
    if (response.statusCode == 200) {
      Dialogs.showInfo(context, '保存成功');
    } else {
      Dialogs.showInfo(this.context, response.statusMessage);
    }
  } on DioError catch (e) {
    Dialogs.showInfo(this.context, e.message);
  } catch (e) {
    Dialogs.showInfo(this.context, e.toString());
  }
}

實際可以發現,我們的網絡請求除了請求方法不同以外,其他代碼幾乎如出一轍,這也是後面的篇章需要統一封裝的原因,要不太多重複代碼了,萬一哪天改起來會很痛苦。DynamicService.update接收要更新的數據的 id 和要更新的表單數據,實際就是簡單調用了 Diopatch 方法。

static Future update(String id, Map<String, dynamic> data) async {
  var result = await Dio().patch(host + 'dynamics/' + id, data: data);

  return result;
}

運行效果

編輯完成後,我們重新刷新數據,可以看到內容和圖片都發生了改變(如何保存成功後自動同步列表,我們講完添加後再一起來解決)。

總結

本篇介紹了詳情數據的獲取,實體對象的部分修改來展示 Dio的 patch 請求。可以看到,Dio 提供的一系列 Restful 請求的方式基本相同,這樣給我們統一封裝留下了空間。下一篇我們介紹如何創建數據以及操作成功後如何同步更新後的數據到列表,網絡相關代碼源碼地址爲:Flutter 入門與實戰網絡相關源碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章