总体的思路,
- 借助Dio,将其封装为一个工具类(dio_utils.dart)
- 封装请求服务(service_api.dart)
- 根据请求参数封装 请求model (RequireModel )
- 根据返回数据类型封装返回Entitiy(list_entity.dart。因为返回的data中是一个list,如果是一个string,直接在entiy中解析好,上层进行调用即可)
- data中的单个对象进行封装(PersionEntity),方便解析
- 使用
总的来说封装了这么多就是为了后期使用方便。
1、dio_utils.dart
import 'dart:async';
import 'package:dio/dio.dart';
import 'err_code.dart';
import 'method.dart';
class DioNetUtils {
static final DioNetUtils _singleton = DioNetUtils._init();
static Dio _dio;
static const String text_type = "application/json; charset=utf-8";
static const String from_type = "application/x-www-form-urlencoded";
/// 是否是debug模式.
static bool _isDebug = true;
/// 打开debug模式.
static void openDebug() {
_isDebug = true;
}
DioNetUtils._init() {
BaseOptions options = new BaseOptions(
baseUrl: "https://www.baidu.com",
connectTimeout: 1000 * 10,
receiveTimeout: 1000 * 10,
headers: {},
//表示期望以那种格式(方式)接受响应数据。
// 接受4种类型 `json`, `stream`, `plain`, `bytes`. 默认值是 `json`,
responseType: ResponseType.json,
);
_dio = Dio(options);
//添加拦截器
_dio.interceptors.add(InterceptorsWrapper(
onRequest: (RequestOptions options) {
print("\n================== 请求数据 ==========================");
print("url = ${options.uri.toString()}");
print("headers = ${options.headers}");
print("params = ${options.data}");
},
onResponse: (Response response) {
print("\n================== 响应数据 ==========================");
print("code = ${response.statusCode}");
print("data = ${response.data}");
print("\n");
},
onError: (DioError e) {
print("\n================== 错误响应数据 ======================");
print("type = ${e.type}");
print("message = ${e.message}");
print("\n");
}
));
}
factory DioNetUtils() {
return _singleton;
}
/// Make http request with options.
/// [method] The request method.
/// [path] The url path.
/// [data] The request data
/// [options] The request options.
/// String 返回 json data .
Future<Map<String,dynamic>> request<T>(
String path, {
String method = Method.get,
String contentType = text_type,
queryParameters,
Options options,
// CancelToken cancelToken,
}) async {
print('path===' + path);
Response response;
if (method == Method.get) {
//GET方式
response = await _dio.request(
path,
queryParameters: queryParameters,
options: _checkOptions(method, contentType, options),
// cancelToken: cancelToken,
);
} else {
//除GET的其他方式
var requestData;
print(contentType);
if (contentType == from_type) { //表单方式
requestData = new FormData.fromMap({
"key": "value"
});
} else { //json格式
requestData = queryParameters;
}
response = await _dio.request(
path,
data: requestData,
options: _checkOptions(method, contentType, options),
// cancelToken: cancelToken,
);
}
_printHttpLog(response);
print('response.statusCode = ${response.statusCode}');
if (response.statusCode == 200) {
try {
if (response.data is Map) {
print('response.data["code"] = ${response.data["code"]}');
// 由于不同的接口返回的格式不固定不规范,所以需要根据接口格式自定义.
print('return response.data[\'data\'] = ${response.data['data']}');
return response.data;
} else if (response.data is List) {
print('return List branch');
return response.data;
} else {
print('return default else');
return response.data;
}
} catch (e) {
print('response error e =$e');
return new Future.error(new DioError(
response: response,
type: DioErrorType.RESPONSE,
));
}
} else {
//ShowToast.warning("网络连接不可用,请稍后重试");
print('response defalut error....');
new Future.error(new DioError(
response: response,
type: DioErrorType.RESPONSE,
));
}
}
/// check Options.
Options _checkOptions(method, contentType, options) {
if (options == null) {
options = new Options();
}
// if (contentType) {
// //设置请求的类型 json 表单
// options.contentType = contentType;
// }
options.method = method;
return options;
}
// print Http Log.
void _printHttpLog(Response response) {
print(!_isDebug);
if (!_isDebug) {
return;
}
try {
print("\n----------------Http Log Start----------------" +
_getOptionsStr(response.request));
print(response);
print("\n----------------Http Log end----------------");
} catch (ex) {
print("\nHttp Log" + " error......");
}
}
// get Options Str.
String _getOptionsStr(RequestOptions request) {
return "\nmethod: " +
request.method +
"\nbaseUrl: " +
request.baseUrl +
"\npath: " +
request.path;
}
// 错误全局处理
dealErrorInfo(DioError error) {
print(error.type);
// 请求错误处理
Response errorResponse;
if (error.response != null) {
errorResponse = error.response;
} else {
errorResponse = new Response(statusCode: 201);
}
// 请求超时
if (error.type == DioErrorType.CONNECT_TIMEOUT) {
//ShowToast.warning("网络请求超时,请稍后重试");
errorResponse.statusCode = ResultCode.CONNECT_TIMEOUT;
}
// 请求连接超时
else if (error.type == DioErrorType.RECEIVE_TIMEOUT) {
//ShowToast.warning("网络连接超时,请稍后重试");
errorResponse.statusCode = ResultCode.RECEIVE_TIMEOUT;
}
// 服务器错误
else if (error.type == DioErrorType.RESPONSE) {
//ShowToast.warning("服务器繁忙,请稍后重试");
errorResponse.statusCode = ResultCode.RESPONSE;
}
// 一般服务器错误
else {
//ShowToast.warning("网络连接不可用,请稍后重试1");
errorResponse.statusCode = ResultCode.DEFAULT;
}
return errorResponse;
}
}
err_code.dart
/*
* dio网络请求失败的回调错误码 自定义
*/
class ResultCode {
//正常返回是1
static const SUCCESS = 1;
//异常返回是0
static const ERROR = 0;
/// When opening url timeout, it occurs.
static const CONNECT_TIMEOUT = -1;
///It occurs when receiving timeout.
static const RECEIVE_TIMEOUT = -2;
/// When the server response, but with a incorrect status, such as 404, 503...
static const RESPONSE = -3;
/// When the request is cancelled, dio will throw a error with this type.
static const CANCEL = -4;
/// read the DioError.error if it is not null.
static const DEFAULT = -5;
}
method.dart
/// 请求方法.
class Method {
static const String get = "GET";
static final String post = "POST";
static final String put = "PUT";
static final String head = "HEAD";
static final String delete = "DELETE";
static final String patch = "PATCH";
}
2、service_api.dart 请求服务封装
import 'dart:async';
import 'package:dio/dio.dart';
import 'common/dio_utils.dart';
import 'common/method.dart';
class ServiceNetApi {
Future<Map> getPersons(data) async {
return await DioNetUtils().request<String>(
"/pwd/peoples",
queryParameters:data,
method:Method.get
);
}
}
3、请求参数Model封装
import 'package:flutter/material.dart';
class RequireModel {
String prov;
String parm;
RequireModel ({
@required this.prov, // 必须传递的参数使用@require修饰
this.parm
});
/// 实体类转 Map
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['prov'] = this.prov;
data['parm'] = this.parm;
return data;
}
}
返回数据
{
"code": 0,
"data": [
{
"addr": "shanghai",
"name": "java"
},
{
"addr": "beijing",
"name": "c"
}
],
"msg": "success"
}
4、list_entity.dart 封装如下
class ListEntity {
int code;
List<dynamic> data;
String msg;
/// Map 转实体类
ListEntity.fromJson(Map<String, dynamic> json) {
this.code = json['code'];
this.data = json['data'];
this.msg = json['msg'];
}
}
5、返回的一个people_entity.dart Model 对象封装
class PersionEntity {
String name;
String addr;
/// Map 转实体类
PersionEntity.fromJson(Map<String, dynamic> json) {
this.name= json['name'];
this.addr= json['addr'];
}
}
6、使用
void _getPeopleInfos() async {
await ServiceNetApi()
.getPersons(RequireModel(prov:'aa',parm:'bb').toJson())
.then((value) {
ListEntity entity = ListEntity.fromJson(value);
if (entity.code == 0) {
/// 解析数据
List<PersionEntity > list = entity.data
.map((e) => PersionEntity.fromJson((e as Map<String, dynamic>)))
.toList();
// do something...
setState(() {});
} else {
print('get failed');
}
}).catchError((e) {
print('get failed e = $e');
});
}