SpringBoot 參數(shù)校驗/參數(shù)驗證,常用方法都給你總結(jié)好了!
今日推薦
1、前言
在控制器類的方法里自己寫校驗邏輯代碼當然也可以,只是代碼比較丑陋,有點“l(fā)ow”。業(yè)界有更好的處理方法,分別闡述如下。
2、PathVariable校驗
@GetMapping("/path/{group:[a-zA-Z0-9_]+}/{userid}")
@ResponseBody
public String path(@PathVariable("group") String group, @PathVariable("userid") Integer userid) {
return group + ":" + userid;
}
用法是:路徑變量:正則表達式。當請求URI不滿足正則表達式時,客戶端將收到404錯誤碼。不方便的地方是,不能通過捕獲異常的方式,向前端返回統(tǒng)一的、自定義格式的響應(yīng)參數(shù)。
3、方法參數(shù)校驗
@GetMapping("/validate1")
@ResponseBody
public String validate1(
@Size(min = 1,max = 10,message = "姓名長度必須為1到10")@RequestParam("name") String name,
@Min(value = 10,message = "年齡最小為10")@Max(value = 100,message = "年齡最大為100") @RequestParam("age") Integer age) {
return "validate1";
}
如果前端傳遞的參數(shù)不滿足規(guī)則,則拋出異常。注解Size、Min、Max來自validation-api.jar,更多注解參見相關(guān)標準小節(jié)。
4、表單對象/VO對象校驗
當參數(shù)是VO時,可以在VO類的屬性上添加校驗注解。
public class User {
@Size(min = 1,max = 10,message = "姓名長度必須為1到10")
private String name;
@NotEmpty
private String firstName;
@Min(value = 10,message = "年齡最小為10")@Max(value = 100,message = "年齡最大為100")
private Integer age;
@Future
@JSONField(format="yyyy-MM-dd HH:mm:ss")
private Date birth;
。。。
}
其中,F(xiàn)uture注解要求必須是相對當前時間來講“未來的”某個時間。
@PostMapping("/validate2")
@ResponseBody
public User validate2(@Valid @RequestBody User user){
return user;
}
5、自定義校驗規(guī)則
5.1 自定義注解校驗
需要自定義一個注解類和一個校驗類。
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER,ElementType.FIELD})
@Constraint(validatedBy = FlagValidatorClass.class)
public @interface FlagValidator {
// flag的有效值,多個使用,隔開
String values();
// flag無效時的提示內(nèi)容
String message() default "flag必須是預(yù)定義的那幾個值,不能隨便寫";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class FlagValidatorClass implements ConstraintValidator<FlagValidator,Object> {
/**
* FlagValidator注解規(guī)定的那些有效值
*/
private String values;
@Override
public void initialize(FlagValidator flagValidator) {
this.values = flagValidator.values();
}
/**
* 用戶輸入的值,必須是FlagValidator注解規(guī)定的那些值其中之一。
* 否則,校驗不通過。
* @param value 用戶輸入的值,如從前端傳入的某個值
*/
@Override
public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
// 切割獲取值
String[] value_array = values.split(",");
Boolean isFlag = false;
for (int i = 0; i < value_array.length; i++){
// 存在一致就跳出循環(huán)
if (value_array[i] .equals(value)){
isFlag = true; break;
}
}
return isFlag;
}
}
使用我們自定義的注解:
public class User {
// 前端傳入的flag值必須是1或2或3,否則校驗失敗
@FlagValidator(values = "1,2,3")
private String flag ;
。。。
}
5.2 分組校驗
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
public class Resume {
public interface Default {
}
public interface Update {
}
@NotNull(message = "id不能為空", groups = Update.class)
private Long id;
@NotNull(message = "名字不能為空", groups = Default.class)
@Length(min = 4, max = 10, message = "name 長度必須在 {min} - {max} 之間", groups = Default.class)
private String name;
@NotNull(message = "年齡不能為空", groups = Default.class)
@Min(value = 18, message = "年齡不能小于18歲", groups = Default.class)
private Integer age;
。。。
}
/**
* 使用Defaul分組進行驗證
* @param resume
* @return
*/
@PostMapping("/validate5")
public String addUser(@Validated(value = Resume.Default.class) @RequestBody Resume resume) {
return "validate5";
}
/**
* 使用Default、Update分組進行驗證
* @param resume
* @return
*/
@PutMapping("/validate6")
public String updateUser(@Validated(value = {Resume.Update.class, Resume.Default.class}) @RequestBody Resume resume) {
return "validate6";
}
建立了兩個分組,名稱分別為Default、Update。POST方法提交時使用Defaut分組的校驗規(guī)則,PUT方法提交時同時使用兩個分組規(guī)則。
6、異常攔截器
通過設(shè)置全局異常處理器,統(tǒng)一向前端返回校驗失敗信息。
import com.scj.springbootdemo.WebResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
/**
* 全局異常處理器
*/
@ControllerAdvice
public class GlobalExceptionHandler {
private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 用來處理bean validation異常
* @param ex
* @return
*/
@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
public WebResult resolveConstraintViolationException(ConstraintViolationException ex){
WebResult errorWebResult = new WebResult(WebResult.FAILED);
Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
if(!CollectionUtils.isEmpty(constraintViolations)){
StringBuilder msgBuilder = new StringBuilder();
for(ConstraintViolation constraintViolation :constraintViolations){
msgBuilder.append(constraintViolation.getMessage()).append(",");
}
String errorMessage = msgBuilder.toString();
if(errorMessage.length()>1){
errorMessage = errorMessage.substring(0,errorMessage.length()-1);
}
errorWebResult.setInfo(errorMessage);
return errorWebResult;
}
errorWebResult.setInfo(ex.getMessage());
return errorWebResult;
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public WebResult resolveMethodArgumentNotValidException(MethodArgumentNotValidException ex){
WebResult errorWebResult = new WebResult(WebResult.FAILED);
List<ObjectError> objectErrors = ex.getBindingResult().getAllErrors();
if(!CollectionUtils.isEmpty(objectErrors)) {
StringBuilder msgBuilder = new StringBuilder();
for (ObjectError objectError : objectErrors) {
msgBuilder.append(objectError.getDefaultMessage()).append(",");
}
String errorMessage = msgBuilder.toString();
if (errorMessage.length() > 1) {
errorMessage = errorMessage.substring(0, errorMessage.length() - 1);
}
errorWebResult.setInfo(errorMessage);
return errorWebResult;
}
errorWebResult.setInfo(ex.getMessage());
return errorWebResult;
}
}
7、相關(guān)標準
JSR 303 是Bean驗證的規(guī)范 ,Hibernate Validator 是該規(guī)范的參考實現(xiàn),它除了實現(xiàn)規(guī)范要求的注解外,還額外實現(xiàn)了一些注解。
validation-api-1.1.0.jar 包括如下約束注解:

hibernate-validator-5.3.6.jar 包括如下約束注解:

8、同時校驗2個或更多個字段/參數(shù)
常見的場景之一是,查詢某信息時要輸入開始時間和結(jié)束時間。顯然,結(jié)束時間要≥開始時間??梢栽诓樵?a target="_blank" textvalue="VO類" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" style="text-decoration: underline;" data-linktype="2">VO類上使用自定義注解,下面的例子來自這里。劃重點:@ValidAddress使用在類上。
@ValidAddress
public class Address {
@NotNull
@Size(max = 50)
private String street1;
@Size(max = 50)
private String street2;
@NotNull
@Size(max = 10)
private String zipCode;
@NotNull
@Size(max = 20)
private String city;
@Valid
@NotNull
private Country country;
// Getters and setters
}
public class Country {
@NotNull
@Size(min = 2, max = 2)
private String iso2;
// Getters and setters
}
@Documented
@Target(TYPE)
@Retention(RUNTIME)
@Constraint(validatedBy = { MultiCountryAddressValidator.class })
public @interface ValidAddress {
String message() default "{com.example.validation.ValidAddress.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class MultiCountryAddressValidator
implements ConstraintValidator<ValidAddress, Address> {
public void initialize(ValidAddress constraintAnnotation) {
}
@Override
public boolean isValid(Address address,
ConstraintValidatorContext constraintValidatorContext) {
Country country = address.getCountry();
if (country == null || country.getIso2() == null || address.getZipCode() == null) {
return true;
}
switch (country.getIso2()) {
case "FR":
return // Check if address.getZipCode() is valid for France
case "GR":
return // Check if address.getZipCode() is valid for Greece
default:
return true;
}
}
}
來源:blog.csdn.net/jinjiankang/article/details/89711493
推薦文章
1、一款高顏值的 SpringBoot+JPA 博客項目 2、超優(yōu) Vue+Element+Spring 中后端解決方案 3、推薦幾個支付項目! 4、推薦一個 Java 企業(yè)信息化系統(tǒng) 5、一款基于 Spring Boot 的現(xiàn)代化社區(qū)(論壇/問答/社交網(wǎng)絡(luò)/博客)
