参数校验:简单的就逐个手动写代码校验,推荐用Valid,使用hibernate-validator提供的,如果参数不能通过校验,报400错误,请求格式不正确:
步骤1:在参数对象的属性上添加校验注解如@NotBlank
步骤2:用@Valid注解controller方法的参数对象
常用校验注解(
通过注解的message属性自定义校验错误的信息
):
@NotNull值不能为空
@Null值必须为空
@Pattern(regx=)字符串必须匹配正则表达式
@Size(min=,max=)集合元素数量必须在min和max之间
@CreditCardNumber(ignoreNonDigitCharacters=)字符串必须是信用卡号(按美国的标准校验)
@Email字符串必须是email地址
@Length(min=,max=)字符串长度
@NotBlank字符串必须有字符
@NotEmpty字符串不为null,集合有元素
@Range(min=,max=)数字范围
@SafeHtml字符串必须是安全的html
@URL字符串是合法的URL
@AssertFalse值必须是false
@AssertTrue值必须是true
@DecimalMax(value=,inclusive=)值必须小于等于(inclusive=true)/小于(inclusive=false)value指定的值,可以注解在字符串类型属性上
@DecimalMin(value=,inclusive=)值必须大于等于(inclusive=true)/大于(inclusive=false)value指定的值,可以注解在字符串类型属性上
@Digits(integer=,fraction=)数字格式检查,integer指定整数部分最大长度,fraction指定小数部分最大长度
@Future值必须是未来的日期
@Past值必须是过去的日期
@Max(value=)值必须小于等于value指定的值,不能注解在字符串类型属性上
@Min(value=)值必须大于等于value指定的值,不能注解在字符串类型属性上
当参数校验未通过,controller不会进入,某些场景,如参数校验出错,需要记录业务日志,可在controller方法添加BindingResult参数,即可携带错误信息进入controller方法
BindingResult对象封装了参数校验的错误信息,其hasErrors方法表示有错误,使用getAllErrors然后stream流化遍历获取单条错误信息(错误信息可以定制):
例如:
import
lombok.
Data
;
import
javax.validation.constraints.
NotBlank
;
@Data
public class
User {
@NotBlank
(
message
=
"用户名不能为空"
)
private
String
username
;
}
@GetMapping
(
"/user"
)
public
User
user
(
@Valid
User user
,
BindingResult errors) {
if
(errors.hasErrors()) {
errors.getAllErrors().stream().forEach(
// error -> System.out.println(error.getDefaultMessage())
error -> {
FieldError fieldError = (FieldError)error
; //Error是Object类型,转换成FieldError可以获取校验错误的属性字段
System.
out
.println(fieldError.getField() +
" : "
+ error.getDefaultMessage())
;
}
)
;
}
return
user
;
}
复杂的业务场景比如校验传入的username是否已经在数据库中存在,需要自定义校验逻辑,步骤(其实就是自定义校验注解及其校验逻辑):
1.写校验类
2.写校验注解
3.在属性上使用(使用同系统提供的注解如@NotNull)
校验类:
package
com.example.security.valid
;
import
javax.validation.ConstraintValidator
;
import
javax.validation.ConstraintValidatorContext
;
/**
* 自定义校验类,实现ConstraintValidator接口,两个泛型分别是自定义的校验注解MyConstraint和注解生效的属性类型
* Object可以放在任何类型的属性上,String只能校验String类型的属性,如此
* initialize方法是校验器初始化执行,isValid是校验逻辑,value是属性值,context校验上下文,里面包含校验注解里面的信息
* 返回true校验通过,false校验失败,是javax.validation包提供的
*
* 该类里面可以通过@Autowire注入spring管理的bean。Spring会将实现了ConstraintValidator接口的类搞成bean,所以这个类不需要加@Component。
*/
public class
MyConstraintValidtor
implements
ConstraintValidator<
MyConstraint
,
Object> {
@Override
public void
initialize
(
MyConstraint
constraintAnnotation) {
System.
out
.println(
"MyConstraintValidtor initialize"
)
;
}
@Override
public boolean
isValid
(Object t
,
ConstraintValidatorContext constraintValidatorContext) {
return
t.equals(
"123456"
)
;
}
}
校验注解:
package
com.example.security.valid
;
import
javax.validation.
Constraint
;
import
javax.validation.Payload
;
import
java.lang.annotation.*
;
/**
* 参考系统提供的校验注解可知,message,groups,payload这3个属性必须提供
*
@Constraint(validatedBy
= MyConstraintValidtor.class)指定该注解的校验类
*/
@Target
({ElementType.
METHOD
,
ElementType.
FIELD
})
@Retention
(RetentionPolicy.
RUNTIME
)
@Constraint
(
validatedBy
= MyConstraintValidtor.
class
)
public
@
interface
MyConstraint
{
String
message
()
default
"校验未通过"
;
Class<?>[]
groups
()
default
{}
;
Class<?
extends
Payload>[]
payload
()
default
{}
;
}