Spring?Validation實(shí)現(xiàn)數(shù)據(jù)校驗(yàn)的示例
一、什么是 Spring Validation
在開發(fā)中,我們經(jīng)常遇到參數(shù)校驗(yàn)的需求,比如用戶注冊(cè)的時(shí)候,要校驗(yàn)用戶名不能為空、用戶名長(zhǎng)度不超過(guò)20個(gè)字符、手機(jī)號(hào)是合法的手機(jī)號(hào)格式等等。
如果使用普通方式,我們會(huì)把校驗(yàn)的代碼和真正的業(yè)務(wù)處理邏輯耦合在一起,而且如果未來(lái)要新增一種校驗(yàn)邏輯也需要在修改多個(gè)地方。
而spring validation允許通過(guò)注解的方式來(lái)定義對(duì)象校驗(yàn)規(guī)則,把校驗(yàn)和業(yè)務(wù)邏輯分離開,讓代碼編寫更加方便。
Spring Validation其實(shí)就是對(duì)Hibernate Validator進(jìn)一步的封裝,方便在Spring中使用。
Spring提供了數(shù)種數(shù)據(jù)校驗(yàn)的方式:
- 實(shí)現(xiàn)org.springframework.validation.Validator接口,調(diào)用接口實(shí)現(xiàn)類;
- 通過(guò) 注解 方式進(jìn)行數(shù)據(jù)校驗(yàn)(按照Bean Validation方式);
- 基于 方法(函數(shù)) 實(shí)現(xiàn)數(shù)據(jù)校驗(yàn);
- 自定義校驗(yàn)
二、實(shí)現(xiàn)數(shù)據(jù)校驗(yàn)
??準(zhǔn)備相關(guān)jar包
引入Maven依賴:
<dependencies>
<!-- validator校驗(yàn)相關(guān)依賴 -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>7.0.5.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>4.0.1</version>
</dependency>
</dependencies>注意:上述依賴還不夠,請(qǐng)記得添加spring的基礎(chǔ)依賴和Junit測(cè)試等依賴
?Validator接口方式
這是一個(gè)用于測(cè)試校驗(yàn)的實(shí)體類:
/**
* @author .29.
* @create 2023-03-01 10:58
*/
//創(chuàng)建實(shí)體類,定義屬性及方法,供校驗(yàn)測(cè)試
public class Person {
private String name;
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}這是一個(gè)實(shí)現(xiàn)了Validator接口的實(shí)體類:
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
/**
* @author .29.
* @create 2023-03-01 11:00
*/
//validator接口方式實(shí)現(xiàn) 校驗(yàn)
public class PersonValidator implements Validator {
@Override
public boolean supports(Class<?> aClass) {
return Person.class.equals(aClass); //比對(duì)實(shí)體類的類對(duì)象與參數(shù)是否一致
}
@Override
public void validate(Object o, Errors errors) { //重寫校驗(yàn)方法
//設(shè)置name為空時(shí),報(bào)錯(cuò):name.empty
ValidationUtils.rejectIfEmpty(errors,"name","name.empty");
//傳入對(duì)象,強(qiáng)轉(zhuǎn)為實(shí)體類Person對(duì)象
Person p = (Person)o;
if(p.getAge() < 0){ //設(shè)置age屬性小于零時(shí)報(bào)錯(cuò)
errors.rejectValue("age","error (age < 0)");
}else if(p.getAge() > 110){//設(shè)置age屬性大于110報(bào)錯(cuò)
errors.rejectValue("age","error (age > 110) too old !!");
}
}
}校驗(yàn)測(cè)試:
import org.springframework.validation.BindingResult;
import org.springframework.validation.DataBinder;
/**
* @author .29.
* @create 2023-03-01 11:21
*/
public class testPersonValidator {
public static void main(String[] args){
Person person = new Person();
// person.setName("高啟強(qiáng)");
// person.setAge(29);
//創(chuàng)建person對(duì)象的DataBinder
DataBinder binder = new DataBinder(person);
//設(shè)置校驗(yàn)
binder.setValidator(new PersonValidator());
//校驗(yàn)(當(dāng)person屬性值為空時(shí),校驗(yàn)不通過(guò))
binder.validate();
//輸出校驗(yàn)結(jié)果
//binder.getBindingResult() 獲取校驗(yàn)結(jié)果對(duì)象
//bindingResult.getAllErrors() 獲取所有校驗(yàn)到的錯(cuò)誤
BindingResult bindingResult = binder.getBindingResult();
System.out.println(bindingResult.getAllErrors());
}
}沒有傳入?yún)?shù)時(shí),對(duì)象為空,得到 name.empty 的校驗(yàn)錯(cuò)誤:
[Field error in object ‘target’ on field ‘name’: rejected value [null]; codes [name.empty.target.name,name.empty.name,name.empty.java.lang.String,name.empty]; arguments []; default message [null]]
傳入正確參數(shù)后,沒有校驗(yàn)錯(cuò)誤可輸出:
[]
?基于注解方式(Bean Validation)
使用Bean Validation校驗(yàn)方式,就是如何將Bean Validation需要使用的javax.validation.ValidatorFactory 和javax.validation.Validator注入到容器中。spring默認(rèn)有一個(gè)實(shí)現(xiàn)類LocalValidatorFactoryBean,它實(shí)現(xiàn)了上面Bean Validation中的接口,并且也實(shí)現(xiàn)了org.springframework.validation.Validator接口。
這是一個(gè)配置了配置LocalValidatorFactoryBean的配置類:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
/**
* @author .29.
* @create 2023-03-01 11:34
*/
//配置類
@Configuration //聲明為Spring配置類
@ComponentScan("com.haojin.spring.config") //設(shè)置需要掃描的包
public class ValidationConfig {
@Bean //返回值放入ioc容器
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
}這是一個(gè)用于測(cè)試校驗(yàn)的實(shí)體類:
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
/**
* @author .29.
* @create 2023-03-01 11:36
*/
//實(shí)體類,使用注解定義校驗(yàn)規(guī)則
public class User {
@NotNull //不可為空
private String name;
@Min(0) //最小值
@Max(110) //最大值
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
這里總結(jié)一下常見的注解:
- @NotNull 限制必須不為null
- @NotEmpty 只作用于字符串類型,字符串不為空,并且長(zhǎng)度不為0
- @NotBlank 只作用于字符串類型,字符串不為空,并且trim()后不為空串
- @DecimalMax(value) 限制必須為一個(gè)不大于指定值的數(shù)字
- @DecimalMin(value) 限制必須為一個(gè)不小于指定值的數(shù)字
- @Max(value) 限制必須為一個(gè)不大于指定值的數(shù)字
- @Min(value) 限制必須為一個(gè)不小于指定值的數(shù)字
- @Pattern(value) 限制必須符合指定的正則表達(dá)式
- @Size(max,min) 限制字符長(zhǎng)度必須在min到max之間
- @Email 驗(yàn)證注解的元素值是Email,也可以通過(guò)正則表達(dá)式和flag指定自定義的email格式
接下來(lái)設(shè)置校驗(yàn)器(兩種方式):
方式一:使用java原生的jakarta.validation.Validator校驗(yàn)
校驗(yàn)器一號(hào):
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Set;
/**
* @author .29.
* @create 2023-03-01 11:39
*/
//使用java原生的jakarta.validation.Validator校驗(yàn)
@Service
public class MyService1 {
@Autowired //自動(dòng)裝配Validator對(duì)象
private Validator validator;
//校驗(yàn)方法
public boolean validator(User user){
//校驗(yàn)后的結(jié)果存放進(jìn)Set集合
Set<ConstraintViolation<User>> set = validator.validate(user);
//若沒有校驗(yàn)到錯(cuò)誤,集合為空,返回true。
return set.isEmpty();
}
}方式二:用spring提供的validator校驗(yàn)
校驗(yàn)器一號(hào):
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.BindException;
import org.springframework.validation.Validator;
/**
* @author .29.
* @create 2023-03-02 9:24
*/
//使用spring提供的validate校驗(yàn)方法
@Service
public class MyService2 {
@Autowired
private Validator validator;
public boolean validator2(User user){
BindException bindException = new BindException(user,user.getName());
validator.validate(user,bindException); //調(diào)用校驗(yàn)方法進(jìn)行校驗(yàn)
System.out.println(bindException.getAllErrors()); //輸出所有錯(cuò)誤信息
return bindException.hasErrors(); //若沒有異常,返回false
}
}
創(chuàng)建測(cè)試類,分別測(cè)試兩種校驗(yàn)器:
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author .29.
* @create 2023-03-02 9:33
*/
public class testBeanValidator {
@Test
public void testValidatorOne(){
//獲取context對(duì)象
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);
//校驗(yàn)器的實(shí)現(xiàn)類對(duì)象
MyService1 myValidatorOne = context.getBean(MyService1.class);
User user = new User();
boolean validator = myValidatorOne.validator(user);
System.out.println(validator);
}
@Test
public void testValidatorTwo(){
//獲取context對(duì)象
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(ValidationConfig.class);
//校驗(yàn)器的實(shí)現(xiàn)類對(duì)象
MyService2 myValidatorTwo = annotationConfigApplicationContext.getBean(MyService2.class);
User user = new User();
boolean validator = myValidatorTwo.validator2(user);
System.out.println(validator);
}
}
?基于方法的方式
這是一個(gè)配置了MethodValidationPostProcessor的配置類:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
/**
* @author .29.
* @create 2023-03-02 18:28
*/
//配置了MethodValidationPostProcessor的配置類
@Configuration
@ComponentScan("com.haojin.spring.three")
public class validationPostProcessor {
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor(){
return new MethodValidationPostProcessor();
}
}
這是一個(gè)測(cè)試校驗(yàn)的實(shí)體類,校驗(yàn)規(guī)則通過(guò)注解設(shè)置
import jakarta.validation.constraints.*;
/**
* @author .29.
* @create 2023-03-02 18:30
*/
public class User {
@NotNull
private String name;
@Min(0)
@Max(129)
private int age;
//手機(jī)號(hào)格式 1開頭 第二位是(3、4、6、7、9)其一,后面是9位數(shù)字
@Pattern(regexp = "^1(3|4|6|7|9)\\d{9}$",message = "手機(jī)號(hào)碼格式錯(cuò)誤")
@NotBlank(message = "手機(jī)號(hào)碼不能為空")
private String phone;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", phone='" + phone + '\'' +
'}';
}
}
定義Service類,通過(guò)注解操作對(duì)象
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
/**
* @author .29.
* @create 2023-03-02 18:35
*/
@Service
@Validated
public class MyService { //定義Service類,通過(guò)注解操作對(duì)象
public String testParams(@NotNull @Valid User user){
return user.toString();
}
}測(cè)試:
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author .29.
* @create 2023-03-02 18:37
*/
public class TestMethod {
@Test
public void testMyService(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(validationPostProcessor.class);
MyService bean = context.getBean(MyService.class);
User user = new User();
bean.testParams(user);
}
}?自定義校驗(yàn)
自定義設(shè)置校驗(yàn)規(guī)則的注解:
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {CannotBlankValidator.class})
public @interface CannotBlank {
//默認(rèn)錯(cuò)誤消息
String message() default "不能包含空格";
//分組
Class<?>[] groups() default {};
//負(fù)載
Class<? extends Payload>[] payload() default {};
//指定多個(gè)時(shí)使用
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface List {
CannotBlank[] value();
}
}編寫校驗(yàn)類:
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class CannotBlankValidator implements ConstraintValidator<CannotBlank, String> {
@Override
public void initialize(CannotBlank constraintAnnotation) {
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
//null時(shí)不進(jìn)行校驗(yàn)
if (value != null && value.contains(" ")) {
//獲取默認(rèn)提示信息
String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate();
System.out.println("default message :" + defaultConstraintMessageTemplate);
//禁用默認(rèn)提示信息
context.disableDefaultConstraintViolation();
//設(shè)置提示語(yǔ)
context.buildConstraintViolationWithTemplate("can not contains blank").addConstraintViolation();
return false;
}
return true;
}
}到此這篇關(guān)于 Spring Validation 數(shù)據(jù)校驗(yàn)的文章就介紹到這了,更多相關(guān) Spring Validation 數(shù)據(jù)校驗(yàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringMVC中的DispatcherServlet初始化流程詳解
這篇文章主要介紹了SpringMVC中的DispatcherServlet初始化流程詳解,DispatcherServlet這個(gè)前端控制器是一個(gè)Servlet,所以生命周期和普通的Servlet是差不多的,在一個(gè)Servlet初始化的時(shí)候都會(huì)調(diào)用該Servlet的init()方法,需要的朋友可以參考下2023-12-12
SpringBoot啟動(dòng)security后如何關(guān)閉彈出的/login頁(yè)面
這篇文章主要介紹了SpringBoot啟動(dòng)security后如何關(guān)閉彈出的login頁(yè)面問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12
基于SpringBoot實(shí)現(xiàn)輕量級(jí)的動(dòng)態(tài)定時(shí)任務(wù)調(diào)度的方法
本文介紹了如何在SpringBoot框架中實(shí)現(xiàn)輕量級(jí)的動(dòng)態(tài)定時(shí)任務(wù)調(diào)度,通過(guò)將任務(wù)以類為基礎(chǔ)單位,并通過(guò)配置數(shù)據(jù)進(jìn)行任務(wù)讀取和反射生成任務(wù)對(duì)象,感興趣的朋友跟隨小編一起看看吧2024-11-11
圖文講解IDEA中根據(jù)數(shù)據(jù)庫(kù)自動(dòng)生成實(shí)體類
這篇文章主要以圖文講解IDEA中根據(jù)數(shù)據(jù)庫(kù)自動(dòng)生成實(shí)體類,本文主要以Mysql數(shù)據(jù)庫(kù)為例,應(yīng)該會(huì)對(duì)大家有所幫助,如果有錯(cuò)誤的地方,還望指正2023-03-03
本地啟動(dòng)RocketMQ未映射主機(jī)名產(chǎn)生的超時(shí)問(wèn)題最新解決方案
這篇文章主要介紹了本地啟動(dòng)RocketMQ未映射主機(jī)名產(chǎn)生的超時(shí)問(wèn)題,本文給大家分享最新解決方案,感興趣的朋友跟隨小編一起看看吧2024-02-02
Java類初始化和實(shí)例化中的2個(gè)“雷區(qū)”
這篇文章主要介紹了Java類初始化和實(shí)例化中的2個(gè)“雷區(qū)”,大家要注意,感興趣的小伙伴們可以參考一下2016-02-02
Maven倉(cāng)庫(kù)分類的優(yōu)先級(jí)
本文主要介紹了Maven倉(cāng)庫(kù)分類的優(yōu)先級(jí),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
JavaWeb項(xiàng)目Servlet無(wú)法訪問(wèn)問(wèn)題解決
這篇文章主要介紹了JavaWeb項(xiàng)目Servlet無(wú)法訪問(wèn)問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11
關(guān)于Java雙大括號(hào){{}}的具體使用
本文主要介紹了關(guān)于Java雙大括號(hào){{}}的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07

