1. 程式人生 > >Spring Boot MVC 引數校驗

Spring Boot MVC 引數校驗

文章目錄

Spring Boot Validate

Spring Boot 支援JSR303/JSR349驗證框架,通過註解實現對引數的校驗,並將校驗結果封裝成BindingResult物件。

常用註解

下面的表格列出常用校驗類及主要功能。這些註解必須配合@Valid或@Validated使用,通過這兩個註解開啟校驗。

檢查型別 註解 說明
空檢查 @Null 驗證物件為null
@NotNull 驗證物件不為null
@NotEmpty 驗證物件不為null、且長度>0
@NotBlank 驗證字串不為null、且最少有一個非空格字元
長度檢查 @Size(min,max) 驗證物件長度
@Length(min,max) 驗證字串長度
數值檢查 @Min(value) 驗證數字>=value
@Max(value) 驗證數字<=value
@Digits(integer,fraction) 驗證數字格式
@Range(min,max) 驗證數字是否符合[min,max]
正則檢查 @Pattern(regexp) 驗證字串是否符合正則表示式
@Email 驗證是否郵箱格式

注 :對於長度的校驗基本都支援字串、集合、Map、陣列的長度。

下面是@Valid和@Validated的區別。

@Valid @Validated
分組校驗 不支援 支援
使用範圍 方法、屬性、構造方法、引數 類、方法、引數
巢狀驗證 支援 不支援

注 :巢狀驗證。JavaBean a中某個屬性型別是JavaBean b,對a進行驗證的同時驗證b。

使用說明

基本使用

以新增使用者為例

新建User類,為name屬性新增@NotBlank註解

@Data
class User {
	private Integer id;
	@NotBlank
	private String name;
}

新增新建使用者介面,新增@Validated註解開啟user引數校驗

@RestController
@RequestMapping("/validate")
public class ValidateController {
	@RequestMapping("/addUser")
	public Integer addUser(@Validated User user) {
		// 假設插入資料庫後,生成id為89757
		user.setId(89757);
		// 插入成功後返回id
		return user.getId();
	}
}

啟動服務,測試程式碼

瀏覽器輸入 :http://localhost:8080/validate/addUser
由於name是null,校驗不通過,返回錯誤

瀏覽器輸入 :http://localhost:8080/validate/addUser?name=ly
校驗通過,返回89757

實現分組校驗

同一個JavaBean在不同的場景可能需要不用的校驗規則,例如:新增使用者時id必須是null,修改使用者時id不能是null。每一個校驗註解都有group屬性,通過group屬性可以實現不同方法採用不同的校驗規則。以新建使用者為例

修改User類,新增並指定校驗組

@Data
class User {
	// 定義新增校驗組和更新校驗組
	public interface Add {}
	public interface Update {}

	// 新增校驗並指定不同的校驗組
	@Null(groups = Add.class)
	@NotNull(groups = Update.class)
	private Integer id;

	// 新增新增和修改校驗組
	@NotBlank(groups = {Add.class, Update.class})
	private String name;
}

新增修改使用者介面,為新增和修改使用者介面指定校驗組

@RestController
@RequestMapping("/validate")
public class ValidateController {
	// 通過group屬性指定新增使用者校驗組
	@RequestMapping("/addUser")
	public Integer addUser(@Validated(User.Add.class) User user) {
		// 同上,略
	}

	// 通過group屬性執行修改使用者校驗組
	@RequestMapping("/updateUser")
	public boolean updateUser(@Validated(User.Update.class) User user) {
		// 假設修改成功,返回true
		return true;
	}
}

啟動服務,測試程式碼

瀏覽器輸入 :http://localhost:8080/validate/addUser?id=1&name=ly
由於id不是空,校驗不通過,返回錯誤

瀏覽器輸入 :http://localhost:8080/validate/addUser?name=ly
校驗通過,返回89757

瀏覽器輸入 :http://localhost:8080/validate/updateUser?name=ly
由於id是空,校驗不通過,返回錯誤

瀏覽器輸入 :http://localhost:8080/validate/updateUser?id=1&name=ly
校驗通過,返回true

處理校驗結果

Spring Boot 會將校驗結果封裝成BindingResult物件,可以通過BindingResult引數獲取校驗結果。

新增方法,用於測試校驗結果的獲取

@RestController
@RequestMapping("/validate")
public class ValidateController {
	
	// 其他方法略
	
	@RequestMapping("/handlerBindingResult")
	public Object bindingResult(@Validated(User.Add.class) User user, BindingResult bindingResult) {
		// 若存在校驗異常則處理
		if (bindingResult.hasErrors()) {
			StringBuilder errorMessage = new StringBuilder();
			// 遍歷全部校驗異常並拼接異常資訊
			for (FieldError error : bindingResult.getFieldErrors()) {
				errorMessage.append(error.getField()).append(error.getDefaultMessage()).append('\n');
			}
			return errorMessage.toString();
		}
		return true;
	}
}

啟動服務,測試程式碼

瀏覽器輸入 :http://localhost:8080/validate/handlerBindingResult?id=1
返回處理後的錯誤資訊 :id必須為null name不能為空

瀏覽器輸入 :http://localhost:8080/validate/handlerBindingResult?name=ly
校驗通過,返回true

注 :若方法需要校驗多個引數,例如:method(param1,param2…),需要依次獲取校驗結果,例如 :method(param1,bindingResult1,param2,bindingResult2…)。對於未通過引數注入處理的BindingResult物件,會丟擲異常,可以通過捕獲MethodArgumentNotValidExceptionBindException統一處理,個人習慣在這裡處理。

自定義校驗註解

當現有的校驗註解不滿足業務要求的時候,就需要通過自定義註解來滿足我們自定義的校驗規則。以性別校驗為例,假設1代表男、2代表女,輸入其他都是不合法的,下面說明如何自定義性別校驗註解

新建Sex註解,用於性別引數校驗

@Documented
@Retention(RUNTIME)
// 指定校驗類
@Constraint(validatedBy = SexValidator.class)
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@interface Sex {
	// 必須的三個屬性
	String message() default "引數值不正確";
	Class<?>[] groups() default {};
	Class<? extends Payload>[] payload() default {};
	// 允許值(預設1男2女)。若使用方的性別列舉不同,可以通過該欄位指定校驗通過的值。
	int[] allowed() default {1, 2};
}

新增Sex註解校驗類

// 校驗類需要實現ConstraintValidator介面,通過泛型指定被校驗註解型別和被校驗欄位型別
class SexValidator implements ConstraintValidator<Sex, Integer> {
	private Set<Integer> allowed = new HashSet<>(2);

	// 初始化允許校驗通過的值
	@Override
	public void initialize(Sex sex) {
		for (int i : sex.allowed()) {
			allowed.add(i);
		}
	}
	// 執行校驗
	@Override
	public boolean isValid(Integer value, ConstraintValidatorContext context) {
		return allowed.contains(value);
	}
}

修改User類

@Data
class User {

	// 略
	
	// 假設註解使用方的性別列舉分別是0未知、1男、2女
	@Sex(allowed = {0, 1, 2}, groups = {Add.class, Update.class})
	private Integer sex;
}

啟動服務,測試程式碼

瀏覽器輸入 :http://localhost:8080/validate/handlerBindingResult?name=ly&sex=4
返回處理後的錯誤資訊 :sex引數值不正確

瀏覽器輸入 :http://localhost:8080/validate/handlerBindingResult?name=ly&sex=1
校驗通過,返回true

配置校驗提示資訊

classpath下新建ValidationMessages.properties檔案

com.example.validate.sex = :incorrect parameter values

修改Sex類

@Documented
@Retention(RUNTIME)
@Constraint(validatedBy = SexValidator.class)
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@interface Sex {
	// 指定配置檔案中訊息
	String message() default "{com.example.validate.sex}";
	
	//略
}

啟動服務,測試程式碼

瀏覽器輸入 :http://localhost:8080/validate/handlerBindingResult?name=ly&sex=4
返回處理後的錯誤資訊 :sex:incorrect parameter values

手動進行校驗

一般用不到,校驗方法如下

注入校驗物件,新增手動校驗測試方法

@RestController
@RequestMapping("/validate")
public class ValidateController {
	// 注入校驗物件。可以通過Validation.buildDefaultValidatorFactory().getValidator()獲得。
	@Autowired
	private Validator validator;
	
	// 其他程式碼略
	
	@RequestMapping("/activeValidate")
	public String activeValidate(User user) {
		// 使用新增使用者規則校驗使用者物件
		Set<ConstraintViolation<User>> validate = validator.validate(user, User.Add.class);
		// 處理校驗結果
		StringBuilder result = new StringBuilder();
		for (ConstraintViolation<User> violation : validate) {
			result.append(violation.getPropertyPath()).append(violation.getMessage());
		}
		return result.toString();
	}
}

啟動服務,測試程式碼

瀏覽器輸入 :http://localhost:8080/validate/activeValidate?name=ly
返回處理後的錯誤資訊 :sex:incorrect parameter values