Asynchronous JavaScript And XML
웹 페이지를 새로 고침하지 않고도 서버와 비동기적으로 데이터를 주고받는 기술이다.
페이지 전체를 새로고침하지 않고도 필요한 데이터만 주고받아서 빠른 사용자 경험(UX)을 제공한다.
fetch, jQuery.ajax() 등)// JavaScript fetch 사용 예시
fetch('/hello', {
method: 'GET'
})
.then(response => response.json())
.then(data => {
console.log(data.message); // "안녕하세요"
});
@RestController
public class HelloController {
@GetMapping("/hello")
public Map<String, String> sayHello() {
Map<String, String> response = new HashMap<>();
response.put("message", "안녕하세요");
return response; // JSON 응답
}
}
REpresentational State Transfer
웹에서 자원을 정의하고 자원에 대한 행위를 HTTP 메소드로 표현하는 아키텍쳐 스타일
자원을 URI로 표현하고, 해당 자원에 대한 동작은 HTTP 메서드(GET, POST, PUT, DELETE 등)로 정의
| HTTP 메서드 | 설명 | 예시 |
|---|---|---|
GET | 자원 조회 | /users/1 → id가 1인 사용자 정보 가져오기 |
POST | 자원 생성 | /users + body → 새 사용자 등록 |
PUT | 자원 전체 수정 | /users/1 + body → id가 1인 사용자 정보 전체 수정 |
PATCH | 자원 일부 수정 | /users/1 + body → 사용자 일부 정보만 수정 |
DELETE | 자원 삭제 | /users/1 → id가 1인 사용자 삭제 |
REST 원칙을 잘 지켜서 설계한 웹 서비스나 API
| 동작 | URL | 메서드 |
|---|---|---|
| 회원 전체 조회 | /members | GET |
| 회원 등록 | /members | POST |
| 회원 상세 조회 | /members/1 | GET |
| 회원 정보 수정 | /members/1 | PUT |
| 회원 삭제 | /members/1 | DELETE |
| 항목 | @Controller | @RestController (Spring 4.0+) |
|---|---|---|
| 설명 | 기존 Spring MVC 방식 | API 응답 전용 컨트롤러 |
| 반환 대상 | View (JSP 등) | 데이터 (JSON, XML 등) |
| 사용 목적 | 사용자에게 웹 페이지 제공 | 프론트엔드 또는 외부 시스템과 데이터 통신 |
| 반환 타입 | ModelAndView 또는 String(뷰 이름) | 객체 → 자동으로 JSON/XML 변환 |
| 구성 요소 | 단독 사용 | @Controller + @ResponseBody 조합 |
| 자동 변환 | 없음 (ViewResolver를 통해 View 렌더링) | 있음 (@ResponseBody로 자동 JSON/XML 변환) |
| 사용 예 | 게시판, 로그인 화면 등 HTML UI 제공 | REST API 서버 구축, Ajax 응답 등 |
메소드에서 반환한 데이터를 HTTP 응답 바디에 그대로 담아 전송하도록 만드는 어노테이션
메서드 반환값을 View로 처리하지 말고, HTTP 응답 바디에 그대로 쓰라는 뜻
객체를 반환하면 JSON으로 자동 변환하여 응답한다. (Jackson 등 사용)
// @Controller + @ResponseBody 조합 사용 시
@Controller
public class MyController {
@GetMapping("/data")
@ResponseBody
public Map<String, String> getData() {
return Map.of("message", "hello");
}
}
// @RestController는 위와 동일한 역할을 자동으로 처리
// @RestController 사용 시
@RestController
public class ApiController {
@GetMapping("/data")
public Map<String, String> getData() {
return Map.of("message", "hello");
}
}
| 상황 | 사용 어노테이션 |
|---|---|
| HTML 뷰를 반환해야 할 때 | @Controller |
| JSON/XML 데이터를 반환해야 할 때 | @RestController |
| 구성 요소 | 설명 |
|---|---|
@RestController | REST API를 처리하는 컨트롤러. 모든 메서드는 데이터(JSON/XML)를 반환 |
@RequestMapping, @GetMapping, @PostMapping 등 | HTTP 메서드(GET, POST, PUT, DELETE 등)에 따른 요청 매핑 |
@PathVariable | URL 경로에 포함된 변수 값 추출 |
@RequestParam | 쿼리 파라미터 추출 |
@RequestBody | HTTP 요청 본문에서 JSON 데이터를 객체로 매핑 |
@ResponseEntity | 응답 상태 코드, 헤더, 바디를 명시적으로 제어 가능 |
오늘은 Spring에서 Ajax와 REST에 대해 공부했다.
최근 채용 공고에서 "REST 기반 설계 경험"이라는 조건을 보고 궁금했는데, 오늘 학습을 통해 개념을 이해할 수 있었다.
RESTful API는 일관성, 유지보수성, 확장성, 표준화된 통신 등 다양한 이점을 제공한다고 한다.
개념적으로는 이해했지만, 아직 직접 적용해보지 않아서 실무에서 언제 어떻게 사용하는지, 어떤 기준으로 사용해야 하는지는 명확하게 와닿지 않는다.
공부 중에 본 예제들은 대부분 @Controller와 @RestController를 서로 다른 클래스에 나누어 사용하는 방식이었다.
데이터를 반환할 때는 @RestController를 사용한다고는 하지만, 실제 프로젝트에서 컨트롤러를 그렇게 명확하게 나눌 수 있을지 의문이 들었다.
검색으로도 명확한 답을 찾기 어려워 챗GPT에게 질문했고, 아래는 그에 대한 답변이다.
▶ 동일한 컨트롤러에서 일부는 뷰를 반환하고, 일부는 JSON/XML 데이터를 반환하는 경우
@Controller를 기본으로 사용하면서, 데이터를 반환해야 하는 메서드에만 @ResponseBody를 붙이는 방식
@Controller
@RequestMapping("/user")
public class UserController {
// ✅ 뷰 반환
@GetMapping("/profile")
public String userProfile(Model model) {
model.addAttribute("name", "홍길동");
return "user/profile"; // JSP 등으로 렌더링
}
// ✅ JSON 반환 (일부 메서드만)
@GetMapping("/data")
@ResponseBody
public Map<String, Object> getUserData() {
return Map.of("id", 1, "name", "홍길동");
}
}
RedirectView나 ResponseEntity<String> 등으로 처리
// @RestController + RedirectView 로 뷰 이동
@RestController
@RequestMapping("/rest")
public class RestExampleController {
// JSON 응답
@GetMapping("/data")
public Map<String, String> getData() {
return Map.of("message", "Hello, world!");
}
// 브라우저에서 페이지 이동 시도
@GetMapping("/go-to-page")
public RedirectView redirectToPage() {
return new RedirectView("/page/main");
}
}
// @RestController + ResponseEntity<String> 로 HTML 직접 반환
@RestController
@RequestMapping("/rest")
public class RestHtmlController {
@GetMapping("/html")
public ResponseEntity<String> getHtmlPage() {
String html = """
<html>
<body>
<h1>Hello from REST!</h1>
</body>
</html>
""";
return ResponseEntity.ok()
.header("Content-Type", "text/html; charset=UTF-8")
.body(html);
}
}
뷰 중심이 많다면 @Controller + @ResponseBody 구조가 일반적