본문으로 건너뛰기

컨트롤러 다루기

스프링에서 컨트롤러

컨트롤러 기본사용

HelloController.java
import org.springframework.stereotype.Controller;

@Controller
public class HelloController {

}

@Component를 상속한 @Controller는 @Controller가 붙은 클래스의 객체를 메모리에 생성하는 기능을 제공 단순히 객체를 생성하는 것에 그치지 않고, DispatcherServlet이 인식하는 Controller객체로 만들어준다

만일 @Controller를 사용하지 않는다면, 다음의 예처럼 모든 클래스는 반드시 스프링에서 제공하는 Controller 인터페이스를 구현해야 한다. 그리고 handleRequest() 메소드를 반드시 재정의하여 DispatcherServlet이 모든 Controller의 handleRequest() 메소드를 호출할 수 있도록 해야 한다.

HelloController.java
package com.study.spring;

import org.springframework.web.servlet.mvc.Controller;

public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
System.out.println("hello");
return null;
}
}

하지만 이렇게 구현한 Controller는 스프링 프레임워크가 지향하는 POJO(Plain Old Java Object)스타일의 클래스가 아니다. Controller를 POJO 스타일의 클래스로 구현하려면 우선 클래스 선언부에 있는 "implements Controller"를 제거하고 클래스 위에 "@Controller"를 선언해야 한다. 스프링 컨테이너는 @Controller가 선언된 객체를 자동으로 Controller 객체로 인식한다.

@RequestMapping 사용하기

제일 처음의 코드처럼 @Controller를 클래스 위에 추가함으로써 HelloController을 컨트롤러 로써 인식하게 할 수는 있지만, 클라이언트의 특정 uri요청에 대해서 특정 메서드가 실행되도록 할 수는 없다. 기존에는 HandlerMapping을 이용하여 클라이언트의 요청을 매핑했었다.
스프링에서는 @RequestMapping을 이용하여 HandlerMapping설정을 대체한다.
@RequestMapping을 메서드 위에 써줌으로써 각 메서드를 uri에 매핑시켜준다.

여기까지가 스프링 퀵 스타트에서 발췌한 인용문 이다.

간단하게 컨트롤러를 어떤식으로 써야하는지 왜 이렇게 써야 하는지 알아보았다.


이제 실제 사용법을 좀 알아보자

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class HelloController {

@RequestMapping(value = "/hello-people", method = { RequestMethod.GET })
@ResponseBody
public Map<String, Object> getHelloPeople() {

Map<String, Object> result = new HashMap<String, Object>();

return result;
}
}

Spring 4.3부터는 다음과 같은 어노테이션이 추가되었으므로, 위의 코드를 조금더 간편하게 쓸 수 있다.

  • @PostMApping
  • @GetMApping
  • @PutMApping
  • @PDeleteMApping
  • @PatchMApping

다음과 같은 코드를

@RequestMapping(value="/hello-people", method = { RequestMethod.GET}

이렇게 쓸 수 있다.

// GET메서드로 받을때는 GetMapping을 import해준다
import org.springframework.web.bind.annotation.GetMapping;

@GetMapping("/hello-people")

잠깐....

@RequestMapping의 기본사용에 대해서 조금더 알아보자

@RequestMapping(value="/test", method=RequestMethod.GET, headers="Accept=application/*", params="id=002")
  • value : uri를 지정한다.
  • method : HTTP메소드를 지정한다
  • headers : HTTP헤더를 지정한다. 헤더명이 지정되었을 경우 그 헤더가 존재하는지 매칭판정을 한다. 위의 경우는 Accept헤더에 application/*에 매치되는 값이 설정되었을 경우 매치판정이 된다.
  • params : 헤더와 같은 방법으로 기재한다. 위의 경우는 id가 002일 경우에 매치된다.

단순하게 View를 통한(thymeleaf나 freemarker 등의) 페이지 uri를 리턴하려고 한다면 @ResponseBody 를 빼고 리소스 쪽의 templates의 파일구조대로 적어주면 된다.

@ResponseBody 로 어노테이션이 있으면 메소드의 리턴값을 View(thymeleaf등등)로 출력하지않고 HTTP Response Body에 직접 매핑한다
반대로 @ResponseBody를 쓰지않으면 View(thymeleaf등등)쪽을 엑세스하게하여 템플릿엔진이 렌더링한 결과를 HTTP Response로 매핑한다

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HelloController {

@GetMapping(value = "/hello")
public String hello() {
return "hello";
}
}

위의 경우는 thymeleaf나 freemarker 등의 템플릿 엔진의 리소스가 있는 templates/hello.html 을 로드한다.

만약 하위 폴더구조를 갖고 있는경우에는 다음과 같이 사용하면 된다.

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HelloController {
@GetMapping(value = "/hello")
public String helloworld() {
return "hello/hello";
}
}

templates/hello/hello.html을 로드한다.


@RequestHeader을 사용 할 경우

@RequestMapping("/test")
public ModelAndView test(@RequestHeader(value="User-Agent", required=false) String agent, ModelAndView mav) {
...
}

@CookieValue을 사용 할 경우

@RequestMapping("/test")
public ModelAndView test(@CookieValue(value="SESSIONID", required=false) String sid, ModelAndView mav) {
...
}

@RequestParam어노테이션을 사용 할 경우

@Controller
public class HelloController {
@GetMapping(value = "/hello")
public String helloworld(
@RequestParam(value = "world",required = false) String world {
return helloService.getWorldMsg(world);
}
}

required의 기본은 true이기 때문에 클라이언트쪽에서 값을 안넘겨주면 에러가 발생한다
값을 보내도 안보내도 상관없을때는 false로 해준다.

파라미터가 복수일때 필수는 true로 필수가 아닌것은 false로 사용하면 된다.

@PathVariable을 사용 할 경우

@Controller
public class HelloController {
@GetMapping(value = "/hello/{worldId}")
public World getWorldMsg(@PathVariable(name = "worldId") Integer worldId) {
return helloService.getWorldMsg(worldId);
}
}

매핑 쪽에 {}안에 변수식으로 적어주고 @PathVariable(name = 부분을 맞춰준다.

단순히 Map형일때

@Controller
public class HelloController {
@GetMapping(value = "/hello")
public World getWorldMsg(@RequestBody Map<String, String> param) {
String id = param.get("id");
String pwd = param.get("password");
String email = param.get("email");
return helloService.setInfo(id,pwd,email);
}
}

DTO를 굳이 안만들어도 될때 이렇게 사용도 가능하다.


@Controller와 @RestController의 차이.

@Controller
전통적인 Spring MVC의 컨트롤러 View 기술사용
@ResponseBody를 사용하면 View를 리턴하지 않고
Controller에서 직접 데이터 리턴 가능
Spring4.0부터 @RestController를 통해 더 단순화 되었다.

@RestController
Restful 웹서비스의 컨트롤러
반환 되는 객체 데이터 타입 : JSON/XML 타입의 HTTP 응답을 직접 리턴

실행 흐름
@Controller의 실행 흐름
Client -> Request -> Dispatcher Servlet -> Handler Mapping -> Controller -> View -> Dispatcher Servlet -> Response -> Client

@ResponseBody의 실행 흐름 Client -> Request -> Dispatcher Servlet -> Handler Mapping -> Controller (ResponseBody) -> Response -> Client

@RestController의 실행 흐름 Client -> HTTP Request -> Dispatcher Servlet -> Handler Mapping -> RestController (자동 ResponseBody 추가) -> HTTP Response -> Client

출저
링크 : Spring, @Controller @RestController 차이