@PathVariable은 요청 URI 매핑에서 템플릿 변수를 처리하고 이를 메서드 매개변수로 설정하는데 사용된다.
@PathVariable는 URI의 변하는 부분을 이용하여 엔티티의 주요 키 값을 메서드의 입력값으로 받을 수 있게 해준다.
@GetMapping("/api/employees/{id}")
@ResponseBody
public String getEmployeesById(@PathVariable String id) {
return "ID: " + id;
}
이 예제에서는 @PathVariable을 사용하여 {id}에서 값을 추출하여 매개변수에 주입한다.
다음 결과는 /api/employees/111 로 요청을 하였을 때 위의 예제에서 return되는 값을 출력한 결과이다.
http://localhost:8080/api/employees/111
----
ID: 111
api/employees/111 중에서 111은 {id}를 통하여 값을 받아 매개변수인 String id에 주입하여 id변수를 출력한 결과는 ID: 111이다.
이전 예제에서는 매개변수와 @PathVariable dml {id} 가 동일하여 템플린 경로 변수의 이름 정의를 건너뛰었다. 하지만 경로 변수 이름이 과 매개변수 이름이 다른경우 @PathVariable에 속성으로 이름을 지정할 수 있다.
@GetMapping("/api/employeeswithvariable/{id}")
@ResponseBody
public String getEmployeesByIdWithVariableName(@PathVariable("id") String employeeId) {
return "ID: " + employeeId;
}
좀더 명확하게 하기 위해 경로 변수 이름을 PathVariable(“id”) 대신 @PathVariable(value=”id”)로도 정의할 수 있다.
사용 사례에 따라서 컨트롤러 메서드에 대한 요청 URI에 둘 이상의 경로 변수가 들어있을 수 있다. 이 예제에는 URI에 여러개의 템플릿 변수가 있는 예제이다.
@GetMapping("/api/employees/{id}/{name}")
@ResponseBody
public String getEmployeesByIdAndName(@PathVariable String id, @PathVariable String name) {
return "ID: " + id + ", name: " + name;
}
http://localhost:8080/api/employees/1/bar
----
ID: 1, name: bar
Map형식인 MapM<String,String> 형태의 매개변수를 사용하여 둘 이상의 @PathVariable을 사용할 수 있다.
@GetMapping("/api/employeeswithmapvariable/{id}/{name}")
@ResponseBody
public String getEmployeesByIdAndNameWithMapVariable(@PathVariable Map<String, String> pathVarsMap) {
String id = pathVarsMap.get("id");
String name = pathVarsMap.get("name");
if (id != null && name != null) {
return "ID: " + id + ", name: " + name;
} else {
return "Missing Parameters";
}
}
http://localhost:8080/api/employees/1/bar
----
ID: 1, name: bar
http://localhost:8080/api/employees/1/bar 로 입력한 경우 1은 {id} 파라미터가 담당하고 bar는 {name}변수가 담당하였다. 그래서 String타입 변수인 id에 pathVarsMap.get("id")로 파라미터로 받은 값을 꺼내 초기화 하며 name도 마찬가지 이다. 그랬더니 예제의 밑에 출력결과인 ID: 1, name: bar처럼 받아지는것을 확인할 수 있다.
하지만 경로 변수에 문자열이 아닌 도트(.)가 찍힌경우 @PathVariable 매개변수를 처리하는 동안 에러가 발생할 수 있다. 이에 대한 문제는 https://www.baeldung.com/spring-mvc-pathvariable-dot여기서 확인할 수 있다.
spring에서는 기본적으로 @PathVariable 어노테이션이 달린 메서드 매개변수가 필요하다
@GetMapping(value = { "/api/employeeswithrequired", "/api/employeeswithrequired/{id}" })
@ResponseBody
public String getEmployeesByIdWithRequired(@PathVariable String id) {
return "ID: " + id;
}
위 컨트롤러는 /api/employeeswithrequired 및 /api/employeeswithrequired/1 요청 경로를 모두 처리해야 한다. 그러나 @PathVariables 어노테이션이 붙은 메소드 매개변수는 기본적으로 필수처리 이기 때문에 /api/employees로 전송된 요청을 처리하지 않습니다.
http://localhost:8080/api/employeeswithrequired
----
{"timestamp":"2020-07-08T02:20:07.349+00:00","status":404,"error":"Not Found","message":"","path":"/api/employeeswithrequired"}
http://localhost:8080/api/employeeswithrequired/1
----
ID: 111
하지만 이것을 2가지의 방법으로 해결할 수 있다.
@PathVariable에 필수 속성을 false라고 설정할 수 있다. 따라서 수정된 예제에서는 경로 변수가 있거나 없어도 두가지의 URI를 처리할 수 있다.
@GetMapping(value = { "/api/employeeswithrequiredfalse", "/api/employeeswithrequiredfalse/{id}" })
@ResponseBody
public String getEmployeesByIdWithRequiredFalse(@PathVariable(required = false) String id) {
if (id != null) {
return "ID: " + id;
} else {
return "ID missing";
}
}
http://localhost:8080/api/employeeswithrequiredfalse
----
ID missing
해당 결과는 경로 변수에 id를 지정하지 않으면 기본 응답을 얻을 수 있다.
앞의 예제에서 본것처럼 java.Util.Map 유형의 단일 메소드 매개변수를 사용하여 요청 URI의 모든 경로 변수를 처리할 수 있다. 또한 이 방법을 사용하여 선택적으로 경로 변수를 처리할 수 있다.
@GetMapping(value = { "/api/employeeswithmap/{id}", "/api/employeeswithmap" })
@ResponseBody
public String getEmployeesByIdWithMap(@PathVariable Map<String, String> pathVarsMap) {
String id = pathVarsMap.get("id");
if (id != null) {
return "ID: " + id;
} else {
return "ID missing";
}
}
기본적으로 @PathVariable 어노테이션이 달린 메서드 매개변수의 기본값을 정의하는 조항이 없다. 하지만 위에서 설명한 것과 동일한 방법을 사용하여 @PathVariable의 기본값을 지정할 수 있다. 경로 변수에서 Null체크만 하면 된다.
각 인스턴스에 Map<Stirng,String>을 사용하여 경로변수가 Null혹은 NotNull인지 체크하여 Null인 경우 기본값을 설정하여 응답할 수 있다.
@GetMapping(value = { "/api/defaultemployeeswithoptional", "/api/defaultemployeeswithoptional/{id}" })
@ResponseBody
public String getDefaultEmployeesByIdWithOptional(@PathVariable Optional<String> id) {
if (id.isPresent()) {
return "ID: " + id.get();
} else {
return "ID: Default Employee";
}
}
Boolean 타입
Optional 객체가 값을 가지고 있다면 true, 값이 없다면 false 리턴