基于AF的二次封装FrankNetworkManage

对于iOS程序猿来说,AFNetworking的强大之处,自然是不用言表,大家都早已深有体会。但是一般在使用这些第三方的时候,我们一般都会根据自己的使用习惯及业务功能需求进行封装处理,当然我也一样,对AFNetworking进行了二次封装处理,所以此次发布出来仅供参考:

<a href="#">注意:使用该框架前,需要集成 AFNetworking 和 FMDB,因为该框架是基于这两者进行的二次封装</a>
<h4>一:框架特点</h4><h6>1:基于AFNetworking封装处理,简化了对AFNetworking的直接操作,使调用更加方便简洁;
2:将AFNetworking原有的两种回调方式拓展为了三种回调,并且支持用户根据服务器数据格式进行配置,功能细化,操作简单;
3:结合FMDB封装了数据库,可以根据需要进行缓存网络数据;
4:集成了DelegateBlock两种网络回调方式,用户可以根据自己的喜好进行选择使用任意一种回调方式;</h6>
Demo链接:https://github.com/Kinglions/FrankNetworkManage</br>
<h4>二:框架解析</h4>

框架截图.png

<h6>(1)网络请求框架:</h6>

/**
 *  网络请求封装
 */

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <AFNetworking.h>
#import <AFNetworking/AFURLSessionManager.h>
#import "FrankNetworkMacro.h"

typedef void (^RequestPrepare)();
typedef void (^RequestFinally)();

/**
 请求成功回调

 @param task 请求对象
 @param responseObject 响应数据
 @param requestParams 请求参数
 */
typedef void (^ReplySucess)(NSURLSessionDataTask *task, id responseObject, NSDictionary* requestParams);

/**
 请求失败回调
 */
typedef void (^ReplyFailure)(NSURLSessionDataTask *task, id responseObject, NSDictionary* requestParams);
/**
 请求错误回调
 */
typedef void (^ReplyError)(NSError *error, NSURLSessionDataTask *task, NSDictionary* requestParams);
/*  上传进度
 *
 *  @param bytesWritten              已上传的大小
 *  @param totalBytesWritten         总上传大小
 */
typedef void (^ReplyUploadProgress)(int64_t bytesWritten,int64_t totalBytesWritten);

typedef void (^MultipartData)(id <AFMultipartFormData> formData);

/**
 基础网络请求 其他的请求统一由此类发出

 - HTTP_REQUEST_METHOD_GET:
 - HTTP_REQUEST_METHOD_HEAD:
 - HTTP_REQUEST_METHOD_POST:
 - HTTP_REQUEST_METHOD_PUT:
 - HTTP_REQUEST_METHOD_PATCH:
 - HTTP_REQUEST_METHOD_DELETE:
 */
typedef NS_ENUM(NSUInteger, HTTP_REQUEST_METHOD) {
    
    HTTP_REQUEST_METHOD_GET = 0,
    HTTP_REQUEST_METHOD_HEAD,
    HTTP_REQUEST_METHOD_POST,
    HTTP_REQUEST_METHOD_PUT,
    HTTP_REQUEST_METHOD_PATCH,
    HTTP_REQUEST_METHOD_DELETE,
};

/**
 网络请求缓存处理

 - NetworkCacheType_Never: 重不进行缓存处理
 - NetworkCacheType_OnlyCache: 只进行缓存,但是不读取
 - NetworkCacheType_CacheAndLoad: 进行缓存,并且请求数据时先进行加载缓存,本次请求数据,下次加载
 */
typedef NS_ENUM(NSUInteger, NetworkCacheType) {
    
    NetworkCacheType_Never = 0,
    NetworkCacheType_OnlyCache,
    NetworkCacheType_CacheAndLoad,

};

@interface FrankNetworkManage : NSObject

/**
 *  创建单例对象
 */
+(instancetype)shareManager;

/**
 网络数据的缓存处理类型
 */
@property (nonatomic,assign)NetworkCacheType cacheType;

/**
 *  判断请求时是否需要 hud
 */
@property (nonatomic, assign) BOOL isShowHUD;

/**
 *  请求之前的准备,可直接调用本类对象的 prepare
 */
@property (nonatomic, copy) RequestPrepare prepare;

/**
 *  一个网络请求返回后做清理。
 */
@property (nonatomic,copy) RequestFinally finally;
/**
 *  网络请求返回成功
 */
@property (nonatomic, copy) ReplySucess sucess;

/**
 *  失败
 */
@property (nonatomic, copy) ReplyFailure failure;
/**
 *  请求出错
 */
@property (nonatomic, copy) ReplyError error;

/**
 共外界调用配置 判断逻辑【根据服务器返回值进行配置,可以在 Appdelegate 中进行设置】
 *
 *  @return YES 表示数据正确,NO 表示后台的错误提示,证明返回有误
 */
@property (nonatomic,copy) BOOL (^judgeResponseIsSuccess)(id responseSuccess);
/*
 *
 *  用于指定网络请求接口的基础url,如:
 *  http://www.baudu.com
 *  通常在AppDelegate中启动时就设置一次就可以了。
    如果接口有来源于多个服务器,可以调用更新
 *
 *
 *  @param baseUrl 网络接口的基础url
 */
+ (void)updateBaseUrl:(NSString *)baseUrl;
/*
 *  对外公开可获取当前所设置的网络接口基础url
 *
 *  @return 当前基础url
 */
+ (NSString *)baseUrl;
/**
 进行编码
 */
+ (NSString *)encodeUrl:(NSString *)url;
/**
 自动判断 baseurl 并进行组合 url
 */
+ (NSString *)absoluteUrlWithPath:(NSString *)path;


/**
 *  统一网络请求
 *
 *  @param method      请求类型(直接调用 枚举)
 *  @param urlString    请求URLString
 *  @param headerParams 请求头添加的参数
 *  @param params       请求参数
 *  @param finally      请求结束,进行清理(直接调用)
 *  @param sucess       请求成功,数据正常
 *  @param failure      请求失败
 *  @param netError      请求连接错误
 */
+(void)httpRequestWithHttpMethod:(HTTP_REQUEST_METHOD)method
                       urlString:(NSString *)urlString
                    headerParams:(NSDictionary *)headerParams
                          params:(id)params
                         finally:(RequestFinally)  finally
                          sucess:(ReplySucess)   sucess
                         failure:(ReplyFailure)  failure
                           error:(ReplyError)netError;




/*
 *
 *  开启或关闭是否自动将URL使用UTF8编码,用于处理链接中有中文时无法请求的问题
 *
 *  @param shouldAutoEncode YES or NO,默认为NO
 */
+ (void)shouldAutoEncodeUrl:(BOOL)shouldAutoEncode;


/*
 *  图片上传接口,若不指定baseurl,可传完整的url
 *
 *  @param image            图片对象
 *  @param url              上传图片的接口路径,如/path/images/
 *  @param filename     给图片起一个名字,默认为当前日期时间,格式为"yyyyMMddHHmmss",后缀为`jpg`
 *  @param name             与指定的图片相关联的名称,这是由后端写接口的人指定的,如imagefiles
 *  @param mimeType     默认为image/jpeg
 *  @param parameters   参数
 *  @param progress     上传进度
 *  @param success      上传成功回调
 *  @param fail             上传失败回调
 *
 *  @return
 */

+ (void)uploadWithImage:(UIImage *)image
                    url:(NSString *)url
               filename:(NSString *)filename
                   name:(NSString *)name
               mimeType:(NSString *)mimeType
             parameters:(NSDictionary *)parameters
               progress:(ReplyUploadProgress)progress
                success:(ReplySucess)success
                   fail:(ReplyError)fail;

/**
 *  上传文件操作
 *
 *  @param url                      上传路径
 *  @param uploadingFile    待上传文件的路径
 *  @param progress         上传进度
 *  @param success              上传成功回调
 *  @param fail                 上传失败回调
 *
 */
+ (void)uploadFileWithUrl:(NSString *)url
            uploadingFile:(NSString *)uploadingFile
                 progress:(ReplyUploadProgress)progress
                  success:(ReplySucess)success
                     fail:(ReplyError)fail;

其中需要注意的是@property (nonatomic,copy) BOOL (^judgeResponseIsSuccess)(id responseSuccess)属性,这个是根据后台的数据格式配置请求结果判断的回调,只需要在AppDelegate中进行配置一次就行。例如:

配置示例.png

<h6>(2)网络下载框架:</h6>

#import "FrankNetworkManage.h"

/**
 断点下载

 - DownloadStatus_ResumingDown: 开始下载
 - DownloadStatus_SuspendDown: 暂停下载
 */
typedef NS_ENUM(NSInteger ,DownloadStatus) {
    
    DownloadStatus_ResumingDown = 0,
    DownloadStatus_SuspendDown = 1,

};

@interface FrankHttpDownloadManage : FrankNetworkManage

/** AFNetworking断点下载(支持离线)需用到的属性 **********/
/** 
 文件的总长度
 */
@property (nonatomic,assign,readonly) NSInteger fileLength;
/** 
 当前下载长度
 */
@property (nonatomic,assign,readonly) NSInteger currentLength;

/**
 下载文件保存路径
 */
@property (nonatomic,copy,readonly)NSString * downSavePath;


/**
 *  下载文件操作
 *
 *  @param url                      下载地址
 *  @param saveName               保存文件名字
 *  @param progressBlock            下载进度
 *  @param success                  下载成功回调
 *  @param failure                  下载失败回调
 */
- (instancetype)initWithDownloadUrl:(NSString *)url
             saveName:(NSString *)saveName
               progress:(ReplyUploadProgress)progressBlock
                success:(ReplySucess)success
                failure:(ReplyError)failure;
/**
 下载状态
 
 - DownloadStatus_SuspendDown: 暂停下载
 - DownloadStatus_ResumingDown: 开始下载
 
 */
-(void)setDownloadStatus:(DownloadStatus)status;

@end

<h6>(3)请求类BaseModel类 :</h6>
这个类是为了方便使用,而创建的一个基类框架,相当于在ViewControllerFrankNetworkManage中间添加的一层,用于处理数据交互相关逻辑,所以后期创建具体请求类只需要集成该BaseRequestHttpModel类,重写父类方法即可。
代码解析:

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

/**
 请求成功时返回的数据

 @param models 数据模型
 */
typedef void(^SuccessModel)(id models);


/**
 代理方式下的 网络请求结果状态

 - ResponseHttpType_Success: 请求成功
 - ResponseHttpType_Failure: 请求失败
 - ResponseHttpType_NetworkError: 网络异常
 */
typedef NS_ENUM(NSInteger,ResponseHttpType) {
    ResponseHttpType_Success,
    ResponseHttpType_Failure,
    ResponseHttpType_NetworkError,
};
/**
 代理方式下的 网络请求类型,枚举回调区分
 */
typedef NS_ENUM(NSInteger,BusinessHttpType) {
    
    BusinessHttpType_None = 0,// 默认状态
    BusinessHttpType_LoadWeather ,// 请求天气
    
    // 此处可以根据自己的工程需求进行添加枚举分类。。。
};

#pragma mark -------- 通过 代理 方式处理请求回调,当使用 block 方式处理时,可以忽略代理  ---------
@protocol BaseRequestHttpModelDelegate <NSObject>

@optional
/**
 *  为了降低耦合性,通过这个协议方法可以在对请求状态进行判断
 *
 *  @param type      判断是哪一类发送的请求
 *  @param retStatus 请求成功失败的状态
 */
- (void)DoneBusiness:(enum BusinessHttpType)type status:(ResponseHttpType)retStatus;

@end


@interface BaseRequestHttpModel : NSObject


/**
 请求地址
 */
@property (nonatomic,strong)NSString * urlStr;

/**
 请求头数据字典
 */
@property (nonatomic,strong)NSMutableDictionary * headerParams;

/**
 网络请求失败回调
 */
@property (nonatomic,copy)ReplyFailure failureBlock;
/**
 网络错误回调
 */
@property (nonatomic,copy)ReplyError networkerrBlock;

#pragma mark -------- 通过 代理 方式处理请求回调  ---------
#pragma mark -------- 通过 代理 方式处理请求回调  ---------

/**
 设置网络请求代理【当使用 block 方式处理时,可以忽略代理】
 */
@property (nonatomic,weak)id <BaseRequestHttpModelDelegate>delegate;
/**
 网络请求API类型
 */
@property (nonatomic,assign) BusinessHttpType businessType;
/**
 告知当前网络处理状态
 */
-(void)doneBusiness:(ResponseHttpType)returnStatus;



/**
 供子类调用 【  代理方式请求调用方法  】
 
 @param method 请求方式
 @param params 请求参数数据
 @param isNeedHeader 是否需要 请求头数据
 */
-(void)doRequestWithHttpMethod:(HTTP_REQUEST_METHOD)method
                        params:(id)params
            isNeedHeaderParams:(BOOL)isNeedHeader;

#pragma mark -------- 通过 block 方式处理请求回调  ---------
#pragma mark -------- 通过 block 方式处理请求回调  ---------

/**
 供子类调用 【  代理方式请求调用方法  】
 
 @param method 请求方式
 @param params 请求参数数据
 @param isNeedHeader 是否需要 请求头数据
 @param success 成功回调数据模型
 @param fail 失败回调
 @param errorBlock 链接错误回调
 */
-(void)doRequestWithHttpMethod:(HTTP_REQUEST_METHOD)method
                        params:(id)params
        isNeedHeaderParams:(BOOL)isNeedHeader
                   success:(SuccessModel)success
                   failure:(ReplyFailure)fail
                  netError:(ReplyError)errorBlock;

#pragma mark -------- 根据自己的需求进行重写,数据转模型  ---------

/**
 之类需要根据自己的需求进行重写
 处理请求成功时,字典转模型的具体实现,并返回字典模型

 @param responseObject 响应数据
 @param requestParams 请求数据
 */
-(id)changeDateForModelWithResponseObject:(id)responseObject requestParams:(NSDictionary *)requestParams;

@end

<h6>注意点:</h6>
(1)当使用代理方式进行处理网络回调时,需要设置 delegate,调用请求方法

/**
 供子类调用 【  代理方式请求调用方法  】

 @param method 请求方式
 @param params 请求参数数据
 @param isNeedHeader 是否需要 请求头数据
 */
-(void)doRequestWithHttpMethod:(HTTP_REQUEST_METHOD)method
                        params:(id)params
            isNeedHeaderParams:(BOOL)isNeedHeader;

并且实现代理方法即可,后续的处理逻辑可以统一放在代理方法中进行处理

/**
 *  为了降低耦合性,通过这个协议方法可以在对请求状态进行判断
 *
 *  @param type      判断是哪一类发送的请求
 *  @param retStatus 请求成功失败的状态
 */
- (void)DoneBusiness:(enum BusinessHttpType)type status:(ResponseHttpType)retStatus

(2)当使用block回调进行处理网络回调时,只需要调用请求方法,对于每一个请求结果的处理都可以单独进行处理

/**
 供子类调用 【  代理方式请求调用方法  】
 
 @param method 请求方式
 @param params 请求参数数据
 @param isNeedHeader 是否需要 请求头数据
 @param success 成功回调数据模型
 @param fail 失败回调
 @param errorBlock 链接错误回调
 */
-(void)doRequestWithHttpMethod:(HTTP_REQUEST_METHOD)method
                        params:(id)params
        isNeedHeaderParams:(BOOL)isNeedHeader
                   success:(SuccessModel)success
                   failure:(ReplyFailure)fail
                  netError:(ReplyError)errorBlock;

但是不管是用那种方式,如果想要实现字典转模型,那都需要在子类中重写实现具体方法逻辑

/**
 之类需要根据自己的需求进行重写
 处理请求成功时,字典转模型的具体实现,并返回字典模型

 @param responseObject 响应数据
 @param requestParams 请求数据
 */
-(id)changeDateForModelWithResponseObject:(id)responseObject requestParams:(NSDictionary *)requestParams;

两种方式虽然方式不同,但是效果相同,所以只需要根据自己的喜好及业务需求进行选择使用即可。
<h6>(4)加载动画HUD展示:</h6>
这部分是加载动画hud,具体内容可移步 FrankActivityHUD 动画 进行查看</br>
<h6>(5)设备信息加载工具 DeviceManager:</h6>
这部分主要是为了方便查看、获取一些设备信息而集成的一个工具单例类,功能如下:

#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import <UIKit/UIKit.h>

//获取当前设备对应的height
#define Screen_height (MAX([[UIScreen mainScreen] bounds].size.height, [[UIScreen mainScreen] bounds].size.width))
//获取当前设备对应的width
#define Screen_width (MIN([[UIScreen mainScreen] bounds].size.height, [[UIScreen mainScreen] bounds].size.width))
//用于判断设备是否为长屏幕iphone,比如iphone5,iphone6,iphone6plus
#define IS_4inchIPHONE ( !IS_IPHONE4 )
//用于判断设备是否为iphone4
#define IS_IPHONE4 ( fabs( ( double )Screen_height - ( double )480 ) < DBL_EPSILON )
//用于判断设备是否为iphone5
#define IS_IPHONE5s_SE ( fabs( ( double )Screen_height - ( double )568 ) < DBL_EPSILON )
//用于判断设备是否为iphone6\iphone6plus
#define IS_IPHONE6_7 ( fabs( ( double )Screen_height - ( double )667 ) < DBL_EPSILON )
//用于判断设备是否为iphone6plus
#define IS_IPHONE6_PLUS ( fabs( ( double )Screen_height - ( double )736 ) < DBL_EPSILON)
//用于判断设备是否为iphone6之后
#define IS_IPHONE6_OR_LATER (((double)Screen_height - (double )568) > DBL_EPSILON)

// 比当前版本大
#define NOT_LESS_THAN_IOSVERSION(version) ([[[UIDevice currentDevice] systemVersion] floatValue] >= version)
// ios7 之后
#define IOS7_OR_LATER ([[[UIDevice currentDevice] systemVersion] compare:@"7.0" options:NSNumericSearch] != NSOrderedAscending)
// ios8 之后
#define IOS8_OR_LATER ([[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] != NSOrderedAscending)
// ios9 之后
#define IOS9_OR_LATER ([[[UIDevice currentDevice] systemVersion] compare:@"9.0" options:NSNumericSearch] != NSOrderedAscending)
// ios10 之后
#define IOS10_OR_LATER ([[[UIDevice currentDevice] systemVersion] compare:@"10.0" options:NSNumericSearch] != NSOrderedAscending)


@interface DeviceManage : NSObject


/**
 *  网络状态
 */
@property(nonatomic,copy)NSString * netWorkStatus;

/**
 *  设备系统版本
 */
@property (nonatomic, copy) NSString *systemVersion;
/**
 *   设备系统名
 */
@property (nonatomic,  copy) NSString *systemName;
/**
 *  机型
 */
@property (nonatomic,  copy) NSString *deviceModel;
/**
 *  设备名称(别名)
 */
@property (nonatomic,  copy) NSString *deviceName;
/**
 *  设备型号
 */
@property (nonatomic,  copy) NSString *deviceType;
/**
 *  手机总存储容量
 */
@property (nonatomic,  strong)NSString * totalDSB;
/**
 *  手机空闲存储容量
 */
@property (nonatomic,  strong)NSString * freeDSB;
/**
 *  手机总内存容量
 */
@property (nonatomic,  strong)NSString * totalMB;
/**
 *  手机空闲内存容量
 */
@property (nonatomic,  strong)NSString * freeMB;
/**
 *  cpu类型
 */
@property(nonatomic,strong)NSString * cpuType;
/**
 *  屏幕宽度
 */
@property (nonatomic, assign) CGFloat screenWidth;
/**
 *  屏幕高度
 */
@property (nonatomic, assign) CGFloat screenHeight;
/**
 *  分辨率
 */
@property (nonatomic, assign) CGFloat screenScale;
/**
 *  处理器(多核)
 */
@property (nonatomic, assign) NSInteger cpuCoreCount;
/**
 *  应用版本 【version】
 */
@property (nonatomic, strong) NSString *applicationMajorVersion;
/**
 *  最小版本 【build version】
 */
@property (nonatomic, strong) NSString *applicationMinorVersion;
/**
 *  当前应用名
 */
@property (nonatomic, strong) NSString *applicationDisplayName;
/**
 *  应用标识符
 */
@property (nonatomic, strong) NSString *applicationIdentifier;
/**
 *  启动状态
 */
@property (nonatomic, assign) NSInteger fetchLocationErrorCode;//-2--not started or OK, -1--in progress, >=0----failed
/**
 *  获取手机 IP 地址
 */
@property (nonatomic, strong) NSString * phoneIPAdress;
/**
 *   获取手机 Mac 地址
 */
@property (nonatomic, strong) NSString * phoneMacAddress;
/**
 *  获取单例对象
 */
+(DeviceManage *)shareDeviceManage;

@end

<h6>(6)数据库存储框架:</h6>
文件中包含三个类文件:
(1)FrankFMDBManage:是基于FMDB集成的数据库工具,隔离了SQL语句繁琐的操作,并且结合runtime实现了对象的直接存储操作,支持增、删、改、查、支持原始网络数据的存储
(2)FrankUserDefaults:是对 NSUserDefaults进行的一个简单封装,并且提供了不同类型数据的本地读写功能
(3)NSString+Category:是对NSString的一个分类,将一些常用的NSString功能方法进行封装,以便调用

具体的使用详情可参见 Demo链接: https://github.com/Kinglions/FrankNetworkManage</br> 如有发现存在问题,希望可以及时提出,相互交流,共同进步

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • 今天去看了电影,《古剑奇谭之流月昭明》,剧情感觉一般,喜欢里面的特效,喜欢在画里的唯美风,假期去打发一下时间还是可...
    车小刀阅读 156评论 0 0
  • 当你看到这段文字 我已经爱上了你 你一定会讶异我会未卜先知 寻到一个意外之喜 我也在庆幸 此刻,有你
    边策_7c2a阅读 80评论 0 0
  • 2017,世界还是那么大,可是我开始记录自己了。你呢?(持续更新中) 已经有很长时间没有提起笔来,慢慢书写自己的心...
    RUGEN阅读 175评论 0 1
  • 话本小说收作者啦,主收同人(明星、动漫、游戏、影视、小说同人) 副收女频(现言、古言等)。网编负责带。 1,作者...
    碎糖阅读 166评论 0 1
  • 奈何舍万代永安之策,徇一时省费之便乎!
    Poison_a29a阅读 187评论 0 0