Return Values

2024. 10. 9. 21:21Spring Framework/Web on Servlet Stack

Spring의 컨트롤러 메서드 리턴 값은 클라이언트에 대한 응답을 구성하는 데 매우 중요한 역할을 합니다. 아래에서는 지원되는 리턴 값 유형을 자세히 설명하고, 각 유형에 대한 샘플 코드를 제공하겠습니다.

1. @ResponseBody

메서드의 리턴 값이 HttpMessageConverter를 통해 변환되어 응답 본문에 작성됩니다. 이는 RESTful 웹 서비스에서 JSON 또는 XML 형식으로 데이터를 리턴할 때 자주 사용됩니다.

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ResponseBodyController {

    @GetMapping("/responsebody")
    @ResponseBody
    public User getUser() {
        return new User("Alice", 30);
    }

    static class User {
        private String name;
        private int age;

        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }

        // Getters
        public String getName() { return name; }
        public int getAge() { return age; }
    }
}

2. HttpEntity<B>, ResponseEntity<B>

HttpEntity 또는 ResponseEntity를 사용하면 HTTP 헤더와 본문을 모두 포함하는 전체 응답을 리턴할 수 있습니다.

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class EntityController {

    @GetMapping("/responseentity")
    public ResponseEntity<User> getUser() {
        HttpHeaders headers = new HttpHeaders();
        headers.add("Custom-Header", "value");

        User user = new User("Bob", 25);
        return ResponseEntity.ok()
                             .headers(headers)
                             .body(user);
    }

    static class User {
        private String name;
        private int age;

        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }

        // Getters
        public String getName() { return name; }
        public int getAge() { return age; }
    }
}

3. HttpHeaders

헤더만 리턴하고 본문은 포함하지 않는 경우입니다.

import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HeadersController {

    @GetMapping("/headers")
    public HttpHeaders getHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.add("Custom-Header", "value");
        return headers;
    }
}

4. String / View

문자열을 리턴하면 뷰 이름으로 해석되어 ViewResolver를 통해 렌더링됩니다.

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

@Controller
public class StringViewController {

    @GetMapping("/viewname")
    public String getViewName(Model model) {
        model.addAttribute("message", "Hello, Thymeleaf!");
        return "greeting"; // greeting.html로 이동
    }
}

5. ModelAndView

모델과 뷰 속성을 모두 포함하여 리턴할 수 있습니다.

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

@RestController
public class ModelAndViewController {

    @GetMapping("/modelandview")
    public ModelAndView getModelAndView() {
        ModelAndView mav = new ModelAndView("greeting");
        mav.addObject("message", "Hello, ModelAndView!");
        return mav;
    }
}

6. void

메서드가 void를 리턴하면 응답이 완전히 처리된 것으로 간주되며, ServletResponse, OutputStream 인수 또는 @ResponseStatus 애너테이션을 사용할 수 있습니다.

import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class VoidResponseController {

    @PostMapping("/void")
    public void handleVoid(HttpServletResponse response) {
        response.setStatus(HttpServletResponse.SC_NO_CONTENT);
    }
}

7. DeferredResult<V>

비동기적으로 결과를 리턴할 수 있습니다. 예를 들어, 백그라운드에서 작업이 완료된 후 결과를 클라이언트에 반환합니다.

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.DeferredResult;

import java.util.concurrent.CompletableFuture;

@RestController
public class DeferredResultController {

    @GetMapping("/deferred")
    public DeferredResult<String> handleDeferred() {
        DeferredResult<String> deferredResult = new DeferredResult<>();

        // 비동기 작업 예시
        CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(2000); // 지연 시간
                deferredResult.setResult("Deferred Result after 2 seconds");
            } catch (InterruptedException e) {
                deferredResult.setErrorResult("Error occurred");
            }
        });

        return deferredResult;
    }
}

8. Callable<V>

Spring MVC 관리 스레드에서 비동기적으로 리턴할 수 있습니다.

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.Callable;

@RestController
public class CallableController {

    @GetMapping("/callable")
    public Callable<String> handleCallable() {
        return () -> {
            Thread.sleep(2000); // 지연 시간
            return "Callable Result after 2 seconds";
        };
    }
}

9. StreamingResponseBody

비동기적으로 응답 OutputStream에 작성할 수 있습니다. 스트리밍 데이터 전송에 유용합니다.

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import java.io.IOException;
import java.io.OutputStream;

@RestController
public class StreamingResponseBodyController {

    @GetMapping("/stream")
    public StreamingResponseBody stream() {
        return outputStream -> {
            try {
                for (int i = 0; i < 10; i++) {
                    outputStream.write(("Line " + i + "\n").getBytes());
                    outputStream.flush();
                    Thread.sleep(500); // 지연 시간
                }
            } catch (IOException | InterruptedException e) {
                // 예외 처리
            }
        };
    }
}

10. 기타 리턴 값

리턴 값이 다른 방법으로 해결되지 않으면, 모델 속성으로 처리됩니다. 단, 간단한 유형인 경우에는 @ModelAttribute로 간주됩니다.

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OtherReturnValueController {

    @GetMapping("/other")
    public User getUser() {
        return new User("Charlie", 35);
    }

    static class User {
        private String name;
        private int age;

        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }

        // Getters
        public String getName() { return name; }
        public int getAge() { return age; }
    }
}

Spring에서 컨트롤러 메서드의 리턴 값은 클라이언트에 대한 응답을 정의하는 중요한 역할을 합니다. 다양한 리턴 값 유형을 통해 RESTful API부터 전통적인 MVC 구조까지 여러 가지 방식으로 응답을 처리할 수 있습니다. 각 리턴 값의 유형은 사용 사례에 따라 다르게 활용될 수 있습니다.

<참고> : https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-methods/return-types.html

'Spring Framework > Web on Servlet Stack' 카테고리의 다른 글

Annotated Controllers  (0) 2024.10.09
Type Conversion  (0) 2024.10.09
Method Arguments  (0) 2024.10.09
Handler Method  (0) 2024.10.09
Mapping Requests  (0) 2024.10.09