고양의 성장일기

[Spring] @PathVariable과 @RequestParam 응용해보기 본문

⚙️ Back-End/Spring Framework

[Spring] @PathVariable과 @RequestParam 응용해보기

고 양 2025. 7. 21. 20:20
반응형
@PathVariable과 @RequestParam 응용해 보기

앞서 스프링 컨트롤러에서 URL에 매핑된 변수를 어떻게 받아내는지 여기에서 간단하게 정리했습니다.

이번 글에서는 두 어노테이션에서 여러 개의 변수를 받는 법, 기본값 설정하는 법 등을 정리해 보겠습니다.

✅ 두 어노테이션의 차이?

이전 글을 읽을 시간이 없으신 분들을 위해 두 어노테이션의 차이를 간략하게 다시 짚어보겠습니다.

두 어노테이션 모두 GET 방식을 기반으로 URL에 포함된 요청 파라미터를 파싱하고 메서드 파라미터로 바인딩해줍니다.

 

  • @PathVariable: URI 경로에 포함된 값을 바인딩할 때 사용
  • @RequestParam: 쿼리 스트링, 즉 ?key=value 형식이나 폼 데이터에서 사용

 

✅ 어노테이션 속성 부여하기

URL 변수와 메서드 바인딩 변수의 매핑을 위한 변수명 속성, Null 방지 속성 등 여러 가지 속성을 어노테이션에 부여할 수 있습니다.

대체로 비슷하지만 약간의 차이가 있으며 차이점과 사용법 위주로 알아보았습니다.

@PathVariable

📌 value , name (String)

속성 명은 다르지만 동일한 역할을 합니다.

경로에 포함된 요청 파라미터의 키가 속성의 값에 해당되는 파라미터를 찾습니다.

만약 경로에 포함된 파라미터명과 메서드 내에서 사용할 변수 명이 동일하다면 해당 속성을 생략할 수 있습니다.

📌 required (boolean)

속성 값이 true라면 요청 파라미터에 반드시 해당 파라미터가 포함되어야 하며, 없으면 400 Bad Request 예외를 반환합니다.

하지만 @PathVariable을 사용하는 상황일 경우 파라미터가 URL에 반드시 포함되어야 하므로, 유명무실한 속성입니다.

 

아래는 예제코드입니다.

@GetMapping("/users/{id}")
public String getUser(@PathVariable(value = "id", required = true) String userId) {
    return "userDetail";
}

@RequestParam

📌 value, name(String)

@PathVariable 어노테이션의 value, name 속성과 동일한 역할을 합니다. 마찬가지로 생략할 수 있습니다.

📌 required(boolean)

@PathVariable 어노테이션의 required 속성과 동일한 역할을 합니다.

다만 필수적인 옵션을 요구할 때 @PathVariable과는 달리 유용하게 사용할 수 있습니다.

📌 defaultValue(String)

이 속성이 지정되면 required 속성은 false로 간주됩니다.

요청 파라미터가 빈 값이거나 존재하지 않을 때 메서드 내에서 사용할 기본값을 부여합니다.

 

이 속성은 @PathVariable에는 존재하지 않는데, @PathVariable은 URL 템플릿에 명시된 값을 필수로 바인딩해야 하기 때문입니다.

그렇기 때문에 defaultValue 속성 자체가 제공되지 않으며, 경로에 존재하지 않는 변수는 바인딩 자체가 불가능합니다.

 

예제코드 보겠습니다.

@GetMapping("/search")
public String search(
    @RequestParam(value = "keyword", required = false, defaultValue = "") String keyword,
    @RequestParam(name = "page", defaultValue = "1") int pageNumber
) {
    System.out.println("keyword: " + keyword);
    System.out.println("pageNumber: " + pageNumber);
    
    return "searchResult";
}

✅ 다수의 변수 바인딩

DTO나 HashMap 등을 이용하여 여러 개의 URL 변수를 바인딩할 수 있습니다.

어노테이션 별로 사용 가능한 방식에 약간의 차이가 존재합니다. 주의해서 사용해야 합니다.

@PathVariable

📌 개별 변수로 받기

메서드 파라미터를 여러 개 선언하는 방법으로 URL에 매핑된 여러 개의 파라미터를 바인딩할 수 있습니다.

이런 경우 직관적이지만 변수가 많아질수록 관리가 어렵겠죠..

@GetMapping("/users/{userId}/orders/{orderId}")
public String getOrder(
        @PathVariable("userId") String userId,
        @PathVariable("orderId") String orderId
) {
    return "orderDetail";
}

//요청 파라미터와 메서드 파라미터명이 동일하다면 생략 가능
@GetMapping("/users/{userId}/orders/{orderId}")
public String getOrder(
        @PathVariable String userId, 
        @PathVariable String orderId
) {
    return "orderDetail";
}

📌 Map<String, String>

URL에 지정된 파라미터 키를 그대로 Map에 저장하여 줍니다.

일반적인 Map에서 키를 이용해 값을 참조하듯이 사용하면 됩니다.

@GetMapping("/users/{userId}/orders/{orderId}")
public String getOrder(@PathVariable Map<String, String> pathVars) {
    String userId = pathVars.get("userId");
    String orderId = pathVars.get("orderId");
    
    return "orderDetail";
}

@RequestParam

📌 개별 변수로 받기

@PathVariable 어노테이션과 동일한 패턴입니다.

@GetMapping("/search")
public String search(
        @RequestParam("keyword") String keyword,
        @RequestParam("page") int page,
        @RequestParam("size") int size
) {
    return "searchResult";
}

//요청 파라미터와 메서드 파라미터명이 동일하다면 생략 가능
@GetMapping("/search")
public String search(
        String keyword, 
        int page, 
        int size
) {
    return "searchResult";
}

 

📌 Map<String, String>

@PathVariable 어노테이션에서 맵을 사용하는 방법과 비슷한 패턴입니다.

@GetMapping("/search")
public String search(@RequestParam Map<String, String> paramMap) {
    String keyword = paramMap.get("keyword");
    String page = paramMap.getOrDefault("page", "1");
    String size = paramMap.getOrDefault("size", "10");
    
    System.out.println("keyword: " + keyword);
    System.out.println("page: " + page);
    System.out.println("size: " + size);

    return "searchResult";
}

📌 DTO 사용하기

Map 대신 미리 작성된 DTO 등 엔터티 클래스를 이용해 변수를 바인딩하는 것도 가능합니다.

매우 직관적이고 명확하며 유지보수에도 편리한 방법입니다.

public class SearchRequest {
    private String keyword;
    private int page;
    private int size;
    
    public String getKeyword() {
        return this.keyword;
    }
    
    public void setKeyword(String keyword) {
        this.keyword = keyword;
    }
    
    //이하 getter, setter 생략
}

@GetMapping("/search")
public String search(SearchRequest request) {
    System.out.println("keyword: " + request.getKeyword());
    System.out.println("page: " + request.getPage());
    System.out.println("size: " + request.getSize());
    
    return "searchResult";
}

✅ 하나의 변수에 여러 개의 값 바인딩

@RequestParam의 경우 특성상, @PathVariable의 경우에 비해 포함될 수 있는 파라미터의 개수가 더 유동적이고 다양합니다.

혹시 게시글 태그 등 하나의 키에 여러 개의 값이 부여되어야 할 때도 있지 않을까요? 아래와 같이 두 가지 방법을 사용할 수 있습니다.

📌 MultiValueMap<String, String>

이 MultiValueMap은 하나의 키에 여러 값을 매핑할 수 있도록 설계된, 스프링 프레임워크에서 제공하는 인터페이스입니다.

아래와 같이 구성되어 있으며 키와 리스트로 이루어진 Map을 생성합니다.

public interface MultiValueMap<K, V> extends Map<K, List<V>> {
    void add(K key, V value);
    void addAll(K key, List<? extends V> values);
    void addAll(MultiValueMap<K, V> values);
    void set(K key, V value);
    void setAll(Map<K, V> values);
    Map<K, V> toSingleValueMap();
}
import org.springframework.util.MultiValueMap;

@GetMapping("/search") // /search?tag=java&tag=spring
public String search(@RequestParam MultiValueMap<String, String> paramMap) {
    List<String> tags = paramMap.get("tag"); // tag = ["java", "spring"]
    return "searchResult";
}

📌 List<String>

또는 단순하게 아래와 같이 리스트로 받을 수도 있습니다.

이 경우에도 하나의 파라미터에 여러 개의 값이 매핑되어 있어야 정상적으로 동작합니다.

@GetMapping("/search") // /search?tag=java&tag=spring
public String search(@RequestParam List<String> tag) {
    return "result";
}

✅ 조금 더 응용해보기

📌 Optional<?> 사용해보기

@RequestParam 어노테이션에서 제공하는 required와 defaultValue 속성은 Optional을 이용해 세련되게 표현할 수 있습니다.

value 변수에는 keyword 파라미터가 존재할 경우 keyword의 값을, 없을 경우 "기본값"이란 값이 할당됩니다. 

@GetMapping("/search")
public String search(@RequestParam Optional<String> keyword) {
    String value = keyword.orElse("기본값");
    System.out.println(value);
    return "searchResult";
}

@GetMapping("/search")
public String search(@RequestParam(defaultValue = "기본값") keyword) {
    System.out.println(value);
    return "searchResult";
}

마치며

Spring MVC에서 널리 사용되는 가장 기본적인 바인딩 도구인 @RequestParam과 @PathVariable에 대해 조금 자세히 알아봤습니다.

다수의 변수를 바인딩하는 방법은 이 글의 핵심 토픽이었지만, 복잡한 구조의 데이터나 다량의 데이터를 바인딩 할 때에는 POST/PUT 메서드를 기반으로 하는 @ModelAttribute나 @RequestBody의 사용도 고려할 수 있습니다.

 

다음 글에서는 이 두 어노테이션의 차이점과 활용 방법에 대해 자세히 알아보겠습니다.

 

감사합니다.

반응형