스프링 프레임웍의 컨트롤러에서는 http 요청이 들어오면 특정 메서드를 실행하고 반환하는 방식으로 작동합니다.
이 포스팅에서는 컨트롤러에서 요청을 처리할 메서드에 매핑하는 기준들에 대해 작성해볼까 합니다!
Http Method (요청 방식)
http 요청 메세지에는 method라는 것이 존재합니다.
대표적으로 GET, POST, PUT, PATCH, DELETE 5가지가 존재하며, 특별한 역할을 하는 기타 메서드들도 존재합니다.
스프링 컨트롤러에선 이 http 메서드로 요청 매핑을 나눌 수 있습니다.
@PostMapping("/http-method/users")
public ResponseEntity createUser(@RequestBody User user) {
Long id = 1L;
return ResponseEntity.created(URI.create("/users/" + id))
.build();
}
@GetMapping("/http-method/users")
public ResponseEntity<List<User>> showUser() {
List<User> users = Arrays.asList(
new User("이름", "email"),
new User("이름", "email")
);
return ResponseEntity.ok().body(users);
}
컨트롤러의 요청을 처리하는 두 메서드에 매핑된 URI가 같지만, 서로 담당하는 요청방식이 다르기 때문에 POST요청으로 들어오면 @PostMapping 어노테이션이 붙은 createUser메서드, GET요청으로 들어오면 @GetMapping 어노테이션이 붙은 showUser메서드에 매핑됩니다.
미디어 타입
http 요청과 응답 메세지의 데이터 타입을 알려주기 위한 미디어 타입으로도 매핑을 구분할 수 있습니다.
@PostMapping(path = "/users", consumes = "application/json")
public ResponseEntity createUser(@RequestBody User user) {
Long id = 1L;
return ResponseEntity.created(URI.create("/users/" + id)).build();
}
@GetMapping(path = "/users", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<User>> showUser() {
List<User> users = Arrays.asList(
new User("이름", "email"),
new User("이름", "email")
);
return ResponseEntity.ok().body(users);
}
@GetMapping(path = "/users", produces = MediaType.TEXT_HTML_VALUE)
public String userPage() {
return "user page";
}
http method 매핑 어노테이션에 미디어 타입을 정의하면 들어오는 데이터와 나가는 데이터를 정의할 수 있습니다.
consumes는 들어오는 데이터 타입을 정의합니다. 위 코드의 createUser 메서드는 consumes에 application/json으로 들어오는 메시지의 타입을 정의하고 있기 때문에 요청 메시지에서 application/json으로 Content-Type을 정의해야만 매핑됩니다.
produces는 나가는 데이터 타입을 정의합니다. Http 요청을 보낼 때 Accept헤더에 응답받을 미디어 타입을 기재할 수 있는데요, Accept헤더에 기재된 타입에 맞게 메서드를 매핑합니다. 위 코드로 작성된 컨틀롤러에서 GET 방식에 '/users' 라는 URI에 Accept 헤더에 application/json 이라고 기재한 요청이 들어왔다면 showUser메서드로 매핑되고, Accept 헤더에 text/html 이라고 기재했다면 userPage 메서드가 매핑되게 됩니다.
특정 파라미터, 특정 헤더 따로 처리
같은 요청방식에 같은 URI이어도 특정 파라미터나 헤더가 들어왔을 때 다른 처리 메서드로 연결하게 할 수 있습니다.
@GetMapping("/message")
public ResponseEntity<String> message() {
return ResponseEntity.ok().body("message");
}
@GetMapping(path = "/message", params = "name")
public ResponseEntity<String> messageForParam(@RequestParam("name") String name) {
return ResponseEntity.ok().body(name);
}
@GetMapping(path = "/message", headers = "HEADER")
public ResponseEntity<String> messageForHeader(HttpServletRequest request) {
final String header = request.getHeader("HEADER");
return ResponseEntity.ok().body(header);
}
위 세 메서드는 매핑되는 요청 방식과 URI가 모두 같습니다. 일반적으로는 아무런 요소도 기재되지 않은 message 메서드에 매핑됩니다.
params
URL 패턴
스프링에서는 두 가지 URL패턴을 사용할 수 있습니다.
PathPattern - URL 경로와 일치하는 사전 구문 분석된 패턴으로, PathContainer로도 사전 구문 분석됩니다. 웹용으로 설계된 이 솔루션은 인코딩 및 경로 매개 변수를 효과적으로 처리하고 효율적으로 일치시킵니다.
AntPathMatcher - 문자열 패턴을 문자열 경로에 일치시킵니다. 이 솔루션은 클래스 경로, 파일 시스템 및 기타 위치에서 리소스를 선택하는 데 Spring 구성에서도 사용되는 원래 솔루션입니다. 이것은 덜 효율적이며 String 경로 입력은 인코딩과 URL의 다른 문제를 효과적으로 처리하기 위한 과제이다.
- 스프링 공식문서
다음과 같이 사용할 수 있습니다!
- "/resources/ima?e.png" - 경로 세그먼트에서 한 문자를 일치시킵니다.
- "/match/*.png" - 경로 세그먼트에서 0개 이상의 문자를 일치시킵니다.
- "/model/**" - 여러 경로 세그먼트와 일치
- "/syslog/{project}/syslog" - 경로 세그먼트를 일치시키고 변수로 캡처합니다.
- "/filename/{project:[a-z]+}/filename" - 정규식과 변수 일치 및 캡처
코드로 살펴볼게요!
@GetMapping("/users/{id}")
public ResponseEntity<User> pathVariable(@PathVariable Long id) {
User user = new User(id, "이름", "email");
return ResponseEntity.ok().body(user);
}
@GetMapping("/patterns/?") //
public ResponseEntity<String> pattern() {
return ResponseEntity.ok().body("pattern");
}
@GetMapping("/patterns/*")
public ResponseEntity<String> patternStar() {
return ResponseEntity.ok().body("pattern-star");
}
@GetMapping("/patterns/**")
public ResponseEntity<String> patternStars() {
return ResponseEntity.ok().body("pattern-multi");
}
pathVariable 메서드는 URL경로에 파라미터를 포함시켜서 매핑받습니다. 문법은 {파라미터명}을 path구분자 사이에 포함시키고 해당 파라미터명에 맞는 메서드 파라미터에 @PathVariable 어노테이션을 붙여서 값을 메서드의 파라미터로 받을 수 있습니다.
pattern 메서드는 URL 패턴에 '?'기호가 사용되었는데요, ?기호는 URL 패턴에서 한 글자에 대해서 매핑됩니다.
위의 경우 "/pattern/a"나 "/pattern/b"같이 ? 자리에 어떤 한 글자가 오면 이 메서드로 오게 됩니다.
patternStar와 patternStars 메서드는 * 기호를 사용하는데요,
둘의 차이점은 *가 한 개 붙어있을 때는 해당 뎁스에 대해서만 매핑되고, 두개 붙어있을 때는 그 이하의 뎁스에 모두 매핑됩니다.
- "/patterns/a/b/c/d" - "/patterns/**"
- "/patterns/abcd" - "/patterns/*"
이런 식으로 차별을 둘 수 있겠네요.
지금까지 스프링 컨트롤러의 핸들러 메서드 매핑 방식 4가지에 대해서 정리해봤습니다!
'Spring' 카테고리의 다른 글
로깅 성능에 대한 고민 (0) | 2022.10.24 |
---|---|
로그 잘 남기면 디버깅이 수월해짐 (0) | 2022.10.23 |
요청로깅 AOP로 해야겠다 (0) | 2022.10.23 |
요청 정보는 서비스 로직 시작 전에 찍어야지..? (6) | 2022.09.26 |
아 인터셉터에서 Request Body 로그 찍고싶다.. (0) | 2022.08.17 |