亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

springboot使用hibernate validator校驗方式

2024-07-13 10:16:55
字體:
來源:轉載
供稿:網友

一、參數校驗

 在開發中經常需要寫一些字段校驗的代碼,比如字段非空,字段長度限制,郵箱格式驗證等等,寫這些與業務邏輯關系不大的代碼個人感覺有兩個麻煩:

  • 驗證代碼繁瑣,重復勞動
  • 方法內代碼顯得冗長
  • 每次要看哪些參數驗證是否完整,需要去翻閱驗證邏輯代碼

hibernate validator(官方文檔)提供了一套比較完善、便捷的驗證實現方式。

spring-boot-starter-web包里面有hibernate-validator包,不需要引用hibernate validator依賴。

二、hibernate validator校驗demo

 先來看一個簡單的demo,添加了Validator的注解:

import org.hibernate.validator.constraints.NotBlank;import javax.validation.constraints.AssertFalse;import javax.validation.constraints.Pattern;
@Getter@Setter@NoArgsConstructorpublic class DemoModel { @NotBlank(message="用戶名不能為空") private String userName; @NotBlank(message="年齡不能為空") @Pattern(regexp="^[0-9]{1,2}$",message="年齡不正確") private String age; @AssertFalse(message = "必須為false") private Boolean isFalse; /** * 如果是空,則不校驗,如果不為空,則校驗 */ @Pattern(regexp="^[0-9]{4}-[0-9]{2}-[0-9]{2}$",message="出生日期格式不正確") private String birthday;}

POST接口驗證,BindingResult是驗證不通過的結果集合:

 @RequestMapping("/demo2") public void demo2(@RequestBody @Valid DemoModel demo, BindingResult result){ if(result.hasErrors()){  for (ObjectError error : result.getAllErrors()) {  System.out.println(error.getDefaultMessage());  } } }

POST請求傳入的參數:{"userName":"dd","age":120,"isFalse":true,"birthday":"21010-21-12"}

輸出結果:

出生日期格式不正確
必須為false
年齡不正確

 參數驗證非常方便,字段上注解+驗證不通過提示信息即可代替手寫一大堆的非空和字段限制驗證代碼。下面深入了解下參數校驗的玩法。

三、hibernate的校驗模式

細心的讀者肯定發現了:上面例子中一次性返回了所有驗證不通過的集合,通常按順序驗證到第一個字段不符合驗證要求時,就可以直接拒絕請求了。Hibernate Validator有以下兩種驗證模式:

1、普通模式(默認是這個模式)

  普通模式(會校驗完所有的屬性,然后返回所有的驗證失敗信息)

2、快速失敗返回模式

  快速失敗返回模式(只要有一個驗證失敗,則返回)

兩種驗證模式配置方式:(參考官方文檔)

failFast:true  快速失敗返回模式    false 普通模式

ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class ) .configure() .failFast( true ) .buildValidatorFactory();Validator validator = validatorFactory.getValidator();

和 (hibernate.validator.fail_fast:true  快速失敗返回模式    false 普通模式)

ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class ) .configure() .addProperty( "hibernate.validator.fail_fast", "true" ) .buildValidatorFactory();Validator validator = validatorFactory.getValidator();

四、hibernate的兩種校驗

配置hibernate Validator為快速失敗返回模式:

@Configurationpublic class ValidatorConfiguration { @Bean public Validator validator(){ ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )  .configure()  .addProperty( "hibernate.validator.fail_fast", "true" )  .buildValidatorFactory(); Validator validator = validatorFactory.getValidator(); return validator; }}

1、請求參數校驗

如demo里示例的,驗證請求參數時,在@RequestBody DemoModel demo之間加注解 @Valid,然后后面加BindindResult即可;多個參數的,可以加多個@Valid和BindingResult,如:

public void test()(@RequestBody @Valid DemoModel demo, BindingResult result)public void test()(@RequestBody @Valid DemoModel demo, BindingResult result,@RequestBody @Valid DemoModel demo2, BindingResult result2)
 @RequestMapping("/demo2") public void demo2(@RequestBody @Valid DemoModel demo, BindingResult result){ if(result.hasErrors()){  for (ObjectError error : result.getAllErrors()) {  System.out.println(error.getDefaultMessage());  } } }

2、GET參數校驗(@RequestParam參數校驗)

使用校驗bean的方式,沒有辦法校驗RequestParam的內容,一般在處理Get請求(或參數比較少)的時候,會使用下面這樣的代碼:

 @RequestMapping(value = "/demo3", method = RequestMethod.GET) public void demo3(@RequestParam(name = "grade", required = true) int grade,@RequestParam(name = "classroom", required = true) int classroom) { System.out.println(grade + "," + classroom); }

使用@Valid注解,對RequestParam對應的參數進行注解,是無效的,需要使用@Validated注解來使得驗證生效。如下所示:

a.此時需要使用MethodValidationPostProcessor 的Bean:

 @Bean public MethodValidationPostProcessor methodValidationPostProcessor() {     /**默認是普通模式,會返回所有的驗證不通過信息集合*/ return new MethodValidationPostProcessor(); }

或 可對MethodValidationPostProcessor 進行設置Validator(因為此時不是用的Validator進行驗證,Validator的配置不起作用)

@Bean public MethodValidationPostProcessor methodValidationPostProcessor() { MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();     /**設置validator模式為快速失敗返回*/ postProcessor.setValidator(validator()); return postProcessor; } @Bean public Validator validator(){ ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )  .configure()  .addProperty( "hibernate.validator.fail_fast", "true" )  .buildValidatorFactory(); Validator validator = validatorFactory.getValidator(); return validator; }

b.方法所在的Controller上加注解@Validated

@RequestMapping("/validation")@RestController@Validatedpublic class ValidationController { /**如果只有少數對象,直接把參數寫到Controller層,然后在Controller層進行驗證就可以了。*/ @RequestMapping(value = "/demo3", method = RequestMethod.GET) public void demo3(@Range(min = 1, max = 9, message = "年級只能從1-9")   @RequestParam(name = "grade", required = true)   int grade,   @Min(value = 1, message = "班級最小只能1")   @Max(value = 99, message = "班級最大只能99")   @RequestParam(name = "classroom", required = true)   int classroom) { System.out.println(grade + "," + classroom); }}

c.返回驗證信息提示

可以看到:驗證不通過時,拋出了ConstraintViolationException異常,使用同一捕獲異常處理:

@ControllerAdvice@Componentpublic class GlobalExceptionHandler { @ExceptionHandler @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public String handle(ValidationException exception) { if(exception instanceof ConstraintViolationException){  ConstraintViolationException exs = (ConstraintViolationException) exception;  Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();  for (ConstraintViolation<?> item : violations) {          /**打印驗證不通過的信息*/  System.out.println(item.getMessage());  } } return "bad request, " ; }}

d.驗證

瀏覽器服務請求地址:http://localhost:8080/validation/demo3?grade=18&classroom=888

沒有配置快速失敗返回的MethodValidationPostProcessor 時輸出信息如下:

年級只能從1-9
班級最大只能99

配置了快速失敗返回的MethodValidationPostProcessor 時輸出信息如下:

年級只能從1-9

瀏覽器服務請求地址:http://localhost:8080/validation/demo3?grade=0&classroom=0

沒有配置快速失敗返回的MethodValidationPostProcessor 時輸出信息如下:

年級只能從1-9
班級最小只能1

配置了快速失敗返回的MethodValidationPostProcessor 時輸出信息如下:

年級只能從1-9

3、model校驗

待校驗的model:

@Datapublic class Demo2 { @Length(min = 5, max = 17, message = "length長度在[5,17]之間") private String length; /**@Size不能驗證Integer,適用于String, Collection, Map and arrays*/ @Size(min = 1, max = 3, message = "size在[1,3]之間") private String age; @Range(min = 150, max = 250, message = "range在[150,250]之間") private int high; @Size(min = 3,max = 5,message = "list的Size在[3,5]") private List<String> list;}

驗證model,以下全部驗證通過:

 @Autowired private Validator validator; @RequestMapping("/demo3") public void demo3(){ Demo2 demo2 = new Demo2(); demo2.setAge("111"); demo2.setHigh(150); demo2.setLength("ABCDE"); demo2.setList(new ArrayList<String>(){{add("111");add("222");add("333");}}); Set<ConstraintViolation<Demo2>> violationSet = validator.validate(demo2); for (ConstraintViolation<Demo2> model : violationSet) {  System.out.println(model.getMessage()); } }

4、對象級聯校驗

對象內部包含另一個對象作為屬性,屬性上加@Valid,可以驗證作為屬性的對象內部的驗證:(驗證Demo2示例時,可以驗證Demo2的字段)

@Datapublic class Demo2 { @Size(min = 3,max = 5,message = "list的Size在[3,5]") private List<String> list; @NotNull @Valid private Demo3 demo3;}@Datapublic class Demo3 { @Length(min = 5, max = 17, message = "length長度在[5,17]之間") private String extField;}

級聯校驗:

 /**前面配置了快速失敗返回的Bean*/ @Autowired private Validator validator; @RequestMapping("/demo3") public void demo3(){ Demo2 demo2 = new Demo2(); demo2.setList(new ArrayList<String>(){{add("111");add("222");add("333");}}); Demo3 demo3 = new Demo3(); demo3.setExtField("22"); demo2.setDemo3(demo3); Set<ConstraintViolation<Demo2>> violationSet = validator.validate(demo2); for (ConstraintViolation<Demo2> model : violationSet) {  System.out.println(model.getMessage()); } }

可以校驗Demo3的extField字段。

5、分組校驗

結論:分組順序校驗時,按指定的分組先后順序進行驗證,前面的驗證不通過,后面的分組就不行驗證。

有這樣一種場景,新增用戶信息的時候,不需要驗證userId(因為系統生成);修改的時候需要驗證userId,這時候可用用戶到validator的分組驗證功能。

設置validator為普通驗證模式("hibernate.validator.fail_fast", "false"),用到的驗證GroupA、GroupB和model:

GroupA、GroupB:public interface GroupA {}public interface GroupB {}

驗證model:Person

@Datapublic class Person { @NotBlank @Range(min = 1,max = Integer.MAX_VALUE,message = "必須大于0",groups = {GroupA.class}) /**用戶id*/ private Integer userId; @NotBlank @Length(min = 4,max = 20,message = "必須在[4,20]",groups = {GroupB.class}) /**用戶名*/ private String userName; @NotBlank @Range(min = 0,max = 100,message = "年齡必須在[0,100]",groups={Default.class}) /**年齡*/ private Integer age; @Range(min = 0,max = 2,message = "性別必須在[0,2]",groups = {GroupB.class}) /**性別 0:未知;1:男;2:女*/ private Integer sex;}

如上Person所示,3個分組分別驗證字段如下:

  • GroupA驗證字段userId;
  • GroupB驗證字段userName、sex;
  • Default驗證字段age(Default是Validator自帶的默認分組)
  •  

a、分組

只驗證GroupA、GroupB標記的分組:

@RequestMapping("/demo5")public void demo5(){ Person p = new Person(); /**GroupA驗證不通過*/ p.setUserId(-12); /**GroupA驗證通過*/ //p.setUserId(12); p.setUserName("a"); p.setAge(110); p.setSex(5); Set<ConstraintViolation<Person>> validate = validator.validate(p, GroupA.class, GroupB.class); for (ConstraintViolation<Person> item : validate) { System.out.println(item); }}

 @RequestMapping("/demo6") public void demo6(@Validated({GroupA.class, GroupB.class}) Person p, BindingResult result){ if(result.hasErrors()){  List<ObjectError> allErrors = result.getAllErrors();  for (ObjectError error : allErrors) {  System.out.println(error);  } } }

GroupA、GroupB、Default都驗證不通過的情況:

驗證信息如下所示:

ConstraintViolationImpl{interpolatedMessage='必須在[4,20]', propertyPath=userName, rootBeanClass=class validator.demo.project.model.Person, messageTemplate='必須在[4,20]'}ConstraintViolationImpl{interpolatedMessage='必須大于0', propertyPath=userId, rootBeanClass=class validator.demo.project.model.Person, messageTemplate='必須大于0'}ConstraintViolationImpl{interpolatedMessage='性別必須在[0,2]', propertyPath=sex, rootBeanClass=class validator.demo.project.model.Person, messageTemplate='性別必須在[0,2]'}

GroupA驗證通過、GroupB、Default驗證不通過的情況:

驗證信息如下所示:

ConstraintViolationImpl{interpolatedMessage='必須在[4,20]', propertyPath=userName, rootBeanClass=class validator.demo.project.model.Person, messageTemplate='必須在[4,20]'}ConstraintViolationImpl{interpolatedMessage='性別必須在[0,2]', propertyPath=sex, rootBeanClass=class validator.demo.project.model.Person, messageTemplate='性別必須在[0,2]'}

b、組序列

除了按組指定是否驗證之外,還可以指定組的驗證順序,前面組驗證不通過的,后面組不進行驗證:

指定組的序列(GroupA》GroupB》Default):

@GroupSequence({GroupA.class, GroupB.class, Default.class})public interface GroupOrder {}

測試demo:

 @RequestMapping("/demo7") public void demo7(){ Person p = new Person(); /**GroupA驗證不通過*/ //p.setUserId(-12); /**GroupA驗證通過*/ p.setUserId(12); p.setUserName("a"); p.setAge(110); p.setSex(5); Set<ConstraintViolation<Person>> validate = validator.validate(p, GroupOrder.class); for (ConstraintViolation<Person> item : validate) {  System.out.println(item); } }

 @RequestMapping("/demo8") public void demo8(@Validated({GroupOrder.class}) Person p, BindingResult result){ if(result.hasErrors()){  List<ObjectError> allErrors = result.getAllErrors();  for (ObjectError error : allErrors) {  System.out.println(error);  } } }

GroupA、GroupB、Default都驗證不通過的情況:

驗證信息如下所示:

ConstraintViolationImpl{interpolatedMessage='必須大于0', propertyPath=userId, rootBeanClass=class validator.demo.project.model.Person, messageTemplate='必須大于0'}

GroupA驗證通過、GroupB、Default驗證不通過的情況:

驗證信息如下所示:

ConstraintViolationImpl{interpolatedMessage='必須在[4,20]', propertyPath=userName, rootBeanClass=class validator.demo.project.model.Person, messageTemplate='必須在[4,20]'}ConstraintViolationImpl{interpolatedMessage='性別必須在[0,2]', propertyPath=sex, rootBeanClass=class validator.demo.project.model.Person, messageTemplate='性別必須在[0,2]'}

結論:分組順序校驗時,按指定的分組先后順序進行驗證,前面的驗證不通過,后面的分組就不行驗證。

五、自定義驗證器

一般情況,自定義驗證可以解決很多問題。但也有無法滿足情況的時候,此時,我們可以實現validator的接口,自定義自己需要的驗證器。

如下所示,實現了一個自定義的大小寫驗證器:

public enum CaseMode { UPPER, LOWER;}@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })@Retention(RetentionPolicy.RUNTIME)@Constraint(validatedBy = CheckCaseValidator.class)@Documentedpublic @interface CheckCase { String message() default ""; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; CaseMode value();}public class CheckCaseValidator implements ConstraintValidator<CheckCase, String> { private CaseMode caseMode; public void initialize(CheckCase checkCase) { this.caseMode = checkCase.value(); } public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) { if (s == null) {  return true; } if (caseMode == CaseMode.UPPER) {  return s.equals(s.toUpperCase()); } else {  return s.equals(s.toLowerCase()); } }}

要驗證的Model:

 public class Demo{ @CheckCase(value = CaseMode.LOWER,message = "userName必須是小寫") private String userName; public String getUserName() {  return userName; } public void setUserName(String userName) {  this.userName = userName; } }

validator配置:

@Bean public Validator validator(){ ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )  .configure()  .addProperty( "hibernate.validator.fail_fast", "true" )  .buildValidatorFactory(); Validator validator = validatorFactory.getValidator(); return validator; }

驗證測試:

 @RequestMapping("/demo4") public void demo4(){ Demo demo = new Demo(); demo.setUserName("userName"); Set<ConstraintViolation<Demo>> validate = validator.validate(demo); for (ConstraintViolation<Demo> dem : validate) {  System.out.println(dem.getMessage()); } }

輸出結果:

userName必須是小寫

六、常見的注解

 Bean Validation 中內置的 constraint @Null 被注釋的元素必須為 null @NotNull 被注釋的元素必須不為 null @AssertTrue 被注釋的元素必須為 true @AssertFalse 被注釋的元素必須為 false @Min(value) 被注釋的元素必須是一個數字,其值必須大于等于指定的最小值 @Max(value) 被注釋的元素必須是一個數字,其值必須小于等于指定的最大值 @DecimalMin(value) 被注釋的元素必須是一個數字,其值必須大于等于指定的最小值 @DecimalMax(value) 被注釋的元素必須是一個數字,其值必須小于等于指定的最大值 @Size(max=, min=) 被注釋的元素的大小必須在指定的范圍內 @Digits (integer, fraction) 被注釋的元素必須是一個數字,其值必須在可接受的范圍內 @Past 被注釋的元素必須是一個過去的日期 @Future 被注釋的元素必須是一個將來的日期 @Pattern(regex=,flag=) 被注釋的元素必須符合指定的正則表達式 Hibernate Validator 附加的 constraint @NotBlank(message =) 驗證字符串非null,且長度必須大于0 @Email 被注釋的元素必須是電子郵箱地址 @Length(min=,max=) 被注釋的字符串的大小必須在指定的范圍內 @NotEmpty 被注釋的字符串的必須非空 @Range(min=,max=,message=) 被注釋的元素必須在合適的范圍內//大于0.01,不包含0.01@NotNull@DecimalMin(value = "0.01", inclusive = false)private Integer greaterThan;//大于等于0.01@NotNull@DecimalMin(value = "0.01", inclusive = true)private BigDecimal greatOrEqualThan;@Length(min = 1, max = 20, message = "message不能為空")//不能將Length錯用成Range//@Range(min = 1, max = 20, message = "message不能為空")private String message;

七、參考資料

參考資料:

http://docs.jboss.org/hibernate/validator/4.2/reference/zh-CN/html_single/#validator-gettingstarted


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美壮男野外gaytube| 久久免费精品日本久久中文字幕| 一本一本久久a久久精品牛牛影视| 精品欧美激情精品一区| 国产不卡精品视男人的天堂| 91九色单男在线观看| 午夜精品久久久久久久99热浪潮| 色777狠狠综合秋免鲁丝| 国内偷自视频区视频综合| 欧美日韩亚洲网| 一区二区成人av| 欧美激情第三页| 亚洲www永久成人夜色| 国产精品夜间视频香蕉| 亚洲深夜福利网站| 日本不卡高字幕在线2019| 日韩视频免费中文字幕| 亚洲国产精品va| 一区二区三区四区精品| 精品美女久久久久久免费| 欧美伊久线香蕉线新在线| 亚洲国产中文字幕久久网| 欧美大胆在线视频| 亚洲人精品午夜在线观看| 国产一区二区三区在线播放免费观看| 日韩中文字幕在线精品| 国产精品在线看| 精品视频在线播放色网色视频| 国产精品久久久久久久久久尿| 在线一区二区日韩| 亚洲精品日韩在线| 欧美成人精品一区二区三区| 日韩av网站导航| 亚洲第一页中文字幕| 日本高清久久天堂| 亚洲自拍高清视频网站| 国产亚洲欧美aaaa| 欧美视频免费在线观看| 欧美另类xxx| 日韩av在线网| 国产精品成人av在线| 成人性生交大片免费看视频直播| 久久综合色影院| 热久久视久久精品18亚洲精品| 国产精品第七十二页| 欧美国产欧美亚洲国产日韩mv天天看完整| 米奇精品一区二区三区在线观看| 疯狂做受xxxx欧美肥白少妇| 欧美激情在线狂野欧美精品| 美女999久久久精品视频| 久久精品这里热有精品| 亚洲综合在线中文字幕| 国产精品入口尤物| 亚洲综合小说区| 欧美在线激情视频| 久久成人精品电影| 亚洲第一天堂无码专区| 中文字幕欧美精品在线| 日韩欧美中文第一页| 在线看片第一页欧美| 狠狠躁天天躁日日躁欧美| 浅井舞香一区二区| 欧美大片在线影院| 亚州国产精品久久久| 亚洲欧美精品伊人久久| 欧美wwwwww| 97久久久免费福利网址| 国产精品美女在线观看| 国产激情综合五月久久| 日韩在线视频观看正片免费网站| 成人高h视频在线| 欧美一级高清免费| 国产精品久久久久久久久粉嫩av| 亚洲精品97久久| 亚洲一区中文字幕在线观看| 91精品免费看| 国产视频精品va久久久久久| 国产精品免费久久久久影院| 中文字幕一区二区三区电影| 亚洲人成电影网站色| 亚洲精品白浆高清久久久久久| 91社影院在线观看| 亚洲国产精品成人一区二区| 亚洲自拍另类欧美丝袜| 91老司机精品视频| 午夜精品久久久久久久久久久久久| 91视频九色网站| 欧美黑人xxxx| 亚洲国产成人精品久久久国产成人一区| 亚洲国语精品自产拍在线观看| 国产一区二区三区日韩欧美| 91精品视频在线看| 久久精品国产亚洲| 国产日韩欧美在线观看| 2019中文字幕全在线观看| 亚洲综合精品一区二区| 日韩黄色高清视频| 国产亚洲福利一区| 91中文在线观看| 欧美精品一区三区| 98精品国产自产在线观看| 亚洲欧美日韩精品久久| 久久影院免费观看| 尤物精品国产第一福利三区| 久久久精品网站| 日韩久久免费视频| 亚洲日本aⅴ片在线观看香蕉| 久久国产精品免费视频| 日韩av电影免费观看高清| 亚洲激情视频在线观看| 高跟丝袜欧美一区| 久久伊人精品天天| 亚洲欧美成人网| 在线观看精品自拍私拍| 亚洲国产一区二区三区四区| 成人免费观看49www在线观看| 亚洲国产精品久久久久秋霞不卡| 欧美日韩美女在线| 日本精品一区二区三区在线播放视频| 国产精品视频999| 成人激情av在线| 亚洲视频电影图片偷拍一区| 久久综合网hezyo| 国产不卡视频在线| 欧美日韩一区二区精品| 久久久久五月天| 欧美超级乱淫片喷水| 久久中国妇女中文字幕| 一区二区国产精品视频| 欧美激情视频一区| 成人黄色av播放免费| 国内精品久久久久久久久| 久久久电影免费观看完整版| 亚洲老司机av| 91精品视频专区| 992tv成人免费视频| 91高清免费视频| 欧美激情一级精品国产| 69视频在线免费观看| 综合国产在线视频| 91精品国产高清自在线看超| 国产精品成熟老女人| 亚洲人成网在线播放| 国产综合香蕉五月婷在线| 亚洲欧美日韩国产精品| 国产免费一区二区三区香蕉精| 亚洲一区二区中文字幕| 亚洲成人激情在线| 热久久视久久精品18亚洲精品| 九色91av视频| 欧美激情图片区| 色狠狠av一区二区三区香蕉蜜桃| 日韩成人免费视频| 欧美成人免费在线观看| 日韩精品极品毛片系列视频| 韩国三级电影久久久久久| 国产男人精品视频| 亚洲欧洲午夜一线一品| 热久久视久久精品18亚洲精品| 中文欧美在线视频| 亚洲综合视频1区| 亚洲欧洲日韩国产| 亚洲精品日韩av| 国产精品偷伦一区二区|