backend
  • README
  • DOCS
    • Java Docs
    • Servlet Docs
    • JSP Docs
    • DB & SQL Docs
    • Spring Boot Docs
    • Spring Security Docs
    • AWS Docs
  • 설치하기
    • Intellij 설정
  • 자바
    • 01 Java란?
    • 02 자바 시작하기
    • 03 자료형과 연산자
    • 04 제어문
    • 05 메소드
    • 06 클래스 기초
      • Static 보충자료
      • 패키지 보충자료
    • 07 객체지향 프로그래밍
    • 08 클래스 더 알아보기
      • 열거형 ENUM 보충자료
    • 09 클래스와 자료형
      • 다형성 보충자료
      • 제네릭 보충자료
    • 10 컬렉션 프레임워크
      • 컬렉션 프레임워크 보충자료
    • 11 람다식과 함수형 프로그래밍
      • 람다식 보충자료
    • 12 오류 대비하기
      • 오류 보충자료
    • 13 멀티태스킹
      • 멀티태스킹 보충자료
    • 교재보충
      • java.lang
  • 스프링
    • 서블릿, JSP
      • 05 Servlet(서블릿)
        • 서블릿 보충자료
        • 서블릿 추가코드
        • XML, YAML, JSON
      • 06 JSP(자바 서버 페이지)
        • JSP 보충자료
      • 07 JSTL(JSP 스탠다드 태그 라이브러리)
        • JSTL 보충자료
      • 08 Cookie(쿠키), Session(세션)
      • 09 서블릿,필터,리스너
        • 서블릿,필터,리스너 보충자료
      • 11 도서관리 프로젝트 실습
    • Spring Boot
      • 01 스프링 등장 배경, 객체지향
        • 스프링 등장 배경, 객체지향 보충자료
      • 02 IOC(제어의 역전), DI(의존성 주입)
        • IOC 보충자료
        • DI 보충자료
      • 03 스프링 구조
        • 스프링 구조 보충설명
      • 04 테스트코드 실습
      • 05 스프링 빈 설정
        • 스프링 빈 설정 보충자료
      • 06 싱글톤
        • 싱글톤 보충 자료
      • 07 스프링 빈 자동설정
        • 스프링 빈 자동설정 보충자료
      • 08 빈 생명주기
        • 빈 생명주기 보충자료
      • 09 빈 스코프
        • 빈 스코프 보충자료
      • 10 스프링 MVC
        • 스프링 MVC 보충자료
        • 데이터베이스 연동에 필요한 부분
      • 11 Validation(검증)
        • Validation(검증) 보충자료
      • 12 Bean Validation(빈검증)
        • Bean Validation(빈검증) 보충자료
      • 13 예외처리
        • 예외처리 보충자료
      • 14 타입변환
      • 15 JDBC(Java Database Connectivity)
      • 16 커넥션풀
      • 17 트랜잭션
        • 트랜잭션 보충자료
      • 18 JDBC 템플릿 활용
      • 19 MyBatis
      • 20 JPA(Java Persistence API)
      • 22 게시판 프로젝트 실습
    • Spring Security
      • 보안(Security)
      • Spring Security
      • 2. Spring Security 알아보기
        • 보안 위협 실제 사례와 방어 전략
      • 3. Spring Security 기본 동작 흐름
      • 4. Spring Security로 인증 권한 추가하기
        • Spring Security의 인증 및 인가
      • 5. Spring Security에서 세션 관리하기
        • 세션(Session)과 쿠키(Cookie) 비교, 토큰(Token)과의 관계
        • 해싱 및 해싱알고리즘
        • base64
      • 6. Spring Security 악용 보호
        • SameSite
      • 7. Spring Security로 인가 권한 추가하기
      • 8. Bcrypt(비크립트) 암호화
      • OAuth2 적용하기
  • 네트워크
    • HTTP
    • OSI 7계층
  • DB&SQL
    • 01 Database(데이터베이스)와 SQL 개요
    • 02 관계형 모델
    • 03 집합
    • 04 JOIN 연산
    • 05 MySQL
      • 세이브포인트
      • DBeaver, Mysql 오토커밋 설정 관련
    • 06 SQL 기초
      • 예시데이터 쿼리문
    • 07 SQL 실습
      • 실습 스키마
    • 08 Join 활용
      • 실습스키마
    • 09 SQL 활용
      • 실습스키마
    • 10 정규화
      • 실습 스키마
    • 데이터타입
    • 예시 프로젝트 스키마 구성
  • AWS
    • SSL 연결하기
    • 보충설명
Powered by GitBook
On this page
  1. 스프링
  2. Spring Boot

11 Validation(검증)

p197 ~ 199 - src/main/java/spring/mvc/controller/ValidationFormController

@Slf4j
@Controller
@RequestMapping("/validation/form")
public class ValidationFormController {

    private final BookService bookService;

    public ValidationFormController(BookService bookService) {
        this.bookService = bookService;
    }

    @GetMapping("/books")
    public String showBookForm(Model model) {
        model.addAttribute("book", new Book());  // 빈 Book 객체를 모델에 추가
        return "validation/bookForm";
    }

    // CREATE: 책 생성 - 수동 검증
    @PostMapping("/books")
    public String createBook(@ModelAttribute Book book, Model model) {
        // 수동 검증 로직
        if (book.getTitle() == null || book.getTitle().trim().isEmpty()) {
            model.addAttribute("error", "책 제목은 필수 입력값입니다.");
            return "validation/bookForm";
        }
        if (book.getPublisher() == null || book.getPublisher().trim().isEmpty()) {
            model.addAttribute("error", "저자는 필수 입력값입니다.");
            return "validation/bookForm";
        }
        if (book.getSalePrice() < 0) {
            model.addAttribute("error", "책 가격은 0 이상이어야 합니다.");
            return "validation/bookForm";
        }

        // 검증이 통과된 경우 책 생성
        Book createdBook = bookService.createBook(book);
        model.addAttribute("book", createdBook);
        model.addAttribute("success", "책이 성공적으로 생성되었습니다!");
        return "validation/bookForm";  // 동일한 폼 페이지로 리다이렉트하여 성공 메시지 표시
    }

    // READ: ID로 책 검색 - 수동 검증
    @GetMapping("/books/{bookIdx}")
    public String getBookById(@PathVariable Long bookIdx, Model model) {
        // 수동 검증 로직
        if (bookIdx == null || bookIdx <= 0) {
            model.addAttribute("error", "책 ID는 0보다 큰 값이어야 합니다.");
            return "validation/bookDetail";
        }

        Optional<Book> book = bookService.getBookById(bookIdx);
        if (book.isPresent()) {
            model.addAttribute("book", book.get());
            return "validation/bookDetail"; // 책 정보를 보여줄 뷰 페이지
        } else {
            model.addAttribute("error", "책을 찾을 수 없습니다.");
            return "validation/bookDetail";
        }
    }

    // UPDATE: 책 정보 수정 - 수동 검증
    @PostMapping("/books/{bookIdx}/update")
    public String updateBook(@PathVariable Long bookIdx, @ModelAttribute Book updatedBook, Model model) {
        // 수동 검증 로직
        if (bookIdx == null || bookIdx <= 0) {
            model.addAttribute("error", "책 ID는 0보다 큰 값이어야 합니다.");
            return "validation/bookForm";
        }
        if (updatedBook.getTitle() == null || updatedBook.getTitle().trim().isEmpty()) {
            model.addAttribute("error", "책 제목은 필수 입력값입니다.");
            return "validation/bookForm";
        }
        if (updatedBook.getPublisher() == null || updatedBook.getPublisher().trim().isEmpty()) {
            model.addAttribute("error", "저자는 필수 입력값입니다.");
            return "validation/bookForm";
        }
        if (updatedBook.getSalePrice() < 0) {
            model.addAttribute("error", "책 가격은 0 이상이어야 합니다.");
            return "validation/bookForm";
        }

        Optional<Book> book = bookService.updateBook(bookIdx, updatedBook);
        if (book.isPresent()) {
            model.addAttribute("book", book.get());
            model.addAttribute("success", "책 정보가 성공적으로 수정되었습니다!");
            return "validation/bookForm"; // 동일한 폼 페이지로 리다이렉트하여 성공 메시지 표시
        } else {
            model.addAttribute("error", "책을 찾을 수 없습니다.");
            return "validation/bookForm";
        }
    }

    // DELETE: 책 삭제 - 수동 검증
    @PostMapping("/books/{bookIdx}/delete")
    public String deleteBook(@PathVariable Long bookIdx, Model model) {
        // 수동 검증 로직
        if (bookIdx == null || bookIdx <= 0) {
            model.addAttribute("error", "책 ID는 0보다 큰 값이어야 합니다.");
            return "validation/bookDetail";
        }

        boolean deleted = bookService.deleteBook(bookIdx);
        if (deleted) {
            model.addAttribute("message", "책이 성공적으로 삭제되었습니다.");
            return "validation/bookDetail"; // 동일한 페이지에서 메시지 표시
        } else {
            model.addAttribute("error", "책을 찾을 수 없습니다.");
            return "validation/bookDetail";
        }
    }

    // BOOKING: 책 대여 - 수동 검증
    @PostMapping("/books/{bookIdx}/rent/{userIdx}")
    public String rentBook(@PathVariable Long bookIdx, @PathVariable Long userIdx, Model model) {
        // 수동 검증 로직
        if (bookIdx == null || bookIdx <= 0) {
            model.addAttribute("error", "책 ID는 0보다 큰 값이어야 합니다.");
            return "validation/bookDetail";
        }
        if (userIdx == null || userIdx <= 0) {
            model.addAttribute("error", "사용자 ID는 0보다 큰 값이어야 합니다.");
            return "validation/bookDetail";
        }

        try {
            Optional<Book> rentedBook = bookService.rentBook(bookIdx, userIdx);
            if (rentedBook.isPresent()) {
                model.addAttribute("book", rentedBook.get());
                model.addAttribute("success", "책이 성공적으로 대여되었습니다!");
                return "validation/bookDetail"; // 동일한 페이지에서 메시지 표시
            } else {
                model.addAttribute("error", "책을 찾을 수 없습니다.");
                return "validation/bookDetail";
            }
        } catch (IllegalStateException | IllegalArgumentException e) {
            log.error("책 대여 오류: {}", e.getMessage());
            model.addAttribute("error", e.getMessage());
            return "validation/bookDetail";
        }
    }

    // RETURN: 책 반납 - 수동 검증
    @PostMapping("/books/{bookIdx}/return/{userIdx}")
    public String returnBook(@PathVariable Long bookIdx, @PathVariable Long userIdx, Model model) {
        // 수동 검증 로직
        if (bookIdx == null || bookIdx <= 0) {
            model.addAttribute("error", "책 ID는 0보다 큰 값이어야 합니다.");
            return "validation/bookDetail";
        }
        if (userIdx == null || userIdx <= 0) {
            model.addAttribute("error", "사용자 ID는 0보다 큰 값이어야 합니다.");
            return "validation/bookDetail";
        }

        try {
            Optional<Book> returnedBook = bookService.returnBook(bookIdx, userIdx);
            if (returnedBook.isPresent()) {
                model.addAttribute("book", returnedBook.get());
                model.addAttribute("success", "책이 성공적으로 반납되었습니다!");
                return "validation/bookDetail"; // 동일한 페이지에서 메시지 표시
            } else {
                model.addAttribute("error", "책을 찾을 수 없습니다.");
                return "validation/bookDetail";
            }
        } catch (IllegalStateException | IllegalArgumentException e) {
            log.error("책 반납 오류: {}", e.getMessage());
            model.addAttribute("error", e.getMessage());
            return "validation/bookDetail";
        }
    }
}

p202 - src/main/java/spring/mvc/controller/ValidationFormBindingController

@Slf4j
@Controller
@RequestMapping("/validation/form/binding")
public class ValidationFormBindingController {

    private final BookService bookService;

    public ValidationFormBindingController(BookService bookService) {
        this.bookService = bookService;
    }

    @GetMapping("/books")
    public String showBookForm(Model model) {
        model.addAttribute("book", new Book());  // 빈 Book 객체를 모델에 추가
        return "validation/bookFormBinding";
    }

    // CREATE: 책 생성 - BindingResult 사용
    @PostMapping("/books")
    public String createBook(@ModelAttribute Book book, BindingResult bindingResult, Model model) {
        // 수동 검증 로직
        if (book.getTitle() == null || book.getTitle().trim().isEmpty()) {
            bindingResult.rejectValue("title", "error.title", "책 제목은 필수 입력값입니다.");
        }
        if (book.getPublisher() == null || book.getPublisher().trim().isEmpty()) {
            bindingResult.rejectValue("publisher", "error.publisher", "저자는 필수 입력값입니다.");
        }
        if (book.getSalePrice() < 0) {
            bindingResult.rejectValue("salePrice", "error.salePrice", "책 가격은 0 이상이어야 합니다.");
        }

        // 검증 실패 시, 다시 폼 페이지로 이동
        if (bindingResult.hasErrors()) {
            log.info("errors = {}", bindingResult);
            return "validation/bookFormBinding";
        }

        // 검증이 통과된 경우 책 생성
        Book createdBook = bookService.createBook(book);
        model.addAttribute("book", createdBook);
        model.addAttribute("success", "책이 성공적으로 생성되었습니다!");
        return "validation/bookFormBinding";
    }

    // READ: ID로 책 검색 - 수동 검증
    @GetMapping("/books/{bookIdx}")
    public String getBookById(@PathVariable Long bookIdx, Model model) {
        if (bookIdx <= 0) {
            model.addAttribute("error", "책 ID는 0보다 큰 값이어야 합니다.");
            return "validation/bookDetailBinding";
        }

        Optional<Book> book = bookService.getBookById(bookIdx);
        if (book.isPresent()) {
            model.addAttribute("book", book.get());
        } else {
            model.addAttribute("error", "책을 찾을 수 없습니다.");
        }
        return "validation/bookDetailBinding";
    }

    // UPDATE: 책 정보 수정 - BindingResult 사용
    @PostMapping("/books/{bookIdx}/update")
    public String updateBook(@PathVariable Long bookIdx, @ModelAttribute Book updatedBook, BindingResult bindingResult, Model model) {
        // 수동 검증 로직
        if (updatedBook.getTitle() == null || updatedBook.getTitle().trim().isEmpty()) {
            bindingResult.rejectValue("title", "error.title", "책 제목은 필수 입력값입니다.");
        }
        if (updatedBook.getPublisher() == null || updatedBook.getPublisher().trim().isEmpty()) {
            bindingResult.rejectValue("publisher", "error.publisher", "저자는 필수 입력값입니다.");
        }
        if (updatedBook.getSalePrice() < 0) {
            bindingResult.rejectValue("salePrice", "error.salePrice", "책 가격은 0 이상이어야 합니다.");
        }

        // 검증 실패 시, 다시 폼 페이지로 이동
        if (bindingResult.hasErrors()) {
            return "validation/bookFormBinding";
        }

        Optional<Book> book = bookService.updateBook(bookIdx, updatedBook);
        if (book.isPresent()) {
            model.addAttribute("book", book.get());
            model.addAttribute("success", "책 정보가 성공적으로 수정되었습니다!");
        } else {
            model.addAttribute("error", "책을 찾을 수 없습니다.");
        }
        return "validation/bookFormBinding";
    }
}

p203 - src/main/resources/templates/validation/bookFormBinding.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <title>책 관리 폼</title>
</head>
<body>
<h1>책 관리</h1>

<!-- 에러 메시지 표시 -->
<div th:if="${error}" style="color: red;">
  <p th:text="${error}"></p>
</div>

<!-- 성공 메시지 표시 -->
<div th:if="${success}" style="color: green;">
  <p th:text="${success}"></p>
</div>

<form th:action="@{/validation/form/binding/books}" th:object="${book}" method="post">
  <label for="title">책 제목:</label>
  <input type="text" th:field="*{title}" id="title"><br>
  <div th:if="${#fields.hasErrors('title')}" style="color: red;">
    <p th:errors="*{title}"></p>
  </div>

  <label for="publisher">저자:</label>
  <input type="text" th:field="*{publisher}" id="publisher"><br>
  <div th:if="${#fields.hasErrors('publisher')}" style="color: red;">
    <p th:errors="*{publisher}"></p>
  </div>

  <label for="salePrice">가격:</label>
  <input type="text" th:field="*{salePrice}" id="salePrice"><br>
  <div th:if="${#fields.hasErrors('salePrice')}" style="color: red;">
    <p th:errors="*{salePrice}"></p>
  </div>

  <button type="submit">제출</button>
</form>
</body>
</html>

p206 , 207- src/main/java/spring/mvc/controller/ValidationController

@Slf4j
@RestController
@RequestMapping("/validation")
public class ValidationController {

    private final BookService bookService;
    private final ObjectMapper objectMapper = new ObjectMapper();

    public ValidationController(BookService bookService) {
        this.bookService = bookService;
    }

    // JSON 변환을 위한 헬퍼 메서드
    private String convertToJson(Object object) {
        try {
            return objectMapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            log.error("JSON 변환 오류: {}", e.getMessage());
            return "{\"error\": \"JSON 변환 중 오류가 발생했습니다.\"}";
        }
    }

    // CREATE: 책 생성 - 수동 검증
    @PostMapping("/books")
    public String createBook(@RequestBody Book book) {
        // 수동 검증 로직
        if (book.getTitle() == null || book.getTitle().trim().isEmpty()) {
            return "{\"error\": \"책 제목은 필수 입력값입니다.\"}";
        }
        if (book.getPublisher() == null || book.getPublisher().trim().isEmpty()) {
            return "{\"error\": \"저자는 필수 입력값입니다.\"}";
        }
        if (book.getSalePrice() < 0) {
            return "{\"error\": \"책 가격은 0 이상이어야 합니다.\"}";
        }

        // 검증이 통과된 경우 책 생성
        Book createdBook = bookService.createBook(book);
        return convertToJson(createdBook);
    }

    // READ: ID로 책 검색 - 수동 검증
    @GetMapping("/books/{bookIdx}")
    public String getBookById(@PathVariable Long bookIdx) {
        // 수동 검증 로직
        if (bookIdx == null || bookIdx <= 0) {
            return "{\"error\": \"책 ID는 0보다 큰 값이어야 합니다.\"}";
        }

        Optional<Book> book = bookService.getBookById(bookIdx);
        if (book.isPresent()) {
            return convertToJson(book.get());
        } else {
            return "{\"error\": \"책을 찾을 수 없습니다.\"}";
        }
    }

    // UPDATE: 책 정보 수정 - 수동 검증
    @PutMapping("/books/{bookIdx}")
    public String updateBook(@PathVariable Long bookIdx, @RequestBody Book updatedBook) {
        // 수동 검증 로직
        if (bookIdx == null || bookIdx <= 0) {
            return "{\"error\": \"책 ID는 0보다 큰 값이어야 합니다.\"}";
        }
        if (updatedBook.getTitle() == null || updatedBook.getTitle().trim().isEmpty()) {
            return "{\"error\": \"책 제목은 필수 입력값입니다.\"}";
        }
        if (updatedBook.getPublisher() == null || updatedBook.getPublisher().trim().isEmpty()) {
            return "{\"error\": \"저자는 필수 입력값입니다.\"}";
        }
        if (updatedBook.getSalePrice() < 0) {
            return "{\"error\": \"책 가격은 0 이상이어야 합니다.\"}";
        }

        Optional<Book> book = bookService.updateBook(bookIdx, updatedBook);
        if (book.isPresent()) {
            return convertToJson(book.get());
        } else {
            return "{\"error\": \"책을 찾을 수 없습니다.\"}";
        }
    }

    // DELETE: 책 삭제 - 수동 검증
    @DeleteMapping("/books/{bookIdx}")
    public String deleteBook(@PathVariable Long bookIdx) {
        // 수동 검증 로직
        if (bookIdx == null || bookIdx <= 0) {
            return "{\"error\": \"책 ID는 0보다 큰 값이어야 합니다.\"}";
        }

        boolean deleted = bookService.deleteBook(bookIdx);
        if (deleted) {
            return "{\"message\": \"책이 성공적으로 삭제되었습니다.\"}";
        } else {
            return "{\"error\": \"책을 찾을 수 없습니다.\"}";
        }
    }

    // BOOKING: 책 대여 - 수동 검증
    @PostMapping("/books/{bookIdx}/rent/{userIdx}")
    public String rentBook(@PathVariable Long bookIdx, @PathVariable Long userIdx) {
        // 수동 검증 로직
        if (bookIdx == null || bookIdx <= 0) {
            return "{\"error\": \"책 ID는 0보다 큰 값이어야 합니다.\"}";
        }
        if (userIdx == null || userIdx <= 0) {
            return "{\"error\": \"사용자 ID는 0보다 큰 값이어야 합니다.\"}";
        }

        try {
            Optional<Book> rentedBook = bookService.rentBook(bookIdx, userIdx);
            if (rentedBook.isPresent()) {
                return convertToJson(rentedBook.get());
            } else {
                return "{\"error\": \"책을 찾을 수 없습니다.\"}";
            }
        } catch (IllegalStateException | IllegalArgumentException e) {
            log.error("책 대여 오류: {}", e.getMessage());
            return "{\"error\": \"" + e.getMessage() + "\"}";
        }
    }

    // RETURN: 책 반납 - 수동 검증
    @PostMapping("/books/{bookIdx}/return/{userIdx}")
    public String returnBook(@PathVariable Long bookIdx, @PathVariable Long userIdx) {
        // 수동 검증 로직
        if (bookIdx == null || bookIdx <= 0) {
            return "{\"error\": \"책 ID는 0보다 큰 값이어야 합니다.\"}";
        }
        if (userIdx == null || userIdx <= 0) {
            return "{\"error\": \"사용자 ID는 0보다 큰 값이어야 합니다.\"}";
        }

        try {
            Optional<Book> returnedBook = bookService.returnBook(bookIdx, userIdx);
            if (returnedBook.isPresent()) {
                return convertToJson(returnedBook.get());
            } else {
                return "{\"error\": \"책을 찾을 수 없습니다.\"}";
            }
        } catch (IllegalStateException | IllegalArgumentException e) {
            log.error("책 반납 오류: {}", e.getMessage());
            return "{\"error\": \"" + e.getMessage() + "\"}";
        }
    }
}

Previous데이터베이스 연동에 필요한 부분NextValidation(검증) 보충자료

Last updated 6 months ago