본문 바로가기
Spring/스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술

스프링 MVC를 이용해서 회원 관리 웹 만들기

by hk27 2022. 1. 28.
스프링 MVC를 이용해서 어떻게 웹을 만들까요?

 

안녕하세요.

오늘은 스프링 MVC를 이용해서 간단한 회원 관리 웹을 만들어보겠습니다. 

회원 등록 폼을 보여주고, 회원을 저장하고, 회원 목록을 조회하는 웹입니다. 

 

앞서 회원 관리 웹을 서블릿, JSP, MVC 패턴을 적용해서 만들어보았습니다. 

관심 있으신 분은 아래 게시글을 참고해주세요!

함께 코드를 작성하실 분은 가장 위의 게시글 '서블릿으로 회원 관리 웹 만들기'에서 '회원 도메인, 회원 저장소 만들기'를 먼저 수행해주세요! 

서블릿으로 회원 관리 웹 만들기
JSP로 회원 관리 웹 만들기
MVC 패턴을 적용해서 회원 관리 웹 만들기

 

V1 - 시작하기

스프링은 어노테이션 기반 컨트롤러를 제공하기 때문에 정말 간편합니다.

@Controller : 컨트롤러 메소드가 있는 클래스에 @Controller 어노테이션을 붙여서 스프링 빈으로 등록합니다.

스프링 MVC는 클래스를 어노테이션 기반 컨트롤러로 인식합니다.

@RequestMapping : 요청 정보를 매핑합니다. 해당 URL이 호출되면 이 메서드가 호출됩니다. 

 

회원 등록 폼 컨트롤러

@Controller
public class SpringMemberFormControllerV1 {

    @RequestMapping("/springmvc/v1/members/new-form")
    public ModelAndView process(){
        return new ModelAndView("new-form");
    }
}

 

스프링은 @Controller를 보고 클래스를 스프링 빈에 등록하고, 어노테이션 기반 컨트롤러로 인식합니다.

또한 @RequestMapping의 "/springmvc/v1/members/new-form" URL 요청이 들어오면 process 메소드를 수행합니다.

ModelAndView로 모델과 뷰 정보를 담아서 반환 할 수 있습니다. 

논리 이름을 담아서 전송하면, 디스패처 서블릿이 뷰 리졸버를 불러서 물리 이름으로 변환합니다.

저는 prefix를 /WEB-INF/views/로, suffix를 .jsp로 설정했기 때문에 /WEB-INF/views/new-form.jsp 파일로 포워드 됩니다.

뷰 리졸버의 동작 방식과 prefix, suffix 설정은 아래 게시글을 참고해주세요.

핸들러 매핑, 핸들러 어댑터, 뷰 리졸버

 

회원 등록 폼 뷰

src/main/webapp/WEB-INF/views/new-form.jsp 파일은 아래와 같습니다. 

<%@ page contentType = "text/html; charset=UTF-8" language = "java" %>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--상대 경로 사용, [현재 URL이 속한 계층 경로 + /save] -->
<form action="save" method="post">
    username=<input type="text" name="username" />
    age: <input type="text" name="age" />
    <button type="submit">전송</button>
</form>
</body>
</html>

스프링 MVC가 주제이므로 jsp 파일에 대한 설명은 생략하겠습니다. 

 

http://localhost:8080/springmvc/v1/members/new-form에 접속하면 아래와 같은 화면이 뜹니다. 

 

회원 저장 컨트롤러

@Controller
public class SpringMemberSaveControllerV1 {
    private MemberRepository memberRepository = MemberRepository.getInstance();
    
    @RequestMapping("/springmvc/v1/members/save")
    public ModelAndView process(HttpServletRequest request, HttpServletResponse response){
        String username = request.getParameter("username");
        int age= Integer.parseInt(request.getParameter("age"));
        Member member = new Member(username, age);
        System.out.println("member = " + member);
        memberRepository.save(member);
        ModelAndView mv = new ModelAndView("save-result");
        mv.addObject("member", member);
        return mv;
    }
}

회원 저장을 위해서는 파라미터를 받아야 하므로 HttpServletRequest 객체를 메소드의 파라미터로 받았습니다.

또한 뷰로 보낼 데이터는 ModelAndView 객체에 addObject로 담았습니다.

 

회원 저장 폼 뷰

src/main/webapp/WEB-INF/views/save-result.jsp 파일은 아래와 같습니다. 

<%@ page contentType = "text/html; charset=UTF-8" language = "java" %>
<html>
<head>
    <meta charset="UTF-8">
</head>
<body>
성공
<ul>
    <li>id=${member.id}</li>
    <li>username=${member.username}</li>
    <li>age=${member.age}</li>
</ul>
<a href="/index.html">메인</a>
</body>
</html>

 

위에서 만든 회원 가입 폼에 이름과 나이를 입력하면 아래 결과 페이지가 나옵니다.  

 

회원 목록 컨트롤러

@Controller
public class SpringMemberListControllerV1 {
    private MemberRepository memberRepository = MemberRepository.getInstance();

    @RequestMapping("/springmvc/v1/members")
    public ModelAndView process(){
        List<Member> members = memberRepository.findAll();
        ModelAndView mv = new ModelAndView("members");
        mv.addObject("members", members);
        return mv;
    }
}

 

회원 목록 뷰

src/main/webapp/WEB-INF/views/members.jsp

<%@ page contentType = "text/html; charset=UTF-8" language = "java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<a href="/index.html">메인</a>
<table>
    <thead>
    <th>id</th>
    <th>username</th>
    <th>age</th>
    </thead>
    <tbody>
    <c:forEach var="item" items="${members}">
        <tr>
            <td>${item.id}</td>
            <td>${item.username}</td>
            <td>${item.age}</td>
        </tr>
    </c:forEach>
    </tbody>
</table>

</body>
</html>

 

http://localhost:8080/springmvc/v1/members 에 접속하면 아래 페이지가 나옵니다. 

 

지금까지 회원 가입 폼, 회원 저장, 회원 목록을 구현해보았습니다. 

이제 두 단계에 걸쳐서 컨트롤러를 발전 시켜 보겠습니다. 

 

V2 - 컨트롤러 통합

컨트롤러 3개가 현재는 각각 다른 클래스에 속해있는데, 컨트롤러 클래스를 하나로 통합해보겠습니다.

@Controller
@RequestMapping("/springmvc/v2/members")
public class SpringMemberControllerV2 {
    private MemberRepository memberRepository = MemberRepository.getInstance();

    @RequestMapping("/new-form")
    public ModelAndView newForm(){
        return new ModelAndView("new-form");
    }

    @RequestMapping("/save")
    public ModelAndView process(HttpServletRequest request, HttpServletResponse response){
        String username = request.getParameter("username");
        int age= Integer.parseInt(request.getParameter("age"));
        Member member = new Member(username, age);
        memberRepository.save(member);
        
        ModelAndView mv = new ModelAndView("save-result");
        mv.addObject("member", member);
        return mv;
    }

    @RequestMapping
    public ModelAndView members(){
        List<Member> members = memberRepository.findAll();
        
        ModelAndView mv = new ModelAndView("members");
        mv.addObject("members", members);
        return mv;
    }
}

 

클래스 레벨에 @Controller에 더해 @RequestMapping("/springmvc/v2/members")도 붙였습니다. 이렇게 하면 메소드 레벨과 조합이 됩니다. 

예를 들어서 메소드 레벨에 @RequestMapping("/new-form")이 있으면 "/springmvc/v2/members/new-form" URL의 요청이 매핑됩니다.

members 함수처럼 RequestMapping에 주소를 지정하지 않으면 클래스 레벨에서 정한 "/springmvc/v2/members" URL의 요청이 매핑됩니다. 

 

V3 - 실용적인 방식

실무에서 주로 사용하는 방식입니다. 

예시 코드를 봅시다. 

@Controller
@RequestMapping("/springmvc/v3/members")
public class SpringMemberControllerV3 {
    private MemberRepository memberRepository = MemberRepository.getInstance();

    @GetMapping("/new-form")
    public String newForm(){
        return "new-form";
    }

    @PostMapping("/save")
    public String process(@RequestParam("username") String username,
                          @RequestParam("age") int age,
                          Model model){
        Member member = new Member(username, age);
        memberRepository.save(member);

        model.addAttribute("member", member);
        return "save-result";
    }

    @GetMapping
    public String members(Model model){
        List<Member> members = memberRepository.findAll();

        model.addAttribute("members", members);
        return "members";
    }
}

 

V3에서 변화된 점은 아래와 같습니다.

1. Model 도입: save와 members 메소드를 보면 Model 객체를 파라미터로 받아 뷰에 전달해야 하는 값을 addAttribute로 넣습니다. 

2. ViewName 반환: ModelAndView 객체 대신 뷰의 논리 이름 String만 간편하게 반환합니다. 

3. @RequestParam 사용: save 메소드의 파라미터를 보면 @RequestParam("username") String username, @RequestParam("age") int age로 값을 받습니다. 요청 파라미터 이름을 넣고 값을 받습니다. 

4. @RequestMapping -> @GetMapping, @PostMapping : @RequestMapping은 URL만 맞으면 모든 HTTP 메소드 요청을 다 받습니다. @GetMapping, @PostMapping 함수를 사용해서 메소드도 구분할 수 있습니다. Get, Post, Put, Delete, Patch 모두 어노테이션이 준비되어 있습니다.

 

이번 게시글에서는 스프링 MVC를 이용해서 회원 관리 웹을 만들어보았습니다. 

V1부터 V3로 발전시키며 편리한 컨트롤러까지 알아보았습니다.

다음 게시글에서는 스프링 MVC의 여러 기능을 알아보겠습니다. 

 

 

인프런  '스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술' 강의를 듣고 공부하며 정리한 자료입니다. 

잘못된 부분은 피드백 주시면 감사하겠습니다. 

글 읽어주셔서 감사합니다 :-)

 

참고 자료

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술, 섹션 5. 스프링 MVC - 구조 이해 https://www.inflearn.com/course/스프링-mvc-1

댓글