想进阿里?先搞懂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 提供的参数校验功能极大地简化了我们的开发工作,让我们能够更加专注于业务逻辑的实现,而不是琐碎的参数校验工作。通过合理地使用注解和第三方库,我们可以让我们的代码更加简洁、优雅,提升开发效率,保证系统的稳定性和安全性。

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

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

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

相关推荐
桦说编程16 分钟前
Java 中如何创建不可变类型
java·后端·函数式编程
IT毕设实战小研19 分钟前
基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
java·开发语言·spring boot·后端·spring·毕业设计·课程设计
wyiyiyi42 分钟前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
甄超锋1 小时前
Java ArrayList的介绍及用法
java·windows·spring boot·python·spring·spring cloud·tomcat
阿华的代码王国2 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
Jimmy2 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
AntBlack2 小时前
不当韭菜V1.1 :增强能力 ,辅助构建自己的交易规则
后端·python·pyqt
bobz9653 小时前
pip install 已经不再安全
后端
寻月隐君3 小时前
硬核实战:从零到一,用 Rust 和 Axum 构建高性能聊天服务后端
后端·rust·github
Java小白程序员5 小时前
Spring Framework:Java 开发的基石与 Spring 生态的起点
java·数据库·spring