요즘 주식 많이 하시죠? 개인 플젝을 하고 싶다는 생각으로 "어떤 주제로 프로젝트를 해볼까.."하는 생각 중에 주식을 주제로 프로젝트를 하고 있습니다. (👉궁금하시다면 여기로)(https://github.com/jiyoungzero/stock-dividend-project)
덕분에 스프링으로 오랜만에 개발하는 중인데, 그냥 지나갔던 어노테이션의 의미를 깊게 들어다보게 되었습니다,
그 중 스프링 공부 초반에 제가 헷갈려했던@RequestParam
,@PathVariable
에 대해서 알아보겠습니다.
알고보면 굉장히 쓰임이 다른데 처음에 헷갈린다고 생각하는 이유는 둘 다 URL에서 값을 가져온다는 점입니다. 즉 HTTP 요청에서 데이터를 추출하고 사용하고자 할 때 쓰는 어노테이션입니다.
또한 Springboot 공식문서에서는 매개변수 바인딩을 위한 어노테이션이라고 소개합니다. 둘 다 클라이언트가 요청한 데이터를 컨트롤러에서 쓰는 메서드 매개변수와 바인딩하는데 사용한다는 것입니다.
이렇게 보면 둘 다 비슷한 쓰임새 같지만 하나하나 알아보면 많은 곳에서 차이점을 가집니다.
Springboot 공식문서
@RequestParam
: https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-methods/requestparam.html
제가 개발했던 프로젝트 컨트롤러 메서드를 예시로 들어보겠습니다.
@GetMapping("autocomplete")
public ResponseEntity<?> autocompleteCompany(@RequestParam String keyword) {
var result = this.companyService.getCompanyNamesByKeyword(keyword);
return ResponseEntity.ok(result);
}
어느 서비스에나 찾아볼 수 있는 자동완성 컨트롤러입니다. 클라이언트의 검색어를 받아 해당 검색어를 가진 회사를 return해주는 메서드입니다. 즉 /autocomplete?keyword=전자
와 같은 요청이 들어오면 해당 쿼리 파라미터를 받아 메서드 내에서 데이터를 처리하는 것입니다.
기본적으로 해당 어노테이션을 쓰면 매개변수가 필수가 됩니다. 만약 선택사항으로 쓰고 싶다면 required = false
를 명시하면 됩니다. (이 때 java.util.Optional
를 이용하면 null값 처리를 안전하게 처리할 수 있고, orElse()
, orElseThrow()
같은 처리를 쉽게 할 수 있겠죠? 실제로 공식문서에서도 추천하는 방식입니다.)
위의 예시보다 더 간단한 것들은
@GetMapping("/search")
public String search(@RequestParam String query) {
return "Search results for: " + query;
}
등이 될 수 있습니다. 각각의 상황에 맞춰서 url파라미터 값을 받아오고 데이터를 처리할 수 있도록 하면 됩니다.
Springboot 공식문서
@PathVariable
: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/PathVariable.html
PathVariable은 RequestParam과 달리 PostMapping에서도 사용가능한 어노테이션입니다.
왜냐하면 RequestParam은 쿼리 파라미터에서만 값을 가져올 수 있지만, PathVariable은 url경로에서 값을 가져올 수 있습니다. 당연히 url경로의 값을 가져오다보니 required=false
와 같은 선택사항 옵션은 주어지지 않는다는 차이점도 존재합니다.
그래서 주로 ReqeustParam은 검색, 필터링과 같은 옵션을 전달하는 용도이고, PathVariable은 url에 기재된 리소스를 식별하거나 요청할 때도 사용합니다, 즉 GetMapping뿐만 아니라 PostMapping에서도 사용가능한 어노테이션인거죠!
아래 GetMapping 예시를 보겠습니다. url에 기재되는 companyName을 String타입으로 받고 있습니다.
@GetMapping("/dividend/{companyName}")
public ResponseEntity<?> searchFinance(@PathVariable String companyName) {
var result = this.financeService.getDividendByCompanyName(companyName);
return ResponseEntity.ok(result);
}
간단한 PostMapping 예시는 아래와 같을 수 있습니다. /users/{userId}/posts
경로로 POST 요청을 보냅니다. 여기서 {userId}는 특정 사용자의 ID를 의미합니다.
@RestController
@RequestMapping("/users")
public class UserController {
private final PostService postService;
public UserController(PostService postService) {
this.postService = postService;
}
@PostMapping("/{userId}/posts")
public ResponseEntity<Post> createPost(@PathVariable String userId, @RequestBody Post newPost) {
newPost.setUserId(userId); // 포스트에 사용자 ID 설정
Post createdPost = postService.save(newPost);
return ResponseEntity.status(HttpStatus.CREATED).body(createdPost);
}
}
그래서 위의 예시로도 보이시겠지만 . @PathVariable과 @RequestBody의 조합은 클라이언트가 특정 사용자와 관련된 데이터를 처리할 때 유용합니다.
해당 사진을 보면 url경로인 곳에는 @PathValuable이 붙었고 ?
뒤에 오는 쿼리파라미터에는 @RequestParam이 처리합니다.
이제는 헷갈리지 않고 잘 사용할 수 있을 것 같습니다 :)