A validação de dados de classe (bean) em java não é um tópico novo, mas também é relevante aqui e vou combinar vários aspectos: validação de dados no JSR-303, mostrarei como fazer isso puramente em Java e usando Spring, como em um aplicativo padrão e na Web.
Conteúdo: Validação de Dados (JSR-303) em
- aplicação java padrão
- usando o Spring
- Associação Java + Spring
- Spring mvc
Validação em um aplicativo Java padrão
Para verificar o objeto, são usadas anotações nos campos da classe, ou seja, modelo declarativo. As anotações já estão prontas:
Nulo , @DecimalMin, @Digits, Pattern , Email , etc.
, e você também pode fazer o seu próprio. E então há uma classe (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; } }
Aqui no exemplo, as anotações prontas
Size e @Digits e as próprias @PersonAgeConstraint. Como fazer o seu:
- preparar a anotação
@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 {}; }
Na mensagem (), especifique a chave (value.negative) do arquivo de recurso (ValidationMessages.properties) da mensagem
value.negative = Valor negativo
e implementação da classe de verificação - PersonAgeConstraintValidator.class
public class PersonAgeConstraintValidator implements ConstraintValidator<PersonAgeConstraint, Integer> { @Override public boolean isValid(Integer age, ConstraintValidatorContext constraintValidatorContext) { return age > 0; } }
Minha própria anotação está pronta, a adicionamos ao campo e já é possível verificar, todos os campos nos quais existem anotações serão verificados pelas regras correspondentes.
import javax.validation.Validator; public class DemoJValidationApplicationTests {
Resultado no console
3-
As mensagens para anotações padrão podem ser especificadas no arquivo de mensagens, como regra:
AnnotationName.entity.fieldname=
Estrutura do projeto

arquivo 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/> </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>
Verificação faseada. Para Grupos <?> [] Groups (), você pode especificar os tipos de classes pelos quais você pode agrupá-los, limitar a lista de verificações, ou seja, use como um filtro. Assim, a verificação pode ser feita em etapas, 1) Por exemplo, dividimos o exame de uma pessoa por motivos de saúde, 2) e depois dados profissionais. Vamos preparar duas anotações
HealthConstraint e ProfessionalConstraint e implementações para eles. Primeiro, verificamos a conformidade com a saúde e, em seguida, se passa pela saúde, verificamos os dados profissionais.
Um exemplo:
public class Person { @HealthConstraint(groups = Health.class) private Documents healthDocuments; @ProfessionalConstraint(groups = Professional.class) private Documents ProfessionalDocuments;
Exemplo de anotação 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 {}; }
Exemplo de implementação HealthConstraintValidator
public class HealthConstraintValidator implements ConstraintValidator<HealthConstraint, Documents> { @Override public boolean isValid(Documents documents, ConstraintValidatorContext constraintValidatorContext) { return documents.contains(" 1"); } }
para ProfessionalConstraint, tudo é igual
Em seguida, verifique assim:
@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")));
Tais verificações, por exemplo, são necessárias quando carregamos dados de um arquivo, serviço da web e outras fontes.
Documentos de classe 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); } }
Validação usando Spring
O Spring também possui sua própria interface Validator.
(org.springframework.validation.Validator)
como em java
(javax.validation.Validator)
e é precisamente sua implementação que valida os dados. Isso não é mais uma abordagem declarativa, mas tem sua própria flexibilidade e extensibilidade. Na mesma lixeira, faço a mesma verificação de idade.
Substituindo os dois métodos, validamos
@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 - também é a chave no arquivo de mensagens,
public boolean supports
determinam o tipo de classe suportada.
A verificação é iniciada através do DataBinder
Um exemplo:
@RunWith(SpringRunner.class) @SpringBootTest public class DemoJValidationApplicationTests {
Todas as verificações que implementaram org.springframework.validation.Validator para a classe Person serão executadas.
Você também pode adicionar vários validadores, dataBinder.addValidators, pode fazer uma composição de regras (uma chamada de uma regra, outra), por exemplo:
public class OtherValidator implements Validator { @Override public boolean supports(Class<?> aClass) { return Person.class.equals(aClass); } @Override public void validate(Object obj, Errors errors) {
Por alguma razão, eu esperava que o Spring também executasse as verificações indicadas nas anotações, mas não, essa chamada deve ser feita de forma independente.
Estrutura do projeto

arquivo 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/> </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
Obviamente, quero usar duas abordagens na verificação de dados - Java e Spring, você pode combiná-las, a saber, adicionar a chamada javax.validation.Validator ao
validador Spring.
Exemplo
import javax.validation.Validator; @Service public class PersonValidator implements org.springframework.validation.Validator {
Usando a primavera, fazemos a injeção
javax.validation.Validator
@Autowired
private Validator validator;
mais adiante, o método
public void validate(Object obj, Errors errors)
execute verificações declarativas em java e, em seguida, execute todas as verificações da classe Person no spring org.springframework.validation.Validator.
Também executamos a verificação na primavera
@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()
Agora, na coleção, haverá verificações nas anotações java e spring (org.springframework.validation.Validator) para Person
Saída do console
()
3- ()
(spring)
Estrutura do projeto

Spring mvc
Obviamente, agora tudo isso pode ser aplicado em um aplicativo da web.
Adicionamos a página Controller, jsp ao projeto (aqui, a propósito, pode haver outras opções, por exemplo, gerar páginas usando freeMarker, etc.), estilo css, dependência de pom. E assim, em ordem
1) Controlador MVC
import org.springframework.validation.Validator; @Controller public class DemoJValidationController { @Autowired @Qualifier("personValidator")
Aqui com injeção de mola conectada PersonValidator
@Autowired
@Qualifier("personValidator") // spring validator
private Validator personValidator;
defina PersonValidator como initBinder
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(personValidator);
}
Validação acionada pela anotação
@Valid
Nesse caso, somente a verificação de primavera será realizada, as verificações declarativas serão ignoradas.
Se removido do código
@InitBinder
protected void initBinder(WebDataBinder binder)
pelo contrário, todas as verificações declarativas serão realizadas e a primavera será ignorada.
Para concluir todas as verificações, declarativas e primavera, você pode fazer o seguinte:
Remova o @InitBinder, deixe a injeção
@Autowired
@Qualifier("personValidator") // spring validator
private Validator personValidator;
e adicione uma chamada de verificação de primavera manualmente
// spring validate
personValidator.validate(person, bindingResult);
Aqui está o código:
@Controller public class DemoJValidationController { @Autowired @Qualifier("personValidator")
isto é verificações adicionais da primavera serão adicionadas ao bindingResult :-), que é o que eu queria!
A ligação de dados no jsp e no modelo é realizada pelo atributo -
modelAttribute="person"
No exemplo, a Form Tag Library do SpringMVC está conectada.
Os recursos restantes deste exemplo são:
DemoJValidationApplication @SpringBootApplication @ImportResource("classpath:configuration.xml") public class DemoJValidationApplication { public static void main(String[] args) { SpringApplication.run(DemoJValidationApplication.class, args); } }
Configuração de mola
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; }
arquivo 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/> </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>
Estrutura do projeto

Trabalho de aplicação

Materiais
Especificação de validação de bean