[java, #19] MVC 기초2

1. 목적

오늘은 MVC를 활용하면서 마주칠 수 있는 다양한 궁금증을 해소해보는 시간으로 구성했다. 먼저, MVC를 활용하여 login을 구현해볼 것이다. 구현하면서 실질적으로 데이터가 어떻게 움직이는지(HTTP)에 대하여 알아보고, 그것을 어떻게 해석하면 되는지 간략하게 알아볼 것이다. 또한, 실제로 구현이 어떠한 흐름으로 이루어지는지 알아본다. 이는 추후 에러가 발생할 경우 발생 위치를 찾아내는데 요긴하게 도움을 줄 수 있을 것이다. 그 이후에는 각종 annotation(@)의 기능과 역할에 대하여 알아본다. 어떠한 상황에서 어떠한 annotation을 활용해야 하는지 알아본다.

자 이제 시작해보자.

2. MVC 활용하기

2.1 주제

login 구현하기

간단한 로그인을 구현하는 코드를 제작할 것이다. login 페이지로 들어갈 수 있는 api, 아이디와 비밀번호를 입력하면 로그인되도록 하는 api 두 가지를 만들어볼 것이다.

규칙은 다음과 같다.

주소(api): "/login"이다.
로그인 성공 조건: 아이디와 패스워드가 동일해야 한다.
request HTTP: CONTENTS TYPE은 application/~ 이어야 한다.
MVC의 model을 활용한다.

이와 같은 규칙을 가지고 코드를 설계해보자.

2.2 설계

2.2.1 login 페이지 접근

login 페이지에 접근할 때에는 "/login" 페이지에 get 방식으로 정보를 보낸다. 단순히 접속하는 것이기 때문에 post 방식을 사용할 필요가 없다. 백엔드에 도착하면 로그인 페이지를 반환해야 한다. 해당 페이지는 static 폴더에 존재하며, redirect를 사용한다.

2.2.2 login 수행

login 페이지에 접속했다면, 아이디와 비밀번호를 입력할 수 있는 input란이 보일 것이다. input란에 입력된 정보는 post 방식으로 api를 통해 전달된다. back-end에서 데이터를 받으면, 로그인 성공 페이지로 돌아간다. 이 때, MVC를 활용하여 성공 시 입력한 아이디를 현시한다. 위 규칙에 명시되었듯이, id와 비밀번호가 동일해야 로그인을 성공할 수 있다.

2.3 코드

front-end와 back-end에 활용되는 코드를 볼 수 있다. 이와 함께 어떤 역할을 하는지 주석을 달았다.

2.3.1 back-end

@ LoginController.java

package com.modulepractice.module.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

@Controller
public class LoginController {

    // 1. get방식: login 페이지에 접속할 수 있도록 함 / return redirect:/login-form.html
    
    // /login api를 타고 get 방식으로 들어옴
    @GetMapping("/login") 
    
    // 함수 실행: redirect 시키기 to login-form.html
    public String accessToLoginPage(){
        return "redirect:/login-form.html"; // login-form.html: static 폴더에 있으므로 확장자까지 포함하기
    }



    // 2. post 방식: 로그인 정보(id와 password)를 송부함 / return login-result.html
    
    // Post방식으로 받기: /login api를 타고 들어옴.
    @PostMapping("/login")
    
    // 함수 실행하기: Model(MVC)의 model 객체, HTTP body에 있는 id와 password를 인자로 받음
    public String loginProcess(Model model, @RequestBody String id, @RequestBody String password){

        // 로그인 조건: 만약 id와 pw가 동일하면 페이지 이동
        if ( password.equals(id) ){
            model.addAttribute("loginId", id); # view에 전송할 변수를 할당(front-end)와 동일함
        }
        return "login-result";
    }
}

2.3.2 front-end

2.3.2.1 login-form.html

@ /static/login-form.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello Login Form</title>
</head>
<body>
<form action="login" method="POST">
    <div>
        아이디: <input name="id" type="text">
    </div>
    <div>
        비밀번호: <input name="password" type="password">
    </div>
    <button>로그인</button>
</form>

<div>
    * 아이디는 영어만 가능 <br>
    * 비밀번호 Hint: 아이디 <br>
</div>
</body>
</html>

2.3.2.2 login-result.html

@ template/login-result.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Hello Login Result</title>
</head>
<body>
Hello Login by Spring MVC!

<br><br>

<div th:if = "${loginId != null}"
     th:text="|로그인 아이디: ${loginId}|" /> <--back-end의 model 입력 인자와 동일함-->
<div th:unless = "${loginId != null}"
     th:text="|로그인에 실패했습니다. 아이디와 패스워드를 다시 확인해 주세요.|" />

</body>
</html>

3. HTTP

3.1 개념

컴퓨터는 무엇을 근거로 로그인을 시켜주는 것일까? 그 답은 HTTP 메시지에서 확인할 수 있다.

back-end와 front-end가 상호작용 할 때에는 HTTP 메시지가 오간다. 그 종류는 방향에 따라 크게 두 가지로 구분된다.

① request HTTP 메시지
② response HTTP 메시지

request HTTP 메시지는 front-end가 back-end로 이동할 때 함께 전송된다. 반면, response HTTP 메시지는 back-end에서 front-end로 이동할 때 전송된다.

위에서, 이 메시지를 근거로 데이터가 이동하고, 현시된다고 하였다. 그러면 어떤 내용이 어떤 형식으로 존재할까?

3.1 형식과 내용

3.1.1 형식

먼저, 형식부터 알아보자. 두 메시지 모두 크게 3가지 부분으로 구분된다.

① start line
② header
③ body

3.1.2 내용

start line 부터 알아보자. request 메시지에서는 전송 방식과 요청 내용이 현시된다. response 메시지에서는 데이터 처리 성공 여부와 상태가 현시된다.

header에서는, 두 메시지 모두, 데이터 전송 타입이 전송된다. 우리는 주로 CONTENTS TYPE을 통해 확인할 수 있다.

body에는 실제 데이터를 볼 수 있다. 데이터 형식과 실제 데이터 내용을 확인할 수 있다. 이를 활용해 데이터가 전송되었는지 눈으로 확인할 수 있다.

4. controller flow

이렇게 활용이 가능한 controller가 어떻게 작동되는지 flow를 간단하게 알아보자. 총 6단계로 구분할 수 있다.

① HTTP 메시지 전송: front-end → back-end
② 응답소 도착: servlet에서 controller를 탐색함
③ 대응 함수 확인: controller에서 대응 함수를 찾으면 해당 함수 실행
④ 데이터 전송: model 및 view에 데이터 전송
⑤ 결과 수집: model과 view의 결과를 수집
⑥ HTTP 메시지 전송: back-end → front-end

이로서 우리는 우리의 마음대로 함수명을 제작할 수 있으며, 조금 더 편리하게 controller를 활용할 수 있는 것이다.

5. @RestController

결론부터 말하면, @RestController는 body에 담기는 데이터의 형식이 String 또는 JSON일 경우 사용한다. Rest는 @ResponseBody의 줄임말이고, Controller는 controller를 그대로 활용한 것이다.

@ResponseBody는 자바 객체 형태 또는 JSON 형태로 body에 데이터를 입력할 때 사용한다. 동시에 controller는 응답소를 의미한다. 그래서 String 또는 JSON 형식의 데이터 송부가 가능한 것이다.

@ResponseBody를 활용했을 때를 상상해보자. HTTP 메시지 내용 중 response header 부분에 CONTENT TYPE에는 'application/json' 또는 'text/html' 형식이 담겨져 있을 것이다. response body에는 아마 데이터가 담겨져 있을 것이다.

6. @RequestMapping

api를 받을 때 class 위에 보면 @RequestMapping이 적혀있을 때가 있다. 왜 사용될까?

결론적으로, 공통된 api를 묶을 때 사용한다. 만약 '/api/request1'과 '/api/request2'를 받는 함수가 있다면 '/api'를 묶을 수 있다. 이 때 사용하는 것이 @RequestMapping이다.

예를 들어보자. 아래와 같은 코드를 작성할 때 @RequestMapping을 활용하면 아주 유리하다.

@RequestMapping('/api') // 공통 주소를 묶었다.
@Controller  // String 형식으로 데이터를 주고받는다.
public class HiRequestMapping(){
	
    @GetMapping('/request1')  // /api/request1 로 접근하면 된다.
    public String request1(){
    
    	return "request1"
    
    }
    
    
    @PostMapping('/request2') // /api/request2 로 접근하면 된다.
    public String request1(@RequestBody String id){
    
    	return "request2"
    
    }
}

7. 데이터를 받는 방법

front-end에서 송부된 데이터를 받는 방법은 총 5가지가 있다. 조금 더 기억하기 쉽도록 주소창에 데이터가 현시되는가 여부에 따라 분류를 해보았다.

그 결과는 다음과 같다.

url에 데이터 표시 ┳ ① @PathVariable: 주소가 /{} 형식일 때 사용
                └ ② @RequestParam: ?name=kwon 형식일 때 사용
               

url에 데이터 미표시┳ ① @RequestParam
				 ┠ ② @RequestBody
                └  ③ @ModelAttribute: MVC를 활용하여 데이터를 받을 때 사용

url에 데이터가 표시될 때 데이터를 받는 방법은 @PathVariable과 @RequestParam을 활용하는 것이다. @PathVariable은 주소가 /{} 형식일 때 활용되며, @RequestParam은 검색할 때와 같이 '?search=name'일 때 name을 받을 때 사용된다.

url에 데이터가 미표시될 때에는 @RequestParam, @RequestBody 그리고 @ModelAttribute를 활용할 수 있다. 이 중 ModelAttribute는 MVC를 활용할 때 사용되며, 객체로 변환하여 바로 MVC에 입력할 수 있다.

좋은 웹페이지 즐겨찾기