Validasi Data - Validasi Java & Spring

Memvalidasi data kelas (kacang) di java bukanlah topik baru, tetapi juga relevan di sini dan saya akan menggabungkan berbagai aspek: validasi data dalam JSR-303, saya akan menunjukkan bagaimana melakukan ini secara murni di Jawa dan menggunakan Spring, bagaimana melakukannya dalam aplikasi standar dan di Web.

Isi: Validasi Data (JSR-303) di

  • aplikasi java standar
  • menggunakan Spring
  • Asosiasi Jawa + Musim Semi
  • Musim semi mvc

Validasi dalam aplikasi Java standar


Untuk memeriksa objek, anotasi pada bidang kelas digunakan, yaitu model deklaratif. Anotasi sudah siap:
Null , @DecimalMin, @Digits, Pattern , Email , dll.
, dan Anda juga bisa membuatnya sendiri. Dan ada kelas (kacang)

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; } } 

Di sini, dalam contoh Ukuran dan @Digits siapkan anotasi, dan @PersonAgeConstraint sendiri. Cara membuat sendiri:

- siapkan anotasi

 @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 {}; } 

Dalam pesan (), tentukan kunci (value.negative) dari file sumber daya (ValidationMessages.properties) untuk pesan
value.negative = Nilai negatif
dan implementasi kelas verifikasi - PersonAgeConstraintValidator.class

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

Anotasi saya sendiri sudah siap, kami menambahkannya ke bidang dan sudah mungkin untuk memeriksa, semua bidang yang ada anotasi akan diperiksa oleh aturan yang sesuai.

 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); } } 

Menghasilkan konsol

3-



Pesan untuk anotasi standar dapat ditentukan dalam file pesan, sebagai aturan:

AnnotationName.entity.fieldname=

Struktur proyek

gambar

file 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> 


Verifikasi bertahap. Untuk Kelas <?> [] Grup (), Anda dapat menentukan jenis kelas yang digunakan untuk mengelompokkannya, membatasi daftar cek, mis. gunakan sebagai filter. Dengan demikian, verifikasi dapat dilakukan secara bertahap, 1) Misalnya, kami membagi pemeriksaan seseorang untuk alasan kesehatan, 2) dan kemudian data profesional. Kami akan menyiapkan dua anotasi
HealthConstraint dan ProfessionalConstraint dan implementasi untuk mereka. Pertama kita memeriksa kepatuhan dengan kesehatan dan kemudian jika melalui kesehatan, kita memeriksa data profesional.

Contoh:

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

Contoh penjelasan 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 {}; } 

Contoh implementasi HealthConstraintValidator

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

untuk ProfessionalConstraint semuanya sama

Cek selanjutnya seperti ini:

  @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); } 

Pemeriksaan semacam itu, misalnya, diperlukan ketika kita memuat data dari file, layanan web, dan sumber lainnya.

Dokumen kelas
 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); } } 


Validasi menggunakan Spring


Spring juga memiliki antarmuka Validator sendiri.
(org.springframework.validation.Validator)
seperti di java
(javax.validation.Validator)
dan justru implementasinya yang memvalidasi data. Ini bukan lagi pendekatan deklaratif, tetapi memiliki fleksibilitas dan ekstensibilitas sendiri. Untuk tempat sampah yang sama, saya akan melakukan pemeriksaan usia yang sama.

Dengan mengganti kedua metode, kami memvalidasi

 @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 - juga merupakan kunci dalam file pesan, public boolean supports menentukan jenis kelas yang didukung.

Verifikasi diluncurkan melalui DataBinder

Contoh:

 @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()))); } } } 

Semua pemeriksaan yang mengimplementasikan org.springframework.validation.Validator untuk kelas Person akan dilakukan.

Anda juga dapat menambahkan beberapa validator, dataBinder.addValidators, Anda dapat membuat komposisi aturan (panggilan dari satu aturan, yang lain), misalnya:

 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); } } 

Untuk beberapa alasan saya berharap bahwa Spring juga akan melakukan pemeriksaan yang ditunjukkan dalam penjelasan, tetapi tidak, panggilan ini harus dilakukan secara independen.

Struktur proyek

gambar

file 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> 


Jawa & Musim Semi


Jelas, saya ingin menggunakan dua pendekatan dalam verifikasi data - Java dan Spring, Anda dapat menggabungkan mereka, yaitu, tambahkan panggilan javax.validation.Validator ke validator Spring.

Contoh

 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"); } } } 

Dengan menggunakan pegas, kami melakukan injeksi javax.validation.Validator

@Autowired
private Validator validator;


lebih lanjut tentang metode public void validate(Object obj, Errors errors)
melakukan pemeriksaan deklaratif di java dan kemudian lakukan semua pemeriksaan untuk kelas Person di spring org.springframework.validation.Validator.

Kami juga menjalankan verifikasi melalui pegas

  @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() // .... 

Sekarang dalam koleksi akan ada pemeriksaan terhadap anotasi java dan spring (org.springframework.validation.Validator) untuk Orang

Output konsol

()
3- ()
(spring)


Struktur proyek

gambar

Musim semi mvc


Tentu saja, sekarang semua ini bisa diterapkan dalam aplikasi web.

Kami menambahkan Controller, halaman jsp ke proyek (di sini, omong-omong, mungkin ada opsi lain, misalnya, menghasilkan halaman menggunakan freeMarker, dll.), Gaya css, ketergantungan pom. Dan demikianlah urutannya

1) Kontroler 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; } } 

Di sini dengan injeksi spring terhubung PersonValidator

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


atur PersonValidator ke initBinder

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


Validasi dipicu oleh anotasi @Valid
Dalam hal ini, hanya pemeriksaan pegas yang akan dilakukan, pemeriksaan deklaratif akan diabaikan.

Jika dihapus dari kode

@InitBinder
protected void initBinder(WebDataBinder binder)


sebaliknya, semua pemeriksaan deklaratif akan dilakukan, dan pegas akan diabaikan.
Untuk menyelesaikan semua pemeriksaan, deklaratif dan pegas, Anda dapat melakukan ini:

Hapus @InitBinder, tinggalkan injeksi

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


dan tambahkan panggilan periksa pegas secara manual

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


Ini kodenya:

 @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 } } 

yaitu cek tambahan dari musim semi akan ditambahkan ke bindingResult :-), itulah yang saya inginkan!

Pengikatan data dalam jsp dan model dilakukan oleh atribut - modelAttribute="person" Dalam contoh ini, Pustaka Tag Formulir SpringMVC terhubung.

Sumber daya yang tersisa dari contoh ini adalah:

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


Konfigurasi pegas
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; } 


file 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> 


Struktur proyek

gambar

Pekerjaan aplikasi

gambar

Material

Spesifikasi validasi kacang

Source: https://habr.com/ru/post/id424819/


All Articles