감 잃지말고 개발하기

[Spring][STS][Spring MVC] #3. 스프링 MVC의 Controller 본문

코드로 배우는 스프링 웹 프로젝트(개정판)/Part 2 스프링 MVC 설정

[Spring][STS][Spring MVC] #3. 스프링 MVC의 Controller

persii 2023. 8. 18. 23:19

목표

스프링 MVC를 이용하는 경우 작성하는 Controller는 다음과 같은 특징이 있다.

  • 상속 / 인터페이스 방식 대신 어노테이션만으로 필요한 설정을 할 수 있다.
  • HttpServletRequest, HttpServletResponse 객체를 거의 사용할 필요 없이 필요한 기능을 구현할 수 있다.
  • GET / POST 방식 등의 전송 방식을 어노테이션으로 처리할 수 있다.
  • 다양한 타입의 파라미터를 처리할 수 있다.
  • 다양한 리턴 타입을 사용할 수 있다.

아래의 정리를 통해 특징을 이해해보자.

 

 

1. @Controller, @RequestMapping

@RequestMapping은 현재 클래스의 모든 메서드들의 기본 URL 경로를 설정한다.

 

Controller

 

생성한 SampleController 클래스는 @Controller 어노테이션과 아래 servlet-context.xml의 설정에 의해 자동으로 스프링의 빈으로 등록된다.

 

servlet-context.xml

 

♠ @RequestMapping의 변화

Spring 4.3v부터는 @GetMapping, @PostMapping으로 @RequestMapping 대신 사용할 수 있다.

@RequestMapping(value="/basic", method={RequestMethod.GET, RequestMethod.POST})
public void basicGet() {

}


// From Spring 4.3v
@GetMapping("/basicOnlyGet")
public void basicGet2() {

}

 

2. Controller의 파라미터 수집

Spring MVC에서 Controller가 파라미터를 수집하는 방식에는 크게 두 가지 특징이 있다.

  1. 브라우저에서 넘어온 파라미터를 알아서 수집한다.
    • 따라서 HttpServletRequest 객체의 getParameter() 메서드를 사용할 필요가 없다.
    • "반복되는 코드의 제거"
  2. 브라우저에서 넘어온 파라미터를 해당 메서드의 파라미터 타입으로 자동 변환하여 저장한다.
    • 파라미터 타입으로 객체를 생성하여 파라미터 값을 저장한다.

 

1. VO / DTO 타입으로 수집

- com.zerock.domain 패키지 하위에 SampleDTO 클래스를 생성한다.

package com.zerock.domain;

import lombok.Data;

@Data
public class SampleDTO {

	private String name;
	private int age;
}

 

- SampleController 클래스에 아래 메서드를 작성한다.

  SampleController의 경로가 '/sample/*'이므로 ex01() 메서드를 호출하는 경로는 '/sample/ex01'이 된다.

@GetMapping("/ex01")
public String ex01(SampleDTO dto) {
	log.info(""+dto);
	return "ex01";
}

 

- 확인을 위해 URL 경로 뒤에 'name=이클립스&age=112' 쿼리를 추가해 호출해보자.

  로그를 보면 SampleDTO 객체 안에 name과 age 속성이 저장된 것을 확인할 수 있다.

 

ex01 확인

 

♠ @RequestParam

@RequestParam은 파라미터로 사용된 변수명과 Spring MVC에서 사용하는 파라미터명이 다른 경우 사용할 수 있다.

 

@RequestParam

 

2. List / Array 타입으로 수집

동일한 이름의 파라미터가 여러 개 전달되는 경우 List / Array 타입으로 수집할 수 있다.

스프링은 메서드의 파라미터 타입을 보고 객체를 생성하므로, 인터페이스가 아닌 실제 클래스 타입으로 파라미터 타입을 설정해야 한다.

 

♠ List 타입

@GetMapping("/ex02List")
public String ex02List(@RequestParam("ids") ArrayList<String> ids) {
	log.info("ids: "+ids);
	return "ex02List";
}

 

- 확인을 위해 URL 경로 뒤에 'ids=111&ids=112&ids=113' 쿼리를 추가해 호출해보자.

  동일한 이름의 파라미터가 여러 개 전달되더라도 ArrayList 타입의 객체에 자동으로 수집된다.

 

ex02List 확인

 

♠ Array 타입

@GetMapping("/ex02Array")
public String ex02Array(@RequestParam("ids") String[] ids) {
	log.info("ids: "+ids);
	log.info("ids: "+Arrays.toString(ids));

	return "ex02Array";
}

 

확인을 위해 URL 경로 뒤에 'ids=112&ids=113&ids=114' 쿼리를 추가해 호출해보자.

 

ex02Array 확인

 

3. 객체 리스트 타입으로 수집

- SampleDTO의 리스트를 포함하는 SampleDTOList 클래스를 생성한다.

package com.zerock.domain;

import java.util.ArrayList;
import java.util.List;

import lombok.Data;

@Data
public class SampleDTOList {
	
	private List<SampleDTO> list;

	public SampleDTOList() {
		list = new ArrayList<SampleDTO>();
	}
}

 

- SampleController에서 SampleDTOList 타입을 파라미터로 사용하는 메서드를 작성한다.

@GetMapping("/ex02Bean")
public String ex02Bean(SampleDTOList list) {
    log.info("list dtos: "+list);
    return "ex02Bean";
}

 

- 확인을 위해 URL 경로 뒤에 'list%5B0%5D.name=aaa&list%5B2%5D.name=bbb쿼리를 추가해 호출해보자.

   '%5B' 및 '%5D'는 각각 '['와 ']'를 의미한다.

 

ex02Bean 확인

 

위의 URL을 호출하면 콘솔 로그의 결과처럼 3개의 SampleDTO 객체가 생성되었고, '[ ]'안에 인덱스 번호에 맞게 객체의

속성값이 세팅된 것을 확인할 수 있다.

 

3. 데이터 전달자 : Model

♠ Model

Controller에서 메서드를 작성할 때 특별히 Model이라는 타입을 파라미터로 지정할 수 있다.

 

Model 객체는 Controller에서 생성된 데이터를 JSP와 같은 뷰로 전달하는 그릇 역할을 하는데,

모델 2 방식에서 사용하는 HttpServletResponse.setAttribute()의 역할과 비슷하다고 할 수 있다.

 

개발자가 메서드파라미터를 Model 타입으로 지정하면, Spring MVC가 Model 타입의 객체를 자동으로 생성하기 때문에 뷰로 보낼 데이터를 일일이 담는 작업을 하지 않아도 된다. 

 

Model은 주로 Controller에 전달된 데이터를 이용해서 추가적인 데이터를 가져와야 하는 경우 사용한다.

 

♠ @ModelAttribute

한편, 스프링 MVC의 Controller는 기본적으로 Java Beans 규칙에 맞는 객체를 뷰로 전달한다.

(이때 클래스명의 앞글자는 소문자로 처리된다)

 

좁은 의미에서의 Java Beans 규칙은

  1. 단순히 생성자가 없거나 빈 생성자를 가지고

  2. getter/setter를 가진 클래스

의 객체들을 의미한다.

 

하지만 기본 자료형의 경우, 메서드의 파라미터로 선언하더라도 기본적으로 뷰까지 전달되지는 않는다.

이때, 우리는 @ModelAttribute를 통해 기본 자료형의 데이터를 뷰로 보낼 수 있다.

 

@ModelAttribute는 전달받은 파라미터를 강제로 Model에 담아서 전달할 때 사용한다.

@ModelAttribute로 지정된 파라미터는 타입에 관계없이 무조건 Model에 담아서 전달되므로, 브라우저에서 건너온 데이터를 다시 화면에서 사용해야 할 때 유용하게 활용할 수 있다.

 

아래 예시로 확인해보자.

 

- SampleDTO 타입과 int 타입의 데이터를 파라미터로 받는 ex04() 메서드를 작성한다.

@GetMapping("/ex04")
public String ex04(SampleDTO dto, int page) {

    log.info("dto: " +dto);
    log.info("page:" +page);

    return "/sample/ex04";
}

 

- 결과를 확인하기 위해 '/WEB-INF/view' 폴더 하위에 sample 폴더를 생성하고 ex04.jsp를 작성한다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>SampleDTO : ${sampleDTO }</h2>
	<h2>page : ${page }</h2>
</body>
</html>

 

- 서버를 실행하고 'http://localhost:8080/sample/ex04?name=AAA&age=12&page=4'를 호출한다.

 

ex04

 

- 해당 ex04() 메서드의 파라미터 page에 @ModelAttribute를 추가해보자.

 

@ModelAttribute 부여

 

- 브라우저를 호출해보자.

 

@ModelAttribute

 

4. 일회성 데이터 전달자 : RedirectAttributes

@RedirectAttributes는 한 번만 사용되는 데이터를 뷰로 전달할 때 사용되며, Model과 같이 파라미터로 선언해서 사용할 수 있다.

기존 서블릿에서 HttpServletResponse.sendRedirect()와 동일한 용도로 사용된다.

@GetMapping("/ex04Redirect")
public String ex04Redirect(RedirectAttributes rttr) {
    rttr.addFlashAttribute("name", "AAA");
    rttr.addFlashAttribute("age", 12);
    
    return "redirect:/";
}

 

5. Controller의 리턴 타입

  • void : 호출하는 URL과 동일한 이름의 jsp를 의미한다.
  • Sring :  jsp를 이용하는 경우, jsp 파일의 경로와 파일이름을 나타내기 위해 사용한다.
    • redirect / forward 키워드를 붙여 사용할 수 있다.
  • VO / DTO 타입 : 주로 JSON 타입의 데이터를 만들어 반환하는 용도로 사용한다.
  • ResponseEntity 타입 : response 할 때 Http 헤더 정보와 내용을 가공하는 용도로 사용한다.
  • Model, ModelAndView : Model로 데이터를 반환하거나 화면까지 같이 지정하는 경우에 사용한다.
  • HttpHeaders : 응답에 내용 없이 Http 헤더 메세지만 전달하는 용도로 사용한다.

 

♠ 객체 타입

Controller의 메서드 리턴 타입을 VO / DTO 타입 등 복합적인 데이터가 들어간 객체 타입으로 지정할 수 있는데, 

이 경우, 주로 JSON 데이터를 만들어 내는 용도로 사용한다.

 

- pom.xml에 jackson-databind 라이브러리를 추가한 후, SampleController에 ex06() 메서드를 생성한다.

 

ex06()

 

- 브라우저를 실행한다.

  객체가 JSON 타입으로 변환되어 전달되었다.

 

ex06() 확인

 

♠ ResponseEntity 타입

Spring MVC는 HttpServletRequest / HttpServletResponse의 직접적인 조작없이 HTTP 프로토콜 헤더를 다룰 수 있는 객체를 제공하는데, 바로 ResponseEntity이다.

ResponseEntity는 org.springframework.http.HttpHeaders 객체를 같이 전달할 수 있으며, 이를 통해 원하는 헤더 정보나 데이터를 뷰에 전달할 수 있다.

 

- SampleController에 ResponseEntity 객체를 리턴하는 ex07() 메서드를 작성한다.

 

ex07()

 

- 브라우저에서 확인한다.

 

ex07() 확인

 

 

정리

1. 스프링 MVC의 Controller : Servlet 보다 쉽게 요청 / 응답 가능

Spring MVC를 사용하면 Spring 내부적으로 Servlet/JSP를 처리하므로

Controller에서 HttpServletRequest / HttpServletResponse 객체의 사용을 지향하면서 요청 및 응답을 처리할 수 있다.

 

2. Controller : 객체 타입으로 파라미터 자동 수집

Controller는 브라우저에서 넘어온 파라미터 타입을 해당 메서드의 파라미터 타입으로 자동으로 변환하여 저장한다.

단, 기본 자료형의 경우, 메서드의 파라미터로 선언하더라도 기본적으로 뷰까지 전달되지 않으므로

이럴 땐@ModelAttribute를 사용해 강제로 Model에 담아서 전달한다.