EJHttpClient

This is a convenient network framework.


License
MIT
Install
pod try EJHttpClient

Documentation

EJHttpClient

这是一个网络封装框架,将网络请求、加载符、错误提示等封装在一起,通过一句话调用方法进行网络请求。该框架集成AFNetworking和MJExtension,利用对象化概念,将请求参数封装成Model作为请求参数,通过请求回调,将响应参数封装成Model并自动赋值,极大的方便了中间解析的过程,更加专注于业务实现。

如何安装

利用Cocoapods安装,版本支持7.0以上

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '7.0'
inhibit_all_warnings!

target 'EJHttpClientDemo' do

pod 'EJHttpClient', '~> 1.0.0'

end

如何使用它

该框架在初始接入项目时,需要做一些花点时间来进行配置工作,本文讲解很细,请耐心看完,因为一旦接入完毕,将极大的简化开发工作和做相关接口测试工作。
通过此框架,基本无需采用MVVM的方式去实现请求代码。

开始配置:第一步,注册基本网络请求相关设置

介绍:总体需要5个配置,之后将围绕该5个配置进行接入。
1.一般应用都有固定的请求域名,配置应用基本域名URL。
2.一般应用都有通用请求参数,配置指定通用请求参数Model类名,并且针对不同数据的业务参数指定具体的Key。
3.一般应用都有通用响应参数,配置指定通用响应参数Model类名,并且针对不同数据的业务参数指定具体的Key。
4.针对响应请求,配置公共拦截器Model,以拦截处理指定信息的业务逻辑。
5.配置通用加载符类名和通用错误提示符类名。

基本代码如下:

- (void)registerAppSetting{
    [[EJHttpClient shared] ej_registerBaseURL:@"https://raw.githubusercontent.com"];
    [[EJHttpClient shared] ej_registerCommonRequestClassName:@"CommonRequestModel"  bizRequestKey:@"data"];
    [[EJHttpClient shared] ej_registerCommonResponseClassName:@"CommonResponseModel" bizResponseKey:@"data"];
    [[EJHttpClient shared] ej_registerInterceptorClassName:@"ResponseInterceptorModel"];
    [[EJHttpClient shared] ej_registerLoadingViewClassName:@"EJDefaultLoadingView" errorViewClassName:@"EJDefaultErrorView"];
    //如果有需要GZIP压缩请求的,还可以启用GZIP
    //[[EJHttpClient shared] ej_enableGzipRequestSerializer];
}
第二步,配置通用请求对象类和业务请求对象类

请求参数JSON例子如下:

{
    "device_id": "xxxx",
    "version" : "1.0.0",
    "channel": "iOS",
    "data": {
        "username" : "admin",
        "password" : "123456"
    }
}

分析:通过以上例子,我们认为,通用请求Model中,方法有3个,分别是device_id,version,channel , 而业务请求参数对应的Key则是data。 业务请求Model中,方法有2个,分别是username,password。因此,我们分别创建通用请求类CommonRequestModel和业务类LoginRequestModel如下:

CommonRequestModel如下:

#import <Foundation/Foundation.h>

@interface CommonRequestModel : NSObject

@property(copy,nonatomic,readonly) NSString *device_id;
@property(copy,nonatomic,readonly) NSString *version;
@property(copy,nonatomic,readonly) NSString *channel;

@end


#import "CommonRequestModel.h"
#import "MJExtension.h"

@implementation CommonRequestModel
MJCodingImplementation

- (instancetype)init
{
    self = [super init];
    if (self) {
        [CommonRequestModel mj_referenceReplacedKeyWhenCreatingKeyValues:YES];

        _channel = @"iOS";
        _version = @"1.0.0";
        _device_id =  @"xxxx";
    }
    return self;
}

@end

LoginRequestModel如下:

#import <Foundation/Foundation.h>
#import "EJHttpRequestDelegate.h"

@interface LoginRequestModel : NSObject <EJHttpRequestDelegate>

@property(copy,nonatomic) NSString *username;
@property(copy,nonatomic) NSString *password;

@end

#import "LoginRequestModel.h"
#import "MJExtension.h"
#import "ViewController.h"

@implementation LoginRequestModel
MJCodingImplementation

- (instancetype)init
{
    self = [super init];
    if (self) {
        [LoginRequestModel mj_referenceReplacedKeyWhenCreatingKeyValues:YES];
    }
    return self;
}

- (NSString *)ej_requestURLString{
    return @"iOnRoad/EJHttpClient/master/response.json";
}

- (NSString *)ej_responseClassName{
    return @"LoginResponseModel";
}

- (BOOL)ej_showLoading{
    return YES;
}

- (NSString *)ej_loadingMessage{
    return @"加载中";
}

- (UIView *)ej_loadingContainerView{
    return [ViewController currentController].view;
}

- (BOOL)ej_endLoadingWhenFinished{
    return YES;
}

- (BOOL)ej_showErrorMessage{
    return NO;
}

- (BOOL)ej_ignoreDuplicateRequest{
    return YES;
}

分析:LoginRequestModel需要实现EJHttpRequestDelegate协议,该协议中定义了 每个请求所需要的基本信息配置。

ej_requestURLString指定该请求的URL。
ej_responseClassName 指定该请求对应的响应参数Model的类名。它将会自动将请求参数转化为该类的对象并给其属性赋值。
ej_showLoading,ej_loadingMessage,ej_loadingContainerViewej_endLoadingWhenFinished是针对加载符的配置,分别标识是否显示加载符,加载符的文案是什么,显示在哪个View上,当请求结束时,是否结束加载符的显示。
ej_showErrorMessage标识是否显示错误提示。
ej_ignoreDuplicateRequest标识有多次请求的情况下,是否忽略重复多余的请求。

建议:最好建个请求Model基类,将这些协议按默认方案实现完毕,然后在某个具体的业务类中继承基类,并适当的修改某些方法的返回值来达到指定的目的,就不用每个类中这么复杂的实现了。

如LoginSubRequestModel类继承LoginRequestModel,仅仅实现2个就好,分别指定请求URL和响应对象类名,其他设置按基类默认设置,则实现如下:

@interface LoginSubRequestModel : LoginRequestModel

@end

@implementation LoginSubRequestModel

- (NSString *)ej_requestURLString{
    return @"/user/login.json";
}

- (NSString *)ej_responseClassName{
    return @"loginSubResponseModel";
}

@end
第三步,配置通用响应对象类和业务响应对象类

响应参数JSON例子如下:

{
    "flag": true,
    "errorCode": 16,
    "errorMsg": "error info",
    "data": {
        "username": "admin",
        "userToken": "123456"
    }
}

分析:通过以上例子,我们认为,通用响应Model中,方法有3个,分别是flag,errorCode,errorMsg , 而业务响应参数对应的Key则是data。 业务响应Model中,方法有2个,分别是username,userToken。因此,我们分别创建通用响应类CommonResponseModel和业务类LoginResponseModel如下:

CommonResponseModel如下:

#import <Foundation/Foundation.h>
#import "EJHttpResponseDelegate.h"

@interface CommonResponseModel : NSObject <EJHttpResponseDelegate>

@property(assign,nonatomic) BOOL flag;
@property(assign,nonatomic) NSInteger errorCode;
@property(copy,nonatomic) NSString *errorMsg;

@end

#import "CommonResponseModel.h"
#import "MJExtension.h"

@implementation CommonResponseModel
MJCodingImplementation

- (instancetype)init
{
    self = [super init];
    if (self) {
        [CommonResponseModel mj_referenceReplacedKeyWhenCreatingKeyValues:YES];
    }
    return self;
}

-(BOOL)ej_resultFlag{
    return self.flag;
}

- (NSString *)ej_errorTitle{
    return @"";
}

- (NSString *)ej_errorMessage{
    return self.errorMsg;
}

@end

LoginResponseModel如下:

@interface LoginResponseModel : NSObject

@property(copy,nonatomic) NSString *username;
@property(copy,nonatomic) NSString *userToken;

@end

#import "LoginResponseModel.h"
#import "MJExtension.h"

@implementation LoginResponseModel
MJCodingImplementation

- (instancetype)init
{
    self = [super init];
    if (self) {
        [LoginResponseModel mj_referenceReplacedKeyWhenCreatingKeyValues:YES];
    }
    return self;
}


@end

分析:CommonResponseModel类需要实现EJHttpResponseDelegate协议,来标识通用请求正确性的判断,错误标题以及错误内容。一般用于通用响应标识即可。如果具体某个请求响应标识的错误信息提示比较特别,则也可以在具体响应类上实现协议并指定。

第四步:配置拦截器
#import <Foundation/Foundation.h>
#import "EJHttpResponseInterceptor.h"

@interface ResponseInterceptorModel : NSObject <EJHttpResponseInterceptor>

@end

@implementation ResponseInterceptorModel

- (BOOL)ej_interceptorResponseObjectWithBizObject:(id)bizObject commonObject:(id)cmnObject{
    CommonResponseModel *cmnModel = (CommonResponseModel *)cmnObject;
    NSLog(@"cmnModel errorCode: %ld",cmnModel.errorCode);
    NSLog(@"cmnModel errorMsg: %@",cmnModel.errorMsg);

    if([bizObject isKindOfClass:[LoginResponseModel class]]){
        LoginResponseModel *model = (LoginResponseModel *)bizObject;
        if([@"admin" isEqualToString:model.username]){
            NSLog(@"admin request is intercepted. ");
            return YES;
        }else{
            NSLog(@"this request is not intercepted.");
        }
    }
    return NO;
}

- (BOOL)ej_interceptorResponseParam:(NSDictionary *)param{
    NSInteger errorCode = [param[@"errorCode"] integerValue];
    NSString *errorMsg = param[@"errorMsg"];
    NSLog(@"errorCode: %ld",errorCode);
    NSLog(@"errorMsg: %@",errorMsg);

    NSDictionary *data = param[@"data"];
    if(data){
        NSString *username = data[@"username"];
        if([@"admin" isEqualToString:username]){
            NSLog(@"admin request is intercepted. ");
            return YES;
        }else{
            NSLog(@"this request is not intercepted.");
        }
    }

    return NO;
}

@end

分析:需要实现EJHttpResponseInterceptor协议
ej_interceptorResponseObjectWithBizObject是针对对象入参出参的请求方式进行拦截。
ej_interceptorResponseParam是针对字典方式入参出参进行的拦截.

最后一步:配置加载符和错误提示

错误提示:
需要根据自己的项目,实现对应的错误提示界面,但需要继承EJErrorView,并实现- (void)ej_show;在该方法实现展示方式,具体参考Demo。

加载符:
需要根据自己的项目,实现对应的加载提示界面,但需要继承EJLoadingVIew,并实现- (void)ej_showInView:(UIView *)mView;- (void)ej_dismiss;,在该方法中实现展示和隐藏方式,具体参考Demo。

如何调用它

经过以上配置后,就可以进行调用了,调用方式如下:

  LoginRequestModel *model = [LoginRequestModel new];
//    model.username = @"admin";
//    model.password = @"123456";

    [[EJHttpClient shared] ej_requestParamObject:model method:GET responseHandler:^(id respObject, BOOL success) {
        if(success){
            LoginResponseModel *respModel = (LoginResponseModel *)respObject;
            NSLog(@"username:%@",respModel.username);
            NSLog(@"userToken:%@",respModel.userToken);
        }else{
            NSLog(@"error!");
        }
    }];

看到最后一步,是不是很简便的在程序中调用网络请求了。虽然配置上看起来繁琐了一些,但是实际操作并不繁琐,仅仅是在开始繁琐了一些,以后则极大的提高了开发效率。

更多用法

请下载demo查阅。我相信该框架对于您在项目中的开发会有很大效率的提高。