Framework/Spring

[Spring] Spring Boot MVC 패턴 익히기

Joonfluence 2022. 5. 21.

서론

오늘은 Spring의 MVC 패턴에 대해 간단히 알아보고 직접 실습해보도록 하겠습니다. 이 글은 김영한님의 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술을 보고 정리한 글임을 서두에 밝힙니다.

본론

MVC의 역할

MVC는 각각 M(Model), V(View), C(Controller)에 약자입니다. 각각 역할이 구분되는데요, Model의 경우에는 데이터의 상태를 나타내는 역할을 합니다. View의 경우에는 화면을 구성하는 역할을 하며, Model의 data와 함께 HTML 파일을 브라우저에 전송합니다. Controller의 경우, View와 Model 간의 인터페이스 역할을 하며, 클라이언트의 요청 및 전송 데이터를 수신하고 적절한 결과물을 Model에 담아 View에 전달합니다.

MVC의 구성

Model의 경우에는 POJO(Plain Old Java Object)로 구성됩니다. View의 경우에는 JSP, Thymeleaf, Groovy, Freemakter 등의 Template Engine이 속합니다. Controller의 경우, Servlet이 여기에 속합니다. 참고로 Servelet이란 자바로 구현 된 CGI라고 말합니다.

Sprint Boot MVC 동작 과정

index.html을 확인하는 과정

static/index.html 을 올려두면 Welcome page 기능을 제공합니다. 예를 들어, 아래와 같은 HTML을 해당 디렉토리에 위치시키면 해당 HTML 파일이 렌더링됩니다.

<!DOCTYPE HTML>
<html>
<head>
    <title>Hello</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
Hello
<a href="/hello">hello</a>
</body>
</html>

Get 요청

1) 먼저 웹 브라우저에서 요청을 보냅니다.
2) 내장 톰캣 서버에서 해당 요청을 확인하고 해당하는 경로의 Controller로 보냅니다.
3) Controller에선 Model 데이터를 생성하고 리턴 값으로 문자열을 반환합니다.
4) 그러면 viewResolver가 /templates/문자열.html 파일을 브라우저로 다시 전송해줍니다.

Post 요청

한가지 차이점은 @ResponseBody를 사용하면 뷰 리졸버(viewResolver)를 사용하지 않는다는 점입니다. 대신에 HTTP의 BODY에 문자 내용을 직접 반환합니다. 그 과정에서 변환기를 거치는데, 두 가지 종류의 변환기가 있습니다. 문자 처리를 위한 StringHttpMessageConverter, 기본 객체 처리를 위한 MappingJackson2HttpMessageConverter가 있습니다.

실습

이제 본격적으로 MVC 패턴에 맞게, 기능 개발을 해보겠습니다. 구체적으로 회원가입을 구현해볼 것입니다. 먼저 조건들은 아래와 같습니다.

1) 홈 화면에서 회원가입 페이지로 이동 할 수 있도록 링크를 제공합니다.
2) 해당 페이지에서 유저가 가입자명을 입력하고 이를 Post 방식으로 서버에 전달합니다.
3) 입력을 완료하면, 콘트롤러는 다시 홈 화면으로 리다이렉트 시킵니다.

먼저, View를 구성해줍니다. 이를 위해, templates 경로에 home 이란 페이지에 (회원가입 페이지로 이동할 수 있는) HTML 파일을 생성해줍니다. 아래와 같이 말이죠. 링크 경로는 /members/new 입니다.

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    Hello Spring
    <ul>
        <li>
            <a href="/members/new">회원가입</a>
        </li>
    </ul>
</body>
</html>

이제, View가 구성됐으니 Controller에서 회원가입을 위한 입력 폼을 전송해주겠습니다. 새롭게 HomeController를 생성해줍니다. 그리고 @Controller 어노테이션을 추가해줍니다. 그런 후, @GetMapping("/")을 추가해, 루트 디렉토리(/)로 요청이 오면, 추가한 home.html 파일로 반환하도록 처리해주겠습니다.

package spring.mvc.sample.controller;

import org.springframework.stereotype.Controller;

@Controller
public class HomeContoller {
    @GetMapping("/")
    public String home(){
        return "home";
    }
}

이번엔 홈 화면에서 링크를 타고 이동했을 때, 나오는 회원가입 페이지를 만들어보겠습니다. 이번에도 먼저 View부터 만들어줍니다. 아래와 같이 말이죠. 경로는 /templates/members로, 파일명은 createMemberForm으로 설정해주겠습니다.

///templates/members/createMemberForm.html

<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div>
        <form action="/members/new" method="post">
            <div>
                <label for="name">이름</label>
                <input id="name" name="name" placeholder="이름를 입력해주세요">
            </div>
            <button type="submit">전송하기</button>
        </form>
    </div>
</body>
</html>

GET /members/new 요청을 처리해야 하므로 membersController를 만들어줍니다. (@Autowired를 추가함으로써 DI 처리도 함께 해줍니다. 가장 많이 쓰이는 생성자 방식으로 말이죠. 자세한 설명은 해당 링크를 참조 바랍니다.) 그런 뒤, members/createMemberForm 페이지를 렌더링합니다.

@Controller
public class MemberController {
    private final MemberService memberService;

    @Autowired
    public MemberController(MemberService memberService){
        this.memberService = memberService;
    }

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

이제 View와 Controller가 연결될 것입니다. 이제 POST 요청으로 전송되는 데이터만 처리해주면 됩니다. 이를 위해, 폼 데이터를 클래스를 정의해줍니다.

package spring.mvc.sample.controller;

public class MemberForm {
    private String name;
    public String getName() {
        return name;
    }

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

이제 마지막 단계입니다. 기존에 만들었던 서비스에서 회원가입 로직을 실행하고 리다이렉트 구문("redirect:/")을 반환해줍니다.

package spring.mvc.dalicious.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import spring.mvc.sample.domain.Member;
import spring.mvc.sample.service.MemberService;

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

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

        return "redirect:/";
    }
}

마무리

이상으로 간단하게 Spring Boot에서 MVC 패턴을 어떻게 다룰 수 있는지 살펴봤습니다. 읽어주셔서 감사합니다!

반응형

댓글