
1. MyValidationHandler 만들기
- 인터셉트와 비슷함
- 모든 컨트롤러에 있는 모든 파일이 실행되기 전에 실행

package shop.mtcoding.blog._core.errors;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect // AOP 등록
@Component // IoC 등록
public class MyValidationHandler {
// Advice (부가 로직 메서드)
// Advice가 수행될 위치 == PointCut
@Before("@annotation(org.springframework.web.bind.annotation.GetMapping)") // PointCut
public void hello(JoinPoint jp){
System.out.println("MyValidationHandler: hello____________________");
}
}



2. JoinPoint
- getArgs() : 조인 포인트의 메서드 호출 시 전달된 인수들을 반환
- getThis() : 조인 포인트로부터 대상 객체 반환
- getTarget() : 조인 포인트의 대상 객체 반환
- getSignature() : 조인 포인트의 서명(메서드에 대한 정보) 반환
- toLongString() : 조인 포인트에 대한 자세한 설명 반환
- toShortString() : 조인 포인트에 대한 간단한 설명 반환
- getStaticPart() : 정적인 정보(메서드, 생성자, 정적 초기화 블록 등)를 반환

package shop.mtcoding.blog._core.errors;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect // AOP 등록
@Component // IoC 등록
public class MyValidationHandler {
// Advice (부가 로직 메서드)
// Advice가 수행될 위치 == PointCut
@Before("@annotation(org.springframework.web.bind.annotation.GetMapping)") // PointCut
public void hello(JoinPoint jp){
Object[] args = jp.getArgs(); // Args: 파라미터 -> object를 리턴
System.out.println("크기 : " + args.length);
System.out.println("MyValidationHandler: hello____________________");
}
}

- GetMapping에서는 바디가 필요없음
- 유효성 검사가 없음
package shop.mtcoding.blog._core.errors;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect // AOP 등록
@Component // IoC 등록
public class MyValidationHandler {
// Advice (부가 로직 메서드)
// Advice가 수행될 위치 == PointCut
@Before("@annotation(org.springframework.web.bind.annotation.GetMapping)") // PointCut
public void hello(JoinPoint jp){
Object[] args = jp.getArgs(); // Args: 파라미터 -> object를 리턴
System.out.println("크기 : " + args.length);
for(Object arg : args) {
System.out.println("매개변수 : " + arg);
}
System.out.println("MyValidationHandler: hello____________________");
}
}

- PostMapping일때 유효성 검사가 실행
- @Valid : 유효성 검사를 실행
- 에러가 나면 errors로 전달
@PostMapping("/api/boards")
public ResponseEntity<?> save(@Valid @RequestBody BoardRequest.SaveDTO reqDTO, Errors errors) {
User sessionUser = (User) session.getAttribute("sessionUser");
BoardResponse.DTO respDTO = boardService.글쓰기(reqDTO, sessionUser);
return ResponseEntity.ok(new ApiUtil(respDTO));
}
3. 유효성 제한
- @NotNull : 값이 null이 아닌지 확인
- @NotEmpty : 값이 null이 아니고, 빈 문자열("")이나 빈 컬렉션([])이 아닌지 확인
- @NotBlank : 값이 null이 아니고, 빈 문자열("")이 아닌지 확인하며, 문자열의 trim() 결과가 빈 문자열이 아닌지도 확인
- @Size(min, max) : 값의 크기가 주어진 범위 내에 있는지 확인
- @Min(value) : 값이 주어진 최솟값 이상인지 확인
- @Max(value) : 값이 주어진 최댓값 이하인지 확인
- @Email : 값이 이메일 주소의 형식인지 확인
- @Pattern(regex) : 값이 지정된 정규 표현식과 일치하는지 확인
- @AssertTrue : 값이 true인지 확인
- @AssertFalse : 값이 false인지 확인
package shop.mtcoding.blog.board;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Size;
import lombok.Data;
import shop.mtcoding.blog.user.User;
public class BoardRequest {
@Data
public static class UpdateDTO {
private String title;
private String content;
}
@Data
public static class SaveDTO {
@Size(min = 1, max = 10, message = "제목은 10자를 초과할 수 없습니다")
@NotEmpty(message = "제목은 공백일 수 없습니다") // null도 안되고, 공백만 있는 것도 안됨
private String title;
@NotEmpty(message = "내용은 공백일 수 없습니다")
private String content;
// DTO를 클라이언트로 부터 받아서, PC에 전달하기 위해 사용
public Board toEntity(User user){
return Board.builder()
.title(title)
.content(content)
.user(user)
.build();
}
}
}
- 데이터 유효성 검사를 수행한 후 발생한 오류를 처리하는 코드
package shop.mtcoding.blog.board;
import jakarta.servlet.http.HttpSession;
import jakarta.validation.Valid;
import jdk.swing.interop.SwingInterOpUtils;
import lombok.RequiredArgsConstructor;
import org.apache.tomcat.util.net.jsse.JSSEUtil;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import shop.mtcoding.blog._core.errors.exception.Exception400;
import shop.mtcoding.blog._core.utils.ApiUtil;
import shop.mtcoding.blog.user.User;
import java.util.List;
@RequiredArgsConstructor // final이 붙은 친구들의 생성자를 만들어줘
@RestController // new BoardController(IoC에서 BoardRepository를 찾아서 주입) -> IoC 컨테이너 등록
public class BoardController {
private final BoardService boardService;
private final HttpSession session;
// TODO: 글목록조회 API 필요 -> @GetMapping("/")
@GetMapping("/")
public ResponseEntity<?> main() {
List<BoardResponse.MainDTO> respDTO = boardService.글목록조회();
return ResponseEntity.ok(new ApiUtil(respDTO));
}
// TODO: 글상세보기 API 필요 -> @GetMapping("/api/boards/{id}/detail")
@GetMapping("/api/boards/{id}/detail")
public ResponseEntity<?> detail(@PathVariable Integer id) {
User sessionUser = (User) session.getAttribute("sessionUser");
BoardResponse.DetailDTO respDTO = boardService.글상세보기(id, sessionUser);
return ResponseEntity.ok(new ApiUtil(respDTO));
}
// TODO: 글조회 API 필요 -> @GetMapping("/api/boards/{id}")
@GetMapping("/api/boards/{id}")
public ResponseEntity<?> findOne(@PathVariable Integer id) {
BoardResponse.DTO respDTO = boardService.글조회(id);
return ResponseEntity.ok(new ApiUtil(respDTO));
}
@PostMapping("/api/boards")
public ResponseEntity<?> save(@Valid @RequestBody BoardRequest.SaveDTO reqDTO, Errors errors) {
if (errors.hasErrors()) {
for (FieldError error : errors.getFieldErrors()) {
System.out.println(error.getField());
System.out.println(error.getDefaultMessage());
throw new Exception400(error.getDefaultMessage() + " : " + error.getField());
}
}
User sessionUser = (User) session.getAttribute("sessionUser");
BoardResponse.DTO respDTO = boardService.글쓰기(reqDTO, sessionUser);
return ResponseEntity.ok(new ApiUtil(respDTO));
}
@PutMapping("/api/boards/{id}")
public ResponseEntity<?> update(@Valid @PathVariable Integer id, @RequestBody BoardRequest.UpdateDTO reqDTO, Errors errors) {
if (errors.hasErrors()) {
for (FieldError error : errors.getFieldErrors()) {
System.out.println(error.getField());
System.out.println(error.getDefaultMessage());
throw new Exception400(error.getDefaultMessage() + " : " + error.getField());
}
}
User sessionUser = (User) session.getAttribute("sessionUser");
BoardResponse.DTO respDTO = boardService.글수정(id, sessionUser.getId(), reqDTO);
return ResponseEntity.ok(new ApiUtil(respDTO));
}
@DeleteMapping("/api/boards/{id}")
public ResponseEntity<?> delete(@PathVariable Integer id) {
User sessionUser = (User) session.getAttribute("sessionUser");
boardService.글삭제(id, sessionUser.getId());
return ResponseEntity.ok(new ApiUtil(null));
}
}
- MyValidationHandler 에 발생한 오류를 처리하는 코드 넣고 CONTROLLER에서 삭제하기
package shop.mtcoding.blog._core.errors;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import shop.mtcoding.blog._core.errors.exception.Exception400;
@Aspect // AOP 등록
@Component // IoC 등록
public class MyValidationHandler {
// Advice (부가 로직 메서드)
// Advice가 수행될 위치 == PointCut
@Before("@annotation(org.springframework.web.bind.annotation.PostMapping)") // PointCut
public void hello(JoinPoint jp) {
Object[] args = jp.getArgs(); // Args: 파라미터 -> object를 리턴
System.out.println("크기 : " + args.length);
for (Object arg : args) {
if (arg instanceof Errors) {
Errors errors = (Errors) arg; // 에러스타입의 arg를 다운캐스팅
if (errors.hasErrors()) {
for (FieldError error : errors.getFieldErrors()) {
System.out.println(error.getField());
System.out.println(error.getDefaultMessage());
throw new Exception400(error.getDefaultMessage() + " : " + error.getField());
}
}
}
}
System.out.println("MyValidationHandler: hello____________________");
}
}


Share article