Spring Boot (31) 數據驗證

曾經參數的驗證是這樣的:java

    public String test(User user){
        if(user == null){
            throw new NullPointerException("user 不能爲空");
        }

        if(user.getUserName() == null){
            throw new NullPointerException("userName 不能爲空");
        }

        if(user.getUserName().length() < 4 || user.getUserName().length()>10){
            throw new RuntimeException("userName 長度小於4位或大於10位");
        }

        return "success";
    }

隨着參數的增長,格式的變化,校驗數據有效性的代碼愈發繁瑣。git

 

經過Spring boot來完成參數數據校驗。web

JSR-303註解介紹正則表達式

這裏只列舉了javax.validation包下的註解,同理在spring-boot-starter-web包種也存在hibernate-validator驗證包,裏面包含了一些javax.validation沒有的註解。spring

註解 說明
@NotNull 限制必須不爲null
@NotEmpty 驗證註解的元素值不爲 null 且不爲空(字符串長度不爲0、集合大小不爲0)
@NotBlank 驗證註解的元素值不爲空(不爲null、去除首位空格後長度爲0),不一樣於@NotEmpty,@NotBlank只應用於字符串且在比較時會去除字符串的空格
@Pattern(value) 限制必須符合指定的正則表達式
@Size(max,min) 限制字符長度必須在 min 到 max 之間(也能夠用在集合上)
@Email 驗證註解的元素值是Email,也能夠經過正則表達式和flag指定自定義的email格式
@Max(value) 限制必須爲一個不大於指定值的數字
@Min(value) 限制必須爲一個不小於指定值的數字
@DecimalMax(value) 限制必須爲一個不大於指定值的數字
@DecimalMin(value) 限制必須爲一個不小於指定值的數字
@Null 限制只能爲null(不多用)
@AssertFalse 限制必須爲false (不多用)
@AssertTrue 限制必須爲true (不多用)
@Past 限制必須是一個過去的日期
@Future 限制必須是一個未來的日期
@Digits(integer,fraction) 限制必須爲一個小數,且整數部分的位數不能超過 integer,小數部分的位數不能超過 fraction (不多用)

 

實體類瀏覽器

public class Book implements Serializable {

    private Integer id;

    @NotBlank(message = "name 不能爲空")
    @Length(min = 2, max = 10, message = "name 長度必須在{min}-{max}之間")
    private String name;

    @NotNull(message = "price 不能爲空")
    @DecimalMin(value = "0.1", message = "價格不能低於 {value}")
    private BigDecimal price;

    ...
}

 

控制層app

這些驗證註解不單單能夠放在controller上,也能夠加在service層上。ide

//todo 開啓數據有效性校驗,添加在類上即爲驗證方法,添加在方法參數中即爲驗證參數對象。(添加在方法上無效)
@Validated
@RequestMapping("/books")
@RestController
public class BookController { @GetMapping("/test1") public String test1(@NotBlank(message = "name不能爲空") @Length(min = 2, max = 10 , message="name 長度必須在{min}-{max}之間") String name){ return "test1"; } @GetMapping("test2") public String test2(@Validated Book book){ return "test2"; } }

這樣就能夠了,在瀏覽器中輸入 /books/test1/ 不輸入參數會拋異常 /books/test1?name=sdf 則能夠經過驗證spring-boot

/books/test2/ 異常 /books/test2?name=sdf&price=0.5就ok了測試

 

Spring Boot 還容許咱們自定義Validatior

自定義註解

package com.spring.boot.utils;


import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//@Target定義範圍 在字段 參數上使用
@Target({ElementType.FIELD, ElementType.PARAMETER})
//定義可見範圍 RUNTIME整個運行階段均可見
@Retention(RetentionPolicy.RUNTIME)
//Constraint指定具體校驗器類
@Constraint(validatedBy = DateTimeValidator.class)
//@interface 定義註解
public @interface DateTime {
    String message() default "格式錯誤";

    String format() default "yyyy-MM-dd";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

具體的校驗器

package com.spring.boot.utils;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.text.ParseException;
import java.text.SimpleDateFormat;

/**
 * 日期格式驗證
 */
public class DateTimeValidator implements ConstraintValidator<DateTime, String> {

    private DateTime dateTime;

    @Override
    //初始化,它能夠得到當前註解的全部屬性
    public void initialize(DateTime constraintAnnotation) {
        this.dateTime = constraintAnnotation;
    }

    @Override
    //約束驗證的主體方法,其中s就是驗證參數的具體事例,context表明約束執行的上下文
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        //若是爲空不用驗證, 爲空驗證能夠用@NotBlank、@NotNull等參數進行控制
        if (s == null) {
            return true;
        }

        String format = dateTime.format();
        if (s.length() != format.length()) {
            return false;
        }

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        try {
            simpleDateFormat.parse(s);
        } catch (ParseException e) {
            return false;
        }
        return true;
    }
}

而後在控制層使用他

    @GetMapping("/test3")
    public String test3(@NotBlank(message = "date 不能爲空") @DateTime(message = "您如的格式錯誤,正確的格式爲:{format}",format = "yyyy-MM-dd HH:mm") String date){
        return "test3";
    }

測試

 

分組驗證

  有時候咱們須要對一個實體類有多種驗證方式,在不一樣的狀況下使用不一樣的驗證方式,好比id,新增的時候是不須要的,更新時是必須的。

定義一個驗證組,裏面寫上不一樣的空接口類便可

public class Groups {
    public interface Update{

    }

    public interface Default{
        
    }
}

實體類

  groups屬性的做用就讓@Validated註解只驗證與自身value屬性想匹配的字段,可多個,只要知足就會去歸入驗證範圍。

public class Book {

    @NotNull(message = "id 不能爲空" , groups = Groups.Update.class)
    private Integer id;

    @NotBlank(message = "name 不能爲空" , groups = Groups.Default.class)
    private String name;

    @NotNull(message = "price 不能爲空" , groups = Groups.Default.class)
    private BigDecimal price;

控制層

  建立一個ValidateControoler類,而後定義好insert、update兩個方法,因爲insert方法並不關心id字段,因此這裏的@Validate的value屬性寫成Groups.Default.class就能夠了,而update方法須要Id,因此此處@Validated註解的value屬性值就要寫成Groups.Default.class,Groups.Update.Class。表明只要是這分組下的數據都須要進行數據有效性校驗操做

@RestController
public class ValidateController {
    //default中沒有id
    @GetMapping("/insert")
    public String insert(@Validated(value=Groups.Default.class) Book book){
        return "insert";
    }

    //update中有id校驗
    @GetMapping("update")
    public String update(@Validated(value={Groups.Default.class,Groups.Update.class}) Book book){
        return "update";
    }

}

 

相關文章
相關標籤/搜索