티스토리 뷰
지원중인 프로젝트들을 보면,
회사의 중대하고 막대한 프로젝트들은 당연히 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>
'Programming > BackEnd' 카테고리의 다른 글
| [BE] Java 8에서 21로 (0) | 2026.02.09 |
|---|---|
| [BE] 스프링 IoC와 DI | 스프링 생명주기 | @Autowired와 getBean() (1) | 2026.01.11 |
| [BE] 주니어 백엔드 개발자가 반드시 알아야 할 실무 지식 Ch03 (0) | 2025.12.12 |
- Total
- Today
- Yesterday
- 이펙티브자바
- 조합
- springboot
- 그래프탐색
- 백준
- docker-compose
- 알고리즘
- IMAGE
- 운영체제
- cicd
- Retrofit2
- DevOps
- 토큰기반인증
- BFS
- 아이템60
- OS
- 아이템61
- dfs
- BOJ
- 아이템59
- dp
- Container
- 완전탐색
- Java
- docker
- EffectiveJava
- subset
- bruteforce
- 완탐
- 순열
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |