iOS XMPP——登錄

一春叫、用戶登錄流程

用戶登錄流程.png
  • 注意:XMPP核心文件噪矛,基于TCP的XML流的傳輸小渊,XMPPFrame框架是通過代理的方式實現(xiàn)消息傳遞的

實現(xiàn)用戶登錄的步驟如下:

  • 1放可、實例化XMPPStream并設(shè)置代理谒臼,同時添加代理到工作隊列
  • 2、使用JID連接至服務(wù)器耀里,默認端口為5222蜈缤,JID字符串中需要包含服務(wù)器的域名
  • 3、 在完成連接的代理方法中驗證用戶密碼备韧,連接完成后XMPPStream的isConnect屬性為YES
    +4劫樟、 在驗證代理方法中判斷用戶是否登錄成功
  • 5、上線或者下線成功后,向服務(wù)器發(fā)送Presence數(shù)據(jù)叠艳,以更新用戶在服務(wù)器的狀態(tài)

二奶陈、注意

  • 為了簡化開發(fā),XMPP的引用程序通常會將XMPPStream放置在AppDelegate中,以便于全局訪問

三阐滩、分析

1闺金、封裝登錄工具類 JPLoginTool

  • 利用工具類,保存用戶登錄信息到沙盒中
    1. 頭文件 .h
#import <Foundation/Foundation.h>

@interface JPLoginTool : NSObject

/**
 *  保存登錄信息到沙盒
 */
+(void)saveLoginInfoWithAccount:(NSString *)account pwd:(NSString *)pwd domain:(NSString *)domain;

/**
 *  獲取沙盒的帳號
 *
 */
+(NSString *)account;

/**
 *  獲取沙盒的密碼
 *
 */
+(NSString *)password;


/**
 *  獲取沙盒的域名
 *
 */
+(NSString *)domain;

/**
 *  從沙盒清除所有的用戶登錄信息
 */
+(void)removeAllLoginInfo;

/**
 *  獲取用戶登錄狀態(tài)
 *
 */
+(BOOL)isLogin;


/**
 *  設(shè)置用戶登錄狀態(tài)
 */
+(void)setLogin:(BOOL)login;
@end
    1. .m實現(xiàn)文件
#import "JPLoginTool.h"

#define kAccountKey @"account"
#define kPasswordKey @"passsword"
#define kDomainKey @"domain"
#define kIsLoginKey @"isLogin"


@implementation JPLoginTool

+(void)saveLoginInfoWithAccount:(NSString *)account pwd:(NSString *)pwd domain:(NSString *)domain{
    NSUserDefaults *defaults =  [NSUserDefaults standardUserDefaults];
    [defaults setObject:account forKey:kAccountKey];
    [defaults setObject:pwd forKey:kPasswordKey];
    [defaults setObject:domain forKey:kDomainKey];
    
    //同步沙盒
    [defaults synchronize];
}

/**
 *  獲取沙盒的帳號
 *
 */
+(NSString *)account{
    
    return [[NSUserDefaults standardUserDefaults] objectForKey:kAccountKey];
}

/**
 *  獲取沙盒的密碼
 *
 */
+(NSString *)password{
    return [[NSUserDefaults standardUserDefaults] objectForKey:kPasswordKey];
}

/**
 *  獲取沙盒的域名
 *
 */
+(NSString *)domain{
    return [[NSUserDefaults standardUserDefaults] objectForKey:kDomainKey];
}

/**
 *  從沙盒清除所有的用戶登錄信息
 *
 */
+(void)removeAllLoginInfo{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults removeObjectForKey:kAccountKey];
    [defaults removeObjectForKey:kPasswordKey];
    [defaults removeObjectForKey:kDomainKey];
    [defaults synchronize];
}


/**
 *  獲取用戶登錄狀態(tài)
 *
 */
+(BOOL)isLogin{
    return [[NSUserDefaults standardUserDefaults] boolForKey:kIsLoginKey];
}


/**
 *  設(shè)置用戶登錄狀態(tài)
 */
+(void)setLogin:(BOOL)login{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setBool:login forKey:kIsLoginKey];
    [defaults synchronize];
}
@end

2徐勃、AppDelegate.h 文件中

  • 1、首先早像,我們布局登錄界面僻肖,提供登錄按鈕,當我們點擊登錄按鈕時就進行登錄操作卢鹦,因為XMPPFrame的相關(guān)操作都建議寫在AppDelegate文件中臀脏,所以我們需要在AppDelegate.h文件中提供接口給用戶,而至于那些連接到服務(wù)器以及授權(quán)等操作都寫在AppDelegate.m中不用暴露給用戶冀自。
#pragma mark 用戶登錄
-(void)xmppUserLogin;
  • 2揉稚、但是,當我們點擊登錄熬粗,在控制器的登錄方法中搀玖,拿到應(yīng)用程序的代理,然后調(diào)用應(yīng)用代理的xmppUserLogin方法驻呐,此時不僅要執(zhí)行登錄操作灌诅,而且應(yīng)用代理必須要告訴我們是否登錄成功,因為登錄操作是封裝到AppDelegate中的 - > 這就要實現(xiàn)兩者之間的通信了暴氏。
    • 有多種通信方式延塑,通知/代理/block/action等,這里我選擇代理答渔,所以重新設(shè)置應(yīng)用代理提供的登錄接口為:
// 在應(yīng)用代理頭文件中

// 1. 定義block

typedef enum {
    XMPPResultTypeLogining,//正在登錄中
    XMPPResultTypeLoginSuccess,//登錄成功
    XMPPResultTypeLoginFailure,//登錄失敗
    XMPPResultTypeNetError,//網(wǎng)絡(luò)不給力
    XMPPResultTypeUnknowDomain,//域名不存在
    XMPPResultTypeConnectionRefused//服務(wù)器拒絕連接
} XMPPResultType;

typedef void (^XMPPResultBlock)(XMPPResultType resultType);//xmpp請求結(jié)果的block

// 2.提供為外界登錄接口
#pragma mark 用戶登錄
-(void)xmppUserLogin:(XMPPResultBlock)resultBlock;
  • 3关带、用戶登錄成功后,可以點擊控制器視圖中的注銷按鈕進行注銷操作沼撕,所以我們在AppDelegate中提供了一個注銷方法接口給外界
#pragma 用戶注銷
-(void)xmppUserLogout;
  • 4宋雏、當我們的用戶狀態(tài)改變的時候,要告訴外界务豺,比如磨总,用戶在線時,需要一些處理笼沥,所以我們不僅需要將用戶的登錄信息寫入到沙盒中蚪燕,而且用戶的狀態(tài)也要寫入到沙盒中娶牌,第二個問題:當我們的用戶狀態(tài)改變的時候,我們要告訴控制器馆纳,讓控制器進行一些處理操作:又牽扯到通信了诗良,這里:采用通知告知吧
//登錄狀態(tài)改變
#define kLoginStateChangeNotification @"LoginStateChangeNotification"
  • 5、AppDelegate.h頭文件
#import <UIKit/UIKit.h>

#define kIsLoginKey @"isLogin"

//登錄狀態(tài)改變
#define kLoginStateChangeNotification @"LoginStateChangeNotification"

#define xmppDelegate ((JPAppDelegate *)[UIApplication sharedApplication].delegate)

typedef enum {
    XMPPResultTypeLogining,//正在登錄中
    XMPPResultTypeLoginSuccess,//登錄成功
    XMPPResultTypeLoginFailure,//登錄失敗
    XMPPResultTypeNetError,//網(wǎng)絡(luò)不給力
    XMPPResultTypeUnknowDomain,//域名不存在
    XMPPResultTypeConnectionRefused//服務(wù)器拒絕連接
}XMPPResultType;
typedef void (^XMPPResultBlock)(XMPPResultType resultType);//xmpp請求結(jié)果的block

@interface JPAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;


#pragma mark 用戶登錄
-(void)xmppUserLogin:(XMPPResultBlock)resultBlock;


#pragma 用戶注銷
-(void)xmppUserLogout;

@end

三鲁驶、AppDelegate.m實現(xiàn)文件

  • 0.在登錄界面點擊登錄按鈕鉴裹,登錄成功后,進入主界面

  • 1.用戶登錄成功后钥弯,退出到后臺時径荔,斷開連接,顯示在前臺時自動連接(添加一個isLogin用戶偏好設(shè)置)

  • 2.用戶成功登錄后脆霎,如果是重新啟動程序总处,直接跳到主界面,否則跳到登錄頁面

  • 3.用戶成功登錄后睛蛛,如果是重新啟動程序辨泳,下次啟動時自動登錄

  • 4.用戶登錄失敗時,清除偏好設(shè)置

  • 5.用戶登錄失敗時要提示

  • 6.用戶注銷

  • 7.進入登錄頁面時玖院,自動顯示上一次登錄數(shù)據(jù)

  • 注意:

    • 官方建議,把用戶授權(quán)寫在appdelegate
#import "JPAppDelegate.h"
#import "JPLoginTool.h"


#define kMainStoryboardName @"Main"
#define kLoginStoryboardName @"Login"

@interface JPAppDelegate()<XMPPStreamDelegate>{
    
    XMPPResultBlock _resultBlock;
}

//初始化xmppStream
-(void)setupXmppStream;

//連接主機
-(void)connectToHost;

//從主機斷開連接
-(void)disconnectFromHost;

//授權(quán)(也就發(fā)送帳號和密碼)
-(void)userAuth;

//用戶上線(通知其他好友,你已經(jīng)在線)
-(void)goOnline;

//用戶用戶離線
-(void)goOffline;

@end

@implementation JPAppDelegate

//官方建議,把用戶授權(quán)寫在appdelegate
/**
 *  0.初始化xmppStream
 *  1.連接主機
 *  2.從主機斷開連接
 *  3.授權(quán)(也就發(fā)送帳號和密碼)
 *  4.用戶上線(通知其他好友,你已經(jīng)在線)
 *  5.用戶用戶離線
 */


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    
    //NSLog(@"%s %d",__func__,__LINE__);
    
    //設(shè)置日志輸出方式(輸出到控制器)
    [DDLog addLogger:[DDTTYLogger sharedInstance]];
    
    //設(shè)置顏色
    [[DDTTYLogger sharedInstance] setColorsEnabled:YES];
    
    
    //設(shè)置自己的日志顏色
    [[DDTTYLogger sharedInstance] setForegroundColor:[UIColor blueColor] backgroundColor:nil forFlag:LOG_LEVEL_INFO];
    
    // 初始化xmppStream
    [self setupXmppStream];
    
    return YES;
}
#pragma 失去焦點
- (void)applicationWillResignActive:(UIApplication *)application
{
    //從主機斷開連接
    //[self disconnectFromHost];
    
    //獲取登錄狀態(tài)
    if([JPLoginTool isLogin]){
        //NSLog(@"登錄過");
        //如果是登錄 斷開連接
        [self disconnectFromHost];
    };
}



#pragma mark 獲取焦點
- (void)applicationDidBecomeActive:(UIApplication *)application
{
    //[self connectToHost];
    //獲取登錄狀態(tài) 如果登錄過,直接跳到主頁面 然后自動登錄
    if([JPLoginTool isLogin]){
        NSLog(@"登錄過");
        //直接跳到主頁
        [self showStoryboardWithName:kMainStoryboardName];
        
        //自動登錄
        [self connectToHost];
    };
}

#pragma mark - xmppSteam代理
#pragma mark 連接成功
-(void)xmppStreamDidConnect:(XMPPStream *)sender{
    JPLogInfo(@"與主機連接成功");
     //JPLogInfo(@"登錄");
     //發(fā)送登錄密碼驗證
        [self userAuth];
}

#pragma mark 連接失敗
-(void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error{
    
    //如果error為空,代理正常斷開
    JPLogInfo(@"連接失敗 %@",error);
    
    //有error 并且block有值 通知登錄控制器
    
    if (error && _resultBlock) {
        //域名或者主機不存
        if (error.code == 8) {
            _resultBlock(XMPPResultTypeUnknowDomain);
        }else if(error.code == 61){
            _resultBlock(XMPPResultTypeConnectionRefused);
        } else{
            _resultBlock(XMPPResultTypeNetError);
        }
    }
    
    // 清除用戶偏好設(shè)置
    if (error) {
        [JPLoginTool removeAllLoginInfo];
    }
}

#pragma mark 用戶授權(quán)成功
-(void)xmppStreamDidAuthenticate:(XMPPStream *)sender{
   // 子線程
    NSLog(@"%@",[NSThread currentThread]);
    JPLogInfo(@"用戶授權(quán)成功");
    // 把"登錄狀態(tài)"通知"聊天歷史控制器"
    // 登錄成功
    [self postLoginNotification:XMPPResultTypeLoginSuccess];
    
    // 1.通知用戶上線
    [self goOnline];
    
    // 2.如果用戶登錄成功 沙盒里保存一個登錄狀態(tài)
    [JPLoginTool setLogin:YES];

    //在主線程更新UI
    [self showStoryboardWithName:kMainStoryboardName];
}

#pragma mark 用戶授權(quán)失敗
-(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error{
    JPLogInfo(@"用戶授權(quán)失敗%@",error);
    //把"登錄狀態(tài)"通知"聊天歷史控制器"
    //登錄失敗
    [self postLoginNotification:XMPPResultTypeLoginFailure];
   
    //清除用戶偏好設(shè)置
    [JPLoginTool removeAllLoginInfo];
    //通知登錄控制器
    if (_resultBlock) {
        _resultBlock(XMPPResultTypeLoginFailure);
    }
//    dispatch_async(dispatch_get_main_queue(), ^{
//        
//    });
}

#pragma mark -私有方法

#pragma mark 初始化xmppStrem對象
-(void)setupXmppStream{
    
    NSAssert(_xmppStream == nil, @"xmppStream對象初始化多次");
    
    //1.創(chuàng)建xmppStrem對象
    _xmppStream = [[XMPPStream alloc] init];
    //2.添加代表
    [_xmppStream addDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
}

-(void)connectToHost{
    JPLogInfo(@"開始連接到主機");
    
    //把"登錄狀態(tài)"通知"聊天歷史控制器"
    //登錄中
    [self postLoginNotification:XMPPResultTypeLogining];

    //從沙盒里獲取數(shù)據(jù)
    NSString *account =  [JPLoginTool account];
    NSString *domain = [JPLoginTool domain];
    
    //1.設(shè)置賬號
    _xmppStream.myJID = [XMPPJID jidWithUser:account domain:domain resource:nil];
    
    //2.設(shè)置主機
    _xmppStream.hostName = domain;
    
    //3.設(shè)置主機端口
    //默認端口就5222
    _xmppStream.hostPort = 5222;
    //連接到主機
    
    NSError *err = nil;
    [_xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:&err];
    if (err) {
       JPLogInfo(@"%@ ",err);
    }
}

#pragma mark 從主機斷連接
-(void)disconnectFromHost{
    // 1.通知用戶下線
    [self goOffline];
    
    // 2.斷開連接
    [_xmppStream disconnect];
}

#pragma mark 用戶授權(quán)
-(void)userAuth{
    JPLogInfo(@"用戶開始授權(quán)");
     
    NSError *error = nil;
    //發(fā)送密碼到服務(wù)器
    [_xmppStream authenticateWithPassword:[JPLoginTool password] error:&error];
    
    if (error) {
        JPLogInfo(@"%@",error);
    }
}

#pragma mark 用戶上線
-(void)goOnline{
    JPLogInfo(@"通知用戶在線");
    XMPPPresence *presence  = [XMPPPresence presence];
    [_xmppStream sendElement:presence];
}

#pragma mark 用戶下線
-(void)goOffline{
    JPLogInfo(@"通知用戶下線");
    XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
    [_xmppStream sendElement:presence];
}

#pragma mark 顯示storyboard的第一個控制器
// 比如用戶登錄成功后,設(shè)置主窗口的根控制器為tabVC第岖,然后难菌,選中的tabVC的第三個子控制器,
// 然后退出到后臺蔑滓,當用戶再次進入到前臺時郊酒,并不需要重新設(shè)置窗口的根控制器此時。
// 那什么時候需要設(shè)置呢-> 當主窗口的根控制器不是tabVC才需要重新設(shè)置窗口的根控制器
-(void)showStoryboardWithName:(NSString *)name{
    dispatch_async(dispatch_get_main_queue(), ^{
        // 3.顯示主界面
        // 3.1獲取sotryboard對象
        UIStoryboard *storyboard = [UIStoryboard storyboardWithName:name bundle:nil];
        
        //3.2獲取windows的舊的根控制器
        UIViewController *oldVc = self.window.rootViewController;
        JPLogWarn(@"舊的控制器 %@",oldVc);
        
        //3.3獲取要切換storyboard里面的第一個控制器
        UIViewController *newVc = [storyboard instantiateInitialViewController];
        
        JPLogWarn(@"要切換的控制器 %@",newVc);
        
        //如果舊的控制器類型和新的控制器類型不一樣,才須要切換UIWindow的根控制器
        if (![oldVc isKindOfClass:[newVc class]]) {
            //38
            self.window.rootViewController = newVc;
        }
    });
}


#pragma mark -公共方法
#pragma mark 用戶登錄
-(void)xmppUserLogin:(XMPPResultBlock)resultBlock{
    //block負值
    _resultBlock = resultBlock;
    
    JPLogInfo(@"用戶登錄被調(diào)用");
    //如果當前socket存在連接,應(yīng)該斷開
//    if (_xmppStream.isConnected) {
//        [_xmppStream disconnect];
//    }
    
    [_xmppStream disconnect];
    [self connectToHost];
}


#pragma mark 用戶注銷
-(void)xmppUserLogout{
    //1.設(shè)置登錄狀態(tài)為NO
    [JPLoginTool setLogin:NO];
    
    //2.斷開連接
    [self disconnectFromHost];
    
    //3.返回到登錄頁面
    [self showStoryboardWithName:@"Login"];
}

#pragma mark 登錄狀態(tài)通知
-(void)postLoginNotification:(XMPPResultType)resultType{
    //把"登錄狀態(tài)"通知"聊天歷史控制器"
    //登錄成功
    dispatch_async(dispatch_get_main_queue(), ^{
        NSDictionary *userInfo = @{@"LoginState": @(resultType)};
        
        [[NSNotificationCenter defaultCenter] postNotificationName:kLoginStateChangeNotification object:nil userInfo:userInfo];
    });
}

四键袱、控制器中實現(xiàn)登錄

- (IBAction)login {
    
    //1.把你登錄信息保存到沙盒里
    NSString *account = self.accountField.text;
    NSString *password = self.passwordFiled.text;
    NSString *domain = self.domainField.text;
    
    [JPLoginTool saveLoginInfoWithAccount:account pwd:password domain:domain];
    
    //隱藏keyboard
    [self.view endEditing:YES];
    
    //提醒正在登錄
    UIView *showView = self.view;
    [MBProgressHUD showMessage:@"正在登錄......" toView:showView];
    
    
    xmppDelegate.userRegister = NO;//代表登錄
    
    //2.調(diào)用appdelegate里的xmmpUserLogin方法
    //JPAppDelegate *delegate = [UIApplication sharedApplication].delegate;
    [xmppDelegate xmppUserLogin:^(XMPPResultType resultType) {
        //隱藏正在登錄
        //因為這個block是被appdelegate里面xmppStream的代理調(diào)用,而xmppStream代理被調(diào)用是在子線線程中的,所在更新UI放在主線程
        dispatch_async(dispatch_get_main_queue(), ^{
            [MBProgressHUD hideHUDForView:showView];
            switch (resultType) {
                case XMPPResultTypeLoginFailure:
                    [MBProgressHUD showError:@"用戶名或者密碼錯誤"];
                    break;
                case XMPPResultTypeNetError:
                    [MBProgressHUD showError:@"網(wǎng)絡(luò)不給力"];
                    break;
                case XMPPResultTypeConnectionRefused:
                    [MBProgressHUD showError:@"服務(wù)器拒絕連接,可能服務(wù)沒有開啟"];
                    break;
                case XMPPResultTypeUnknowDomain:
                    JPLogInfo(@"域名不存在或者錯誤");
                    [MBProgressHUD showError:@"域名不存在或者錯誤"];
                    break;
                default:
                    break;
            }
        });
       
    }];
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末燎窘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蹄咖,更是在濱河造成了極大的恐慌褐健,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件澜汤,死亡現(xiàn)場離奇詭異蚜迅,居然都是意外死亡,警方通過查閱死者的電腦和手機俊抵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門谁不,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人徽诲,你說我怎么就攤上這事刹帕〕逞” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵偷溺,是天一觀的道長蹋辅。 經(jīng)常有香客問我,道長亡蓉,這世上最難降的妖魔是什么晕翠? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮砍濒,結(jié)果婚禮上淋肾,老公的妹妹穿的比我還像新娘。我一直安慰自己爸邢,他們只是感情好樊卓,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著杠河,像睡著了一般碌尔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上券敌,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天唾戚,我揣著相機與錄音,去河邊找鬼待诅。 笑死叹坦,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的卑雁。 我是一名探鬼主播募书,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼测蹲!你這毒婦竟也來了莹捡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤扣甲,失蹤者是張志新(化名)和其女友劉穎篮赢,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體琉挖,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡荷逞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了粹排。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片种远。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖顽耳,靈堂內(nèi)的尸體忽然破棺而出坠敷,到底是詐尸還是另有隱情妙同,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布膝迎,位于F島的核電站粥帚,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏限次。R本人自食惡果不足惜芒涡,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望卖漫。 院中可真熱鬧费尽,春花似錦、人聲如沸羊始。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽突委。三九已至柏卤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間匀油,已是汗流浹背缘缚。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留敌蚜,地道東北人忙灼。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像钝侠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子酸舍,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理帅韧,服務(wù)發(fā)現(xiàn),斷路器啃勉,智...
    卡卡羅2017閱讀 134,601評論 18 139
  • 國家電網(wǎng)公司企業(yè)標準(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 10,871評論 6 13
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,125評論 29 470
  • 蘇老濕講干貨,今天講的是:《孫子兵法》這么講泣特,我就會了浩姥! 做好事不留名;大家好状您,我是蘇老濕勒叠。上回我們說的是孫子傳奇...
    蘇老濕講干貨閱讀 2,060評論 2 43
  • 刮痧法:內(nèi)臟病瘀滯開鎖法 肩胸鎖:心肺病必見此處有紫黑點或瘀皰成串 膝關(guān)鎖:肝膽病膝關(guān)乃指內(nèi)外側(cè)兜挨,肝膽病日久其氣血...
    小范工作室閱讀 1,427評論 0 22