人世繁华|请不要在Java开发中再使用判断进行参数校验了


2.数据校验的痛点为了保证数据语义的正确 , 我们需要进行大量的判断来处理验证逻辑 。 而且项目的分层也会造成一些重复的校验 , 产生大量与业务无关的代码 。 不利于代码的维护 , 增加了开发人员的工作量 。
3.JSR303校验规范及其实现为了解决上面的痛点 , 将验证逻辑与相应的领域模型进行绑定是十分有必要的 。 为此产生了JSR303–BeanValidation规范 。 HibernateValidator是JSR-303的参考实现 , 它提供了JSR303规范中所有的约束(constraint)的实现 , 同时也增加了一些扩展 。
HibernateValidator提供的常用的约束注解
4.验证注解的使用在SpringBoot开发中使用HibernateValidator是非常容易的 , 引入下面的starter就可以了:
org.springframework.bootspring-boot-starter-validation一种可以实现接口来定制Validator , 一种是使用约束注解 。 胖哥觉得注解可以满足绝大部分的需求 , 所以建议使用注解来进行数据校验 。 而且注解更加灵活 , 控制的粒度也更加细 。 接下来我们来学习如何使用注解进行数据校验 。
4.1约束注解的基本使用我们对需要校验的方法入参进行注解约束标记 , 例子如下:
@DatapublicclassStudent{@NotBlank(message="姓名必须填")privateStringname;@NotNull(message="年龄必须填写")@Range(min=1,max=50,message="年龄取值范围1-50")privateIntegerage;@NotEmpty(message="成绩必填")privateListscores;}POST请求然后定义一个POST请求的SpringMVC接口:
?@RestController@RequestMapping("/student")publicclassStudentController{?@PostMapping("/add")publicRest>addStudent(@Valid@RequestBodyStudentstudent){returnRestBody.okData(student);}}通过对addStudent方法入参添加@Valid来启用参数校验 。 当使用下面数据进行请求将会抛出MethodArgumentNotValidException异常 , 提示age范围超出1-50 。
POST/student/addHTTP/1.1Host:localhost:8888Content-Type:application/json?{"name":"felord.cn","age":77,"scores":[55]}GET请求如法炮制 , 我们定义一个GET请求的接口:
@GetMapping("/get")publicRest>getStudent(@ValidStudentstudent){returnRestBody.okData(student);}使用下面的请求可以正确对学生分数scores进行了校验 , 但是抛出的并不是MethodArgumentNotValidException异常 , 而是BindException异常 。 这和使用@RequestBody注解有关系 , 这对我们后面的统一处理非常十分重要 。
GET/student/get?name=felord.cn&age=12HTTP/1.1Host:localhost:8888自定义注解可能有些同学注意到上面的年龄我进行了这样的标记:
@NotNull(message="年龄必须填写")@Range(min=1,max=50,message="年龄取值范围1-50")privateIntegerage;这是因为@Range不会去校验为空的情况 , 它只处理非空的时候是否符合范围约束 。 所以要用多个注解来约束 。 如果我们某些场景需要重复的捆绑多个注解来使用时 , 可以使用自定义注解将它们封装起来组合使用 , 下面这个注解就是将@NotNull和@Range进行了组合 , 你可以仿一个出来用用看 。
importorg.hibernate.validator.constraints.Range;?importjavax.validation.Constraint;importjavax.validation.Payload;importjavax.validation.ReportAsSingleViolation;importjavax.validation.constraints.NotNull;importjavax.validation.constraintvalidation.SupportedValidationTarget;importjavax.validation.constraintvalidation.ValidationTarget;importjava.lang.annotation.*;?/***@authora*@since17:31**/@Constraint(validatedBy={})@SupportedValidationTarget({ValidationTarget.ANNOTATED_ELEMENT})@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD,ElementType.FIELD,ElementType.ANNOTATION_TYPE,ElementType.CONSTRUCTOR,ElementType.PARAMETER,ElementType.TYPE_USE})@NotNull@Range(min=1,max=50)@Documented@ReportAsSingleViolationpublic@interfaceAge{//message必须有Stringmessage()default"年龄必须填写 , 且范围为1-50";?//可选Class>[]groups()default{};?//可选ClassextendsPayload>[]payload()default{};}还有一种情况 , 我们在后台定义了枚举值来进行状态的流转 , 也是需要校验的 , 比如我们定义了颜色枚举: