国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频

Spring Boot 實(shí)現(xiàn)各種參數(shù)校驗(yàn),寫得太好了,建議收藏!

共 25971字,需瀏覽 52分鐘

 ·

2022-07-17 02:49

點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)

來源:juejin.im/post/6856541106626363399

作者:夜盡天明_


之前也寫過一篇關(guān)于Spring Validation使用的文章,不過自我感覺還是浮于表面,本次打算徹底搞懂Spring Validation。本文會(huì)詳細(xì)介紹Spring Validation各種場(chǎng)景下的最佳實(shí)踐及其實(shí)現(xiàn)原理,死磕到底!

項(xiàng)目源碼:https://github.com/chentianming11/spring-validation

簡(jiǎn)單使用

Java API規(guī)范(JSR303)定義了Bean校驗(yàn)的標(biāo)準(zhǔn)validation-api,但沒有提供實(shí)現(xiàn)。hibernate validation是對(duì)這個(gè)規(guī)范的實(shí)現(xiàn),并增加了校驗(yàn)注解如@Email、@Length等。

Spring Validation是對(duì)hibernate validation的二次封裝,用于支持spring mvc參數(shù)自動(dòng)校驗(yàn)。接下來,我們以spring-boot項(xiàng)目為例,介紹Spring Validation的使用。

引入依賴

如果spring-boot版本小于2.3.x,spring-boot-starter-web會(huì)自動(dòng)傳入hibernate-validator依賴。如果spring-boot版本大于2.3.x,則需要手動(dòng)引入依賴:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.1.Final</version>
</dependency>

對(duì)于web服務(wù)來說,為防止非法參數(shù)對(duì)業(yè)務(wù)造成影響,在Controller層一定要做參數(shù)校驗(yàn)的!大部分情況下,請(qǐng)求參數(shù)分為如下兩種形式:

  • POST、PUT請(qǐng)求,使用requestBody傳遞參數(shù);
  • GET請(qǐng)求,使用requestParam/PathVariable傳遞參數(shù)。

下面我們簡(jiǎn)單介紹下requestBody和requestParam/PathVariable的參數(shù)校驗(yàn)實(shí)戰(zhàn)!

requestBody參數(shù)校驗(yàn)

POST、PUT請(qǐng)求一般會(huì)使用requestBody傳遞參數(shù),這種情況下,后端使用DTO對(duì)象進(jìn)行接收。只要給DTO對(duì)象加上@Validated注解就能實(shí)現(xiàn)自動(dòng)參數(shù)校驗(yàn)。比如,有一個(gè)保存User的接口,要求userName長(zhǎng)度是2-10,account和password字段長(zhǎng)度是6-20。

如果校驗(yàn)失敗,會(huì)拋出MethodArgumentNotValidException異常,Spring默認(rèn)會(huì)將其轉(zhuǎn)為400(Bad Request)請(qǐng)求。

DTO表示數(shù)據(jù)傳輸對(duì)象(Data Transfer Object),用于服務(wù)器和客戶端之間交互傳輸使用的。在spring-web項(xiàng)目中可以表示用于接收請(qǐng)求參數(shù)的Bean對(duì)象。

在DTO字段上聲明約束注解

@Data
public class UserDTO {

    private Long userId;

    @NotNull
    @Length(min = 2, max = 10)
    private String userName;

    @NotNull
    @Length(min = 6, max = 20)
    private String account;

    @NotNull
    @Length(min = 6, max = 20)
    private String password;
}

在方法參數(shù)上聲明校驗(yàn)注解

@PostMapping("/save")
public Result saveUser(@RequestBody @Validated UserDTO userDTO) {
    // 校驗(yàn)通過,才會(huì)執(zhí)行業(yè)務(wù)邏輯處理
    return Result.ok();
}

這種情況下,使用@Valid和@Validated都可以。

requestParam/PathVariable參數(shù)校驗(yàn)

GET請(qǐng)求一般會(huì)使用requestParam/PathVariable傳參。如果參數(shù)比較多(比如超過6個(gè)),還是推薦使用DTO對(duì)象接收。

否則,推薦將一個(gè)個(gè)參數(shù)平鋪到方法入?yún)⒅?。在這種情況下,必須在Controller類上標(biāo)注@Validated注解,并在入?yún)⑸下暶骷s束注解(如@Min等)。如果校驗(yàn)失敗,會(huì)拋出ConstraintViolationException異常。

代碼示例如下:

@RequestMapping("/api/user")
@RestController
@Validated
public class UserController {
    // 路徑變量
    @GetMapping("{userId}")
    public Result detail(@PathVariable("userId") @Min(10000000000000000L) Long userId) {
        // 校驗(yàn)通過,才會(huì)執(zhí)行業(yè)務(wù)邏輯處理
        UserDTO userDTO = new UserDTO();
        userDTO.setUserId(userId);
        userDTO.setAccount("11111111111111111");
        userDTO.setUserName("xixi");
        userDTO.setAccount("11111111111111111");
        return Result.ok(userDTO);
    }

    // 查詢參數(shù)
    @GetMapping("getByAccount")
    public Result getByAccount(@Length(min = 6, max = 20) @NotNull String  account) {
        // 校驗(yàn)通過,才會(huì)執(zhí)行業(yè)務(wù)邏輯處理
        UserDTO userDTO = new UserDTO();
        userDTO.setUserId(10000000000000003L);
        userDTO.setAccount(account);
        userDTO.setUserName("xixi");
        userDTO.setAccount("11111111111111111");
        return Result.ok(userDTO);
    }
}

統(tǒng)一異常處理

前面說過,如果校驗(yàn)失敗,會(huì)拋出MethodArgumentNotValidException或者ConstraintViolationException異常。在實(shí)際項(xiàng)目開發(fā)中,通常會(huì)用統(tǒng)一異常處理來返回一個(gè)更友好的提示。

比如我們系統(tǒng)要求無論發(fā)送什么異常,http的狀態(tài)碼必須返回200,由業(yè)務(wù)碼去區(qū)分系統(tǒng)的異常情況。

@RestControllerAdvice
public class CommonExceptionHandler {

    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException ex
{
        BindingResult bindingResult = ex.getBindingResult();
        StringBuilder sb = new StringBuilder("校驗(yàn)失敗:");
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", ");
        }
        String msg = sb.toString();
       return Result.fail(BusinessCode.參數(shù)校驗(yàn)失敗, msg);
    }

    @ExceptionHandler({ConstraintViolationException.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public Result handleConstraintViolationException(ConstraintViolationException ex
{
        return Result.fail(BusinessCode.參數(shù)校驗(yàn)失敗, ex.getMessage());
    }
}

推薦下自己做的 Spring Boot 的實(shí)戰(zhàn)項(xiàng)目:

https://github.com/YunaiV/ruoyi-vue-pro

進(jìn)階使用

分組校驗(yàn)

在實(shí)際項(xiàng)目中,可能多個(gè)方法需要使用同一個(gè)DTO類來接收參數(shù),而不同方法的校驗(yàn)規(guī)則很可能是不一樣的。這個(gè)時(shí)候,簡(jiǎn)單地在DTO類的字段上加約束注解無法解決這個(gè)問題。因此,spring-validation支持了分組校驗(yàn)的功能,專門用來解決這類問題。

還是上面的例子,比如保存User的時(shí)候,UserId是可空的,但是更新User的時(shí)候,UserId的值必須>=10000000000000000L;其它字段的校驗(yàn)規(guī)則在兩種情況下一樣。這個(gè)時(shí)候使用分組校驗(yàn)的代碼示例如下:

約束注解上聲明適用的分組信息groups

@Data
public class UserDTO {

    @Min(value = 10000000000000000L, groups = Update.class)
    private Long userId
;

    @NotNull(groups = {Save.classUpdate.class})
    @Length(min 
2, max = 10, groups = {Save.classUpdate.class})
    private String userName
;

    @NotNull(groups = {Save.classUpdate.class})
    @Length(min 
6, max = 20, groups = {Save.classUpdate.class})
    private String account
;

    @NotNull(groups = {Save.classUpdate.class})
    @Length(min 
6, max = 20, groups = {Save.classUpdate.class})
    private String password
;

    /**
     * 保存的時(shí)候校驗(yàn)分組
     */

    public interface Save {
    }

    /**
     * 更新的時(shí)候校驗(yàn)分組
     */

    public interface Update {
    }
}

@Validated注解上指定校驗(yàn)分組

@PostMapping("/save")
public Result saveUser(@RequestBody @Validated(UserDTO.Save.class) UserDTO userDTO) {
    // 校驗(yàn)通過,才會(huì)執(zhí)行業(yè)務(wù)邏輯處理
    return Result.ok();
}

@PostMapping("/update")
public Result updateUser(@RequestBody @Validated(UserDTO.Update.class) UserDTO userDTO) {
    // 校驗(yàn)通過,才會(huì)執(zhí)行業(yè)務(wù)邏輯處理
    return Result.ok();
}

嵌套校驗(yàn)

前面的示例中,DTO類里面的字段都是基本數(shù)據(jù)類型和String類型。但是實(shí)際場(chǎng)景中,有可能某個(gè)字段也是一個(gè)對(duì)象,這種情況先,可以使用嵌套校驗(yàn)。

比如,上面保存User信息的時(shí)候同時(shí)還帶有Job信息。需要注意的是,此時(shí)DTO類的對(duì)應(yīng)字段必須標(biāo)記@Valid注解。

@Data
public class UserDTO {

    @Min(value = 10000000000000000L, groups = Update.class)
    private Long userId
;

    @NotNull(groups = {Save.classUpdate.class})
    @Length(min 
2, max = 10, groups = {Save.classUpdate.class})
    private String userName
;

    @NotNull(groups = {Save.classUpdate.class})
    @Length(min 
6, max = 20, groups = {Save.classUpdate.class})
    private String account
;

    @NotNull(groups = {Save.classUpdate.class})
    @Length(min 
6, max = 20, groups = {Save.classUpdate.class})
    private String password
;

    @NotNull(groups = {Save.classUpdate.class})
    @Valid
    private Job job
;

    @Data
    public static class Job {

        @Min(value = 1, groups = Update.class)
        private Long jobId
;

        @NotNull(groups = {Save.classUpdate.class})
        @Length(min 
2, max = 10, groups = {Save.classUpdate.class})
        private String jobName
;

        @NotNull(groups = {Save.classUpdate.class})
        @Length(min 
2, max = 10, groups = {Save.classUpdate.class})
        private String position
;
    }

    /**
     * 保存的時(shí)候校驗(yàn)分組
     */

    public interface Save {
    }

    /**
     * 更新的時(shí)候校驗(yàn)分組
     */

    public interface Update {
    }
}

嵌套校驗(yàn)可以結(jié)合分組校驗(yàn)一起使用。還有就是嵌套集合校驗(yàn)會(huì)對(duì)集合里面的每一項(xiàng)都進(jìn)行校驗(yàn),例如List<Job>字段會(huì)對(duì)這個(gè)list里面的每一個(gè)Job對(duì)象都進(jìn)行校驗(yàn)

集合校驗(yàn)

如果請(qǐng)求體直接傳遞了json數(shù)組給后臺(tái),并希望對(duì)數(shù)組中的每一項(xiàng)都進(jìn)行參數(shù)校驗(yàn)。此時(shí),如果我們直接使用java.util.Collection下的list或者set來接收數(shù)據(jù),參數(shù)校驗(yàn)并不會(huì)生效!我們可以使用自定義list集合來接收參數(shù):

包裝List類型,并聲明@Valid注解

public class ValidationList<Eimplements List<E{

    @Delegate // @Delegate是lombok注解
    @Valid // 一定要加@Valid注解
    public List<E> list = new ArrayList<>();

    // 一定要記得重寫toString方法
    @Override
    public String toString() {
        return list.toString();
    }
}

@Delegate注解受lombok版本限制,1.18.6以上版本可支持。如果校驗(yàn)不通過,會(huì)拋出NotReadablePropertyException,同樣可以使用統(tǒng)一異常進(jìn)行處理。

比如,我們需要一次性保存多個(gè)User對(duì)象,Controller層的方法可以這么寫:

@PostMapping("/saveList")
public Result saveList(@RequestBody @Validated(UserDTO.Save.class) ValidationList<UserDTO> userList) {
    // 校驗(yàn)通過,才會(huì)執(zhí)行業(yè)務(wù)邏輯處理
    return Result.ok();
}

自定義校驗(yàn)

業(yè)務(wù)需求總是比框架提供的這些簡(jiǎn)單校驗(yàn)要復(fù)雜的多,我們可以自定義校驗(yàn)來滿足我們的需求。

自定義spring validation非常簡(jiǎn)單,假設(shè)我們自定義加密id(由數(shù)字或者a-f的字母組成,32-256長(zhǎng)度)校驗(yàn),主要分為兩步:

自定義約束注解

@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {EncryptIdValidator.class})
public @interface EncryptId 
{

    // 默認(rèn)錯(cuò)誤消息
    String message() default "加密id格式錯(cuò)誤";

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

    // 負(fù)載
    Class<? extends Payload>[] payload() default {};
}

實(shí)現(xiàn)ConstraintValidator接口編寫約束校驗(yàn)器

public class EncryptIdValidator implements ConstraintValidator<EncryptIdString{

    private static final Pattern PATTERN = Pattern.compile("^[a-f\\d]{32,256}$");

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        // 不為null才進(jìn)行校驗(yàn)
        if (value != null) {
            Matcher matcher = PATTERN.matcher(value);
            return matcher.find();
        }
        return true;
    }
}

這樣我們就可以使用@EncryptId進(jìn)行參數(shù)校驗(yàn)了!

編程式校驗(yàn)

上面的示例都是基于注解來實(shí)現(xiàn)自動(dòng)校驗(yàn)的,在某些情況下,我們可能希望以編程方式調(diào)用驗(yàn)證。這個(gè)時(shí)候可以注入javax.validation.Validator對(duì)象,然后再調(diào)用其api。

@Autowired
private javax.validation.Validator globalValidator;

// 編程式校驗(yàn)
@PostMapping("/saveWithCodingValidate")
public Result saveWithCodingValidate(@RequestBody UserDTO userDTO) {
    Set<ConstraintViolation<UserDTO>> validate = globalValidator.validate(userDTO, UserDTO.Save.class);
    // 如果校驗(yàn)通過,validate為空;否則,validate包含未校驗(yàn)通過項(xiàng)
    if (validate.isEmpty()) {
        // 校驗(yàn)通過,才會(huì)執(zhí)行業(yè)務(wù)邏輯處理

    } else {
        for (ConstraintViolation<UserDTO> userDTOConstraintViolation : validate) {
            // 校驗(yàn)失敗,做其它邏輯
            System.out.println(userDTOConstraintViolation);
        }
    }
    return Result.ok();
}

快速失敗(Fail Fast)

Spring Validation默認(rèn)會(huì)校驗(yàn)完所有字段,然后才拋出異常??梢酝ㄟ^一些簡(jiǎn)單的配置,開啟Fali Fast模式,一旦校驗(yàn)失敗就立即返回。

@Bean
public Validator validator() {
    ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
            .configure()
            // 快速失敗模式
            .failFast(true)
            .buildValidatorFactory()
;
    return validatorFactory.getValidator();
}

@Valid和@Validated區(qū)別

推薦下自己做的 Spring Cloud 的實(shí)戰(zhàn)項(xiàng)目:

https://github.com/YunaiV/onemall

實(shí)現(xiàn)原理

requestBody參數(shù)校驗(yàn)實(shí)現(xiàn)原理

在spring-mvc中,RequestResponseBodyMethodProcessor是用于解析@RequestBody標(biāo)注的參數(shù)以及處理@ResponseBody標(biāo)注方法的返回值的。顯然,執(zhí)行參數(shù)校驗(yàn)的邏輯肯定就在解析參數(shù)的方法resolveArgument()中:

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
    @Override
    public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory)
 throws Exception 
{

        parameter = parameter.nestedIfOptional();
        //將請(qǐng)求數(shù)據(jù)封裝到DTO對(duì)象中
        Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
        String name = Conventions.getVariableNameForParameter(parameter);

        if (binderFactory != null) {
            WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
            if (arg != null) {
                // 執(zhí)行數(shù)據(jù)校驗(yàn)
                validateIfApplicable(binder, parameter);
                if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
                    throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
                }
            }
            if (mavContainer != null) {
                mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
            }
        }
        return adaptArgumentIfNecessary(arg, parameter);
    }
}

可以看到,resolveArgument()調(diào)用了validateIfApplicable()進(jìn)行參數(shù)校驗(yàn)。

protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
    // 獲取參數(shù)注解,比如@RequestBody、@Valid、@Validated
    Annotation[] annotations = parameter.getParameterAnnotations();
    for (Annotation ann : annotations) {
        // 先嘗試獲取@Validated注解
        Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
        //如果直接標(biāo)注了@Validated,那么直接開啟校驗(yàn)。
        //如果沒有,那么判斷參數(shù)前是否有Valid起頭的注解。
        if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
            Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
            Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
            //執(zhí)行校驗(yàn)
            binder.validate(validationHints);
            break;
        }
    }
}

看到這里,大家應(yīng)該能明白為什么這種場(chǎng)景下@Validated、@Valid兩個(gè)注解可以混用。我們接下來繼續(xù)看WebDataBinder.validate()實(shí)現(xiàn)。

@Override
public void validate(Object target, Errors errors, Object... validationHints) {
    if (this.targetValidator != null) {
        processConstraintViolations(
            //此處調(diào)用Hibernate Validator執(zhí)行真正的校驗(yàn)
            this.targetValidator.validate(target, asValidationGroups(validationHints)), errors);
    }
}

最終發(fā)現(xiàn)底層最終還是調(diào)用了Hibernate Validator進(jìn)行真正的校驗(yàn)處理。

方法級(jí)別的參數(shù)校驗(yàn)實(shí)現(xiàn)原理

上面提到的將參數(shù)一個(gè)個(gè)平鋪到方法參數(shù)中,然后在每個(gè)參數(shù)前面聲明約束注解的校驗(yàn)方式,就是方法級(jí)別的參數(shù)校驗(yàn)。

實(shí)際上,這種方式可用于任何Spring Bean的方法上,比如Controller/Service等。其底層實(shí)現(xiàn)原理就是AOP,具體來說是通過MethodValidationPostProcessor動(dòng)態(tài)注冊(cè)AOP切面,然后使用MethodValidationInterceptor對(duì)切點(diǎn)方法織入增強(qiáng)。

public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessorimplements InitializingBean {
    @Override
    public void afterPropertiesSet() {
        //為所有`@Validated`標(biāo)注的Bean創(chuàng)建切面
        Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
        //創(chuàng)建Advisor進(jìn)行增強(qiáng)
        this.advisor = new DefaultPointcutAdvisor(pointcut, createMethodValidationAdvice(this.validator));
    }

    //創(chuàng)建Advice,本質(zhì)就是一個(gè)方法攔截器
    protected Advice createMethodValidationAdvice(@Nullable Validator validator) {
        return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor());
    }
}

接著看一下MethodValidationInterceptor:

public class MethodValidationInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        //無需增強(qiáng)的方法,直接跳過
        if (isFactoryBeanMetadataMethod(invocation.getMethod())) {
            return invocation.proceed();
        }
        //獲取分組信息
        Class<?>[] groups = determineValidationGroups(invocation);
        ExecutableValidator execVal = this.validator.forExecutables();
        Method methodToValidate = invocation.getMethod();
        Set<ConstraintViolation<Object>> result;
        try {
            //方法入?yún)⑿r?yàn),最終還是委托給Hibernate Validator來校驗(yàn)
            result = execVal.validateParameters(
                invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
        }
        catch (IllegalArgumentException ex) {
            ...
        }
        //有異常直接拋出
        if (!result.isEmpty()) {
            throw new ConstraintViolationException(result);
        }
        //真正的方法調(diào)用
        Object returnValue = invocation.proceed();
        //對(duì)返回值做校驗(yàn),最終還是委托給Hibernate Validator來校驗(yàn)
        result = execVal.validateReturnValue(invocation.getThis(), methodToValidate, returnValue, groups);
        //有異常直接拋出
        if (!result.isEmpty()) {
            throw new ConstraintViolationException(result);
        }
        return returnValue;
    }
}

實(shí)際上,不管是requestBody參數(shù)校驗(yàn)還是方法級(jí)別的校驗(yàn),最終都是調(diào)用Hibernate Validator執(zhí)行校驗(yàn),Spring Validation只是做了一層封裝。


1、致歉!抖音Semi Design承認(rèn)參考阿里Ant Design

2、對(duì)比7種分布式事務(wù)方案,還是偏愛阿里開源的Seata,真香!

3、Redis存儲(chǔ)結(jié)構(gòu)體信息,選hash還是string?

4、掃盲 docker 常用命令

5、最全分布式Session解決方案

6、21 款 yyds 的 IDEA插件

7、真香!用 IDEA 神器看源碼,效率真高!

點(diǎn)分享

點(diǎn)收藏

點(diǎn)點(diǎn)贊

點(diǎn)在看

瀏覽 38
點(diǎn)贊
評(píng)論
收藏
分享

手機(jī)掃一掃分享

分享
舉報(bào)
評(píng)論
圖片
表情
推薦
點(diǎn)贊
評(píng)論
收藏
分享

手機(jī)掃一掃分享

分享
舉報(bào)

感谢您访问我们的网站,您可能还对以下资源感兴趣:

国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频 老妇bbw| 中文字幕精品无码| A免费观看| 91精品日韩| 中文字幕久热| gogogo高清在线观看免费直播中国| 99国产免费视频| AV无码免费观看| 9l视频自拍蝌蚪9l视频成人| 亚洲精品久久久久久久久豆丁网 | 男女成人视频| 黄色资源在线观看| 久久久伊人网| 小黄片免费在线观看| 小黄片高清无码| 超碰在线视| 亚洲精品一区二区二区的游戏情况| 久久大鸡| 激情毛片| 欧美一本在线| 人人操在线| 国产午夜精品一区二区三区牛牛 | 亚洲无码一二三区| 免费看黄色录像| 天天人人精品| 色婷婷香蕉在线一区二区| 操大爷影院| 国产午夜福利免费视频在线观看| A视频在线免费观看| 狼友视频免费观看| 色五婷婷| 激情开心站| 婷婷视频在线观看| 亚洲免费观看在线观看| 午夜成人在线| 51妺妺嘿嘿午夜成人| 成人性爱AV| 69自拍视频| 亚洲中文字| 欧美日韩久久久| 丁香婷婷色五月| 一级电影视频去去去| 99re99| 围内精品久久久久久久久久‘变脸 | 国产人妖av| 3D动漫啪啪精品一区二区中文字幕 | 成人精品网| 日韩AV片| 国产凹凸视频在线观看| 色99999| 国产传媒一区| 亚洲第一黄色| 久久综合伊人777777| 日韩高清一级免费| 亚洲综合天堂| 欧美日韩人妻高清中文| 高潮喷水在线观看| 四川性BBB搡BBB爽爽爽小说| 五月天婷婷在线观看| 国产欧美成人在线| 国产婷婷久久Av免费高清| 波多野结衣91| 688AV秘无码一区二区| 中日韩一级片| 91精品久| 国产欧美高清在线| 国产三级av在线| 中文字幕在线视频无码| 大鸡巴导航| 操比视频在线观看| 日韩中文字幕永久| 亚洲AV无码成人精品涩涩麻豆| 操操综合| 一区二区在线不卡| 亚洲视频在线免费播放| 成人激情四射网| 国产精品激情| 99福利视频| 欧美最猛黑A片黑人猛交蜜桃视频| 国产成人视频在线| 国产一级婬乱片AV片AAA毛片| 草碰在线视频| 亚洲色图图片| 麻豆精品一区| 日韩69视频| 亚洲另类视频| 99久久婷婷国产精品2020| 成人综合大香蕉| 欧美精产国品一二三区| 日本高清无码在线| 嫩BBB槡BBBB槡BBBB二一| 免费在线成人网| 91亚洲高清| 爱爱综合| 周晓琳AV| 黄片免费观看视频| 中文在线免费看视频| 在线免费观看国产视频| 伊人网址| 中文字幕2025年最好看电视剧| 天堂网2018| 秋霞久久日| 久久国产精品久久| 亚洲色婷婷五月天| 国产日韩在线播放| 伊人大香蕉网| 亚洲无码AV一区二区三区| 黄色无码视频在线观看| 黄色成人视频网站在线观看| 青青国产| 亚洲中文字幕网站| 黄色视频A| 大香煮伊在75| 国产色情性黄片Av网站| 91www| 一区视频免费观看| 中国熟女视频| AV资源在线| 亚洲无码一级片| 88在线无码精品秘入口九色| 高清无码中文字| 成人在线视频观看| 国产一级片在线播放| 少妇喷水视频| 一区二区免费在线观看| 成人在线91| 综合天堂AV久久久久久久| 国产综合婷婷| 操逼视频网站免费观看| 亚洲国产成人精品女人久久| 视频一视频二在线视频| 东京热男人的天堂| 成人无码一区二区三区| 在线操b| 亚洲黄色在线免费观看| 99亚洲欲妇| 亚洲色图在线观看| 夜夜爽久久精品91| 日日拍夜夜拍| 日韩中文字幕精品| 中文字幕丰满的翔田千里| 亚洲国产成人自拍| 麻豆一区| 在线观看高清无码视频| 国产日韩在线视频| 91无码AⅤ在线| 亚洲在线观看中文字幕| 国产婬片一级A片AAA毛片AⅤ | 天天肏| 日韩黄片视频| 国内自拍一区| 婷婷在线电影| 波多野吉衣高清无码| 特爽特黄特级特色视频| 蜜柚Av| 国产在线欧美在线| 日本在线免费观看| 91精品亚洲| 北条麻妃网址| 插插插视频| 日本无码成人| 尤物网站在线播放| 国产精品成人在线视频| 国产成人小电影| 日韩中文字幕永久| 中国免费视频高清观看| 操逼无码| 亚洲成人无码在线| 日逼视频免费观看| 中文av字幕| 免费无码进口视频| 色婷婷日韩精品一区二区三区| 狼友视频在线观看18| 亚洲日韩中文无码| 日韩va中文字幕无码免费| 伊人视频在线| 杨贵妃一级婬片90分钟| 91丝袜一区二区三区| 久久大陆| 欧美性区| 亚洲AV成人片色在线观看高潮| 怡红院成人在线| av免费观看网站| AAA三级视频| 久久伊人中文字幕| 波多野吉衣视频| 国内无码| 国产激情在线观看| 亚洲色图15p| 中文字幕成人电影| 欧美日日日| 亚洲成人性爱| 一级片免费| 日韩三级小说| 国产精品揄拍一区二区| 97福利视频| 黄片免费大全| 操b网站| 婷婷五月天在线观看| www.欧美日韩| 亚洲无码成人电影| h片在线免费观看| 青娱乐AV| 中文字幕av高清片,中文在线观看| 久久亚洲中文字幕乱码| 欧美伊人网在线观看| 人人操AV在线| 青吴乐大香蕉| 日韩av在线不卡| 日韩性网| 伊人日逼| 中文字幕一级A片高清免| 国产无码高清在线观看| 777三级| 午夜亚洲福利| 亚洲欧美在线视频免费| 搡BBB搡BBBB搡BBBB'| 日日干视频| 日本综合久久| 久久这里只有精品99| 91丨PORNY丨丰满人妻网站| 超碰97在线免费观看| 国产精品秘久久久久久1-~/\v7-/ 囯产精品一区二区三区线一牛影视1 | 骚视频网站| 免费一级婬片AA片观看| 91小仙女jK白丝袜呻吟| 国产成人91| 成人免费激情视频| 人人看人人摸人人草| 一区二区三区四区在线视频| 高清无码视频在线免费观看| 亚洲中文字幕免费观看| 黄色一级片在线| 老司机一区二区| 日韩精品丰满无码一级A片∴| 日韩人妻中文字幕| 污网站在线观看| 麻豆三级片| 大色欧美综合| 成人三级在线观看| 欧美激情伊人| 青青久久91| 在线成人自拍| 91久久久久久久久久久久18| 黑人亚洲娇小videos∞| 好吊妞视频在线| 成人免费一区| 免费无码婬片AAAA片老婦| 国产成人免费视频在线| 九九久热| 欧美三级大片| 九色PORNY9l原创自拍| 翔田千里AV在线| 五月天性爱视频| 97无码精品人妻| 久久肏| 久久国产黄色一级片| 中文字幕在线观看a| 一级a片在线免费观看| 亚州操B| 久久久久久久AV| 黄色中文字幕| 九九综合网| 九九视频免费观看| 热99视频| 五月婷婷中文| 亚洲热热| 青青操国产乱伦| 久色婷婷在线| 69亚洲| 高清无码不卡在线观看| 欧美日色| www.亚洲精品| 在线观看污视频| 三级片久久| 国产成人精品无码片区在线观91| 欧美性生活视频| 中字AV| 亚洲第一大网站| 天天日天天撸| 国产福利在线观看| 伊人网综合| 亚洲天堂一级片| 国产一区亚洲| 91精品人妻一区二区三区四区| 国内精品久久久久久久久98| 亚洲福利一区| 一本色道久久综合亚洲二区三区| 欧美日韩中文字幕无码| 国产午夜精品视频| 久久久高清无码视频| 国产人妖TS重口系列网站观看| 成人激情视频网| 免费在线观看毛片| 久久午夜无码鲁丝片午夜精品偷窥 | 人人操人人撸| 久久三级| 韩国一区二区三区在线观看| 欧美亚洲视频在线观看| 欧美国产日韩在线观看| 操逼网站免费观看| 久操视频在线| 久久日精品| 日韩精品成人av| 亚洲无码在线免费视频| 天天操网站| 免费无码A片在线观看全| 在线观看免费a片| 蜜桃视频在线观看视频| 国产精品国产精品国产专区不卡| 日本黄色A片| 内射学生妹视频| 国产免费av网站| 日韩在线一级| 一区不卡| 麻妃无码| 亚洲AV成人无码精品区| 特逼视频| 六月婷| 日韩AⅤ无码一区二区三区 | 青青草在线视频免费观看| 亚洲女与黑人正在播放| 国产精品视频在线播放| A片黄色电影网站| 黄色在线免费| 久久成人18免费网站波多野结衣 | 很很撸在线视频| 久久久久99精品成人片三人毛片 | 性欧美丰满熟妇XXXX性久久久 | 手机看片久草| 日韩无码人妻一区| 中文在线字幕免费观| 九色影院| 牛牛成人在线视频| 九色丨蝌蚪丨老版熟女| 亚洲午夜免费视频| 爱爱无码| 成人黄色性视频| 亚洲欧洲精品视频| 授乳奶水x88MAV| 农村A片婬片AAA毛片| 三级片在线观看网站| 日韩加勒比在线| 操屄视频网站| 在线观看黄色av| 视色视频在线观看| 一级黄色电影免费在线观看 | 亚洲欧美精品| 午夜精品18视频国产| 激情久久AV一区AV二区AV三区| 欧美婷婷五月天| 美女网站黄| 偷拍亚洲综合| 天天弄天天操| 国产无码免费| 999成人网| 一区二区三区免费在线观看| A在线观看| 青草在线视频| 操逼福利视频| 69毛片| 99在线观看视频在线高清| 亚洲中文字幕在| 婷婷色色五月天| 黄片中文| 亚洲成人综合网站| 狠狠狠干| 欧美MV日韩MV国产网站| 秋霞国产| 极品小仙女69| 国产一级AV免费观看| 人妻少妇一区二区三区| 精品福利一区二区三区| 3d动漫精品一区二区三区在线观看| 大香蕉日逼| 久久综合久久鬼色| 91蝌蚪在线观看| 一本在线| www.91madou| 色婷婷一区二区| 黄色电影毛片| 亚洲视频欧美| 色婷婷丁香五月| 波多野结衣高清av久久直播免| 国产精品欧美综合| 天堂资源| 日本在线一级| 婷婷视频在线| 日韩欧美国产一区二区| 丝袜人妻| 午夜午夜福利理论片在线播放| 一级特黄妇女高潮AA片免费播放| 逼特逼在线观看| 中文字幕乱码在线| 久久国产精品久久| 三级高清无码视频| 自拍乱伦| AV电影免费看| 麻豆黄色| 国产中文字幕亚洲综合欧美| 停停六综合| 51成人网站免费| 免费国产黄色视频网站| 国产中文字幕在线视频| 日韩三级视频在线观看| 国产精品成人99一区无码| 激情五月色五月| 日本国产在线观看| 欧美性极品少妇精品网站| 麻豆成人精品国产免费| 大香蕉一区| 天天日少妇| 欧美一二三区| av一区二区在线观看| 99热免费在线观看| 国产福利在线导航| 中文AV在线播放| 久久久老熟女一区二区三区91| 大鸡巴操骚逼视频| 国产成人精品一区二区三区四区| 日本欧美亚洲| 人人摸人人摸人人| 久久久久久久性爱| 91亚洲精品国产成人| 成人三级在线观看| 日韩中字幕无码| 美女一区| 99久热在线精品| 波多野结衣网址| 婷婷色六月| 免费一区二区三区四区| 久久九九热| 丹麦电影《下午》| 国产男女无套免费视频| 人人操人人超碰| A级片在线观看| 少妇BBBB| 先锋影音av资源网| 国产免费内射| 久热久| 69国产精品成人无码视频色| 亚洲高清视屏| 中国老熟女重囗味HDXX| 99久久久精品久久久久久| 欧美综合国产| 久久久久久伊人| 麻豆一级片| 91蜜桃在线观看| 三级电影久久麻豆| 婷婷色色婷婷| 欧美老熟妇BBBBB搡BBB| 亚洲性爱在线观看| 黄页av| 91熟女丰满原味| 大香蕉国产精品视频| 一级A片黃色A片| 日韩人妻无码一区二区三区99| 五月天一区二区三区| 久久久精品黄色网址| 色色大香蕉| 91网站观看| 五月丁香啪| 人妻福利导航| 熟妇高潮一区二区高潮| 少妇搡BBBB搡BBB搡造水多| 91人体视频| 伊人久久大香| 麻豆做爱| 亚洲精品另类| 亚洲久久视频| 老婆被黑人杂交呻吟视频| 国产午夜福利视频在线观看| 国产女人18毛片18精品| 无码内射在线播放| 男人天堂网AV| 久久精品在线视频| 欧美日韩毛片| 亚洲福利在线免费观看| 欧美一级a| 亚洲熟女av中文字幕| 超碰91免费在线观看| 色婷婷综合久久久中文字幕| 91肏屄视频| jizz18日本| 日韩黄色一级片| 成人黄色免费观看| 日韩日韩日韩日韩日韩| 国产成人综合自拍| 成人AV毛片| 少妇无码在线观看| 亚洲国产高清国产精品| 大香蕉尹人在线| 国产欧美精品一区二区色综合| 91久久久久久久18| 亚洲日韩国产AV| 国产性色| 亚洲精品久久久久久久久豆丁网| 国产亚洲无码激情| 三级黄色免费| 亚洲色图图片| 天天做夜夜操| 亚洲砖区区免费| 国产人妻精品一区二区三区不卡| AV在线免费播放| 日韩有码在线观看| 多啪啪免费视频| 大香蕉精品一区| 婷婷五月天色| 免费的黄色视频| 日韩成人视频在线| 亚洲xx网| 天天日综合网| 国产欧美精品成人在线观看| 在线观看的av| 操欧美美女| 婷婷五月天影视| 视频國产在线| 国家一级A片| 亚洲国产91| 777免费视频| 99热这里只有精| 波多野结衣久久精品| 狼友视频免费| 欧美综合亚洲图片综合区| 在线无码免费观看| 免费一级a| 亚洲日韩欧美成人| 国产精品一区av| 黄色A片网| h片在线免费观看| 日韩av电影在线观看| 欧美一级网站| 日韩欧美第一页| 久久伊思人在| 高潮毛片| 91精品国产综合久久久蜜臀图片 | 欧美成人无码A片免费| 岛国免费AV| 国产无遮挡又黄又爽又色| 午夜免费小视频| 日韩日逼网站| 日本www视频| 久久久中文字幕| 亚洲综合区| 免费看无码一级A片放24小时| 躁BBB躁BBB添BBBBBB| 亚洲无码观看视频| 毛片中文字幕| 午夜在线免费视频| 一本加勒比HEZYO东京热无码| 亚洲中文免费观看| 亚洲激情欧美激情| 99A片| 欧美精品无码久久久精品酒店| 亚洲欧洲久久电影| 日韩成人电影| 激情五月综合| 午夜精品久久久久久久99黑人| 欧美国产激情| 亚洲无码黄片| 久久骚| 超碰一级片| 再深点灬好爽灬轻点久久国产| 亚洲性爱在线播放| 91丨PORNY丨对白| 成人免费一区| 农村三级片| 日本免费黄| 天天撸在线| 少妇中文字幕| 广州媚黑妇系列视频在线| 国产乱子伦一区二区三| 91精品视频在线免费观看| 亚洲成人视频网| 伊人日逼| av无码av天天av天天爽| 台湾中文字幕网| 久久久永久免费视频| 香蕉视频啪啪啪| 欧美日韩在线观看中文字幕| 日韩欧美大片在线观看| 韩国无码一区二区| 日韩无码链接| 夜夜操夜夜| 国产理论片在线观看| 综合偷拍| 中文字幕aV在线| 欧美口爆视频| 伊人视频在线| 中文字幕日本无码| 亚洲精品suv视频| 欧美综合第一页| 亚洲理伦| 国产免费自拍视频| 国产精品久久精品| 黄页网站免费观看| 国产在线第一页| 99久久久| 青青在线| 尤物一区二区| 天天撸天天色| 69成人国产| 伊人大香在线| 人人干日日干| 91第一页| 北京熟妇槡BBBB槡BBBB| 俺去听听婷婷| 操逼的网站| 婷婷丁香六月| 日本成人午夜福利| 天堂在线观看AV| 亚洲国产成人视频| 九一亚洲精品| 成人AV十八亚洲二区| 黄片免费看视频| 91精品久久香蕉国产线看观看 | JlZZJLZZJlZZ亚洲女人17| 大香蕉尹人在线视频| 成人无码网站在线观看| 成人爽爽视频| 亚洲字幕无码| 欧美精品综合| 日韩综合网| 一道本视频在线| 精品无码免费视频| 婷婷五月色综合| 69AV无码| 欧美1区| 操逼的视频| 大香蕉伊人操| 风间由美大荫蒂无码AV| 色视频在线播放| 日韩欧美一| 欧美日韩免费看| 精品无码一| 国产精品色情A级毛片| 91亚洲精品视频在线| 国产嫩BBwBBw高潮| 99乱伦| 午夜亚洲国产一区视频网站| 中文字幕成人在线播放| www.日韩av| 91亚洲高清| 影音先锋aV成人无码电影| 2025中文在线观看最好看的电影| 自拍偷拍1| 婷婷狠狠爱| 不卡无码在线观看| 三级网站在线| 成人黄色在线观看视频| 欧美人成人无码| 中文字幕系列| 五月丁香激情四射| 欧美伊人在线| 亚洲高清av| 羞羞色院91蜜桃| 亚洲国产色婷婷| 2021天天操| 98国产精品| 尤物Av| 波多野结衣在线无码视频| 国产操b视频| 西西特级无码444www| 色吧五月| jt33免费观看高清| 91久久国产综合久| 亚洲视频在线免费观看| 欧美熟妇另类久久久久久不卡| 自拍偷拍网址| 波多野成人无码精品69| 国产精品超碰| 婷婷五月天激情电影| 中文在线高清字幕| h片在线观看| 天堂视频在线观看亚洲美女| 91农村站街老熟女露脸| 中文字幕AV在线播放| 北条麻妃二区三区| 欧美精品成人免费| 精品国产三级| 九九热精品视频99| WWW久久久| 泄火熟妇2-ThePorn| 一级A片黃色A片| 男人av在线| 久久婷婷视频| 一级A毛片| av黄片| avav无码| 午夜免费小视频| 国产永久免费| 午夜激情网站| 亚洲中文免费观看| 大香蕉伊| 激情另类| 欧美日韩国产激情| 国产18| 免费国产乱伦| 91视频色| 国产免费观看av| 日本精品人妻| 天天干天天做| 国产第五页| 麻豆mdapp03.tⅴ| 婷婷A片| 日韩中文字幕网站| av一区二区三区| 日无码视频| 特级特黄AAAAAAAA片| 夜夜夜夜撸| www四虎com| av人人| 一级性爽A√毛片| 中文字幕高清AⅤ| 东方av在线播放| 天堂精品| 国产污视频在线观看| av中文字幕在线播放| 乱人伦欲国语对白| 欧美一级特黄A片免费| 激情五月天小说网| 日韩有码一区| 美女天天操| 天天爱天天插| 一级女婬片A片AAAA片| 亚洲国产精品成人综合色在线婷婷| 国产精品久久久久久久久夜色| 欧美大鸡| 亚洲视频免费在线播放| 高清无码免费在线视频| 成人大片在线观看| 欧美在线一区二区| 男女一区二区三区| 乱伦视频网站| 亚洲精品久久久久久久蜜桃| 亚洲成人日韩| 精品网站| 欧美性猛交XXXX乱大交3| 台湾无码精品| 成人在线精品| 好好日视频| 中文字幕乱码人妻二区三区| 黄色免费AV| 日韩视频一区二区三区| 免费电影日本黄色| 欧美三区| 草逼视频免费看| 黄片网站在线观看| 肏网站| 中文字幕视频一区| 国产成人精品123区免费视频| 免费在线观看黄片| 国产精品久久久久久久久久久久久| 国产日皮| 怡春院在线| 97人妻精品一区二区三区软件| 麻豆乱伦| 天天操天天射天天日| 久久久无码精品亚洲日韩男男| 无码人妻精品一区二区三区99仓 | 丁香六月综合激情| 白丝自慰网站| 国产三级电影在线观看| 北条麻妃中文字幕旡码| 中文字幕精品无码亚| 操逼视频网址| 久久精品国产AV| 日韩激情| 精品www| 大香蕉88| 日韩黄色三级片| 日本黄色毛片| 亚洲欧美婷婷五月色综合| 三级片无码在线播放| 成人做爰黄A片免费看| 影音先锋无码AV| 一区二区三区四区免费| 欧美激情四射| 北条麻妃一区二区三区在线| av无码一区| 色欲av网站| 亚洲AV无码成人网站国产网站| 中文字幕免费在线视频| 成人亚洲综合| 肏逼在线观看| 青青草成人网| 无码中文字幕在线视频| 影音先锋色资源站| 91成人精品一区在线播放| 国产视频一区二区三区四区五区| 国产精品卡一| 麻豆精东一区二区欧美国产| 亚洲AV无码成人精品区| 嗯啊在线视频| 欧美一区二区三区婷婷五月| 日本欧美在线观看| 一区二区三区不卡在线| 日韩一及| 大鸡巴在线视频| 久久精品亚洲无码| 欧美成人网站免费在线观看| 国内精产品一二区秘| 无码人妻丰满熟妇区毛片视频| 波多无码在线| 亚洲区一区二| 国产黄色AV片| 成人性爱AV| 亚欧成人网站| 色播国产成人AV| 夜色福利网| 中文字幕+乱码+中文乱码91| 人人摸人人色| 久久蜜桃视频| 国产熟女AV| 国产牛牛在线| 少妇无码视频| 国产精品二区高清在线苍井空| 黄总AV| 亚洲日本中文字幕在线观看| 辽宁模特张雪馨视频最新| 国产精品AV在线| 欧美黄片免费在线观看| 国产伊人网| 97香蕉久久夜色精品国产| 日本久久久久久久久视频在线观看| 欧美另类激情| 色秘乱码一区二区三区唱戏| 日韩色情在线| 99热精品2| 99大香蕉视频| 亚洲性爱在线| 欧美手机在线视频| 丁香五月大香蕉| 日韩成人无码免费视频| 国产18水真多18精品| 婷婷色综合视频二区| 动漫3d啪啪成人h动漫| 暖暖无码| sm在线观看| 国产黄色自拍| 一本色道无码人妻精品| 超碰在线观看2407| 日本熟女视频| 亚洲成人A片| 91视频18| 日韩精品免费观看| 男人的天堂免费视频| 色视频免费观看| 操B视频在线播放| 九九色在线视频| 国外成人视频| 免费看操逼| 91偷拍网| 蜜桃av在线播放| 99久久99九九九99九他书对| 午夜福利小视频| 亚洲黄色电影在线| 国产免费久久久| 欧美AAA| 五月天婷婷在线观看视频| 欧美精品18videosex性欧美| 新亚洲天堂男子Av-| 国产成人高清| av在线无码| 久久丝袜| 国产又大又粗又长| 97香蕉久久国产超碰青草专区 | 91香蕉视频在线播放| 国产福利精品视频| 精品人妻二区中文字幕| 岛国免费AV| AV无码电影| av在线观看中文字幕| 国产精品高潮无套内谢| h视频| 精品无码人妻一区二区三区| 日本在线无码| 国产女人高潮毛片| 91一二区| 青青色综合| 国产免费内射| 国产精品久久毛片| 欧美日韩一区在线观看| 影音先锋男人网| 欧美操逼在线观看| A片在线观看网站| 亚洲五月丁香婷婷| 欧美69p| 另类视频在线| 韩国免费一级a一片在线播放| 成人黄A片免费| 美女天天日| 91亚洲精选| 天天操电影| 熟女嗷嗷叫高潮合集91| 精品国产黄色| 不卡视频在线观看| 草逼的视频| 天天干夜夜骑| 成人网站在线看|