数据验证-Java和Spring验证

在Java中验证类数据(bean)并不是一个新话题,但它在这里也很重要,我将结合各个方面:在JSR-303中进行数据验证,我将展示如何仅在Java和Spring中执行此操作,以及如何在标准应用程序和Web上执行此操作。

内容:中的数据验证(JSR-303)

  • 标准的Java应用程序
  • 使用Spring
  • Java +春季协会
  • 春季MVC

在标准Java应用程序中进行验证


为了检查对象,使用在类的字段上的注释,即 声明模型。 注释已经准备就绪:
Null ,@DecimalMin,@Digits, PatternEmail
,您也可以自己制作。 所以有一个类(bean)

import javax.validation.constraints.Digits; import javax.validation.constraints.Size; public class Person { @Size(min=2, max=50) private String Name; @Digits(integer=3, fraction=0, message = "  3- ") @PersonAgeConstraint private Integer age; public Person(String name, Integer age) { Name = name; this.age = age; } } 

在此示例中, Size和@Digits准备好注解,以及@PersonAgeConstraint自己。 如何制作自己的:

-准备注释

 @Target({ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy=PersonAgeConstraintValidator.class) public @interface PersonAgeConstraint { String message() default "{value.negative}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; } 

在消息()中,从消息的资源文件(ValidationMessages.properties)中指定键(value.negative)
value.negative =负值
类的设计和实现-PersonAgeConstraintValidator.class

 public class PersonAgeConstraintValidator implements ConstraintValidator<PersonAgeConstraint, Integer> { @Override public boolean isValid(Integer age, ConstraintValidatorContext constraintValidatorContext) { return age > 0; } } 

我自己的注释已准备就绪,我们将其添加到字段中,并且已经可以进行检查,所有带有注释的字段将通过相应的规则进行检查。

 import javax.validation.Validator; /** * Test Validation */ public class DemoJValidationApplicationTests { //  Validator private static Validator validator; static { ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); validator = validatorFactory.usingContext().getValidator(); } @Test public void testValidators() { final Person person = new Person(" ", -4500); Set<ConstraintViolation<Person>> validates = validator.validate(person); Assert.assertTrue(validates.size() > 0); validates.stream().map(v -> v.getMessage()) .forEach(System.out::println); } } 

控制台结果

3-



通常,可以在消息文件中指定标准注释的消息:

AnnotationName.entity.fieldname=

项目结构

图片

pom文件
 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>DemoJSRvalidation</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>DemoJSRvalidation</name> <description>Demo project for Spring Boot JSR-303 validation</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 


分阶段验证。 对于Class <?> [] Groups(),您可以指定可以对它们进行分组的类的类型,限制检查的列表,即 用作过滤器。 因此,可以分阶段进行验证:1)例如,出于健康原因,我们将对某人的检查分为两部分,然后是专业数据。 我们将准备两个注释
HealthConstraint和ProfessionalConstraint及其实现。 首先,我们检查对健康的依从性,然后通过健康检查专业数据。

一个例子:

 public class Person { @HealthConstraint(groups = Health.class) private Documents healthDocuments; @ProfessionalConstraint(groups = Professional.class) private Documents ProfessionalDocuments; //... } 

HealthConstraint注释示例

 @Target({ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy=HealthConstraintValidator.class) public @interface HealthConstraint { String message() default "{health.documents}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; } 

HealthConstraintValidator实现示例

 public class HealthConstraintValidator implements ConstraintValidator<HealthConstraint, Documents> { @Override public boolean isValid(Documents documents, ConstraintValidatorContext constraintValidatorContext) { return documents.contains(" 1"); } } 

对于ProfessionalConstraint,一切都一样

下一步检查像这样:

  @Test public void healthAndProfessionalValidators() { final Person person = new Person(" ", 45); person.setHealthDocuments(new Documents(Arrays.asList(" 1", " 3"))); person.setProfessionalDocuments(new Documents(Arrays.asList(" 1", " 4"))); //    Set<ConstraintViolation<Person>> validates = validator.validate(person, Health.class); Assert.assertTrue(validates.size() == 0); //    ,  .  validates = validator.validate(person, Professional.class); Assert.assertTrue(validates.size() == 0); } 

例如,当我们从文件,Web服务和其他来源加载数据时,需要进行此类检查。

课程文件
 public class Documents { private List<String> tests = new ArrayList(); public Documents(List<String> tests) { this.tests.addAll(tests); } public boolean contains(String test) { return this.tests.contains(test); } } 


使用Spring验证


Spring还具有自己的Validator接口。
(org.springframework.validation.Validator)
如在Java中
(javax.validation.Validator)
而正是它的实现验证了数据。 这不再是一种声明式方法,而是具有自己的灵活性和可扩展性。 对于同一个垃圾箱,我将进行相同的年龄检查。

通过覆盖这两种方法,我们验证了

 @Service public class PersonValidator implements Validator { @Override public boolean supports(Class<?> aClass) { return Person.class.equals(aClass); } @Override public void validate(Object obj, Errors errors) { Person p = (Person) obj; if (p.getAge() < 0) { errors.rejectValue("age", "value.negative"); } } } 

value.negative-也是消息文件中的键, public boolean supports决定了所支持类的类型。

通过DataBinder启动验证

一个例子:

 @RunWith(SpringRunner.class) @SpringBootTest public class DemoJValidationApplicationTests { //    private static final ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); static { messageSource.setBasename("message"); } @Autowired private PersonValidator personValidator; @Test public void testValidators() { final Person person = new Person(" ", -4500); final DataBinder dataBinder = new DataBinder(person); dataBinder.addValidators(personValidator); dataBinder.validate(); Assert.assertTrue(dataBinder.getBindingResult().hasErrors()); if (dataBinder.getBindingResult().hasErrors()) { dataBinder.getBindingResult().getAllErrors().stream(). forEach(e -> System.out.println(messageSource .getMessage(e, Locale.getDefault()))); } } } 

将执行为Person类实现org.springframework.validation.Validator的所有检查。

您还可以添加几个验证器dataBinder.addValidators,可以组成规则的组合(从一个规则调用,从另一个规则调用),例如:

 public class OtherValidator implements Validator { @Override public boolean supports(Class<?> aClass) { return Person.class.equals(aClass); } @Override public void validate(Object obj, Errors errors) { // ... } } //--------- @Service public class PersonValidator implements Validator { /** *   */ @Autowired private OtherValidator otherValidator; @Override public void validate(Object obj, Errors errors) { Person p = (Person) obj; if (p.getAge() < 0) { errors.rejectValue("age", "value.negative"); } //   ,   otherValidator.validate(obj, errors); } } 

出于某种原因,我希望Spring也将执行注释中指示的检查,但是不,此调用必须独立完成。

项目结构

图片

pom文件
 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>DemoJSRvalidation</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>DemoJSRvalidation</name> <description>Demo project for Spring Boot JSR-303 validation</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 


Java和Spring


显然,我想在数据验证中使用两种方法-Java和Spring,您可以将它们组合在一起,即将javax.validation.Validator调用添加到Spring validateator。

例子

 import javax.validation.Validator; @Service public class PersonValidator implements org.springframework.validation.Validator { // javax.validation.Validator @Autowired private Validator validator; @Override public boolean supports(Class<?> aClass) { return Person.class.equals(aClass); } @Override public void validate(Object obj, Errors errors) { Set<ConstraintViolation<Object>> validates = validator.validate(obj); for (ConstraintViolation<Object> constraintViolation : validates) { String propertyPath = constraintViolation.getPropertyPath().toString(); String message = constraintViolation.getMessage(); errors.rejectValue(propertyPath, "", message); } Person p = (Person) obj; if (p.getAge() < 0) { errors.rejectValue("age", "only.positive.numbers"); } } } 

使用spring,我们进行注入javax.validation.Validator

@Autowired
private Validator validator;


进一步关于方法public void validate(Object obj, Errors errors)
在Java上执行声明性检查,然后在spring org.springframework.validation.Validator上对Person类执行所有检查。

我们还在春季进行验证

  @Test public void testValidators() { final Person person = new Person("", -4500); final DataBinder dataBinder = new DataBinder(person); dataBinder.addValidators(personValidator); dataBinder.validate(); if (dataBinder.getBindingResult().hasErrors()) { dataBinder.getBindingResult().getAllErrors() // .... 

现在,在集合中将检查Person的java和spring批注(org.springframework.validation.Validator)

控制台输出

()
3- ()
(spring)


项目结构

图片

春季MVC


当然,现在所有这些都可以在Web应用程序中应用。

我们将Controller,jsp页面添加到项目中(顺便说一下,这里可能还有其他选项,例如,使用freeMarker生成页面等),css样式,pom依赖项。 因此,为了

1)MVC控制器

 import org.springframework.validation.Validator; @Controller public class DemoJValidationController { @Autowired @Qualifier("personValidator") // spring validator private Validator personValidator; @InitBinder protected void initBinder(WebDataBinder binder) { binder.setValidator(personValidator); } @GetMapping("/") public String savePersonAction(ModelMap model) { model.addAttribute("person", new Person(null, null)); return "personEdit"; } @RequestMapping(value = "/save", method = RequestMethod.POST) public String savePersonAction( @Valid @ModelAttribute("person") Person person, BindingResult bindingResult, Model model) { if (bindingResult.hasErrors()) { return "personEdit"; // to person.jsp page } model.addAttribute("name", person.getName()); model.addAttribute("age", person.getAge()); return "saveSuccess"; // to saveSuccess.jsp page } @RequestMapping(value = "/edit", method = RequestMethod.POST) public String editPersonAction(ModelMap model) { model.addAttribute("person", new Person(null, null)); return "personEdit"; // to personEdit.jsp page; } } 

在这里与弹簧注入连接的PersonValidator

@Autowired
@Qualifier("personValidator") // spring validator
private Validator personValidator;


将PersonValidator设置为initBinder

@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(personValidator);
}


@Valid批注触发验证
在这种情况下,将仅执行弹簧检查,而声明式检查将被忽略。

如果从代码中删除

@InitBinder
protected void initBinder(WebDataBinder binder)


相反,将执行所有声明性检查,而spring将被忽略。
要完成所有声明式和弹簧式检查,您可以执行以下操作:

删除@InitBinder,保留注入

@Autowired
@Qualifier("personValidator") // spring validator
private Validator personValidator;


并手动添加弹簧检查电话

// spring validate
personValidator.validate(person, bindingResult);


这是代码:

 @Controller public class DemoJValidationController { @Autowired @Qualifier("personValidator") // spring validator private Validator personValidator; //... @RequestMapping(value = "/save", method = RequestMethod.POST) public String savePersonAction( @Valid @ModelAttribute("person") Person person, BindingResult bindingResult, Model model) { // spring validate personValidator.validate(person, bindingResult); if (bindingResult.hasErrors()) { return "personEdit"; // to person.jsp page } model.addAttribute("name", person.getName()); model.addAttribute("age", person.getAge()); return "saveSuccess"; // to saveSuccess.jsp page } } 

即 春季的其他检查将添加到bindingResult :-)中,这就是我想要的!

jsp和模型中的数据绑定由属性modelAttribute="person" 。在示例中,连接了SpringMVC的Form Tag Library。

该示例的其余资源为:

DemoJValidationApplication
 @SpringBootApplication @ImportResource("classpath:configuration.xml") public class DemoJValidationApplication { public static void main(String[] args) { SpringApplication.run(DemoJValidationApplication.class, args); } } 


弹簧配置
configuration.xml
 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/c" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="classpath:message"/> <property name="defaultEncoding" value="UTF-8"/> </bean> <mvc:annotation-driven/> <mvc:resources mapping="/resources/**" location="classpath:/META-INF/resources/"/> </beans> 


personEdit.jsp
 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <link href="<c:url value="/resources/my.css" />" rel="stylesheet"> <title>Person</title> </head> <body> <h3> Enter Person. </h3> <form:form method="POST" modelAttribute="person" action="save"> <div> Name: <form:input path="name"/> <form:errors path="name" cssClass="error"/> </div> <div> Age: <form:input path="age"/> <form:errors path="age" cssClass="error"/> </div> <button type="submit">Registration</button> </form:form> </body> </html> 


saveSuccess.jsp
 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <link href="<c:url value="/resources/my.css" />" rel="stylesheet"> <title>Person Saved Successfully</title> </head> <body> <h3> Person Saved Successfully. </h3> <form:form method="POST" modelAttribute="person" action="edit"> <div> ${name} </div> <div> ${age} </div> <button type="submit">Edit</button> </form:form> </body> </html> 


my.css
 span.error { color: red; } form div{ margin: 5px; } 


pom文件
 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>DemoJSRvalidation</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>DemoJSRvalidation</name> <description>Demo project for Spring Boot JSR-303 validation</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>4.1.0.Final</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 


项目结构

图片

申请工作

图片

用料

Bean验证规范

Source: https://habr.com/ru/post/zh-CN424819/


All Articles