본문 바로가기
BackEnd/JPA

[JPA] 웹 계층 개발(1)

by 개발 Blog 2024. 10. 4.

공부 내용을 정리하고 앞으로의 학습에 이해를 돕기 위해 작성합니다.

 

홈 화면과 레이아웃

1. homecontroller

HomeController는 웹 애플리케이션의 홈 화면을 처리하는 컨트롤러이다. 사용자가 루트 경로인 /에 접근하면 홈 화면이 표시되며, 로그를 통해 접근을 기록한다.

package jpabook.jpashop.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@Slf4j
public class HomeController {

    @RequestMapping("/")
    public String home() {
        log.info("home controller");
        return "home";
    }
}

 

2. 홈 화면 (home.html)

홈 화면은 Thymeleaf 템플릿을 사용하여 구성된다. 화면 상단에는 사이트의 내비게이션이 표시되며, 회원 기능, 상품 기능, 주문 기능을 제공하는 버튼들이 배치되어 있다. 각각의 버튼을 클릭하면 해당 기능 페이지로 이동할 수 있다.

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="~{fragments/header :: header}">
    <title>Hello</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<div class="container">
    <div th:replace="~{fragments/bodyHeader :: bodyHeader}"/>
    <div class="jumbotron"><h1>HELLO SHOP</h1>
        <p class="lead">회원 기능</p>
        <p>
            <a class="btn btn-lg btn-secondary" href="/members/new">회원 가입</a>
            <a class="btn btn-lg btn-secondary" href="/members">회원 목록</a></p>
        <p class="lead">상품 기능</p>
        <p>
            <a class="btn btn-lg btn-dark" href="/items/new">상품 등록</a>
            <a class="btn btn-lg btn-dark" href="/items">상품 목록</a></p>
        <p class="lead">주문 기능</p>
        <p>
            <a class="btn btn-lg btn-info" href="/order">상품 주문</a> <a class="btn btn-lg btn-info" href="/orders">주문
            내역</a>
        </p></div>
    <div th:replace="~{fragments/footer :: footer}"/>
</div> <!-- /container -->
</body>
</html>

 

3. 헤더 (header.html)

헤더는 사이트 전체에 걸쳐 공통적으로 사용되는 상단 네비게이션 바를 정의한다. 여기에는 사이트의 기본적인 정보와 브라우저 창 크기에 맞게 반응하는 meta 태그가 포함되어 있다. 또한, 외부 CSS 파일 (부트스트랩)을 불러와 웹사이트의 스타일을 정의한다.

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:fragment="header">
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="/css/bootstrap.min.css">
    <!-- Custom styles for this template -->
    <link href="/css/jumbotron-narrow.css" rel="stylesheet">
    <title>Hello, world!</title>
</head>

 

4. 푸터 (footer.html)

푸터는 페이지 하단에 표시되며, 사이트의 저작권 정보를 담고 있다. 사이트의 버전이나 간단한 저작권 문구가 포함되어 있다.

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="footer" th:fragment="footer">
    <p>&copy; Hello Shop V2</p>
</div>

 

5. 바디 헤더 (bodyHeader.html)

바디 헤더는 사이트 내에서 페이지 상단에 위치한 헤더 부분을 구성하며, 주요 내비게이션 링크를 포함한다. 이 부분은 "Home"으로 이동할 수 있는 버튼을 포함하여 사용자가 쉽게 홈으로 돌아갈 수 있도록 돕는다.

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="header" th:fragment="bodyHeader">
    <ul class="nav nav-pills pull-right">
        <li><a href="/">Home</a></li>
    </ul>
    <a href="/"><h3 class="text-muted">HELLO SHOP</h3></a>
</div>

 

6. 레이아웃 적용 후 홈 화면 실행 결과

아래 화면은 회원, 상품, 주문 기능을 빠르게 접근할 수 있도록 구성되어 있으며, 직관적인 레이아웃을 통해 사용자가 쉽게 탐색할 수 있다.

회원 등록

1. build.gradle 설정

build.gradle 파일에서 Hibernate Validator를 추가하여 폼 데이터에 대한 유효성 검증을 수행할 수 있다. 이를 통해 입력값에 대한 검증 로직을 간단하게 처리할 수 있다. 특히, 회원 이름과 같은 필수 입력 항목에 대한 유효성 검사를 할 때 유용하다.

// Hibernate Validator 추가 (Bean Validation)
implementation 'org.hibernate.validator:hibernate-validator:8.0.0.Final'
implementation 'jakarta.validation:jakarta.validation-api:3.0.2'
  • 이 두 가지 의존성을 추가하면 Bean Validation을 사용할 수 있게 된다.
  • hibernate-validator는 Hibernate가 제공하는 유효성 검사 기능이며, jakarta.validation-api는 검증을 위한 표준 API를 제공한다.
  • 이를 통해 @NotEmpty, @Valid와 같은 어노테이션을 활용하여 폼 데이터의 유효성을 쉽게 관리할 수 있다.

2. MemberForm

MemberForm 클래스는 회원 가입 폼의 데이터를 담는 DTO(Data Transfer Object) 역할을 한다. 이 클래스는 유효성 검증을 위한 어노테이션을 사용하여 입력값을 제어한다. 특히 @NotEmpty 어노테이션을 통해 이름 필드가 반드시 입력되도록 강제한다.

package jpabook.jpashop.controller;

import lombok.Getter;
import lombok.Setter;
import jakarta.validation.constraints.NotEmpty;

@Getter
@Setter
public class MemberForm {

    @NotEmpty(message = "회원 이름은 필수 입니다.")
    private String name;

    private String city;
    private String street;
    private String zipcode;
}

 

3. MemberController

유효성 검사는 MemberController에서 처리되며, 사용자가 입력한 데이터가 유효하지 않을 경우 폼으로 다시 돌아가 오류 메시지를 출력한다. 이 과정에서 BindingResult를 통해 오류를 확인하고, 문제가 있을 경우 다시 입력 폼으로 돌려보낸다.

package jpabook.jpashop.controller;

import jakarta.validation.Valid;
import jpabook.jpashop.domain.Address;
import jpabook.jpashop.domain.Member;
import jpabook.jpashop.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
@RequiredArgsConstructor
public class MemberController {
    private final MemberService memberService;

    @GetMapping("/members/new")
    public String createForm(Model model) {
        model.addAttribute("memberForm", new MemberForm());
        return "members/createMemberForm";
    }

    @PostMapping("/members/new")
    public String create(@Valid MemberForm form, BindingResult result) {

        if (result.hasErrors()) {
            return "members/createMemberForm";
        }

        Address address = new Address(form.getCity(), form.getStreet(), form.getZipcode());

        Member member = new Member();
        member.setName(form.getName());
        member.setAddress(address);

        memberService.join(member);
        return "redirect:/";
    }
}
  • @Valid 어노테이션은 MemberForm 객체의 유효성을 검증하며, 오류가 발생하면 해당 오류 메시지를 사용자가 볼 수 있도록 설정된다.

4. 회원 등록 화면 (createMemberForm.html)

이 페이지는 회원 등록을 위한 화면을 구성하는 HTML 파일이다. 사용자로부터 이름, 도시, 거리, 우편번호 등의 정보를 입력받고, 이를 서버로 제출하기 위한 폼을 제공한다.

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/header :: header"/>
<style>
    .fieldError {
        border-color: #bd2130;
    }
    .errorMessage {
        color: #bd2130;
        font-size: 0.9em;
        margin-top: 5px;
    }
</style>
<body>
<div class="container">
    <div th:replace="fragments/bodyHeader :: bodyHeader"/>
    <form role="form" action="/members/new" th:object="${memberForm}" method="post">
        <div class="form-group">
            <label th:for="name">이름</label>
            <input type="text" th:field="*{name}" class="form-control"
                   th:class="${#fields.hasErrors('name')}? 'form-control fieldError' : 'form-control'"
                   placeholder="이름을 입력하세요">
            <p th:if="${#fields.hasErrors('name')}"
               th:errors="*{name}" class="errorMessage">Incorrect date</p>
        </div>
        <div class="form-group">
            <label th:for="city">도시</label>
            <input type="text" th:field="*{city}" class="form-control"
                   placeholder="도시를 입력하세요">
        </div>
        <div class="form-group">
            <label th:for="street">거리</label>
            <input type="text" th:field="*{street}" class="form-control"
                   placeholder="거리를 입력하세요">
        </div>
        <div class="form-group">
            <label th:for="zipcode">우편번호</label>
            <input type="text" th:field="*{zipcode}" class="form-control"
                   placeholder="우편번호를 입력하세요">
        </div>
        <button type="submit" class="btn btn-primary">Submit</button>
    </form>
    <br/>
    <div th:replace="fragments/footer :: footer"/>
</div> <!-- /container -->
</body>
</html>

 

5. 실행화면

회원가입 버튼을 클릭하면 아래와 같은 회원 가입 폼이 나타난다. 사용자는 이름, 도시, 거리, 우편번호를 입력할 수 있다.

  • 이름 미입력 시: 이름은 필수 입력 항목으로 설정되어 있으며, 입력하지 않을 경우 memberForm에서 유효성 검사를 통해 "회원 이름은 필수입니다."라는 오류 메시지가 빨간색으로 표시된다.

정상 입력 후 제출

모든 필드를 올바르게 입력한 후 Submit 버튼을 누르면 POST 메서드를 통해 서버로 데이터가 전송된다. 이때 회원 정보는 데이터베이스에 저장되며, 저장된 회원 정보는 추후 회원 목록에서 확인할 수 있다.

 

이를 통해 폼이 정상적으로 동작하며, Hibernate Validator를 사용한 유효성 검사를 통과한 데이터만 데이터베이스에 저장된다.

'BackEnd > JPA' 카테고리의 다른 글

[JPA] 웹 계층 개발(3)  (0) 2024.10.05
[JPA] 웹 계층 개발(2)  (0) 2024.10.05
[JPA] 주문 도메인 개발  (3) 2024.10.03
[JPA] 상품 도메인 개발  (0) 2024.10.03
[JPA] 회원 도메인 개발  (0) 2024.10.02