精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

ENode 2.0 第一個真實案例剖析-一個簡易論壇(Forum)

開發 前端
經過不斷的堅持和努力,ENode 2.0的第一個真實案例終于出來了。這個案例是一個簡易的論壇,開發這個論壇的初衷是為了驗證用ENode框架來開發一個真實項目的可行性。目前這個論壇在UI上是使用了最終一致性,也就是說當我們發帖或回帖后不會立馬顯示你的帖子或回復。

前言

經過不斷的堅持和努力,ENode 2.0的***個真實案例終于出來了。這個案例是一個簡易的論壇,開發這個論壇的初衷是為了驗證用ENode框架來開發一個真實項目的可行性。目前這個論壇在UI上是使用了最終一致性,也就是說當我們發帖或回帖后不會立馬顯示你的帖子或回復。當我們下一次刷新頁面時,會顯示出來。這點貌似很多人向我反饋不太習慣,接受不了,呵呵。我之所以這樣做也是想看看最終一致性大家的接受程度如何,看來UI層面上的最終一致性,大部分人接受不了。回頭我改進下效果,改為立即可以看到帖子或回復吧!另外,關于ENode是什么,本文就不多介紹了,可以參考這篇文章的介紹。本文重點介紹一下ENode是如何幫助我們開發一個基于DDD+CQRS+Event Sourcing架構的應用程序的。這個論壇使用到了ENode, EQueue兩個框架,EQueue是一個分布式的消息隊列組件,該組件的主體思想是參考阿里的RocketMQ。當我們使用EQueue時,面向的不是Queue,而是Topic。EQueue也是完全用C#實現的,關于EQueue詳細介紹,大家可以看一下這篇文章

ENode, EQueue, Forum 開源項目地址

  1. ENode開源地址:https://github.com/tangxuehua/enode
  2. EQueue開源地址:https://github.com/tangxuehua/equeue
  3. ECommon開源地址:https://github.com/tangxuehua/ecommon
  4. Forum開源地址:https://github.com/tangxuehua/forum
  5. Forum論壇線上地址(臨時域名,以后會改為enode.me):http://enode.cloudapp.net
  6. Forum論壇的equeue消息數據監控統計頁面:http://enode.cloudapp.net/equeueadmin

另外,項目中如果要開發引用程序集,可以通過Nuget來獲取,輸入關鍵字ENode就能看到所有相關的Package了,如下圖所示:

Forum總體架構分析

Forum采用DDD+CQRS+Event Sourcing的架構。借助于ENode,使得Forum本身無須再做技術架構方面的設計了,直接使用ENode就能完成這種架構。所以我們只要明白了ENode的架構,就知道這個Forum的架構是怎樣的了。以下是ENode的架構圖(已經理解了這個圖的朋友請直接跳過這一節):

上圖是一個CQRS架構的數據流向圖。UI請求會分為兩類:Command和Query。

Command用于寫數據,Query用于讀數據,寫數據和讀數據完全采用不同的架構實現。寫數據支持同步和異步的方式,讀數據完全走簡單高效思路來實現。當我們要對系統做寫操作時,如果你是用ASP.NET MVC來開發站點,那就可以在Controller中創建并發送一個Command即可。該Command會被發送到消息隊列(EQueue中),然后消息隊列的訂閱方,也就是處理Command的進程會拉取這些Command,然后調用Command Handler完成Command的處理;Command Handler處理Command時,是調用Domain的方法來完成相關的業務邏輯操作。Domain就是DDD中的領域層,負責實現整個系統的業務邏輯。 然后由于是Event Sourcing的架構,所以Domain中任何聚合根的修改都會產生相應的領域事件(Domain Event),領域事件會先被持久化到EventStore中,持久化如果沒有遇到并發沖突,成功后,則會被發布(Publish)到消息隊列(EQueue中),然后消息隊列的訂閱方,也就是處理Domain Event的進程會拉取這些Domain Event,然后調用相關的Event Handler做相關的更新,比如有些Event Handler是會更新讀庫(Read DB),有些是會產生新的Command,這種我把它叫做流程管理器(Process Manager,也有人叫做Saga)。當我們有時一個業務場景需要涉及到多個聚合根的修改時,我們會需要用到Process Manager。Process Manager負責對流程進行建模,它的原理是基于事件驅動的流程實現。Process Manager處理事件,然后產生響應的Command,從而完成聚合根之間的交互。一般一個流程,我們會設計一個流程聚合根以及其他的參與該流程的聚合根,Process Manager則是用于負責協調這些聚合根之間的交互。具體的例子可以看一下ENode源代碼中的BankTransferSample。

關于Query端,由于都是查詢,這些查詢都是用于UI展示數據或者為第三方接口提供數據為目的,查詢對系統無副作用。我們可以用我們自己任意喜歡的方式來實現Query端。查詢面向的是Read DB。上面提到,Read DB中的數據是通過Event Handler(老外叫Denormalizer)來更新的。

所以我們可以看到,整個架構中,Command端和Query端的數據源是完全分離的。Command端***的結果就是Domain Event,Domain Event是持久化在Event Store中的;Query端的數據源就是Read DB,一般可以用關系型數據庫來作為存儲。CQ兩端的數據同步通過Domain Event來實現。

上圖的CQRS架構***的好處是在架構級別以及數據存儲級別,把讀寫都分離了。這樣我們可以方便的對讀或寫單獨做優化。另外由于使用了Event Sourcing的架構,使得我們的Command端只要持久化了Domain Event,就意味著保存了這個Domain的所有狀態。這個特性,可以讓我們的框架有很多設計余地,比如不必考慮Domain Event和業務數據要強一致等問題,因為Domain Event本身就是業務數據本身了,我們通過Domain Event隨時可以還原出任意時刻的Domain的狀態。當我們要查詢Domain的當前***數據時,就走Query端即可。當然,由于Query端是異步更新的,所以Query端的數據可能會有一點點延遲。這點也就是我們平時一直講到的最終一致性(CQ兩端的數據最終會一致)。

通過上面的架構圖,我們知道,一個Command發出后會經過兩個階段的處理:1)先被某個Command Service處理(調用Domain完成業務邏輯產生Domain Event);2)再被Event Service處理(響應Domain Event,完成Read DB的更新或者產生新的Command);理解這兩個階段對理解下面的Forum的項目結構很有用處。

#p#

Forum項目結構分析

 

以上是Forum的項目工程結構,項目中包含四個宿主工程,分別是:

Forum.BrokerService:

這個工程用于宿主EQueue的Broker,整個論壇中所有的Command,Domain Event的消息,都會被放在Broker上。比如Controller發送的Command會被發送到Broker,同樣Domain產生的Domain Event也會被發送到Broker;然后消費者消費消息則都是從BrokerService拉取消息。由于該宿主工程不需要和用戶交互,所以我部署為Windows Service。

Forum.CommandService:

這個工程就是用于處理Command的進程,同樣也部署為Windows Service。

Forum.EventService:

這個工程就是用于處理Domain Event的進程,同樣也部署為Windows Service。

Forum.Web:

這個就是論壇的Web站點了,不用多講了;這個Web站點做的事情就是發送Command或者調用Query端的查詢服務查詢數據;Web站點只需要依賴于Forum.Commands和Forum.QueryServices即可,因為它只需要發送Command和查詢數據即可。

Forum.CommandHandlers:

所有的Command Handler都在這個工程,Command Handler的職責是處理Command,調用Domain的方法完成業務邏輯;

Forum.Commands:

所有的Command都在這個工程中,每個Command都是一個DTO,會被封裝為消息發送到EQueue。

Forum.Domain:

就是論壇的領域層了,所有的聚合以、工廠、領域服務,以及領域事件等都在這個工程中。這個工程是整個Forum最有價值的地方,是業務邏輯所在的工程。

Forum.Domain.Dapper:

由于Domain中可能會定義一些接口,這些接口背后的持久化需要在外部實現;如果按照經典DDD的架構,比如倉儲接口是在Domain層定義,而實現則是在基礎層(Infrastructure)中。而從經典DDD的分層架構圖上來看,Domain層是依賴于Infrastructure層的,但是Infrastructure層中又有一些倉儲的實現類要依賴于Domain層;雖然我能理解這種雙向依賴,但很容易會給不少學DDD的人帶來困惑,所以我更加傾向于,把Domain看做是架構的核心,其他一切都是Domain的外圍。這個思想其實和六邊形架構是一個思路。就是從架構上來看,不是上層依賴于下層,而是外層依賴于內層;內層通過定義出接口,外層實現接口,內層只要面向自己定義的接口即可。所以基于這個思路,我會把Forum.Domain中定義的接口,如果用Dapper來實現,那我就定義一個Forum.Domain.Dapper這樣的工程,意思是實現Forum.Domain.Dapper依賴于內層的Forum.Domain。假如以后我們有一個基于EntityFramework的實現,則只要再創建一個Forum.Domain.EntityFramework這樣的工程即可。所以可以看出,Forum.Domain.Dapper這種工程司機上是Forum.Domain對外部的適配器,Forum.Domain里定義好適配接口,Forum.Domain.Dapper這種工程實現這些適配接口。基于這種思想,我們的架構就沒有了上層依賴下層的概念了,而是替換為內外層的關系,內層不依賴外層,外層依賴于內層,內層與外層直接通過適配器接口來交互,或者通過Domain Event也可以。這樣我們就不用再去糾結經典DDD中看似雙向依賴的問題了。

Forum.Domain.Tests:

這個工程就是對Forum.Domain的一個測試工程。每個測試用例會模擬Controller發起Command,然后***檢查Domain中的狀態是否正確修改。

Forum.QueryServices:

這個工程定義了Query端的所有查詢接口,Forum.Web站點依賴于這個工程中的查詢服務接口;然后這些查詢接口的實現則是放在Forum.QueryServices.Dapper中。Forum.QueryServices與Forum.QueryServices.Dapper之間的關系和Forum.Domain與Forum.Domain.Dapper之間的關系類似,這里就不在重復了。

Forum.Denormalizers.Dapper:

這個工程中的就是所有的Denormalizer,Denormalizer就是負責處理Domain Event,然后更新讀庫。然后由于目前使用Dapper實現數據持久化,所以工程名以Dapper結尾。

Forum.Infrastructure:

這是一個基礎工程,存放所有基礎的公共的東西,比如一些業務無關的服務或配置信息或全局變量等東西;需要強調的是:這里的Forum.Infrastructure和經典DDD中的Infrastructure不是同一個概念。DDD中的Infrastructure是一個邏輯上的分層,領域層中所有的技術支撐實現都在Infrastructure中;而這里的Infrastructure,則僅僅只是一些Common的基礎的公用的東西,Infrastructure不是為了為其它哪一層服務的,它可以被其他任何項目使用;

好了,以上簡單介紹了每個工程的作用和設計目的。下面我們來看看Forum的領域模型的設計吧!

Forum的Domain Model的設計

  • 核心功能需求分析:
    1. 提供用戶注冊、登錄、注銷三個功能;注冊用戶時需要驗證用戶名是否唯一;
    2. 提供發帖、回帖、修改帖子、修改回復,以及回復的回復這些基本核心功能;
    3. 系統管理員可以對論壇版塊進行維護;
  • 聚合識別:識別出來的聚合有:論壇賬號、帖子、回復、版塊這四個。
  • 再分析下每個聚合我們所關心的信息:賬號的最少信息應該有:賬號名稱+密碼;版塊要有名稱即可;帖子要有標題、內容、發帖人、發帖時間、所屬版塊;回復要有回復內容、回復時間、回復人、所屬版塊,父回復(可以為空);
  • 場景走查:注冊就是創建賬號(賬號唯一性的設計后面在詳細分析);登錄本質就是調用Query端的查詢服務查找賬號是否存在,所以不需要Domain做什么處理,注銷也是;發帖就是創建帖子;回帖就是創建回復;修改帖子就是對帖子聚合根做修改;修改回復就是對回復聚合根做修改;版塊添加就是創建一個版塊聚合根;
  • 關鍵業務規則識別:1)賬號名稱不能重復;2)帖子必須要有所屬版塊和發帖人;3)回復必須要有一個對應的帖子和回復人;
  • 關鍵業務規則的實現:
    1. 如何實現賬號名稱不能重復?首先它是一條業務規則,所以必須在Domain里實現,而不應該在Command Handler里。然后由于Event Sourcing的架構,天生有一個缺陷就是無法實現唯一性約束這種需求。所以我們需要在Domain中顯式設計出可以表達聚合根索引的東西,我把它們叫做IndexStore,表示是一種聚合根索引的存儲。這個思路非常類似于在經典DDD中,我們有倉儲(Repository)的概念,倉儲維護了所有的聚合根;而我這里的IndexStore則是維護了聚合根的索引信息。有了這個索引信息后,我們就能在注冊新賬號時,在Domain中設計一個RegisterAccountService這樣的領域服務,領域服務里通過AccountIndexStore來檢查賬號名稱是否重復,如果不重復,則將當前賬號名稱添加到AccountIndexStore中,如果重復,則報異常。另外一個非業務的點需要考慮,那就是如何實現并發注冊用戶的處理。我們可以在Command Handler中實現db級別的鎖(但不不需要鎖整個賬號表,而是鎖一個其他表中的某一條記錄),確保同一時刻,不會有兩個Account名稱添加到AccountIndexStore中;我們通過RegisterAccountService把“賬號名稱不能重復”的這個業務規則顯式的表達出來,從而在代碼級別體現領域內實現了這個業務規則。以前,如果沒有用Event Sourcing,我們可能會依賴db的唯一索引來實現這個唯一性,雖然功能上也可以實現,但實際上賬號名稱不能重復的這個業務規則沒有體現在領域內。這點也是我這次通過實現基于Event Sourcing而實現的唯一性驗證而想到的點。
    2. 帖子必須要有所屬版塊和發帖人,這條業務規則很容易保證,只要在帖子聚合根上,對版塊和發帖子判斷是否為空就行了;
    3. 回復必須要有一個對應的帖子和回復人,也是同理,只要在構造函數中判斷是否為空即可;

#p#

以注冊新用戶為例,展示代碼實現

客戶端JS通過angularJS提交注冊信息:

  1. $scope.submit = function () {  
  2.         if (isStringEmpty($scope.newAccount.accountName)) {  
  3.             $scope.errorMsg = '請輸入賬號。';  
  4.             return false;  
  5.         }  
  6.         if (isStringEmpty($scope.newAccount.password)) {  
  7.             $scope.errorMsg = '請輸入密碼。';  
  8.             return false;  
  9.         }  
  10.         if (isStringEmpty($scope.newAccount.confirmPassword)) {  
  11.             $scope.errorMsg = '請輸入密碼確認。';  
  12.             return false;  
  13.         }  
  14.         if ($scope.newAccount.password != $scope.newAccount.confirmPassword) {  
  15.             $scope.errorMsg = '密碼輸入不一致。';  
  16.             return false;  
  17.         }  
  18.  
  19.         $http({  
  20.             method: 'POST',  
  21.             url: '/account/register',  
  22.             data: $scope.newAccount  
  23.         })  
  24.         .success(function (result, status, headers, config) {  
  25.             if (result.success) {  
  26.                 $window.location.href = '/home/index';  
  27.             } else {  
  28.                 $scope.errorMsg = result.errorMsg;  
  29.             }  
  30.         })  
  31.         .error(function (result, status, headers, config) {  
  32.             $scope.errorMsg = result.errorMsg;  
  33.         });  
  34.     }; 

Controller處理請求:

  1. [HttpPost]  
  2. [AjaxValidateAntiForgeryToken]  
  3. [AsyncTimeout(5000)]  
  4. public async Task<ActionResult> Register(RegisterModel model, CancellationToken token)  
  5. {  
  6.     var command = new RegisterNewAccountCommand(model.AccountName, model.Password);  
  7.     var result = await _commandService.Execute(command, CommandReturnType.EventHandled);  
  8.  
  9.     if (result.Status == CommandStatus.Failed)  
  10.     {  
  11.         if (result.ExceptionTypeName == typeof(DuplicateAccountException).Name)  
  12.         {  
  13.             return Json(new { success = false, errorMsg = "該賬號已被注冊,請用其他賬號注冊。" });  
  14.         }  
  15.         return Json(new { success = false, errorMsg = result.ErrorMessage });  
  16.     }  
  17.  
  18.     _authenticationService.SignIn(result.AggregateRootId, model.AccountName, false);  
  19.     return Json(new { success = true });  

CommandHandler處理Command:

  1. [Component(LifeStyle.Singleton)]  
  2. public class AccountCommandHandler : ICommandHandler<RegisterNewAccountCommand>  
  3. {  
  4.     private readonly ILockService _lockService;  
  5.     private readonly RegisterAccountService _registerAccountService;  
  6.  
  7.     public AccountCommandHandler(ILockService lockService, RegisterAccountService registerAccountService)  
  8.     {  
  9.         _lockService = lockService;  
  10.         _registerAccountService = registerAccountService;  
  11.     }  
  12.  
  13.     public void Handle(ICommandContext context, RegisterNewAccountCommand command)  
  14.     {  
  15.         _lockService.ExecuteInLock(typeof(Account).Name, () =>  
  16.         {  
  17.             context.Add(_registerAccountService.RegisterNewAccount(command.Id, command.Name, command.Password));  
  18.         });  
  19.     }  

RegisterAccountService領域服務:

  1. /// <summary>提供賬號注冊的領域服務,封裝賬號注冊的業務規則,比如賬號唯一性檢查  
  2.     /// </summary>  
  3.     [Component(LifeStyle.Singleton)]  
  4.     public class RegisterAccountService  
  5.     {  
  6.         private readonly IIdentityGenerator _identityGenerator;  
  7.         private readonly IAccountIndexStore _accountIndexStore;  
  8.         private readonly AggregateRootFactory _factory;  
  9.  
  10.         public RegisterAccountService(IIdentityGenerator identityGenerator, AggregateRootFactory factory, IAccountIndexStore accountIndexStore)  
  11.         {  
  12.             _identityGenerator = identityGenerator;  
  13.             _factory = factory;  
  14.             _accountIndexStore = accountIndexStore;  
  15.         }  
  16.  
  17.         /// <summary>注冊新賬號  
  18.         /// </summary>  
  19.         /// <param name="accountIndexId"></param>  
  20.         /// <param name="accountName"></param>  
  21.         /// <param name="accountPassword"></param>  
  22.         /// <returns></returns>  
  23.         public Account RegisterNewAccount(string accountIndexId, string accountName, string accountPassword)  
  24.         {  
  25.             //首先創建一個新賬號  
  26.             var account = _factory.CreateAccount(accountName, accountPassword);  
  27.  
  28.             //先判斷該賬號是否存在  
  29.             var accountIndex = _accountIndexStore.FindByAccountName(account.Name);  
  30.             if (accountIndex == null)  
  31.             {  
  32.                 //如果不存在,則添加到賬號索引  
  33.                 _accountIndexStore.Add(new AccountIndex(accountIndexId, account.Id, account.Name));  
  34.             }  
  35.             else if (accountIndex.IndexId != accountIndexId)  
  36.             {  
  37.                 //如果存在但和當前的索引ID不同,則認為是賬號有重復  
  38.                 throw new DuplicateAccountException(accountName);  
  39.             }  
  40.  
  41.             return account;  
  42.         }  
  43.     } 

EventHandler處理Domain Event:

  1. [Component(LifeStyle.Singleton)]  
  2. public class AccountEventHandler : BaseEventHandler, IEventHandler<NewAccountRegisteredEvent>  
  3. {  
  4.     public void Handle(IEventContext context, NewAccountRegisteredEvent evnt)  
  5.     {  
  6.         using (var connection = GetConnection())  
  7.         {  
  8.             connection.Insert(  
  9.                 new 
  10.                 {  
  11.                     Id = evnt.AggregateRootId,  
  12.                     Name = evnt.Name,  
  13.                     Password = evnt.Password,  
  14.                     CreatedOn = evnt.Timestamp,  
  15.                     UpdatedOn = evnt.Timestamp,  
  16.                     Version = evnt.Version  
  17.                 }, Constants.AccountTable);  
  18.         }  
  19.     }  

結束語

好了,大概就這些吧。好久沒寫文章了,都不知道該怎么寫了,呵呵。接下來準備再好好分享下ENode,EQueue最近幾個月在不斷完善中我遇到的一些技術問題。對了,大家可以去體驗下這個論壇的功能哦,雖然很簡單,但基本的功能還是有的。http://enode.cloudapp.net/

責任編輯:林師授 來源: netfocus的博客
相關推薦

2013-07-08 10:40:02

2009-05-06 19:04:32

LinuxMoonlight 2預覽版

2020-11-13 07:08:51

Spring Boot應用Spring

2016-08-24 15:12:41

LXDLinux容器

2021-04-07 13:38:27

Django項目視圖

2023-09-21 22:43:17

Django框架

2011-03-21 14:24:13

Debian 6

2013-01-14 09:44:58

JavaScriptJSJS框架

2010-07-30 14:58:06

Flex應用

2011-03-03 21:04:08

bug程序員

2012-02-08 11:15:38

HibernateJava

2009-09-22 10:00:08

曙光BBSBBS站

2022-10-17 10:28:05

Web 組件代碼

2010-08-04 13:16:23

Flex項目

2009-10-23 09:21:08

2013-10-30 22:10:28

Clouda程序

2023-05-19 08:49:58

SQLAlchemy數據庫

2009-06-26 16:07:43

MyEclipse開發Hibernate程序

2012-05-25 15:20:38

XNA

2018-08-22 17:32:45

點贊
收藏

51CTO技術棧公眾號

污视频在线免费观看一区二区三区| 成人免费电影网址| 国产欧美日韩在线观看| 国产精品免费一区| 久久中文免费视频| 亚洲精品一区在线| 欧美午夜激情在线| 亚洲精品在线免费| 亚洲国产福利视频| 久久精品麻豆| 色综合久久久888| 在线免费观看麻豆| 精品视频成人| 91成人网在线| 草草草视频在线观看| 久香视频在线观看| 韩国女主播成人在线| 69精品小视频| 日韩激情小视频| 中文字幕精品影院| 日韩午夜激情视频| 成年人小视频网站| а√天堂中文在线资源8| 久久精品一区二区三区四区| 国产精品中文字幕在线观看| 国产一级做a爱片久久毛片a| 亚洲精品2区| 亚洲精品在线91| 香蕉视频1024| 99精品女人在线观看免费视频| 亚欧色一区w666天堂| 中文字幕久精品免| 国产黄色在线播放| 91网站黄www| 亚洲一区二区三| 国产成人精品亚洲| 国产日韩高清一区二区三区在线| 久久福利视频网| 中字幕一区二区三区乱码| 精品福利一区| 精品成人私密视频| 日本美女久久久| 激情亚洲小说| 91国在线观看| 女人天堂av手机在线| 亚洲妇熟xxxx妇色黄| 中文字幕中文字幕中文字幕亚洲无线 | 欧美日韩免费观看中文| 69精品丰满人妻无码视频a片| 男人天堂久久久| 国产精品私人影院| 欧美一区亚洲二区| 国产在线视频网址| 久久久噜噜噜久噜久久综合| 精品一区二区三区免费毛片| 欧美性受xxxx狂喷水| 国产激情一区二区三区| 成人亚洲激情网| 国产又黄又大又粗的视频| 男人的天堂亚洲一区| 国产精品国产福利国产秒拍| 波多野结衣啪啪| 久久亚洲精选| 国产精品久久久久久久av电影| www.国产毛片| 免费观看在线色综合| 国产精品久久久久91| 国产男人搡女人免费视频| 三级在线观看一区二区| 国产91色在线|免| 亚洲男人天堂网址| 日韩精品一级中文字幕精品视频免费观看| 日本韩国在线不卡| 波多野结衣小视频| 蜜桃在线一区二区三区| 成人av.网址在线网站| 国产乱码久久久久| 国产99久久久国产精品潘金| 精品一区二区免费| 精品国产九九九| 精品国产日韩欧美| 亚洲欧美日韩久久久久久| 亚洲区免费视频| 日韩精品第一区| 久久成人这里只有精品| 久久精品久久国产| 亚洲欧美日韩综合国产aⅴ| 欧洲亚洲免费在线| 成人黄色片在线观看| 韩国av一区二区三区四区| 不卡一区二区三区视频| 水莓100国产免费av在线播放| 国产午夜精品久久久久久免费视| 性刺激综合网| 美女91在线| 一本大道久久a久久综合婷婷| xx欧美撒尿嘘撒尿xx| 欧美高清hd| 亚洲欧美日韩网| 免费三级在线观看| 亚洲精选成人| 国产精品视频区| 欧美 日韩 国产 成人 在线| 久久精品视频在线免费观看| 久久av秘一区二区三区| 国产夫妻在线播放| 欧美日本视频在线| 2一3sex性hd| 97精品国产一区二区三区| 欧美激情精品久久久久久黑人| 日韩综合在线观看| 国产精品一二一区| 欧美一区二区三区在线播放| 色呦呦呦在线观看| 91国偷自产一区二区三区成为亚洲经典| 一区二区三区四区毛片| 全球av集中精品导航福利| 精品久久久av| 手机av免费观看| 岛国精品在线观看| 日本一区二区免费高清视频| 日韩伦理在线| 欧美成人猛片aaaaaaa| xxxxx99| 99精品国产一区二区青青牛奶| 国产区亚洲区欧美区| 欧美在线一卡| 亚洲一卡二卡三卡四卡五卡| 91小视频在线播放| 激情五月色综合国产精品| 亚洲2020天天堂在线观看| 国产无遮挡又黄又爽又色视频| 成人一级视频在线观看| 91xxx视频| japanese23hdxxxx日韩| 日韩国产一区三区| 国产精品第九页| 国产精品一区在线观看你懂的| 亚洲一区二区三区加勒比| 伊人久久综合一区二区| 亚洲国产精品推荐| 我家有个日本女人| 精品一区二区日韩| 制服国产精品| 麻豆久久久久| 在线不卡国产精品| 狠狠狠狠狠狠狠| 久久精品视频一区二区三区| 免费无码av片在线观看| 欧美天堂社区| 欧美一级高清免费播放| 亚州av在线播放| 精品日本高清在线播放| 在线观看国产免费视频| 最新日韩av| 精品乱码一区二区三区| 高清在线视频不卡| 精品亚洲男同gayvideo网站| 日本一区二区免费电影| 久久久久久一级片| www.日本xxxx| 欧美mv日韩| 成人黄色av播放免费| 麻豆传媒在线免费看| 在线电影院国产精品| 日本裸体美女视频| 国产一区二区h| 麻豆视频传媒入口| 7m精品国产导航在线| 久久久久久有精品国产| 少妇av在线播放| 欧美性xxxx在线播放| 国产高清一区二区三区四区| 青青草97国产精品免费观看无弹窗版 | 国产精品久久久免费视频| 99视频精品免费视频| www黄色在线| 婷婷另类小说| 国产精品国产三级国产专区53| 三妻四妾的电影电视剧在线观看| 亚洲欧美日韩精品久久| 亚洲一区在线观| 洋洋av久久久久久久一区| 麻豆精品国产传媒av| 久久一二三区| 亚洲天堂av免费在线观看| 成人搞黄视频| 国产精品第二页| a黄色片在线观看| 亚洲成人激情在线| 午夜一区二区三区四区| 亚洲欧美日韩国产另类专区| 韩国三级hd两男一女| 日韩精品亚洲专区| 特级西西444| 免费看成人吃奶视频在线| 成人免费视频97| 天堂资源在线| 久久成人这里只有精品| 精品推荐蜜桃传媒| 欧美一区二区私人影院日本| 国语对白永久免费| 亚洲免费看黄网站| 素人fc2av清纯18岁| 极品尤物av久久免费看| 国产精品自拍片| 午夜影院欧美| 日本一区二区在线视频| 亚洲va欧美va人人爽成人影院| 日本欧美爱爱爱| 欧美14一18处毛片| 日韩中文字幕在线视频| 天堂av在线资源| 91精品国产黑色紧身裤美女| 无码人妻av免费一区二区三区 | 久久亚洲综合色一区二区三区| 久久久久久久高清| 老司机亚洲精品| 黄色一级片在线看| 亚洲精品久久| 亚洲视频电影| 韩日一区二区三区| 久久久久久久久久久久久久一区 | 亚洲国产精久久久久久久| 中文在线观看免费高清| 欧美日韩中文字幕综合视频| 欧美人妻精品一区二区三区 | 久久草视频在线| 亚洲免费在线视频一区 二区| 欧美另类z0zx974| 91麻豆精品一区二区三区| 韩国三级在线看| 国产精品自产自拍| 久久黄色片网站| 日本欧美加勒比视频| 青青在线视频观看| 亚洲综合丁香| 波多野结衣家庭教师在线播放| 欧美另类亚洲| 久久亚洲国产成人精品无码区| 999精品一区| 中文字幕日韩精品一区二区| 久久国产电影| 亚洲精品在线免费| 色一区二区三区四区| 先锋影音亚洲资源| 日韩在线观看电影完整版高清免费悬疑悬疑| 乱一区二区三区在线播放| 欧美成人午夜77777| 国内精品视频免费| 免费成人蒂法| 精品午夜一区二区三区| 美女呻吟一区| 欧美日本国产精品| 免费国产自久久久久三四区久久| 久久久免费看| 精品久久久久久久久久久下田| 秋霞在线观看一区二区三区| 久久综合影院| 亚洲午夜激情| 亚洲视频电影在线| 日韩中文字幕亚洲精品欧美| 亚洲高清不卡| 国产亚洲精品网站| 首页综合国产亚洲丝袜| 五月天亚洲视频| 久久国产夜色精品鲁鲁99| 国产三级生活片| 国产精品99久久久久久有的能看 | 中国女人真人一级毛片| 欧美日韩国产欧美日美国产精品| 国产一区二区女内射| 欧美一区二区免费| 男人天堂综合网| 亚洲天堂成人在线| 日本暖暖在线视频| 欧美激情a在线| 美女100%一区| 91嫩草在线视频| 成人激情自拍| 日本精品一区二区| 围产精品久久久久久久| 精品丰满人妻无套内射| 老司机精品视频网站| theporn国产精品| 成+人+亚洲+综合天堂| 亚洲精品国产一区黑色丝袜| 一区在线中文字幕| 国产无套粉嫩白浆内谢| 在线看一区二区| a网站在线观看| 精品视频在线播放| 自拍视频在线| 久久久久久久国产精品视频| 欧美不卡高清一区二区三区| 亚洲自拍另类欧美丝袜| 亚州国产精品| 日韩精品一区二区三区电影| 在线一区免费观看| 欧美国产日韩另类| 26uuu精品一区二区在线观看| 国产免费嫩草影院| 五月天激情小说综合| 中文字幕资源网| 亚洲国产三级网| 97影院秋霞午夜在线观看| 欧美一区二区三区…… | 午夜宅男久久久| 91网址在线观看精品| 2023国产一二三区日本精品2022| 日本妇女毛茸茸| 欧美在线综合视频| 凸凹人妻人人澡人人添| 久久福利视频导航| 日韩精品第二页| 乱一区二区三区在线播放| 狠狠入ady亚洲精品| 一级淫片在线观看| 欧美国产一区在线| 69国产精品视频免费观看| 日韩三级在线免费观看| 日本在线观看| 国产精品女主播| 久久99国产成人小视频| 欧美成人高潮一二区在线看| 国产精品一区在线观看你懂的| 欧美福利在线视频| 91久久精品一区二区三| 亚州av在线播放| 91精品国产91久久久久久| 哺乳一区二区三区中文视频 | 欧美家庭影院| 91高跟黑色丝袜呻吟在线观看| 99re久久最新地址获取| 国产精品久久a| 国产精品视频在线看| 中文字幕av第一页| 国产小视频国产精品| 麻豆精品蜜桃| 色姑娘综合网| 日本不卡一二三区黄网| 免费看裸体网站| 欧美亚洲一区三区| av网站在线免费观看| 国产精品一区专区欧美日韩| 九九久久婷婷| 日韩在线第三页| 国产欧美日韩在线视频| 波多野结衣在线观看一区| 亚洲人成在线免费观看| 欧美18—19sex性hd| 免费精品视频一区| 国产精品外国| 中文字幕高清视频| 亚欧色一区w666天堂| 蜜桃成人在线视频| 欧日韩在线观看| 青青草91久久久久久久久| 激情综合网俺也去| 中文一区二区在线观看| 中文字幕日韩三级| 在线观看亚洲区| avtt久久| 男人的天堂视频在线| 成人教育av在线| 久久久久久久99| 亚洲欧美在线一区二区| 欧美色网在线| 日本午夜精品一区二区| 免费人成在线不卡| 亚洲天堂av中文字幕| 欧美一区二区在线不卡| 影院在线观看全集免费观看| 国产一区二区三区色淫影院| 亚洲伦伦在线| 九九九视频在线观看| 欧美色精品在线视频| 国产爆初菊在线观看免费视频网站| 国产日韩精品在线| 欧美91大片| 亚洲av成人片色在线观看高潮| 精品国产户外野外| 在线日本中文字幕| 国产日韩精品视频| 国产综合自拍| xxxx日本黄色| 精品国产一区二区国模嫣然| 都市激情国产精品| 一区二区三区我不卡| 国产美女精品在线| 久久久久久久久精| 亚洲精品视频二区| 欧美性理论片在线观看片免费| 无码毛片aaa在线| www.日韩大片| 国产精品国产三级国产普通话对白| 欧美疯狂性受xxxxx另类| 欧美精品一区二区久久| www.亚洲自拍| 色欧美片视频在线观看 |