参数校验-SpringBoot-优雅的-你把握了吗 (参数校验失败是什么原因)
前言
在后端的接口开发环节,实践上每一个接口都或多或少有不同规定的参数校验,有一些是基础校验,如非空校验、长度校验、大小校验、格局校验;也有一些校验是业务校验,如学号不能重重复、手机号不能重复注册等;关于业务校验,是须要和数据库交互才干知道校验结果;关于参数的基础校验,是有一些共有特色可以形象进去,可以做成一个通用模板(就是一种面向对象的编程言语,还记得天天快要说烂问烂的面向对象的三大特性吗?)。基于实践场景的须要,javaAPI中定义了一些Bean校验的规范规范(JSR303:validation-api),然而没有详细成功,不过hibernatevalidation和springvalidation都提供了一些比拟低劣的成功。假设在名目里,你还是像相似这样的方式来启动参数校验就太low了,活该加班到天黑(当然假设你所在公司目前依然用统计代码量来考核你的上班,就算我没说,你可以继续经常使用这种方式)。
@PostMing("/add")publicStringadd(Studentstudent){if(null==student){thrownewRuntimeException("在校生不为空");}if("".equals(student.getStuCode())){thrownewRuntimeException("学号不能为空");}if("".equals(student.getStuName())){thrownewRuntimeException("在校生姓名不能为空");}if(null==student.getTeacher()){thrownewRuntimeException("在校生的教员的不能为空");}if("".equals(student.getTeacher().getTecName())){thrownewRuntimeException("在校生的教员的姓名不能为空");}if("".equals(student.getTeacher().getSubject())){thrownewRuntimeException("在校生的教员的所授科目不为能空");}return"success";}
依赖引入
分享的这篇文章里的校验参数注解经常使用方法,我是在一个springboot名目里亲身从新测实验证过的,springboot的版本是2.3.9.RELEASE,另外也引入了关于参数校验的starter包,这样就不用额外去引关于参数校验的其余包了;
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId><version>2.3.9.RELEASE</version></dependency>
参数方式
在java名目中,前端恳求后端的接口中,罕用的恳求类型关键是post和get。
罕用到的解放注解
被注释的元素是一个对象,须要审核此对象的一切字段值 |
|
被注释的元素必需为null |
|
被注释的元素必需不为null |
|
@AssertTrue |
被注释的元素必需为true |
@AssertFalse |
被注释的元素必需为false |
@Min(value) |
被注释的元素必需是一个数字,其值必需大于等于指定的最小值 |
@Max(value) |
被注释的元素必需是一个数字,其值必需小于等于指定的最大值 |
@DecimalMin(value) |
被注释的元素必需是一个数字,其值必需大于等于指定的最小值 |
@DecimalMax(value) |
被注释的元素必需是一个数字,其值必需小于等于指定的最大值 |
@Size(max,min) |
被注释的元素的大小必需在指定的范围内 |
@Digits(integer,fraction) |
被注释的元素必需是一个数字,其值必需在可接受的范围内 |
@Pattern(value) |
被注释的元素必需合乎指定的正则表白式 |
HibernateValidator附加的constrnt
注解 |
作用 |
被注释的元素必需是电子邮箱地址 |
|
@Length(min=,max=) |
被注释的字符串的大小必需在指定的范围内 |
被注释的字符串的必需非空 |
|
@Range(min=,max=) |
被注释的元素必需在适合的范围内 |
被注释的字符串的必需非空 |
|
@URL(protocol=, host=,port=, regexp=,flags=) |
被注释的字符串必需是一个有效的url |
@CreditCardNumber |
被注释的字符串必需经过Luhn校验算法, 银行卡,信誉卡等号码普通都用Luhn 计算非法性 |
@ScriptAssert (lang=,script=,alias=) |
要有JavaScriptingAPI即JSR223 ("ScriptingfortheJavaTMPlatform")的成功 |
(whitelistType=, additionalTags=) |
classpath中要有jsoup包 |
参数基础校验
参数的基础校验,通常是指的非空、长度、最大值、最小值、格局(数字、邮箱、正则)等这些场景的校验。
@RequestBody参数
1.在controller层的方法的形参数前面加一个@Valid或@Validated的注解;
2.在用@RequestBody润色的类的属性上加上解放注解,如@NotNull、@Length、@NotBlank;
3.@RequestBody参数在触发校验规定时,会抛出MethodArgumentNotValidException,这里经常使用一致的意外处置机制来处置意外;
总结:第1步的valid的作用就是一个标志,表明这个参数须要启动校验;第2步的解放注解的上注明校验的规定;第3步的一致校验机制是前后盾恳求后盾接口时,假设校验参数的校验规定后会抛出意外,意外附带有解放注解上的揭示消息,那么经过意外一致处置机制就可以一致处置意外消息,并以适合的方式前往给前台(所谓适合的方式是指意外消息的格局可以自行制订)。
@PostMapping("/add")publicStudentadd(@Valid@RequestBodyStudentstudent){System.out.println(student.getStuName());returnstudent;}@DatapublicclassStudent{@NotNull(message="学号不能为空")@Length(min=2,max=4,message="学号的长度范围是(2,4)")privateStringstuCode;@NotNull(message="姓名不能为空")@Length(min=2,max=3,message="姓名的长度范围是(2,3)")privateStringstuName;}
@RequestParam参数/@PathVariable参数
1.在controller层的控制类上参与@Validated注解;
2.在controller层方法的校验参数上参与解放注解,如@NotNull、@Pattern;
3.@RequestParam参数/@PathVariable参数在触发校验规定时,会抛出ConstraintViolationException类型的意外,所以在一致意外处置机制中参与对这种类型意外的处置机制;
@RestController@RequestMapping("/student")@ValidatedpublicclassStudentController{@GetMapping("/{sex}/info")publicStringgetBySex(@PathVariable("sex")@Pattern(regexp="boy||girl",message="在校生性别只能是boy或girl")Stringsex){System.out.println("在校生性别:"+sex);return"success";}@GetMapping("/getOne")publicStringgetOne(@NotNull(message="在校生姓名不能为空")StringstuName,@NotNull(message="在校生学号不能为空")StringstuCode){System.out.println("stuName:"+stuName+",stuCode:"+stuCode);return"success";}}
意外一致处置
@RestControllerAdvicepublicclassCommonExceptionHandler{/***用于捕捉@RequestBody类型参数触发校验规定抛出的意外**@parame*@return*/@ExceptionHandler(value=MethodArgumentNotValidException.class)publicStringhandleValidException(MethodArgumentNotValidExceptione){StringBuildersb=newStringBuilder();List<ObjectError>allErrors=e.getBindingResult().getAllErrors();if(!CollectionUtils.isEmpty(allErrors)){for(ObjectErrorerror:allErrors){sb.append(error.getDefaultMessage()).append(";");}}returnsb.toString();}/***用于捕捉@RequestParam/@PathVariable参数触发校验规定抛出的意外**@parame*@return*/@ExceptionHandler(value=ConstraintViolationException.class)publicStringhandleConstraintViolationException(ConstraintViolationExceptione){StringBuildersb=newStringBuilder();Set<ConstraintViolation<?>>conSet=e.getConstraintViolations();for(ConstraintViolation<?>con:conSet){Stringmessage=con.getMessage();sb.append(message).append(";");}returnsb.toString();}}
嵌套校验
在实践名目中有这样一种场景,用来接纳参数的类的属性字段也是一个对象,属性对象的字段也须要启动必要的参数校验,这个时刻可以经常使用嵌套校验来处置这个疑问,hibernate-validator提供了详细的处置方式。
2.在接纳参数的类的属性是对象的字段上参与@Valide注解,这里须要留意的是肯定是@Valid,不是@Validated,由于@Valid的成功是由hibernate-validator提供,有嵌套校验的才干,而@Validated是由spring-validation提供的详细成功方式,@Validated有分组校验的才干,然而没有嵌套校验的才干;(javaAPI规范(JSR303)定义了Bean的校验规范validation-api,然而没有详细的成功,所以各有各的成功,在性能上也是有区别的)
3.嵌套属性类上的解放注解的用法,与用来接纳参数的对象属性上的解放注解的用法是一样的;
总结:@Valid的成功是由hibernate-validator提供,有嵌套校验的才干,然而没有分组校验的才干,@Validated是由spring-validation提供的详细成功方式,@Validated有分组校验的才干,然而没有嵌套校验的才干,在经常使用的环节须特意留意,要依据实践须要启动剪裁。
@PostMapping("/addStuaAndTeach")publicStringaddStuaAndTeach(@Validated(AddStuAndTeach.class)@RequestBodyStudentstudent){System.out.println("在校生的工号:"+student.getStuCode()+",在校生的教员的姓名:"+student.getTeacher().getTecName());return"success";}
@DatapublicclassTeacher{@NotNull(message="在校生的教员姓名不能为空",groups=AddStuAndTeach.class)privateStringtecName;@NotNull(message="在校生的教员传授科目不能为空",groups=AddStuAndTeach.class)privateStringsubject;}publicinterfaceAddStuAndTeach{}
@DatapublicclassStudent{@NotNull(message="在校生id不能为空",groups=QueryDetail.class)privateIntegerid;@NotNull(message="学号不能为空",groups=AddStudent.class)@Length(min=2,max=4,message="学号的长度范围是(2,4)")privateStringstuCode;@NotNull(message="姓名不能为空",groups=AddStudent.class)@Length(min=2,max=3,message="姓名的长度范围是(2,3)",groups=AddStudent.class)privateStringstuName;@Valid@NotNull(message="在校生的教员不能为空",groups=AddStuAndTeach.class)privateTeacherteacher;}
分组校验
在实践的名目中,或者多个方法经常使用同一个类来接纳参数,然而不同的方法的校验规定又是不同的,这个时刻就可以经常使用分组校验的方式来处置这个疑问了,spring-validation提供了详细的成功方式。
1.申明分组用的接口,比如参与和查问概略的时刻,校验的规定必需是不一样的,参与的时刻普通不用传id,由后盾自增长生成,查问概略的时刻id是必需传的;
//用于参与场景参数校验分组publicinterfaceAddStudent{}
//用于查问概略场景参数校验分组publicinterfaceQueryDetail{}
@PostMapping("/add")publicStudentadd(@Validated(AddStudent.class)@RequestBodyStudentstudent){System.out.println(student.getStuName());returnstudent;}@PostMapping("/detail")publicStringdetail(@Validated(QueryDetail.class)@RequestBodyStudentstudent){System.out.println("在校生id:"+student.getId());return"success";}
@DatapublicclassStudent{@NotNull(message="在校生id不能为空",groups=QueryDetail.class)privateIntegerid;@NotNull(message="学号不能为空",groups=AddStudent.class)@Length(min=2,max=4,message="学号的长度范围是(2,4)")privateStringstuCode;@NotNull(message="姓名不能为空",groups=AddStudent.class)@Length(min=2,max=3,message="姓名的长度范围是(2,3)",groups=AddStudent.class)privateStringstuName;}
优雅的方式来校验spring-boot的form表单参数和json的body参数合法性验证方式
作为一个好的服务端的开发人员,对于外部传入的参数一定要做参数验证,我们使用springboot可以方便的利用内置的 包来进行参数的验证 对于RequestParam类型参数的验证,需要在controller类上面加入 @Validated 注解 下面的例子就是简单的post方法中的form表单参数验证 下面的例子就是简单的post方法中的form表单中有复杂参数验证 对于RequestBody类型参数的验证,需要在 @RequestBody 参数前面加上 @Valid 注解 下面的例子就是简单的post方法中的单个requestbody中有参数验证 下面的例子就是简单的post方法中的requestbody中有对象参数验证
SpringBoot项目启动时校验@ConfigurationProperties注解(对于内部类的支持)
文章参考: JAVA基础篇(4)-Validation验证框架 注意点: 结果: 结论:可以支持内部类参数校验; 结果:项目正常启动; 因为 #autoCorrectCallBack 属性上不存在校验注解,故内部类的属性不生效;
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。