最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?controller校驗入?yún)⒌姆椒ㄔ斀?/h1>
 更新時間:2024年06月07日 08:27:02   作者:有信仰  
項目中使用Springboot,在Controller中配置了@NotNull和@Valid,@Notnull不生效,@Valid生效,返回http?status為400,本文給大家介紹了Spring?controller校驗入?yún)⒌姆椒?需要的朋友可以參考下

問題描述

項目中使用Springboot,在Controller中配置了@NotNull和@Valid,@Notnull不生效,@Valid生效,返回http status為400。

@RestController
@RequestMapping("/demo")
public class DemoController {
    @Override
    @PostMapping("/user")
    public CreateUserRsp createUser(
        @NotNull @Size(min = 1, max = 64) @RequestHeader(value = "token") String token,
        @NotNull @Valid @RequestBody CreateUserReq createUserReq) {
        // 業(yè)務邏輯
    }
}

原因分析

controller接收到請求,首先會進行參數(shù)解析,解析相關的類:

為什么@RequestBody中的@Valid生效了?

參數(shù)中@RequestBody注解是使用RequestResponseBodyMethodProcessor解析的,下面重點看下這個。

public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
	parameter = parameter.nestedIfOptional();
	Object arg = this.readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
	String name = Conventions.getVariableNameForParameter(parameter);
	if (binderFactory != null) {
		WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
		if (arg != null) {
                // 重點
			this.validateIfApplicable(binder, parameter);
			if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) {
				throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
			}
		}

		if (mavContainer != null) {
			mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
		}
	}

	return this.adaptArgumentIfNecessary(arg, parameter);
}
protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
	Annotation[] annotations = parameter.getParameterAnnotations();
	Annotation[] var4 = annotations;
	int var5 = annotations.length;

	for(int var6 = 0; var6 < var5; ++var6) {
		Annotation ann = var4[var6];
        // 重點,解析參數(shù)的注解
		Object[] validationHints = ValidationAnnotationUtils.determineValidationHints(ann);
		if (validationHints != null) {
            // 執(zhí)行校驗
			binder.validate(validationHints);
			break;
		}
	}

}

可以看出,@Valid和@Validated注解都可以解析到:

public static Object[] determineValidationHints(Annotation ann) {
	if (ann instanceof Validated) {
		return ((Validated)ann).value();
	} else {
		Class<? extends Annotation> annotationType = ann.annotationType();
		if ("javax.validation.Valid".equals(annotationType.getName())) {
			return EMPTY_OBJECT_ARRAY;
		} else {
			Validated validatedAnn = (Validated)AnnotationUtils.getAnnotation(ann, Validated.class);
			if (validatedAnn != null) {
				return validatedAnn.value();
			} else {
				return annotationType.getSimpleName().startsWith("Valid") ? convertValidationHints(AnnotationUtils.getValue(ann)) : null;
			}
		}
	}
}

為什么@RequestHeader中的@NotNull沒有生效?

按照上面的思路,我們看下RequestHeaderMapMethodArgumentResolver,里面并沒有調用validate相關的代碼。

怎么樣才能生效?

在類上加@Validated。并且加maven依賴

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

@Validated生效原理

后處理器MethodValidationPostProcessor中給使用了@Validated注解的類創(chuàng)建了個切面。實際執(zhí)行切面邏輯的是MethodValidationInterceptor

public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor implements InitializingBean {
    private Class<? extends Annotation> validatedAnnotationType = Validated.class;
	public void afterPropertiesSet() {
		Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
		this.advisor = new DefaultPointcutAdvisor(pointcut, this.createMethodValidationAdvice(this.validator));
	}

	protected Advice createMethodValidationAdvice(@Nullable Validator validator) {
		return validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor();
	}
}

請求執(zhí)行時,MethodValidationInterceptor中先判斷方法和類上有沒有@Validated,

public Object invoke(MethodInvocation invocation) throws Throwable {
	if (this.isFactoryBeanMetadataMethod(invocation.getMethod())) {
		return invocation.proceed();
	} else {
        // 方法和類上有沒有@Validated
		Class<?>[] groups = this.determineValidationGroups(invocation);
		ExecutableValidator execVal = this.validator.forExecutables();
		Method methodToValidate = invocation.getMethod();
		Object target = invocation.getThis();
		Assert.state(target != null, "Target must not be null");

		Set result;
		try {
            // 校驗
			result = execVal.validateParameters(target, methodToValidate, invocation.getArguments(), groups);
		} catch (IllegalArgumentException var8) {
			methodToValidate = BridgeMethodResolver.findBridgedMethod(ClassUtils.getMostSpecificMethod(invocation.getMethod(), target.getClass()));
			result = execVal.validateParameters(target, methodToValidate, invocation.getArguments(), groups);
		}

		if (!result.isEmpty()) {
            // 校驗失敗的異常
			throw new ConstraintViolationException(result);
		} else {
			Object returnValue = invocation.proceed();
			result = execVal.validateReturnValue(target, methodToValidate, returnValue, groups);
			if (!result.isEmpty()) {
				throw new ConstraintViolationException(result);
			} else {
				return returnValue;
			}
		}
	}
}

實際校驗的類是ValidatorImpl。代碼一直跟下去,能找到最終執(zhí)行校驗的地方。---注意,ValidatorImpl已經(jīng)是hibernate-validator提供的了。

private void validateMetaConstraints(BaseBeanValidationContext<?> validationContext, ValueContext<?, Object> valueContext, Object parent, Iterable<MetaConstraint<?>> constraints) {
	Iterator var5 = constraints.iterator();

	while(var5.hasNext()) {
		MetaConstraint<?> metaConstraint = (MetaConstraint)var5.next();
		this.validateMetaConstraint(validationContext, valueContext, parent, metaConstraint);
		if (this.shouldFailFast(validationContext)) {
			break;
		}
	}

}

總結

controller中requestBody中直接可以用@Valid或@Validated校驗,如果想校驗方法中單個參數(shù),需要在方法或類上加@Validated,這樣會開啟方法校驗的切面,切面中會拿到方法簽名中每個字段的注解然后進行校驗。

以上就是Spring controller校驗入?yún)⒌姆椒ㄔ斀獾脑敿殐热?,更多關于Spring controller校驗入?yún)⒌馁Y料請關注腳本之家其它相關文章!

相關文章

  • Java安全框架——Shiro的使用詳解(附springboot整合Shiro的demo)

    Java安全框架——Shiro的使用詳解(附springboot整合Shiro的demo)

    這篇文章主要介紹了Java安全框架——Shiro的使用詳解,幫助大家更好的理解和學習使用Shiro,感興趣的朋友可以了解下
    2021-04-04
  • 基于java ssm springboot+mybatis酒莊內部管理系統(tǒng)設計和實現(xiàn)

    基于java ssm springboot+mybatis酒莊內部管理系統(tǒng)設計和實現(xiàn)

    這篇文章主要為大家詳細介紹了java ssm springboot+mybatis實現(xiàn)酒店管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Java 中 Function 與 apply 的實際應用場景分析(含優(yōu)化前后案例)

    Java 中 Function 與 apply 的實際應用場景分析(含

    本文介紹了如何使用Java 8的Function函數(shù)式接口簡化重復邏輯,包括判空、格式化、字段提取等常見場景,通過實際案例,展示了如何將多個字段的處理邏輯集中到一個函數(shù)中,從而提高代碼的可讀性和可維護性,感興趣的朋友跟隨小編一起看看吧
    2025-12-12
  • 基于Java代碼配置MyBatis Generator

    基于Java代碼配置MyBatis Generator

    這篇文章主要介紹了基于Java代碼配置MyBatis Generator,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06
  • Java之SpringCloud Eurka注冊錯誤解決方案

    Java之SpringCloud Eurka注冊錯誤解決方案

    這篇文章主要介紹了Java之SpringCloud Eurka注冊錯誤解決方案,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下
    2021-07-07
  • 詳解mybatis多對一關聯(lián)查詢的方式

    詳解mybatis多對一關聯(lián)查詢的方式

    這篇文章主要給大家介紹了關于mybatis多對一關聯(lián)查詢的相關資料,文中將關聯(lián)方式以及配置方式介紹的很詳細,需要的朋友可以參考下
    2021-06-06
  • SpringBoot服務獲取Pod當前IP的兩種方案

    SpringBoot服務獲取Pod當前IP的兩種方案

    在 Kubernetes 集群中,Spring Boot 服務獲取 Pod 當前 IP 的方案主要有兩種,通過環(huán)境變量注入 或 通過 Java 代碼動態(tài)獲取網(wǎng)絡接口 IP,下面我們來看看具體實現(xiàn)方法吧
    2025-06-06
  • Java利用Socket實現(xiàn)網(wǎng)絡通信功能

    Java利用Socket實現(xiàn)網(wǎng)絡通信功能

    在早期的網(wǎng)絡編程中,Socket是很常見的實現(xiàn)技術之一,比如早期的聊天室,就是基于這種技術進行實現(xiàn)的,另外現(xiàn)在有些消息推送,也可以基于Socket實現(xiàn),本文小編給大家介紹了Java利用Socket實現(xiàn)網(wǎng)絡通信功能的示例,需要的朋友可以參考下
    2023-11-11
  • Java字符串詳解的實例介紹

    Java字符串詳解的實例介紹

    本篇文章介紹了,在Java中關于字符串詳解一些實例操作,需要的朋友參考下
    2013-04-04
  • Java深入分析動態(tài)代理

    Java深入分析動態(tài)代理

    動態(tài)代理指的是,代理類和目標類的關系在程序運行的時候確定的,客戶通過代理類來調用目標對象的方法,是在程序運行時根據(jù)需要動態(tài)的創(chuàng)建目標類的代理對象。本文將通過案例詳細講解一下Java動態(tài)代理的原理及實現(xiàn),需要的可以參考一下
    2022-07-07

最新評論

镇宁| 六盘水市| 万荣县| 蒲江县| 上杭县| 承德县| 万安县| 旬阳县| 舟山市| 仁怀市| 察隅县| 河曲县| 东辽县| 禹州市| 凭祥市| 房山区| 永寿县| 晋宁县| 永平县| 罗城| 阿城市| 同江市| 大化| 建水县| 丘北县| 龙口市| 成武县| 娄底市| 敖汉旗| 阜平县| 林周县| 临清市| 交城县| 永川市| 岱山县| 布拖县| 罗田县| 霍城县| 绥滨县| 南岸区| 乌拉特前旗|