Server/Spring (Boot & Framework)

[Spring] Spring MVC: Controller return 타입

ooeunz 2020. 4. 6. 22:54
반응형

이번 포스팅에서는 spring controller의 리턴 타입에 대해서 살펴보도록 하겠습니다. 처음 스프링 부트를 배우기 시작했을 때 @RestController 애노테이션을 사용했기 때문에 줄곧 json 타입으로 return을 해왔는데, 우연히 외주 프로젝트를 하며 다른 리턴 타입들을 알게 되었고, @RestController가 어떤 애노테이션인지와 MVC에 대한 이해를 좀 키울 수 있었습니다.

 

String

Spring + View template을 사용할 때 흔히 사용하는 타입입니다.

@GetMapping("/test")
public String test(Model model) {
    model.addAttribute("data", data);
    return "/test/data";
}

Model 안에 데이터를 key, value 값으로 담고, return 타입을 String 값으로 뷰의 이름을 지정해주면 뷰로 데이터가 전송되게 됩니다. 뷰에서는 해당 데이터의 key값을 객체 이름으로 하여 그 안에 데이터를 조회합니다.

 

※ 아래 ${} 코드는 임의로 작성한 것입니다.

대부분의 뷰 템플릿이 이와 비슷한 문법을 사용하고 있으니 사용하는 템플릿의 문법에 맞게 사용하시기 바랍니다. :)

<!DOCTYPE html>
<html>
    <head>
        <title>Document</title>
    </head>
    <body>
        <p>${data.name}</p>
        <p>${data.age}</p>
    </body>
</html>

 

그런데 model에도 여러 종류가 있습니다. 바로 Model, ModelMap, ModelAndView입니다. 구글링을 하다보면 예제마다 다른 객체를 사용하기 때문에 헷갈릴 수 있으므로 짚고 넘어가도록 하겠습니다.

 

Model & ModelMap

결론부터 이야기하면 Model과 ModelMap은 같은 기능입니다. Model은 인터페이스이고, ModelMap은 구현체인데, 스프링 내부적으로는 사용하는 개체의 타입이 동일하기 때문에 개발자의 취향에 따라 선택하여 사용하면 됩니다.

 

 

ModelAndView

반면 ModelAndView는 Model과 View를 동시에 설정가능한 객체입니다. Controller는 ModelAndView 객체만을 반환하지만 Model과 View 모두를 가지고 반환합니다. 생성자로 뷰의 이름을 저장하거나 setViewName() 매서드를 사용하여 뷰 네임을 지정하고, addObject() 메서드로 데이터를 저장합니다.

@GetMapping("/test")
public ModelAndView test() {
    ModelAndView mav = new ModelAndView("test/viewPage");
    modelAndView.addObject("data", "Baeldung");
    return mav;
}

 

 

redirect

redirect: 접두어를 붙이게 되는 경우 지정한 페이지로 리다이렉트가 되게 됩니다. 리다이렉트는 두 가지 방식으로 입력할 수 있습니다.

 

redirect: /api/test -> 현재 서블릿 컨텍스트에 대한 상대적인 경로로 리다이렉트를 하게 됩니다.

redirect: http//:localhost:8080/api/test ->  같이 전체 경로를 적는 경우 절대 경로로 리다이렉트를 하게 됩니다.

@GetMapping("/test")
public ModelAndView test() {
    ModelAndView mav = new ModelAndView();
    mav.setViewName("redirect:/api/test");

    return mav;
}

 

 

void

하지만 독특하게 Spring에서는 뷰의 이름을 지정해주지 않아도 Spring이 해당 url을 보고 뷰 네임을 자동으로 결정하는 기능을 제공합니다. 스프링 설정 파일에 RequestToViewNameTranslator 빈이 존재하지 않을 경우, 기본적으로 DefaultRequestToViewNameTranslator구현체를 사용합니다. 이 클래스는 요청 url에서 제일 앞의 '/'와 확장자를 제외한 나머지 부분을 뷰 네임으로 지정하게 됩니다.

 

@GetMapping("/test/address")
public void void(Model model) {
    model.addAttribute("user", data);
}

위의 예제에서는 test/address가 뷰 네임으로 지정되게 됩니다.

 

 

Map

Model 오브젝트와 동일하게 Map 형태로도 리턴이 가능합니다. 모델과는 조금 다른 점은 개별로 모델이 등록되기 때문에 뷰에서 key.value 형태로 데이터에 접근했던 Model과는 다르게 value만으로 데이터에 접근해야 합니다.그다지 추천하지는 않는 방법이라고 합니다.

 

@GetMapping("/test")
public Map<String, String> test() {
    return data;
}
<!DOCTYPE html>
<html>
    <head>
        <title>Document</title>
    </head>
    <body>
        <p>${name}</p>
        <p>${age}</p>
    </body>
</html>

 

 

@ResponseBody

위의 방법들은 모두 전통적인 Spring MVC 컨트롤러인 @Controller를 사용한 형태로써 View를 반환하기 위해 사용했습니다. 하지만 Spring MVC의 컨트롤러에서도 JSON/XML과 같은 데이터를 반환해야 하는 경우가 있습니다. Spring MVC 컨트롤러에서는 데이터를 반환하기 위해서 @ResponseBody 애노테이션을 붙여줌으로써 JSON 형태로 데이터를 반환해줄 수 있게 됩니다. 주로 SPA나 ajax, 또는 모바일 애플리케이션의 서버와 같은 REST SERVER로서의 역할을 할 때 사용하게 됩니다.

@Controller
public class TestController {
	
	@GetMapping("/test/account")
	@ResponseBody 
	public Account void(Account Account) {
  		return account;
	}
}

 

위의 코드는 Account 객체를 반환하는 형태로써 클라이언트에서는 JSON 데이터로 Account 객체를 받게 됩니다.

 

 

@RestController

RestController는 Restful Controller의 준말로써, Spring MVC Controller에 @ResponseBody가 추가된 것입니다.

@Controller 대신 @RestController 애노테이션을 붙여줌으로써 @Controller와 @ResponseBody 애노테이션 두 가지를 모두 사용하는 효과를 낼 수 있습니다.

@RestController
@RequestMapping("/test")
public class TestController {

    @GetMapping
    public Account test(Account account) {
        return account;
    }
}

 


여기까지 Spring MVC Controller의 return 타입에 대해 알아보았습니다. 저도 여기까지 공부하며 막연히 개발을 할 줄 알았지 스프링의 철학이나 MVC 패턴에 대한 깊은 이해를 갖지 못했었는데, 하나하나 찾아보며 많은 공부가 되었습니다. 특히 MVC나 restful server, was, web server와 같은 헷갈리는 용어들의 헷갈림이 컸었는데, 조금씩 이해를 키워가며 용어들에 대한 이해가 확립되어 가는 것 같아서 기쁩니다. 다음번엔 이러한 용어들에 대해 하나씩 살펴보는 포스팅을 해볼까 합니다. :)

반응형