作为服务端开发,验证前端传入的参数的合法性是一个必不可少的步骤,但是验证参数是一个基本上是一个体力活,而且冗余代码繁多,也影响代码的可阅读性,所以有没有一个比较优雅的方式来解决这个问题?

这么简单的问题当然早就有大神遇到并且解决了,这一篇文章主要讲一下解决基于spring-boot的验证参数的比较好的方法:利用validator-api来进行验证参数。

spring-boot-starter-web包里面有hibernate-validator包,它提供了一系列验证各种参数的方法,所以说spring-boot已经帮我们想好要怎么解决这个问题了。

这篇文章针对spring-boot里面的spring-mvc介绍三种方式来验证参数。

(一):这个方法在网上大部分都可以查到,先假设我们的restful的接口接受一个GradeAndClassroomModel类型的对象,并且这个类被定义成

@Data
public class GradeAndClassroomModel {
@Range(min = 1, max = 9, message = "年级只能从1-9")
private int grade;
@Range(min = 1, max = 99, message = "班级只能从1-99")
private int classroomNumber;
}

利用validator提供的一系列注解,比如本例中的@Range,就可以表示参数的范围和出错时候的提示信息。还有很多其他注解,这里就不一一列出

然后我们的Controller层的代码为

@RequestMapping(value = "/paramErrorTest", method = RequestMethod.GET)
public String paramErrorTest(
@Valid
@ModelAttribute
GradeAndClassroomModel gradeAndClassroomModel,
BindingResult result) {
return classroomService.getTeacherName(gradeAndClassroomModel.getGrade(), gradeAndClassroomModel.getClassroomNumber());
}

其中如果验证出错,result对象里面就会有错误信息,然后可以自己进行处理。

(二): 针对上面的例子,会有人说,就两个参数,为什么要作为对象呢?会不会太麻烦?确实,如果只有少数对象,直接把参数写到Controller层,然后在Controller层进行验证就可以了。

@RequestMapping(value = "/teacherName", method = RequestMethod.GET)
public String teacherName(
@Range(min = 1, max = 9, message = "年级只能从1-9")
@RequestParam(name = "grade", required = true)
int grade,
@Min(value = 1, message = "班级最小只能1")
@Max(value = 99, message = "班级最大只能99")
@RequestParam(name = "classroom", required = true)
int classroom) {
return classroomService.getTeacherName(grade, classroom);
}

如果直接把validator提供的注解移除来写到请求参数上面的话是不是就可以了呢?答案是错,为什么这样不能成功的验证参数呢?具体原因大家可以参考官方文档:http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/htmlsingle/#validation-beanvalidation-spring-method

上面的文档已经说的很清楚了,所以我们需要创建一个Bean

@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}

然后在类方法上面加上注解@Validated

@RestController
@RequestMapping("/spring-boot/classroom")
@Validated
public class ClassroomController {
...
}

然后之前没有生效的注解@Range@Min@Maxvalidator包里面提供的注解就可以生效了。

(三)估计到了这里又会有人问,如果validator包里面注解不能满足我们的需求,我们是否可以自己定义参数验证的逻辑。答案是肯定的,我们可以利用

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Constraint(validatedBy = {Validator.class})
public @interface ParamValidator { String message() default "Parameter error!"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }

public class Validator implements ConstraintValidator<ParamValidator, Object> {
...
}

组合进行自定义,具体的例子网上其他文章就很多了,这里就不进行详细的例子了,但是最终使用的时候就是

  @RequestMapping(value = "/paramValidator", method = RequestMethod.GET)
public String paramValidator(
@ParamValidator(isRequired = true, desc = "年级", range = "int:1~9", message = "年级只能从1-9")
@RequestParam(name = "grade", required = true)
int grade,
@ParamValidator(isRequired = true, desc = "班级", range = "int:1~99", message = "班级只能从1-99")
@RequestParam(name = "classroom", required = true)
int classroom) {
return classroomService.getTeacherName(grade, classroom);
}

另外不要忘记方法二里面里面提到的MethodValidationPostProcessor这个bean,如果没有初始化这个bean,自定义的验证方法也不会执行。验证逻辑会失效。

是不是通过这样写注解的方式来验证进行请求的参数,代码逻辑更佳清晰和优雅?表达的含义也会更佳清楚?并且没有了大量重复的类似的验证代码。

Ps:这里的代码都是基于spring-mvc框架来试验的,如果有人并没有使用spring-mvc作为rest框架,而是使用jersey来作为rest框架的话,可能一些细节方面需要调整, 但是这三种方案应该都是可以兼容的。

最后如果觉得所讲的东西能够帮助到你,并且希望了解更多的知识,进行更详细的深入的学习,欢迎加群632109190进行讨论和学习。

使用validator-api来验证spring-boot的参数的更多相关文章

  1. spring boot:使用validator做接口的参数、表单、类中多字段的参数验证(spring boot 2.3.1)

    一,为什么要做参数验证? 永远不要相信我们在后端接收到的数据, 1,防止别人通过接口乱刷服务:有些不怀好意的人或机构会乱刷我们的服务,例如:短信接口, 相信大家可能很多人在工作中遇到过这种情况 2,防 ...

  2. Kotlin + Spring Boot 请求参数验证

    编写 Web 应用程序的时候,经常要做的事就是要对前端传回的数据进行简单的验证,比如是否非空.字符长度是否满足要求,邮箱格式是否正确等等.在 Spring Boot 中,可以使用 Bean Valid ...

  3. spring boot:spring security整合jwt实现登录和权限验证(spring boot 2.3.3)

    一,为什么使用jwt? 1,什么是jwt? Json Web Token, 它是JSON风格的轻量级的授权和身份认证规范, 可以实现无状态.分布式的Web应用授权 2,jwt的官网: https:// ...

  4. spring boot 输入参数统一校验

    1 引入spring boot validate    maven 依赖 <!-- 验证 --> <dependency> <groupId>org.hiberna ...

  5. spring boot validation参数校验

    对于任何一个应用而言在客户端做的数据有效性验证都不是安全有效的,这时候就要求我们在开发的时候在服务端也对数据的有效性进行验证. Spring Boot自身对数据在服务端的校验有一个比较好的支持,它能将 ...

  6. Spring boot 配置文件参数映射到配置类属性

    [参考文章]:SpringBoot之@EnableConfigurationProperties分析 [参考文章]:在Spring Boot中使用 @ConfigurationProperties 注 ...

  7. Spring Boot 构造器参数绑定,越来越强大了!

    在之前的文章:Spring Boot读取配置的几种方式,我介绍到 Spring Boot 中基于 Java Bean 的参数绑定,在一个 Java Bean 类上用 @ConfigurationPro ...

  8. spring boot datasource 参数设置

    datasource spring.dao.exceptiontranslation.enabled是否开启PersistenceExceptionTranslationPostProcessor,默 ...

  9. spring boot 当参数传入开头多个0时,报错:JSON parse error: Invalid numeric value: Leading zeroes not allowed

    原因是: Jackson解析json配置的问题 在配置文件中设置下: spring.jackson.parser.allow-numeric-leading-zeros=true

  10. spring boot 的参数配置。

    https://blog.csdn.net/baidu_24237655/article/details/72772402

随机推荐

  1. storm1.0节点间消息传递过久分析及调优

    序:最近对storm平台系统进行性能检测发现偶尔会出现oncebolt向另一个twobolt发送数据后,twobolt要500毫秒后才接收到进行处理.这里简单说增大twobolt的并行度即可解决,但是 ...

  2. 对bootstrap不同版本的总结

    之前以为bootstrap2和bootstrap3没啥区别,无非就是功能增加了,简直是误区啊 bootstrap3与bootstrap2版本语法都不同啦 栅格写法 col-md-3/span3 文本效 ...

  3. java线程的等待、通知机制【读书笔记】

    代码示例: package com.baidu.nuomi.concurrent; import java.text.SimpleDateFormat; import java.util.Date; ...

  4. MyBatis解决字段名与实体类属性名不相同的冲突(四)

    一.创建表和表数据 CREATE TABLE orders( order_id INT PRIMARY KEY AUTO_INCREMENT, order_no ), order_price FLOA ...

  5. lsusb命令

    运行 yum install libusb usbutils

  6. PHPSTORM下安装XDEBUG

    本文不是教程安装XDEBUG,具体的请自行百度(我也是按照百度上的一步步来的). 以下纠正几点目前我安装时查看播客的不对之处: 1. Setting > PHP > DEBUG > ...

  7. PRINCE2的国际形势?光环国际项目管理培训

    PRINCE2的使用和应用非常广泛.在过去的12个月里,超过60,000人参加了PRINCE2基础资格(Foundation)或从业资格(Practitioner)考试.现在每周参加考试的人数超过了2 ...

  8. [Python]获取子线程异常信息

    起因 今天在写东西的时候,用到了多线程.遇到了个问题: 子线程的异常,在父线程中无法捕获. 解决 问题代码 问题代码示例代码如下: import threading class SampleThrea ...

  9. js-面试题之字符串

    问题:输入两个字符串,从第一个字符串中删除第二个字符串中的所有字符串不可以使用replace<!--例如:输入"They are students" 和"aeiou ...

  10. redis实现队列消息的ack

    由于公司提供的队列实在太过于蛋疼而且还限制不能使用其他队列,但为了保证数据安全性需要一个可以有ack功能的队列. 原生的redis中通过L/R PUSH/POP方式来实现队列的功能,这个当然是没办法满 ...