flutter dio封装结合json_serializable创建网络请求

1.依赖

dio: ^3.0.9
fluttertoast: ^4.0.1
shared_preferences: ^0.5.7+3
build_runner: ^1.7.1
json_serializable: ^3.2.3

注意:序列化依赖是放在dev_dependencies里面

2.目录结构

3.开始封装dio网络请求

1.创建DioManage

  • 利用factory创建dio单列
  • 配置dio基本属性options
  • 设置拦截器
class DioManager{
  static const String BASE_URL = "http://172.16.3.52:8083/V1";
  static const int CONNECT_TIMEOUT = 10000;
  static const int RECEIVE_TIMEOUT = 10000;
 ///创建单例
  //1.私有静态实例对象
  static final DioManager _dioManager = DioManager._instance();

  //2.创建工厂方法
  factory DioManager() => _dioManager;

  //3.私有的命名式构造方法
  DioManager._instance() {

    if (_dio == null) {
      ///dio配置基本属性
      BaseOptions _options = BaseOptions(
          baseUrl: BASE_URL,
          contentType: Headers.jsonContentType,
          responseType: ResponseType.json,
          connectTimeout: CONNECT_TIMEOUT,
          receiveTimeout: RECEIVE_TIMEOUT,);
      _dio = Dio(_options);

      ///拦截器
      _dio.interceptors
        ..add(HeadersInterceptors())
        ..add(LogsInterceptor())
        ..add(ResponseInterceptors());
    }
  }
}

2.创建拦截器

  • HeadersInterceptors()头部拦截器,设置token和其他参数
  • LogsInterceptor()日志拦截器,控制台打印数据
  • ResponseInterceptors()相应拦截器,打印接口返回值

上代码

import 'dart:io';

import 'package:dio/dio.dart';
import 'package:shared_preferences/shared_preferences.dart';

class HeadersInterceptors extends InterceptorsWrapper{
  var encryptResult = '';
  @override
  Future onRequest(RequestOptions options) async{
    // TODO: implement onRequest
    SharedPreferences _sp = await SharedPreferences.getInstance();
    options.headers.addAll({
      HttpHeaders.contentTypeHeader: 'application/json',
      'antappid': 'appId',
      'antplatform': Platform.isIOS ? 'ios' : 'android',
      'authorization': 'token',
      'antciphertext': '加密',
    });

    return super.onRequest(options);
  }
}

根据每个公司不同的头部要求设置相应的头部参数

import 'package:dio/dio.dart';
import 'package:flutter_widget_project/dio_util/http_error.dart';

///日志拦截器
class LogsInterceptor extends InterceptorsWrapper {
  @override
  Future onError(DioError err) {
    print('请求异常信息: ' + HttpError(code: err.type.toString() ,message:  err.message).toString());
    return super.onError(err);
  }

  @override
  Future onRequest(RequestOptions options) {
    print("请求API:${options.baseUrl}${options.path}");
    print('请求头: ' + options.headers.toString());
    if (options.data != null) {
      print('请求参数: ' + options.data.toString());
    }
    return super.onRequest(options);
  }

  @override
  Future onResponse(Response response) {
    return super.onResponse(response);
  }
}

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_widget_project/dio_util/base_model.dart';
import 'package:fluttertoast/fluttertoast.dart';

class ResponseInterceptors extends InterceptorsWrapper {
  @override
  onResponse(Response response) {
    RequestOptions _options = response.request;
    String body = response.data.toString();
    print("${_options.contentType}");
    try{
      if(_options.contentType != null && _options.contentType == "text"){
        print("HTTP_RESPONSE_BODY::${response.data}");
      }
      if(response.statusCode == 200){
        if(body.length > 600){
          for(int i = 0 ; i< body.toString().length ; i+= 600){
            if(i+600 < body.toString().length){
              print("HTTP_RESPONSE_BODY::${body.toString().substring(i , i+600)}");
            }else{
              print("HTTP_RESPONSE_BODY::${body.toString().substring(i , body.toString().length)}");
            }
          }
        }else{
          print('HTTP_RESPONSE_BODY::$body');
        }
      }

    }catch(e){
      print('ERROR::$body');
    }
    return super.onResponse(response);
  }
}

***响应拦截将日志进行字符长度遍历,防止日志过长导致打印信息不全***

3.HttpError错误提示

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_widget_project/dio_util/constant.dart';
import 'package:flutter_widget_project/dio_util/error_page.dart';
import 'package:fluttertoast/fluttertoast.dart';

class HttpError{

  static const int UNAUTHORIZED = 401;
  static const int FORBIDDEN = 403;
  static const int NOT_FOUND = 404;
  static const int REQUEST_TIMEOUT = 408;
  static const int INTERNAL_SERVER_ERROR = 500;
  static const int BAD_GATEWAY = 502;
  static const int SERVICE_UNAVAILABLE = 503;
  static const int GATEWAY_TIMEOUT = 504;

  ///未知错误
  static const String UNKNOWN = "UNKNOWN";

  ///解析错误
  static const String PARSE_ERROR = "PARSE_ERROR";

  ///网络错误
  static const String NETWORK_ERROR = "NETWORK_ERROR";

  ///协议错误
  static const String HTTP_ERROR = "HTTP_ERROR";

  ///证书错误
  static const String SSL_ERROR = "SSL_ERROR";

  ///连接超时
  static const String CONNECT_TIMEOUT = "CONNECT_TIMEOUT";

  ///响应超时
  static const String RECEIVE_TIMEOUT = "RECEIVE_TIMEOUT";

  ///发送超时
  static const String SEND_TIMEOUT = "SEND_TIMEOUT";

  ///网络请求取消
  static const String CANCEL = "CANCEL";

  String code;

  String message;

  HttpError({this.code, this.message});

  HttpError.dioError(DioError error){

    message = error.message;
    switch(error.type){
      case DioErrorType.CONNECT_TIMEOUT:
        code = CONNECT_TIMEOUT;
        message = "网络连接超时,请检查网络设置!";
        break;
      case DioErrorType.RECEIVE_TIMEOUT:
        code = RECEIVE_TIMEOUT;
        message = "服务器异常,请稍后重试!";
        break;
      case DioErrorType.SEND_TIMEOUT:
        code = SEND_TIMEOUT;
        message = "网络连接超时,请检查网络设置!";
        break;
      case DioErrorType.RESPONSE:
        code = HTTP_ERROR;
        message = "服务器异常,请稍后重试!";
        break;
      case DioErrorType.CANCEL:
        code = CANCEL;
        message = "请求已被取消,请重新请求!";
        break;
      case DioErrorType.DEFAULT:
        code = UNKNOWN;
        message = "网络或服务器异常,请稍后重试!";
        break;
    }

    //跳转错误页面
    //push(ErrorPage(message: message,));
    Fluttertoast.showToast(msg: message);
  }

  @override
  String toString() {
    // TODO: implement toString
    return 'HttpError{code:$code , message:$message}';
  }

}

4.根据返回值结构,创建BaseModel , BaseListModel类

一般结构:data里面的数据才是我们需要的responsbody,所以我们要将拿的的返回值进行封装

{"code":0 ,
"message":"success",
"data":"{}"
}

数据序列化成json

我的数据结构

{
"Code":0,
"Message":"",
"Data":{
    "Token":"wewewwwewew",
    {
      "Id":"112" , 
      "Name":"ee"
    }
  }
}

创建返回值model

// ignore_for_file: non_constant_identifier_names,library_prefixes最顶部这句话可取消警告
part 'user_model.g.dart';创建.g文件不可少
下面这两句是模版
factory LoginModel.fromJson(Map<String, dynamic> json) =>
    _$LoginModelFromJson(json);

LoginModel from(Map<String, dynamic> json) => _$LoginModelFromJson(json);
// ignore_for_file: non_constant_identifier_names,library_prefixes
import 'package:flutter_widget_project/dio_util/base_model.dart';
import 'package:json_annotation/json_annotation.dart';

part 'user_model.g.dart';


/*
* 登录接口请求成功的返回值
*
* */

@JsonSerializable(createToJson: false)
class LoginModel{
  String Token;
  UserModel Member;

  LoginModel({this.Token , this.Member});


  factory LoginModel.fromJson(Map<String, dynamic> json) =>
      _$LoginModelFromJson(json);

  LoginModel from(Map<String, dynamic> json) => _$LoginModelFromJson(json);
}


@JsonSerializable(createToJson: false)
class UserModel {
  final String Id;


  UserModel({
    this.Id,

  });

  factory UserModel.fromJson(Map<String, dynamic> json) =>
      _$UserModelFromJson(json);

  UserModel from(Map<String, dynamic> json) => _$UserModelFromJson(json);
}

创建完model后在控制台输入flutter packages pub run build_runner build 创建.g文件,如果不成功就使用flutter packages pub run build_runner build --delete-conflicting-outputs再次创建

创建EntityFactory申明model

import 'package:flutter_widget_project/model/entrust_search_model.dart';
import 'package:flutter_widget_project/model/user_model.dart';

class EntityFactory {
  static T generateOBJ<T>(json) {
    if (json == null) {
      return null;
    }
//可以在这里加入任何需要并且可以转换的类型,例如下面
//    else if (T.toString() == "LoginModel") {
//      return LoginModel.fromJson(json) as T;
//    }
//    else if (T.toString() == "EntrustModel") {
//      return EntrustModel.fromJson(json) as T;
//    }
//    else if (T.toString() == "EntrustListModel") {
//      return EntrustListModel.fromJson(json) as T;
//    }
    else {
      return json as T;
    }
  }
}

BaseModel

import 'entity_factory.dart';

///因为我的接口返回的是大写数据,所以json["Data"].

class BaseModel<T> {
///拿到服务器数据后,我们希望转换成自己方便使用的model结构
  int code;
  String message;
  String serverMessage;
  T data;

  BaseModel({this.code, this.message, this.data});

  factory BaseModel.fromJson(json) {
    ///获取接口数据
    if(json["Data"] != null){
      return BaseModel(
        code: json["Code"],
        message: json["Message"],
        // data值需要经过工厂转换为我们传进来的类型
        data: EntityFactory.generateOBJ<T>(json["Data"]),
      );
    }else{
      return BaseModel(
        code: json["Code"],
        message: json["Message"],
        data: null
      );
    }
  }
}

BaseListModel

import 'package:flutter_widget_project/dio_util/entity_factory.dart';
import 'package:flutter_widget_project/model/page_option_model.dart';

class BaseListModel<T>{
  int code;
  String message;
  dynamic pageResult;
  List<T> data;

  BaseListModel({this.code, this.message, this.data ,this.pageResult});

  factory BaseListModel.fromJson(json){
    List<T> mData = List();
    if (json["Data"] != null && json["Data"]["Data"] != null) {
      (json["Data"]["Data"] as List).forEach((element) {
        mData.add(EntityFactory.generateOBJ<T>(element));
      });
    }


    if(json["Data"] != null){
      return BaseListModel(
          code: json["Code"],
          message: json["Message"],
          data: mData,
          pageResult: EntityFactory.generateOBJ(json["Data"]["PagingResult"])
      );
    }else{
       return BaseListModel(
          code: json["Code"],
          message: json["Message"],
          data: null,
      );
    }


  }
}

5.再回到DioManager创建请求方法

 Future request<T>(
    BuildContext context,
    NetMethod method,
    String path, {
    bool isLoading,
    Map param,
    Map formData,
    Function(T) onSuccess,
    Function(HttpError) onError,
  }) async {
    try {
      ///开始做网络请求
      Response response = await _dio.request(path,
          queryParameters: param,
          data: formData,
          options: Options(method: NetMethodValues[method]));
      if (response != null) {
        ///返回数据转化成对应的model实例
        BaseModel entity = BaseModel<T>.fromJson(response.data);

        ///根据状态码处理相应的状态
        if (entity.code == 0) {
          onSuccess(entity.data);
        } else {
          onError(HttpError(code: entity.code.toString(), message: entity.message));
        }
      } else {
        onError(HttpError(code: "-1", message: "未知错误"));
      }
    } on DioError catch (e) {
      ///异常拦截
      onError(HttpError.dioError(e));
    }
  }
///请求列表
  Future requestList<T>(
    BuildContext context,
    NetMethod method,
    String path, {
    bool isLoading,
    Map param,
    Map formData,
    Function(List , dynamic) onSuccess,
    Function(HttpError) onError,
  }) async {
    try {
      Response response = await _dio.request(path,
          queryParameters: param,
          data: formData,
          options: Options(method: NetMethodValues[method]));
      if (response != null) {
        BaseListModel entity = BaseListModel<T>.fromJson(response.data);
        if (entity.code == 0) {
          onSuccess(entity.data , entity.pageResult);
        } else {
          onError(
              HttpError(code: entity.code.toString(), message: entity.message));
        }
      } else {
        onError(HttpError(code: "-1", message: "未知错误"));
      }
    } on DioError catch (error) {
      onError(HttpError.dioError(error));
    }
  }
}

枚举请求方式


enum NetMethod { GET, POST, DELETE, PUT }

const NetMethodValues = {
  NetMethod.GET: "get",
  NetMethod.POST: "post",
  NetMethod.DELETE: "delete",
  NetMethod.PUT: "put"
};

使用 

request() {
    DioManager().request<LoginModel>(
      context,
      NetMethod.POST,
      "/MemberAuth/Login",
      formData: {"Account": "zws1234", "Password": "123456"},
      onSuccess: (data) async {
        LoginModel dataModel = data;
        SharedPreferences sp = await SharedPreferences.getInstance();
        sp.setString("accessToken" ,dataModel.Token);
      },
      onError: (error) {
        Fluttertoast.showToast(msg: error.message);
        print("error code = ${error.code}, massage = ${error.message}");
      },
    );
  }

分页列表请求

1.先设置监听是否滑动到最底部或者最顶部

import 'package:flutter/material.dart';
import 'package:flutter_widget_project/model/page_option_model.dart';

class PageMini {
  ScrollController pageScrollController = new ScrollController();
  bool isPageLoading = false;

  PageResultModel pageResultModel = new PageResultModel.empty();
  PageOptionModel pageOptionModel = new PageOptionModel.empty();

  initPage() {
    if(pageScrollController != null){
      pageScrollController.addListener(() {
        if (pageScrollController.position.pixels >=
            pageScrollController.position.maxScrollExtent  && !isPageLoading) {
          isPageLoading = true;
          loadMoreData();
        }
        if (pageScrollController.position.pixels ==
            pageScrollController.position.minScrollExtent && !isPageLoading) {
          isPageLoading = true;
          refreshData();
        }
      });
    }
  }


  @protected
  refreshData() {}

  @protected
  loadMoreData() {}
}

在页面混入,并设置滚动controller

请求

 requestList({int goPage = 1}) {
    setState(() {
      isLoading = true;
    });
     goPage = pageOptionModel.GotoPageNumber;
    DioManager().requestList<EntrustModel>(
      context,
      NetMethod.POST,
      "/Entrust/Search",
      formData: {"EntrustType": 1 , "PagingOption":{"GotoPageNumber":"$goPage" , "PageSize":"15"}},
      onSuccess: (response , pageResult){

        if(goPage == 1){
          dataList.clear();
        }
        dataList = response;
        setState(() {
          isLoading = false;
          isPageLoading = false;
        });
      },
      onError: (error){
        Fluttertoast.showToast(msg: error.message);
        setState(() {
          isLoading = false;
        });
      }
    );
  }

 github链接dio_util

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用 Flutter Dio 进行网络请求时,可以将其进行封装,以便于代码的复用和维护。以下是一个简单的 Flutter Dio 封装示例: ```dart import 'package:dio/dio.dart'; class HttpUtil { static HttpUtil instance; Dio dio; BaseOptions options; // 构造函数 HttpUtil() { options = BaseOptions( baseUrl: 'https://api.example.com/', // 接口地址 connectTimeout: 5000, // 连接超时时间 receiveTimeout: 3000, // 接收超时时间 headers: { 'Content-Type': 'application/json', // 设置请求头 }, ); dio = Dio(options); } // 单例模式 static HttpUtil getInstance() { if (instance == null) { instance = HttpUtil(); } return instance; } // GET 请求 Future<Map<String, dynamic>> get(String url, {Map<String, dynamic> params}) async { Response response; try { response = await dio.get(url, queryParameters: params); } on DioError catch (e) { return Future.error(e); } return response.data; } // POST 请求 Future<Map<String, dynamic>> post(String url, {Map<String, dynamic> params}) async { Response response; try { response = await dio.post(url, data: params); } on DioError catch (e) { return Future.error(e); } return response.data; } } ``` 在上述示例中,我们定义了一个 HttpUtil 类,其中包含了 Dio 实例的初始化、GET 和 POST 请求封装。我们可以通过 `HttpUtil.getInstance()` 获取 HttpUtil 的单例对象,然后通过调用 `get` 或 `post` 方法来发起网络请求。这样做的好处是可以将网络请求的相关设置和配置统一管理,方便后续的维护和扩展。同时,通过封装,也避免了在多个地方重复编写相同的代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值