<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    夢想飛翔

    自強不息
    posts - 111, comments - 30, trackbacks - 0, articles - 0
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理
     多數it 組織都必須解決三個主要問題:1.幫助組織減少成本 2.增加并且保持客戶 3.加快業(yè)務效率。完成這些問題一般都需要實現對多個業(yè)務系統(tǒng)的數據和業(yè)務邏輯的無縫訪問,也就是說,要實施系統(tǒng)集成工程,以便聯結業(yè)務流程、實現數據的訪問與共享。

      jpetstore 4.0是ibatis的最新示例程序,基于struts mvc框架(注:非傳統(tǒng)struts開發(fā)模式),以ibatis作為持久化層。該示例程序設計優(yōu)雅,層次清晰,可以學習以及作為一個高效率的編程模型參考。本文是在其基礎上,采用spring對其中間層(業(yè)務層)進行改造。使開發(fā)量進一步減少,同時又擁有了spring的一些好處…

      1. 前言

      jpetstore 4.0是ibatis的最新示例程序。ibatis是開源的持久層產品,包含sql maps 2.0 和 data access objects 2.0 框架。jpetstore示例程序很好的展示了如何利用ibatis來開發(fā)一個典型的j2ee web應用程序。jpetstore有如下特點:

    • ibatis數據層
    • pojo業(yè)務層
    • pojo領域類
    • struts mvc
    • jsp 表示層

      以下是本文用到的關鍵技術介紹,本文假設您已經對struts,springframewok,ibatis有一定的了解。

    • struts 是目前java web mvc框架中不爭的王者。經過長達五年的發(fā)展,struts已經逐漸成長為一個穩(wěn)定、成熟的框架,并且占有了mvc框架中最大的市場份額。但是struts某些技術特性上已經落后于新興的mvc框架。面對spring mvc、webwork2 這些設計更精密,擴展性更強的框架,struts受到了前所未有的挑戰(zhàn)。但站在產品開發(fā)的角度而言,struts仍然是最穩(wěn)妥的選擇。本文的原型例子jpetstore 4.0就是基于struts開發(fā)的,但是不拘泥于struts的傳統(tǒng)固定用法,例如只用了一個自定義action類,并且在form bean類的定義上也是開創(chuàng)性的,令人耳目一新,稍后將具體剖析一下。
    • spring framework 實際上是expert one-on-one j2ee design and development 一書中所闡述的設計思想的具體實現。spring framework的功能非常多。包含aop、orm、dao、context、web、mvc等幾個部分組成。web、mvc暫不用考慮,jpetstore 4.0用的是更成熟的struts和jsp;dao由于目前hibernate、jdo、ibatis的流行,也不考慮,jpetstore 4.0用的就是ibatis。因此最需要用的是aop、orm、context。context中,最重要的是beanfactory,它能將接口與實現分開,非常強大。目前aop應用最成熟的還是在事務管理上。
    • ibatis 是一個功能強大實用的sql map工具,不同于其他orm工具(如hibernate),它是將sql語句映射成java對象,而對于orm工具,它的sql語句是根據映射定義生成的。ibatis 以sql開發(fā)的工作量和數據庫移植性上的讓步,為系統(tǒng)設計提供了更大的自由空間。有ibatis代碼生成的工具,可以根據ddl自動生成ibatis代碼,能減少很多工作量。

      2. jpetstore簡述

      2.1. 背景

      最初是sun公司的j2ee petstore,其最主要目的是用于學習j2ee,但是其缺點也很明顯,就是過度設計了。接著oracle用j2ee petstore來比較各應用服務器的性能。微軟推出了基于。net平臺的 pet shop,用于競爭j2ee petstore.而jpetstore則是經過改良的基于struts的輕便框架j2ee web應用程序,相比來說,jpetstore設計和架構更優(yōu)良,各層定義清晰,使用了很多最佳實踐和模式,避免了很多"反模式",如使用存儲過程,在java代碼中嵌入sql語句,把html存儲在數據庫中等等。最新版本是jpetstore 4.0.

      2.2. jpetstore開發(fā)運行環(huán)境的建立

      1、開發(fā)環(huán)境

    • java sdk 1.4.2
    • apache tomcat 4.1.31
    • eclipse-sdk-3.0.1-win32
    • hsqldb 1.7.2

      2、eclipse插件

    • emf sdk 2.0.1:eclipse建模框架,lomboz插件需要,可以使用runtime版本。
    • lomboz 3.0:j2ee插件,用來在eclipse中開發(fā)j2ee應用程序
    • spring ide 1.0.3:spring bean配置管理插件
    • xmlbuddy_2.0.10:編輯xml,用免費版功能即可
    • tomcatpluginv3:tomcat管理插件
    • properties editor:編輯java的屬性文件,并可以預覽以及自動存盤為unicode格式。免去了手工或者ant調用native2ascii的麻煩。
      3.4. 持久層

        在討論業(yè)務層之前,我們先看一下持久層,如下圖所示:


       

       

        在上文中,我們把iface包下的dao接口歸為業(yè)務層,在這里不需要做修改。ibatis的sql配置文件也不需要改。要改的是dao實現類,并在spring的配置文件中配置起來。

        1、修改基類

        所有的dao實現類都繼承于basesqlmapdao類。修改basesqlmapdao類如下:

      public class basesqlmapdao extends sqlmapclientdaosupport {
        protected static final int page_size = 4;
        protected sqlmapclienttemplate smctemplate = this.getsqlmapclienttemplate();
        public basesqlmapdao() {
       }
      }

        使basesqlmapdao類改為繼承于spring提供的sqlmapclientdaosupport類,并定義了一個保護屬性smctemplate,其類型為sqlmapclienttemplate。關于sqlmapclienttemplate類的詳細說明請參照附錄中的"spring中文參考手冊"

        2、修改dao實現類

        所有的dao實現類還是繼承于basesqlmapdao類,實現相應的dao接口,但其相應的dao操作委托sqlmapclienttemplate來執(zhí)行,以accountsqlmapdao類為例,部分代碼如下:

          public list getusernamelist() {
          return smctemplate.queryforlist("getusernamelist", null);
        }
        public account getaccount(string username, string password) {
          account account = new account();
          account.setusername(username);
          account.setpassword(password);
          return (account) smctemplate.queryforobject("getaccountbyusernameandpassword", account);
        }
        public void insertaccount(account account) {
         smctemplate.update("insertaccount", account);
         smctemplate.update("insertprofile", account);
         smctemplate.update("insertsignon", account);
        }
       

        就這么簡單,所有函數的簽名都是一樣的,只需要查找替換就可以了!

        3、除去工廠類以及相應的配置文件

        除去daoconfig.java這個dao工廠類和相應的配置文件dao.xml,因為dao的獲取現在要用spring來管理。

        4、dao在spring中的配置(applicationcontext.xml)

          <bean id="datasource"
              class="org.springframework.jdbc.datasource.drivermanagerdatasource">
              <property name="driverclassname">
                  <value>org.hsqldb.jdbcdriver</value>
              </property>
              <property name="url">
                  <value>jdbc:hsqldb:hsql://localhost/xdb</value>
              </property>
              <property name="username">
                  <value>sa</value>
              </property>
              <property name="password">
                  <value></value>
              </property>
          </bean>   
          <!-- ibatis sqlmapclient config -->
          <bean id="sqlmapclient"
              class="org.springframework.orm.ibatis.sqlmapclientfactorybean">
              <property name="configlocation">
                  <value>
                      classpath:comibatisjpetstorepersistencesqlmapdaosqlsql-map-config.xml
                  </value>
              </property>
              <property name="datasource">
                  <ref bean="datasource"/>
              </property>   
          </bean>
          <!-- transactions -->
          <bean id="transactionmanager"
              class="org.springframework.jdbc.datasource.datasourcetransactionmanager">
              <property name="datasource">
                  <ref bean="datasource"/>
              </property>
          </bean>
          <!-- persistence layer -->
          <bean id="accountdao"
              class="com.ibatis.jpetstore.persistence.sqlmapdao.accountsqlmapdao">
              <property name="sqlmapclient">
                  <ref local="sqlmapclient"/>
              </property>
          </bean>

        具體的語法請參照附錄中的"spring中文參考手冊".在這里只簡單解釋一下:

        1. 我們首先創(chuàng)建一個數據源datasource,在這里配置的是hsqldb數據庫。如果是oracle數據庫,driverclassname的值是"oracle.jdbc.driver.oracledriver",url的值類似于"jdbc:oracle:thin:@wugfmobile:1521:cdcf".數據源現在由spring來管理,那么現在我們就可以去掉properties目錄下database.properties這個配置文件了;還有不要忘記修改sql-map-config.xml,去掉 對它的引用。

        2. sqlmapclient節(jié)點。這個是針對ibatis sqlmap的sqlmapclientfactorybean配置。實際上配置了一個sqlmapclient的創(chuàng)建工廠類。configlocation屬性配置了ibatis映射文件的名稱。datasource屬性指向了使用的數據源,這樣所有使用sqlmapclient的dao都默認使用了該數據源,除非在dao的配置中另外顯式指定。

        3. transactionmanager節(jié)點。定義了事務,使用的是datasourcetransactionmanager.

        4. 下面就可以定義dao節(jié)點了,如accountdao,它的實現類是com.ibatis.jpetstore.persistence.sqlmapdao.accountsqlmapdao,使用的sql配置從sqlmapclient中讀取,數據庫連接沒有特別列出,那么就是默認使用sqlmapclient配置的數據源datasource.

        這樣,我們就把持久層改造完了,其他的dao配置類似于accountdao.怎么樣?簡單吧。這次有接口了:) accountdao接口->accountsqlmapdao實現。

        3.5. 業(yè)務層

        業(yè)務層的位置以及相關類,如下圖所示:


       

       

        在這個例子中只有3個業(yè)務類,我們以orderservice類為例來改造,這個類是最復雜的,其中涉及了事務。

        1、在applicationcontext配置文件中增加bean的配置:

          <bean id="orderservice"
              class="org.springframework.transaction.interceptor.transactionproxyfactorybean">
              <property name="transactionmanager">
                  <ref local="transactionmanager"></ref>
              </property>
              <property name="target">
                  <bean class="com.ibatis.jpetstore.service.orderservice">
                      <property name="itemdao">
                          <ref bean="itemdao"/>
                      </property>
                      <property name="orderdao">
                          <ref bean="orderdao"/>
                      </property>
                      <property name="sequencedao">
                          <ref bean="sequencedao"/>
                      </property>
                  </bean>
              </property>
              <property name="transactionattributes">
                  <props>
                      <prop key="insert*">propagation_required</prop>
                  </props>
              </property>
          </bean>

       

        定義了一個orderservice,還是很容易懂的。為了簡單起見,使用了嵌套bean,其實現類是com.ibatis.jpetstore.service.orderservice,分別引用了itemdao,orderdao,sequencedao。該bean的insert*實現了事務管理(aop方式)。transactionproxyfactorybean自動創(chuàng)建一個事務advisor, 該advisor包括一個基于事務屬性的pointcut,因此只有事務性的方法被攔截。

    3、示例源程序
    • ibatis示例程序jpetstore 4.0 http://www.ibatis.com/jpetstore/jpetstore.html
    • 改造后的源程序(+spring)(源碼鏈接)

      2.3. 架構

      圖1 jpetstore架構圖

     

      圖1 是jpetstore架構圖,更詳細的內容請參見jpetstore的白皮書。參照這個架構圖,讓我們稍微剖析一下源代碼,得出jpetstore 4.0的具體實現圖(見圖2),思路一下子就豁然開朗了。前言中提到的非傳統(tǒng)的struts開發(fā)模式,關鍵就在struts action類和form bean類上。

      struts action類只有一個:beanaction.沒錯,確實是一個!與傳統(tǒng)的struts編程方式很不同。再仔細研究beanaction類,發(fā)現它其實是一個通用類,利用反射原理,根據url來決定調用formbean的哪個方法。beanaction大大簡化了struts的編程模式,降低了對struts的依賴(與struts以及web容器有關的幾個類都放在com.ibatis.struts包下,其它的類都可以直接復用)。利用這種模式,我們會很容易的把它移植到新的框架如jsf,spring.

      這樣重心就轉移到form bean上了,它已經不是普通意義上的form bean了。查看源代碼,可以看到它不僅僅有數據和校驗/重置方法,而且已經具有了行為,從這個意義上來說,它更像一個bo(business object)。這就是前文講到的,beanaction類利用反射原理,根據url來決定調用form bean的哪個方法(行為)。form bean的這些方法的簽名很簡單,例如:
    public string myactionmethod() {
       //..work
       return "success";
     }

      方法的返回值直接就是字符串,對應的是forward的名稱,而不再是actionforward對象,創(chuàng)建actionforward對象的任務已經由beanaction類代勞了。

      另外,程序還提供了actioncontext工具類,該工具類封裝了request 、response、form parameters、request attributes、session attributes和 application attributes中的數據存取操作,簡單而線程安全,form bean類使用該工具類可以進一步從表現層框架解耦。[iocblog.net 來源]

      在這里需要特別指出的是,beanaction類是對struts擴展的一個有益嘗試,雖然提供了非常好的應用開發(fā)模式,但是它還非常新,一直在發(fā)展中。

      圖2 jpetstore 4.0具體實現

     

      2.4. 代碼剖析

      下面就讓我們開始進一步分析jpetstore4.0的源代碼,為下面的改造鋪路。

    • beanaction.java是唯一一個struts action類,位于com.ibatis.struts包下。正如上文所言,它是一個通用的控制類,利用反射機制,把控制轉移到form bean的某個方法來處理。詳細處理過程參考其源代碼,簡單明晰。
    • form bean類位于com.ibatis.jpetstore.presentation包下,命名規(guī)則為***bean。form bean類全部繼承于basebean類,而basebean類實際繼承于actionform,因此,form bean類就是struts的 actionform,form bean類的屬性數據就由struts框架自動填充。而實際上,jpetstore4.0擴展了struts中actionform的應用: form bean類還具有行為,更像一個bo,其行為(方法)由beanaction根據配置(struts-config.xml)的url來調用。雖然如此,我們還是把form bean類定位于表現層。

        struts-config.xml的配置里有3種映射方式,來告訴beanaction把控制轉到哪個form bean對象的哪個方法來處理。

        以這個請求連接為例http://localhost/jpetstore4/shop/vieworder.do

        1. url pattern
          <action path="/shop/vieworder" type="com.ibatis.struts.beanaction"
          name="orderbean" scope="session"
          validate="false">
          <forward name="success" path="/order/vieworder.jsp"/>
        </action>
       

      此種方式表示,控制將被轉發(fā)到"orderbean"這個form bean對象 的"vieworder"方法(行為)來處理。方法名取"path"參數的以"/"分隔的最后一部分。

      2. method parameter

     

        <action path="/shop/vieworder" type="com.ibatis.struts.beanaction"
        name="orderbean" parameter="vieworder" scope="session"
        validate="false">
        <forward name="success" path="/order/vieworder.jsp"/>
      </action>
     

      此種方式表示,控制將被轉發(fā)到"orderbean"這個form bean對象的"vieworder"方法(行為)來處理。配置中的"parameter"參數表示form bean類上的方法。"parameter"參數優(yōu)先于"path"參數。

      3. no method call

     

        <action path="/shop/vieworder" type="com.ibatis.struts.beanaction"
        name="orderbean" parameter="*" scope="session"
        validate="false">
        <forward name="success" path="/order/vieworder.jsp"/>
      </action>

      此種方式表示,form bean上沒有任何方法被調用。如果存在"name"屬性,則struts把表單參數等數據填充到form bean對象后,把控制轉發(fā)到"success".否則,如果name為空,則直接轉發(fā)控制到"success".

      這就相當于struts內置的org.apache.struts.actions.forwardaction的功能

    <action path="/shop/vieworder" type="org.apache.struts.actions.forwardaction"
        parameter="/order/vieworder.jsp " scope="session" validate="false">
     </action>

    • service類位于com.ibatis.jpetstore.service包下,屬于業(yè)務層。這些類封裝了業(yè)務以及相應的事務控制。service類由form bean類來調用。
    • com.ibatis.jpetstore.persistence.iface包下的類是dao接口,屬于業(yè)務層,其屏蔽了底層的數據庫操作,供具體的service類來調用。daoconfig類是工具類(dao工廠類),service類通過daoconfig類來獲得相應的dao接口,而不用關心底層的具體數據庫操作,實現了如圖2中{耦合2}的解耦。
    • com.ibatis.jpetstore.persistence.sqlmapdao包下的類是對應dao接口的具體實現,在jpetstore4.0中采用了ibatis來實現orm。這些實現類繼承basesqlmapdao類,而basesqlmapdao類則繼承ibatis dao 框架中的sqlmapdaotemplate類。ibatis的配置文件存放在com.ibatis.jpetstore.persistence.sqlmapdao.sql目錄下。這些類和配置文件位于數據層
    • domain類位于com.ibatis.jpetstore.domain包下,是普通的javabean。在這里用作數據傳輸對象(dto),貫穿視圖層、業(yè)務層和數據層,用于在不同層之間傳輸數據。

      剩下的部分就比較簡單了,請看具體的源代碼,非常清晰。

      2.5. 需要改造的地方

      jpetstore4.0的關鍵就在struts action類和form bean類上,這也是其精華之一(雖然該實現方式是試驗性,待擴充和驗證),在此次改造中我們要保留下來,即控制層一點不變,表現層獲取相應業(yè)務類的方式變了(要加載spring環(huán)境),其它保持不變。要特別關注的改動是業(yè)務層和持久層,幸運的是jpetstore4.0設計非常好,需要改動的地方非常少,而且由模式可循,如下:

      1. 業(yè)務層和數據層用spring beanfactory機制管理。

      2. 業(yè)務層的事務由spring 的aop通過聲明來完成。

      3. 表現層(form bean)獲取業(yè)務類的方法改由自定義工廠類來實現(加載spring環(huán)境)。

      3. jpetstore的改造

      3.1. 改造后的架構

     


     

     

      其中紅色部分是要增加的部分,藍色部分是要修改的部分。下面就讓我們逐一剖析。

      3.2. spring context的加載

      為了在struts中加載spring context,一般會在struts-config.xml的最后添加如下部分:

    <plug-in classname="org.springframework.web.struts.contextloaderplugin">
    <set-property property="contextconfiglocation"
    value="/web-inf/applicationcontext.xml" />
    </plug-in>

      spring在設計時就充分考慮到了與struts的協同工作,通過內置的struts plug-in在兩者之間提供了良好的結合點。但是,因為在這里我們一點也不改動jpetstore的控制層(這是jpetstore4.0的精華之一),所以本文不準備采用此方式來加載applicationcontext.我們利用的是spring framework 的beanfactory機制,采用自定義的工具類(bean工廠類)來加載spring的配置文件,從中可以看出spring有多靈活,它提供了各種不同的方式來使用其不同的部分/層次,您只需要用你想用的,不需要的部分可以不用。

      具體的來說,就是在com.ibatis.spring包下創(chuàng)建custombeanfactory類,spring的配置文件applicationcontext.xml也放在這個目錄下。以下就是該類的全部代碼,很簡單:

    public final class custombeanfactory {
     static xmlbeanfactory factory = null;
     static {
      resource is = new
    inputstreamresource( custombeanfactory.class.getresourceasstream("applicationcontext.xml"));
      factory = new xmlbeanfactory(is);
     }
     public static object getbean(string beanname){
      return factory.getbean(beanname);
     }
    }

      實際上就是封裝了spring 的xmlbeanfactory而已,并且spring的配置文件只需要加載一次,以后就可以直接用custombeanfactory.getbean("somebean")來獲得需要的對象了(例如somebean),而不需要知道具體的類。custombeanfactory類用于{耦合1}的解耦。

      custombeanfactory類在本文中只用于表現層的form bean對象獲得service類的對象,因為我們沒有把form bean對象配置在applicationcontext.xml中。但是,為什么不把表現層的form bean類也配置起來呢,這樣就用不著這custombeanfactory個類了,spring會幫助我們創(chuàng)建需要的一切?問題的答案就在于form bean類是struts的actionform類!如果大家熟悉struts,就會知道actionform類是struts自動創(chuàng)建的:在一次請求中,struts判斷,如果actionform實例不存在,就創(chuàng)建一個actionform對象,把客戶提交的表單數據保存到actionform對象中。因此formbean類的對象就不能由spring來創(chuàng)建,但是service類以及數據層的dao類可以,所以只有他們在spring中配置。

      所以,很自然的,我們就創(chuàng)建了custombeanfactory類,在表現層來銜接struts和spring.就這么簡單,實現了另一種方式的{耦合一}的解耦。

      3.3. 表現層

      上面分析到,struts和spring是在表現層銜接起來的,那么表現層就要做稍微的更改,即所需要的service類的對象創(chuàng)建上。以表現層的accountbean類為例:

      原來的源代碼如下

        private static final accountservice accountservice = accountservice.getinstance();
      private static final catalogservice catalogservice = catalogservice.getinstance();

      改造后的源代碼如下

    private static final accountservice accountservice = (accountservice)custombeanfactory.getbean("accountservice");
    private static final catalogservice catalogservice = (catalogservice)custombeanfactory.getbean("catalogservice");

      其他的幾個presentation類以同樣方式改造。這樣,表現層就完成了。關于表現層的其它部分如jsp等一概不動。也許您會說,沒有看出什么特別之處的好處啊?你還是額外實現了一個工廠類。別著急,帷幕剛剛開啟,spring是在表現層引入,但您發(fā)沒發(fā)現:

    • presentation類僅僅面向service類的接口編程,具體"accountservice"是哪個實現類,presentation類不知道,是在spring的配置文件里配置。(本例中,為了最大限度的保持原來的代碼不作變化,沒有抽象出接口)。spring鼓勵面向接口編程,因為是如此的方便和自然,當然您也可以不這么做。
    • custombeanfactory這個工廠類為什么會如此簡單,因為其直接使用了spring的beanfactory。spring從其核心而言,是一個di容器,其設計哲學是提供一種無侵入式的高擴展性的框架。為了實現這個目標,spring 大量引入了java 的reflection機制,通過動態(tài)調用的方式避免硬編碼方式的約束,并在此基礎上建立了其核心組件beanfactory,以此作為其依賴注入機制的實現基礎。org.springframework.beans包中包括了這些核心組件的實現類,核心中的核心為beanwrapper和beanfactory類。[iocblog.net 來源]
       2、業(yè)務類的修改

        以orderservice為例:
      public class orderservice {

         /* private fields */
        private itemdao itemdao;
        private orderdao orderdao;
        private sequencedao sequencedao;

        /* constructors */

        public orderservice() {
        }

      /**
       * @param itemdao 要設置的 itemdao。
       */
      public final void setitemdao(itemdao itemdao) {
       this.itemdao = itemdao;
      }
      /**
       * @param orderdao 要設置的 orderdao。
       */
      public final void setorderdao(orderdao orderdao) {
       this.orderdao = orderdao;
      }
      /**
       * @param sequencedao 要設置的 sequencedao。
       */
      public final void setsequencedao(sequencedao sequencedao) {
       this.sequencedao = sequencedao;
      }
      //剩下的部分
      …….
      }

        紅色部分為修改部分。spring采用的是type2的設置依賴注入,所以我們只需要定義屬性和相應的設值函數就可以了,itemdao,orderdao,sequencedao的值由spring在運行期間注入。構造函數就可以為空了,另外也不需要自己編寫代碼處理事務了(事務在配置中聲明),daomanager.starttransaction();等與事務相關的語句也可以去掉了。和原來的代碼比較一下,是不是處理精簡了很多!可以更關注業(yè)務的實現。

        4. 結束語

        ibatis是一個功能強大實用的sql map工具,可以直接控制sql,為系統(tǒng)設計提供了更大的自由空間。其提供的最新示例程序jpetstore 4.0,設計優(yōu)雅,應用了迄今為止很多最佳實踐和設計模式,非常適于學習以及在此基礎上創(chuàng)建輕量級的j2ee web應用程序。jpetstore 4.0是基于struts的,本文在此基礎上,最大程度保持了原有設計的精華以及最小的代碼改動量,在業(yè)務層和持久化層引入了spring。在您閱讀了本文以及改造后的源代碼后,會深切的感受到spring帶來的種種好處:自然的面向接口的編程,業(yè)務對象的依賴注入,一致的數據存取框架和聲明式的事務處理,統(tǒng)一的配置文件…更重要的是spring既是全面的又是模塊化的,spring有分層的體系結構,這意味著您能選擇僅僅使用它任何一個獨立的部分,就像本文,而它的架構又是內部一致。

    主站蜘蛛池模板: 毛片a级三毛片免费播放| 亚洲精品无码精品mV在线观看| 国产午夜影视大全免费观看| 亚洲伊人久久精品| 深夜免费在线视频| 亚洲精品NV久久久久久久久久| 亚洲综合色一区二区三区小说| 久久黄色免费网站| 亚洲欧洲自拍拍偷综合| 57pao国产成视频免费播放 | 国产精品福利在线观看免费不卡| 亚洲国产日韩成人综合天堂| 人成免费在线视频| 亚洲精品无码永久在线观看你懂的| 在线免费观看h片| 免费一级毛片在播放视频| 青娱乐在线免费观看视频| 手机在线毛片免费播放| 国产精品亚洲专区在线观看| 最新猫咪www免费人成| 久久久久久亚洲av无码蜜芽 | 亚洲一区无码中文字幕| 最近免费中文字幕MV在线视频3 | 国产成人免费片在线视频观看| 羞羞视频在线免费观看| 久久久久亚洲AV成人网人人网站| 亚洲精品无码久久久久YW| 成人人免费夜夜视频观看| 亚洲国产成人AV网站| 久久亚洲中文字幕精品一区| 免费不卡在线观看AV| 亚洲av综合avav中文| 9久9久女女免费精品视频在线观看| 亚洲国产成人精品无码区二本| 亚洲国产成人五月综合网| 国产91成人精品亚洲精品| 亚洲精品亚洲人成人网| 青草草色A免费观看在线| 美国毛片亚洲社区在线观看| 亚洲国产综合无码一区| 日本免费电影一区|