티스토리 뷰
개발 환경
Spring Boot 3.2.2
JAVA 17
ES6
MacOS
Postman v10.22
해당 블로그 코드들은 GitHub에 남겨져 있습니다.
작성하게된 이유
데이터 유효성 검사를 Front단 에만 쳐 내는 것이 아닌 Back단 에서도 유효성 검사를 해서 막아야합니다.
근데 실무에서는 관리자만 사용하는 웹 어플리케이션 ( CMS 라 칭함 )을 만들었기 때문에 사용자가 악용할 일이 없어서 배제해 왔지만 플랫폼처럼 서비스 하기 위해서는 이제는 Back단에서도 유효성 검사를 해야겠다고 생각했습니다.
또한, 클라이언트에서 언제든지 데이터 값을 변경하여 백엔드에게 전송할 수 있기 때문에 필수적으로 Validation을 알아야한다고 생각했습니다.
조건
- 이름, 휴대폰 번호, 이메일은 필수 값입니다.
- 휴대폰 번호는 10자리 or 11자리 숫자로 이루어져야 합니다.
- 이메일은 이메일 양식을 지켜야 합니다. (xxx@xxx)
- 이메일은 중복 등록 할 수 없습니다.
- DB로 저장하지 않고 메모리로 저장합니다.
- jQuery, bootstrap 을 이용한 간단한 회원가입 기능입니다.
코드
코드들이 길어서 더보기를 눌러서 확인해주세요!
build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.2'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'aoxx'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
Member.class
원래 엔티티(Entity)로 사용해야 했지만 JPA, DB를 사용하지 않고 메모리로 저장하기 때문에 그냥 Member 객체로 사용하였습니다.
@Setter
@Getter
@AllArgsConstructor
@RequiredArgsConstructor
public class Member {
private Long id;
private String name;
private String phoneNumber;
private String email;
}
MemberRequestDto.class
변화에 대응하기 위해 요청객체를 만들었습니다.
@Setter
@Getter
@AllArgsConstructor
@RequiredArgsConstructor
public class MemberRequestDto {
private Long id;
@NotBlank(message = "이름은 공백일 수 없습니다.")
private String name;
@NotBlank
@Pattern(regexp = "[0-9]{10,11}", message = "10~11자리의 숫자만 입력가능합니다.")
private String phoneNumber;
@NotBlank
@Email(message = "이메일 양식을 지켜주세요")
private String email;
}
MemberResponseDto.class
변화에 대응하기 위해 응답객체를 만들었습니다.
@Setter
@Getter
@AllArgsConstructor
@RequiredArgsConstructor
public class MemberResponseDto {
private Long id;
private String name;
private String phoneNumber;
private String email;
public MemberResponseDto(Member member) {
id = member.getId();
name = member.getName();
phoneNumber = member.getPhoneNumber();
email = member.getEmail();
}
}
MemberController.class
@Validated를 사용하여 유효성 검사를 해주었고 MemberRuquestDto에 걸려있는 Validation 어노테이션이 검증 해줍니다.
@Slf4j
@RestController
@RequiredArgsConstructor
public class MemberController {
private final MemberService memberService;
// 저장
@PostMapping("/member")
public MemberResponseDto join(@Validated @RequestBody MemberRequestDto memberRequestDto){
return memberService.save(memberRequestDto);
}
// 회원 목록
@GetMapping("/members")
public List<MemberResponseDto> findAll(){
return memberService.findAll();
}
}
MemberService.class
@Service
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
// 저장
public MemberResponseDto save(MemberRequestDto memberRequestDto){
Member member = new Member();
member.setName(memberRequestDto.getName());
member.setEmail(memberRequestDto.getEmail());
member.setPhoneNumber(memberRequestDto.getPhoneNumber());
Member saveMember = memberRepository.save(member);
return new MemberResponseDto(saveMember);
}
// 회원목록
public List<MemberResponseDto> findAll() {
return memberRepository.findAll().stream().map(MemberResponseDto::new).collect(Collectors.toList());
}
}
MemberRespository.class
@Repository
public class MemberRepository {
private Map<Long, Member> store = new HashMap<>();
private Long sequence = 1L;
@PostConstruct
public void init(){
Member member1 = new Member(sequence++, "김길동", "01012345678", "example1@tt.com");
Member member2 = new Member(sequence++, "이천수", "01055665678", "example2@tt.com");
Member member3 = new Member(sequence++, "조규성", "01012342234", "example3@tt.com");
store.put(member1.getId(), member1);
store.put(member2.getId(), member2);
store.put(member3.getId(), member3);
}
public Member save(Member member){
member.setId(sequence++);
store.put(member.getId(), member);
return member;
}
public List<Member> findAll(){
return new ArrayList<>(store.values());
}
}
index.html
Spring Boot의 경우 경로 / 에 매핑된 메서드가 없다면 / 접속 시 자동으로 index.html을 호출하게 됩니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Validation 확인하기</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.7.1.js" integrity="sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4=" crossorigin="anonymous"></script>
</head>
<body>
<div class="myContainer">
<div class="col-md-6" style="width: 40.5%; float : left; margin :50px;">
<h1> 회원가입 </h1>
<form>
<div class="form-group" style="margin-bottom: 15px">
<label for="name">이름</label>
<input type="text" class="form-control" id="name" placeholder="이름을 입력하세요">
</div>
<div class="form-group" style="margin-bottom: 15px">
<label for="phoneNumber"> 휴대폰번호 </label>
<input type="text" class="form-control" id="phoneNumber" placeholder="휴대폰 번호를 입력하세요">
</div>
<div class="form-group" style="margin-bottom: 15px">
<label for="email">이메일</label>
<input type="text" class="form-control" id="email" placeholder="이메일을 입력하세요">
</div>
<button type="button" class="btn btn-primary" id="btnSave">등록</button>
</form>
</div>
<div class="col-md-6" style="width: 40.5%; float: right; margin :50px;">
<h1> 회원목록 </h1>
<div style="border: 1px solid blue; width: 100%; height:500px;" id="member-list">
</div>
</div>
</div>
</body>
<script>
// 함수 호출
memberAll();
// 회원 가입 등록
$('#btnSave').click(function(){
memberJoin();
})
// 회원 가입 등록 함수
async function memberJoin(){
const url = '/member';
const member = {
name: $('#name').val(),
phoneNumber: $('#phoneNumber').val(),
email: $('#email').val()
};
$.ajax({
url: url,
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(member)
})
.done(function(data) {
memberListHTML(data);
})
.fail(function(error) {
errorShowHTML(error);
});
}
// 회원 목록 조회
function memberAll(){
const url = '/members'
$.ajax({
url: url,
type : 'GET',
contentType: "application/json; charset=utf-8",
})
.done(function(data) {
data.map(member => { memberListHTML(member); })
})
.fail(function(xhr, status, error) {
console.log('Error: ' + error);
console.log('Status: ' + status);
console.dir(xhr);
});
}
// 회원 목록 HTML 만들기
function memberListHTML(member){
let template = `
<div>${member.id} | ${member.name} | ${member.phoneNumber} | ${member.email} | </div>
`;
$('#member-list').append(template);
}
// 에러 메시지 출력 함수
function errorShowHTML(response){
const errorFields = response.responseJSON.errors;
errorFields.map(error => {
let field = error.field;
let template = `
<span class="error-message text-danger text-small" id="error-${field}">${error.defaultMessage}</span>
`;
$(`#${field}`).after(template);
});
}
</script>
</html>
테스트 시작
스프링을 기동시켜주어서 http://localhost:8080/ 로 접속해 줍니다.
순서1) 포스트맨으로 확인
포스트맨을 열고 http://localhost:8080/member 경로에 POST 메서드로 3개 필드 @NotBlank이고, null 값으로 날리면 400에러가 갈 것입니다.
아래와 같이 봐야할 것은 4가지 입니다.
- HTTP 상태 코드
- errors
- 오류난 메시지 (=defaultMessage)
- 오류난 필드 (= field)
순서2) 웹 어플리케이션으로 확인
index.html에서 이러한 오류가 나면 errorShowHTML 이라는 함수로 처리하도록 했습니다.
그냥 아무 것도 입력하지 않았으니 다 null 값으로 데이터를 보내겠죠!
그래서 각각의 에러난 필드에 맞춰서 에러 코드를 보이게 해주었습니다.
짠! 잘 작동하는 것을 볼 수 있겠지요!
![](https://t1.daumcdn.net/keditor/emoticon/friends1/large/009.gif)
한계점과 궁금증
MethodArgumentNotValidException 이라는 예외가 발생하여 DefaultHandlerExceptionResolver 가 자체적으로 오류 메시지와 JSON 을 응답해주고 있었습니다...
다시 한번 포스트맨의 JSON 응답 값을 보면 아무 것도 입력하지 않은 상태로 요청을 보냈기 때문에 rejectedValue 값이 null로 요청되었다고 나오는 것입니다.
만약 값을 입력했는데 유효성이 다르다면? 제가 값 입력한 것이 거절 되었으니 rejectedValue에 입력 값이 나옵니다.
우린 Front 대 Back, 기업 대 기업, 기업 대 개인 끼리 API 통신을 합니다.
그런데 되게 어지럽고 불필요한 데이터를 API Response 해줄 필요가 있을까요?
제가 Back 단 코드를 만지고 그냥 스프링이 내려주는 대로 API Response 해주면 편하지만 이 코드를 받는 Front 분들은 어떤 코드를 써야하고 어디가 필요한 값인지 헷갈릴거 같습니다..
한마디로 너무 불친절하다는 것이죠
해결 방안으로 @RestControllerAdvice 와 @ExceptionHandler 를 사용
@RestControllerAdvice
@ResponseBody + @ControllerAdvice 어노테이션이 합쳐진 것이며,
@RestControllerAdvice는 여러 컨트롤러에서 발생하는 예외를 한 곳에서 관리할 수 있는 어노테이션 입니다.
@ExceptionHandler
해당 컨트롤러에서 발생한 예외를 처리하는 역할을 합니다.
ErrorResult.class
예외 처리했을 때 내가 커스텀하여 내려주고 싶은 클래스 생성
@Setter
@Getter
@AllArgsConstructor
public class ErrorResult {
private Integer code;
private String message;
private Map<String, Object> data;
}
ValidControllerAdvice.class
중요!) 유효성 검사로 인하여 예외가 났을 때 처리할 함수!
설명은 어노테이션과 함께 하겠습니다.
// RestController 어노테이션 붙은 컨트롤러에 오류 났을 때만 호출
@RestControllerAdvice(annotations = RestController.class)
public class ValidControllerAdvice {
@ResponseStatus(HttpStatus.BAD_REQUEST) // HTTP 상태코드 400으로 응답
@ExceptionHandler(MethodArgumentNotValidException.class) // MethodArgumentNotValidException 예외 났을 때 처리
public ErrorResult MethodArgumentNotValidExHandler(MethodArgumentNotValidException e) {
Map<String, Object> data = new HashMap<>();
List<Map<String, Object>> list = new ArrayList<>();
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
for (FieldError fieldError : fieldErrors) {
Map<String, Object> field = new HashMap<>();
field.put("field", fieldError.getField());
field.put("msg", fieldError.getDefaultMessage());
field.put("rejectedValue", fieldError.getRejectedValue());
list.add(field);
}
data.put("connStatus", "fail");
data.put("errorList", list);
return new ErrorResult(HttpStatus.BAD_REQUEST.value(), "실패", data);
}
}
@RestControllerAdvice와 @ExceptionHandler의 사용법은 이글에 주제가 벗어나니 사용법은 익혀오시면 감사하겠습니다.
이제 보면 유효성 검사를 하여 예외가 발생하여 위에 메서드를 호출 할텐데 매개변수인 MethodArgumentNotValidException e을 어떻게 처리할 지 아래와 같이 보여 드리겠습니다.
데이터를 잘못 넣었을 상황 데이터 예시
1) 모두 null 값으로 넣었을 때
@RestControllerAdvice(annotations = RestController.class)
public class ValidControllerAdvice {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ErrorResult MethodArgumentNotValidExHandler(MethodArgumentNotValidException e) {
Map<String, Object> data = new HashMap<>();
data.put("connStatus", "fail");
log.info("getBindingResult : {}", e.getBindingResult());
List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
for (ObjectError allError : allErrors) {
log.info("allError.getDefaultMessage : {}", allError.getDefaultMessage());
log.info("allError.getObjectName : {}", allError.getObjectName());
}
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
for (FieldError fieldError : fieldErrors) {
log.info("fieldError.getDefaultMessage : {}", fieldError.getDefaultMessage());
log.info("fieldError.getField : {}", fieldError.getField());
log.info("fieldError.getObjectName : {}", fieldError.getObjectName());
log.info("fieldError.getRejectedValue : {}", fieldError.getRejectedValue());
}
log.info("getGlobalError : {}", e.getGlobalError());
log.info("getMessage : {}", e.getMessage());
log.info("getDetailMessageArguments : {}", e.getDetailMessageArguments());
log.info("getFieldError : {}", e.getFieldError());
log.info("getStatusCode : {}", e.getStatusCode());
return new ErrorResult(HttpStatus.BAD_REQUEST.value(), "실패", data);
}
}
/** 출력 값
getBindingResult : org.springframework.validation.BeanPropertyBindingResult: 3 errors
Field error in object 'memberRequestDto' on field 'phoneNumber': rejected value [null]; codes [Pattern.memberRequestDto.phoneNumber,Pattern.phoneNumber,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [memberRequestDto.phoneNumber,phoneNumber]; arguments []; default message [phoneNumber],[Ljakarta.validation.constraints.Pattern$Flag;@5a32ffe5,[0-9]{10,11}]; default message [10~11자리의 숫자만 입력가능합니다.]
Field error in object 'memberRequestDto' on field 'email': rejected value [null]; codes [NotBlank.memberRequestDto.email,NotBlank.email,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [memberRequestDto.email,email]; arguments []; default message [email]]; default message [공백일 수 없습니다]
Field error in object 'memberRequestDto' on field 'name': rejected value [null]; codes [NotBlank.memberRequestDto.name,NotBlank.name,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [memberRequestDto.name,name]; arguments []; default message [name]]; default message [이름은 공백일 수 없습니다.]
allError.getDefaultMessage : 공백일 수 없습니다
allError.getObjectName : memberRequestDto
allError.getDefaultMessage : 이름은 공백일 수 없습니다.
allError.getObjectName : memberRequestDto
allError.getDefaultMessage : 10~11자리의 숫자만 입력가능합니다.
allError.getObjectName : memberRequestDto
fieldError.getDefaultMessage : 공백일 수 없습니다
fieldError.getField : email
fieldError.getObjectName : memberRequestDto
fieldError.getRejectedValue : null
fieldError.getDefaultMessage : 이름은 공백일 수 없습니다.
fieldError.getField : name
fieldError.getObjectName : memberRequestDto
fieldError.getRejectedValue : null
fieldError.getDefaultMessage : 10~11자리의 숫자만 입력가능합니다.
fieldError.getField : phoneNumber
fieldError.getObjectName : memberRequestDto
fieldError.getRejectedValue : null
getGlobalError : null
getMessage : Validation failed for argument [0] in public aoxx.validation.domain.member.dto.MemberResponseDto aoxx.validation.domain.web.MemberController.join(aoxx.validation.domain.member.dto.MemberRequestDto) with 3 errors: [Field error in object 'memberRequestDto' on field 'phoneNumber': rejected value [null]; codes [Pattern.memberRequestDto.phoneNumber,Pattern.phoneNumber,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [memberRequestDto.phoneNumber,phoneNumber]; arguments []; default message [phoneNumber],[Ljakarta.validation.constraints.Pattern$Flag;@5a32ffe5,[0-9]{10,11}]; default message [10~11자리의 숫자만 입력가능합니다.]] [Field error in object 'memberRequestDto' on field 'email': rejected value [null]; codes [NotBlank.memberRequestDto.email,NotBlank.email,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [memberRequestDto.email,email]; arguments []; default message [email]]; default message [공백일 수 없습니다]] [Field error in object 'memberRequestDto' on field 'name': rejected value [null]; codes [NotBlank.memberRequestDto.name,NotBlank.name,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [memberRequestDto.name,name]; arguments []; default message [name]]; default message [이름은 공백일 수 없습니다.]]
getDetailMessageArguments :
getFieldError : Field error in object 'memberRequestDto' on field 'phoneNumber': rejected value [null]; codes [Pattern.memberRequestDto.phoneNumber,Pattern.phoneNumber,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [memberRequestDto.phoneNumber,phoneNumber]; arguments []; default message [phoneNumber],[Ljakarta.validation.constraints.Pattern$Flag;@5a32ffe5,[0-9]{10,11}]; default message [10~11자리의 숫자만 입력가능합니다.]
getStatusCode : 400 BAD_REQUEST
Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public aoxx.validation.domain.member.dto.MemberResponseDto aoxx.validation.domain.web.MemberController.join(aoxx.validation.domain.member.dto.MemberRequestDto) with 3 errors: [Field error in object 'memberRequestDto' on field 'phoneNumber': rejected value [null]; codes [Pattern.memberRequestDto.phoneNumber,Pattern.phoneNumber,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [memberRequestDto.phoneNumber,phoneNumber]; arguments []; default message [phoneNumber],[Ljakarta.validation.constraints.Pattern$Flag;@5a32ffe5,[0-9]{10,11}]; default message [10~11자리의 숫자만 입력가능합니다.]] [Field error in object 'memberRequestDto' on field 'email': rejected value [null]; codes [NotBlank.memberRequestDto.email,NotBlank.email,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [memberRequestDto.email,email]; arguments []; default message [email]]; default message [공백일 수 없습니다]] [Field error in object 'memberRequestDto' on field 'name': rejected value [null]; codes [NotBlank.memberRequestDto.name,NotBlank.name,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [memberRequestDto.name,name]; arguments []; default message [name]]; default message [이름은 공백일 수 없습니다.]] ]
*/
3) 이메일 필드만 제대로 입력 안했을 때
@RestControllerAdvice(annotations = RestController.class)
public class ValidControllerAdvice {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ErrorResult MethodArgumentNotValidExHandler(MethodArgumentNotValidException e) {
Map<String, Object> data = new HashMap<>();
data.put("connStatus", "fail");
log.info("getBindingResult : {}", e.getBindingResult());
List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
for (ObjectError allError : allErrors) {
log.info("allError.getDefaultMessage : {}", allError.getDefaultMessage());
log.info("allError.getObjectName : {}", allError.getObjectName());
}
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
for (FieldError fieldError : fieldErrors) {
log.info("fieldError.getDefaultMessage : {}", fieldError.getDefaultMessage());
log.info("fieldError.getField : {}", fieldError.getField());
log.info("fieldError.getObjectName : {}", fieldError.getObjectName());
log.info("fieldError.getRejectedValue : {}", fieldError.getRejectedValue());
}
log.info("getGlobalError : {}", e.getGlobalError());
log.info("getMessage : {}", e.getMessage());
log.info("getDetailMessageArguments : {}", e.getDetailMessageArguments());
log.info("getFieldError : {}", e.getFieldError());
log.info("getStatusCode : {}", e.getStatusCode());
return new ErrorResult(HttpStatus.BAD_REQUEST.value(), "실패", data);
}
}
/** 출력 값
getBindingResult : org.springframework.validation.BeanPropertyBindingResult: 3 errors
Field error in object 'memberRequestDto' on field 'phoneNumber': rejected value [null]; codes [Pattern.memberRequestDto.phoneNumber,Pattern.phoneNumber,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [memberRequestDto.phoneNumber,phoneNumber]; arguments []; default message [phoneNumber],[Ljakarta.validation.constraints.Pattern$Flag;@5a32ffe5,[0-9]{10,11}]; default message [10~11자리의 숫자만 입력가능합니다.]
Field error in object 'memberRequestDto' on field 'email': rejected value [null]; codes [NotBlank.memberRequestDto.email,NotBlank.email,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [memberRequestDto.email,email]; arguments []; default message [email]]; default message [공백일 수 없습니다]
Field error in object 'memberRequestDto' on field 'name': rejected value [null]; codes [NotBlank.memberRequestDto.name,NotBlank.name,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [memberRequestDto.name,name]; arguments []; default message [name]]; default message [이름은 공백일 수 없습니다.]
allError.getDefaultMessage : 이메일 양식을 지켜주세요
allError.getObjectName : memberRequestDto
fieldError.getDefaultMessage : 이메일 양식을 지켜주세요
fieldError.getField : email
fieldError.getObjectName : memberRequestDto
fieldError.getRejectedValue : aoxx.co.kr
getGlobalError : null
getMessage : Validation failed for argument [0] in public aoxx.validation.domain.member.dto.MemberResponseDto aoxx.validation.domain.web.MemberController.join(aoxx.validation.domain.member.dto.MemberRequestDto): [Field error in object 'memberRequestDto' on field 'email': rejected value [aoxx.co.kr]; codes [Email.memberRequestDto.email,Email.email,Email.java.lang.String,Email]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [memberRequestDto.email,email]; arguments []; default message [email],[Ljakarta.validation.constraints.Pattern$Flag;@71633d19,.*]; default message [이메일 양식을 지켜주세요]]
getDetailMessageArguments :
getFieldError : Field error in object 'memberRequestDto' on field 'email': rejected value [aoxx.co.kr]; codes [Email.memberRequestDto.email,Email.email,Email.java.lang.String,Email]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [memberRequestDto.email,email]; arguments []; default message [email],[Ljakarta.validation.constraints.Pattern$Flag;@71633d19,.*]; default message [이메일 양식을 지켜주세요]
getStatusCode : 400 BAD_REQUEST
Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public aoxx.validation.domain.member.dto.MemberResponseDto aoxx.validation.domain.web.MemberController.join(aoxx.validation.domain.member.dto.MemberRequestDto): [Field error in object 'memberRequestDto' on field 'email': rejected value [aoxx.co.kr]; codes [Email.memberRequestDto.email,Email.email,Email.java.lang.String,Email]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [memberRequestDto.email,email]; arguments []; default message [email],[Ljakarta.validation.constraints.Pattern$Flag;@71633d19,.*]; default message [이메일 양식을 지켜주세요]] ]
*/
기능 완료
값을 입력하지 않고 요청했을 때 null 값으로 갔을 겁니다.
Index.html
errorShowHTML JS 함수에서 제가 만든 JSON 규격으로 변경해야하므로 아래 코드로 변경해줍니다.
// 에러 메시지 출력 함수
function errorShowHTML(response){
const errorList = response.responseJSON.data.errorList;
errorList.map(error => {
let field = error.field;
let template = `
<div class="error-message text-danger text-small" id="error-${field}">${error.msg}</div>
`;
$(`#${field}`).after(template);
});
}
짠, 잘 출력되는걸 볼 수 있죠!!!!
이제 이렇게 유효성 검사해서 에러를 컨트롤 하도록 합니다!!
![](https://t1.daumcdn.net/keditor/emoticon/niniz/large/047.gif)
감사합니다.
'백엔드 > 🌸Spring' 카테고리의 다른 글
[Spring] Spring Boot3에 Swagger 적용하기 (6) | 2024.10.17 |
---|---|
[Spring] ThreadLocal : 동시성을 해결하는 물품 보관소 (0) | 2024.05.10 |
[Spring] ArgumentResolver : @Pathvariable 요청 정보 가져오기 (0) | 2024.04.24 |
[Spring] 첨부파일과 여러 데이터 전송하기 (0) | 2024.04.10 |
[Spring] 빈이 중복 조회가 된다면? : @Autowired, @Qualifier, @Primary 의존성 주입의 다양한 접근 방법 (0) | 2023.12.19 |
- Total
- Today
- Yesterday
- Mac
- Spring Security
- Fetch
- 템플릿
- 깃허브 액션
- spring
- 개발자
- 자바스크립트
- 오라클
- 프로세스
- git
- 디자인패턴
- DBeaver
- 데이터 베이스
- Front
- aws
- 네트워크
- 비동기
- 개발환경
- java
- AJAX
- 개발
- 코딩테스트
- JavaScript
- Cors
- 개발블로그
- 프론트
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |