이번 편에서는 스프링 MVC에서 클라이언트 요청 URL과 컨트롤러 메서드를 연결하는 방법을 다룬다.
단순히 @RequestMapping 하나만 아는 것과, 다양한 속성과 어노테이션의 의미를 깊게 이해하는 것은 큰 차이가 있다. 실무에서는 이 매핑 설정이 잘못되면 API 호출이 아예 불가능해지거나, 잘못된 응답을 반환하는 경우가 생기므로 반드시 확실히 알아둬야 한다.
1. @RequestMapping 기본 사용
@RestController
public class MappingController {
private final Logger log = LoggerFactory.getLogger(getClass());
@RequestMapping("/hello-basic")
public String helloBasic() {
log.info("helloBasic");
return "ok";
}
}
핵심 개념
- @RestController
- @Controller + @ResponseBody 조합
- 반환 값을 뷰로 해석하지 않고 HTTP 응답 바디에 그대로 작성
- @RequestMapping("/hello-basic")
- /hello-basic URL 호출 시 해당 메서드 실행
- 배열 형태({"/path1", "/path2"})로 다중 매핑 가능
스프링 부트 3.0 이전과 이후 차이
- 3.0 이전: /hello-basic과 /hello-basic/를 동일하게 처리
- 3.0 이후: 두 경로를 서로 다른 요청으로 구분 (마지막 / 유지)
2. HTTP 메서드 지정
@RequestMapping은 기본적으로 모든 HTTP 메서드(GET, POST, PUT…)를 허용한다.
하지만 REST API에서는 보통 HTTP 메서드를 명확히 제한한다.
@RequestMapping(value = "/mapping-get-v1", method = RequestMethod.GET)
public String mappingGetV1() {
log.info("mappingGetV1");
return "ok";
}
- method 속성으로 허용할 HTTP 메서드 지정
- 지정하지 않으면 모든 메서드 허용
- 잘못된 메서드로 요청 시 405 Method Not Allowed 반환
3. 축약 어노테이션
매번 method = RequestMethod.GET을 적는 건 번거롭다.
스프링은 이를 위해 축약형 어노테이션을 제공한다.
어노테이션 | 설명 |
@GetMapping | GET 요청 전용 |
@PostMapping | POST 요청 전용 |
@PutMapping | PUT 요청 전용 |
@DeleteMapping | DELETE 요청 전용 |
@PatchMapping | PATCH 요청 전용 |
@GetMapping("/mapping-get-v2")
public String mappingGetV2() {
log.info("mapping-get-v2");
return "ok";
}
4. @PathVariable (경로 변수)
RESTful API에서 리소스 식별자는 URL 경로에 포함시키는 것이 일반적이다.
@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable("userId") String data) {
log.info("mappingPath userId={}", data);
return "ok";
}
- {userId} 부분이 경로 변수
- @PathVariable("userId")로 바인딩
- 변수명이 같다면 생략 가능: @PathVariable String userId
다중 경로 변수
@GetMapping("/mapping/users/{userId}/orders/{orderId}")
public String mappingPath(@PathVariable String userId, @PathVariable Long orderId) {
log.info("mappingPath userId={}, orderId={}", userId, orderId);
return "ok";
}
5. params 속성 - 요청 파라미터 조건 매핑
@GetMapping(value = "/mapping-param", params = "mode=debug")
public String mappingParam() {
log.info("mappingParam");
return "ok";
}
- params="mode" → 해당 파라미터가 존재해야 함
- params="!mode" → 해당 파라미터가 없어야 함
- params="mode=debug" → 값까지 일치해야 함
- 여러 조건: params = {"mode=debug", "data=good"}
6. headers 속성 - HTTP 헤더 조건 매핑
@GetMapping(value = "/mapping-header", headers = "mode=debug")
public String mappingHeader() {
log.info("mappingHeader");
return "ok";
}
- headers="mode=debug" → 요청 헤더 값이 일치해야 함
- !로 부정 가능: headers="!mode"
7. consumes 속성 - Content-Type 조건 매핑
@PostMapping(value = "/mapping-consume", consumes = "application/json")
public String mappingConsumes() {
log.info("mappingConsumes");
return "ok";
}
- 요청 Content-Type과 매핑
- 일치하지 않으면 415 Unsupported Media Type 발생
8. produces 속성 - Accept 조건 매핑
@PostMapping(value = "/mapping-produce", produces = "text/html")
public String mappingProduces() {
log.info("mappingProduces");
return "ok";
}
- 요청 Accept 헤더와 매핑
- 일치하지 않으면 406 Not Acceptable 발생
9. 클래스 레벨 매핑
@RestController
@RequestMapping("/mapping/users")
public class MappingClassController {
@GetMapping
public String users() { return "get users"; }
@PostMapping
public String addUser() { return "post user"; }
@GetMapping("/{userId}")
public String findUser(@PathVariable String userId) {
return "get userId=" + userId;
}
@PatchMapping("/{userId}")
public String updateUser(@PathVariable String userId) {
return "update userId=" + userId;
}
@DeleteMapping("/{userId}")
public String deleteUser(@PathVariable String userId) {
return "delete userId=" + userId;
}
}
- 클래스 레벨 @RequestMapping은 공통 URL prefix 지정
- 메서드 레벨 매핑과 조합됨 (/mapping/users/{id})
회고
이번 장을 정리하면서 @RequestMapping 하나로도 수많은 매핑 조건을 만들 수 있다는 걸 다시 느꼈다.
과거에는 단순히 URL만 맞추면 된다고 생각했는데, 실제로는 HTTP 메서드, 파라미터, 헤더, 미디어 타입까지 세밀하게 조건을 걸 수 있어 API를 더 안전하고 명확하게 설계할 수 있다는 점이 인상 깊었다.
앞으로 REST API를 설계할 때 이런 매핑 조건을 적극 활용해서, 잘못된 요청이 아예 컨트롤러에 들어오지 않게 만드는 구조를 의식적으로 적용해야겠다.
'Spring' 카테고리의 다른 글
[Spring] MVC 14편 - HTTP 메시지 바디와 JSON 처리 (2) | 2025.08.14 |
---|---|
[Spring] MVC 13편 - HTTP 요청 데이터 처리와 바인딩 (2) | 2025.08.14 |
[Spring] MVC 11편 - 스프링 MVC 구조 완전 이해 (3) | 2025.08.13 |
[Spring] MVC 10편 - 프론트 컨트롤러 v1~v5 정리 (1) | 2025.08.12 |
[Spring] MVC 9편 - 프론트 컨트롤러 v5 (0) | 2025.08.12 |