57. 유효성 검사

송민경's avatar
Apr 02, 2024
57. 유효성 검사

1. MyValidationHandler 만들기

  • 인터셉트와 비슷함
  • 모든 컨트롤러에 있는 모든 파일이 실행되기 전에 실행
    • notion image
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____________________"); } }
notion image
notion image
notion image
 

2. JoinPoint

  • getArgs() : 조인 포인트의 메서드 호출 시 전달된 인수들을 반환
  • getThis() : 조인 포인트로부터 대상 객체 반환
  • getTarget() : 조인 포인트의 대상 객체 반환
  • getSignature() : 조인 포인트의 서명(메서드에 대한 정보) 반환
  • toLongString() : 조인 포인트에 대한 자세한 설명 반환
  • toShortString() : 조인 포인트에 대한 간단한 설명 반환
  • getStaticPart() : 정적인 정보(메서드, 생성자, 정적 초기화 블록 등)를 반환
notion image
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____________________"); } }
notion image
  • 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____________________"); } }
notion image
  • 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____________________"); } }
notion image
notion image
 
Share article
RSSPowered by inblog