Compare commits
2 Commits
1309a553a4
...
9d44c12fac
Author | SHA1 | Date | |
---|---|---|---|
9d44c12fac | |||
95a6621d6c |
15
pom.xml
15
pom.xml
@ -2,10 +2,11 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-parent -->
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
<version>2.7.1</version>
|
<version>3.3.5</version>
|
||||||
<relativePath/> <!-- lookup parent from repository -->
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@ -15,7 +16,7 @@
|
|||||||
<name>spring-validation</name>
|
<name>spring-validation</name>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>17</java.version>
|
<java.version>21</java.version>
|
||||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
@ -28,15 +29,11 @@
|
|||||||
<artifactId>spring-boot-starter-validation</artifactId>
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<!-- https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-starter-webmvc-ui -->
|
||||||
<groupId>io.swagger.core.v3</groupId>
|
|
||||||
<artifactId>swagger-annotations</artifactId>
|
|
||||||
<version>2.2.1</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springdoc</groupId>
|
<groupId>org.springdoc</groupId>
|
||||||
<artifactId>springdoc-openapi-ui</artifactId>
|
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||||
<version>1.6.9</version>
|
<version>2.6.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
109
postman/Spring Validation.postman_collection.json
Normal file
109
postman/Spring Validation.postman_collection.json
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
{
|
||||||
|
"info": {
|
||||||
|
"_postman_id": "bb233500-0318-496e-9882-071ee5de34a0",
|
||||||
|
"name": "Spring Validation",
|
||||||
|
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
||||||
|
"_exporter_id": "16442716"
|
||||||
|
},
|
||||||
|
"item": [
|
||||||
|
{
|
||||||
|
"name": "Person",
|
||||||
|
"item": [
|
||||||
|
{
|
||||||
|
"name": "Create Person",
|
||||||
|
"event": [
|
||||||
|
{
|
||||||
|
"listen": "test",
|
||||||
|
"script": {
|
||||||
|
"exec": [
|
||||||
|
"pm.test(\"Status code is 400\", function () {",
|
||||||
|
" pm.response.to.have.status(400);",
|
||||||
|
"});",
|
||||||
|
"",
|
||||||
|
"pm.test(\"violations is not null\", function () {",
|
||||||
|
" var jsonData = pm.response.json();",
|
||||||
|
" pm.expect(jsonData.violations).is.not.null;",
|
||||||
|
" pm.expect(jsonData.violations[0].fieldName).to.be.oneOf([\"numberBetweenOneAndTen\", \"ipAddress\", \"name\"])",
|
||||||
|
" pm.expect(jsonData.violations[1].fieldName).to.be.oneOf([\"numberBetweenOneAndTen\", \"ipAddress\", \"name\"])",
|
||||||
|
" pm.expect(jsonData.violations[2].fieldName).to.be.oneOf([\"numberBetweenOneAndTen\", \"ipAddress\", \"name\"])",
|
||||||
|
" pm.expect(jsonData.violations[0].message).to.be.oneOf([\"Не соответствует формату IP адреса\", \"должно быть не больше 10\", \"не должно быть пустым\"])",
|
||||||
|
" pm.expect(jsonData.violations[1].message).to.be.oneOf([\"Не соответствует формату IP адреса\", \"должно быть не больше 10\", \"не должно быть пустым\"])",
|
||||||
|
" pm.expect(jsonData.violations[2].message).to.be.oneOf([\"Не соответствует формату IP адреса\", \"должно быть не больше 10\", \"не должно быть пустым\"])",
|
||||||
|
"});"
|
||||||
|
],
|
||||||
|
"type": "text/javascript"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"request": {
|
||||||
|
"method": "POST",
|
||||||
|
"header": [],
|
||||||
|
"body": {
|
||||||
|
"mode": "raw",
|
||||||
|
"raw": "{\n \"name\": null,\n \"numberBetweenOneAndTen\": 20,\n \"ipAddress\": \"15434.250.124.\"\n}",
|
||||||
|
"options": {
|
||||||
|
"raw": {
|
||||||
|
"language": "json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"raw": "http://localhost:8080/api/person",
|
||||||
|
"protocol": "http",
|
||||||
|
"host": [
|
||||||
|
"localhost"
|
||||||
|
],
|
||||||
|
"port": "8080",
|
||||||
|
"path": [
|
||||||
|
"api",
|
||||||
|
"person"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Get Person",
|
||||||
|
"event": [
|
||||||
|
{
|
||||||
|
"listen": "test",
|
||||||
|
"script": {
|
||||||
|
"exec": [
|
||||||
|
"pm.test(\"Status code is 400\", function () {",
|
||||||
|
" pm.response.to.have.status(400);",
|
||||||
|
"});",
|
||||||
|
"",
|
||||||
|
"pm.test(\"violations is not null\", function () {",
|
||||||
|
" var jsonData = pm.response.json();",
|
||||||
|
" pm.expect(jsonData.violations).is.not.null;",
|
||||||
|
" pm.expect(jsonData.violations[0].fieldName).to.be.eq(\"getById.personId\")",
|
||||||
|
" pm.expect(jsonData.violations[0].message).to.be.eq(\"должно быть не меньше 0\")",
|
||||||
|
"});"
|
||||||
|
],
|
||||||
|
"type": "text/javascript"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [],
|
||||||
|
"url": {
|
||||||
|
"raw": "http://localhost:8080/api/person/-1",
|
||||||
|
"protocol": "http",
|
||||||
|
"host": [
|
||||||
|
"localhost"
|
||||||
|
],
|
||||||
|
"port": "8080",
|
||||||
|
"path": [
|
||||||
|
"api",
|
||||||
|
"person",
|
||||||
|
"-1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package org.sadtech.example.springvalidation.controller;
|
package org.sadtech.example.springvalidation.controller;
|
||||||
|
|
||||||
|
import jakarta.validation.ConstraintViolationException;
|
||||||
import org.sadtech.example.springvalidation.dto.ValidationErrorResponse;
|
import org.sadtech.example.springvalidation.dto.ValidationErrorResponse;
|
||||||
import org.sadtech.example.springvalidation.dto.Violation;
|
import org.sadtech.example.springvalidation.dto.Violation;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
@ -9,7 +10,6 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
|
|||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
import javax.validation.ConstraintViolationException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -2,7 +2,12 @@ package org.sadtech.example.springvalidation.controller;
|
|||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.validation.constraints.Min;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.sadtech.example.springvalidation.dto.PersonDto;
|
import org.sadtech.example.springvalidation.dto.PersonDto;
|
||||||
|
import org.sadtech.example.springvalidation.service.PersonService;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@ -13,16 +18,18 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import java.time.LocalDate;
|
||||||
import javax.validation.constraints.Min;
|
import java.util.List;
|
||||||
import javax.validation.constraints.NotBlank;
|
|
||||||
|
|
||||||
@Validated
|
@Validated
|
||||||
@RestController
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
@RequestMapping("/api/person")
|
@RequestMapping("/api/person")
|
||||||
@Tag(name = "Пользователи системы", description = "Валидация на уровне контроллера")
|
@Tag(name = "Пользователи системы", description = "Валидация на уровне контроллера")
|
||||||
public class PersonController {
|
public class PersonController {
|
||||||
|
|
||||||
|
private final PersonService personService;
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping
|
||||||
@Operation(summary = "Сохранение пользователя")
|
@Operation(summary = "Сохранение пользователя")
|
||||||
public ResponseEntity<String> save(@Valid @RequestBody PersonDto personDto) {
|
public ResponseEntity<String> save(@Valid @RequestBody PersonDto personDto) {
|
||||||
@ -45,4 +52,15 @@ public class PersonController {
|
|||||||
return ResponseEntity.ok("valid");
|
return ResponseEntity.ok("valid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("birthday")
|
||||||
|
@Operation(summary = "Получить пользователей в диапазоне ДР")
|
||||||
|
public ResponseEntity<List<PersonDto>> getByPersonBirthday(
|
||||||
|
@RequestParam("from") LocalDate from,
|
||||||
|
@RequestParam("to") LocalDate to
|
||||||
|
) {
|
||||||
|
return ResponseEntity.ok(
|
||||||
|
personService.getAllByHappyBirthdayBetween(from, to)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.sadtech.example.springvalidation.controller;
|
package org.sadtech.example.springvalidation.controller;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
import org.sadtech.example.springvalidation.dto.PersonDto;
|
import org.sadtech.example.springvalidation.dto.PersonDto;
|
||||||
import org.sadtech.example.springvalidation.valid.Marker;
|
import org.sadtech.example.springvalidation.valid.Marker;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
@ -11,7 +12,6 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
|
||||||
|
|
||||||
@Validated
|
@Validated
|
||||||
@RestController
|
@RestController
|
||||||
|
@ -12,9 +12,9 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
@RequestMapping("/api/no-valid/person")
|
@RequestMapping("/api/no-valid/person")
|
||||||
@Tag(name = "Пользователи системы 2", description = "Валидация на уровне сервиса")
|
@Tag(name = "Пользователи системы 2", description = "Валидация на уровне сервиса")
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class PersonControllerNoValidation {
|
public class PersonControllerNoValidation {
|
||||||
|
|
||||||
private final PersonService personService;
|
private final PersonService personService;
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package org.sadtech.example.springvalidation.dto;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class Address {
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
private String state;
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
private String city;
|
||||||
|
|
||||||
|
}
|
@ -1,23 +1,23 @@
|
|||||||
package org.sadtech.example.springvalidation.dto;
|
package org.sadtech.example.springvalidation.dto;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import jakarta.persistence.Transient;
|
||||||
|
import jakarta.validation.constraints.Max;
|
||||||
|
import jakarta.validation.constraints.Min;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Null;
|
||||||
|
import jakarta.validation.constraints.Pattern;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.sadtech.example.springvalidation.valid.CapitalLetter;
|
import org.sadtech.example.springvalidation.valid.CapitalLetter;
|
||||||
import org.sadtech.example.springvalidation.valid.Marker;
|
import org.sadtech.example.springvalidation.valid.Marker;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.GeneratedValue;
|
|
||||||
import javax.persistence.GenerationType;
|
|
||||||
import javax.persistence.Id;
|
|
||||||
import javax.persistence.Table;
|
|
||||||
import javax.validation.constraints.Max;
|
|
||||||
import javax.validation.constraints.Min;
|
|
||||||
import javax.validation.constraints.NotBlank;
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
import javax.validation.constraints.Null;
|
|
||||||
import javax.validation.constraints.Pattern;
|
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@ -46,4 +46,7 @@ public class PersonDto {
|
|||||||
)
|
)
|
||||||
private String ipAddress;
|
private String ipAddress;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private Address address;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
package org.sadtech.example.springvalidation.service;
|
package org.sadtech.example.springvalidation.service;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
import org.sadtech.example.springvalidation.dto.PersonDto;
|
import org.sadtech.example.springvalidation.dto.PersonDto;
|
||||||
|
import org.sadtech.example.springvalidation.valid.LocalDateBetween;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import java.time.LocalDate;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Validated
|
@Validated
|
||||||
@ -14,4 +18,10 @@ public class PersonService {
|
|||||||
// do something
|
// do something
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@LocalDateBetween
|
||||||
|
public List<PersonDto> getAllByHappyBirthdayBetween(LocalDate from, LocalDate to) {
|
||||||
|
System.out.println("valid");
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package org.sadtech.example.springvalidation.valid;
|
package org.sadtech.example.springvalidation.valid;
|
||||||
|
|
||||||
import javax.validation.Constraint;
|
import jakarta.validation.Constraint;
|
||||||
import javax.validation.Payload;
|
import jakarta.validation.Payload;
|
||||||
|
|
||||||
import java.lang.annotation.Documented;
|
import java.lang.annotation.Documented;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package org.sadtech.example.springvalidation.valid;
|
package org.sadtech.example.springvalidation.valid;
|
||||||
|
|
||||||
import javax.validation.ConstraintValidator;
|
|
||||||
import javax.validation.ConstraintValidatorContext;
|
import jakarta.validation.ConstraintValidator;
|
||||||
|
import jakarta.validation.ConstraintValidatorContext;
|
||||||
|
|
||||||
public class CapitalLetterValidator implements ConstraintValidator<CapitalLetter, String> {
|
public class CapitalLetterValidator implements ConstraintValidator<CapitalLetter, String> {
|
||||||
|
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package org.sadtech.example.springvalidation.valid;
|
||||||
|
|
||||||
|
import jakarta.validation.Payload;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
@Documented
|
||||||
|
@Target(METHOD)
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface LocalDateBetween {
|
||||||
|
|
||||||
|
String message() default "Дата невалидна";
|
||||||
|
|
||||||
|
Class<?>[] groups() default {};
|
||||||
|
|
||||||
|
Class<? extends Payload>[] payload() default {};
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package org.sadtech.example.springvalidation.valid;
|
||||||
|
|
||||||
|
import jakarta.validation.ConstraintValidator;
|
||||||
|
import jakarta.validation.ConstraintValidatorContext;
|
||||||
|
import jakarta.validation.constraintvalidation.SupportedValidationTarget;
|
||||||
|
import jakarta.validation.constraintvalidation.ValidationTarget;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
@SupportedValidationTarget(ValidationTarget.PARAMETERS)
|
||||||
|
public class LocalDateBetweenValidator implements ConstraintValidator<LocalDateBetween, Object[]> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid(Object[] value, ConstraintValidatorContext context) {
|
||||||
|
final Object objDateFrom = value[0];
|
||||||
|
final Object objDateTo = value[1];
|
||||||
|
|
||||||
|
if (
|
||||||
|
!(objDateFrom instanceof final LocalDate dateFrom)
|
||||||
|
|| !(objDateTo instanceof final LocalDate dateTo)
|
||||||
|
) {
|
||||||
|
throw new IllegalArgumentException("Illegal method signature, expected two parameters of type LocalDate.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return dateFrom.isAfter(LocalDate.now()) && dateFrom.isBefore(dateTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user