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

如何正確使用 Bean Validation 進行數據校驗

大數據 數據分析
為了避免重復這些驗證,通常的做法是將驗證邏輯直接捆綁到領域模型中,通過元數據(默認是注解)去描述模型, 生成校驗代碼,從而使校驗從業務邏輯中剝離,提升開發效率,使開發者更專注業務邏輯本身。

一、背景

在前后端開發過程中,數據校驗是一項必須且常見的事,從展示層、業務邏輯層到持久層幾乎每層都需要數據校驗。如果在每一層中手工實現驗證邏輯,既耗時又容易出錯。

圖片圖片

為了避免重復這些驗證,通常的做法是將驗證邏輯直接捆綁到領域模型中,通過元數據(默認是注解)去描述模型, 生成校驗代碼,從而使校驗從業務邏輯中剝離,提升開發效率,使開發者更專注業務邏輯本身。

圖片圖片

在 Spring 中,目前支持兩種不同的驗證方法:Spring Validation 和 JSR-303 Bean Validation,即 @Validated(org . springframework.validation.annotation.Validated)和 @Valid(javax.validation.Valid)。兩者都可以通過定義模型的約束來進行數據校驗,雖然兩者使用類似,在很多場景下也可以相互替換,但實際上卻完全不同,這些差別長久以來對我們日常使用產生了較大疑惑,本文主要梳理其中的差別、介紹 Validation 的使用及其實現原理,幫助大家在實踐過程中更好使用 Validation 功能。

二、Bean Validation簡介

什么是JSR?

JSR 是 Java Specification Requests 的縮寫,意思是 Java 規范提案。是指向 JCP(Java Community Process) 提出新增一個標準化技術規范的正式請求,以向 Java 平臺增添新的 API 和服務。JSR 已成為 Java 界的一個重要標準。

JSR-303定義的是什么標準?

JSR-303 是用于 Bean Validation 的 Java API 規范,該規范是 Jakarta EE and JavaSE 的一部分,Hibernate Validator 是 Bean Validation 的參考實現。Hibernate Validator 提供了 JSR 303 規范中所有內置 Constraint 的實現,除此之外還有一些附加的 Constraint。(最新的為 JSR-380 為 Bean Validation 3.0)

圖片圖片

常用的校驗注解補充:

@NotBlank 檢查約束字符串是不是 Null 還有被 Trim 的長度是否大于,只對字符串,且會去掉前后空格。

@NotEmpty 檢查約束元素是否為 Null 或者是 Empty。

@Length 被檢查的字符串長度是否在指定的范圍內。

@Email 驗證是否是郵件地址,如果為 Null,不進行驗證,算通過驗證。

@Range 數值返回校驗。

@IdentityCardNumber 校驗身份證信息。

@UniqueElements 集合唯一性校驗。

@URL 驗證是否是一個 URL 地址。

Spring Validation的產生背景

上文提到 Spring 支持兩種不同的驗證方法:Spring Validation 和 JSR-303 Bean Validation(下文使用@Validated和@Valid替代)。為什么會同時存在兩種方式?

Spring 增加 @Validated 是為了支持分組校驗,即同一個對象在不同的場景下使用不同的校驗形式。比如有兩個步驟用于提交用戶資料,后端復用的是同一個對象,第一步驗證姓名,電子郵件等字段,然后在后續步驟中的其他字段中。這時候分組校驗就會發揮作用。

  • 為什么不合入到 JSR-303 中?

之所以沒有將它添加到 @Valid 注釋中,是因為它是使用 Java 社區過程(JSR-303)標準化的,這需要時間,而 Spring 開發者想讓人們更快地使用這個功能。

  • @Validated 的內置自動化校驗

Spring 增加 @Validated 還有另一層原因,Bean Validation 的標準做法是在程序中手工調用 Validator 或者 ExecutableValidator 進行校驗,為了實現自動化,通常通過 AOP、代理等方法攔截技術來調用。而 @Validated 注解就是為了配合 Spring 進行 AOP 攔截,從而實現 Bean Validation 的自動化執行。

  • @Validated 和 @Valid 的區別

@Valid 是 JSR 標準 API,@Validated 擴展了 @Valid 支持分組校驗且能作為 SpringBean 的 AOP 注解,在 SpringBean 初始化時實現方法層面的自動校驗。最終還是使用了 JSR API 進行約束校驗。

三、Bean Validation的使用

引入POM

// 正常應該引入hibernate-validator,是JSR的參考實現


<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
</dependency>
// Spring在stark中集成了,所以hibernate-validator可以不用引入
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Bean層面校驗

  • 變量層面約束
public class EntryApplicationInfoCmd {
    /**
     * 用戶ID
     */
    @NotNull(message = "用戶ID不為空")
    private Long userId;


    /**
     *   證件類型
     */
    @NotEmpty(message = "證件類型不為空")
    private String certType;
}
  • 屬性層面約束

主要為了限制 Setter 方法的只讀屬性。屬性的 Getter 方法打注釋,而不是 Setter。

public class EntryApplicationInfoCmd {
    public EntryApplicationInfoCmd(Long userId, String certType) {
            this.userId = userId;
            this.certType = certType;
        }
    /**
     * 用戶ID
     */
    private Long userId;


    /**
     *   證件類型
     */
    private String certType;
    
    @NotNull
    public String getUserId() {
        return userId;
    }
    
    @NotEmpty
    public String getCertType() {
        return userId;
    }
}
  • 容器元素約束
public class EntryApplicationInfoCmd {
    ...
    List<@NotEmpty Long> categoryList;
}
  • 類層面約束

@CategoryBrandNotEmptyRecord 是自定義類層面的約束,也可以約束在構造函數上。

@CategoryBrandNotEmptyRecord
public class EntryApplicationInfoCmd {
    /**
     * 用戶ID
     */
    @NotNull(message = "用戶ID不為空")
    private Long userId;
       
    List<@NotEmpty Long> categoryList;
}
  • 嵌套約束

嵌套對象需要額外使用 @Valid 進行標注(@Validate 不支持,為什么?請看產生的背景)。

public class EntryApplicationInfoCmd {
    /**
     *  主營品牌
     */  
    @Valid
    @NotNull 
    private MainBrandImagesCmd mainBrandImage;
}


public class MainBrandImagesCmd {
    /**
     *  品牌名稱
     */  
    @NotEmpty 
    private String brandName;;
}
  • 手工驗證Bean約束
// 獲取校驗器
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();


// 進行bean層面校驗
Set<ConstraintViolation<User>> violations = validator.validate(EntryApplicationInfoCmd);
// 打印校驗信息
for (ConstraintViolation<User> violation : violations) {
    log.error(violation.getMessage()); 
}

方法層面校驗

  • 函數參數約束
public class MerchantMainApplyQueryService {
    MainApplyDetailResp detail(@NotNull(message = "申請單號不能為空") Long id) {
        ...
    }
}
  • 函數返回值約束
public class MerchantMainApplyQueryService {
    @NotNull
    @Size(min = 1)
    public List<@NotNull MainApplyStandDepositResp> getStanderNewDeposit(Long id) {
        //...
    }
}
  • 嵌套約束

嵌套對象需要額外使用 @Valid 進行標注(@Validate 不支持)。

public class MerchantMainApplyQueryService {
    public NewEntryBrandRuleCheckApiResp brandRuleCheck(@Valid @NotNull NewEntryBrandRuleCheckRequest request) {
        ...
    }
}


public class NewEntryBrandRuleCheckRequest {
    @NotNull(message = "一級類目不能為空")
    private Long level1CategoryId;
}
  • 在繼承中方法約束

Validation 的設計需要遵循里氏替換原則,無論何時使用類型 T,也可以使用 T 的子類型 S,而不改變程序的行為。即子類不能增加約束也不能減弱約束。

子類方法參數的約束與父類行為不一致(錯誤例子):

// 繼承的方法參數約束不能改變,否則會導致父類子類行為不一致
public interface Vehicle {


    void drive(@Max(75) int speedInMph);
}


public class Car implements Vehicle {


    @Override
    public void drive(@Max(55) int speedInMph) {
        //...
    }
}

方法的返回值可以增加約束(正確例子):

// 繼承的方法返回值可以增加約束
public interface Vehicle {


    @NotNull
    List<Person> getPassengers();
}


public class Car implements Vehicle {


    @Override
    @Size(min = 1)
    public List<Person> getPassengers() {
        //...
        return null;
    }
}
  • 手工驗證方法約束

方法層面校驗使用的是 ExecutableValidator。

// 獲取校驗器
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator executableValidator = factory.getValidator().forExecutables();


// 進行方法層面校驗
MerchantMainApplyQueryService service = getService();
Method method = MerchantMainApplyQueryService.class.getMethod( "getStanderNewDeposit", int.class );
Object[] parameterValues = { 80 };
Set<ConstraintViolation<Car>> violations = executableValidator.validateParameters(
        service,
        method,
        parameterValues
);
// 打印校驗信息
for (ConstraintViolation<User> violation : violations) {
    log.error(violation.getMessage()); 
}

分組校驗

不同場景復用一個 Model,采用不一樣的校驗方式。

public class NewEntryMainApplyRequest {
    @NotNull(message = "一級類目不能為空")
    private Long level1CategoryId;
    
    @NotNull(message = "申請單ID不能為空", group = UpdateMerchantMainApplyCmd.class)
    private Long applyId;
    
    @NotEmpty(message = "審批人不能為空", group = AddMerchantMainApplyCmd.class)
    private String operator;
}


// 校驗分組UpdateMerchantMainApplyCmd.class
NewEntryMainApplyRequest request1 = new NewEntryMainApplyRequest( 29, null, "aaa");
Set<ConstraintViolation<NewEntryMainApplyRequest>> constraintViolations = validator.validate( request1, UpdateMerchantMainApplyCmd.class );
assertEquals("申請單ID不能為空", constraintViolations.iterator().next().getMessage());


// 校驗分組AddMerchantMainApplyCmd.class
NewEntryMainApplyRequest request2 = new NewEntryMainApplyRequest( 29, "12345", "");
Set<ConstraintViolation<NewEntryMainApplyRequest>> constraintViolations = validator.validate( request2, AddMerchantMainApplyCmd.class );
assertEquals("審批人不能為空", constraintViolations.iterator().next().getMessage());

自定義校驗

自定義注解:

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MyConstraintValidator.class)
public @interface MyConstraint {
    String message();


    Class<?>[] groups() default {};


    Class<? extends Payload>[] payload() default {};
}

自定義校驗器:

public class MyConstraintValidator implements ConstraintValidator<MyConstraint, Object> {
    @Override
    public void initialize(MyConstraint constraintAnnotation) {
    
    }
    
    @Override
    public isValid isValid(Object value, ConstraintValidatorContext context) {
         String name = (String)value;
         if("xxxx".equals(name)) {
             return true;
         }
         
         return false;
    }
}

使用自定義約束:

public class Test {
    @MyConstraint(message = "test")
    String name;
}

四、Bean Validation自動執行以及原理

上述 2.6 和 3.5 分別實現了 Bean 和 Method 層面的約束校驗,但是每次都主動調用比較繁瑣,因此 Spring 在 @RestController 的 @RequestBody 注解中內置了一些自動化校驗以及在 Bean 初始化中集成了 AOP 來簡化編碼。

Validation的常見誤解

最常見的應該就是在 RestController 中,校驗 @RequestBody 指定參數的約束,使用 @Validated 或者 @Valid(該場景下兩者等價)進行約束校驗,以至于大部分人理解的 Validation 只要打個注解就可以生效,實際上這只是一種特例。很多人在使用過程中經常遇到約束校驗不生效。約束校驗生效

Spring-mvc 中在 @RequestBody 后面加 @Validated、@Valid 約束即可生效。

@RestController
@RequestMapping("/biz/merchant/enter")
public class MerchantEnterController {
    @PostMapping("/application")
    // 使用@Validated
    public HttpMessageResult addOrUpdateV1(@RequestBody @Validated MerchantEnterApplicationReq req){
        ...
    }
    // 使用@Valid
    @PostMapping("/application2")
    public HttpMessageResult addOrUpdate2(@RequestBody @Valid MerchantEnterApplicationReq req){
        ...
    }
}
  • 約束校驗不生效

然而下面這個約束其實是不生效的,想要生效得在 MerchantEntryServiceImpl 類目加上 @Validated 注解。

// @Validated 不加不生效
@Service
public class MerchantEntryService {
    public Boolean applicationAddOrUpdate(@Validated MerchantEnterApplicationReq req) {
        ...
    }
    
    public Boolean applicationAddOrUpdate2(@Valid MerchantEnterApplicationReq req) {
        ...
    }
}

那么究竟為什么會出現這種情況呢,這就需要對 Spring Validation 的注解執行原理有一定的了解。

Controller自動執行約束校驗原理

在 Spring-mvc 中,有很多攔截器對 Http 請求的出入參進行解析和轉換,Validation 解析和執行也是類似,其中 RequestResponseBodyMethodProcessor 是用于解析 @RequestBody 標注的參數以及處理 @ResponseBody 標注方法的返回值的。

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {


    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(RequestBody.class);
    }
    // 類上或者方法上標注了@ResponseBody注解都行
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class));
    }
    
    // 這是處理入參封裝校驗的入口
    @Override
    public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
        parameter = parameter.nestedIfOptional();
        // 獲取請求的參數對象
        Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
        // 獲取參數名稱
        String name = Conventions.getVariableNameForParameter(parameter);


        // 只有存在binderFactory才會去完成自動的綁定、校驗~
        if (binderFactory != null) {
            WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
            if (arg != null) {
                // 這里完成數據綁定+數據校驗~~~~~(綁定的錯誤和校驗的錯誤都會放進Errors里)
                validateIfApplicable(binder, parameter);


                // 若有錯誤消息hasErrors(),并且僅跟著的一個參數不是Errors類型,Spring MVC會主動給你拋出MethodArgumentNotValidException異常
                if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
                    throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
                }
            }
        
            // 把錯誤消息放進去 證明已經校驗出錯誤了~~~
            // 后續邏輯會判斷MODEL_KEY_PREFIX這個key的~~~~
            if (mavContainer != null) {
                mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
            }
        }


        return adaptArgumentIfNecessary(arg, parameter);
    }
    
    ...
}

約束的校驗邏輯是在 RequestResponseBodyMethodProcessor.validateIfApplicable 實現的,這里同時兼容了 @Validated 和 @Valid,所以該場景下兩者是等價的。

// 校驗,如果合適的話。使用WebDataBinder,失敗信息最終也都是放在它身上~  
// 入參:MethodParameter parameter
protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
    // 拿到標注在此參數上的所有注解們(比如此處有@Valid和@RequestBody兩個注解)
    Annotation[] annotations = parameter.getParameterAnnotations();
    for (Annotation ann : annotations) {
        // 先看看有木有@Validated
        Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);


        // 這個里的判斷是關鍵:可以看到標注了@Validated注解 或者注解名是以Valid打頭的 都會有效哦
        //注意:這里可沒說必須是@Valid注解。實際上你自定義注解,名稱只要一Valid開頭都成~~~~~
        if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
            // 拿到分組group后,調用binder的validate()進行校驗~~~~
            // 可以看到:拿到一個合適的注解后,立馬就break了~~~
            // 所以若你兩個主機都標注@Validated和@Valid,效果是一樣滴~
            Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
            Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
            binder.validate(validationHints);
            break;
        }
    }

binder.validate() 的實現中使用的 org.springframework.validation.Validator 的接口,該接口的實現為 SpringValidatorAdapter。

public void validate(Object... validationHints) {
    Object target = getTarget();
    Assert.state(target != null, "No target to validate");
    BindingResult bindingResult = getBindingResult();


    for (Validator validator : getValidators()) {
       // 使用的org.springframework.validation.Validator,調用SpringValidatorAdapter.validate
       if (!ObjectUtils.isEmpty(validationHints) && validator instanceof SmartValidator) {
          ((SmartValidator) validator).validate(target, bindingResult, validationHints);
       }
       else if (validator != null) {
          validator.validate(target, bindingResult);
       }
    }
}

在 ValidatorAdapter.validate 實現中,最終調用了 javax.validation.Validator.validate,也就是說最終是調用 JSR 實現,@Validate 只是外層的包裝,在這個包裝中擴展的分組功能。

public class SpringValidatorAdapter {
    ...
    private javax.validation.Validator targetValidator;
    
    @Override
    public void validate(Object target, Errors errors) {
        if (this.targetValidator != null) {
           processConstraintViolations(
               // 最終是調用JSR實現
               this.targetValidator.validate(target), errors));
        }
    }
 }

targetValidator.validate 就是 javax.validation.Validator.validate 上述 2.6 Bean 層面手工驗證一致。

Service自動執行約束校驗原理

非Controller的@RequestBody注解,自動執行約束校驗,是通過 MethodValidationPostProcessor 實現的,該類繼承。

BeanPostProcessor, 在 Spring Bean 初始化過程中讀取 @Validated 注解創建 AOP 代理(實現方式與 @Async 基本一致)。該類開頭文檔注解(JSR 生效必須類層面上打上 @Spring Validated 注解)。

/**
* <p>Target classes with such annotated methods need to be annotated with Spring's
* {@link Validated} annotation at the type level, for their methods to be searched for
* inline constraint annotations. Validation groups can be specified through {@code @Validated}
* as well. By default, JSR-303 will validate against its default group only.
*/
public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor
       implements InitializingBean {


    private Class<? extends Annotation> validatedAnnotationType = Validated.class;


    @Nullable
    private Validator validator;
    
    .....
        
    /**
     * 設置Validator
     * Set the JSR-303 Validator to delegate to for validating methods.
     * <p>Default is the default ValidatorFactory's default Validator.
     */
    public void setValidator(Validator validator) {
       // Unwrap to the native Validator with forExecutables support
       if (validator instanceof LocalValidatorFactoryBean) {
          this.validator = ((LocalValidatorFactoryBean) validator).getValidator();
       }
       else if (validator instanceof SpringValidatorAdapter) {
          this.validator = validator.unwrap(Validator.class);
       }
       else {
          this.validator = validator;
       }
    }


    /**
     * Create AOP advice for method validation purposes, to be applied
 * with a pointcut for the specified 'validated' annotation.
     * @param validator the JSR-303 Validator to delegate to
     * @return the interceptor to use (typically, but not necessarily,
     * a {@link MethodValidationInterceptor} or subclass thereof)
     * @since 4.2
     */
    protected Advice createMethodValidationAdvice(@Nullable Validator validator) {
       // 創建了方法調用時的攔截器
       return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor());
    }


}

真正執行方法調用時,會走到 MethodValidationInterceptor.invoke,進行約束校驗。

public class MethodValidationInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        // Avoid Validator invocation on FactoryBean.getObjectType/isSingleton
        if (isFactoryBeanMetadataMethod(invocation.getMethod())) {
           return invocation.proceed();
        }
    
        // Standard Bean Validation 1.1 API
        ExecutableValidator execVal = this.validator.forExecutables();
        ...
    
        try {
           // 執行約束校驗
           result = execVal.validateParameters(
                 invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
        }
        catch (IllegalArgumentException ex) {
           // Probably a generic type mismatch between interface and impl as reported in SPR-12237 / HV-1011
           // Let's try to find the bridged method on the implementation class...
           methodToValidate = BridgeMethodResolver.findBridgedMethod(
                 ClassUtils.getMostSpecificMethod(invocation.getMethod(), invocation.getThis().getClass()));
           result = execVal.validateParameters(
                 invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
        }
        
        ...
    
        return returnValue;
    }
}

execVal.validateParameters 就是 javax.validation.executable.ExecutableValidator.validateParameters 與上述 3.5 方法層面手工驗證一致。

五、總結

圖片圖片

參考文章:https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single

責任編輯:武曉燕 來源: 得物技術
相關推薦

2020-08-31 08:42:21

Node Controller數據校驗

2022-11-02 14:45:24

Python數據分析工具

2010-01-08 14:41:24

JSON 緩存數據

2017-10-31 11:55:46

sklearn數據挖掘自動化

2017-09-26 19:02:09

PythonInstagram數據分析

2023-09-27 15:34:48

數據編程

2024-10-28 12:57:36

Pandas數據清洗

2019-09-30 10:12:21

機器學習數據映射

2009-03-16 10:29:45

數據挖掘過濾器Access

2009-09-08 16:50:12

使用LINQ進行數據轉

2019-09-27 12:44:03

數據建模企業數據存儲

2022-06-09 11:47:21

工具數據儀連接器

2017-02-16 08:41:09

數據Vlookup匹配

2010-01-18 17:14:50

C++語言

2021-12-10 15:03:20

數字化轉型企業技術

2019-01-15 14:21:13

Python數據分析數據

2022-04-15 10:36:11

數據治理企業

2025-02-10 10:29:32

2022-09-16 13:26:49

云計算云遷移數據

2022-06-06 06:10:00

密碼驗證安全
點贊
收藏

51CTO技術棧公眾號

三级黄色片免费看| 国产麻豆乱码精品一区二区三区| av永久免费观看| 日日夜夜精品| 五月天激情小说综合| 亚洲国产精品www| 精品久久人妻av中文字幕| 国产一区二区三区的电影 | 欧美一级在线亚洲天堂| frxxee中国xxx麻豆hd| 亚洲日本va| 欧美视频免费在线| 国内精品国产三级国产99| 四虎成人免费在线| 国产精品中文字幕日韩精品 | 国产精品88久久久久久妇女| 亚洲aⅴ乱码精品成人区| 精品一区二区三区视频在线观看| 午夜免费在线观看精品视频| 99re6热在线精品视频| 欧美三级午夜理伦三级小说| 9191久久久久久久久久久| 欧美 国产 综合| 亚洲奶水xxxx哺乳期| 国产校园另类小说区| 国产精品日韩二区| 国产伦精品一区二区三区视频痴汉| 欧美一级久久| 国产69精品久久久久99| 青娱乐国产在线| 日韩欧美国产精品综合嫩v| 亚洲国产欧美一区二区丝袜黑人| 亚欧美一区二区三区| 精品国产黄a∨片高清在线| 欧美日韩日本国产| 人人妻人人做人人爽| 嫩草在线视频| 中文字幕一区二区三区色视频| 欧美国产视频在线观看| 五月婷婷六月色| jizz一区二区| 狠狠色噜噜狠狠狠狠色吗综合| 国产999久久久| 国产一区久久久| 国产精品偷伦视频免费观看国产| 免费av中文字幕| 首页亚洲欧美制服丝腿| 欧洲成人午夜免费大片| 日日夜夜综合网| 国产欧美日韩一区二区三区在线| 欧美高跟鞋交xxxxxhd| 99精品久久久久| 欧美黄色aaaa| 久久久久久美女| 国产无码精品久久久| 亚洲黄色影片| 91精品国产高清| 亚洲天堂av片| 肉丝袜脚交视频一区二区| 日本免费久久高清视频| 成人h动漫精品一区二区下载| 久久精品中文| 国产精品日本精品| 91国内精品视频| 国产精品资源网站| 国产精品视频在线免费观看 | 一区二区三区回区在观看免费视频| 高潮毛片无遮挡| 日韩免费视频| 九九热精品视频国产| 久久久久久蜜桃| 国产亚洲激情| 国产精品吊钟奶在线| 艳妇乳肉豪妇荡乳av| 国产一区二区三区美女| 国产精品入口免费| 国产一区精品| 日韩毛片在线免费观看| 99er在线视频| av资源亚洲| 欧美人与禽zozo性伦| 中国老熟女重囗味hdxx| 色吊丝一区二区| 在线丨暗呦小u女国产精品| 国产午夜精品理论片| 在线观看日韩av电影| 秋霞av国产精品一区| 国产精品国产一区二区三区四区 | 97se在线视频| 色视频免费在线观看| 国产精品美女久久久久久2018| 亚洲av综合色区| 国产精品伦理| 91精品国产欧美一区二区| 中文字幕精品久久久| 欧美va久久久噜噜噜久久| 久久久久免费精品国产| 日韩精选在线观看| 成人美女视频在线观看| 视频一区亚洲| 亚洲电影观看| 欧美一区二区久久久| 亚洲一区二区在线免费| 久久亚洲国产| 欧美亚洲日本网站| www.久久成人| 国产精品乱码人人做人人爱| 成年人午夜视频在线观看 | 久久午夜精品一区二区| 999视频在线观看| 精品av中文字幕在线毛片| 亚洲精品成a人| 波多结衣在线观看| 欧美高清视频看片在线观看| 毛片精品免费在线观看| 最新中文字幕第一页| 不卡免费追剧大全电视剧网站| 亚洲视频欧美在线| 日韩pacopacomama| 亚洲精品国产电影| 久久国产在线观看| 久久99精品国产91久久来源| 欧美日韩在线精品| av在线网页| 日韩欧美国产午夜精品| 中文字幕乱码av| 天堂va蜜桃一区二区三区 | 婷婷丁香久久五月婷婷| 一卡二卡三卡四卡五卡| 国产电影一区二区在线观看| 国产精品爱久久久久久久| 日韩中文字幕影院| 亚洲自拍与偷拍| 欧美污在线观看| 1024精品久久久久久久久| 国产精品入口免费视频一| 蜜桃视频在线观看网站| 欧美日韩激情视频8区| 中文字幕在线播放一区二区| 教室别恋欧美无删减版| 欧美综合在线第二页| 午夜视频在线免费播放| 亚洲成av人片在线| 7788色淫网站小说| 午夜在线播放视频欧美| 麻豆精品蜜桃一区二区三区| rebdb初裸写真在线观看| 精品国产三级电影在线观看| 免费无遮挡无码永久在线观看视频| 国内成人精品2018免费看| 国产福利片一区二区| 二区三区精品| 久久99久久亚洲国产| 草逼视频免费看| 亚洲成年人影院| 中出视频在线观看| 天堂资源在线中文精品| 亚洲精品国产一区| 成人永久在线| 久久久久久香蕉网| 麻豆影视在线| 欧美日韩一区二区三区四区| 国产人与禽zoz0性伦| 国产综合色产在线精品| 国产情侣第一页| 乱亲女h秽乱长久久久| 日韩美女视频免费看| 深夜福利在线看| 欧美网站在线观看| 美国一级黄色录像| 国产一级精品在线| 伊人成色综合网| 成人3d动漫在线观看| 成人两性免费视频| 999精品网| 亚洲欧美中文在线视频| 91免费视频播放| 亚洲成av人影院在线观看网| 中文字幕 自拍| 国产一区高清在线| 91黄色小网站| 天天综合久久| 国产亚洲第一区| 97成人超碰| 欧美黄色三级网站| 免费在线稳定资源站| 911精品国产一区二区在线| 91香蕉在线视频| 国产精品视频一二三区| 国产精品久久久久久亚洲av| 男人的j进女人的j一区| 国产精品免费看久久久无码| 香蕉久久夜色精品国产更新时间 | 成人精品电影| www日韩av| 欧美国产日韩电影| 久久久久久久久久久久av| 91网页在线观看| 亚洲成人免费在线视频| 在线免费观看一区二区| 婷婷综合五月天| 欧美一区免费观看| 久久久综合激的五月天| xxxx视频在线观看| 日韩av在线发布| 精品国产av无码一区二区三区| 日韩精品一区二区三区免费观影| 国产一区二区不卡视频| 警花av一区二区三区| 国产精品白嫩初高中害羞小美女| 黄页网站大全在线免费观看| www.久久久久| 国产一二三区在线| 日韩av中文字幕在线| 国产成人三级一区二区在线观看一| 91福利视频网站| 日韩不卡视频在线| 午夜精品久久久久久久蜜桃app| 国产真实乱在线更新| 欧美韩国一区二区| b站大片免费直播| 99热精品一区二区| 免费看三级黄色片| 韩国精品在线观看| 国产欧美一区二| 免费观看成人鲁鲁鲁鲁鲁视频| av网站在线观看不卡| 亚洲九九精品| 91精品国产91久久久久麻豆 主演| 99久精品视频在线观看视频| 亚洲v国产v在线观看| 欧美亚洲精品在线| 欧美日韩在线高清| 国产欧美日韩| 日本一区二区三区视频在线观看 | 久久这里都是精品| 午夜视频在线观看国产| 成人精品电影在线观看| 亚洲欧美日韩偷拍| 99久久婷婷国产综合精品| 午夜av免费看| 91小视频免费观看| 欧美bbbbb性bbbbb视频| 91蝌蚪porny成人天涯| 五月婷婷综合在线观看| 2023国产精品自拍| 在线观看日本中文字幕| 欧美激情在线免费观看| 黄色片在线观看免费| 国产精品素人一区二区| 日韩欧美视频免费观看| 成人欧美一区二区三区| 一区二区视频免费看| 亚洲另类中文字| 国产亚洲欧美精品久久久www| 亚洲一区二区视频| 全部毛片永久免费看| 91久久久免费一区二区| 中文字幕一区二区三区人妻四季| 欧美巨大另类极品videosbest | 精品99一区二区三区| 天天色棕合合合合合合合| 精品无人区乱码1区2区3区在线 | 国产xxxx在线观看| 欧美精品一区二区三区蜜桃| 欧美色视频免费| www国产91| 搞黄网站在线看| 国产ts一区二区| 色999久久久精品人人澡69| 91免费版网站在线观看| 欧美1区二区| 亚洲欧洲精品一区| 黄色精品免费| 免费激情视频在线观看| 国产精品亚洲成人| 三级男人添奶爽爽爽视频| 国产精品久久久久9999吃药| 激情综合五月网| 91精品福利视频| 精品久久久无码中文字幕| 亚洲免费电影一区| 蜜桃视频网站在线观看| 性色av一区二区三区免费| 欧洲成人一区| 国产欧美日韩在线播放| 精品午夜久久| 欧美一级欧美一级| 日韩av成人高清| 国产大学生视频| 欧美国产精品v| 国产精品第一页在线观看| 欧美日韩日日摸| 婷婷在线免费观看| www.日韩av.com| 最新中文字幕在线播放| 91传媒在线免费观看| 国产精品免费大片| 拔插拔插海外华人免费| 激情文学综合丁香| 天天躁日日躁aaaa视频| 亚洲成人av免费| 国内毛片毛片毛片毛片| 国产亚洲精品久久久久久| sis001亚洲原创区| 成人美女av在线直播| 国产麻豆精品久久| 奇米精品一区二区三区| 国产成人av福利| 林心如三级全黄裸体| 富二代精品短视频| 亚洲国产精品一| 日韩天堂在线视频| japanese23hdxxxx日韩| 国产主播一区二区三区四区| 欧美成人首页| 999久久久精品视频| 国产精品视频看| 日韩美一区二区| 日韩av影视综合网| 好看的中文字幕在线播放| 91欧美日韩一区| 91精品啪在线观看国产18| 久久国产这里只有精品| 中文字幕第一区二区| 一级片在线观看免费| 日韩经典一区二区三区| 成人高潮aa毛片免费| 成人av播放| 欧美片第1页综合| 自拍偷拍激情视频| 亚洲精品久久久久久国产精华液| 亚洲图片中文字幕| 中文在线不卡视频| 91成人抖音| 亚洲成人第一| 美国欧美日韩国产在线播放| 国产黄色大片免费看| 日本韩国一区二区| 国产露出视频在线观看| 国产精品国产福利国产秒拍| 国产日产精品一区二区三区四区的观看方式| 和岳每晚弄的高潮嗷嗷叫视频| 国产aⅴ综合色| 久久香蕉精品视频| 亚洲缚视频在线观看| 888av在线视频| 精品国产中文字幕| 天堂va蜜桃一区二区三区 | 夜夜嗨av一区二区三区网页| 亚洲高清在线观看视频| 久久久日本电影| 免费看久久久| 精品www久久久久奶水| 国产日产精品1区| 一区二区视频播放| 裸体女人亚洲精品一区| 亚洲国产中文在线| 91专区在线观看| 国产午夜一区二区三区| 国产永久免费视频| 欧美另类高清videos| 欧美激情极品| 538在线视频观看| 日韩一区中文字幕| 亚洲国产视频一区二区三区| 91精品成人久久| 欧美日韩伦理在线免费| 精品国产鲁一鲁一区二区三区| 亚洲在线视频免费观看| 亚州av在线播放| 国产在线视频2019最新视频| 亚洲性色视频| 中文字幕国产专区| 69久久99精品久久久久婷婷 | 中文在线日韩| 噜噜噜在线视频| 69p69国产精品| 成入视频在线观看| 亚洲精品成人a8198a| 成人午夜激情影院| 中文字幕日本视频| 欧美黄色三级网站| 国产在视频线精品视频www666| 一级网站在线观看| 欧美日韩精品二区| 国内外激情在线| 久久一区二区三区欧美亚洲| 久久99国产精品成人| 日韩字幕在线观看| 久久香蕉频线观| 亚洲精品推荐| 亚洲天堂小视频| 欧美综合在线视频| 福利写真视频网站在线| 一区二区成人国产精品| 99精品视频在线播放观看| 国产美女免费看| 国产成人精品在线视频| 在线观看一区视频|