본문 바로가기
기초 및 언어/▶ Spring

04. Spring MVC에서 데이터 전달하기

by 류딩이 2025. 9. 19.

🌈컨트롤러에서 폼 데이터를 받는 방법 

📑 목차

1️⃣ HttpServletRequest & Model

2️⃣ @RequestParam + VO/DTO

3️⃣ ModelAndView

4️⃣ 커맨드 객체

5️⃣ @ModelAttribute

⭐ 배열(체크박스) 뷰에 넘기는 법

⭐ 배열 출력할때 컴마 마지막에 항목엔 안찍고 넘기는 법

⭐ MVC란?

 


  • 화면을 띄울 때 : @GetMapping("/form") ==> http://localhost:9292/form
  • 폼 제출 처리용 :@PostMapping("/input1") 

✅ HTML파일에  최상단에 작성 (result와 form 최상단에 기입)

// Thymeleaf 문법(th:text, th:each, th:action 등)을 사용
<html lang="en" xmlns:th="http://www.thymeleaf.org">

 

 Controller 예제 (전체코드)

package com.example.Ex02;

import com.example.Ex02.dto.MusicBean;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HomeController {

    // http://localhost:9292/form
    //@RequestMapping(value="/form",method=RequestMethod.GET)
    @GetMapping(value="/form")
    public String form(){
        return "form";
    }

	 // 1. HttpServletRequest & Model 사용
    //@RequestMapping(value="/input", method=RequestMethod.POST)
    @PostMapping(value="/input1")
    public String input1(HttpServletRequest request, Model model){

        String title = request.getParameter("title");
        String singer = request.getParameter("singer");
        String price = request.getParameter("price");

        System.out.println(title+"/"+singer+"/"+price);

        request.setAttribute("rtitle",title);
        model.addAttribute("mtitle",title);

        request.setAttribute("rsinger",singer);
        model.addAttribute("msinger",singer);

        request.setAttribute("rprice",price);
        model.addAttribute("mprice",price);
        return "music/result1"; // view
    }
	
    // 2. @RequestParam + VO/DTO 사용
    @PostMapping("/input2")
    public String input2(@RequestParam("title") String title,
                         @RequestParam("singer") String singer,
                         @RequestParam("price") int price,Model model) {

        //String title = request.getParameter("title");
        System.out.println(title+"/"+singer+"/"+price);

        MusicBean music = new MusicBean();
        music.setTitle(title);
        music.setSinger(singer);
        music.setPrice(price);

        model.addAttribute("music",music);
        return "music/result2";
    }

	// 3. ModelAndView 사용
    @PostMapping("/input3")
    public ModelAndView input3(HttpServletRequest request) {

        String title = request.getParameter("title");
        String singer = request.getParameter("singer");
        String price = request.getParameter("price");

        ModelAndView mav = new ModelAndView();
        mav.addObject("title",title);
        mav.addObject("singer",singer);
        mav.addObject("price",price);
        mav.addObject("addr","서울");

        MusicBean music = new MusicBean();
        music.setTitle(title);
        music.setSinger(singer);
        music.setPrice(Integer.parseInt(price));
        mav.addObject("mavMusic",music);

        mav.setViewName("music/result3");
        return mav;
    }

	// 4. 커맨드 객체 (VO/DTO 자동 바인딩)
    @PostMapping("/input4")
    public String input4(MusicBean mb) {
        //MusicBean mb : command 객체
       /* String title = request.getParameter("title");
        String singer = request.getParameter("singer");
        String price = request.getParameter("price");

        MusicBean music = new MusicBean();
        music.setTitle(title);
        music.setSinger(singer);
        music.setPrice(Integer.parseInt(price));

        model.addObject("bean",music);*/

        System.out.println(mb.getTitle());
        System.out.println(mb.getSinger());
        System.out.println(mb.getPrice());
        return "music/result4";
    }

	// 5. @ModelAttribute 사용 (4번의 커맨드 객체를 별칭으로 만듬)
    @PostMapping("/input5")
    public String input5(@ModelAttribute("bean") MusicBean mb) {
        //model.addObject("musicBean",music);

        return "music/result5";
    }
}

 

📄 form.html 예제 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Form 입력</title>
</head>
<body>
<form th:action="@{/input1}" method="post">
    제목 : <input type="text" name="title"><br>
    가수 : <input type="text" name="singer"><br>
    가격 : <input type="number" name="price"><br>
    <button type="submit">전송</button>
</form>
</body>
</html>

👉 th:action="@{/input1}" 부분만 @{/input2}, @{/input3} … 로 바꿔가며 테스트

 

📄 MusicBean 예제 

package com.example.Ex02.dto;
import java.util.List;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class MusicBean {
    private String title;
    private String singer;
    private int price;
    //private List<String> hobby; // 배열<체크박스>

}

 

⬆ 맨 위로 가기


1️⃣ HttpServletRequest & Model

// 2. @RequestParam + VO/DTO 사용
@PostMapping("/input2")
public String input2(@RequestParam("title") String title,
                     @RequestParam("singer") String singer,
                     @RequestParam("price") int price,Model model) {

    //String title = request.getParameter("title");
    System.out.println(title+"/"+singer+"/"+price);

    MusicBean music = new MusicBean();
    music.setTitle(title);
    music.setSinger(singer);
    music.setPrice(price);

    model.addAttribute("music",music);
    return "music/result2";
}

result1.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Result1</title>
</head>
<body>
<h2>입력값 출력 비교</h2>

<!-- 1. param : request.getParameter()와 동일 -->
<p>param.title : <span th:text="${param.title}"></span></p>
<p>param.singer : <span th:text="${param.singer}"></span></p>
<p>param.price : <span th:text="${param.price}"></span></p>

<hr>

<!-- 2. request.setAttribute() 로 저장한 값 -->
<p>rtitle (request) : <span th:text="${rtitle}"></span></p>
<p>rsinger (request) : <span th:text="${rsinger}"></span></p>
<p>rprice (request) : <span th:text="${rprice}"></span></p>

<hr>

<!-- 3. model.addAttribute() 로 저장한 값 -->
<p>mtitle (model) : <span th:text="${mtitle}"></span></p>
<p>msinger (model) : <span th:text="${msinger}"></span></p>
<p>mprice (model) : <span th:text="${mprice}"></span></p>

</body>
</html>

 

  • ${param.xxx} 는 폼 input name 그대로 접근하는 방식,
  • ${rtitle} 는 request에 직접 저장한 값,
  • ${mtitle} 는 model에 추가한 값

⬆ 맨 위로 가기


2️⃣ @RequestParam + VO/DTO

// 2. @RequestParam + VO/DTO 사용
@PostMapping("/input2")
public String input2(@RequestParam("title") String title,
                     @RequestParam("singer") String singer,
                     @RequestParam("price") int price,Model model) {

    //String title = request.getParameter("title");
    System.out.println(title+"/"+singer+"/"+price);

    MusicBean music = new MusicBean();
    music.setTitle(title);
    music.setSinger(singer);
    music.setPrice(price);

    model.addAttribute("music",music); // 👉 Model에 저장
    // model.addAttribute("music", new MusicBean(title, singer, price))
    
    return "music/result2";	 // 👉 뷰 이름 문자열 반환
}

 

 

@RequestParam 의 역할

  • request.getParameter() + 타입 변환(int, double 등) 과정을 자동으로 대신 해주는 축약 문법

✅일반 클래스 객체 생성 다른점

일반 클래스 객체 생성:

// 일반 클래스 객체 생성: 단순히 메모리에 객체 생성 (컨트롤러 내부에서만 사용 가능).
MusicBean mb = new MusicBean(title, singer, price);
→ 이 상태로는 뷰(JSP/Thymeleaf)에서 접근 불가.

 

Model에 담은 경우:

model.addAttribute("music", mb);
→ request scope에 "music" 이름으로 객체 저장 → 뷰에서 ${music.title} 로 접근 가능.

 

result2.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    music/result2.html <br>
    제목1 : <span th:text="${param.title}"></span><br> // 출력❌
    
    
    제목2 : <span th:text="${music.title}"></span><br>
    가수1 : <span th:text="${music.singer}"></span><br>
    가격1 : <span th:text="${music.price}"></span><br>
</body>
</html>

⬆ 맨 위로 가기


3️⃣ ModelAndView (단일값 전달, 객체 전달) 2가지

  • Model + View를 하나의 객체(ModelAndView)에 담아서 반환.
  • 데이터(addObject)뷰 이름(setViewName)을 한 번에 처리.

3-1) 단일 값 전달 방식

// 3-1. ModelAndView (단일 값 전달)
@PostMapping("/input3")
public ModelAndView input3(HttpServletRequest request) {

    String title = request.getParameter("title");
    String singer = request.getParameter("singer");
    String price = request.getParameter("price");

    ModelAndView mav = new ModelAndView();
    // 단일 값 추가
    mav.addObject("title", title);
    mav.addObject("singer", singer);
    mav.addObject("price", price);
    mav.addObject("addr", "서울");

    mav.setViewName("music/result3"); // 뷰 이름 지정
    return mav;
}
  • addr → 그냥 "서울" 이라는 문자열을 모델에 직접 담음. (VO와 무관)
  • mavMusic → MusicBean 객체 (title, singer, price 필드만 존재)

3-2) VO/DTO 객체 전달 방식

// 3-2. ModelAndView (VO/DTO 전달)
@PostMapping("/input3")
public ModelAndView input3(HttpServletRequest request) {

    String title = request.getParameter("title");
    String singer = request.getParameter("singer");
    String price = request.getParameter("price");

    // VO/DTO 객체 생성 후 값 설정
    MusicBean music = new MusicBean();
    music.setTitle(title);
    music.setSinger(singer);
    music.setPrice(Integer.parseInt(price));

    ModelAndView mav = new ModelAndView();
    mav.addObject("mavMusic", music);

    mav.setViewName("music/result3"); // 뷰 이름 지정
    return mav;
}

 

reulst3.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    music/result3.html<br>

	// 단일 값 전달
    title : <span th:text="${title}"></span><br>
    singer : <span th:text="${singer}"></span><br>
    price : <span th:text="${price}"></span><br>
    addr : <span th:text="${addr}"></span><br>
    
    <hr>
    
    // 객체전달
    제목: <span th:text="${mavMusic.title}"></span><br>
    가수: <span th:text="${mavMusic.singer}"></span><br>
    가격: <span th:text="${mavMusic.price}"></span><br>
    
    //addr은 컨트롤러에서 단일 값으로만 모델에 담았기 때문에 ${mavMusic.addr} 로는 출력할 수 없음

</body>
</html>

✅ 핵심 정리

  • ${mavMusic.xxx} → MusicBean 안에 있는 필드여야만 출력 가능.
  • addr은 VO에 없는 값이라 ${mavMusic.addr}은 불가능.
  • VO에 추가하거나, 단일 값 그대로 ${addr}로 출력해야 함.

⬆ 맨 위로 가기


4️⃣ 커맨드 객체

규칙

  1. 클래스 이름 그대로 가져옴 → MusicBean
  2. 첫 글자를 소문자로 바꿈 → musicBean

👉 그래서 뷰에서 접근할 땐 ${musicBean.title}, ${musicBean.singer}, ${musicBean.price}

// 4. 커맨드 객체 (VO/DTO 자동 바인딩)
@PostMapping("/input4")
public String input4(MusicBean mb) {
	  //MusicBean mb : command 객체
   
    return "music/result4";
}
더보기

✅커맨드객체를 넣으면 자동으로 스프링이 모델에 담아줌

 실제론 아래 작업이 이루어짐
   String title = request.getParameter("title");
    String singer = request.getParameter("singer");
    String price = request.getParameter("price");

    MusicBean music = new MusicBean();
    music.setTitle(title);
    music.setSinger(singer);
    music.setPrice(Integer.parseInt(price));

    model.addObject("bean",music);
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    music/result4.html<br>
    제목: <span th:text="${musicBean.title}"></span><br>
    가수: <span th:text="${musicBean.singer}"></span><br>
    가격: <span th:text="${musicBean.price}"></span><br>
</body>
</html>

 

기본 이름 = 클래스명에서 첫 글자만 소문자로 바꾼 것.

소문자로 출력!

⬆ 맨 위로 가기


5️⃣ @ModelAttribute 

  • 4번의 커맨드객체에 별칭만 추가한 것
@PostMapping("/input5")
public String input5(@ModelAttribute("bean") MusicBean mb) {

    return "music/result5";
}

 

@ModelAttribute("bean")

  • 커맨드 객체 MusicBean mb가 자동으로 모델에 등록될 때,
  • 기본 이름(musicBean) 대신 "bean" 이라는 이름으로 저장됨.
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    music/result5.html<br>
    제목:<span th:text="${bean.title}"></span><br><hr>
    가수:<span th:text="${bean.singer}"></span><br><hr>
    가격:<span th:text="${bean.price}"></span><br><hr>
</body>
</html>

 

  • 접근할때 별칭으로 접근해야함

Controller 의 매핑과 form 태그 연결

Controller의 @Post

 

@GetMapping("/input1")

@PostMapping("/input1")

@RequestMapping(value="/input2", method=RequestMethod.Get)
@RequestMapping(value="/input2", method=RequestMethod.POST)
@RequestMapping(value="/input2")

Spring Controller 매핑

<form th:action="@{/input1}" method="post">
    제목 : <input type="text" name="title"><br>
    가수 : <input type="text" name="singer"><br>
    가격 : <input type="number" name="price"><br>
    <button type="submit">전송</button>
</form>

⬆ 맨 위로 가기


⭐ 배열(체크박스) 처리

 

📌 5가지 방식에서 배열 처리 비교

1️⃣ HttpServletRequest & Model

@PostMapping("/input1")
public String input1(HttpServletRequest request, Model model) {
    String[] hobby = request.getParameterValues("hobby");

    request.setAttribute("rhobby", hobby);
    model.addAttribute("mhobby", hobby);

    return "result1";
}

뷰(result1.html):

취미(request) :
<span th:each="h : ${rhobby}" th:text="${h} + ' '"></span>

취미(model) :
<span th:each="h : ${mhobby}" th:text="${h} + ' '"></span>

 

2️⃣ @RequestParam + VO/DTO

@PostMapping("/input2")
public String input2(@RequestParam("hobby") String[] hobby, Model model) {
    model.addAttribute("mhobby", hobby);
    return "result2";
}

뷰(result2.html):

취미 :
<span th:each="h : ${mhobby}" th:text="${h}"></span>

3️⃣ ModelAndView

@PostMapping("/input3")
public ModelAndView input3(HttpServletRequest request) {
    String[] hobby = request.getParameterValues("hobby");

    ModelAndView mav = new ModelAndView();
    mav.addObject("hobbyArr", hobby);
    mav.setViewName("result3");

    return mav;
}

 

뷰(result3.html):

취미 :
<span th:each="h : ${hobbyArr}" th:text="${h}"></span>

4️⃣ Command 객체 (VO/DTO 자동 바인딩)

VO 클래스:

public class Member {
    private String name;
    private String age;
    private String[] hobby; // ✅ 배열 필드
    // getter, setter
}

컨트롤러:

@PostMapping("/input4")
public String input4(Member member) {
    return "result4";
}

뷰(result4.html):

취미 :
<span th:each="h : ${member.hobby}" th:text="${h}"></span>

5️⃣ @ModelAttribute

@PostMapping("/input5")
public String input5(@ModelAttribute("bean") Member member) {
    return "result5";
}

뷰(result5.html):

취미 :
<span th:each="h : ${bean.hobby}" th:text="${h}"></span>

 


⭐ 배열 출력 마지막에 , 안 붙이는 방법 3가지

 

// 1) th:if 조건문과 조합
취미 : 
<span th:each ="rh, stat : ${rhobby}">
          <span th:text="${rh}"></span>
          <span th:if="${not stat.last}">, </span>
</span>

// 2-1) 삼항연산자 not 사용 ==> h가 마지막이 아니면 ' , '
취미 :
<span th:each="h, stat : ${mhobby}">
    <span th:text="${h + (not stat.last ? ', ' : '')}"></span>
</span>


// 2-2) 삼항연산자 사용 ==> h가 마지막이면  ' '
취미 : 
<span th:each ="h, stat : ${member.hobby}"
        th:text="${h + (stat.last ? '':', ')}"></span>

 

 

 

// 3. 컨트롤러에서 반복문 돌려서 출력
    @PostMapping(value="/input1")
    public String input1(HttpServletRequest request, Model model){

       String name = request.getParameter("name");
       String age = request.getParameter("age");
       String[] hobby = request.getParameterValues("hobby"); // 요리, 게임
       
       String temp="";
        for(String hb : hobby){
            temp += hb+" ";

        request.setAttribute("rhobby",temp);
        model.addAttribute("mhobby",temp);

        }

 

✅ 정리

  • 체크박스 같은 다중 선택 값은 배열(String[])로 바인딩된다.
  • 배열 그대로 넘기면 뷰에서 th:each 반복문으로 출력해야 한다.
  • 한 줄로 합쳐서 출력하려면 컨트롤러에서 String.join(", ", hobby) 으로 문자열 변환해서 넘기면 된다.

 

⬆ 맨 위로 가기

 

 


✅ 차이 핵심 표정리

 

구분 2️⃣@RequestParam + VO/DTO 3️⃣ModelAndView
파라미터 추출 @RequestParam 자동 바인딩 request.getParameter() 직접 호출
VO 처리 VO를 수동으로 만들어 model에 담음 VO를 만들어 addObject()로 담음
뷰 이름 String으로 반환 ModelAndView.setViewName()

 

 

 

구분 3️⃣ModelAndView 4️⃣커맨드 객체
파라미터 추출 request.getParameter() 수동 스프링이 자동 바인딩
모델 추가 mav.addObject("키", 값) 수동 자동으로 모델에 들어감
뷰 이름 mav.setViewName("...") 메서드에서 return "뷰이름"
사용 빈도 예전 방식, 지금은 거의 안 씀 실무 표준 👍

⬆ 맨 위로 가기

 

 


📌 MVC란?

Model – View – Controller 의 약자.
애플리케이션을 세 가지 역할로 분리해서 유지보수성과 확장성을 높이려는 구조

1️⃣ Model (모델)

  • 데이터와 비즈니스 로직 담당
  • DB, DAO, VO/DTO, Service 같은 계층이 여기 속해요.
  • ex) MusicBean, User, BoardDao 등

2️⃣ View (뷰)

  • 사용자에게 보여지는 화면
  • HTML, JSP, Thymeleaf, React 같은 UI 부분
  • 데이터는 직접 처리하지 않고, 컨트롤러가 전달해 준 것만 표시

3️⃣ Controller (컨트롤러)

  • 사용자의 요청(Request)을 받아 Model을 호출하고, 결과를 View로 전달
  • 흐름 제어 역할
  • Spring에서는 @Controller 클래스, @RequestMapping, @GetMapping, @PostMapping 등이 이에 해당