姓名校验正则表达式_springboot参数校验这么做简洁实⽤
⽂章为本⼈原创,创作不易,如果对您有帮助,点赞收藏加关注。
spring boot 优雅的参数校验
最近在公司其它业务组的项⽬中发现地⽅很多⽤if else校验请求参数,⼏乎每个接收参数的地⽅都有⼀⼤堆参数校验。
这篇⽂章介绍在spring boot项⽬中,如何使⽤ validation优雅的校验请求参数
假设我们已经做好了所有的前期⼯作,这时候有个新接⼝需要校验参数
先在接⼝参数前⾯增加@Valid注解表⽰需要校验,controller如下:
@PostMapping
public HttpResponse demo(@Valid @RequestBody DemoDTO dto) {
Name();
}
再增加validation注解:
@NotNull(message = "请输⼊姓名")
private String name;
好,我们调⽤输出如下:
{
"code": 500,
"msg": "请输⼊姓名"
}
是不是很简单,只需要增加两个注解,⼀个注解表⽰需要校验,⼀个注解表⽰怎么校验,所有的⼀切就搞定了。
不过在这之前,还需要做点其他⼯作。
1. 定义统⼀返回响应类
2. 拦截异常
我们先定义⼀个封装响应的类HttpResponse:
@Setter
@Getter
@Builder
public class HttpResponse {
private Integer code;
private String msg;
}
再全局拦截异常,返回这个对象,完整的异常处理以后会讲,这⾥只给⼤家看怎么配置:
@ControllerAdvice
public class BaseExceptionHandler {
@ResponseBody
@ExceptionHandler(MethodArgumentNotValidException.class)
public HttpResponse handle(MethodArgumentNotValidException e) {
FieldError fieldError = e.getBindingResult().getFieldError();
return HttpResponse.builder().code(500).DefaultMessage()).build();
}
}
这⾥的MethodArgumentNotValidException是在校验时抛出的,实际情上因为校验失败还会抛出其它异常,不过⼀般都是由于开发过程中导致的问题,与⽤户的输⼊⽆关,所以可以统⼀响应"系统异常",⽆需单独处理。
异常的处理还有其它⽅式,但统⼀拦截是最轻松的⼀种,开发过程中,⽆需考虑校验失败怎么处理,只需要写⼏个注解定规则。
Bean Validation 介绍
Bean Validation 中的约束
@Null
说明:被注释的元素必须为 null
适⽤范围:Object
@NotNull
说明:被注释的元素必须不为 null
适⽤范围:Object
@AssertTrue
说明:被注释的元素必须为 true
适⽤范围:boolean、Boolean
@AssertFalse
说明:被注释的元素必须为 false
适⽤范围:boolean、Boolean
@Min(value)
说明:被注释的元素必须是⼀个数字,其值必须⼤于等于指定的最⼩值
适⽤范围:BigDecimal、BigInteger、byte、Byte、short、Short、int、Integer、long、Long
@Max(value)
说明:被注释的元素必须是⼀个数字,其值必须⼩于等于指定的最⼤值
适⽤范围:BigDecimal、BigInteger、byte、Byte、short、Short、int、Integer、long、Long
@DecimalMin(value)
说明:被注释的元素必须是⼀个数字,其值必须⼤于等于指定的最⼩值
适⽤范围:BigDecimal、BigInteger、CharSequence、byte、Byte、short、Short、int、Integer、long、Long
@DecimalMax(value)
说明:被注释的元素必须是⼀个数字,其值必须⼩于等于指定的最⼤值
适⽤范围:BigDecimal、BigInteger、CharSequence、byte、Byte、short、Short、int、Integer、long、Long
@Size(max, min)
说明:被注释的元素的⼤⼩必须在指定的范围内
适⽤范围:CharSequence、Collection、Map、Array
@Digits (integer, fraction)
说明:被注释的元素必须是⼀个数字,其值必须在可接受的范围内
适⽤范围:BigDecimal、BigInteger、CharSequence、byte Byte、short Short、int Integer、long Long
@Past
说明:被注释的元素必须是⼀个过去的⽇期
适⽤范
围:Date、Calendar、Instant、LocalDate、LocalDateTime、LocalTime、MonthDay、OffsetDateTime、OffsetTime、Year、YearMonth、ZonedDateTime、HijrahDate、JapaneseDate
@Future
说明:被注释的元素必须是⼀个将来的⽇期
适⽤范
围:Date、Calendar、Instant、LocalDate、LocalDateTime、LocalTime、MonthDay、OffsetDateTime、OffsetTime、Year、YearMonth、ZonedDateTime、HijrahDate、JapaneseDate
@Pattern(value)
说明:被注释的元素必须符合指定的正则表达式bigdecimal转换为integer
适⽤范围:CharSequence、null
@Email
说明:被注释的元素必须是电⼦邮箱地址
适⽤范围:CharSequence
@Length
说明:被注释的字符串的⼤⼩必须在指定的范围内
适⽤范围:
@NotEmpty
说明:被注释的字符串的必须⾮空
适⽤范围:
@Range
说明:被注释的元素必须在合适的范围内
适⽤范围:
使⽤代码中校验
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = Validator();
Set<ConstraintViolation<DemoDTO>> violations = validator.validate(dto);
spring boot中其实已经有定义好的,可以直接依赖:
@Resource
private Validator validator;
⾃定义约束
⾃带的约束⼀般来说已经够⽤,如果有不⼀般的情况,就需要⾃⼰定义约束。
组合其它约束
直接将原有的约束添加到⾃⼰的注解上,我们新增个约束年龄属性的注解,假如我们限制年龄必须在0-150之间:
@Max(150)
@Min(0)
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {})
public @interface Age {
@OverridesAttribute(constraint = Max.class, name = "message")
@OverridesAttribute(constraint = Min.class, name = "message")
String message() default "年龄超出范围";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@OverridesAttribute注解可以覆盖组合约束的⼀些属性,这⾥只是覆盖message,其它属性也可以覆盖
简单测试⼀下:
@Age(message = "这年龄不太对吧")
private Integer age;
输出:
{
"code": 500,
"msg": "这年龄不太对吧"
}
新建约束
还是限制年龄的例⼦,这次我们⾃⼰写逻辑,⾸先是约束注解:
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = AgeValidtor.class)
public @interface Age {
String message() default "年龄超出范围";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
注意这⾥的 @Constraint(validatedBy = AgeValidtor.class),它设置了我们⾃⼰实现的验证器
接下来是实现验证器:
public class AgeValidtor implements ConstraintValidator<Age, Integer> {
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
return value == null || (value >= 0 && value <= 150);
}
}
验证器实现的接⼝的两个泛型,前⾯的 Age表⽰约束注解,后⾯的 Integer表⽰这个验证器⽤来验证这个类型的属性,前⾯介绍过,⼀个约束注解可以关联多个验证器,根据要验证的属性类型选择合适的验证器。
输出还是⼀样的:
{
"code": 500,
"msg": "这年龄不太对吧"
}
嵌套验证
如果⼀个对象内部有另⼀个对象需要验证,需要在这个对象属性上⽅加@Valid注解
@Getter
@Setter
@ToString
public class DemoDTO {
@Valid
private InlineObject inlineObject;
}
普通⽅法校验参数
除了验证接⼝,我们还可以验证普通的⽅法,⾸先在需要验证的⽅法所在类上⾯增加注解@Validated:
@Validated
@Service
public class DemoService {
public void demo(@Valid DemoDTO dto) {
}
}
正常调⽤后返回:
{
"code": 500,
"msg": "这年龄不太对吧"
}
注意:
1. 基于aop机制,被验证的⽅法需要注册为组件
2. 只能在类上⾯增加注解@Validated,不能在单个⽅法上
3. 抛出的异常为ConstraintViolationException,需要单独拦截,⽰例:
@ResponseBody
@ExceptionHandler(ConstraintViolationException.class)
public HttpResponse handle(ConstraintViolationException e) {
return HttpResponse.builder().code(500).msg(
.stream()
.findFirst()
.
map(ConstraintViolation::getMessage)
.orElse("参数校验失败")).build();
}
分组验证
很多时候,新增和更新使⽤了⽤⼀个类,但是更新的时候要求id属性不能为空,⽽新增时必须为空,或者新增时⽆所谓是什么。这时候,就需要根据情况,使⽤不同的校验规则,先定义新增和更新这两种情况分组:
public interface ValidationGroup {
interface Create extends Default {}
interface Update extends Default {}
}
注意:
1. 只能定义为接⼝
2. 需要继承ups.Default,否则没有加groups的其它约束将被视为其它分组
接着,定义两种情况需要验证的属性:
@NotNull(message = "更新时id必填", groups = ValidationGroup.Update.class)
private Integer id;
@NotNull(message = "新增时name必填", groups = ValidationGroup.Create.class)
private String name;
@NotNull(message = "任何情况age必填")
private Integer age;
再定义两种情况的接⼝:
@PostMapping("/create")
public String create(@Validated(ValidationGroup.Create.class) @RequestBody DemoDTO dto) {    Name();
}
@PostMapping("/update")
public String update(@Validated(ValidationGroup.Update.class) @RequestBody DemoDTO dto) {    Name();
}
这时候,我们⽤固定的⼊参,分别调⽤者两个接⼝,参数:
{
"age": 12
}
两种情况输出:
{
"code": 500,
"msg": "新增时name必填"
}
{
"code": 500,
"msg": "更新时id必填"
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。