티스토리 뷰

지원중인 프로젝트들을 보면, 

회사의 중대하고 막대한 프로젝트들은 당연히 BE/FE 나누어 개발을 하지만

아주 소소한, 조마난 플젝들은 굳이 BE/FE를 나누지 않고 여전히 JSP, Timeleaf등을 많이 사용하고 있다

 

그럼 백 코드를 @RestController를 써야할지, @Controller를 써야할지 여쭤보시는데

대충 어디에 뭘 어떻게 쓴다만 알지 내부 구조를 자세하기 알진 못해서 알아봄

 

@Controller vs @RestController, 상황별 선택 가이드

1. 두 응답의 목적은?

- @Controller (View 기반) : 전통적인 Spring MVC의 컨트롤러. 주로 View(화면)을 반환하기 위해 사용한다. 메서드가 String을 반환하면 View Resolver가 해당 이름의 뷰 파일(JSP, HTML 등)을 찾아 렌더링한다.

- @RestController (Data 기반): @Controller에 @ResponseBody가 결합된 형태. View를 찾지 않고, 반환하는 객체(DTO, Map 등)을 JSON이나 XML같은 데이터 형식으로 직접 응답 본문에 작성한다.

 

2. FE 기술별 최적의 조합

  • Case A : JSP나 Thymeleaf를 사용하는 경우 (Server-Side Rendering)
    이 방식은 서버에서 이미 HTML을 다 만들어서 보내주는 방식임.
    • 권장 선택 : @Controller
    • 이유 : 컨트롤러에서 데이터를 Model 객체에 담아 뷰 템플릿으로 전달해야 하기 때문임
    • 주의사항 : 만약 JSP화면 안에서 특정 부분만 비동기(Ajax)로 데이터를 가져오고 싶다면, 해당 메서드에만 @ResponseBody를 붙이거나 별도의 @RestController를 만들어야 함
@Controller
public class ViewController {
    @GetMapping("/home")
    public String homePage() {
        return "home"; // home.jsp 파일을 찾아가라는 뜻!
    }
}
  • Case B : React, Vue, Angular를 사용하는 경우 (Client-Side Rendering)
    서버는 데이터만 던져주고, 화면은 브라우저(프론트엔드)가 그리는 방식
    • 권장 선택 : @RestController
    • 이유 : 현대적인 웹 아키텍처에서는 서버와 클라이언트를 완전히 분리함. 서버는 순수하게 비즈니스 로직과 데이터(JSON) 제공에만 집중하는 REST API 서버 역할을 수행해야 함
@RestController
@RequestMapping("/api/users")
public class UserApiController {
    @GetMapping("/{id}")
    public UserDto getUserInfo(@PathVariable String id) {
        return userService.findById(id); // { "name": "Hyerin", "role": "Dev" } 같은 데이터만 감!
    }
}

 

3. 유연성을 고려해야 함

최근 트렌드는 화면 제어와 데이터 제공을 철저히 분리하는 것임.

만약 프로젝트 초기라 JSP를 쓰고 있더라도, 나중에 모바일 앱이나 React로 확장할 계획이 있다면 처음부터 API 전용 컨트롤러(@RestController)와 화면 전용 컨트롤러(@Controller)를 패키지 단계부터 분리해 두는 것이 유지보수에 훨씬 유리함.

또한, @RestController를 사용하면 공통 응답 객체(Common Response)를 만들어 에러 코드나 메시지 형식을 표준화하기가 매우 수월해짐

 

@Controller 구조도

[ Client ] ──(1) Request──▶ [ Dispatcher Servlet ]
                                   │
      ┌────────────────────────────┴────────────────────────────┐
      │ (2) Handler Mapping 조회                                 │ (3) Controller 결정
      ▼                                                         ▼
[ Handler Mapping ]                                     [ Handler Adapter ]
                                                                │
      ┌─────────────────────────────────────────────────────────┴────────────────┐
      │ (4) 비즈니스 로직 실행                                                    │ (5) View Name 반환
      ▼                                                                          ▼
[ @Controller ] ──▶ [ Service ] ──▶ [ DB ]                      [ Dispatcher Servlet ]
                                                                         │
      ┌──────────────────────────────────────────────────────────────────┴───────┐
      │ (6) 화면 탐색 요청                                                        │ (7) 실제 View 파일 반환
      ▼                                                                          ▼
[ View Resolver ]                                                      [ View (JSP/HTML) ]
                                                                         │
[ Client ] ◀──(8) Response (HTML 완성본) ──────────────────────────────────┘

 

@RestController 구조도

[ Client ] ──(1) Request──▶ [ Dispatcher Servlet ]
                                   │
      ┌────────────────────────────┴────────────────────────────┐
      │ (2) Handler Mapping 조회                                 │ (3) Controller 결정
      ▼                                                         ▼
[ Handler Mapping ]                                     [ Handler Adapter ]
                                                                │
      ┌─────────────────────────────────────────────────────────┴────────────────┐
      │ (4) 비즈니스 로직 실행                                                    │ (5) 객체(DTO) 반환
      ▼                                                                          ▼
[ @RestController ] ──▶ [ Service ] ──▶ [ DB ]                  [ Dispatcher Servlet ]
                                                                         │
      ┌──────────────────────────────────────────────────────────────────┴───────┐
      │ 🌟 핵심: ViewResolver 대신 가동                                           │ (7) 변환 데이터 수신
      ▼                                                                          ▼
[ HttpMessageConverter ] ──(6) JSON으로 직렬화 (Serialization) ─────────────▶ [ Dispatcher Servlet ]
                                                                         │
[ Client ] ◀──(8) Response (JSON Data) ───────────────────────────────────┘

 

 

JSP와 @RestController의 협업: 비동기 데이터 업데이트

JQuery의 Ajax 사용

이 방식은 화면은 @Controller가 열어주고, 데이터는 @RestController가 배달한다는 분업 특징이 있음

 

1. 백엔드 구성

먼저 화면을 보여주는 컨트롤러와 데이터를 처리하는 API 컨트롤러를 나눔

// 화면담당 (ViewController.java)

@Controller
public class ViewController {
    @GetMapping("/user-page")
    public String userPage() {
        return "userView"; // userView.jsp를 호출하여 전체 화면을 그림
    }
}
// 데이터 담당 (UserApiController.java)

@RestController
@RequestMapping("/api/v1")
public class UserApiController {
    @GetMapping("/users/{id}")
    public UserDto getUserInfo(@PathVariable String id) {
        // 비즈니스 로직 실행 후 객체 반환 (자동으로 JSON 변환됨)
        return new UserDto(id, "Hyerin", "Software Developer");
    }
}

 

2. 프론트엔드 구성 (userView.jsp)

JSP 안에서 버튼을 클릭했을 때, 페이지 새로고침 없이 서버에서 데이터만 쏙 가져오는 Ajax 코드

<html>
<head>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
    <h2>사용자 정보 조회</h2>
    <input type="text" id="userId" placeholder="아이디 입력">
    <button id="fetchBtn">정보 가져오기</button>

    <div id="resultArea" style="margin-top: 20px; border: 1px solid #ccc;">
        <p>이름: <span id="userName">-</span></p>
        <p>직무: <span id="userRole">-</span></p>
    </div>

    <script>
        $('#fetchBtn').click(function() {
            const id = $('#userId').val();

            // @RestController로 데이터 요청
            $.ajax({
                url: '/api/v1/users/' + id,
                type: 'GET',
                success: function(data) {
                    // 데이터만 받아서 특정 부분만 업데이트!
                    $('#userName').text(data.name);
                    $('#userRole').text(data.role);
                },
                error: function() {
                    alert('사용자를 찾을 수 없습니다.');
                }
            });
        });
    </script>
</body>
</html>

 

728x90
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/03   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함
250x250