一、核心理念
化繁为简,最终使用时,简单易用,扩展性强即可。
二、网络请求,基于Dio的封装
dio 官网地址
先看最终使用事例(1.定义返回的实体类 2.发起网络请求)
// 1. 返回实体类 UserBean 的定义(根据Json 用开发工具生成即可)
class UserBean implements BaseHttpBean {
UserBean({
this.token,
this.userId,
});
String? token;
String? userId;
// 解析数据
UserBean.fromJson(dynamic json) {
token = json['token'];
user_id = json['userId']?.toString();
}
// 这个方法是 实现父类BaseHttpBean 的方法,下面会详解
@override
UserBean fromJson(dynamic json) {
return UserBean.fromJson(json);
}
}
// 2. 登录网络请求--事例
void login(){
AppRequest.login("account","password", cancelToken).then((UserBean bean) {
// 成功处理 ...
}).catchError((e) {
// 异常处理 ...
});
}
三、网络封装具体过程
1.接口定义
/// 网络请求 最常用的定义 实际项目自己添加或者修改
class BaseHttp {
/// BaseUrl
String baseUrl() {
return "";
}
/// 固定的请求头(所有接口只走一次)
Map<String, dynamic>? baseHeaders() {
return null;
}
/// 特有的请求头(每个接口都会走)
Map<String, dynamic>? headers() {
return null;
}
/// 超时时间
Duration timeout() {
return const Duration(seconds: 45);
}
/// 连接超时时间
Duration connectTimeout() {
return const Duration(seconds: 3);
}
/// 数据转换 - 扩展用(比如数据解密)
dynamic convert(dynamic json) {
return json;
}
}
2. DIO 实现基本的网络请求
/// 根据Dio的基本封装
class BaseDio extends BaseHttp {
late Dio _dio;
// 配置信息
late BaseOptions baseOptions;
// 是否初始化
bool _isInit = false;
/// 初始化构造
BaseDio.init() {
if (_isInit) {
return;
}
baseOptions = BaseOptions(
baseUrl: baseUrl(),
headers: baseHeaders(),
connectTimeout: connectTimeout(),
);
_dio = Dio(baseOptions);
_isInit = true;
}
/// 设置BaseURL 根据实际情况修改 如果固定 就复写 baseUrl()
void setBaseUrl(String url) {
if (_isInit) {
baseOptions.baseUrl = url;
}
}
/// 配置信息,子类可以根据实际覆写
Options options() {
final options = Options(
headers: headers(),
);
return options;
}
/// 核心方法:网络请求统一实现
Future<T> request<T>(
String path, {
String method = "GET",
Map<String, dynamic>? params,
CancelToken? cancelToken,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
// 参数配置
var option = options();
if (method == "FORM") {
option.method = "POST";
} else {
option.method = method;
}
// 请求参数
Map<String, dynamic>? queryParameters;
// 表单请求
Object? data;
if (method == "GET") {
queryParameters = params;
} else {
// POST FORM
if (params != null) {
if (method == "POST") {
data = params;
} else {
data = FormData.fromMap(params);
}
}
}
// dio 发起网络请求
var response = await _dio.request(
path,
data: data,
queryParameters: queryParameters,
cancelToken: cancelToken,
options: option,
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress,
);
if (response.statusCode == 200) {
// 返回请求成功的结果
return Future.value(response.data);
}
throw Exception("网络请求出错:${response.statusCode}");
}
}
3.基本数据类的定义
/// 1.网络请求 数据解析定义
abstract class BaseHttpBean {
dynamic fromJson(dynamic json);
}
/// 2. 网络请求处理 根据实际项目 自己统一封装的类
class HttpBean<T extends BaseHttpBean, K> {
HttpBean({
this.code,
this.msg,
this.data,
});
int? code; // 响应码
String? msg; // 响应的信息
K? data; // 响应的数据 可能是:{} 或者 []
/// 是否成功
bool success() {
return code == 0 || code == 1;
}
HttpBean.fromJson(dynamic json, T type) {
code = json['code'] as int?;
msg = json['msg'];
// 解析data
var result = json['data'];
// List 处理
if (result is List) {
this.data = List<T>.from(result.map((item) => type.fromJson(item)).toList()) as K?;
} else {
this.data = type.fromJson(result);
}
}
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['code'] = code;
map['msg'] = msg;
map['data'] = data;
return map;
}
}
4.网络请求,实际项目客户端请求封装(Get Post Form),上传下载这些可以自己扩展
/// 网络请求,实际项目客户端请求封装(Get Post Form)
class BaseClient extends BaseDio {
BaseClient.init() : super.init();
/// 核心方法 -- 数据统一处理
Future<K> _requestData<T extends BaseHttpBean, K>(
String path, // 路径
T type, // 实际解析类
{
String method = "GET", // 请求方式
Map<String, dynamic>? params, // 请求参数
CancelToken? cancelToken, // 取消的Token
ProgressCallback? onSendProgress, // 扩展操作用
ProgressCallback? onReceiveProgress, // 扩展操作用
}) async {
// 1. 请求数据
var data = await request(
path,
method: method,
params: params,
cancelToken: cancelToken,
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress,
);
// 2. 根据实际 转换数据,默认就是返回 data原有数据
var json = convert(data);
// 测试模式 打印LOG
if (kDebugMode) {
print("url==>${baseOptions.baseUrl}$path");
print("header==>${jsonEncode(params)}");
print("result==>${jsonEncode(json)}");
}
// 3. 解析数据
var bean = HttpBean.fromJson(json, type);
if (bean.success()) {
// 4. 返回最终结果
return Future.value(bean.data as K);
}
throw Exception("数据解析出错 请检查实体Bean");
}
/// Get 请求
Future<K> get<T extends BaseHttpBean, K>(
String path,
T type, {
Map<String, dynamic>? params,
CancelToken? cancelToken,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
return _requestData(
path,
type,
method: "GET",
params: params,
cancelToken: cancelToken,
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress,
);
}
/// Post请求
Future<K> post<T extends BaseHttpBean, K>(
String path,
T type, {
Map<String, dynamic>? params,
CancelToken? cancelToken,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
return _requestData(
path,
type,
method: "POST",
params: params,
cancelToken: cancelToken,
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress,
);
}
/// 表单请求
Future<K> form<T extends BaseHttpBean, K>(
String path,
T type, {
Map<String, dynamic>? params,
CancelToken? cancelToken,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
return _requestData(
path,
type,
method: "FORM",
params: params,
cancelToken: cancelToken,
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress,
);
}
}
5.项目最终使用
5.1 项目网络的最终封装
/// 客户端网络请求
class AppClient extends BaseClient {
AppClient.init() : super.init();
/// 请求头
@override
Map<String, dynamic>? headers() {
Map<String, dynamic> header = {};
header["deviceid"] = "AAABBBCCC123456XXX";
// ...
return header;
}
/// 根据实际情况处理数据,比如解密操作
@override
dynamic convert(json) {
return json;
}
}
5.2 接口统一管理类(项目接口统一定义的地方)
/// 1. 接口统一管理类
class AppRequest {
static final _client = AppClient.init();
/// 设置BaseUrl
static void setBaseUrl(String url) {
_client.setBaseUrl(url);
}
/// 登录接口 (UserBean在下面最终使用里会看到)
static Future<UserBean> login(var account,var password, {CancelToken? cancelToken}) {
var path = "/login";
Map<String, dynamic> params = {};
params["account"] = account;
params["password"] = password;
return _client.post(path, UserBean(),
cancelToken: cancelToken, params: params);
}
/// 系统配置接口
static Future<SystemBean> systemConfig({CancelToken? cancelToken}) {
var path = "/system/config";
return _client.post(path, SystemBean(), cancelToken: cancelToken);
}
}
5.3 最终使用事例(1.定义返回的实体类 2.发起网络请求)
// 1. 返回实体类 UserBean 的定义(根据Json 用开发工具生成即可)
class UserBean implements BaseHttpBean {
UserBean({
this.token,
this.userId,
});
String? token;
String? userId;
// 解析数据
UserBean.fromJson(dynamic json) {
token = json['token'];
user_id = json['userId']?.toString();
}
// 这个方法是 实现父类BaseHttpBean 的方法,下面会详解
@override
UserBean fromJson(dynamic json) {
return UserBean.fromJson(json);
}
}
// 2. 登录网络请求--事例
void login(){
AppRequest.login("account","password", cancelToken).then((UserBean bean) {
// 成功处理 ...
}).catchError((e) {
// 异常处理 ...
});
}