成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

jBPM 3.2用戶指南 Hello World范例

開發 后端
本文節選自jBPM 3.2用戶指南的第三章。本節jBPM用戶指南提供了jBPM范例Hello World:一個數據庫范例,一個流程變量的context范例,一個任務分配范例,以及兩個定制action范例。

本教程向你展示用jpdl構造的簡單流程和使用API管理流程運行時執行的過程。

本教程的形式是解釋一批范例。這些范例著眼于一個特定的主題并包含大量的注解。這些范例也能夠在jBPM下載軟件包的src/java.examples目錄中找到。

最好的學習方式是創建一個項目,并通過創建下面的范例的變體來體驗它。

在開始之前,首先下載和安裝jBPM。

jBPM包含一個圖形設計器工具,可用于創建在這些范例中顯示的xml文件。你可以在《下載和安裝jBPM》部分找到下載這個圖形設計器的指南。你不需要為了完成本教程而使用這個圖形設計工具。

Hello World范例

流程定義是一個有向圖,由節點(node)和轉移(transition)組成。Hello world流程有三個節點。為了看到這些代碼片段如何組合在一起,我們從一個簡單的流程開始,不使用圖形設計工具。下面的圖顯示hello world流程的圖形表示:

圖 3.1. Hello world流程圖

Hello world流程圖

  1. public void testHelloWorldProcess() {  
  2. // 本方法顯示一個流程定義和此流程定義的執行。這個流程定義有三個節點:一個未命名的  
  3. // start狀態,一個狀態s和一個名為end的結束狀態。  
  4. // 下面一行將一段xml文本解析為一個流程定義ProcessDefinition。流程定義是對流程  
  5. // 的正式描述,表示為一個Java對象。  
  6. ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(  
  7.     "<process-definition>" +  
  8.     "  <start-state>" +  
  9.     "    <transition to='s' />" +  
  10.     "  </start-state>" +  
  11.     "  <state name='s'>" +  
  12.     "    <transition to='end' />" +  
  13.     "  </state>" +  
  14.     "  <end-state name='end' />" +  
  15.     "</process-definition>" 
  16. );  
  17.  
  18.   // 下面一行代碼創建流程定義的一個執行。流程執行創建之后將擁有一個主執行  
  19.   // 路徑(=根token),指向開始狀態節點。  
  20.   ProcessInstance processInstance = new ProcessInstance(processDefinition);  
  21.  
  22.   // 流程執行創建之后,擁有一個主執行路徑(=根token)。  
  23.   Token token = processInstance.getRootToken();  
  24.  
  25.   // 流程執行創建之后,主執行路徑指向流程定義的開始狀態節點。  
  26.   assertSame(processDefinition.getStartState(), token.getNode());  
  27.  
  28.   // 下面我們啟動流程執行,從缺省轉移路線離開開始狀態節點。  
  29.   token.signal();  
  30.   // signal方法將阻塞,直至流程執行進入一個等待狀態。  
  31.   // 流程執行進入了第一個等待狀態:狀態s。所以主執行路徑現在指向狀態s。  
  32.   assertSame(processDefinition.getNode("s"), token.getNode());  
  33.  
  34.   // 下面我們發送第二個信號。這將恢復流程執行,通過缺省的轉移路徑離開狀態s。  
  35.   token.signal();  
  36.  
  37.   // 現在signal方法返回了,因為流程實例到達了結束狀態節點。  
  38.     assertSame(processDefinition.getNode("end"), token.getNode());  

數據庫范例

jBPM的一個基本特征是把處于等待狀態中的流程執行持久化到數據庫中的能力。下面的范例將向你展示如何將一個流程實例保存到jBPM數據庫中。本范例也暗示存在一個流程執行的上下文。下面各個方法在不同的用戶代碼片段中創建,例如,在web應用程序中的一段用戶代碼發起一個流程執行并將它持久化到數據庫中,隨后,一個消息驅動bean從數據庫中裝載這個流程實例并恢復其執行。

  1. public class HelloWorldDbTest extends TestCase {  
  2.  
  3.   static JbpmConfiguration jbpmConfiguration = null;   
  4.  
  5.   static {  
  6.     // 像此處的范例配置文件能夠在'src/config.files'中找到。典型地配置信息存在  
  7.    // 于資源文件'jbpm.cfg.xml'中,但在這里我們直接傳遞一個XML字符串形式的配置信息。  
  8.  
  9.     // 首先我們創建一個JbpmConfiguration靜態對象。系統中的所有線程可以使用  
  10.     // 同一個JbpmConfiguration,因此我們可以安全地把它設定為靜態的。  
  11.     jbpmConfiguration = JbpmConfiguration.parseXmlString(  
  12.       "<jbpm-configuration>" +  
  13.  
  14.       // jbpm-context機制能夠從jbmp使用的環境服務中分離出jbpm核心引擎。  
  15.  
  16.       "  <jbpm-context>" +  
  17.       "    <service name='persistence' " +  
  18.       "             factory='org.jbpm.persistence.db.DbPersistenceServiceFactory' />" +   
  19.       "  </jbpm-context>" +  
  20.  
  21.       // 同樣地,jbpm使用的所有資源文件可以從jbpm.cfg.xml中引用。  
  22.  
  23.       "  <string name='resource.hibernate.cfg.xml' " +  
  24.       "          value='hibernate.cfg.xml' />" +  
  25.       "  <string name='resource.business.calendar' " +  
  26.       "          value='org/jbpm/calendar/jbpm.business.calendar.properties' />" +  
  27.       "  <string name='resource.default.modules' " +  
  28.       "          value='org/jbpm/graph/def/jbpm.default.modules.properties' />" +  
  29.       "  <string name='resource.converter' " +  
  30.       "          value='org/jbpm/db/hibernate/jbpm.converter.properties' />" +  
  31.       "  <string name='resource.action.types' " +  
  32.       "          value='org/jbpm/graph/action/action.types.xml' />" +  
  33.       "  <string name='resource.node.types' " +  
  34.       "          value='org/jbpm/graph/node/node.types.xml' />" +  
  35.       "  <string name='resource.varmapping' " +  
  36.       "          value='org/jbpm/context/exe/jbpm.varmapping.xml' />" +  
  37.       "</jbpm-configuration>" 
  38.     );  
  39.   }  
  40.  
  41.   public void setUp() {  
  42.     jbpmConfiguration.createSchema();  
  43.   }  
  44.  
  45.   public void tearDown() {  
  46.     jbpmConfiguration.dropSchema();  
  47.   }  
  48.  
  49.   public void testSimplePersistence() {  
  50.     // 在以下的三個方法調用之間,所有的數據通過數據庫傳遞。在這個單元測試中,  
  51.     // 這三個方法是順序執行的,因為我們要測試一個完整的流程場景。但是在現實  
  52.     //中,這些方法代表對服務器的不同請求。  
  53.  
  54.     // 因為我們從一個干凈的、空的內存數據庫中啟動,必須首先部署流程。現實中,  
  55.     // 流程部署是由流程開發者一次性完成的。  
  56.     deployProcessDefinition();  
  57.  
  58.     // 假設當用戶在web應用程序中提交一個form的時候,我們要啟動一個流程實例……  
  59.     processInstanceIsCreatedWhenUserSubmitsWebappForm();  
  60.  
  61.     // 隨后,當異步消息到達之后,將繼續執行流程。  
  62.     theProcessInstanceContinuesWhenAnAsyncMessageIsReceived();  
  63.   }  
  64.  
  65.   public void deployProcessDefinition() {  
  66.     // 本測試展示一個流程定義和該流程定義的一個執行實例。這個流程定義有  
  67.     // 三個節點:一個未命名的開始狀態,一個狀態s和一個名為end的結束狀態。  
  68.     ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(  
  69.       "<process-definition name='hello world'>" +  
  70.       "  <start-state name='start'>" +  
  71.       "    <transition to='s' />" +  
  72.       "  </start-state>" +  
  73.       "  <state name='s'>" +  
  74.       "    <transition to='end' />" +  
  75.       "  </state>" +  
  76.       "  <end-state name='end' />" +  
  77.       "</process-definition>" 
  78.     );  
  79.  
  80.     // 查找在上面的過程中已配置好的POJO持久化上下文生成器。  
  81.     JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();  
  82.     try {  
  83.       // 將流程定義部署到數據庫。  
  84.       jbpmContext.deployProcessDefinition(processDefinition);  
  85.  
  86.     } finally {  
  87.       // 銷毀POJO持久化上下文。  
  88.      // 這包括刷新SQL,將流程定義插入到數據庫中。  
  89.       jbpmContext.close();  
  90.     }  
  91.   }  
  92.  
  93.   public void processInstanceIsCreatedWhenUserSubmitsWebappForm() {  
  94.     // 本方法中的代碼應存在于一個struts的action 或JSF托管的bean中。  
  95.  
  96.     //  查找在上面的過程中已配置好的POJO持久化上下文生成器。  
  97.     JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();  
  98.     try {  
  99.  
  100.       GraphSession graphSession = jbpmContext.getGraphSession();  
  101.  
  102.       ProcessDefinition processDefinition =   
  103.           graphSession.findLatestProcessDefinition("hello world");  
  104.  
  105.       // 從數據庫中取得流程定義之后,我們可以創建該流程定義的一個執行實例,  
  106.       // 就像Hello world范例中一樣(后者沒有使用持久化)。  
  107.       ProcessInstance processInstance =   
  108.           new ProcessInstance(processDefinition);  
  109.  
  110.       Token token = processInstance.getRootToken();   
  111.       assertEquals("start", token.getNode().getName());  
  112.       // 下面啟動流程執行  
  113.       token.signal();  
  114.       // 現在流程處于狀態s。  
  115.       assertEquals("s", token.getNode().getName());  
  116.  
  117.       // 現在流程實例被保存到數據庫中,所以流程執行的當前狀態被保存到數據庫中了。  
  118.       jbpmContext.save(processInstance);  
  119.       // 下面的方法將從數據庫中取回流程實例,通過提供另一個外部信號恢復流程的執行。  
  120.  
  121.     } finally {  
  122.       // 銷毀POJO持久化上下文。  
  123.       jbpmContext.close();  
  124.     }  
  125.   }  
  126.  
  127.   public void theProcessInstanceContinuesWhenAnAsyncMessageIsReceived() {  
  128.     // 本方法中的代碼可以是一個消息驅動bean的內容。  
  129.     //查找在上面的代碼中已經配置好的POJO持久化上下文生成器  
  130.     JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();  
  131.     try {  
  132.  
  133.       GraphSession graphSession = jbpmContext.getGraphSession();  
  134.       // 首先,我們需要從數據庫中取回流程實例。為了知道哪個流程實例是我們這里要使用的,  
  135.       // 有幾個可選方法。在這個簡單的測試案例中,最容易的方式是在整個流程實例列表中查  
  136.       // 找,這將僅僅返回一個結果。所以,讓我們獲取這個流程定義。  
  137.  
  138.       ProcessDefinition processDefinition =   
  139.           graphSession.findLatestProcessDefinition("hello world");  
  140.  
  141.       // 現在,我們查找這個流程定義中的所有流程實例。  
  142.       List processInstances =   
  143.           graphSession.findProcessInstances(processDefinition.getId());  
  144.  
  145.       // 因為我們知道,在這個單元測試測環境中只存在一個執行實例。在現實中,  
  146.       // processInstanceId要從到達的消息內容中提取,或來自用戶的選擇。  
  147.       ProcessInstance processInstance =   
  148.           (ProcessInstance) processInstances.get(0);  
  149.  
  150.       // 現在我們可以繼續流程執行了。記住流程實例將信號轉發給主執行路徑(=根token)。  
  151.       processInstance.signal();  
  152.  
  153.       // 發出信號之后,我們知道流程執行到達了結束狀態。  
  154.       assertTrue(processInstance.hasEnded());  
  155.  
  156.       // 現在我們可以將流程執行的狀態更新到數據庫中  
  157.       jbpmContext.save(processInstance);  
  158.  
  159.     } finally {  
  160.       // 銷毀POJO持久化上下文。  
  161.       jbpmContext.close();  
  162.     }  
  163.   }  

#p#

上下文(context)范例:流程變量

流程變量包含流程執行過程中的上下文信息。流程變量類似于java.util.Map,將變量名映射到值,值是java對象。流程變量作為流程實例的一部分被持久化。為了保持簡單,在此范例中我們僅僅展示與流程變量有關的API,不考慮持久化。

  1. // 這個范例同樣從Hello world流程開始。  
  2. // 這次甚至沒有修改。  
  3. ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(  
  4.   "<process-definition>" +  
  5.   "  <start-state>" +  
  6.   "    <transition to='s' />" +  
  7.   "  </start-state>" +  
  8.   "  <state name='s'>" +  
  9.   "    <transition to='end' />" +  
  10.   "  </state>" +  
  11.   "  <end-state name='end' />" +  
  12.   "</process-definition>" 
  13. );  
  14.  
  15. ProcessInstance processInstance =  
  16.   new ProcessInstance(processDefinition);  
  17.  
  18. // 從流程實例中取得上下文實例,以處理流程變量。  
  19. ContextInstance contextInstance =   
  20.   processInstance.getContextInstance();  
  21.  
  22. // 在流程離開開始狀態之前,我們準備在流程實例的上下文中設置一些流程變量。  
  23. contextInstance.setVariable("amount"new Integer(500));  
  24. contextInstance.setVariable("reason""i met my deadline");  
  25.  
  26. // 從現在開始,這些變量關聯到這個流程實例了。現在這些變量可以通過用戶代碼  
  27. // 使用在這里顯示的API來訪問了,但是,也可以在action和節點實現中訪問。流  
  28. // 程變量作為流程實例的一部分,也被存儲到數據庫中。  
  29.  
  30. processInstance.signal();  
  31.  
  32. // 流程變量可以通過contextInstance訪問。  
  33.  
  34. assertEquals(new Integer(500),   
  35.              contextInstance.getVariable("amount"));  
  36. assertEquals("i met my deadline",   
  37.              contextInstance.getVariable("reason")); 

任務分配范例

在下面的例子中我們展示如何將任務分配給用戶。因為jBPM工作流引擎和組織機構模型的分離,一個用于計算參與者(actor)的表達式語言總是太受限了。因此,你必須指定一個 AssignmentHandler接口的實現類來包含計算任務的參與者的過程。

  1. public void testTaskAssignment() {  
  2.   // 下面的流程基于hello world流程。狀態節點被任務節點取代。任務節點是jPDL中  
  3.   // 的一種節點,表示一個等待狀態,并創建在流程繼續執行之前必須完成的任務。  
  4.   ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(  
  5.     "<process-definition name='the baby process'>" +  
  6.     "  <start-state>" +  
  7.     "    <transition name='baby cries' to='t' />" +  
  8.     "  </start-state>" +  
  9.     "  <task-node name='t'>" +  
  10.     "    <task name='change nappy'>" +  
  11.     "      <assignment class='org.jbpm.tutorial.taskmgmt.NappyAssignmentHandler' />" +  
  12.     "    </task>" +  
  13.     "    <transition to='end' />" +  
  14.     "  </task-node>" +  
  15.     "  <end-state name='end' />" +  
  16.     "</process-definition>" 
  17.   );  
  18.  
  19.   // 創建流程定義的一個執行實例。  
  20.   ProcessInstance processInstance =   
  21.       new ProcessInstance(processDefinition);  
  22.   Token token = processInstance.getRootToken();  
  23.  
  24.   // 下面開始流程執行,從缺省轉換路徑離開開始狀態。  
  25.   token.signal();  
  26.   // signal方法將阻塞,直至流程執行進入一個等待狀態。在這里,就是任務節點t。  
  27.   assertSame(processDefinition.getNode("t"), token.getNode());  
  28.  
  29.   // 當流程執行到達任務節點,一個'換尿布(change nappy)'任務將被創建,  
  30.   // NappyAssignmentHandler被調用以決定把這個任務分配給誰。  
  31.   // NappyAssignmentHandler返回'(爸爸)papa'。  
  32.  
  33.   // 在真實的環境中,任務通過org.jbpm.db.TaskMgmtSession類中的方法從數據  
  34.   // 庫中取得。因為我們不想在本范例中包含持久化的復雜性,我們僅僅從流程實例中  
  35.   // 取出第一個任務實例(我們知道在這個測試場景中只有一個任務實例)。  
  36.   TaskInstance taskInstance = (TaskInstance)    
  37.       processInstance  
  38.         .getTaskMgmtInstance()  
  39.         .getTaskInstances()  
  40.         .iterator().next();  
  41.  
  42.   // 現在,我們檢測任務實例是否真正被指派給'papa'.  
  43.   assertEquals("papa", taskInstance.getActorId() );  
  44.  
  45.   // 現在我們假設爸爸已經完成他的任務,并把任務標記為已完成。  
  46.   taskInstance.end();  
  47.  
  48.   // 因為這是最后(唯一)一個要完成的任務,這個任務的完成出發了流程實例的繼續執行。  
  49.   assertSame(processDefinition.getNode("end"), token.getNode());  

定制action范例

action是把你的客戶java代碼綁定到jBPM流程的一種機制。action能夠關聯到它自己的節點(如果它們在流程的圖形表示中是相關的的話)。action也能夠放置在事件(例如進入轉換、離開節點、進入節點等)之中。在這種情況下,action不是流程的圖形表示的一部分,但是,當運行時流程執行觸發了這些事件的時候,這些action將被執行。

  1. // MyActionHandler代表一個能夠在jBPM流程執行過程中執行某些用戶代碼的類。  
  2. public class MyActionHandler implements ActionHandler {  
  3.  
  4.   // 在每個test之前(在setUp方法中), isExecuted成員將被設置為false。  
  5.   public static boolean isExecuted = false;    
  6.  
  7.   // action將把 isExecuted設置為true,使得單元測試能夠顯示action在什么時候被執行。  
  8.   public void execute(ExecutionContext executionContext) {  
  9.     isExecuted = true;  
  10.   }  

我們從在下面的范例中將要用到的action實現:MyActionHandler開始。這個action處理器實現沒有做真正有用的工作,僅僅把布爾變量isExecuted設置為true。變量isExecuted是靜態的,所以能夠同時從action處理器內部和要校驗它的值的action中訪問。

  1. // 每個測試將在開始時設置MyActionHandler的靜態成員isExecuted為false。  
  2. public void setUp() {  
  3.   MyActionHandler.isExecuted = false;  

下面的例子顯示同樣的action,但是現在action被分別放在enter-node和leave-node事件之中。請注意與轉換只有一個事件不同,節點擁有多個事件類型,因此被放置到節點中的action應該放在event元素之中。

  1. public void testTransitionAction() {  
  2.     // 下面的流程是hello world流程的一個變體。我們把一個action加入從狀態s到結束狀  
  3.     // 態的轉換之中。本測試的目的是顯示要把java代碼集成到jBPM流程中是多么容易。  
  4.     ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(  
  5.       "<process-definition>" +  
  6.       "  <start-state>" +  
  7.       "    <transition to='s' />" +  
  8.       "  </start-state>" +  
  9.       "  <state name='s'>" +  
  10.       "    <transition to='end'>" +  
  11.       "      <action class='org.jbpm.tutorial.action.MyActionHandler' />" +  
  12.       "    </transition>" +  
  13.       "  </state>" +  
  14.       "  <end-state name='end' />" +  
  15.       "</process-definition>" 
  16.     );  
  17.  
  18.     // 啟動流程定義的一個新的執行實例。  
  19.     ProcessInstance processInstance =   
  20.       new ProcessInstance(processDefinition);  
  21.  
  22.     // 下一個信號將導致執行離開開始狀態,到達狀態s。  
  23.     processInstance.signal();  
  24.  
  25.     // 這里我們顯示 MyActionHandler還沒有被執行。  
  26.     assertFalse(MyActionHandler.isExecuted);  
  27.     // ... 以及主執行路徑指向狀態s  
  28.     assertSame(processDefinition.getNode("s"),   
  29.                processInstance.getRootToken().getNode());  
  30.  
  31.     // 下一個信號將觸發根token的執行。該token將取得包含action的轉換,  
  32.     // 該action將在調用signal方法的過程中執行。  
  33.     processInstance.signal();  
  34.  
  35.     // 這里我們可以看到在signal方法被調用的時候, MyActionHandler被執行了。  
  36.     assertTrue(MyActionHandler.isExecuted);  
  37.   } 
  1. ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(  
  2.   "<process-definition>" +  
  3.   "  <start-state>" +  
  4.   "    <transition to='s' />" +  
  5.   "  </start-state>" +  
  6.   "  <state name='s'>" +  
  7.   "    <event type='node-enter'>" +  
  8.   "      <action class='org.jbpm.tutorial.action.MyActionHandler' />" +  
  9.   "    </event>" +  
  10.   "    <event type='node-leave'>" +  
  11.   "      <action class='org.jbpm.tutorial.action.MyActionHandler' />" +  
  12.   "    </event>" +  
  13.   "    <transition to='end'/>" +  
  14.   "  </state>" +  
  15.   "  <end-state name='end' />" +  
  16.   "</process-definition>" 
  17. );  
  18.  
  19. ProcessInstance processInstance =   
  20.   new ProcessInstance(processDefinition);  
  21.  
  22. assertFalse(MyActionHandler.isExecuted);  
  23. // 下一個信號將導致流程執行離開開始狀態,進入狀態s。因此狀態s被進入,action被執行。  
  24. processInstance.signal();  
  25. assertTrue(MyActionHandler.isExecuted);  
  26.  
  27. // 重置MyActionHandler.isExecuted。  
  28. MyActionHandler.isExecuted = false;  
  29.  
  30. // 下一個信號將觸發流程執行離開狀態s,因此action將被再次執行。  
  31. processInstance.signal();  
  32. // 瞧……  
  33. assertTrue(MyActionHandler.isExecuted); 

【編輯推薦】

  1. jBPM 3.2用戶指南 概覽
  2. jBPM 4.0.0用戶指南 安裝配置
  3. jBPM數據庫表說明:流程節點表
  4. jBPM 4.0.0.Beta2版本發布
  5. Equinox動態化深入分析
責任編輯:yangsai 來源: 大雅之堂
相關推薦

2009-06-11 13:53:35

jBPM用戶指南

2011-12-05 15:44:45

Knockout

2009-06-11 13:43:21

jBPM用戶指南jBPM 4.0

2014-12-19 10:07:10

C

2017-11-23 17:45:46

Yii框架IntelYii框架深度剖析

2012-02-20 14:26:48

JavaPlay Framew

2009-07-30 13:21:17

Scala入門Hello World

2023-01-06 08:18:44

2009-08-11 10:32:23

什么是Groovy

2023-09-04 07:30:03

Wasm匯編語言

2009-09-16 17:15:19

OSGi Bundle

2011-06-08 14:39:06

Qt 教程

2009-08-14 16:54:19

C# Hello Wo

2021-11-26 08:22:01

Java動態開發

2011-08-05 09:48:46

iPhone Interface

2024-04-11 13:13:27

2014-04-11 11:36:42

NDKAndroid開發終端

2023-05-23 08:01:10

Netty網絡通信

2015-10-27 09:47:11

2021-03-30 13:48:47

WebAssemblyWeb瀏覽器編程語言
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 九九热在线观看 | 中文字幕免费视频 | 操视频网站| www.五月天婷婷.com | 嫩草视频在线免费观看 | 91在线视频观看免费 | 在线免费看毛片 | 国产精品久久久久久久久久软件 | 狠狠av| 日本国产精品视频 | 先锋资源吧 | 91麻豆精品国产91久久久更新资源速度超快 | 亚洲成人动漫在线观看 | 国产在线高清 | 国产精品精品视频一区二区三区 | 久久免费看 | 成人午夜视频在线观看 | 精品一区二区三区电影 | 色婷婷国产精品综合在线观看 | 国产日韩久久久久69影院 | 999久久 | 亚洲一区二区三区视频免费观看 | 中文字幕一区在线观看视频 | 激情的网站 | 草草视频在线播放 | 日韩精品在线一区 | 在线日韩| 日本精品一区二区在线观看 | 在线观看中文字幕 | 射欧美| 亚洲成人精品久久 | 亚洲国产在 | 91成人精品 | 韩日在线视频 | 黄色电影在线免费观看 | 国产精品极品美女在线观看免费 | a在线视频观看 | 嫩草视频在线 | 久久久久久av | 麻豆一区 | 国产精品久久久久久久岛一牛影视 |