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

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

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

    持久層的組成(轉)

    持久層的組成
        這一節的名字應該換成“基于Hibernate的持久層的組成”更合適一點,可是它太長了。既然Hibernate是用來開發持久層,那么我先介紹一下這個持久層中的各個元素。
    1.    POJO:Plain Old Java Object,你可以把它看作是簡單的JavaBean。一般說來,一張數據庫表對應一個POJO,也就是對象/關系的一一映射。
    2.    DAO:對于每一個POJO,一般都有一個DAO與之對應,承擔所有關于該POJO的訪問控制。實際上也就是控制了對數據庫中一張表的訪問控制。
    3.    *.hbm.xml文件:這個文件定義了POJO和數據庫中的表是如何映射的,比如POJO中的字段對應數據庫表中的哪個字段等等。一般每個映射都用單獨的文件來描述,也就是有一個POJO就有一個*.hbm.xml文件。
    4.    *.cfg.xml文件:這個文件定義了Hibernate的基本信息,比如數據庫驅動,用戶名,密碼等等連接信息,也包括了所有要用的*.hbm.xml文件,在初始化的時候,Hibernate會讀取這個文件來找相應的映射文件完成對象/關系。
    我們還是以上文的例子來詳細描述一下這里提到的各個元素的內容。
    1.    Student.java:
    代碼片段4:
    1. public class Student  implements java.io.Serializable 
    2. {
    3.     private String id;
    4.     private String name;
    5.     private Set courseSelections = new HashSet(0);
    6.     public Student() 
    7.     {
    8.     }
    9.     public String getId() 
    10.     {
    11.         return this.id;
    12.     }
    13.     
    14.     public void setId(String id) 
    15.     {
    16.         this.id = id;
    17.     }
    18.     public String getName() 
    19.     {
    20.         return this.name;
    21.     }
    22.     
    23.     public void setName(String name) 
    24.     {
    25.         this.name = name;
    26.     }
    27.     public Set getCourseSelections() 
    28.     {
    29.         return this.courseSelections;
    30.     }
    31.     
    32.     public void setCourseSelections(Set courseSelections) 
    33.     {
    34.         this.courseSelections = courseSelections;
    35.     }
    36. }

    這個類就是一個POJO,你可以很明顯的看出來它就是一個JavaBean。我想解釋它的courseSelection字段。很顯然,在數據庫表student中,沒有這個字段。這里的這個字段是因為一個外鍵引用,course_selection的student_id是一個外鍵,引用了student表中的id字段。那么在Student類中courseSelection來記錄這樣的外鍵關系,也就是說,當我們獲取了Student對象以后,就可以直接獲取他的選課記錄,這樣就為上層的調用提供了很大的方便。這里有點模糊沒關系,我在介紹映射定義文件(*.hbm.xml)的時候還會提到這個問題。
    2.    StudentDAO.java
    代碼片段5:
    1. public class StudentDAO 
    2. {
    3.     Session session;
    4.     public StudentDAO()
    5.     {
    6.         Configuration cfg = new Configuration();
    7.         cfg.configure("/hibernate.cfg.xml");
    8.         SessionFactory sessionFactory = cfg.buildSessionFactory();
    9.         session = sessionFactory.openSession();
    10.     }
    11.     
    12.     public void save(Student transientInstance) 
    13.     {
    14.         session.save(transientInstance);
    15.     }
    16.     
    17.     public void delete(Student persistentInstance) 
    18.     {
    19.         session.delete(persistentInstance);
    20.     }
    21.     
    22.     public Student findById(java.lang.String id) 
    23.     {
    24.         List list = session.createCriteria(Student.class).add(
    25. Expression.eq("id", id)).list();
    26.         if (list.size() > 0) 
    27.         {
    28.             return (Student)list.get(0);
    29.         }
    30.         return null;
    31.     }
    32. }

    這里的構造函數是用來啟動Hibernate,并獲取session。打開一個session就相當于打開了一個數據庫連接,然后我們就可以對這個session進行操作,完成數據庫操作,完全不用寫SQL語句。我這里Hibernate的啟動方式寫的很不規范,系統應該只需要完成一次Hibernate啟動就可以在不同的DAO中使用,我把它寫在構造函數里面純粹是為了簡化演示代碼。
    你可以看到save和delete方法都很簡單直接對對象操作,而findById就有些麻煩,因為這里有一個查詢過程在里面。Hibernate里面查詢可以用Criteria這個類來完成,我們也常用Hibernate獨有的HQL(Hibernate Query Language)來完成查詢。當然Hibernate也是支持原生SQL的。關于查詢的詳細信息請參考其他文章或書籍,我只是演示一個流程,介紹一些概念。
    3.    Student.hbm.xml
    代碼片段6:
    1. <hibernate-mapping>
    2.     <class name="Student" table="STUDENT">
    3.         <id name="id" type="string">
    4.             <column name="ID" length="10" />
    5.             <generator class="assigned" />
    6.         </id>
    7.         <property name="name" type="string">
    8.             <column name="NAME" not-null="true" />
    9.         </property>
    10.         <set name="courseSelections" inverse="true">
    11.             <key>
    12.                 <column name="STUDENT_ID" length="10" 
    13. not-null="true" />
    14.             </key>
    15.             <one-to-many class="CourseSelection" />
    16.         </set>
    17.     </class>
    18. </hibernate-mapping>

    這個文件定義了Student類和Student表是如何映射的。class元素定義了Sudent類和STUDENT表映射,然后就定義了各個屬性是如何映射的。如果一個屬性是數據庫的key,那么會用id標簽來定義,column定義了當前類的屬性和數據庫中的哪個字段對應,generator是id特有的。一般來說id是自增的,由于我的數據庫是用的Oracle,它沒有自增字段,要實現自增必須用Sequence,這超出了本文的范圍,所以我就用assigned來簡化示例代碼。assigned表示id是用戶給定的。
    有一個比較特別的標簽是set,它對應著數據庫中的外鍵關系,上文我提到的通過Student對象可以獲得所有相關的選課記錄就是通過這里的定義實現的。name屬性對應了Student類中的字段名,key表示哪個字段是外鍵,one-to-many表示Student和CourseSelection是一對多關系,這和事實相符。類似的還有many-to-one,many-to-many,不過這些都不常用,我不介紹了。Hibernate根據這個映射定義文件,在實例化一個POJO(比如Student)的時候,會自動的把定義過映射的屬性用數據庫中的數據填充,set也包括在內。
    4.    hibernate.cfg.xml
    代碼片段7:
    1. <hibernate-configuration>
    2.     <session-factory>
    3.         <property name="connection.username">test</property>
    4.         <property name="connection.url">
    5. jdbc:oracle:thin:@10.85.33.199:1521:glee</property>
    6.         <property name="dialect">
    7. org.hibernate.dialect.Oracle9Dialect</property>
    8.         <property name="connection.password">test</property>
    9.         <property name="connection.driver_class">
    10. oracle.jdbc.OracleDriver</property>
    11.         <mapping resource="Student.hbm.xml"></mapping>
    12.         <mapping resource="CourseSelection.hbm.xml"></mapping>
    13.         <mapping resource="Course.hbm.xml"></mapping>
    14.     </session-factory>
    15. </hibernate-configuration>

    這個文件我不解釋了,自己看吧。結合上文StudentDAO的例子,我想你應該能看明白。
    看了這么多,或許你會有點頭皮發麻,POJO,DAO,配置文件...好像要寫的東西還是很多。值得慶幸的是現在Hibernate已經發展的比較成熟了,有很多工具來幫助我們完成這些工作,比如MiddleGen,Hibernate Synchronizer等等。我使用的開發工具是Eclipse+MyEclipse,我所要做的只是把數據庫表建好,然后MyEclipse提供的工具會自動根據數據庫表生成POJO,DAO,*.hbm.xml,甚至hibernate.cfg.xml都是自動完成的(前提是MyEclipse知道你的數據庫連接信息)。我并不打算介紹如何用IDE來開發Hibernate,你可以參考IDE的幫助文檔。
    到這里為止,使用Hibernate進行開發的基本組成元素我都介紹好了,強烈建議你馬上實踐一遍,即使有些不理解,也先依葫蘆畫瓢一個。對了,別忘了把Hibernate的包down下來放到classpath里面。

    三、Session與SessionFactory
    Session可以說是Hibernate的核心,Hibernate對外暴露的接口就是Session。所以我這里講一下有關Session的常用函數和特性。
    在講Session之前,我想先提一下SessionFactory,這個東西不復雜,只要配置好就行了。顧名思義,SessionFactory就是用來創建Session的。SessionFactory是線程安全的,也就是說對于同一個數據庫的所有操作共享一個SessionFactory就行了?;仡^看代碼片段5,我們可以看到SessionFactory的常用配置方式。
    代碼片段8:
    1. Configuration cfg = new Configuration();
    2. cfg.configure("/hibernate.cfg.xml");
    3. SessionFactory sessionFactory = cfg.buildSessionFactory();

    我們通過Configuration來讀取配置文件,然后就可以創建SessionFactory,這段代碼在    所有系統中都大同小異,一般就是xml配置文件的名字不一樣,所以也沒什么好說的。
    當我們有了SessionFactory以后就可以獲取Session了。調用SessionFactory.openSession()就會返回一個Session實例,然后我們操作這個Session來訪問數據庫。值得一提的是Session并不是線程安全的,也就是每一個線程都必須有自己的Session。所以我們一般通過以下方法來獲取和關閉Session:
    代碼片段9:
    1. public static Session currentSession() throws HibernateException 
    2.     {
    3.         Session session = (Session) threadLocal.get();
    4.         if (session == null || !session.isOpen()) 
    5.         {
    6.             if (sessionFactory == null
    7.             {
    8.                 try 
    9.                 {
    10.                     cfg.configure(CONFIG_FILE_LOCATION);
    11.                     sessionFactory = cfg.buildSessionFactory();
    12.                 } 
    13.                 catch (Exception e) 
    14.                 {
    15.                     e.printStackTrace();
    16.                 }
    17.             }
    18.             session = (sessionFactory != null) ?
    19.                  sessionFactory.openSession(): null;
    20.             threadLocal.set(session);
    21.         }
    22.         return session;
    23. }
    24. public static void closeSession() throws HibernateException 
    25.     {
    26.         Session session = (Session) threadLocal.get();
    27.         threadLocal.set(null);
    28.         if (session != null
    29.         {
    30.             session.close();
    31.         }
    32. }

    可以看到,我們通過threadLocal來保存每個線程的session,這樣就保證了各個線程之    間的互不干擾,也保證了系統只有一個SessionFactory實例(對于大多數應用來說已經    足夠了)。如果你使用MyEclipse進行開發的話,它會自動生成一個    HibernateSessionFactory.java,其中就包含了以上代碼。
    好了,現在我們已經獲得了Session,下面我來介紹以下Session的常用函數,這些函數都有很多重載函數,我只介紹以下大概是干嘛的,不一一解釋,詳細信息你可以查看Hibernate的API。
    1.Session.get(),獲取某個類的實例,一般都是通過id來獲取比如
    Session.get(Student.class, "0361095");
    這句話的意思就是獲取id(primary key)為“0361095”的Student對象。這里要注    意的是第二個參數必須是Object,也就是說,如果是long類型的1,那么必須轉換    成new Long(1)再傳入。
    2.Session.load(),用法和意義都和get一樣,不過它們還是有點區別,我稍后解釋。
    3.Session.save(),將某個實例保存到數據庫中去(往往在數據庫中形成一條新的記錄)。
    4.Session.update(),更新某個實例,這個實例必須和數據庫中有對應,否則會報錯。
    5.Session.delete(),刪除某個實例,也就是刪除這個實例對應的數據表中的數據。
    6.Session.saveOrUpdate(),保存或者更新某個實例,調用這個方法你就不用去關心到        底是save還是update了,它會自己判斷,然后調用相應的函數。其實save和update        涉及到實體對象生命周期中的三種狀態,這個比較重要,我在后面會單獨講的。
    對于get和load的區別,很難講清楚,這里涉及到Hibernate的緩存機制,是一個非常    復雜的話題,我不打算深入討論這個內容。簡單的來講,Session實現了Hibernate的一    級緩存,SessionFactory實現了Hibernate的二級緩存。load方法會先查找一級緩存再查    找二級緩存,最后再去數據庫中找,而get只會查找一級緩存,然后就去數據庫中找了。    這只是是get和load的一個區別,另外的區別如果你有興趣的話自己去google吧。關于Hibernate的緩存機制,如果你只是一般用用Hibernate的話沒有必要深入研究,就當它不存在好了,get和load到底用哪個也不用非常講究,如果你用工具生成DAO的話,    生成的代碼用什么就用什么吧。

    四、關鍵概念的理解
    在使用Hibernate進行開發的時候有幾個概念在我看來是必須理解的,否則在開發的時候會遇到很多問題而摸不著頭腦。
    1.Lazy loading,懶加載(延遲加載)
    這個技術在很多地方被應用,比如Eclipse的插件管理也是用的延遲加載。在Hibernate中,所謂延遲加載就是返回一個POJO但是某些數據(往往是實體類型或者Set類型)并沒有被真正的被填充,直到POJO的某個字段真正被引用的時候才從數據庫中讀取相應的數據來填充POJO中的字段。這樣就能有效的避免很多不必要的數據庫操作,因為POJO的有些數據我們并不需要,而且數據庫操作是很費時間的。在Hibernate2中,默認是非延遲加載的,而在Hibernate3中,默認就是延遲加載了。
    如果使用了延遲加載,那么在讀取數據的時候有一個問題必須注意,那就是在數據真正被加載之前,Session不能被關閉。你可以回頭看一下代碼片段5,我在構造函數里面open了session以后就沒有關閉這個session,所以我在使用的時候沒有什么問題,但這樣總占著數據庫連接也不好,用好了應該及時關閉給別人用。我上文給的例子中沒有關閉Session的代碼,要加的話給DAO加一個方法調用Session.close(),然后在代碼片段1中的return之前調用這個方法就行了。
    Hibernate的延遲加載機制遠不是這么簡單,但是普通的應用沒有必要去深究這些東西,了解這么多就夠了。

    2. Object lifecycle,對象生命周期
    在Hibernate中,對象分為三種狀態,Transient(自由狀態)、Persistent(持久狀態),Detached(游離狀態),下面我分別解釋一下。
    1、自由狀態:所謂自由狀態就是說這個對象是自由的,與Hibernate無關,比       如:
    Student student = new Student();
        student.setId("0361095");
                    這里的student就是一個普通的對象與hibernate無關,稱為自由狀態。

    2、持久狀態:所謂持久狀態就是指對象和數據庫中的數據(持久狀態的數據)       有關聯,也就是說對象被Hibernate所管理了,比如:
    session.save(student);
       這樣student對象就從自由狀態變為持久狀態了。持久狀態的對象在Session       與數據庫中的數據進行同步時(比如commit)會把數據更新到數據庫。而         其他狀態的則不會。我覺得可以這樣來理解持久狀態,可以看成Hibernate       也擁有一份對象的引用,那么如果你對持久狀態對象的屬性進行更改的話,       Hibernate看到的對象的狀態也更改了,而Hibernate所看到的對象和數據       庫中的數據是等價的。也正是這樣,Hibernate才實現了Object/Relation       的映射。類似的,load和get方法也一樣會獲取Persistent狀態的對象。

    3、游離狀態:每次調用Session.close以后,所有跟這個session有關的處于
    Persistant的對象就變成了游離狀態。也許你要問Detached和Transient有什么區別。其實從我給的例子來說看不出什么區別,因為我這里ID是給定的,而真正開發的時候ID往往是自增的,那么Transient的對象是沒有ID    的,當save了以后就有了,顯而易見Detached的對象也是有ID,只不過這個對象已經和Hibernate脫離了關系。但是游離狀態的對象仍然和數據庫    中的記錄有一定聯系,至少游離狀態的對象知道數據庫中有條記錄的ID為xxx。從這一點上來講,游離狀態是可以自己創造出來的,只要你知道數據庫中的主鍵信息。
    在使用Hibernate開發的時候要分清楚這三種狀態,否則很容易出錯。比如不能去save一個游離狀態的對象,不能去update一個自由狀態的對象等等。

    五、結束語
    我要講的就這么多,這篇文章不是詳細介紹Hibernate,我只是總結了自己學習和使用Hibernate的一些感受和經驗,希望能給沒有用過Hibernate的開發者一個上手的指引。如果你看完了這篇文章仍然滿頭霧水,無從下手的話,我只能向你表示歉意,浪費你的時間了。不管怎樣,我強烈推薦一本書《深入淺出Hibernate》,這本書既能作為學習的教程,也能作為日后的查詢用書,相當實用。

    posted @ 2008-01-10 11:39 靈! 閱讀(307) | 評論 (0)編輯 收藏

    JAVA數據類型轉換

    基本類型有以下四種:
    int長度數據類型有:byte(8bits)、short(16bits)、int(32bits)、long(64bits)、
    float長度數據類型有:單精度(32bits float)、雙精度(64bits double)
    boolean類型變量的取值有:ture、false
    char數據類型有:unicode字符,16位
    對應的類類型:
    Integer、Float、Boolean、Character、Double、Short、Byte、Long


    轉換原則:
    從低精度向高精度轉換
    byte 、short、int、long、float、double、char
    注:兩個char型運算時,自動轉換為int型;當char與別的類型運算時,也會先自動轉換為int型的,再做其它類型的自動轉換

    基本類型向類類型轉換

    正向轉換:
    通過類包裝器來new出一個新的類類型的變量
    Integer a= new Integer(2);

    反向轉換:
    通過類包裝器來轉換
    int b=a.intValue();
    類類型向字符串轉換


    正向轉換:
    因為每個類都是object類的子類,而所有的object類都有一個toString()函數,所以通過toString()函數來轉換即可

    反向轉換:
    通過類包裝器new出一個新的類類型的變量
    eg1: int i=Integer.valueOf(“123”).intValue()
    說明:上例是將一個字符串轉化成一個Integer對象,然后再調用這個對象的intValue()方法返回其對應的int數值。
    eg2: float f=Float.valueOf(“123”).floatValue()
    說明:上例是將一個字符串轉化成一個Float對象,然后再調用這個對象的floatValue()方法返回其對應的float數值。
    eg3: boolean b=Boolean.valueOf(“123”).booleanValue()
    說明:上例是將一個字符串轉化成一個Boolean對象,然后再調用這個對象的booleanValue()方法返回其對應的boolean數值。
    eg4:Double d=Double.valueOf(“123”).doubleValue()
    說明:上例是將一個字符串轉化成一個Double對象,然后再調用這個對象的doubleValue()方法返回其對應的double數值。
    eg5: long l=Long.valueOf(“123”).longValue()
    說明:上例是將一個字符串轉化成一個Long對象,然后再調用這個對象的longValue()方法返回其對應的long數值。
    eg6: char=Character.valueOf(“123”).charValue()
    說明:上例是將一個字符串轉化成一個Character對象,然后再調用這個對象的charValue()方法返回其對應的char數值。


    基本類型向字符串的轉換

    正向轉換:
    如:int a=12;
    String b;
    b=a+””;

    反向轉換:
    通過類包裝器
    eg1:
    int i=Integer.parseInt(“123”)
    說明:此方法只能適用于字符串轉化成整型變量
    eg2: float f=Float.valueOf(“123”).floatValue()
    說明:上例是將一個字符串轉化成一個Float對象,然后再調用這個對象的floatValue()方法返回其對應的float數值。
    eg3: boolean b=Boolean.valueOf(“123”).booleanValue()
    說明:上例是將一個字符串轉化成一個Boolean對象,然后再調用這個對象的booleanValue()方法返回其對應的boolean數值。
    eg4:Double d=Double.valueOf(“123”).doubleValue()
    說明:上例是將一個字符串轉化成一個Double對象,然后再調用這個對象的doubleValue()方法返回其對應的double數值。
    eg5: long l=Long.valueOf(“123”).longValue()
    說明:上例是將一個字符串轉化成一個Long對象,然后再調用這個對象的longValue()方法返回其對應的long數值。
    eg6: char=Character.valueOf(“123”).charValue()
    說明:上例是將一個字符串轉化成一個Character對象,然后再調用這個對象的charValue()方法返回其對應的char數值。

    posted @ 2008-01-10 11:38 靈! 閱讀(258) | 評論 (0)編輯 收藏

    java 數據庫基本操作

    java 數據庫基本操作

      1、java數據庫操作基本流程

      2、幾個常用的重要技巧:

      ·可滾動、更新的記錄集

      ·批量更新

      ·事務處理

      java數據庫操作基本流程:取得數據庫連接 - 執行sql語句 - 處理執行結果 - 釋放數據庫連接

      1、取得數據庫連接

      1)用DriverManager取數據庫連接

      例子

      String className,url,uid,pwd;

      className = "oracle.jdbc.driver.OracleDriver";

      url = "jdbc:oracle:thin:@127.0.0.1:1521:orasvr;

      uid = "system";

      pwd = "manager";

      Class.forName(className);

      Connection cn = DriverManager.getConnection(url,uid,pwd);

      2)用jndi(java的命名和目錄服務)方式

      例子

      String jndi = "jdbc/db";

      Context ctx = (Context) new InitialContext().lookup("java:comp/env");

      DataSource ds = (DataSource) ctx.lookup(jndi);

      Connection cn = ds.getConnection();

      多用于jsp中

      2、執行sql語句

      1)用Statement來執行sql語句

      String sql;

      Statement sm = cn.createStatement();

      sm.executeQuery(sql); // 執行數據查詢語句(select)

      sm.executeUpdate(sql); // 執行數據更新語句(delete、update、insert、drop等)statement.close();

      2)用PreparedStatement來執行sql語句

      String sql;

      sql = "insert into user (id,name) values (?,?)";

      PreparedStatement ps = cn.prepareStatement(sql);

      ps.setInt(1,xxx);

      ps.setString(2,xxx);

      ...

      ResultSet rs = ps.executeQuery(); // 查詢

      int c = ps.executeUpdate(); // 更新

      3、處理執行結果

      查詢語句,返回記錄集ResultSet

      更新語句,返回數字,表示該更新影響的記錄數

      ResultSet的方法

      1、next(),將游標往后移動一行,如果成功返回true;否則返回false

      2、getInt("id")或getSting("name"),返回當前游標下某個字段的值

      4、釋放連接

      cn.close();

      一般,先關閉ResultSet,然后關閉Statement(或者PreparedStatement);最后關閉Connection

      可滾動、更新的記錄集

      1、創建可滾動、更新的Statement

      Statement sm = cn.createStatement(ResultSet.TYPE_SCROLL_ENSITIVE,ResultSet.CONCUR_READ_ONLY);

      該Statement取得的ResultSet就是可滾動的

      2、創建PreparedStatement時指定參數

      PreparedStatemet ps = cn.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);

      ResultSet.absolute(9000);

      ·批量更新

      1、Statement

      Statement sm = cn.createStatement();

      sm.addBatch(sql1);

      sm.addBatch(sql2);

      ...

      sm.executeBatch()

      一個Statement對象,可以執行多個sql語句以后,批量更新。這多個語句可以是delete、update、insert等或兼有

      2、PreparedStatement

      PreparedStatement ps = cn.preparedStatement(sql);

      {

      ps.setXXX(1,xxx);

      ...

      ps.addBatch();

      }

      ps.executeBatch();

      一個PreparedStatement,可以把一個sql語句,變換參數多次執行,一次更新。

      ·事務的處理

      1、關閉Connection的自動提交

      cn.setAutoCommit(false);

      2、執行一系列sql語句

      要點:執行每一個新的sql語句前,上一次執行sql語句的Statement(或者PreparedStatemet)必須先close

      Statement sm ;

      sm = cn.createStatement(insert into user...);

      sm.executeUpdate();

      sm.close();

      sm = cn.createStatement("insert into corp...);

      sm.executeUpdate();

      sm.close();

      3、提交

      cn.commit();

      4、如果發生異常,那么回滾

      cn.rollback();

    posted @ 2008-01-10 11:37 靈! 閱讀(236) | 評論 (0)編輯 收藏

    可以開始用Struts2.0了

    Apache已經發布了Struts2.0的正式版,即2.0.6GA版本。這個版本已經可以在項目中正式使用了。當然大家一定很關心,從webwork2.2遷移到struts2.0麻煩不麻煩,請看Struts2.0的FAQ:

    引用
    Essentially, Struts 2.0 is the technical equivalent of WebWork 2.3. Aside from the package and property renaming, it isn't much different than, say, migrating from WebWork 2.1 to 2.2.


    Struts2.0其實就是webwork2.3而已,從webwork2.2遷移到struts2.0不會比從webwork2.1到2.2更麻煩。

    webwork2.2和struts2.0差異對比:
    http://struts.apache.org/2.x/docs/key-changes-from-webwork-2.html

    遷移步驟:
    http://struts.apache.org/2.x/docs/webwork-2-migration-strategies.html

    總結:

    大致來說,struts2.0就是把package和配置文件的名字改了改而已,別的沒有做什么改動,所以現在用struts2.0和用webwork2.2沒有多大區別。當然這遷移一遷就是將近兩年,還是有點進步的:

    1、搭配struts2.0的xwork版本必須使用xwork2.0.1,而xwork2.0.1集成了可選的Google Guice IoC容器
    2、Struts2.0弄了一個plugin機制,來適配各種擴展機制
    3、全面引入annotation語法,驗證,攔截都可以用annotation了。

    所以用webwork的同志們,大膽的遷移到struts2.0來吧。

    posted @ 2008-01-08 20:21 靈! 閱讀(407) | 評論 (1)編輯 收藏

    緩存簡述

    緩存實現的層面有很多:

    1、對象緩存
    由ORM框架提供,透明性訪問,細顆粒度緩存數據庫查詢結果,無需業務代碼顯式編程。當軟件結構按照ORM框架的要求進行針對性設計,使用對象緩存將會極大降低web系統對于數據庫的訪問請求。因為類似Hibernate這樣的ORM,良好的設計數據庫結構和利用對象緩存,在大負載網站,能夠提供極高的性能。因為使用對象緩存也無需顯式編程,所以適用范圍也最廣泛。

    2、查詢緩存
    對數據庫查詢結果行集進行緩存,適用于一些耗時,但是時效性要求比較低的場景。iBATIS就只能使用查詢緩存,而無對象緩存。查詢緩存和對象緩存適用的場景不一樣,是互為補充的。

    3、片斷緩存
    針對動態頁面的局部片斷內容進行緩存,適用于一些個性化但不經常更新的頁面(例如博客)。OSCache提供了相當簡陋的片斷緩存,而RoR則提供了相當好的片斷緩存機制。

    4、Action緩存
    針對URL訪問返回的頁面結果進行緩存,適用于粗粒度的頁面緩存,例如新聞發布。OScache提供了相當簡陋的Action緩存(通過web.xml中的配置),而RoR提供了相當好的Action緩存。

    緩存不能一概而論,以上每種緩存分別適用于各自的場景,緩存不同的層面。當然你可以在應用程序當中把4種緩存一起用上。

    posted @ 2008-01-08 20:19 靈! 閱讀(229) | 評論 (0)編輯 收藏

    iReport 報表在應用程序中的應用代碼(轉載)

    import dori.jasper.engine.*;
    import dori.jasper.engine.util.*;
    import java.sql.*;
    import java.util.*;
    import dori.jasper.engine.JasperReport;
    import java.util.Date;
    import java.text.SimpleDateFormat;
    import dori.jasper.view.*;
    import org.apache.commons.logging.LogFactory;
    import com.lowagie.text.DocumentException;
    import com.lowagie.text.*;
    import dori.jasper.engine.design.*;
    import org.apache.commons.digester.Digester;
    import org.apache.commons.beanutils.BeanUtils;

    public class myreport
    {
     public void reportName(String strBbmc)
     {
      JRResultSetDataSource jrds = null;
      JasperPrint jasperPrint = null;
      Map reportParams = new HashMap();
      ResultSet rs = null;
      Connection con = null;
      Statement stmt = null;
      String sql = "select * from  bbmc";
      try
       {
        //動態獲取
        JasperDesign jasperDesign = JasperManager.loadXmlDesign("./bbmc.jrxml");
        JasperReport jasperreport = JasperManager.compileReport(jasperDesign);
        //建立連接
        ConnectionpoolManager mgr = new ConnectionpoolManager();
        mgr.setMonitorThread(520);
        mgr.addAlias("jdbcConnecpool","com.microsoft.jdbc.sqlserver.SQLServerDriver","jdbc:microsoft:sqlserver://192.168.45.233:1433;DatabaseName = ysgl ","sa","sa",10,300,520,30,false);
        con = DriverManager.getConnection(ConnectionPoolManager.URL_PREFIX+ConnectionPoolManager.getPoolName(),null,null);
        stmt = con.creatStatement();
        rs = stmt.executeQuery(sql);
        jrds = new JRResultSetDataSource(rs);
        jasperPrint = JasperFillManager.fillReport(jasperReport,reportParams,jrds);
        //調出JasperViewer進行打印預覽
        JasperViewer.viewReport(jasperPrint);
       }
       catch(ClassNotFoundException ee)
        {
         ee.printStackTrace();
        }
       catch(SQLException ex)
        {
         ex.pritStackTrace;
        }
       catch(JRException e)
        {
         e.getMessage();
        }
     }
    }

    posted @ 2008-01-08 20:08 靈! 閱讀(277) | 評論 (0)編輯 收藏

    JSP實現論壇樹型結構的算法(非遞歸)

    實現論壇樹型結構的算法很多,這里是一個不用遞歸實現樹型結構的算法

    1.演示表的結構: 

        表名:mybbslist 
       字段     數據類型  說明 
       BBSID    自動編號   
       RootID    Int     根帖ID,本身為根帖則RootID = BBSID 
       FID     Int     父帖ID,上一層帖子的ID,如是根帖則FID = 0 
       DEPTH    Int     根帖Level=0,其他依據回復的深度遞增 
       BBSSubject  Char    主題 



    2.創建表(可根據此表的結構在ACCESS中創建表): 


     create table mybbslist ( 
     forumID int(20) not null, 
     bbsID int auto_increment primary key, 
     rootid int(20) not null, 
     fid int(20) not null, 
     depth int(20) not null, 
     userID int(20) not null, 
     bbsUser varchar(24) not null, 
     bbsSubject varchar(100) not null, 
     bbsContent text, 
     bbsTime varchar(30), 
     bbsRead int(20), 
     bbsReply int(20), 
    INDEX forumID (forumID))  




    3.演示論壇樹型結構的JSP程序,注意此程序只對一個根貼進行了演示(數據庫用ACCESS)

     <%@ page contentType="text/html;charset=gb2312" %> 
    <%@ page import="java.io.*" %> 
    <%@ page import="java.sql.*" %> 
    <% 
     String driverName = "sun.jdbc.odbc.JdbcOdbcDriver"; 
     String connURL= "jdbc:odbc:cwb"; 
     Connection conn = null; 
     Statement stmt = null; 

    int intRowCount; 
    out.print("顯示論壇樹形結構"); 
    out.print("<br><br>"); 
    try { 
         Class.forName(driverName); 
         conn = DriverManager.getConnection(connURL); 
         stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
         String sql="select * from mybbslist order by rootid desc,depth,fid,bbsid"; 
         ResultSet rs = stmt.executeQuery(sql); 
         if (rs.next()){ 
                     rs.last(); 
                     intRowCount=rs.getRow(); 
                     out.print("論壇樹中有"); 
                     out.print(intRowCount); 
                     out.print("個葉子節點"); 
                     rs.first(); 
                     int j=0; 
                     int Depth = 0; 
                     out.print("<ul>"); 
                     while(j<intRowCount){ 
                           int rsDepth=rs.getInt("depth"); 
                           if (rsDepth>Depth){ 
                                          out.print("<ul>"); 
                            } 
                            out.print("<li>"); 
                            String bbssubject=rs.getString("bbsSubject"); 
                            out.print(bbssubject); 
                            out.print("</li>"); 
                            Depth=rsDepth;
                            j=j+1; 
                            rs.next(); 
                     } 
                     for(int i=0;i<Depth+1;i=i+1) { 
                        out.print("</ul>"); 
                     } 
        }else{ 
                out.print("數據庫中無記錄"); 
        } 
    }catch (SQLException E) { 
          out.println("SQLException: " + E.getMessage()); 
          out.println("SQLState: " + E.getSQLState()); 
          out.println("VendorError: " + E.getErrorCode()); 

    %> 
    <% //關閉mysql連接 
    try { 
          if(conn!=null)  conn.close(); 
    } catch (Exception ex) { 
          System.err.println("closeConn: " + ex.getMessage()); 

    %> 

    posted @ 2008-01-08 20:07 靈! 閱讀(300) | 評論 (0)編輯 收藏

    J2ME的高級圖形界面

      最近在SUN的網站上看到一則關于J2ME GUI的文章:《The Java ME GUI APIs at a Glance 》。文章對MIDP 1.0, 2.0, 3.0的圖形界面進行了闡述和比較。最吸引我的是Advanced Graphics and User Interface (AGUI),看這界面是不是很COOL,不過要CDC1.1才能運行,希望以后手機能發展到可以支持這樣的圖形界面。


    posted @ 2008-01-08 19:38 靈! 閱讀(249) | 評論 (0)編輯 收藏

    如何做好質量保證工作(轉)

        軟件質量保證和軟件控制都是得罪人的工作,并不是太好的做。經常是費力不討好,最后人得罪了不少,力氣費了不少,成效不大。而很多質量保證人員也不得不離開所在的單位。很多著名的公司為了搞好質量工作,采用國外先進的管理方法進行質量保證,但也往往遇到水土不服的問題,因為這個問題下崗的高級管理人員也不是一個兩個了。為什么在國外很好的質量保證手段在中國就水土不服?為什么質量保證人員總是打一槍換一個地方(很多質量保證人員在一個地方工作的時間往往是2年左右)。如果我們一味強調客觀因素,而不是從我們自身找問題,是沒有辦法真正找到解決這個的方法的。下邊就我說說我自己的一些感受。

    1 質量保證工作,重流程,輕實施是我們的一個問題。

        現在的質量保證人員一般手里都不乏這樣或那樣的證書,拿我們軟件質量保證人員來說,最基本的是ISO9000的證書,然后是CMM/CMMI,似乎沒有這些證書就不適合搞質量保證工作。如果讓他們規范單位開發流程,他們在幾天之內就可以給你拿出一大堆流程文件來,而且可以保證這些問題是符合質量的要求。但一旦到了實施階段,就會發現這些流程不能適應公司的具體要求,不是太繁瑣,就是開發人員搞不明白,和技術人員矛盾不斷涌現,如果你的對手只是普通的技術人員那算你走運,你還可以挺幾年,但如果是和公司幾個核心的開發人員產生矛盾,那你準備卷鋪蓋走人吧。一個公司沒有質量保證人員不會死,但核心技術人員如果走了,公司就會面臨倒閉的問題,再傻的老板到這個時候都會揮淚斬馬謖的。所以,想真正實施好公司的質量保證一定要重流程,更重實施。

    2 質量保證工作,重知識,輕經驗。

        我這里說的知識是指質量保證知識,經驗是指實際工作經驗,拿我們做SQA的來說就是你的開發經驗,我遇到了很多SQA只有1-2年的開發經驗,或者干脆就沒有開發經驗。想一下,沒有調研經驗的人去給一幫參加過7,8個大項目調研的人將如何調研,一個沒有編寫過設計文檔的人,在給一群架構師講解如何設計軟件,一個沒有代碼編程經驗的人給一幫代碼量超過20萬行的程序員講代碼規范,你說是不是一個可笑的事情,開發人員都是很實在的人(甚至有時候可以說比較傻的人),他們長期的工作經驗使他們只信服那些實力比他們強的人,如果你有充足的實際工作經驗(軟件開發經驗),說的問題到位,能夠將質量保證理論和實際開發結合,可以幫助他們解決實際問題,他們很快就會接受你,否則他們會對你不屑一顧。而你的質量保證根本無法實施。

    3 質量保證人員不要搶功勞。

        一個公司就象一個盤子,盤子里的蛋糕就這么大。你進來了需要從別人的蛋糕里切一塊,別人自然會有反彈,作為質量保證人員在這個時候最好的方法就是退后一步,將功勞讓給開發人員。質量保證工作會涉及到公司的各個部門,各項工作,會影響公司幾乎所有的工作人員,如果在這個時候,你想把所有的功勞都搶到自己手里,會樹敵無數,一旦這種情況出現,一個是你的工作無法推行(基本沒有人支持你),另外一個就是你不得不離開這個公司了。但如果你是聰明人,你幫助開發人員不斷的改善他們的工作,他們可以很好的完成自己的開發工作,加班時間大大減少,產品質量不斷提高,不斷獲得客戶和領導的表揚,而且加了工資,你想在這種情況下,他們怎么會不配合你的工作?所以說,好的質量保證人員永遠是站在成功者背后的那個人,他默默地做著自己的工作,為別人做綠葉。一個良好的心態才能真正搞好質量保證工作。在這里再多說一句,任何人的功勞都會得到回報。當公司的整體質量提升了,公司的效益提高了,你覺得老板會不明白這是誰的功勞嗎?

    4 質量保證工作,不能一開始就全面開花,而要由點到線,由線到面。

        上邊說了質量保證工作會涉及到單位工作的各個方面,在你剛進入到公司的時候,立刻會發現很多問題,但如何著手,需要一個謀劃,一般來說比較容易見效果的,投入不大的方面是你首先要考慮的(有時候還不是公司最主要的質量問題)。如果你能在短時間讓別人看到你的工作效果,見到成果,認可你的實力,才可能和他們達成一定的協作關系,為以后的質量保證工作鋪平道路。另外需要說的,質量保證需要不斷的投入人力和物力,而這些東西在你剛進入公司的時候往往是不具備的,分清事情的輕重緩急,難易程度,逐步實施質量保證。可以保證你的工作的順利實施。

    5 做質量保證工作,最重要的是做人的工作,這里分兩個問題來說明,一個是你要有自己可信賴的人員。

        打鐵先要自身硬,做質量保證工作,不但你最好有技術背景,精通軟件開發,遵守公司的規章制度,你還要有一支可培養,可信賴的質量保證隊伍,一個人的精力和能力畢竟是有限的,而一旦你形成了一個良好的質量保證隊伍就可以保證你的工作越做越有成效。另外一個就是善于借力打力。上邊說過,絕大多數開發人員都渴望成功,他們缺少的只是經驗,將你的經驗和知識和他們分享,讓他們成為的朋友,成為工作的伙伴,成為你的編外質量人員,這對那些質量保證人員編制比較少的質量保證部門格外重要。

    6 質量保證工作,遇到問題,先解決問題,找出原因,進行改進,而不要一味地追查責任。

        質量保證人員的責任是改進質量工作,提高整個公司的工作效率,而不是老板,去追查這是誰的責任。當一個問題發生的時候,所有的人員都在往后躲。怕承擔責任,作為質量人員如果在這個時候,首先去追查責任,那你就大錯特錯了,首先我們要解決問題,看有什么補救的方法,先想辦法將事情辦好,然后仔細分析問題產生的原因,找到如何避免這個問題再次發生,至于責任在哪個責任人,自有具體的管理人員負責,這不是我們的責任,說簡單一點,我們的責任就是協助一切工作人員做好他們的工作,而不是給人員裹亂。

    posted @ 2008-01-08 19:31 靈! 閱讀(304) | 評論 (0)編輯 收藏

    SQA到底是什么?(轉)

    一、 前言

    本文作者在企業從事SQA工作,同時兼任SEPG的工作進行基于CMM3的過程改進,在實踐過程中,對SQA的工作有了較多的想法和認識。本文是個人看法,請大家指教,如果要和本人聯系,請發Email到:heqingemail@163.net

    二、SQA的理論探索

    2.1、過程的;認識

    我們都知道一個項目的主要內容是:成本、進度、質量;良好的項目管理就是綜合三方面的因素,平衡三方面的目標,最終依照目標完成任務。項目的這三個方面是相互制約和影響的,有時對這三方面的平衡策略甚至成為一個企業級的要求,決定了企業的行為,我們知道IBM的軟件是以質量為最重要目標的,而微軟的“足夠好的軟件”策略更是耳熟能詳,這些質量目標其實立足于企業的戰略目標。所以用于進行質量保證的SQA工作也應當立足于企業的戰略目標,從這個角度思考SQA,形成對SQA的理論認識。

    軟件界已經達成共識的:影響軟件項目進度、成本、質量的因素主要是“人、過程、技術”。
    首先要明確的是這三個因素中,人是第一位的。
    現在許多實施CMM的人員沉溺于CMM的理論過于強調“過程”,這是很危險的傾向。這個思想傾向在國外受到了猛烈抨擊,從某種意義上各種敏捷過程方法的提出就是對強調過程的一種反思。
    “XP”中的一個思想“人比過程更重要” 是值得我們思考的。我個人的意見在進行過程改進中堅持“以人為本”,強調過程和人的和諧。
    根據現代軟件工程對眾多失敗項目的調查,發現管理是項目失敗的主要原因。這個事實的重要性在于說明了“要保證項目不失敗,我們應當更加關注管理”,注意這個事實沒有說明另外一個問題“良好的管理可以保證項目的成功”?,F在很多人基于一種粗糙的邏輯,從一個事實反推到的這個結論,在邏輯上是錯誤的,這種錯誤形成了更加錯誤的做法,這點在SQA的理解上是體現較深。
    如果我們考證一下歷史的沿革,應當更加容易理解CMM的本質。CMM首先是作為一個“評估標準”出現的,主要評估的是美國國防部供應商保證質量的能力。CMM關注的軟件生產有如下特點:
    質量重要
    規模較大
    這是CMM產生的原因。它引入了“全面質量管理”的思想,尤其側重了“全面質量管理”中的“過程方法”,并且引入了“統計過程控制”的方法??梢哉f這兩個思想是CMM背后的基礎。
    上面這些內容形成了我對軟件過程地位、價值的基本理解;在這個基礎上我們可以引申討論SQA。

    2.2、生產線的隱喻

    如果將一個軟件生產類比于一個工廠的生產。那么生產線就是過程,產品按照生產線的規定過程進行生產。SQA的職責就是保證過程的執行,也就是保證生產線的正常執行。
    抽象出管理體系模型的如下,這個模型說明了一個過程體系至少應當包含“決策、執行、反饋”三個重要方面。QA的職責就是確保過程的有效執行,監督項目按照過程進行項目活動;它不負責監管產品的質量,不負責向管理層提供項目的情況,不負責代表管理層進行管理,只是代表管理層來保證過程的執行。

    2.3、SQA和其他工作的組合

    在很多企業中,將SQA的工作和QC、SEPG、組織級的項目管理者的工作混合在一起了,有時甚至更加注重其他方面的工作而沒有做好SQA的本職工作。
    根據hjhza 的意見“中國現在基本有三種QA(按照工作重點不同來分):一是過程改進型,一是配置管理型,一是測試型”。我個人認為是因為SQA工作和其他不同工作組合在一起形成的。
    下面根據本人經驗對它們之間的關系進行一個說明。

    2.4、QA和QC

    兩者基本職責
    QC:檢驗產品的質量,保證產品符合客戶的需求;是產品質量檢查者;
    QA:審計過程的質量,保證過程被正確執行;是過程質量審計者;
    注意區別檢查和審計的不同
    檢查:就是我們常說的找茬,是挑毛病的;
    審計:來確認項目按照要求進行的證據;仔細看看CMM中各個KPA中SQA的檢查采用的術語大量用到了“證實”,審計的內容主要是過程的;對照CMM看一下項目經理和高級管理者的審查內容,他們更加關注具體內容。

    對照上面的管理體系模型,QC進行質量控制,向管理層反饋質量信息;QA則確保QC按照過程進行質量控制活動,按照過程將檢查結果向管理層匯報。這就是QA和QC工作的關系。在這樣的分工原則下,QA只要檢查項目按照過程進行了某項活動沒有,產出了某個產品沒有;而QC來檢查產品是否符合質量要求。如果企業原來具有QC人員并且QA人員配備不足,可以先確定由QC兼任QA工作。但是只能是暫時的,獨立的QA人員應當具備,因為QC工作也是要遵循過程要求的,也是要被審計過程的,這種混合情況,難以保證QC工作的過程質量。

    2.5、QA和SEPG

    兩者基本職責

    SEPG:制定過程,實施過程改進;
    QA: 確保過程被正確執行

    SEPG應當提供過程上的指導,幫助項目組制定項目過程,幫助項目組進行策劃;從而幫助項目組有效的工作,有效的執行過程。如果項目和QA對過程的理解發生爭持,SEPG作為最終仲裁者。為了進行有效過程改進,SEPG必須分析項目的數據。

    QA本也要進行過程規范,那么所有QA中最有經驗、最有能力的QA可以參加SEPG,但是要注意這兩者的區別。

    如果企業的SEPG人員具有較為深厚的開發背景,可以兼任SQA工作,這樣利于過程的不斷改進;但是由于立法、執法集于一身也容易造成SQA過于強勢,影響項目的獨立性。管理過程比較成熟的企業,因為企業的文化和管理機制已經健全,SQA職責范圍的工作較少,往往只是針對具體項目制定明確重點的SQA計劃,這樣SQA的審計工作會大大減少,從而可以同時審計較多項目。

    另一方面,由于分工的細致化,管理體系的復雜化,往往需要專職的SEPG人員,這些人員要求了解企業的所有管理過程和運作情況,在這個基礎上才能統籌全局的進行過程改進,這時了解全局的SQA人員就是專職SEPG的主要人選;這些SQA人員將逐漸的轉化為SEPG人員,并且更加了解管理知識,而SQA工作漸漸成為他們的兼職工作。

    這種情況在許多CMM5企業比較多見,往往有時看不見SQA人員在項目組出現或者很少出現,這種SEPG和SQA的融合特別有利于組織的過程改進工作。SEPG確定過程改進內容,SQA計劃重點反映這些改進內容,從保證有效的改進,特別有利于達到CMM5的要求。從這個角度,國外的SQA人員為什么高薪就不難理解了,也決定了當前中國SQA人員比較被輕視的原因;因為管理過程還不完善,我們的SQA人員還沒有產生這么大的價值嘛!

    2.6、QA和組織級的監督管理

    有的企業為了更好的監督管理項目,建立了一個角色,我取名為“組織級的監督管理者”,他們的職責是對所有項目進行統一的跟蹤、監督、適當的管理,來保證管理層對所有項目的可視性、可管理性。

    為了有效管理項目,“組織級的監督管理者”必須分析項目的數據。

    他們的職責對照上圖的模型,就是執行“反饋”職能。

    QA本身不進行反饋工作,最多對過程執行情況的信息進行反饋。

    SQA職責最好不要和“組織級的項目管理者”的職責混合在一起,否則容易出現SAQ困境:一方面SQA不能準確定位自己的工作,另一方面過程執行者對SQA人員抱有較大戒心。

    如果建立了較好的管理過程,那么就會增強項目的可視性,從而保證企業對所有項目的較好管理;而QA來確保這個管理過程的運行。

    三、SQA的工作內容和工作方法

    3.1、 計劃

    針對具體項目制定SQA計劃,確保項目組正確執行過程。制定SQA計劃應當注意如下幾點:
    有重點:依據企業目標以及項目情況確定審計的重點
    明確審計內容:明確審計哪些活動,那些產品
    明確審計方式:確定怎樣進行審計
    明確審計結果報告的規則:審計的結果報告給誰

    3.2、審計/證實

    依據SQA計劃進行SQA審計工作,按照規則發布審計結果報告。
    注意審計一定要有項目組人員陪同,不能搞突然襲擊。雙方要開誠布公,坦誠相對。
    審計的內容:是否按照過程要求執行了相應活動,是否按照過程要求產生了相應產品。

    3.3、問題跟蹤
    對審計中發現的問題,要求項目組改進,并跟進直到解決。

    四、SQA的素質

    過程為中心:應當站在過程的角度來考慮問題,只要保證了過程,QA就盡到了責任。

    服務精神:為項目組服務,幫助項目組確保正確執行過程
    了解過程:深刻了解企業的工程,并具有一定的過程管理理論知識
    了解開發:對開發工作的基本情況了解,能夠理解項目的活動
    溝通技巧:善于溝通,能夠營造良好的氣氛,避免審計活動成為一種找茬活動。

    posted @ 2008-01-08 19:31 靈! 閱讀(271) | 評論 (0)編輯 收藏

    僅列出標題
    共6頁: 上一頁 1 2 3 4 5 6 下一頁 
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    導航

    統計

    隨筆分類

    隨筆檔案

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲伊人久久大香线蕉综合图片| 亚洲精品自产拍在线观看动漫| 一级视频免费观看| 亚洲成A人片在线观看WWW| 4hu四虎最新免费地址| 在线亚洲精品视频| 亚洲国产一区二区三区青草影视| 丁香花在线观看免费观看| 亚洲天堂免费在线视频| 亚洲国产精品一区二区久| 亚洲国产成人久久综合野外| 99久久免费中文字幕精品| 国产大陆亚洲精品国产| 亚洲男人天堂影院| 久久精品国产亚洲5555| 青青草免费在线视频| 中国国产高清免费av片| 亚洲精品色播一区二区| 久久综合日韩亚洲精品色| 亚洲Aⅴ无码一区二区二三区软件| 最近中文字幕大全免费视频| 麻豆va在线精品免费播放| 亚洲欧洲国产经精品香蕉网| 亚洲一区二区三区乱码A| 青青青国产在线观看免费网站 | 亚洲国产成+人+综合| 亚洲午夜国产片在线观看| 中文字幕无码不卡免费视频| 青青操在线免费观看| 成人精品国产亚洲欧洲| 亚洲av无码一区二区三区天堂古代| 亚洲人成无码www久久久| 在线免费观看一级片| 美丽的姑娘免费观看在线播放| 免费一级毛片在线播放放视频| 中文字幕亚洲码在线| 91亚洲精品第一综合不卡播放| 国产亚洲AV手机在线观看| 亚洲福利视频一区二区| 麻豆国产精品入口免费观看| 野花高清在线观看免费完整版中文|