본문 바로가기

Spring/SpringBoot

SpringBoot- Controller

MVC 패턴

 컨트롤러에서는 model에서 데이터를 가져와 이를 뷰에 전달한다. 이를 MVC 패턴이라고 한다.

Controller

 1) HomeController 예시

 HomeController.java

package jpabook.jpashop.controller;

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

@Controller
@Slf4j // logger 생성: Logger log = (Logger) LoggerFactory.getLogger(getClass());

public class HomeController {

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

 컨트롤러를 사용할 때에는 @Controller 어노테이션을 사용한다. 위의 예시에서 @Slf4j라는 어노테이션을 사용하였는데 이는 log를 찍기 위한 어노테이션으로 롬복에서 따로 지원하는 어노테이션이다. 만일 @Slf4j 어노테이션을 사용하지 않고 log를 찍기위해선 주석처럼 별도로 선언해서 사용하면 된다.

 결과적으로 "localhost:8080/"에 접속하면 home()이 실행되고 그 결과 log에 "Home Page"가 찍히고 "localhost:8080/"에 home.html이 뿌려진다.

 

2) MemberController 예시

MemberController.java

package jpabook.jpashop.controller;

import jpabook.jpashop.domain.Member;
import jpabook.jpashop.service.MemberService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
@RequiredArgsConstructor
@Slf4j
public class MemberController {

    private final MemberService memberService;
    
	// Get: 클라이언트에서 서버로 어떠한 리소스로부터 정보를 요청하는 메서드
    @GetMapping("/members/new") //@RequestMapping(value = "/members/new", method = "RequestMethod.GET)
    public String createForm(Model model) {
        // model 객체: Controller에서 생성한 데이터를 담아서 View로 전달할 때 사용하는 객체.
        model.addAttribute("memberForm", new MemberForm());
        // memberForm이라는 이름으로 MemberForm 객체가 전달됨

        log.info("Create Member");
        return "members/createMemberForm";
    }
}

MemberController도 HomeController와 비슷하다. "localhost:8080/members/new"에 접속하면 createForm()이 실행되고, 그 결과 model을 파라미터로 받아서 model.addAttribute("memberForm", new MemberForm())을 실행한다. 

여기서  MemberForm은 회원 정보를 담기위한 클래스이다.

 

MemberForm.java

package jpabook.jpashop.controller;

import lombok.Getter;
import lombok.Setter;

import javax.validation.constraints.NotEmpty;

@Getter @Setter
public class MemberForm {

    @NotEmpty(message = "회원 이름은 필수입니다.")  // 값이 없는 경우 에러발생함
    private String name;

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

model.addAttribute에 의해서 MemberForm 객체는 "memberForm"이라는 이름으로 "members/createMemberForm.html" 에 전달된다. 그 결과 화면에서 memberForm 객체에 접근할 수 있게된다.

 

members/createMemberForm.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/header :: header" />
<style>
    .fieldError {
        border-color: #bd2130;
    }
</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"
                   placeholder="이름을 입력하세요"
                   th:class="${#fields.hasErrors('name')}? 'form-control fieldError' : 'form-control'">
            <p th:if="${#fields.hasErrors('name')}"
               th:errors="*{name}">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>

 html을 보면 th: 뭐시기 이런애들이 있는데 여기서 th:는 thymeleaf의 문법이다.

여기서 몇가지만 보면 <form th: object = "${memberForm}">을 보면 'th: object = "${memberForm}" ' 이라는 어트리뷰트를 볼 수 있다. 이는 <form><form/> 내부에서 우리가 넘긴 "memberForm"이라는 객체를 사용할 것이라는 의미이다. 

 th:field 라는 어트리뷰트도 있다. 예컨데 th:field = "*{name}"이라는 어트리뷰트는 id = "name" name = "name"과 같은 의미이다.(솔직히 잘모르겠다).

// 위아래는 동일 코드
<input type="text" th:field="*{city}" class="form-control" placeholder="도시를 입력하세요">
                   
<input type="text" class="form-control" placeholder="도시를 입력하세요" id="city" name="city" value="">

 

@GetMapping과 @PostMapping

 -@GetMapping

 GetMapping은 return 값으로 화면에 보일 뷰(html)의 경로를 반환한다. 

ex) return "memberList.html"

 

 -@PostMapping

 PostMapping은 return 값으로 이동할 url 주소를 반환한다. 

ex) return "redirect:/"