Spring?Validation實(shí)現(xiàn)數(shù)據(jù)校驗(yàn)的示例
一、什么是 Spring Validation
在開發(fā)中,我們經(jīng)常遇到參數(shù)校驗(yàn)的需求,比如用戶注冊的時(shí)候,要校驗(yàn)用戶名不能為空、用戶名長度不超過20個(gè)字符、手機(jī)號是合法的手機(jī)號格式等等。
如果使用普通方式,我們會把校驗(yàn)的代碼和真正的業(yè)務(wù)處理邏輯耦合在一起,而且如果未來要新增一種校驗(yàn)邏輯也需要在修改多個(gè)地方。
而spring validation允許通過注解的方式來定義對象校驗(yàn)規(guī)則,把校驗(yàn)和業(yè)務(wù)邏輯分離開,讓代碼編寫更加方便。
Spring Validation其實(shí)就是對Hibernate Validator進(jìn)一步的封裝,方便在Spring中使用。
Spring提供了數(shù)種數(shù)據(jù)校驗(yàn)的方式:
- 實(shí)現(xiàn)org.springframework.validation.Validator接口,調(diào)用接口實(shí)現(xiàn)類;
- 通過 注解 方式進(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>注意:上述依賴還不夠,請記得添加spring的基礎(chǔ)依賴和Junit測試等依賴
?Validator接口方式
這是一個(gè)用于測試校驗(yàn)的實(shí)體類:
/**
* @author .29.
* @create 2023-03-01 10:58
*/
//創(chuàng)建實(shí)體類,定義屬性及方法,供校驗(yàn)測試
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); //比對實(shí)體類的類對象與參數(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");
//傳入對象,強(qiáng)轉(zhuǎn)為實(shí)體類Person對象
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)測試:
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對象的DataBinder
DataBinder binder = new DataBinder(person);
//設(shè)置校驗(yàn)
binder.setValidator(new PersonValidator());
//校驗(yàn)(當(dāng)person屬性值為空時(shí),校驗(yàn)不通過)
binder.validate();
//輸出校驗(yàn)結(jié)果
//binder.getBindingResult() 獲取校驗(yàn)結(jié)果對象
//bindingResult.getAllErrors() 獲取所有校驗(yàn)到的錯(cuò)誤
BindingResult bindingResult = binder.getBindingResult();
System.out.println(bindingResult.getAllErrors());
}
}沒有傳入?yún)?shù)時(shí),對象為空,得到 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è)用于測試校驗(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 只作用于字符串類型,字符串不為空,并且長度不為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) 限制字符長度必須在min到max之間
- @Email 驗(yàn)證注解的元素值是Email,也可以通過正則表達(dá)式和flag指定自定義的email格式
接下來設(shè)置校驗(yàn)器(兩種方式):
方式一:使用java原生的jakarta.validation.Validator校驗(yàn)
校驗(yàn)器一號:
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對象
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)器一號:
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)建測試類,分別測試兩種校驗(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對象
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);
//校驗(yàn)器的實(shí)現(xiàn)類對象
MyService1 myValidatorOne = context.getBean(MyService1.class);
User user = new User();
boolean validator = myValidatorOne.validator(user);
System.out.println(validator);
}
@Test
public void testValidatorTwo(){
//獲取context對象
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(ValidationConfig.class);
//校驗(yàn)器的實(shí)現(xiàn)類對象
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è)測試校驗(yàn)的實(shí)體類,校驗(yàn)規(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ī)號格式 1開頭 第二位是(3、4、6、7、9)其一,后面是9位數(shù)字
@Pattern(regexp = "^1(3|4|6|7|9)\\d{9}$",message = "手機(jī)號碼格式錯(cuò)誤")
@NotBlank(message = "手機(jī)號碼不能為空")
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類,通過注解操作對象
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類,通過注解操作對象
public String testParams(@NotNull @Valid User user){
return user.toString();
}
}測試:
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è)置提示語
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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java實(shí)現(xiàn)字符串四則運(yùn)算公式解析工具類的方法
今天小編就為大家分享一篇java實(shí)現(xiàn)字符串四則運(yùn)算公式解析工具類的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07
詳解如何把Java中if-else代碼重構(gòu)成高質(zhì)量代碼
這篇文章主要介紹了詳解如何把Java中if-else代碼重構(gòu)成高質(zhì)量代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
高并發(fā)環(huán)境下安全修改同一行數(shù)據(jù)庫數(shù)據(jù)的策略分享
隨著互聯(lián)網(wǎng)技術(shù)的發(fā)展,越來越多的應(yīng)用需要在高并發(fā)環(huán)境中運(yùn)行,數(shù)據(jù)庫的并發(fā)控制成為了業(yè)務(wù)的關(guān)鍵,本文將介紹如何在高并發(fā)情況下,安全地修改數(shù)據(jù)庫中的同一行數(shù)據(jù),需要的可以參考一下2023-06-06

