개발 공부/백엔드

스프링 부트 - 스프링 MVC로 회원 관리 웹 기능 만들기

baby-t 2025. 9. 25. 12:13

https://www.inflearn.com/

 

인프런 - 라이프타임 커리어 플랫폼

프로그래밍, 인공지능, 데이터, 마케팅, 디자인등 입문부터 실전까지 업계 최고 선배들에게 배울 수 있는 곳.

www.inflearn.com

인프런 사이트의 김영한님의 강의를 보면서 작성한 글입니다.

 

 

지난 포스팅에서는 회원 비즈니스 로직을 처리하는 서비스와 데이터 저장을 담당하는 리포지토리를 개발하고, 단위 테스트까지 마쳤습니다.

이제 사용자가 실제로 웹 브라우저를 통해 회원 가입과 조회를 할 수 있도록 웹 MVC 계층을 구현하여, 지금까지 만든 비즈니스 로직과 화면을 연결해 보겠습니다. 💻


## 1. 홈 화면 만들기

가장 먼저 애플리케이션의 대문 역할을 하는 홈 화면을 만들어 보겠습니다.

### 1.1. HomeController 작성

controller 패키지 아래에 HomeController를 생성하고, 루트 URL(/)로 GET 요청이 왔을 때 home.html을 보여주도록 매핑합니다.

Java
 
@Controller
public class HomeController {

    @GetMapping("/")
    public String home() {
        return "home"; // home.html 템플릿을 찾아 렌더링
    }
}

### 1.2. home.html 뷰 템플릿 작성

스프링 부트의 뷰 리졸버(View Resolver)가 templates 폴더에서 home.html을 찾아 처리할 수 있도록 파일을 생성합니다.

HTML
 
<div class="container">
    <div>
        <h1>Hello Spring</h1>
        <p>회원 기능</p>
        <p>
            <a href="/members/new">회원 가입</a>
            <a href="/members">회원 목록</a>
        </p>
    </div>
</div>

이제 애플리케이션을 실행하고 localhost:8080에 접속하면, 위에서 만든 홈 화면이 나타납니다.


## 2. 회원 등록 기능 구현

### 2.1. 등록 폼(Form) 화면

먼저, 사용자가 이름을 입력할 수 있는 회원 가입 폼 화면을 보여주는 컨트롤러 로직을 작성합니다.

MemberController.java

Java
 
@GetMapping("/members/new")
public String createForm() {
    return "members/createMemberForm";
}

templates/members/createMemberForm.html

HTML
 
<form action="/members/new" method="post">
    <div class="form-group">
        <label for="name">이름</label>
        <input type="text" id="name" name="name" placeholder="이름을 입력하세요">
    </div>
    <button type="submit">등록</button>
</form>

이 폼은 method="post"를 통해 /members/new URL로 입력된 데이터를 전송하게 됩니다.

### 2.2. 폼 데이터 처리

이제 사용자가 입력한 이름을 받아 실제로 회원을 등록하는 로직을 구현해야 합니다.

MemberForm.java (DTO) HTML 폼에서 전달된 name 값을 컨트롤러가 받기 위해, name 필드를 가진 MemberForm 클래스(DTO)를 하나 만들어 줍니다.

Java
 
public class MemberForm {
    private String name;

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

MemberController.java에 create() 메소드 추가 @PostMapping을 사용하여 /members/new로 들어오는 POST 요청을 처리합니다. 스프링은 name="name"으로 넘어온 폼 데이터를 보고, MemberForm 객체의 setName() 메소드를 자동으로 호출하여 값을 채워줍니다.

Java
 
@PostMapping("/members/new")
public String create(MemberForm form) {
    Member member = new Member();
    member.setName(form.getName());

    memberService.join(member);

    return "redirect:/"; // 회원가입이 끝나면 홈 화면으로 리다이렉트
}

"redirect:/"는 등록이 끝난 후, 브라우저를 홈 화면(/)으로 다시 이동시키라는 명령어입니다.


## 3. 회원 조회 기능 구현

마지막으로, 등록된 모든 회원의 목록을 보여주는 화면을 구현합니다.

MemberController.java에 list() 메소드 추가 @GetMapping("/members") 요청이 오면, 서비스 계층을 통해 모든 회원을 조회하고, 그 결과를 Model 객체에 담아 뷰로 전달합니다.

Java
 
@GetMapping("/members")
public String list(Model model) {
    List<Member> members = memberService.findMembers();
    model.addAttribute("members", members);
    return "members/memberList";
}

templates/members/memberList.html 컨트롤러가 model에 담아 보낸 "members"라는 이름의 리스트를 타임리프(Thymeleaf)의 th:each를 사용하여 반복 출력합니다.

HTML
 
<div class="container">
    <div>
        <table>
            <thead>
            <tr>
                <th>#</th>
                <th>이름</th>
            </tr>
            </thead>
            <tbody>
            <tr th:each="member : ${members}">
                <td th:text="${member.id}"></td>
                <td th:text="${member.name}"></td>
            </tr>
            </tbody>
        </table>
    </div>
</div>

th:each="member : ${members}"는 모델에서 받은 ${members} 리스트를 순회하면서, 각 항목을 member 변수에 담아 <tr> 블록을 반복 실행하라는 의미입니다.


## 4. 실행 결과 및 다음 단계

이제 회원 가입 폼에 이름을 입력하고 등록하면 홈 화면으로 돌아가고, '회원 목록' 링크를 누르면 방금 등록한 회원의 이름이 목록에 나타나는 것을 확인할 수 있습니다.

실제 뜬 화면

 

하지만! 현재 구현은 메모리 기반 리포지토리를 사용하고 있어, 애플리케이션을 재시작하면 모든 회원 데이터가 사라집니다. 실무에서는 데이터가 영속적으로 보존되어야 하므로, 다음 포스팅에서는 이 데이터를 데이터베이스에 저장하는 방법을 알아보겠습니다.

 


 

## DTO(Data Transfer Object)란?

DTO는 계층 간의 **데이터 전송(Data Transfer)**을 위해 사용되는 **객체(Object)**입니다. 📄➡️

각 계층이 데이터를 주고받을 때 사용하는 전용 데이터 운반용 상자라고 생각하면 쉽습니다.

### DTO를 사용하는 이유

컨트롤러가 클라이언트의 데이터를 받을 때, Member와 같은 도메인(엔티티) 객체를 직접 사용하지 않고 DTO를 사용하는 이유는 역할을 명확하게 분리하기 위해서입니다.

  • 도메인/엔티티 객체 (Member): 데이터베이스 테이블과 직접 매핑되는 핵심 객체입니다. id, 가입일 등 DB에 저장되는 모든 데이터를 가지고 있으며, 중요한 비즈니스 로-직을 포함할 수 있습니다.
  • DTO (MemberForm): 화면(View)과 데이터를 주고받기 위한 객체입니다. 화면의 특정 기능에 필요한 데이터만 선별적으로 가집니다.

만약 Member 객체를 그대로 사용하면, 회원 가입 폼에 필요 없는 id나 가입일 같은 필드까지 외부에 노출될 수 있습니다.

MemberForm과 같은 DTO를 사용하면, 화면에 꼭 필요한 name 필드만 담아서 받기 때문에, 각 계층의 역할이 명확해지고 시스템이 훨씬 더 안전하고 유연해집니다.