SPRING Validation 모듈
- 설치
- build.gradle dependecies에 추가
implementation 'org.springframework.boot:spring-boot-starter-validation'
- 설치 확인
- 외부라이브러리 / jakarta.validation, spring-boot-starter-validation


- 사용
- 주로 RequestDTO에서 검증
- 컨트롤러 중 RequestDTO 파라미터로 사용하는 메서드에서 검증 결과 처리
- @NotNull : null 만 허용 안됨
- @NotEmpty : null 은 되는데 빈문자는 안됨
- @NotBlank : null 도 안되고 빈문자도 안됨
public class ReplyPostDto {
@NotBlank
private String text; // 댓글 내용
@NotBlank
private String author; // 댓글 작성자
@NotNull
private long bno; // 원본 글번호
}

@PostMapping
public ResponseEntity<?> posts(@Validated @RequestBody ReplyPostDto dto
, BindingResult result // 입력값 검증 결과 데이터를 갖고 있는 객체
) {
log.debug("검증결과: {}", result.toString());
if(result.hasErrors()) {
Map<String, String> errors = makeValidationMessageMap(result);
return ResponseEntity
.badRequest()
.body(errors);
}
...
}
검증 결과 BindingResult
- 입력값 검증 결과 데이터를 갖고 있는 객체
public ResponseEntity<?> posts(
@Validated @RequestBody ReplyPostDto dto ,
BindingResult result) { ... }

** 검증결과 예시
더보기
검증결과: org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'replyPostDto' on field 'text': rejected value [];
codes [Size.replyPostDto.text,Size.text,Size.java.lang.String,Size];
arguments [org.springframework.context.support.DefaultMessageSourceResolvable:
codes [replyPostDto.text,text]; arguments []; default message [text],300,1];
default message [크기가 1에서 300 사이여야 합니다]
Field error in object 'replyPostDto' on field 'text': rejected value [];
codes [NotBlank.replyPostDto.text,NotBlank.text,NotBlank.java.lang.String,NotBlank];
arguments [org.springframework.context.support.DefaultMessageSourceResolvable:
codes [replyPostDto.text,text]; arguments [];
default message [text]]; default message [공백일 수 없습니다]
검증 결과 메세지
- key: 에러가 발생한 프로퍼티
ex) error.getField() - value: 에러 원인 메세지
ex) error.getDefaultMessage()
private Map<String, String> makeValidationMessageMap(BindingResult result) {
Map<String, String> errors = new HashMap<>();
// 에러정보가 모여있는 리스트
List<FieldError> fieldErrors = result.getFieldErrors();
for (FieldError error : fieldErrors) {
errors.put(error.getField(), error.getDefaultMessage());
}
return errors;
}
AJAX
- 비동기 관리 라이브러리
동기코드(sync) & 비동기코드(async)
- 동기코드 : 한 작업이 완료될 때까지 다음 작업은 대기 상태
- 비동기코드 : 특정 작업이 완료되기를 기다리지 않고 다음 작업을 실행
- 콜백, 프로미스, fetch API, async/await 등의 패턴을 사용하여 비동기 코드를 관리
XMLHttpRequest 객체
- method: HTTP 메서드 (예: "GET", "POST")
- url: 요청을 보낼 URL
- async: 비동기적으로 요청을 할 것인지를 결정 (기본값은 `true`)
// 1. 객체 생성
const xhr = new XMLHttpRequest();
// 2. 요청 초기화
xhr.open(method, url, async);
// 3. 응답 처리
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 400) {
console.log(xhr.responseText);
} else {
console.error('서버에서 에러 응답:', xhr.statusText);
}
};
xhr.onerror = function() {
console.error('요청 중 에러 발생');
};
// 4. 요청 보내기
xhr.send();
** 주의사항
- 보안: 같은 출처 정책(Same-Origin Policy)로 인해 다른 도메인의 리소스에 대한 요청을 제한적 수행
- 현대적인 대안: XMLHttpRequest는 오래된 API이므로 fetch API나 다른 라이브러리(예: Axios)를 사용하여 HTTP 요청 수행을 권장
- fetch는 더 깔끔한 API와 프로미스 기반의 접근 방식을 제공
콜백 지옥 Callback Hell
- 여러 비동기 연산을 순서대로 처리해야 할 때 발생하는 현상
- 각 비동기 연산이 완료된 후 다음 연산을 수행하기 위해 콜백 함수 내부에 또 다른 콜백 함수를 중첩해 사용
콜백 지옥 예시
더보기
fetchFirstData(function(error1, data1) {
if (error1) {
console.error('Error:', error1);
} else {
fetchSecondData(data1, function(error2, data2) {
if (error2) {
console.error('Error:', error2);
} else {
fetchThirdData(data2, function(error3, data3) {
if (error3) {
console.error('Error:', error3);
} else {
console.log('Final Data:', data3);
}
});
}
});
}
});
프로미스 Promise
- 비동기 작업의 최종 완료 또는 실패를 나타내는 객체
- Promise를 사용하면, 중첩된 콜백 구조 대신 then 메서드를 연속적으로 체인화하여 각 단계의 결과를 순차적으로 처리 가능
- then() 메서드를 제공하여 비동기 연산이 완료되었을 때의 처리를 지정 가능
- catch() 메서드를 통해 오류 처리 가능
- promiseState
- pending: 아직 이행되거나 거부되지 않은 초기 상태
- fulfilled: 연산이 성공적으로 완료 → resolve() 함수 실행
- rejected: 연산 중 에러가 발생 → reject() 함수 실행
let promise = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('Done!');
}, 1000);
});
promise.then(function(value) {
console.log(value); // Outputs: 'Done!'
});
* Promise 메서드: Promise.all, Promise.race, Promise.allSettled 에 대해서는 추후에 자세히 다룰 예정
fetch API
- Fetch API는 네트워크 요청을 수행하기 위한 인터페이스를 제공
- XMLHttpRequest에 비해 더 유연하고 강력하며, Promise 기반의 구조로 설계
- Fetch API는 response 객체(Promise 타입)을 반환하며, 이를 통해 여러 메서드와 속성에 액세스
- 가장 기본적인 형태의 Fetch 요청은 URL을 지정하여 리소스를 가져오는 것
- fetch 함수의 두 번째 인수로 여러 옵션을 설정할 수 있는 객체를 전달 가능
// fetch 함수
fetch(url, 옵션).then()
** 옵션 설정
- method: HTTP 메서드 (GET, POST, PUT, DELETE 등)
- headers: 요청 헤더
- body: 요청 본문
- mode: 요청 모드 (no-cors, cors, same-origin 등)
- credentials: 인증 설정 (include, same-origin, omit)
** response 객체
- response.text(): 응답을 텍스트로 반환
- response.json(): 응답을 JSON으로 파싱하여 반환
- response.blob(): 응답을 Blob 객체로 반환 (예: 이미지 파일)
- response.headers: 응답 헤더를 반환
- response.status: HTTP 상태 코드를 반환 (예: 200, 404 등)
GET 요청
fetch('url')
.then(response => response.json()
.then(data => data처리)
- data를 배열 형태로 받아서 HTML tag를 만들고 추가하는 DOM 을 통해 화면에 렌더링 가능


** JSON 실습 참고 사이트
https://jsonplaceholder.typicode.com