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

這樣寫代碼,比直接使用 MyBatis 效率提高了 100 倍 !

開發 后端
本文會給出一個比直接使用這些 ORM 開發效率至少會提高 100 倍的方法(絕無夸張)。

[[439333]]

對一個 Java 后端程序員來說,MyBatis、Hibernate、Data Jdbc 等都是我們常用的 ORM 框架。它們有時候很好用,比如簡單的 CRUD,事務的支持都非常棒。

但有時候用起來也非常繁瑣,比如接下來我們要聊到的一個常見的開發需求,而對這類需求,本文會給出一個比直接使用這些 ORM 開發效率至少會提高 100 倍的方法(絕無夸張)。

首先數據庫有兩張表

用戶表(user):(簡單起見,假設只有 4 個字段)

字段名 類型 含義
id bitint 用戶 ID
name varchar(45) 用戶名
age int 年齡
role_id int 角色 ID

角色表(role):(簡單起見,假設只有 2 個字段)

字段名 類型 含義
id int 角色 ID
name varchar(45) 角色名

接下來我們要實現一個用戶查詢的功能

這個查詢有點復雜,它的要求如下:

  •  可按用戶名
  •     字段查詢,要求:
    •  可精確匹配(等于某個值)
    •  可全模糊匹配(包含給定的值)
    •  可后模糊查詢(以...開頭)
    •  可前模糊查詢(以.. 結尾)
    •  可指定以上四種匹配是否可以忽略大小寫
  •   可按年齡
  •     字段查詢,要求:
    •   可精確匹配(等于某個年齡)
    •   可大于匹配(大于某個值)
    •   可小于匹配(小于某個值)
    •   可區間匹配(某個區間范圍)
  •  可按角色ID查詢,要求:精確匹配
  •  可按用戶ID查詢,要求:同年齡字段
  •  可指定只輸出哪些列(例如,只查詢 ID 與 用戶名 列)
  •  支持分頁(每次查詢后,頁面都要顯示滿足條件的用戶總數)
  •  查詢時可選擇按  ID、用戶名、年齡 等任意字段排序

后端接口該怎么寫呢?

試想一下,對于這種要求的查詢,后端接口里的代碼如果用 MyBatis、Hibernate、Data Jdbc 直接來寫的話,100 行代碼 能實現嗎?

反正我是沒這個信心,算了,我還是直接坦白,面對這種需求后端如何 只用一行代碼搞定 吧(有興趣的同學可以 MyBatis 等寫個試試,最后可以對比一下)

手把手:只一行代碼實現以上需求

首先,重點人物出場啦:Bean Searcher,  它就是專門來對付這種列表檢索的,無論簡單的還是復雜的,統統一行代碼搞定!而且它還非常輕量,Jar 包體積僅不到 100KB,無第三方依賴。

假設我們項目使用的框架是 Spring Boot(當然 Bean Searcher 對框架沒有要求,但在 Spring Boot 中使用更加方便)

Spring Boot 基礎就不介紹了,推薦下這個實戰教程: https://github.com/javastacks/spring-boot-best-practice

添加依賴

Maven : 

  1. <dependency>  
  2.     <groupId>com.ejlchina</groupId>  
  3.     <artifactId>bean-searcher-boot-starter</artifactId>  
  4.     <version>3.1.2</version> 
  5. </dependency> 

Gradle : 

  1. implementation 'com.ejlchina:bean-searcher-boot-starter:3.1.2' 

然后寫個實體類來承載查詢的結果 

  1. @SearchBean(tables="user u, role r"joinCond="u.role_id = r.id"autoMapTo="u" 
  2. public class User {  
  3.     private Long id;  // 用戶ID(u.id)  
  4.     private String name; // 用戶名(u.name)  
  5.     private int age;  // 年齡(u.age)  
  6.     private int roleId;  // 角色ID(u.role_id)  
  7.     @DbField("r.name")  // 指明這個屬性來自 role 表的 name 字段  
  8.     private String role;        // 角色名(r.name)  
  9.     // Getter and Setter ...  

接著就可以寫用戶查詢接口了

接口路徑就叫 /user/index 吧: 

  1. @RestController  
  2. @RequestMapping("/user")  
  3. public class UserController {  
  4.     @Autowired  
  5.     private MapSearcher mapSearcher;  // 注入檢索器(由 bean-searcher-boot-starter 提供)  
  6.     @GetMapping("/index")  
  7.     public SearchResult<Map<String, Object>> index(HttpServletRequest request) {  
  8.      // 這里咱們只寫一行代碼  
  9.         return mapSearcher.search(User.class, MapUtils.flat(request.getParameterMap()));  
  10.     }  

上述代碼中的 MapUtils 是 Bean Searcher 提供的一個工具類,MapUtils.flat(request.getParameterMap()) 只是為了把前端傳來的請求參數統一收集起來,然后剩下的,就全部交給 MapSearcher 檢索器了。最新面試題整理好了,大家可以在Java面試庫小程序在線刷題。

這樣就完了?那我們來測一下這個接口,看看效果吧

(1)無參請求

  •  GET /user/index
  •  返回結果: 
  1.  
  2.     "dataList": [           // 用戶列表,默認返回第 0 頁,默認分頁大小為 15 (可配置)  
  3.         { "id": 1, "name": "Jack", "age": 25, "roleId": 1, "role": "普通用戶" },  
  4.         { "id": 2, "name": "Tom", "age": 26, "roleId": 1, "role": "普通用戶" },  
  5.         ...  
  6.     ],  
  7.     "totalCount": 100       // 用戶總數  

(2)分頁請求(page | size)

  •  GET /user/index? page=2 & size=10
  •  返回結果:結構同 (1)(只是每頁 10 條,返回第 2 頁)

參數名 size 和 page 可自定義, page 默認從 0 開始,同樣可自定義,并且可與其它參數組合使用。Spring Boot 學習筆記,這個分享給你。

(3)數據排序(sort | order)

  •  GET /user/index? sort=age & order=desc
  •  返回結果:結構同 (1)(只是 dataList 數據列表以 age 字段降序輸出)

參數名 sort 和 order 可自定義,可與其它參數組合使用

(4)指定(排除)字段(onlySelect | selectExclude)

  •  GET /user/index? onlySelect=id,name,role
  •  GET /user/index? selectExclude=age,roleId
  •  返回結果:( 列表只含 id,name 與 role 三個字段) 
  1.  
  2.     "dataList": [           // 用戶列表,默認返回第 0 頁(只包含 id,name,role 字段)  
  3.         { "id": 1, "name": "Jack", "role": "普通用戶" },  
  4.         { "id": 2, "name": "Tom", "role": "普通用戶" },  
  5.         ...  
  6.     ],  
  7.     "totalCount": 100       // 用戶總數  

參數名 onlySelect 和 selectExclude 可自定義,可與其它參數組合使用

(5)字段過濾(op = eq)

  •  GET /user/index? age=20
  •  GET /user/index? age=20 & age-op=eq
  •  返回結果:結構同 (1)(但只返回 age = 20 的數據)

參數 age-op = eq 表示 age 的 字段運算符 是 eq(Equal 的縮寫),表示參數 age 與參數值 20 之間的關系是 Equal,由于 Equal 是一個默認的關系,所以 age-op = eq 也可以省略

參數名 age-op 的后綴 -op 可自定義,且可與其它字段參數 和 上文所列的參數(分頁、排序、指定字段)組合使用,下文所列的字段參數也是一樣,不再復述。

(6)字段過濾(op = ne)

  •  GET /user/index? age=20 & age-op=ne
  •  返回結果:結構同 (1)(但只返回 age != 20 的數據,ne 是 NotEqual 的縮寫)

(7)字段過濾(op = ge)

  •  GET /user/index? age=20 & age-op=ge
  •  返回結果:結構同 (1)(但只返回 age >= 20 的數據,ge 是 GreateEqual 的縮寫)

(8)字段過濾(op = le)

  •  GET /user/index? age=20 & age-op=le
  •  返回結果:結構同 (1)(但只返回 age <= 20 的數據,le 是 LessEqual 的縮寫)

(9)字段過濾(op = gt)

  •  GET /user/index? age=20 & age-op=gt
  •  返回結果:結構同 (1)(但只返回 age > 20 的數據,gt 是 GreateThan 的縮寫)

(10)字段過濾(op = lt)

  •  GET /user/index? age=20 & age-op=lt
  •  返回結果:結構同 (1)(但只返回 age < 20 的數據,lt 是 LessThan 的縮寫)

(11)字段過濾(op = bt)

  •  GET /user/index? age-0=20 & age-1=30 & age-op=bt
  •  GET /user/index? age=[20,30] & age-op=bt(簡化版,[20,30] 需要 UrlEncode, 參考下文)
  •  返回結果:結構同 (1)(但只返回 20 <= age <= 30 的數據,bt 是 Between 的縮寫)

參數 age-0 = 20 表示 age 的第 0 個參數值是 20。上述提到的 age = 20 實際上是 age-0 = 20 的簡寫形式。另:參數名 age-0 與 age-1 中的連字符 - 可自定義。

(12)字段過濾(op = mv)

  •  GET /user/index? age-0=20 & age-1=30 & age-2=40 & age-op=mv
  •  GET /user/index? age=[20,30,40] & age-op=mv(簡化版,[20,30,40] 需要 UrlEncode, 參考下文)
  •  返回結果:結構同 (1)(但只返回 age in (20, 30, 40) 的數據,mv 是 MultiValue 的縮寫,表示有多個值的意思)

(13)字段過濾(op = in)

  •  GET /user/index? name=Jack & name-op=in
  •  返回結果:結構同 (1)(但只返回 name 包含 Jack 的數據,in 是 Include 的縮寫)

(14)字段過濾(op = sw)

  •  GET /user/index? name=Jack & name-op=sw
  •  返回結果:結構同 (1)(但只返回 name 以 Jack 開頭的數據,sw 是 StartWith 的縮寫)

(15)字段過濾(op = ew)

  •  GET /user/index? name=Jack & name-op=ew
  •  返回結果:結構同 (1)(但只返回 name 以 Jack 結尾的數據,sw 是 EndWith 的縮寫)

(16)字段過濾(op = ey)

  • GET /user/index? name-op=ey
  •  返回結果:結構同 (1)(但只返回 name 為空 或為 null 的數據,ey 是 Empty 的縮寫)

(17)字段過濾(op = ny)

  •  GET /user/index? name-op=ny
  •  返回結果:結構同 (1)(但只返回 name 非空 的數據,ny 是 NotEmpty 的縮寫)

(18)忽略大小寫(ic = true)

  •  GET /user/index? name=Jack & name-ic=true
  •  返回結果:結構同 (1)(但只返回 name 等于 Jack (忽略大小寫) 的數據,ic 是 IgnoreCase 的縮寫)

參數名 name-ic 中的后綴 -ic 可自定義,該參數可與其它的參數組合使用,比如這里檢索的是 name 等于 Jack 時忽略大小寫,但同樣適用于檢索 name 以 Jack 開頭或結尾時忽略大小寫。

當然,以上各種條件都可以組合,例如

查詢 name 以 Jack (忽略大小寫) 開頭,且 roleId = 1,結果以 id 字段排序,每頁加載 10 條,查詢第 2 頁:

  •  GET /user/index? name=Jack & name-op=sw & name-ic=true & roleId=1 & sort=id & size=10 & page=2
  •  返回結果:結構同 (1)

OK,效果看完了,/user/index 接口里我們確實只寫了一行代碼,它便可以支持這么多種的檢索方式,有沒有覺得現在 你寫的一行代碼 就可以 干過別人的一百行 呢?

[[439334]]

Bean Searcher

本例中,我們只使用了 Bean Searcher 提供的 MapSearcher 檢索器的一個檢索方法,其實,它還有很多檢索方法。

檢索方法

  •  searchCount(Class<T> beanClass, Map<String, Object> params) 查詢指定條件下的數據 總條數
  •  searchSum(Class<T> beanClass, Map<String, Object> params, String field) 查詢指定條件下的 某字段 的 統計值
  •  searchSum(Class<T> beanClass, Map<String, Object> params, String[] fields) 查詢指定條件下的 多字段 的 統計值
  •  search(Class<T> beanClass, Map<String, Object> params) 分頁 查詢指定條件下數據 列表 與 總條數
  •  search(Class<T> beanClass, Map<String, Object> params, String[] summaryFields) 同上 + 多字段 統計
  •  searchFirst(Class<T> beanClass, Map<String, Object> params) 查詢指定條件下的 第一條 數據
  •  searchList(Class<T> beanClass, Map<String, Object> params) 分頁 查詢指定條件下數據 列表
  •  searchAll(Class<T> beanClass, Map<String, Object> params) 查詢指定條件下 所有 數據 列表

MapSearcher 與 BeanSearcher

另外,Bean Searcher 除了提供了 MapSearcher 檢索器外,還提供了 BeanSearcher 檢索器,它同樣擁有 MapSearcher 所有的方法,只是它返回的單條數據不是 Map,而是一個 泛型 對象。

參數構建工具

另外,如果你是在 Service 里使用 Bean Searcher,那么直接使用 Map<String, Object> 類型的參數可能不太優雅,為此, Bean Searcher 特意提供了一個參數構建工具。

最新面試題整理好了,大家可以在Java面試庫小程序在線刷題。

例如,同樣查詢 name 以 Jack (忽略大小寫) 開頭,且 roleId = 1,結果以 id 字段排序,每頁加載 10 條,加載第 2 頁,使用參數構建器,代碼可以這么寫: 

  1. Map<String, Object> params = MapUtils.builder()  
  2.         .field(User::getName, "Jack").op(Operator.StartWith).ic()  
  3.         .field(User::getRoleId, 1)  
  4.         .orderBy(User::getId, "asc")  
  5.         .page(2, 10)  
  6.         .build()  
  7. List<User> users = beanSearcher.searchList(User.class, params); 

這里使用的是 BeanSearcher 檢索器,以及它的 searchList(Class<T> beanClass, Map<String, Object> params) 方法。

運算符約束

上文我們看到,Bean Searcher 對實體類中的每一個字段,都直接支持了很多的檢索方式。

但某同學:哎呀!檢索方式太多了,我根本不需要這么多,我的數據量幾十億,用戶名字段的前模糊查詢方式利用不到索引,萬一把我的數據庫查崩了怎么辦呀?

好辦,Bean Searcher 支持運算符的約束,實體類的用戶名 name 字段只需要注解一下即可: 

  1. @SearchBean(tables="user u, role r"joinCond="u.role_id = r.id"autoMapTo="u" 
  2. public class User {  
  3.     @DbField(onlyOn = {Operator.Equal, Operator.StartWith})  
  4.     private String name;  
  5.     // 為減少篇幅,省略其它字段...  

如上,通過 @DbField 注解的 onlyOn 屬性,指定這個用戶名 name 只能適用與 精確匹配 和 后模糊查詢,其它檢索方式它將直接忽略。Spring Boot 學習筆記,這個分享給你。

上面的代碼是限制了 name 只能有兩種檢索方式,如果再嚴格一點,只允許 精確匹配,那其實有兩種寫法。

(1)還是使用運算符約束: 

  1. @SearchBean(tables="user u, role r"joinCond="u.role_id = r.id"autoMapTo="u" 
  2. public class User {  
  3.     @DbField(onlyOn = Operator.Equal)  
  4.     private String name;  
  5.     // 為減少篇幅,省略其它字段...  

(2)在 Controller 的接口方法里把運算符參數覆蓋: 

  1. @GetMapping("/index")  
  2. public SearchResult<Map<String, Object>> index(HttpServletRequest request) {  
  3.     Map<String, Object> params = MapUtils.flatBuilder(request.getParameterMap())  
  4.         .field(User::getName).op(Operator.Equal)   // 把 name 字段的運算符直接覆蓋為 Equal  
  5.         .build()  
  6.     return mapSearcher.search(User.class, params);  

條件約束

該同學又:哎呀!我的數據量還是很大,age 字段沒有索引,我不想讓它參與 where 條件,不然很可能就出現慢 SQL 啊!

不急,Bean Searcher 還支持條件的約束,讓這個字段直接不能作為條件: 

  1. @SearchBean(tables="user u, role r"joinCond="u.role_id = r.id"autoMapTo="u" 
  2. public class User {  
  3.     @DbField(conditional = false 
  4.     private int age;  
  5.     // 為減少篇幅,省略其它字段...  

如上,通過 @DbField 注解的 conditional 屬性, 就直接不允許 age 字段參與條件了,無論前端怎么傳參,Bean Searcher 都不搭理。

最新面試題整理好了,大家可以在Java面試庫小程序在線刷題。

參數過濾器

該同學仍:哎呀!哎呀 ...

別怕! Bean Searcher 還支持配置全局參數過濾器,可自定義任何參數過濾規則,在 Spring Boot 項目中,只需要配置一個 Bean: 

  1. @Bean  
  2. public ParamFilter myParamFilter() {  
  3.     return new ParamFilter() {  
  4.         @Override  
  5.         public <T> Map<String, Object> doFilter(BeanMeta<T> beanMeta, Map<String, Object> paraMap) {  
  6.             // beanMeta 是正在檢索的實體類的元信息, paraMap 是當前的檢索參數  
  7.             // TODO: 這里可以寫一些自定義的參數過濾規則  
  8.             return paraMap;      // 返回過濾后的檢索參數  
  9.         }  
  10.     };  

某同學問

參數咋這么怪,這么多呢,和前端有仇么

參數名是否奇怪,這其實看個人喜好,如果你不喜歡中劃線 -,不喜歡 op、ic 后綴,完全可以自定義,參考這篇文檔:

searcher.ejlchina.com/guide/lates…

  1.  參數個數的多少,其實是和需求的復雜程度相關的。如果需求很簡單,那么很多參數沒必要讓前端傳,后端直接塞進去就好。比如:name 只要求后模糊匹配,age 只要求區間匹配,則可以: 

  1. @GetMapping("/index")  
  2. public SearchResult<Map<String, Object>> index(HttpServletRequest request) {  
  3.     Map<String, Object> params = MapUtils.flatBuilder(request.getParameterMap())  
  4.         .field(User::getName).op(Operator.StartWith)  
  5.         .field(User::getAge).op(Operator.Between)  
  6.         .build()  
  7.     return mapSearcher.search(User.class, params);  

這樣前端就不用傳 name-op 與 age-op 這兩個參數了。

其實還有一種更簡單的方法,那就是 運算符約束(當約束存在時,運算符默認就是 onlyOn 屬性中指定的第一個值,前端可以省略不傳): 

  1. @SearchBean(tables="user u, role r"joinCond="u.role_id = r.id"autoMapTo="u" 
  2. public class User { 
  3.     @DbField(onlyOn = Operator.StartWith)  
  4.     private String name;  
  5.     @DbField(onlyOn = Operator.Between)  
  6.     private String age;  
  7.     // 為減少篇幅,省略其它字段...  

   2.  對于 op=bt/mv 的多值參數傳遞,參數確實可以簡化,例如:

  •  把 age-0=20 & age-1=30 & age-op=bt 簡化為 age=[20,30] & age-op=bt,
  •  把 age-0=20 & age-1=30 & age-2=40 & age-op=mv 簡化為 age=[20,30,40] & age-op=mv,

簡化方法:只需配置一個 ParamFilter(參數過濾器)即可,具體代碼可以參考這里:

https://github.com/ejlchina/bean-searcher/issues/10

入參是 request,我 swagger 文檔不好渲染了呀

其實,Bean Searcher 的檢索器只是需要一個 Map<String, Object> 類型的參數,至于這個參數是怎么來的,和 Bean Searcher 并沒有直接關系。前文之所以從 request 里取,只是因為這樣代碼看起來簡潔,如果你喜歡聲明參數,完全可以把代碼寫成這樣: 

  1. @GetMapping("/index")  
  2. public SearchResult<Map<String, Object>> index(Integer page, Integer size,  
  3.             String sort, String order, String name, Integer roleId,  
  4.             @RequestParam(value = "name-op"required = false) String name_op,  
  5.             @RequestParam(value = "name-ic"required = false) Boolean name_ic,  
  6.             @RequestParam(value = "age-0"required = false) Integer age_0,  
  7.             @RequestParam(value = "age-1"required = false) Integer age_1,  
  8.             @RequestParam(value = "age-op"required = false) String age_op) {  
  9.     Map<String, Object> params = MapUtils.builder()  
  10.         .field(Employee::getName, name).op(name_op).ic(name_ic)  
  11.         .field(Employee::getAge, age_0, age_1).op(age_op)  
  12.         .field(Employee::getRoleId, roleId)  
  13.         .orderBy(sort, order)  
  14.         .page(page, size)  
  15.         .build();  
  16.     return mapSearcher.search(User.class, params);  

字段參數之間的關系都是 “且” 呀,那 “或” 呢? “且” “或” 任意組合呢?

上文所述的字段參數之間確是都是 "且" 的關系,至于 “或”,雖然這種使用場景不太多,但 Bean Searcher 也是支持的,詳細可以參考這篇文章:

 https://github.com/ejlchina/bean-searcher/issues/8

這里就不再復述了。

開發效率真的提高 100 倍了嗎?

從本例其實可以看出,效率提升的程度依賴于檢索需求的復雜度。需求越復雜,則效率提高倍數越多,反之則越少,如果需求超級復雜,則提高 1000 倍都有可能。

但即使我們日常開發中沒有如此復雜的需求,開發效率只提升了 5 到 10 倍,那是不是也非常可觀呢?

結語

本文介紹了 Bean Searcher 在復雜列表檢索領域的超強能力。它之所以可以極大提高這類需求的研發效率,根本上歸功于它 獨創 的 動態字段運算符 與 多表映射機制,這是傳統 ORM 框架所沒有的。但由于篇幅所限,它的特性本文不能盡述,比如它還:

  •  支持 聚合查詢
  •  支持 Select|Where|From子查詢
  •  支持 實體類嵌入參數
  •  支持 字段轉換器
  •  支持 Sql 攔截器
  •  支持 數據庫 Dialect 擴展
  •  支持 多數據源
  •  支持 自定義注解
  •  等等

Bean Searcher 是我在工作中總結封裝出來的一個小工具,公司內部使用了 4 年,經歷大小項目三四十個,只是最近才著手完善文檔分享給大家,如果你喜歡,一定去點個 Star 哦 ^_^。 

 

責任編輯:龐桂玉 來源: Java技術棧
相關推薦

2019-06-21 08:39:23

SQLmysql索引

2020-06-12 14:44:06

線程池模式nginx

2020-06-11 08:05:47

nginx線程池數據

2024-02-07 13:37:39

AWS系統應用程序

2024-05-11 09:24:15

性能Go團隊

2012-05-02 12:39:31

無線網絡多跳無線網絡數據傳輸

2012-05-02 11:09:38

無線網絡數據傳輸

2024-08-07 08:51:20

Go優化開發

2024-07-12 11:44:39

2017-05-31 15:36:59

5G頻譜傳感器

2020-02-25 16:51:34

Rust廣告攔截器瀏覽器

2019-12-10 09:47:51

IaaS云計算物聯網

2020-12-24 19:29:08

PCIntel芯片

2023-05-04 07:34:37

Rust代碼CPU

2020-02-25 17:40:52

Python循環內存

2020-08-21 10:59:10

微軟服務器運維

2025-06-10 17:07:44

2021-07-28 14:35:09

代碼進度條前端

2020-09-02 08:27:58

CSS 屬性前端
點贊
收藏

51CTO技術棧公眾號

亚洲电影在线看| 五月综合激情网| 97超级碰碰| 日韩网红少妇无码视频香港| 少妇精品久久久| 在线播放中文字幕一区| 超碰成人免费在线| 999国产在线视频| 粉嫩一区二区三区性色av| 琪琪第一精品导航| 国产人妻精品一区二区三区不卡| 国产精品丝袜在线播放| 欧美三片在线视频观看| 日本一本中文字幕| 在线免费观看黄| 99精品国产99久久久久久白柏 | 一区不卡视频| 天天操天天干天天| 激情综合色综合久久| 欧美在线性爱视频| 全网免费在线播放视频入口| 欧美亚洲精品在线| 精品国产乱码91久久久久久网站| 国产aaaaa毛片| 秋霞伦理一区| 亚洲最快最全在线视频| 亚洲欧美日韩另类精品一区二区三区| 五十路在线观看| 国产黄色精品视频| 国产日韩欧美日韩大片| 国产伦精品一区二区三区视频我| 激情久久久久久久| 俺也去精品视频在线观看| 国产精品毛片一区二区| 麻豆一区二区| 日韩免费高清视频| 久久婷婷中文字幕| 激情欧美一区二区三区黑长吊| 欧美午夜视频在线观看| 国产精品12345| 国产盗摄在线视频网站| 一区二区欧美在线观看| av中文字幕av| av免费在线观看网址| 最新成人av在线| 夜夜春亚洲嫩草影视日日摸夜夜添夜| 国产亚洲依依| 欧美韩国日本一区| 日韩精品久久久免费观看 | 宅男66日本亚洲欧美视频| 亚洲蜜桃精久久久久久久久久久久| 大桥未久女教师av一区二区| 欧美不卡在线视频| 中文字幕人妻无码系列第三区| 亚洲色图图片| 欧美一级在线视频| 亚洲精品乱码久久久久久9色| 秋霞影院一区| 日韩视频免费观看高清完整版在线观看| 五月天视频在线观看| 亚洲欧美在线人成swag| 欧美高清精品3d| 日韩高清第一页| 欧美电影院免费观看| 欧美一级日韩免费不卡| 国产精品偷伦视频免费观看了| 亚洲综合网站| 日韩av一区在线观看| 中文人妻一区二区三区| 久久99国产精品视频| 在线看国产精品| 亚洲欧美精品aaaaaa片| 午夜精品偷拍| 欧美一区视频在线| 中文字幕精品无码亚| 久久99久久99精品免视看婷婷| 成人午夜一级二级三级| 亚洲成人久久精品| 成人a区在线观看| 日本欧洲国产一区二区| 日本天堂在线观看| 樱花草国产18久久久久| 日韩avxxx| 在线观看亚洲精品福利片| 精品人在线二区三区| 国产ts丝袜人妖系列视频| 国产在线观看91一区二区三区 | 欧美成人aaaaⅴ片在线看| 一本色道久久综合亚洲精品高清| 国产成人欧美在线观看| 一级黄在线观看| 成人精品视频一区二区三区尤物| 欧美欧美一区二区| 日本视频在线观看| 午夜电影一区二区三区| 看欧美ab黄色大片视频免费| 国产日韩欧美中文在线| 亚洲第一区第一页| 特级西西人体高清大胆| 欧美视频亚洲视频| 国产精品白嫩初高中害羞小美女 | 亚洲天堂日韩av| 蜜臀av在线播放一区二区三区| 99久热re在线精品视频| 成年人在线观看网站| 亚洲制服欧美中文字幕中文字幕| 一本久道中文无码字幕av| 成人永久在线| 亚洲人精品午夜在线观看| 亚洲国产成人精品综合99| 亚洲尤物在线| 999热视频在线观看| 久热av在线| 一区二区免费看| 一区二区xxx| 日韩精品免费一区二区三区竹菊 | 激情久久五月天| 精品一区二区国产| 2024最新电影免费在线观看| 在线中文字幕不卡| 国产一级免费片| 综合一区在线| 国产精品亚洲网站| 亚洲 欧美 自拍偷拍| 一区二区三区**美女毛片| 亚洲欧美在线精品| 亚洲性视频大全| 97国产精品视频人人做人人爱| 国产婷婷在线视频| 亚洲欧美在线另类| mm1313亚洲国产精品无码试看| 久久久久97| 韩日精品中文字幕| 国产福利免费视频| 亚洲四区在线观看| 特级丰满少妇一级| 欧美偷拍自拍| 国产精品美女999| 黄色软件在线观看| 色婷婷综合久久久中文字幕| 变态另类丨国产精品| 亚洲人体大胆视频| 国产一区二区三区四区五区在线| 免费不卡av| 欧美大片免费久久精品三p| 欧美爱爱小视频| 国产乱色国产精品免费视频| 波多野结衣激情| 成人在线视频区| 久久艳片www.17c.com | 亚洲天堂网站在线观看视频| 午夜婷婷在线观看| 久久亚洲影视婷婷| 久久无码高潮喷水| 九九亚洲视频| 国产精品黄色av| aaa在线免费观看| 欧美午夜在线观看| 国产3级在线观看| 激情五月婷婷综合网| 潘金莲一级淫片aaaaa免费看| 日韩城人网站| 欧美美女15p| 色欲av伊人久久大香线蕉影院| 亚洲国产成人91porn| 国产xxxx视频| 日日夜夜精品免费视频| 亚洲乱码国产乱码精品天美传媒| 亚洲ww精品| 色综合色综合网色综合| 男人天堂一区二区| 午夜精品久久久久久久久久| jizz中文字幕| 狠狠网亚洲精品| 一本久道高清无码视频| 亚洲欧洲av| 国产女人精品视频| 1024在线播放| 亚洲欧美中文日韩v在线观看| 无码人妻丰满熟妇区五十路| 中文字幕在线不卡| 绯色av蜜臀vs少妇| 9色国产精品| 亚洲精品中文字幕乱码三区不卡| 国产精品igao视频网网址不卡日韩| 欧美第一淫aaasss性| 完全免费av在线播放| 久久青青草视频| 欧美韩国日本不卡| 人妻巨大乳一二三区| 99视频精品| 亚洲精品日韩精品| swag国产精品一区二区| 国产精品第二页| 丰满的护士2在线观看高清| 亚洲欧洲在线播放| 国产av无码专区亚洲av麻豆| 日韩欧美一区二区三区| 精品国产视频一区二区三区| 91偷拍与自偷拍精品| 性chinese极品按摩| 日韩一级免费| 在线观看欧美亚洲| 特黄特色欧美大片| 95av在线视频| 快播电影网址老女人久久| 欧美日韩电影在线观看| 国产色a在线| 亚洲国产成人精品电影| 国产理论视频在线观看| 大荫蒂欧美视频另类xxxx| 三级黄色录像视频| 91免费观看视频| 亚洲少妇一区二区| 蜜臀av一区二区在线观看| 成年人午夜视频在线观看| 97在线精品| 免费电影一区| 第四色在线一区二区| 91精品久久久久久久久久久| 都市激情亚洲一区| 欧美精品成人91久久久久久久| 亚洲xxxxxx| 国产亚洲精品一区二555| 丰满肉肉bbwwbbww| 欧美精三区欧美精三区| 中文在线字幕av| 日韩欧美在线观看视频| 国产大片中文字幕| 亚洲精品国产一区二区三区四区在线| 国产传媒在线看| 久久人人爽爽爽人久久久| 制服丝袜av在线| 国产精品一色哟哟哟| 久久国产色av免费观看| 亚洲免费高清| 无码 制服 丝袜 国产 另类| 你懂的国产精品永久在线| 一区高清视频| 97色伦图片97综合影院| 中国一区二区三区| 日韩在线中文| 一区二区三区偷拍| 日韩在线观看| 一区二区三区电影| 久久影院一区| 亚洲三级一区| 国产精品毛片久久| 自拍偷拍亚洲色图欧美| 99精品在线| 日韩第一页在线观看| 99精品全国免费观看视频软件| 亚洲草草视频| 久久中文字幕av| 午夜在线视频免费观看| 小小影院久久| japanese在线播放| 欧美精品福利| 水蜜桃色314在线观看| 性8sex亚洲区入口| 成年人在线看片| 麻豆国产精品一区二区三区| www.成人黄色| 国产91在线|亚洲| 中文乱码人妻一区二区三区视频| 93久久精品日日躁夜夜躁欧美 | 人妻一区二区三区免费| 亚洲国产精品一区二区三区| 四虎精品成人影院观看地址| 亚洲日本成人女熟在线观看| √天堂资源地址在线官网| 日韩视频欧美视频| 欧美草逼视频| 欧美在线观看网址综合| 国产69精品久久久久9999人| 69174成人网| 久久久久高潮毛片免费全部播放| 日本在线一区| 欧美 日韩 国产精品免费观看| 国产a级片网站| 日韩国产欧美在线观看| 天堂在线一区二区三区| 成人av在线看| 国产精品一区二区亚洲| 亚洲精品视频在线| 日韩欧美国产亚洲| 精品视频免费看| 精品国产18久久久久久| 国产视频精品免费播放| 日本中文字幕在线2020| 国语自产在线不卡| av在线一区不卡| 97超碰人人看人人| 狠狠操综合网| 成人av在线不卡| 日本vs亚洲vs韩国一区三区| 无码人妻少妇色欲av一区二区| 久久久久久97三级| 欧美久久久久久久久久久久| 一本久久a久久精品亚洲| 成人1区2区3区| 伊人久久久久久久久久| 丁香花在线电影小说观看| 国产精品久久久久久久久免费看| av成人app永久免费| 亚洲草草视频| 日韩午夜黄色| 99精品视频免费版的特色功能| 久久久久国色av免费看影院| 欧美日韩免费做爰视频| 91国偷自产一区二区三区观看| 欧美熟妇乱码在线一区 | gogo高清午夜人体在线| 国产一区私人高清影院| 杨幂一区二区三区免费看视频| 毛片av在线播放| 精品综合免费视频观看| 99久久久久久久久久| 亚洲一区二区三区三| 艳妇乳肉豪妇荡乳av| 亚洲色图美腿丝袜| 黄网av在线| 91精品国产一区二区三区动漫| 欧美系列电影免费观看| 一级黄色香蕉视频| av在线不卡免费看| 久久一二三四区| 91精品福利在线一区二区三区| 成人在线播放视频| 欧美最近摘花xxxx摘花| 国产成人澳门| 欧美a级免费视频| 国产成人午夜视频| 亚洲天堂一级片| 欧美嫩在线观看| av每日在线更新| 国产精品亚发布| 久久精品国产68国产精品亚洲| 日本www.色| 欧美激情在线看| 中国老头性行为xxxx| 一本大道亚洲视频| 97精品国产综合久久久动漫日韩| 日韩欧美一区二区三区久久婷婷| 亚洲欧美成人综合| 亚洲一区二区观看| 色综合天天综合网国产成人综合天| 天天操天天干天天干| 欧美性做爰毛片| 久久99视频| 国产九九在线视频| 国产精品嫩草99a| 亚洲一级特黄毛片| 色av吧综合网| 国产在线不卡一区二区三区| 黄色网zhan| 国产精品18久久久久久久网站| 久久久久久免费观看| 精品欧美一区二区久久| 2021中文字幕在线| 麻豆传媒一区二区| 日本午夜精品一区二区三区电影| 亚洲毛片亚洲毛片亚洲毛片| 欧美日韩国产综合久久 | 成人影院天天5g天天爽无毒影院| 亚洲 欧美 日韩系列| 亚洲同性gay激情无套| 成 人 黄 色 片 在线播放| 国语自产精品视频在线看抢先版图片| 亚洲欧洲免费| 手机av在线网| 一级特黄大欧美久久久| 国产精品国产高清国产| 国产精品精品国产| 亚洲久久久久| 免费成人蒂法网站| 欧美专区日韩专区| 91高清在线观看视频| 快播亚洲色图| 韩国女主播成人在线观看| 日本三级2019| 在线看欧美日韩| 99精品在免费线中文字幕网站一区 | 国产情侣一区| 免费看的黄色录像| 精品国产一区二区三区久久影院 | 成人精品一区二区三区电影黑人| 欧美激情无毛| 日本精品在线观看视频| 日韩一区二区三区电影在线观看| 精精国产xxxx视频在线野外| 亚洲激情一区二区| 成人永久aaa| 国产情侣呻吟对白高潮| 欧美丰满老妇厨房牲生活| 九九亚洲精品| 成人欧美精品一区二区| 在线观看av一区二区| 国模雨婷捆绑高清在线| 日韩影片在线播放|