Skip to content

Commit c972b5e

Browse files
committed
Update spring-boot-validator
1 parent 5925f3b commit c972b5e

File tree

15 files changed

+274
-81
lines changed

15 files changed

+274
-81
lines changed

SpringBootValidator/build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ repositories {
66
}
77

88
dependencies {
9-
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
109
implementation 'org.springframework.boot:spring-boot-starter-web'
1110
implementation 'org.springframework.boot:spring-boot-starter-validation'
1211

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.example.config;
2+
3+
import org.hibernate.validator.messageinterpolation.AbstractMessageInterpolator;
4+
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.context.support.ResourceBundleMessageSource;
6+
import org.springframework.stereotype.Component;
7+
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
8+
9+
import java.nio.charset.StandardCharsets;
10+
11+
@Configuration
12+
public class WebMvcConfig implements WebMvcConfigurer {
13+
14+
// See AbstractApplicationContext#initMessageSource
15+
@Component("messageSource")
16+
static class ValidationMessageSource extends ResourceBundleMessageSource {
17+
18+
ValidationMessageSource() {
19+
setBasename(AbstractMessageInterpolator.USER_VALIDATION_MESSAGES);
20+
setDefaultEncoding(StandardCharsets.UTF_8.displayName());
21+
}
22+
}
23+
}

SpringBootValidator/src/main/java/com/example/domain/ErrorMessage.java

Lines changed: 0 additions & 29 deletions
This file was deleted.

SpringBootValidator/src/main/java/com/example/domain/Member.java

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,19 @@
11
package com.example.domain;
22

3-
import com.example.validator.Phone;
3+
import com.example.validation.Phone;
44

5-
import javax.persistence.Entity;
6-
import javax.persistence.GeneratedValue;
7-
import javax.persistence.GenerationType;
8-
import javax.persistence.Id;
95
import javax.validation.constraints.Min;
106
import javax.validation.constraints.NotNull;
117

12-
13-
@Entity
148
public class Member {
159

16-
@Id
17-
@GeneratedValue(strategy = GenerationType.AUTO)
1810
private long idx;
1911

20-
@NotNull(message = "name null")
12+
@NotNull
2113
private String name;
2214

23-
@NotNull(message = "age null")
24-
@Min(value = 14, message = "min 14")
15+
@NotNull
16+
@Min(14)
2517
private Integer age;
2618

2719
@Phone

SpringBootValidator/src/main/java/com/example/domain/MemberRepository.java

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.example.errorhandler;
2+
3+
public class ErrorMessage {
4+
5+
private final String field;
6+
private final String message;
7+
8+
public static ErrorMessage of(String field, String message) {
9+
return new ErrorMessage(field, message);
10+
}
11+
12+
protected ErrorMessage(String field, String message) {
13+
this.field = field;
14+
this.message = message;
15+
}
16+
17+
public String getField() {
18+
return field;
19+
}
20+
21+
public String getMessage() {
22+
return message;
23+
}
24+
}
25+
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.example.errorhandler;
2+
3+
import org.hibernate.validator.internal.engine.path.PathImpl;
4+
import org.slf4j.Logger;
5+
import org.slf4j.LoggerFactory;
6+
import org.springframework.context.MessageSource;
7+
import org.springframework.http.ResponseEntity;
8+
import org.springframework.http.converter.HttpMessageNotReadableException;
9+
import org.springframework.web.bind.MethodArgumentNotValidException;
10+
import org.springframework.web.bind.annotation.ExceptionHandler;
11+
import org.springframework.web.bind.annotation.RestControllerAdvice;
12+
import org.springframework.web.context.request.WebRequest;
13+
14+
import javax.validation.ConstraintViolation;
15+
import javax.validation.ConstraintViolationException;
16+
import javax.validation.Path;
17+
import java.util.Collections;
18+
import java.util.List;
19+
import java.util.Locale;
20+
import java.util.stream.Collectors;
21+
22+
@RestControllerAdvice
23+
class GlobalExceptionHandler {
24+
25+
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
26+
27+
private final MessageSource messageSource;
28+
29+
GlobalExceptionHandler(MessageSource messageSource) {
30+
this.messageSource = messageSource;
31+
}
32+
33+
@ExceptionHandler(ConstraintViolationException.class)
34+
ResponseEntity<List<ErrorMessage>> constraintViolationException(ConstraintViolationException exception,
35+
WebRequest request) {
36+
logger.warn("path: {}, locale: {}, principal:{}", request.getContextPath(), request.getLocale(),
37+
request.getUserPrincipal());
38+
39+
final List<ErrorMessage> body = exception.getConstraintViolations().stream()
40+
.map(cv -> ErrorMessage.of(property(cv).toString(), cv.getMessage()))
41+
.collect(Collectors.toList());
42+
return ResponseEntity.badRequest().body(body);
43+
}
44+
45+
@ExceptionHandler(MethodArgumentNotValidException.class)
46+
ResponseEntity<List<ErrorMessage>> methodArgumentNotValidException(MethodArgumentNotValidException exception,
47+
WebRequest request) {
48+
logger.warn("path: {}, locale: {}, principal:{}", request.getContextPath(), request.getLocale(),
49+
request.getUserPrincipal());
50+
51+
final List<ErrorMessage> body = exception.getBindingResult().getAllErrors().stream()
52+
.map(oe -> oe.unwrap(ConstraintViolation.class))
53+
.map(cv -> ErrorMessage.of(property(cv).toString(), cv.getMessage()))
54+
.collect(Collectors.toList());
55+
return ResponseEntity.badRequest().body(body);
56+
}
57+
58+
private static Path.Node property(ConstraintViolation<?> constraintViolation) {
59+
return ((PathImpl) constraintViolation.getPropertyPath()).getLeafNode();
60+
}
61+
62+
@ExceptionHandler(HttpMessageNotReadableException.class)
63+
ResponseEntity<List<ErrorMessage>> emptyBodyException(HttpMessageNotReadableException exception,
64+
WebRequest request) {
65+
logger.warn("path: {}, locale: {}, principal:{}", request.getContextPath(), request.getLocale(),
66+
request.getUserPrincipal());
67+
68+
final String message = messageSource.getMessage("body.incorrect.message", new Object[]{ }, Locale.getDefault());
69+
return ResponseEntity.badRequest().body(Collections.singletonList(ErrorMessage.of("body", message)));
70+
}
71+
}
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
package com.example.validator;
1+
package com.example.validation;
22

33
import javax.validation.Constraint;
44
import javax.validation.Payload;
55
import java.lang.annotation.*;
66

77
@Documented
88
@Constraint(validatedBy = PhoneValidator.class)
9-
@Target({ElementType.METHOD, ElementType.FIELD})
9+
@Target({ElementType.FIELD, ElementType.PARAMETER})
1010
@Retention(RetentionPolicy.RUNTIME)
1111
public @interface Phone {
12-
String message() default "Invalid phone number";
12+
String message() default "{com.example.validation.Phone.message}";
1313

1414
Class<?>[] groups() default {};
1515

1616
Class<? extends Payload>[] payload() default {};
17-
}
17+
}

SpringBootValidator/src/main/java/com/example/validator/PhoneValidator.java renamed to SpringBootValidator/src/main/java/com/example/validation/PhoneValidator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.example.validator;
1+
package com.example.validation;
22

33
import javax.validation.ConstraintValidator;
44
import javax.validation.ConstraintValidatorContext;
Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,30 @@
11
package com.example.web;
22

3-
import com.example.domain.ErrorMessage;
43
import com.example.domain.Member;
5-
import org.springframework.http.HttpStatus;
4+
import com.example.validation.Phone;
65
import org.springframework.http.ResponseEntity;
7-
import org.springframework.validation.BindingResult;
6+
import org.springframework.validation.annotation.Validated;
87
import org.springframework.web.bind.annotation.*;
98

109
import javax.validation.Valid;
10+
import javax.validation.constraints.Min;
11+
import javax.validation.constraints.NotNull;
1112

13+
14+
@Validated
1215
@RestController
1316
@RequestMapping("member")
1417
public class MemberController {
1518

16-
private static final int ZERO = 0;
17-
18-
@GetMapping
19-
public String find() {
20-
return "Error";
21-
}
22-
2319
@PostMapping
24-
public ResponseEntity<?> add(@Valid @RequestBody Member member, BindingResult bindingResult) {
25-
if (bindingResult.hasErrors()) {
26-
String errorMessage = bindingResult.getAllErrors().get(ZERO).getDefaultMessage();
27-
return ResponseEntity.badRequest().body(new ErrorMessage(HttpStatus.BAD_REQUEST.value(), errorMessage));
28-
}
29-
20+
public ResponseEntity<?> postAdd(@Valid @RequestBody Member member) {
3021
return ResponseEntity.ok(member);
3122
}
23+
24+
@GetMapping
25+
public ResponseEntity<?> getAdd(@NotNull String name,
26+
@NotNull @Min(14) Integer age,
27+
@Phone String phone) {
28+
return ResponseEntity.ok(new Member(name, age, phone));
29+
}
3230
}

0 commit comments

Comments
 (0)