🔄 Spring MVC의 Redirect vs Forward 완벽 정리
- 요청 흐름을 제어하는 두 가지 방법

 

✅ Redirect와 Forward란?

웹 애플리케이션에서는 컨트롤러에서 다른 URL로 이동시키고 싶을 때가 많습니다.
Spring MVC에서는 이를 위해 Redirect(리다이렉트)Forward(포워드) 두 가지 방법을 제공합니다.


 

🔁 1. Forward (포워드)

📌 개념

서버 내부에서 한 컨트롤러 → 다른 컨트롤러 or 뷰로 요청을 전달
브라우저 주소창은 변하지 않음

🔧 예시 코드

@GetMapping("/step1")
public String forwardExample() {
    return "forward:/step2";
}
  • /step1 요청이 들어오면 서버 내부적으로 /step2로 이동
  • 클라이언트는 여전히 /step1을 보고 있음
  • 같은 request 객체 공유

✅ 특징

항목 설명
요청 방식 서버 내부에서 요청 전달
주소창 변화 ❌ 없음
request 유지 ✅ 유지됨
속도 빠름 (서버 내부 이동이므로)
주 사용처 내부 흐름 제어, request 데이터를 그대로 넘길 때

 

🔀 2. Redirect (리다이렉트)

📌 개념

클라이언트에게 응답을 보내어, 브라우저가 새로운 요청을 하도록 유도
주소창이 새 주소로 변경됨

🔧 예시 코드

@PostMapping("/form")
public String redirectExample() {
    return "redirect:/success";
}
  • /form 요청을 처리한 후, 브라우저에게 /success로 다시 요청하라고 지시
  • 브라우저 주소창이 /success로 바뀜
  • 완전히 새로운 request

✅ 특징

항목 설명
요청 방식 브라우저가 새 요청 수행
주소창 변화 ✅ 바뀜
request 유지 ❌ 사라짐 (new request)
속도 느림 (두 번 요청)
주 사용처 PRG(Post-Redirect-Get), URL 변경 필요 시, 중복 요청 방지 등

 

🔄 Forward vs Redirect 차이 한눈에 보기

항목 Forward Redirect
주소창(URL) 유지됨 (/step1) 변경됨 (/success)
요청 횟수 1회 (서버 내부) 2회 (클라이언트가 다시 요청)
request 데이터 유지됨 (공유 가능) 유지되지 않음 (필요 시 Flash 사용)
주요 사용 시점 내부 이동, 서버 흐름 제어 폼 제출 후 이동, 새 페이지 유도
속도 상대적으로 빠름 상대적으로 느림

 

🧪 실전 예제: 로그인 후 리다이렉트

@PostMapping("/login")
public String login(@RequestParam String id, Model model) {
    boolean success = authService.login(id);

    if (success) {
        return "redirect:/home";
    } else {
        model.addAttribute("msg", "로그인 실패");
        return "loginForm"; // JSP 그대로 렌더링
    }
}
  • 로그인 성공 → Redirect → 새 페이지 이동 (/home)
  • 로그인 실패 → 기존 요청 유지 → 같은 페이지 렌더링

💡 Flash Attributes와 함께 쓰기 (Redirect 시 request 유지 대안)

@PostMapping("/submit")
public String submit(RedirectAttributes redirectAttributes) {
    redirectAttributes.addFlashAttribute("msg", "저장 완료!");
    return "redirect:/result";
}

@GetMapping("/result")
public String resultPage(@ModelAttribute("msg") String msg) {
    // FlashAttribute는 1회성 request로 전달됨
    return "result";
}

✔ RedirectAttributes는 Redirect 시에도 데이터를 1회성으로 안전하게 전달할 수 있게 해주는 도구입니다.


🔚 마무리 요약

상황 Forward 사용 Redirect 사용
서버 내부 이동
브라우저 URL 변경
request 데이터 유지 ❌ (Flash로 대체)
중복 요청 방지 ✅ (PRG 패턴)
성능 측면 빠름 느림 (2번 요청)

Forward는 내부 흐름 제어,
Redirect는 외부 이동 또는 사용자 UX 제어에 적합합니다.

 

상황에 따라 두 가지 방식을 적절히 활용하면,
리소스를 아끼고 사용자 경험을 향상시키는 웹 애플리케이션을 만들 수 있습니다. 😊

 

 

🔍 Lombok @ToString(callSuper = true)란?
- 상속 구조에서 부모 클래스의 필드까지 출력하려면?


✅ @ToString 어노테이션이란?

Lombok에서 제공하는 @ToString은 클래스의 toString() 메서드를 자동으로 생성해주는 어노테이션입니다.

@Getter
@ToString
public class User {
    private String name;
    private int age;
}

위 코드에서 User 객체의 toString()을 호출하면 다음과 같은 문자열을 자동으로 출력합니다:

User(name=철수, age=30)

 


❓ 그런데 상속받은 클래스라면?

public class BaseEntity {
    private LocalDateTime createdAt;
}

@Getter
@ToString
public class Member extends BaseEntity {
    private String name;
}

이 경우 Member의 toString() 결과는 다음과 같습니다:

 
Member(name=철수)

⚠️ 부모 클래스인 BaseEntity의 createdAt 필드는 출력되지 않습니다!


🧩 해결 방법: @ToString(callSuper = true)

@Getter
@ToString(callSuper = true)
public class Member extends BaseEntity {
    private String name;
}

이렇게 하면 toString() 결과에 부모 클래스의 필드까지 포함됩니다:

Member(super=BaseEntity(createdAt=2024-05-18T22:01:23.456), name=철수)

 

📌 언제 사용하면 좋을까?

상황 사용 여부
DTO나 로그 출력을 위해 전체 필드를 보고 싶을 때 ✅ 사용 권장
부모 클래스에도 중요한 값이 있고, 이를 확인해야 할 때 ✅ 사용
부모 클래스에 민감하거나 불필요한 값이 있을 때 ❌ 사용 주의 (민감 정보 노출 위험)
 

⚠️ 주의사항

  1. 상속 구조가 복잡할수록 출력이 길어질 수 있음
    → 지나치게 많은 정보가 노출될 수 있음
  2. 보안 이슈 주의
    → 부모 클래스에 비밀번호, 인증토큰 등 민감 정보가 포함되면 toString()으로 노출될 수 있음
  3. 무한 순환 참조에 주의
    → @ToString.Exclude를 활용해 순환 필드는 제외할 수 있음
@ToString.Exclude
private Member member; // 예: 양방향 참조
 

 

✅ 마무리 정리

항목 설명
어노테이션 @ToString(callSuper = true)
목적 부모 클래스의 필드도 toString()에 포함
주 사용처 상속 구조에서 로그 출력, 디버깅 시 전체 정보 확인
주의사항 민감 정보, 순환 참조, 출력 과다 가능성 고려 필요

@ToString(callSuper = true)는 단순히 로그 예쁘게 보이기 위한 기능이 아니라,
상속 구조에서 정보 누락 없이 객체 상태를 파악할 수 있게 도와주는 도구입니다.
단, 모든 정보를 노출하는 만큼 신중하게 사용하는 것이 좋습니다. 😊

 

 

🧷 @PostConstruct란? - 스프링 빈 생성 이후 초기화 로직 실행

스프링 기반 애플리케이션을 개발하다 보면, 빈이 생성된 직후 한 번만 실행되어야 하는 초기화 작업이 필요할 때가 있습니다.

이럴 때 사용할 수 있는 간단하고 강력한 도구가 바로 @PostConstruct 어노테이션입니다.


✅ @PostConstruct란?

  • Java에서 제공하는 표준 애노테이션(JSR-250)
  • 스프링 빈이 생성된 직후(의존성 주입 완료 후)에 실행할 초기화 메서드에 붙입니다.
  • 별도의 XML 설정 없이, 메서드에 어노테이션만 붙이면 자동 호출됩니다.

🛠 사용 예제

@Component
public class SampleService {

    @PostConstruct
    public void init() {
        System.out.println("SampleService 초기화 완료!");
    }
}

실행 흐름

  1. SampleService 빈 생성됨
  2. 생성자 실행됨
  3. 의존성 주입 완료됨
  4. @PostConstruct가 붙은 init() 메서드 실행됨 ✅

🔄 왜 쓰는 걸까?

  • 생성자에서는 의존성 주입이 완료되지 않았기 때문에, 초기화 코드를 넣기 어려움
  • 빈이 준비된 이후 실행해야 하는 코드 (ex: 캐시 로딩, 외부 API 호출, 로그 등)는 @PostConstruct가 적합

⛔ 주의사항

항목 설명
매개변수 없음 @PostConstruct 메서드는 반드시 파라미터가 없어야 합니다
반환값 없음 void 타입이어야 함
한 번만 실행 스프링이 빈을 초기화할 때 딱 한 번만 호출
메서드는 한 개 권장 여러 개 있어도 되지만, 복잡성 증가로 인해 1개만 사용하는 것이 일반적

🔁 @PostConstruct vs InitializingBean.afterPropertiesSet()

항목 @PostConstruct InitializingBean
선언 방식 어노테이션 기반 인터페이스 구현 기반
구현 부담 적음 높음 (의존성 생김)
스프링 의존도 낮음 (자바 표준) 높음 (Spring 인터페이스)
추천 여부 ✅ 일반적으로 권장 ❌ 특별한 경우에만 사용

⚙️ 언제 사용하면 좋을까?

  • DB에서 설정 값을 미리 로드하고 싶은 경우
  • 외부 API에서 데이터를 미리 가져와야 할 경우
  • 정적 리소스를 초기화할 경우
  • 한 번만 수행돼야 할 초기화 로직이 있을 때

🔄 자주 묻는 질문

❓ 생성자랑 뭐가 다른가요?

  • 생성자는 의존성 주입이 완료되기 전에 실행됩니다.
    → 따라서 @Autowired된 필드는 아직 null일 수 있어요.
  • @PostConstruct는 모든 주입이 끝난 직후 실행되므로, 안정적인 초기화가 가능합니다.

✅ 정리

항목 설명
목적 스프링 빈 초기화 후 한 번 실행될 로직 작성
실행 시점 의존성 주입 완료 후
제한 파라미터 없음, 반환값 없음 (void)
대안 InitializingBean, @Bean(initMethod="...") 등
추천 여부 일반적인 경우엔 @PostConstruct가 가장 간편하고 명확함 ✅

📌 보너스: Spring 6+ / Jakarta 전환 관련

Spring 6부터는 @PostConstruct가 Jakarta 패키지로 이전됨:

import jakarta.annotation.PostConstruct;

 

기존 코드에서 javax.annotation.PostConstruct를 사용 중이라면 Jakarta EE로 마이그레이션이 필요할 수 있습니다.

 

🌐 @RequestBody, @ResponseBody vs HttpEntity(RequestEntity, ResponseEntity)
- 스프링에서 HTTP Body를 처리하는 5가지 방식 정리

 

REST API를 개발하다 보면 HTTP 요청과 응답의 본문(body)을 직접 다뤄야 할 일이 많습니다.

이때 사용할 수 있는 방법이 여러 가지 있는데, 대표적으로 다음과 같은 것들이 있습니다.

 

@RequestBody, @ResponseBody, HttpEntity, RequestEntity, ResponseEntity

 

이름이 비슷해서 헷갈리기 쉽지만, 의도와 활용 방식에 차이가 있습니다.

이번 글에서는 이 5가지의 차이를 명확하게 비교해보겠습니다.


1️⃣ @RequestBody란?

HTTP 요청의 body 내용을 자바 객체로 변환해주는 어노테이션입니다.
→ JSON, XML, plain text 등을 객체로 바꿔줍니다.

@PostMapping("/hello")
public String hello(@RequestBody UserDto user) {
    return "Hello " + user.getName();
}

특징

  • 요청 본문(JSON 등)을 객체로 바로 변환
  • 내부적으로 HttpMessageConverter가 동작
  • 필수 값 (기본적으로 body가 없으면 400 Bad Request 발생)

2️⃣ @ResponseBody란?

자바 객체를 HTTP 응답의 body로 직접 변환해주는 어노테이션입니다.
→ JSON, XML 등으로 자동 직렬화됩니다.

@GetMapping("/user")
@ResponseBody
public UserDto getUser() {
    return new UserDto("철준", 35);
}

특징

  • 반환값이 뷰 이름이 아닌 데이터 자체로 응답
  • @RestController를 쓰면 클래스 전체에 @ResponseBody 적용됨

3️⃣ HttpEntity<T>란?

요청 또는 응답에서 HTTP 본문(body) + 헤더 정보를 함께 가져오거나 응답할 수 있는 객체입니다.

@PostMapping("/entity")
public String handle(HttpEntity<UserDto> request) {
    HttpHeaders headers = request.getHeaders();
    UserDto body = request.getBody();
    ...
}

특징

  • 본문과 헤더를 동시에 받을 수 있음
  • 파라미터로만 사용 가능 (리턴 시에는 ResponseEntity를 씀)

4️⃣ RequestEntity<T>란?

HttpEntity를 상속한 클래스이며, 요청 메서드, URL, 헤더, 본문 등 더 많은 정보를 포함합니다.

 
@PostMapping("/request-entity")
public String handleRequest(RequestEntity<UserDto> request) {
    HttpMethod method = request.getMethod();
    URI url = request.getUrl();
    UserDto body = request.getBody();
    ...
}
  • HttpEntity + HTTP method, URL 정보 포함
  • 요청 정보를 보다 정밀하게 다루고 싶을 때 사용

5️⃣ ResponseEntity<T>란?

응답의 본문 + 상태 코드 + 헤더를 직접 제어할 수 있는 객체입니다.
→ 가장 많이 사용되는 응답 타입

@GetMapping("/response")
public ResponseEntity<UserDto> response() {
    UserDto user = new UserDto("철준", 35);
    return ResponseEntity
        .status(HttpStatus.CREATED)
        .header("Custom-Header", "hello")
        .body(user);
}

특징

  • HTTP 상태 코드, 헤더, 바디를 자유롭게 설정 가능
  • REST API 응답 커스터마이징에 최적

📊 전체 비교표

항목본문 처리헤더 접근상태 코드 설정사용 위치비고

 

항목 본문 처리 헤더 접근 상태 코드 설정 사용 위치 비고
@RequestBody 파라미터 요청 본문을 객체로 변환
@ResponseBody 반환값 객체를 JSON 등으로 응답
HttpEntity<T> 파라미터 헤더 + 바디 접근 가능
RequestEntity<T> 파라미터 HttpMethod, URL 정보 포함
ResponseEntity<T> 반환값 응답 제어용으로 자주 사용

💡 정리 포인트

  • @RequestBody는 클라이언트 → 서버 요청 본문(JSON 등)을 객체로 바꾸는 도구
  • @ResponseBody는 서버 → 클라이언트 응답을 객체 → JSON 등으로 바꾸는 도구
  • HttpEntity는 본문 + 헤더 모두 보고 싶을 때 사용
  • RequestEntity는 요청의 HTTP 메서드, URI까지 알고 싶을 때
  • ResponseEntity는 응답의 상태 코드, 헤더, 본문 모두 직접 조작할 수 있을 때 사용

✨ 마무리

Spring MVC에서 HTTP 요청과 응답을 다룰 때는 상황에 맞는 도구를 선택하는 것이 중요합니다.

  • 단순 요청이라면 @RequestBody, @ResponseBody로 간단하게 처리
  • 헤더나 상태 코드까지 조작이 필요하다면 HttpEntity, ResponseEntity를 활용하자.

 

 


 

 

 

🧰 HttpEntity, RequestEntity, ResponseEntity는 Body만 다룰까?
- HTTP 요청/응답의 전체 구조를 함께 다루는 '컨테이너' 입니다.

 

Spring MVC에서 HttpEntity, RequestEntity, ResponseEntity는 종종 "HTTP Body를 처리할 때 사용하는 객체"로 소개됩니다.

하지만 이 클래스들은 본문(body)뿐 아니라 헤더(header)까지 포함해서, 더 넓은 역할을 수행합니다.

이 클래스들은 "HTTP 요청/응답을 구성하는 모든 정보(본문, 헤더, 상태 코드 등)를 함께 담는 컨테이너"입니다.

📦 HTTP 요청/응답은 어떤 정보로 구성돼 있을까?

HTTP 메시지는 크게 다음 3가지로 구성됩니다:

  1. 상태 라인 / 요청 라인 (Request: GET /hello, Response: HTTP/1.1 200 OK)
  2. 헤더(Header) — Content-Type, Authorization 등
  3. 본문(Body) — JSON, XML, 텍스트 등 실질적인 데이터

☝️ 여기서 핵심 질문:

"스프링에서는 이 모든 걸 어떻게 한 번에 다룰 수 있을까?"

 

그때 등장하는 것이 바로:

  • HttpEntity<T>
  • RequestEntity<T>
  • ResponseEntity<T>

이들은 단순히 Body만 처리하는 것이 아니라,
HTTP 메시지를 이루는 구조 전체를 객체로 감싸서 통합적으로 다루는 도구입니다.


1️⃣ HttpEntity<T> - 요청/응답의 헤더 + 바디를 함께 담는 기본 컨테이너

public class HttpEntity<T> {
    private final HttpHeaders headers;
    private final T body;
}
  • headers: 요청 또는 응답의 HTTP 헤더
  • body: JSON 등 본문 데이터

✔ 특징

  • 요청과 응답 양쪽에서 사용 가능
  • 상태 라인(메서드, 상태코드)은 포함하지 않음

2️⃣ RequestEntity<T> - 요청 전체 정보를 모두 담고 싶은 경우

public class RequestEntity<T> extends HttpEntity<T> {
    private final HttpMethod method;
    private final URI url;
}
  • HttpEntity의 기능 + 요청 라인(HTTP 메서드, URL) 정보까지 포함
  • 예: POST /api/users, GET /api/data

✔ 특징

  • HTTP 요청 메시지의 구조 전체를 객체로 표현 가능
  • 요청 처리 전에 메서드나 URI 조건을 확인하고 분기할 수 있음

3️⃣ ResponseEntity<T> - 응답 전체 구조를 구성하고 반환하는 객체

public class ResponseEntity<T> extends HttpEntity<T> {
    private final HttpStatus status;
}
  • HttpEntity의 기능 + 응답 상태 코드(200 OK, 404 Not Found 등)까지 포함

✔ 특징

  • 바디, 헤더, 상태 코드 모두 커스터마이징 가능
  • 실제 운영 API에서 가장 자주 쓰이는 반환 타입

📊 전체 비교 정리

항목 바디 헤더 상태 코드 라인 정보(method, URL 등) 사용 목적
HttpEntity<T> 요청/응답 헤더+바디 처리
RequestEntity<T> 요청의 메서드, URL까지 필요할 때
ResponseEntity<T> 응답의 상태 코드까지 제어하고 싶을 때

 


💡 실전에서 언제 쓰일까?

요청 처리할 때

@PostMapping("/auth")
public String auth(HttpEntity<?> request) {
    HttpHeaders headers = request.getHeaders();
    // Authorization, User-Agent 등 확인 가능
    ...
}

→ 요청의 헤더와 바디를 함께 확인해야 할 때 유용


응답 보낼 때

@GetMapping("/download")
public ResponseEntity<Void> download() {
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "attachment; filename=data.csv");
    return new ResponseEntity<>(headers, HttpStatus.OK);
}

본문 없이도 헤더와 상태코드를 명확하게 제어 가능


✨ 마무리 요약

  • HttpEntity, RequestEntity, ResponseEntity는 단순한 Body 전달용이 아님
    • → HTTP 메시지의 모든 구조(본문, 헤더, 상태 코드, 요청 메서드 등)를 객체 형태로 다루는 도구
  • 상황에 따라 필요한 정보를 얼마나 정밀하게 제어할 것인지에 따라 적절한 클래스를 선택하면 됩니다.

 

 

 

 

📌 StreamUtils.copyToString() — InputStream을 String으로 쉽게 변환하는 방법

Spring 기반 웹 애플리케이션을 개발하다 보면, 클라이언트로부터 전달받은 HTTP 요청의 InputStream을 문자열로 읽어야 할 때가 있습니다. 이때 유용하게 사용할 수 있는 도구가 바로 StreamUtils.copyToString()입니다.


🔍 StreamUtils.copyToString()이란?

StreamUtils.copyToString()은 Spring Framework에서 제공하는 유틸리티 메서드로, InputStream으로부터 전달받은 바이트 데이터를 문자열(String)로 간편하게 변환해주는 기능을 합니다.

public static String copyToString(InputStream in, Charset charset) throws IOException
  • in: 읽을 대상 InputStream (예: 요청 본문)
  • charset: 변환 시 사용할 문자 인코딩 (예: StandardCharsets.UTF_8)

✅ 어떤 상황에서 쓰일까?

  • 클라이언트가 POST나 PUT 방식으로 JSON, XML, 혹은 일반 텍스트 데이터를 보낼 때
  • 필터나 인터셉터에서 요청 본문을 직접 읽어야 하는 경우
  • 서블릿에서 InputStream을 문자열로 바꾸고 싶을 때

💡 사용 예제

@PostMapping("/example")
public void example(HttpServletRequest request) throws IOException {
    String body = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
    System.out.println("요청 본문: " + body);
}

위 코드는 다음과 같은 요청에서:

POST /example
Content-Type: application/json

{"name":"철준", "age":35}

다음과 같은 출력 결과를 만듭니다:

요청 본문: {"name":"철준", "age":35}

⚠️ 주의할 점

  1. InputStream은 한 번만 읽을 수 있음!
    • copyToString()을 사용한 후에는 같은 InputStream을 다시 읽을 수 없습니다.
    • 여러 번 사용하려면 RequestWrapper를 만들어 캐싱하거나 별도 처리를 해야 합니다.
  2. 인코딩 설정은 반드시 명시해야 함
    • 클라이언트가 보낸 데이터가 UTF-8이 아닐 경우 StandardCharsets.UTF_8로 읽으면 깨질 수 있습니다.
    • Content-Type의 charset 정보를 확인하거나, UTF-8로 통일되게 처리하는 것이 좋습니다.

📦 어디에 정의되어 있나?

StreamUtils는 Spring Core 모듈에 포함되어 있으며, 다음 패키지에 위치해 있습니다:

org.springframework.util.StreamUtils

의존성은 따로 추가할 필요 없이, 스프링 부트 프로젝트에서는 기본적으로 포함되어 있습니다.


✨ 요약

항목 설명
목적 InputStream → String 변환
위치 org.springframework.util.StreamUtils
주요 사용 예 요청 본문 읽기, JSON 처리, 필터/인터셉터 처리 등
주요 주의 사항 InputStream은 한 번만 읽을 수 있음, 인코딩 주의

✅ 마무리

StreamUtils.copyToString()은 간단하지만 스프링 개발에서 꽤 자주 쓰이는 핵심 유틸 메서드입니다.
특히 요청 본문을 직접 다루거나, 인터셉터에서 로그를 찍을 때 매우 유용하게 사용할 수 있으니 기억해두면 실무에서 큰 도움이 될 것 입니다.

 

 

 

참조:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/StreamUtils.html 

 

 

 

response.getWriter().write() vs return "ok"

Spring MVC를 처음 접하거나, 직접 서블릿 API를 다뤄본 개발자라면 한 번쯤은 다음 두 코드의 차이에 대해 궁금했던 적이 있을 것입니다:

// 방식 1: HttpServletResponse 사용
response.getWriter().write("ok");

// 방식 2: @ResponseBody와 return
@ResponseBody
public String hello() {
    return "ok";
}

이 두 방식은 모두 클라이언트에게 HTTP 응답을 반환하지만, 사용 방식과 처리 흐름에 큰 차이가 있습니다.

이번 글에서는 이 차이를 정리하고, 어떤 상황에서 어떤 방식을 사용하는 것이 좋은지 알아보겠습니다.


1. response.getWriter().write("ok"): 서블릿 API 직접 사용

이 방식은 HttpServletResponse 객체를 통해 직접 응답 본문에 값을 써넣는 저수준 방식입니다.

@Controller
public class ResponseController {

    @RequestMapping("/manual-response")
    public void manualResponse(HttpServletResponse response) throws IOException {
        response.getWriter().write("ok");
    }
}

특징

  • HttpServletResponse의 getWriter()를 통해 PrintWriter를 얻고, 직접 문자열을 씁니다.
  • Spring의 뷰 리졸버(ViewResolver)나 HttpMessageConverter를 거치지 않습니다.
  • 스프링의 생태계를 우회하고 직접 응답을 제어해야 할 때 사용합니다.
  • 예: 파일 다운로드, 이미지 응답, 바이너리 응답 등.

2. return "ok" + @ResponseBody: 스프링 방식의 간결한 처리

반면, 스프링 MVC에서는 메소드 반환값을 HTTP 응답으로 보내고 싶을 때 @RestController 또는 @ResponseBody를 활용할 수 있습니다.

@RestController
public class RestApiController {

    @GetMapping("/spring-response")
    public String springResponse() {
        return "ok";
    }
}

 

※ 또는 @Controller에 @ResponseBody를 붙이면 동일한 효과입니다.

@Controller
public class RestApiController {

    @ResponseBody
    @GetMapping("/spring-response")
    public String springResponse() {
        return "ok";
    }
}

특징

  • @ResponseBody가 붙으면 반환값은 뷰 이름으로 인식되지 않고, HTTP 응답 본문으로 전송됩니다.
  • 내부적으로 HttpMessageConverter가 동작하여 문자열, JSON 등으로 자동 변환됩니다.
  • RESTful API나 간단한 문자열 응답을 만들 때 매우 유용합니다.

3. 어떤 방식을 써야 할까?

기준 response.getWriter().write() @ResponseBody + return
처리 수준 저수준 (서블릿 직접 제어) 고수준 (스프링에서 처리)
코드 간결성 비교적 복잡 매우 간결
뷰/메시지 변환기 사용 여부 사용하지 않음 HttpMessageConverter 사용
사용 사례 파일 다운로드, 이미지 응답 등 문자열, JSON 응답 등 일반적인 API 응답
추천 여부 특별한 제어가 필요한 경우만 추천 대부분의 경우 적극 추천

4. 정리

  • 직접 제어가 필요한 특별한 상황(파일 처리, 비동기 스트림 등)이 아니라면, 스프링이 제공하는 @ResponseBody 방식이 훨씬 간편하고 유지보수에 유리합니다.
  • REST API 개발 시에는 @RestController를 사용하면 @ResponseBody가 자동 적용되므로 더욱 편리합니다.
  • 스프링은 단순히 편리함을 넘어, 개발자의 생산성과 유지보수성을 높여주는 강력한 추상화 도구임을 기억하면 좋습니다.

 

참고 링크

+ Recent posts