본문 바로가기
  • 개발공부 및 일상적인 내용을 작성하는 블로그 입니다.
Spring basic

스프링 입문 : 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 - 회원 웹 기능 : 등록 및 조회

by 방구석 대학생 2021. 11. 8.

"인프런의 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 강의를 듣고 작성한 글 입니다."

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8

 

[무료] 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링 웹 애플리케이션 개발 전반을 빠르게 학습할 수 있습니다., 스프링 학습 첫 길잡이! 개발 공부의 길을 잃지 않도록 도와드립니다. 📣 확인해주세

www.inflearn.com

 

회원 웹 기능 - 등록

MemberController 를 다음과 같이 작성해주자.

- MemberController.java

@Controller
public class MemberController {


    private final MemberService memberService;

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

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

 

/templates/members 경로에 createMemberForm.html 파일을 만들고 아래와 같이 작성해준다.

- createMemberForm.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <div class="container">
        <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>
    </div>
</body>
</html>

 

이제 어플리케이션을 다시 가동 시킨 다음 홈 화면에서 /members/new 경로가 매핑되어 있는 회원 가입 링크를 클릭해보면 정상적으로 createMemberForm.html 파일이 화면에 출력되는 것을 확인할 수 있다.

(페이지 소스 보기를 해보면 파일의 코드 내용이 잘 랜더링 되어 있음을 확인 할 수 있다.)

createMemberForm.html 출력화면

 

여기서 화면에 나와 있는 입력 칸에 아무 글자나 입력해준 후(예를 들어 spring 같은 문자열) 등록 버튼을 누르면 지금은 form 태그에서 작성해준 http 메소드와 경로가 정상적으로 매핑된 컨트롤러가 없기 때무넹 에러가 발생하는 것을 확인할 수 있다.

 

컨트롤러가 존재하는 패키지에 MemberForm 클래스 파일을 만들고 다음과 같이 코드를 작성해주자.

- MemberForm.java

public class MemberForm {

    private String name;

    public String getName() {
        return name;
    }

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

 

이와 같이 작성해두면 createMemberForm 에서 form 태그를 통해 데이터로 넘어오는 name 필드와 MemberForm 에서 작성된 name 필드가 매칭이 되면서 값이 들어오게끔 만들수 있다.

(pro.gg 프로젝트를 할 때는 기능 제공을 위해 필요한 DTO 객체를 포함하여, 그와 관련없는 다른 데이터들이 넘어 오더라도 그 데이터들을 자바 스크립트와 jQuery, Ajax 를 이용해 URL 에 변수값으로 붙어서 컨트롤러로 넘어오게끔 만들었었는데, 여기서는 화면을 통해 넘어오는 데이터를 받아주는 객체 클래스를 따로 만들어서 처리를 하는 듯 하다.)

 

MemberController 에 다음과 같은 코드를 추가해주자.

- MemberController.java

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

    memberService.join(member);
    return "redirect:/";
}

위의 코드를 보면 createMemberForm.html 파일에서 form 태그에 작성해준 바와 같이 post method 로 매핑된 /members/new 경로를 통해 넘어오는 데이터를 MemberForm 객체를 통해 받은 후, 해당 객체에 들어있는 값을 Member 객체에 적재해주고 join 메소드를 통해 회원 가입 기능을 실행시킨다는 것을 알 수 있다.

마지막으로는 redirect 를 통해 홈 화면으로 다시 이동한다.

 

구체적인 원리?

먼저 회원가입 링크를 클릭함 으로서 createMemberForm.html 파일을 출력해주는 화면으로 넘어간다.

현재 회원가입 링크에서 매핑해준 것과 같이 이동 경로를 URL에 직접 작성해서 화면을 넘겨주는 것을 Http Method 중에서 Get 방식이라고 한다.

이와 같은 경로 매핑을 통해 HomeController 에서 해당 메소드와 경로가 매핑되어 있는 createForm() 메소드가 실행된다.

이 메소드는 다른 기능 없이 그냥 createMemberForm.html 화면을 뿌려주는 역할만을 수행한다.(화면 이동 기능만을 수행)

 

createMemberForm.html 에는 form 태그가 존재한다. 이 태그는 화면상에서 사용자가 원하는 데이터 값을 입력할 수 있게끔 해주는 태그이다.

form 태그를 보면 action 속성에 "/members/new", method 속성에 "post" 라고 되어있다.

이후 를 보면 label 태그와 input 태그가 있다.

label 태그는 for 속성에 적혀있는 값과 일치하는 id 속성을 가진 태그에 이름을 붙여주는 태그로 현재 파일에서는 '이름' 이라는 문자열을 name 이라는 id 값을 가진 input 태그에 붙여주고 있다.

input 태그의 경우 텍스트를 입력할 수 있는 입력칸을 만들어주고 name 속성에 적혀있는 값은 컨트롤러로 데이터가 넘어올때 해당 데이터를 구별하는 키 값의 역할을 한다.

 

여기서 input 태그의 입력칸에 "spring" 과 같은 아무 문자열이나 입력해주고 난 다음 등록 버튼을 누르면 어떤일이 발생할까?

form 태그의 action 속성에 적혀있는 경로에 post 방식으로 input 태그에 입력된 데이터가 서버측에 대한 요청으로 넘어가게 된다.

해당 요청을 받은 서버는 스프링 컨테이너에 적재되어 있는 컨트롤러 들을 보다가 똑같은 메소드(post) 와 똑같은 경로("/members/new") 가 매핑된 HomeController 클래스의 create 메소드를 발견하고 해당 메소드에 현재 가지고 있는 데이터를 넘겨주면서 메소드를 실행시키게 된다.

 

* post mapping 은 보통 form 과 같은 태그에 데이터를 실어서 서버 측에 넘겨줘야 할 때 사용하고(데이터를 등록 시킬 경우), get mapping 의 경우 데이터를 조회할 때 주로 사용한다.

이 메소드가 실행되면서 알 수 있는 재밌는 점은 이 메소드에 파라미터 값으로 작성되어 있는 MemberForm 클래스 객체의 name 필드에, 서버 측에서 form 태그에 담져져서 넘어온 name 데이터 값(input 입력값)이 적재되게 된다는 것이다. 

 

아까 위에서 input 태그에 name 속성에 적혀있는 값을 기준으로 데이터를 구별해 줄 수 있다고 했던것을 기억할 것이다.

스프링은 이 name 속성에 적혀있는 데이터 값을 보고 (name="name") MemberForm 클래스 객체에서 이름이 일치하는 필드를 찾아서 현재 가지고 있는 데이터를 적재해준다.(setter 메소드가 실행됨)

 

 

회원 웹 기능 - 조회

회원 목록 링크를 클릭했을 때 회원의 목록을 조회하여 출력하는 기능을 만들어보자.

MemberController 에 다음과 같은 코드를 추가하자.

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

위의 코드를 보면 findMembers() 메소드를 통해 현재 등록되어 있는 회원 들의 데이터를 검색해서 리스트로 반환받은 다음, 해당 리스트를 model 객체에 담아서 /templates/members/ 경로에 있는 memberList.html 파일로 전달해주는 것을 알 수 있다.

그렇다면 memberList.html 파일을 만들어서 작성해보자.

- memberList.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <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>
</body>
</html>

 

이와 같이 파일을 만들어 준 다음 어플리케이션을 재가동 시켜보자.

이제 회원 가입 링크로 이동해 이름을 입력하여 회원 가입기능을 정상적으로 동작시킨 다음 회원 목록 링크를 클릭해보면 화면상에 memberList.html 파일의 내용이 출력되는데, 여기서 HomeController 의 list() 메소드를 통해 검색한 회원 목록 데이터가 정상적으로 잘 출력 되는것을 확인해 볼 수 있다.(화면의 페이지 소스 보기를 해보면 검색된 데이터들이 html 태그로서 잘 랜더링 되있는것 또한 확인해볼 수 있다.)

* html 코드 자체에서는 하나의 데이터만 보여주는 출력문이 있는데 반해, 화면에 랜더링된 html 코드는 검색된 회원들의 숫자 만큼 출력문이 생성되어 있다.

memberList.html 출력 결과

 

thymeleaf 의 기능이 십분 활용된 memberList.html

memberList.html 파일의 코드를 살펴보면 table 태그 내부의 tr 태그에서 ${members} 가 있는것을 확인할 수 있는데, 이는 예전의 정리글에서 말했듯 컨트롤러에서 모델 객체에 실려 넘어온 데이터 값이 적재되는 곳이다.

즉, model 객체에서 members 라는 속성명에 저장해둔 데이터가 화면상에서 사용되는 것이다.

여기서 th:each 는 thymeleaf 에서 제공하는 기능들 중 반복문을 수행하는 것인데, 이로 인해 members 에 실려있는 회원 목록 리스트 데이터 값을 화면상에 반복문을 수행하는 출력해 주는 것을 볼 수 있다. (thymeleaf 문법)

 

좀 더 자세히?

첫번째로 ${members} 에 실려있는 리스트 데이터 값의 요소 하나하나를 순서대로 member 에 담아주면 

두번째로 th:each 가 작성되어 있는 tr 태그 내부에 있는 내용을 members 리스트의 끝까지 탐색하면서 수행한다.

여기서 태그 내부의 내용을 보면 ${member.id}, ${member.name} 를 발견할 수 있는데, 이는 현재 member 에 실려있는 Member 객체(리스트에 실려있는 하나하나의 요소 타입) 의 id, name 필드를 출력해주는 것으로 해당 데이터에 대한 접근은 getter 메소드를 통해 이루어진다.(public method)

 

여기서 어플리케이션을 재가동 시키면 현재는 데이터들을 데이터베이스가 아닌 메모리에 적재해 두기 때문에 이전의 작업을 통해서 회원가입에 성공한 데이터들은 서버가 멈춤과 동시에 모두 메모리에서 지워지게 된다.

 

이 다음 강의 부터는 본격적으로 데이터베이스를 활용하며 스프링과 웹 MVC 에 대해 학습해보자.