GIT : github.com/miseongshin/diary/tree/forValidationInBlog
INDEX
1. @Valitated
- CustomerController.java
2. Custom Validate Annotation
- CustomerSignUpData.java
- SameValue.java
- SameValueValidator.java
3. Validation Annotation, BindingResult
- CustomerController.java
- CustomerSignUpData.java
- DiaryValidErrorException.java
- DiaryExceptionHandlers.java
- ValidErrorData.java
- ValidErrorResultData.java
4. Sequences(or order)
- CustomerController.java
- CustomerSignUpData.java
- Sequences.java
1. pom.xml
org.hibernate.validator is for the Validated field
com.google.cod.gson is for JUnit5
<!-- valid annotation for @Valid -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.13.Final</version>
</dependency>
<!-- for json parameter for java bean -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2. CustomerController.java
@Valitated(Sequence.class) is for Sequences(or order)
@Validated(Sequences.class) @RequestBody CustomerSignUpData customerSignUpData, BindingResult bindingResult) throws DiaryValidErrorException
and
if (bindingResult.hasErrors()) {
throw new DiaryValidErrorException(bindingResult, messageSource);
}
are for @Valitated, BindingResult
@PostMapping("/signUp/ajax")
@ResponseStatus(HttpStatus.CREATED)
public ResponseEntity<Map> signUpAjax(HttpServletRequest request, @Validated(Sequences.class) @RequestBody CustomerSignUpData customerSignUpData, BindingResult bindingResult) throws DiaryValidErrorException {
if (bindingResult.hasErrors()) {
throw new DiaryValidErrorException(bindingResult, messageSource);
}
Map result = new HashMap<>();
return ResponseEntity.ok(result);
}
3. CustomerSignUpData.java
@SameValue(field = "password", fieldMatch = "confirmPassword") is for Custom Validation
groups= Sequences.OrderXX.class is Sequences(or order),
package com.today10sec.diary.customize.dto;
import com.today10sec.diary.customize.validator.SameValue;
import com.today10sec.diary.customize.validator.Sequences;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
@Setter
@Getter
@AllArgsConstructor
@ToString(exclude = {"password", "confirmPassword"})
@SameValue(field = "password", fieldMatch = "confirmPassword", groups= Sequences.Order6.class)
public class CustomerSignUpData {
@NotEmpty(groups = Sequences.Order1.class)
@Length(max=320, groups= Sequences.Order2.class)
@Email(groups= Sequences.Order2.class)
private String email;
@NotEmpty(groups= Sequences.Order3.class)
@Length(min= 6, max= 12, groups= Sequences.Order4.class)
@Pattern(regexp="[a-zA-Z1-9]{6,12}",groups= Sequences.Order4.class)
private String password;
@NotEmpty(groups= Sequences.Order5.class)
@Length(min= 6, max= 12, groups= Sequences.Order7.class)
private String confirmPassword;
}
4. SameValue.java
this source for Custom Validation
package com.today10sec.diary.customize.validator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Constraint(validatedBy = SameValueValidator.class)
public @interface SameValue {
String field();
String fieldMatch();
String message() default "{come.today10sec.diary.error.valid.samePassword}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
5. SameValueValidator.java
this source for Custom Validation
package com.today10sec.diary.customize.validator;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
@Component
public class SameValueValidator implements ConstraintValidator<SameValue,Object> {
private String field;
private String fieldMatch;
@Override
public void initialize(SameValue constraintAnnotation) {
this.field = constraintAnnotation.field();
this.fieldMatch = constraintAnnotation.fieldMatch();
}
@Override
public boolean isValid(Object object, ConstraintValidatorContext constraintValidatorContext) {
String fieldValue = String.valueOf(new BeanWrapperImpl(object).getPropertyValue(field));
String fieldMatchValue = String.valueOf(new BeanWrapperImpl(object).getPropertyValue(fieldMatch));
if (fieldValue == null) {
throw new RuntimeException("fieldValue can not be null");
}else if(fieldMatchValue ==null ){
throw new RuntimeException("fieldMatchValue can not be null");
}
if (fieldValue.equals(fieldMatchValue)){
return true;
} else{
constraintValidatorContext.disableDefaultConstraintViolation();
constraintValidatorContext.buildConstraintViolationWithTemplate("message")
.addPropertyNode(fieldMatch)
.addConstraintViolation();
return false;
}
}
}
6. Sequences.java
this source for Sequences(or order)
package com.today10sec.diary.customize.validator;
import javax.validation.GroupSequence;
import javax.validation.groups.Default;
@GroupSequence(value = {Sequences.Order1.class, Sequences.Order2.class, Sequences.Order3.class, Sequences.Order4.class, Sequences.Order5.class, Sequences.Order6.class, Sequences.Order7.class, Sequences.Order8.class, Sequences.Order9.class, Sequences.Order10.class, Default.class})
public interface Sequences {
public @interface Order1 {
}
public @interface Order2 {
}
public @interface Order3 {
}
public @interface Order4 {
}
public @interface Order5 {
}
public @interface Order6 {
}
public @interface Order7 {
}
public @interface Order8 {
}
public @interface Order9 {
}
public @interface Order10 {
}
}
7. DiaryValidErrorException.java
this source for Custom Validation BindingResult
package com.today10sec.diary.customize.exception;
import lombok.Getter;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpStatus;
import org.springframework.util.Assert;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* Validation Exception for Common Diary
*/
@ResponseStatus(value= HttpStatus.BAD_REQUEST)
@Getter
public class DiaryValidErrorException extends Exception {
private final BindingResult bindingResult;
private final MessageSource messageSource;
public DiaryValidErrorException(BindingResult bindingResult, MessageSource messageSource) {
Assert.notNull(bindingResult, "BindingResult must not be null");
Assert.notNull(bindingResult, "BindingResult must not be null");
this.bindingResult = bindingResult;
this.messageSource = messageSource;
}
}
8. ValidErrorExceptionHandler.java
this source for Custom Validation, BindingResult
package com.today10sec.diary.config;
import com.today10sec.diary.customize.dto.ValidErrorData;
import com.today10sec.diary.customize.dto.ValidErrorResultData;
import com.today10sec.diary.customize.exception.DiaryValidErrorException;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import java.util.List;
import java.util.stream.Collectors;
@ControllerAdvice
public class DiaryExceptionHandlers {
@ResponseBody
@ExceptionHandler(DiaryValidErrorException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ValidErrorResultData ValidErrorExceptionHandler (DiaryValidErrorException diaryValidErrorException){
MessageSource messageSource = diaryValidErrorException.getMessageSource();
BindingResult bindingResult = diaryValidErrorException.getBindingResult();
List<ValidErrorData> errorDataList = bindingResult.getFieldErrors()
.stream().map(error-> new ValidErrorData(error, messageSource)
).collect(Collectors.toList());
return new ValidErrorResultData(errorDataList);
}
}
9. ValidErrorData.java
this source for Custom Validation, BindingResult
package com.today10sec.diary.customize.dto;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.validation.FieldError;
import java.util.Locale;
@Getter
public class ValidErrorData {
Locale locale;
private String fieldName;
private String message;
public ValidErrorData(FieldError fieldError, MessageSource messageSource){
this.fieldName = fieldError.getField();
this.message = messageSource.getMessage(fieldError.getCodes()[0],fieldError.getArguments(),fieldError.getDefaultMessage()+"["+fieldError.getCodes()[0]+"]",locale);
}
@Autowired
public void setLocale(Locale locale) {
this.locale = locale;
}
}
10. ValidErrorResultData.java
this source for Custom Validation, BindingResult
package com.today10sec.diary.customize.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.List;
@AllArgsConstructor
@Getter
public class ValidErrorResultData {
private final Boolean validData = true;
private List<ValidErrorData> errors;
}
11. CustomerControllerTest.java
this source for Custom Validation
package com.today10sec.diary.mvc.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.google.gson.Gson;
import com.today10sec.diary.customize.dto.CustomerSignUpData;
import com.today10sec.diary.customize.dto.ValidErrorResultData;
import com.today10sec.diary.customize.validator.SameValue;
import com.today10sec.diary.customize.validator.SameValueValidator;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
@ExtendWith(SpringExtension.class)
@WebMvcTest({CustomerController.class, SameValueValidator.class, SameValue.class, CustomerSignUpData.class})
class CustomerControllerTest {
@Autowired
MockMvc mockMvc;
@Test
void SIGN_UP_AJAX_VALID_CONFIRM_PW() throws Exception {
String expectedResult = "{\"validData\":true,\"errors\":[{\"locale\":null,\"fieldName\":\"confirmPassword\",\"message\":\"비밀번호와 비밀번호확인값이 일치하지 않습니다. \"}]}";
CustomerSignUpData customerSignUpData = new CustomerSignUpData("a@a.com","111111","222222" );
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
ObjectWriter ow = mapper.writer().withDefaultPrettyPrinter();
String requestJson=ow.writeValueAsString(customerSignUpData);
MvcResult mvcResult= mockMvc.perform(
post("/customer/signUp/ajax")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(requestJson))
.andDo(print())
.andExpect(status().isBadRequest())
.andReturn();
String result = mvcResult.getResponse().getContentAsString();
Gson gson = new Gson();
ValidErrorResultData resultData = gson.fromJson(result, ValidErrorResultData.class);
Assertions.assertEquals("confirmPassword",resultData.getErrors().get(0).getFieldName(),"confirmPassword not contian");
}
}
>> 도움이 많이 되었는데 예전버전이라 이것저것하면서 적용
***Spring REST Validation Example mkyong.com/spring-boot/spring-rest-validation-example
**Spring Boot Validation 순서 정하기 & 테스트 코드 dncjf64.tistory.com/302
www.baeldung.com/spring-mvc-custom-validator
mkyong.com/java/how-do-convert-java-object-to-from-json-format-gson-api/
'JAVA > spring' 카테고리의 다른 글
[1028web 이클립스, sts] (0) | 2021.07.27 |
---|---|
[1028 Spring boot] 에러모음 (0) | 2021.05.11 |
[1028 JPA]에러모음 (0) | 2021.05.06 |
Runner 구현 (0) | 2021.05.03 |
[1028 from 스프링 백기선 JPA] 스프링데이터 Common _ 쿼리, 비동기, 도메인, QueryDSL (추후 추가. ) (0) | 2021.05.03 |