想进阿里?先搞懂Spring Bean作用域!

大家好,我是小米!今天我来和大家分享一下 Java 开发中一项非常重要的技术------参数校验。参数校验在我们的代码中起着至关重要的作用,它能够确保我们的应用程序接收到正确的数据,并且保证了系统的安全性和稳定性。在过去,我们可能会通过繁琐的 if-else 来进行参数校验,但是现在,Spring 框架提供了一些非常便捷和优雅的方式来进行参数校验,让我们的代码更简洁、更优雅。

if-else 缺点

在很多早期的 Java 项目中,我们经常会看到大量的 if-else 语句来对方法的入参进行校验。这种方式虽然可以完成基本的校验功能,但是却存在一些缺点:

  • 代码冗余:大量的 if-else 语句使得代码变得冗长,难以阅读和维护。
  • 可读性差:过多的条件判断会降低代码的可读性,增加了出错的可能性。
  • 重复劳动:相同的参数校验代码可能会在不同的方法中重复出现,增加了代码的重复劳动。

Controller 方法参数注解校验

Spring 框架为我们提供了一种更加优雅的方式来进行参数校验,那就是利用 Controller 方法参数上的注解来完成。下面我们来看一下具体的操作步骤:

在介绍参数校验的效果示例时,我们可以通过一个简单的场景来展示其在实际应用中的优雅之处。假设我们有一个用户注册的功能,用户需要提供用户名和密码进行注册。在这个场景中,我们需要对用户提交的数据进行校验,确保其符合我们的要求。

首先,我们可以使用Spring框架提供的注解来完成参数校验。在Controller层的注册接口中,我们可以使用 @Valid 注解标注待校验的参数对象,比如UserDto。下面是一个简单的示例代码:

在这个示例中,我们通过 @Valid 注解告诉Spring框架需要对UserDto 对象进行参数校验。当接口收到请求时,Spring会自动对UserDto 中的属性进行校验,确保其符合我们定义的校验规则。如果校验失败,Spring会抛出MethodArgumentNotValidException异常,我们可以通过异常处理机制来捕获并返回友好的错误信息给用户。

通过这种方式,我们不再需要手动编写大量的if-else语句来进行参数校验,代码变得简洁清晰,更易于阅读和维护。同时,Spring框架提供了丰富的校验注解,比如 @NotNull@NotBlank等,可以满足我们各种复杂的校验需求。

除了简单的参数校验外,Spring还提供了更加灵活的分组校验、自定义校验注解等功能,可以满足我们更多样化的校验需求。在实际应用中,我们可以根据具体的业务场景和需求,灵活选择合适的校验方式,从而提升代码质量和开发效率。

@Valid 和 @Validated

在Spring框架中, @Valid@Validated是两个常用的参数校验注解,它们在实际应用中扮演着不同的角色,下面我们来详细了解一下它们之间的区别和使用场景。

首先,让我们来看看 @Valid 注解。在Spring MVC中, @Valid 注解通常用于标注在Controller方法的参数上,用于启用方法参数的校验功能。当我们在Controller方法的参数上标注了 @Valid 注解后,Spring框架会在方法执行之前对参数进行校验,如果校验失败,则会抛出MethodArgumentNotValidException异常。通过捕获这个异常,我们可以在全局异常处理器中统一处理参数校验失败的情况,返回友好的错误信息给用户。

@Validated 注解则更加灵活,它是Spring框架为了扩展JSR-303(Bean Validation 1.0)规范而提供的一个功能。除了支持JSR-303中定义的校验注解外, @Validated 还支持Spring自定义的校验注解,比如 @Email@NotBlank 等。此外, @Validated还支持分组校验和嵌套校验等功能,可以满足更加复杂的校验需求。

在实际应用中,我们应该根据具体的需求来选择合适的校验注解。如果我们只需要进行简单的参数校验,并且希望代码更加符合标准化,那么可以选择使用 @Valid 注解;而如果我们需要更加灵活的校验方式,并且希望支持Spring自定义的校验注解,那么就应该选择使用 @Validated注解。

分组校验

在参数校验的实际应用中,有时候我们可能需要对不同的校验规则进行分组处理。比如,在某个场景下我们需要对用户提交的注册信息进行基本校验,而在另一个场景下我们又需要对用户的详细信息进行更严格的校验。这时候,分组校验就能发挥作用了。

Spring框架提供了 @javax.validation.GroupSequence注解来实现分组校验。通过这个注解,我们可以将一组校验规则分成不同的组别,并在校验时指定特定的分组。这样一来,我们就能够灵活地根据不同的场景进行不同的校验操作,提高了代码的灵活性和可维护性。

具体来说,我们可以在校验规则的注解上指定分组信息,比如:

在上面的示例中,我们定义了两个分组:BasicInfoDetailedInfousername 属性属于BasicInfo 分组,email 属性属于DetailedInfo分组。这样一来,在进行参数校验时,我们就可以根据不同的分组指定不同的校验规则,比如:

通过分组校验,我们可以根据具体的业务场景和需求,灵活地选择需要进行校验的规则,避免了不必要的校验操作,提高了代码的执行效率。同时,分组校验也使得我们的校验规则更加清晰明了,便于后续的维护和扩展。

自定义校验注解

在实际开发中,我们可能会遇到一些特定的校验需求,而Spring框架提供的默认校验注解可能无法完全满足我们的需求。这时候,我们就可以通过自定义校验注解来实现特定的校验逻辑,从而提高代码的灵活性和可维护性。

自定义校验注解的实现步骤相对比较简单,主要包括两个方面:创建注解类和编写校验器类。

首先,我们需要创建一个自定义的注解类,使用 @Constraint注解标注,并指定校验器类。在注解类中,我们可以定义一些属性来配置校验规则,比如:

接着,我们需要编写一个校验器类,实现ConstraintValidator 接口,用于定义具体的校验逻辑。在校验器类中,我们需要重写initializeisValid 方法,在isValid方法中编写具体的校验逻辑,比如:

在上面的示例中,我们自定义了一个校验注解 @CustomValidation ,并实现了一个校验器类CustomValidator,用于校验字符串是否以"custom"开头。在实际应用中,我们可以将这个自定义注解应用到我们的实体类属性上,比如:

通过自定义校验注解,我们可以根据实际需求灵活定义校验规则,使得我们的代码更加符合业务需求,提高了代码的可维护性和复用性。同时,自定义校验注解也丰富了Spring框架中的校验功能,使得我们能够更加方便地完成复杂的校验操作。

校验原理

Spring框架中参数注解校验的原理主要基于 JSR-380(Bean Validation 2.0)规范和 Hibernate Validator 实现。Bean Validation规范定义了一系列的校验注解,如@NotNull、@NotBlank、@Email等,用于描述对象的校验规则。而Hibernate Validator是Bean Validation规范的一种具体实现,它提供了校验注解的解析和执行功能。

在Spring框架中,参数注解校验主要依赖于javax.validation.Validorg.springframework.validation.annotation.Validated 注解,以及LocalValidatorFactoryBeanMethodValidationPostProcessor两个核心类。

首先,当我们在Controller方法的参数上标注了 @Valid@Validated 注解时,Spring框架会将这些参数交给MethodValidationPostProcessor 处理。MethodValidationPostProcessor 是一个后置处理器,它会在方法调用之前对标注了 @Valid@Validated注解的方法参数进行校验。

接着,Spring框架会利用LocalValidatorFactoryBean 来创建一个校验器实例。LocalValidatorFactoryBean 是Spring框架对ValidatorFactory接口的一个具体实现,它会加载并初始化所有的校验规则,包括Bean Validation规范中定义的校验注解和自定义的校验注解。

当方法调用时,MethodValidationPostProcessor 会拦截方法调用,并利用LocalValidatorFactoryBean 来对方法参数进行校验。它会根据方法上标注的 @Valid@Validated注解,以及参数对象上标注的校验注解,来确定需要进行校验的参数和校验规则。

校验的过程主要包括以下几个步骤:

  • 参数解析: 根据方法的参数列表和方法签名,获取需要进行校验的参数对象。
  • 校验规则解析: 利用反射机制,解析参数对象上标注的校验注解,获取校验规则。
  • 执行校验: 根据校验规则,对参数对象的属性值进行校验。校验的结果会被封装成一个ConstraintViolation对象,包含了校验失败的参数名、错误消息等信息。
  • 错误处理: 如果校验失败,Spring框架会将校验失败的信息封装成一个MethodArgumentNotValidException异常,并抛出到方法调用栈,同时返回给调用方。

Service 方法参数校验

除了在 Controller 方法中进行参数校验外,我们还可以在 Service 方法中进行参数校验。下面我们来看一下具体的操作步骤:

如果入参是平铺的参数效果示例

当入参是平铺的参数时,指的是参数并非以对象的形式传递,而是作为方法的直接参数进行传递。在这种情况下,我们同样可以利用Spring框架提供的参数校验功能,确保参数的合法性。

举例来说,假设我们有一个用户更新信息的功能,用户需要提供用户名和邮箱地址来更新信息。此时,我们可以直接在Controller方法的参数上使用校验注解来对这些参数进行校验,而不需要将它们封装成一个对象。

下面是一个简单的示例代码:

在上面的示例中,我们使用了 @RequestParam 注解来获取请求参数,并且直接在参数上使用了校验注解,比如 @NotBlank 用于校验参数是否为空, @Email用于校验参数是否符合邮箱地址格式。当请求到达Controller方法时,Spring框架会自动对这些参数进行校验,如果校验失败,则会抛出异常并返回对应的错误信息。

通过这种方式,我们可以在不需要封装成对象的情况下,依然能够利用Spring框架提供的参数校验功能,确保参数的合法性,从而保证系统的稳定性和安全性。

如果入参是对象

当入参是对象时,我们可以将参数封装成一个对象,然后在Controller方法的参数上使用校验注解来对这个对象进行校验。这种方式更加符合面向对象的设计原则,能够使代码结构更加清晰,提高代码的可维护性。

举例来说,假设我们有一个用户注册的功能,用户需要提供用户名、密码和邮箱地址来完成注册。我们可以定义一个UserDto对象来封装这些参数,并在对象的属性上使用校验注解来进行校验。

下面是一个简单的示例代码:

然后,在Controller方法中,我们可以直接将UserDto 对象作为方法的参数,并在参数上使用 @Valid注解来启用参数校验功能。

当请求到达Controller方法时,Spring框架会自动对UserDto对象的属性进行校验,确保它们符合我们定义的校验规则。如果校验失败,则会抛出异常并返回对应的错误信息。

通过将参数封装成对象的方式,我们可以将相关的参数组织成一个逻辑整体,使得代码结构更加清晰,易于理解和维护。同时,利用Spring框架提供的参数校验功能,可以保证参数的合法性,从而提高系统的稳定性和安全性。

简洁的方式 - FastValidatorUtils

在实际开发中,除了使用Spring框架提供的注解来进行参数校验外,我们还可以借助第三方库来简化校验逻辑。其中,FastValidatorUtils 是一个非常不错的选择,它提供了一系列静态方法来完成常见的校验操作,让我们的代码更加简洁、高效。

FastValidatorUtils 提供了丰富的校验方法,涵盖了常见的校验场景,比如判断字符串是否为空、是否为邮箱地址、是否为手机号码等等。通过调用这些方法,我们可以快速地完成参数的校验,而不需要编写大量的校验逻辑。

下面是一个简单的示例代码:

在上面的示例中,我们通过调用 FastValidatorUtils 提供的校验方法,来判断用户提交的邮箱地址和手机号码是否符合规范。如果校验失败,则直接返回错误信息给用户,提高了代码的可读性和可维护性。

使用 FastValidatorUtils 能够让我们的代码更加简洁明了,减少了冗余的校验逻辑,提高了代码的执行效率。同时,FastValidatorUtils 还支持自定义校验规则和扩展功能,可以满足更多复杂的校验需求。

END

总的来说,Spring 提供的参数校验功能极大地简化了我们的开发工作,让我们能够更加专注于业务逻辑的实现,而不是琐碎的参数校验工作。通过合理地使用注解和第三方库,我们可以让我们的代码更加简洁、优雅,提升开发效率,保证系统的稳定性和安全性。

希望本文能够对大家有所帮助,也欢迎大家留言讨论,共同进步!

如有疑问或者更多的技术分享,欢迎关注我的微信公众号"知其然亦知其所以然"!

公众号对技术型文章的推送机制有所调整,需要大家多多点赞在看转发收藏,才能让更多技术同行们能看到优质的技术分享~

相关推荐
豌豆花下猫7 分钟前
Python 潮流周刊#78:async/await 是糟糕的设计(摘要)
后端·python·ai
YMWM_9 分钟前
第一章 Go语言简介
开发语言·后端·golang
码蜂窝编程官方25 分钟前
【含开题报告+文档+PPT+源码】基于SpringBoot+Vue的虎鲸旅游攻略网的设计与实现
java·vue.js·spring boot·后端·spring·旅游
hummhumm44 分钟前
第 25 章 - Golang 项目结构
java·开发语言·前端·后端·python·elasticsearch·golang
J老熊1 小时前
JavaFX:简介、使用场景、常见问题及对比其他框架分析
java·开发语言·后端·面试·系统架构·软件工程
猿java1 小时前
什么是 Hystrix?它的工作原理是什么?
java·微服务·面试
AuroraI'ncoding1 小时前
时间请求参数、响应
java·后端·spring
好奇的菜鸟1 小时前
Go语言中的引用类型:指针与传递机制
开发语言·后端·golang
Alive~o.01 小时前
Go语言进阶&依赖管理
开发语言·后端·golang
许苑向上1 小时前
Dubbo集成SpringBoot实现远程服务调用
spring boot·后端·dubbo