Spring boot JSR-303參數(shù)校驗(yàn)器
1. 運(yùn)用場(chǎng)景
規(guī)定前端傳入的內(nèi)容,否者返回對(duì)應(yīng)的題提示,進(jìn)一步減少臟數(shù)據(jù)的出現(xiàn)。不用我們自己判斷數(shù)據(jù)是否合法,拿到我們想要的數(shù)據(jù)。
2. 進(jìn)入maven依賴
此實(shí)例為Spring boot 2.4.5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
3. 工具類
返回值對(duì)象
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
/**
* @Description 統(tǒng)一返回值對(duì)象
* @Author 張凱強(qiáng)
* @Date Created in 2021/5/20
* @E-mail 862166318@qq.com
*/
@Data
public class R {
private String msg;
private Integer code;
private Boolean success;
private Map<String, Object> data;
public static R ok(){
R r = new R();
r.setMsg("OK");
r.setSuccess(true);
r.setCode(0);
r.setData(new HashMap<String, Object>());
return r;
}
public static R error(){
R r = new R();
r.setMsg("error");
r.setSuccess(false);
r.setCode(-1);
return r;
}
public R code(Integer code){
this.code = code;
return this;
}
public R msg(String msg){
this.msg = msg;
return this;
}
public R success(Boolean success){
this.success = success;
return this;
}
public R data(Map map){
this.data = map;
return this;
}
public R data(String key,Object val){
if(this.data==null)
this.data = new HashMap<String, Object>();
this.data.put(key,val);
return this;
}
}
統(tǒng)一異常處理類
import com.zkq.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
/**
* @Description 異常信息處理器
* @Author 張凱強(qiáng)
* @Date Created in 2021/5/20
* @E-mail 862166318@qq.com
*/
@RestControllerAdvice
@Slf4j
public class ExceptionHandle {
// 固定處理JSR-303 拋出的異常
@ExceptionHandler(BindException.class)
public R validException(BindException e){
Map<String,String> map = new HashMap<String, String>();
e.getBindingResult().getFieldErrors().forEach((fieldError) -> {
map.put(fieldError.getField(),fieldError.getDefaultMessage());
});
return R.ok().msg("參數(shù)錯(cuò)誤!").data(map);
}
// 統(tǒng)一處理不是上面JSR-303 的錯(cuò)誤,當(dāng)然也可以細(xì)分,我在此就部分了,統(tǒng)一處理。
@ExceptionHandler
public R error(Throwable t){
// 記錄響應(yīng)的錯(cuò)誤信息
// log.error("",t.getMessage());
return R.error().msg("系統(tǒng)錯(cuò)誤!");
}
}
4. 代碼實(shí)例
4.1 普通校驗(yàn) @Valid
驗(yàn)證對(duì)象User
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @Description 普通校驗(yàn)
* @Author 張凱強(qiáng)
* @Date Created in 2021/5/20
* @E-mail 862166318@qq.com
*/
@Data
public class User {
@NotNull(message = "id不能為空")
private Long id;
@NotBlank(message = "姓名不能為空")
private String name;
@NotNull(message = "年齡不能為空")
private Integer age;
}
測(cè)試接口
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
@RestController
public class ZkqController{
// 測(cè)試 @Valid
@GetMapping("/zkq")
public R zkq(@Valid User user){
return R.ok().msg("標(biāo)準(zhǔn)校驗(yàn)").data("user",user);
}
}
測(cè)試結(jié)果:
不符合規(guī)范

符合規(guī)范

4.2 分組校驗(yàn) @Validated
這里我就分一組演示
創(chuàng)建校驗(yàn)器分組類
/**
* @Description 校驗(yàn)器分組,GetGroup這個(gè)不固定可隨意寫(xiě)
* @Author 張凱強(qiáng)
* @Date Created in 2021/5/20
* @E-mail 862166318@qq.com
*/
public interface GetGroup {
}
創(chuàng)建校驗(yàn)對(duì)象
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @Description 分組校驗(yàn)
* @Author 張凱強(qiáng)
* @Date Created in 2021/5/20
* @E-mail 862166318@qq.com
*/
@Data
public class User2 {
// groups = {GetGroup.class,User.class} 可分多組這里我就分了一組,根據(jù)需求自行分組
@NotNull(message = "id不能為空",groups = GetGroup.class)
private Long id;
@NotBlank(message = "姓名不能為空",groups = GetGroup.class)
private String name;
@NotNull(message = "年齡不能為空",groups = GetGroup.class)
private Integer age;
}
測(cè)試接口
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ZkqController{
// 測(cè)試 @Validated
@GetMapping("/zkq2")
public R zkq2(@Validated(GetGroup.class) User2 user){
return R.ok().msg("分組校驗(yàn)").data("user",user);
}
}
校驗(yàn)結(jié)果
不符合規(guī)范

符合校驗(yàn)

4.3 自定義校驗(yàn)器校驗(yàn) @Valid
創(chuàng)建檢驗(yàn)器注解@ZkqNumRange
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
/**
* @Description 自定義校驗(yàn)器注解 (message和groups,payload 是必須的)
* @Author 張凱強(qiáng)
* @Date Created in 2021/5/20
* @E-mail 862166318@qq.com
*/
@Documented
// 支持校驗(yàn)的類型 Long ,F(xiàn)loat ,Integer 暫時(shí)這三種類型,有需要可以自己擴(kuò)展
@Constraint(validatedBy = {ZkqNumRangeConstraintValidatorLong.class, ZkqNumRangeConstraintValidatorFloat.class, ZkqNumRangeConstraintValidatorInteger.class})
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ZkqNumRange {
// 必須的不符合的的提示語(yǔ),也可以象注解一樣寫(xiě){javax.validation.constraints.ZkqNumRange .message}
// 但是要在 resources 創(chuàng)建對(duì)應(yīng)的文件 ValidationMessages.properties
String message() default "參數(shù)不符!";
// 必須的適用于分組校驗(yàn)
Class<?>[] groups() default {};
// 必須的
Class<? extends Payload>[] payload() default {};
// 這個(gè)是我們自己定義是否為必須的參數(shù),默認(rèn)為不必須
boolean required() default false;
// 這個(gè)是我們自己定義的最小值,默認(rèn)為 0
int min() default 0;
// 這個(gè)是我們自己定義的最大值,默認(rèn)為 2147483647 Integer.MAX_VALUE = 2147483647 Integer.MIN_VALUE = -2147483648
int max() default Integer.MAX_VALUE;
}
定義校驗(yàn)器支持的類型 這里我們就寫(xiě)三種類型Long ,F(xiàn)loat ,Integer 。需要其他的自己擴(kuò)展
Float 校驗(yàn)器
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* @Description 參數(shù)校驗(yàn)器 Float 類型
* @Author 張凱強(qiáng)
* @Date Created in 2021/5/20
* @E-mail 862166318@qq.com
*/
public class ZkqNumRangeConstraintValidatorFloat implements ConstraintValidator<ZkqNumRange, Float> {
private Integer max;
private Integer min;
private boolean required;
@Override
public void initialize(ZkqNumRange constraintAnnotation) {
max = constraintAnnotation.max();
min = constraintAnnotation.min();
required = constraintAnnotation.required();
}
@Override
public boolean isValid(Float value, ConstraintValidatorContext context) {
if(required || value!=null) {
if(value==null)
return false;
if ((min <= value) && (value<= max)) {
return true;
}
return false;
}
return true;
}
}
Integer 校驗(yàn)器
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* @Description 參數(shù)校驗(yàn)器 Integer 類型
* @Author 張凱強(qiáng)
* @Date Created in 2021/5/20
* @E-mail 862166318@qq.com
*/
public class ZkqNumRangeConstraintValidatorInteger implements ConstraintValidator<ZkqNumRange, Integer> {
private Integer max;
private Integer min;
private boolean required;
@Override
public void initialize(ZkqNumRange constraintAnnotation) {
max = constraintAnnotation.max();
min = constraintAnnotation.min();
required = constraintAnnotation.required();
}
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
if(required || value!=null) {
if(value==null)
return false;
if ((min <= value) && (value<= max)) {
return true;
}
return false;
}
return true;
}
}
Long 校驗(yàn)器
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* @Description 參數(shù)校驗(yàn)器 Long 類型
* @Author 張凱強(qiáng)
* @Date Created in 2021/5/20
* @E-mail 862166318@qq.com
*/
public class ZkqNumRangeConstraintValidatorLong implements ConstraintValidator<ZkqNumRange, Long> {
private Integer max;
private Integer min;
private boolean required;
@Override
public void initialize(ZkqNumRange constraintAnnotation) {
max = constraintAnnotation.max();
min = constraintAnnotation.min();
required = constraintAnnotation.required();
}
@Override
public boolean isValid(Long value, ConstraintValidatorContext context) {
if(required || value!=null) {
if(value==null)
return false;
if ((min <= value) && (value<= max)) {
return true;
}
return false;
}
return true;
}
}
測(cè)試對(duì)象User3
import lombok.Data;
/**
* @Description 自定義校驗(yàn)器 校驗(yàn)
* @Author 張凱強(qiáng)
* @Date Created in 2021/5/20
* @E-mail 862166318@qq.com
*/
@Data
public class User3 {
// required 默認(rèn)為不必須
@ZkqNumRange(message = "id不正確!")
private Long id;
@ZkqNumRange(message = "錢數(shù)不正確!", required = true)
private Float money;
// 最大值為150
@ZkqNumRange(max = 150, message = "年齡不正確!", required = true)
private Integer age;
}
測(cè)試接口
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
@RestController
public class ZkqController{
// 測(cè)試 自定義校驗(yàn)器 @ZkqNumRange
@GetMapping("/zkq3")
public R zkq2(@Valid User3 user){
return R.ok().msg("自定義校驗(yàn)器校驗(yàn)").data("user",user);
}
}
不符合規(guī)范


符合校驗(yàn)

4. 自帶校驗(yàn)注解
我把截圖放這,想看的自行研究。


也可以自行閱讀校驗(yàn)器源碼,例如 @NotNull 和 @NotBlank 區(qū)別了
@NotBlank 做了toString(),然后去空格后的長(zhǎng)度大于0。

@NotNull 就做了 object != null

有問(wèn)題質(zhì)詢QQ:248048521,歡迎技術(shù)交流
浙公網(wǎng)安備 33010602011771號(hào)