Springboot接口參數(shù)校驗的方法
在設計接口時我們通常需要對接口中的非法參數(shù)做校驗,以降低在程序運行時因為一些非法參數(shù)而導致程序發(fā)生異常的風險,例如登錄的時候需要校驗用戶名密碼是否為空,創(chuàng)建用戶的時候需要校驗郵件、手機號碼格式是否準確。如果在代碼中對接口參數(shù)一個個硬編碼校驗的話就太繁瑣了,代碼可讀性極差。這時不妨試試Validator框架。
原生的依賴是validation-api而hibernate-validator是對validation-api的增強,hibernate-validator框架已經(jīng)集成在spring-boot-starter-web中。
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.2.0.Final</version> </dependency>
但從springboot-2.3開始,校驗包被獨立成了一個starter組件,所以需要引入validation和web,而springboot-2.3之前的版本只需要引入web依賴就可以了。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
部分常見注解如下:
| 注解 | 功能 |
| @AssertFalse | 可以為null,如果不為null的話必須為false |
| @AssertTrue | 可以為null,如果不為null的話必須為true |
| @DecimalMax | 設置不能超過最大值 |
| @DecimalMin | 設置不能超過最小值 |
| @Digits | 設置必須是數(shù)字且數(shù)字整數(shù)的位數(shù)和小數(shù)的位數(shù)必須在指定范圍內(nèi) |
| @Future | 日期必須在當前日期的未來 |
| @Past | 日期必須在當前日期的過去 |
| @Max | 最大不得超過此最大值 |
| @Min | 最大不得小于此最小值 |
| @NotNull | 不能為null,可以是空 |
| @Null | 必須為null |
| @Pattern | 必須滿足指定的正則表達式 |
| @Size | 集合、數(shù)組、map等的size()值必須在指定范圍內(nèi) |
| 必須是email格式 | |
| @Length | 長度必須在指定范圍內(nèi) |
| @NotBlank | 字符串不能為null,字符串trim()后也不能等于“” |
| @NotEmpty | 不能為null,集合、數(shù)組、map等size()不能為0;字符串trim()后可以等于“” |
| @Range | 值必須在指定范圍內(nèi) |
| @URL | 必須是一個URL |
一、基礎注解使用
注解簡單演示類
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
@Data
public class UserVo {
@Length(min = 4, max = 12, message = "賬號長度必須位于4到10之間")
private String userCode;
@NotBlank(message = "用戶名不能為空")
private String userName;
@Email(message = "郵箱格式有誤")
private String email;
@Pattern(regexp = "^1[3456789]\\d{9}$", message = "手機號格式錯誤")
private String phone;
/**
* 0:普通用戶;VIP:會員用戶;2:超級VIP用戶
*/
@Pattern(regexp = "[012]", message = "用戶類型有誤,請輸入0:普通用戶;VIP:會員用戶;2:超級VIP用戶")
private String type;
}在全局異常處理里面加上對參數(shù)校驗異常的攔截
@ExceptionHandler(value = {BindException.class, ValidationException.class, MethodArgumentNotValidException.class})
public ResponseVo validatedExceptionHandler(Exception e) {
log.error("參數(shù)校驗異常!原因是{}", e);
if (e instanceof MethodArgumentNotValidException) {
//BeanValidation exception
MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
return ResponseVo.error(ResponseEnum.BODY_NOT_MATCH.getResultCode(),
ex.getBindingResult().getAllErrors().stream()
.map(ObjectError::getDefaultMessage)
.collect(Collectors.joining("; ")));
} else if (e instanceof ConstraintViolationException) {
//BeanValidation GET simple param
ConstraintViolationException ex = (ConstraintViolationException) e;
return ResponseVo.error(ResponseEnum.BODY_NOT_MATCH.getResultCode(),
ex.getConstraintViolations().stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.joining("; ")));
} else if (e instanceof BindException) {
//BeanValidation GET object param
BindException ex = (BindException) e;
return ResponseVo.error(ResponseEnum.BODY_NOT_MATCH.getResultCode(),
ex.getAllErrors().stream()
.map(ObjectError::getDefaultMessage)
.collect(Collectors.joining("; ")));
}
return ResponseVo.error(ResponseEnum.BODY_NOT_MATCH.getResultCode(), ResponseEnum.BODY_NOT_MATCH.getResultMsg());
}定義參數(shù)校驗的controller
import com.yx.light.element.mybatis.vo.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.Email;
@RestController
@RequestMapping(value = "/valid")
@Validated
@Slf4j
public class ValidController {
/**
* 單參數(shù)校驗,單參數(shù)需要在controller上加上@Validated配合使用
* @param email
* @return
*/
@PostMapping(value = "/oneParam", produces = "application/json; charset=UTF-8")
public String oneParam(@Email(message = "郵箱格式有誤") String email) {
log.info("校驗郵箱為:{}", email);
return "郵箱校驗成功";
}
/**
* body類型校驗
* @param vo
* @return
*/
@PostMapping(value = "/bodyParam", produces = "application/json; charset=UTF-8")
public String bodyParam(@Validated @RequestBody UserVo vo) {
log.info("校驗body為:{}", vo);
return "body校驗成功";
}
/**
* 表單參數(shù)校驗
* @param vo
* @return
*/
@PostMapping(value = "/formParam", produces = "application/json; charset=UTF-8")
public String formParam(@Validated UserVo vo) {
log.info("校驗表單為:{}", vo);
return "表單校驗成功";
}
}oneParam接口

bodyParam接口

formParam接口

二、自定義參數(shù)校驗
當然你也可以自定義參數(shù)校驗,出現(xiàn)有些復雜的邏輯基本注解是沒辦法兼容的,需要我們自己去實現(xiàn)自動校驗。
自定義校驗注解
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Documented
@Retention(RUNTIME)
@Target({FIELD, METHOD, PARAMETER, TYPE})
@Constraint(validatedBy = UserValidation.UniqueUserValidator.class)
public @interface UniqueUser {
String message() default "用戶編碼、手機號碼、郵箱不允許與現(xiàn)存用戶重復";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}想讓自定義驗證注解生效,需要實現(xiàn)ConstraintValidator接口。接口的第一個參數(shù)是 自定義注解類型,第二個參數(shù)是 被注解字段的類。
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.annotation.Annotation;
import java.util.function.Predicate;
@Slf4j
public class UserValidation<T extends Annotation> implements ConstraintValidator<T, UserVo> {
protected Predicate<UserVo> predicate = c -> true;
@Override
public boolean isValid(UserVo user, ConstraintValidatorContext constraintValidatorContext) {
return predicate.test(user);
}
/**
* 校驗用戶是否唯一
* 即判斷數(shù)據(jù)庫是否存在當前新用戶的信息,如用戶編碼,手機,郵箱
*/
public static class UniqueUserValidator extends UserValidation<UniqueUser> {
@Override
public void initialize(UniqueUser uniqueUser) {
predicate = c -> !existsUser(c.getUserCode(), c.getEmail(), c.getPhone());
}
private boolean existsUser(String userCode, String email, String phone) {
//TODO 寫一個數(shù)據(jù)庫查詢判斷是否存在相同的用戶,省略...
return true;
}
}
}在controller中添加測試接口
@PostMapping(value = "/addUser", produces = "application/json; charset=UTF-8")
public String addUser(@UniqueUser @Validated @RequestBody UserVo vo) {
log.info("校驗body為:{}", vo);
return "新增成功";
}addUser接口

三、分組校驗
如果你的一個實體中的字段某一些是新增的時候必傳,某一些修改時又不用傳,那么對于不用傳的字段肯定不需要校驗的,這時候如果我們共用一個實體作為多個接口參數(shù)那肯定存在兼容問題,此時你就可以考慮將參數(shù)分組判斷。
定義一個分組接口ValidGroup讓其繼承javax.validation.groups.Default,再在分組接口中定義出多個不同的操作類型,Create,Update,Query,Delete。
import javax.validation.groups.Default;
public interface ValidGroup extends Default {
interface Crud extends ValidGroup {
interface Create extends Crud {
}
interface Update extends Crud {
}
interface Query extends Crud {
}
interface Delete extends Crud {
}
}
}稍微修改一下原來的vo,給他們加上分組參數(shù)groups
import com.yx.light.element.mybatis.validation.ValidGroup;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
@Data
public class UserVo {
@Length(min = 4, max = 12, message = "賬號長度必須位于4到10之間", groups = ValidGroup.Crud.Update.class)
private String userCode;
@NotBlank(message = "用戶名不能為空", groups = ValidGroup.Crud.Create.class)
private String userName;
@Email(message = "郵箱格式有誤")
private String email;
@Pattern(regexp = "^1[3456789]\\d{9}$", message = "手機號格式錯誤")
private String phone;
/**
* 0:普通用戶;VIP:會員用戶;2:超級VIP用戶
*/
@Pattern(regexp = "[012]", message = "用戶類型有誤,請輸入0:普通用戶;VIP:會員用戶;2:超級VIP用戶")
private String type;
}在controller中添加如下方法,這里我們通過value屬性給addUserV2()和updateUser()方法分別指定Create和Update分組。
@PostMapping(value = "/addUserV2", produces = "application/json; charset=UTF-8")
public String addUserV2(@Validated(value = ValidGroup.Crud.Create.class) @RequestBody UserVo vo) {
log.info("校驗body為:{}", vo);
return "新增成功";
}
@PostMapping(value = "/updateUser", produces = "application/json; charset=UTF-8")
public String updateUser(@Validated(value = ValidGroup.Crud.Update.class) @RequestBody UserVo vo) {
log.info("校驗body為:{}", vo);
return "更新成功";
}addUserV2接口

updateUser接口

到此這篇關于Springboot接口參數(shù)校驗的文章就介紹到這了,更多相關Springboot參數(shù)校驗內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
RestFul風格 — 使用@PathVariable傳遞參數(shù)報錯404的解決
這篇文章主要介紹了RestFul風格 — 使用@PathVariable傳遞參數(shù)報錯404的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10
Java數(shù)據(jù)結(jié)構(gòu)之順序表的實現(xiàn)
線性表(linear?list)是n個具有相同特性的數(shù)據(jù)元素的有限序列。順序表是常見的線性表之一,本文將詳細講講順序表的原理與實現(xiàn),需要的可以參考一下2022-08-08
在Spring Boot中使用swagger-bootstrap-ui的方法
Java將CSV的數(shù)據(jù)發(fā)送到kafka的示例

