https://www.cnblogs.com/funyoung/p/8670550.html
https://www.cnblogs.com/monkeydai/p/10068547.html
SpringMVC參數校驗
使用SpringMVC時配合hibernate-validate進行參數的合法性校驗,能節省一定的代碼量。
1.搭建Web工程並引入hibernate-validate依賴
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.7.Final</version>
</dependency>
Maven依賴傳遞,自動依賴validation-api、jboss-logging、classmate。

2.使用校驗注解標注在屬性上(DTO)

*每個注解都有message屬性,該屬性用於填寫校驗失敗時的異常描述信息,當校驗失敗時可以獲取對應的message屬性值。
3.控制層中使用DTO接收參數並使用@Validated/@Valid注解開啟對參數的校驗
*@Validated注解表示開啟Spring的校驗機制,支持分組校驗,聲明在入參上。
*@Valid注解表示開啟Hibernate的校驗機制,不支持分組校驗,聲明在入參上。
*在DTO后面緊跟BindingResult對象,那么當參數不符合時,能通過該對象直接獲取不符合校驗的message描述信息。
*若使用了@Validated/@Valid注解開啟校驗,但DTO后面沒有緊跟BindingResult對象,那么當參數不符合時,將直接返回400 Bad Request狀態碼。
演示:

結果:
密碼不能為空! id不能為空! 用戶名的長度在4~12之間!
*校驗的順序是隨機的,因此程序不能依賴校驗的順序去做相關的邏輯處理。
4.分組校驗
每個校驗注解都有group屬性用於指定校驗所屬的組,其值是Class數組,在Controller中使用@Validated注解開啟對參數的校驗時若指定要進行校驗的組,那么只有組相同的屬性才會被進行校驗(默認全匹配)
Class<?>[] groups() default { };
一般定義標識接口作為組資源
public interface GroupA {
}
public interface GroupB {
}
使用校驗注解標注在屬性上並進行分組
public class User {
@NotNull(message="id不能為空!",groups = {GroupA.class})
private Integer id;
@NotBlank(message="用戶名不能為空!",groups = {GroupB.class})
@Size(min=4,max=12,message="用戶名的長度在4~12之間!")
private String username;
@NotBlank(message="密碼不能為空!")
private String password;
@Email(message="非法郵箱!")
private String email;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public User() {
super();
}
}
Controller中使用@Validated注解開啟對參數的校驗並指定校驗的組,那么只有組相同的屬性才會被進行校驗(默認全匹配)
@RestController
public class BaseController {
@RequestMapping("/test")
public User test(@Validated(value= {GroupB.class}) User user, BindingResult result) {
if (result.hasErrors()) {
List<ObjectError> errors = result.getAllErrors();
for (ObjectError error : errors) {
System.out.println(error.getDefaultMessage());
}
}
return user;
}
}
演示:

結果:
用戶名不能為空!
*后端一般只返回重名等錯誤描述信息,對於非空、字符長度、手機郵箱合法性校驗等由前端進行判斷並提示,后端校驗不通過時不返回錯誤描述信息,所以不需要使用BindingResult獲取錯誤描述,當參數不符合時直接返回400 Bad Request請求。
spring mvc 參數校驗
spring mvc中的參數校驗
spring mvc 支持jsr-303 Bean驗證框架,默認實現是使用的Hibernate validator。在spring mvc中只需要使用@Validated注解在方法參數上即可對參數對象進行校驗。校驗結果放在BindingResult中,所以每個被校驗的參數后面都需要放一個BindingResult。
因為有時候並不是所有的地方需要的驗證都是一樣的,例如更新的時候需要id notnull,而插入的時候確需要id為null,所以驗證的時候在每個驗證條件中都增加了groups屬性,用於標識需要哪種校驗,而在@validated中可以設置vlue屬性,用於和驗證條件中的groups配合使用,只有@Validated中的value類型和驗證注解中的groups屬性一致的時候才進行校驗。
JSR-303提供的常用的校驗注解主要有以下幾類
空類型檢查
@Null驗證對象必須為空
@NotNull驗證對象不能為空
@NotBlank 驗證對象不能為空字符串
@NotEmpty 驗證對象不能為空,集合類型不能為空
長度檢查
@Size(min= ,max=) 驗證對象長度,支持字符串和集合
@Length 驗證字符串長度
數值檢查
@Max 驗證數字大小是否小於某個數值
@Min 驗證數字大小是否大於某個數值
@Digits 驗證數字是否符合某個格式例如:整數3為,小數2位
@Range 驗證數值是否在某個范圍之內
其他檢查
@Email 驗證是否位郵件格式,若為null則不做校驗
@Pattern 驗證是否符合正則表達式規則
例子
在controller中使用@Validated注解
1 @Controller
2 @RequestMapping("valid")
3 @Slf4j
4 public class ValidateController {
5
6 private static final String BASE_PATH = "/valid/";
7
8 @RequestMapping("index")
9 public String index(@Validated() Student student,BindingResult result){
10 if(result.hasErrors()){
11 StringBuffer sb = new StringBuffer();
12 List<FieldError> errorList = result.getFieldErrors();
13 errorList.stream().forEach(error->{
14 String message = error.getDefaultMessage();
15 String field = error.getField();
16 sb.append(field).append(":").append(message).append(",");
17 });
18 log.error(sb.toString());
19 }
20
21 return BASE_PATH + "index";
22 }
23 }
在bean中使用驗證注解
@Data
public class Student {
@Length(max = 32,min = 32,groups = {})
private String id;
@NotNull
@Size(max = 50)
private String name;
@Max(100)
@Min(12)
@NotNull
private Integer age;
@Email
@NotNull
private String email;
@AssertFalse
private Boolean isLeader;
@WorkOverTime
private String workOverTime;
}
這樣在前台請求該方法的時候就會進行自動校驗。而校驗結果會保存在BindingResult中。可以通過hasErrors判斷校驗是否通過,getFieldErrors可以獲取所有的錯誤。
自定義參數校驗
有的時候自帶的參數校驗類型並不能滿足我們的需求,這時我們可以自定校驗注解。
定義自定義注解類:
@Constraint(validatedBy = {ValidatedWorkOverTime.class})
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface WorkOverTime {
String message() default "加班時長不能超過{max}小時";
int max() default 5;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
在這個類中我們使用Constraint注解聲明我們需要使用哪個類來進行具體的驗證。
注解類中必須包含1.錯誤信息。即message方法,2.驗證規則分組,即gourps方法,3.驗證的有效負荷即payload方法。
我們還必須實現一個類來進行具體的驗證。即上面Constraint聲明的類。
@Slf4j
public class ValidatedWorkOverTime implements ConstraintValidator<WorkOverTime,Object> {
private Integer max;
private WorkOverTime workOverTime;
@Override
public void initialize(WorkOverTime constraintAnnotation) {
this.max = constraintAnnotation.max();
this.workOverTime = constraintAnnotation;
}
@Override
public boolean isValid(Object integer, ConstraintValidatorContext constraintValidatorContext) {
Integer overWorkTime = Integer.MAX_VALUE;
if(integer instanceof Integer){
overWorkTime = (Integer) integer;
}else{
try {
overWorkTime = Integer.parseInt(integer.toString());
}catch (Exception e){
log.error(e.toString(),e);
if(e instanceof NumberFormatException){
}
}
}
return max>overWorkTime;
}
}
這樣我們就可以在bean中的屬性中使用@WorkOverTime注解來進行參數校驗了。


