1. 개요
Spring 5는 URI 템플릿 패턴을 구문 분석하기 위한 새로운 PathPatternParser 를 가져왔습니다 . 이것은 이전에 사용된 AntPathMatcher 의 대안 입니다.
AntPathMatcher 는 Ant 스타일 경로 패턴 일치를 구현한 것입니다 . PathPatternParser 는 경로를 PathElements 의 연결된 List으로 나눕니다 . 이 PathElements 체인은 빠른 패턴 일치를 위해 PathPattern 클래스에서 사용합니다.
PathPatternParser 와 함께 새로운 URI 변수 구문에 대한 지원도 도입되었습니다.
이 기사에서는 Spring 5.0 WebFlux에 도입된 신규/업데이트된 URL 패턴 매처 와 이전 버전의 Spring부터 있었던 것을 살펴보겠습니다 .
2. Spring 5.0의 새로운 URL 패턴 매처
Spring 5.0 릴리스에는 매우 사용하기 쉬운 URI 변수 구문인 {*foo}가 추가되어 패턴의 끝에서 여러 경로 세그먼트를 캡처합니다.
2.1. URI 변수 구문 {*foo} 핸들러 메서드 사용
URI 변수 패턴 {*foo} @GetMapping 및 핸들러 메서드 를 사용하는 다른 예를 살펴보겠습니다. "/spring5" 이후의 경로에서 제공하는 모든 내용은 경로 변수 "id"에 저장됩니다.
@GetMapping("/spring5/{*id}")
public String URIVariableHandler(@PathVariable String id) {
return id;
}
@Test
public void givenHandlerMethod_whenMultipleURIVariablePattern_then200() {
client.get()
.uri("/spring5/baeldung/tutorial")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("/baeldung/tutorial");
client.get()
.uri("/spring5/baeldung")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("/baeldung");
}
2.2. URI 변수 구문 {*foo} RouterFunction 사용
RouterFunction 을 사용하는 새로운 URI 변수 경로 패턴의 예를 살펴보겠습니다 .
private RouterFunction<ServerResponse> routingFunction() {
return route(GET("/test/{*id}"),
serverRequest -> ok().body(fromValue(serverRequest.pathVariable("id"))));
}
이 경우 "/test" 뒤에 작성하는 모든 경로는 경로 변수 "id"에 캡처됩니다. 따라서 이에 대한 테스트 사례는 다음과 같습니다.
@Test
public void givenRouter_whenMultipleURIVariablePattern_thenGotPathVariable()
throws Exception {
client.get()
.uri("/test/ab/cd")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("/ab/cd");
}
2.3. URI 변수 구문 {*foo}를 사용하여 리소스에 액세스
리소스에 액세스하려면 이전 예제에서 작성한 것과 유사한 경로 패턴을 작성해야 합니다.
패턴이 "/files/{*filepaths}"라고 가정해 보겠습니다. 이 경우 경로가 /files/hello.txt인 경우 경로 변수 "filepaths" 의 값은 "/hello.txt"가 되고, 경로가 /files/test/test.txt인 경우 "파일 경로" = "/test/test.txt".
/files/ 디렉토리 아래의 파일 리소스에 액세스하기 위한 라우팅 기능 :
private RouterFunction<ServerResponse> routingFunction() {
return RouterFunctions.resources(
"/files/{*filepaths}",
new ClassPathResource("files/")));
}
텍스트 파일 인 hello.txt 와 test.txt 에 각각 "hello" 와 "test" 가 포함되어 있다고 가정해 보겠습니다 . 이는 JUnit 테스트 케이스로 시연할 수 있습니다.
@Test
public void givenResources_whenAccess_thenGot()
throws Exception {
client.get()
.uri("/files/test/test.txt")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("test");
client.get()
.uri("/files/hello.txt")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("hello");
}
3. 이전 버전의 기존 URL 패턴
이제 이전 버전의 Spring에서 지원했던 다른 모든 URL 패턴 매처를 살펴보겠습니다. 이러한 모든 패턴은 @GetMapping을 사용하는 RouterFunction 및 Handler 메서드 모두 에서 작동 합니다 .
3.1. '?' 정확히 하나의 문자와 일치
경로 패턴을 다음과 같이 지정하면 "/t? st ", 이것은 "/test" 및 "/tast" 와 같은 경로와 일치 하지만 "/tst" 및 "/teest"는 일치하지 않습니다.
RouterFunction 및 해당 JUnit 테스트 사례 를 사용하는 예제 코드 :
private RouterFunction<ServerResponse> routingFunction() {
return route(GET("/t?st"),
serverRequest -> ok().body(fromValue("Path /t?st is accessed")));
}
@Test
public void givenRouter_whenGetPathWithSingleCharWildcard_thenGotPathPattern()
throws Exception {
client.get()
.uri("/test")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("Path /t?st is accessed");
}
3.2. '*'는 경로 세그먼트 내에서 0개 이상의 문자와 일치합니다.
경로 패턴을 "/baeldung/*Id" 로 지정하면 "/baeldung/Id", "/baeldung/tutorialId", "/baeldung/articleId" 등과 같은 경로 패턴과 일치합니다 .
private RouterFunction<ServerResponse> routingFunction() {
returnroute(
GET("/baeldung/*Id"),
serverRequest -> ok().body(fromValue("/baeldung/*Id path was accessed"))); }
@Test
public void givenRouter_whenGetMultipleCharWildcard_thenGotPathPattern()
throws Exception {
client.get()
.uri("/baeldung/tutorialId")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("/baeldung/*Id path was accessed");
}
3.3. '**'는 경로가 끝날 때까지 0개 이상의 경로 세그먼트와 일치합니다.
이 경우 패턴 일치는 단일 경로 세그먼트로 제한되지 않습니다. 패턴을 "/resources/**" 로 지정하면 "/resources/" 뒤의 모든 경로가 임의 개수의 경로 세그먼트와 일치합니다 .
private RouterFunction<ServerResponse> routingFunction() {
return RouterFunctions.resources(
"/resources/**",
new ClassPathResource("resources/")));
}
@Test
public void givenRouter_whenAccess_thenGot() throws Exception {
client.get()
.uri("/resources/test/test.txt")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("content of file test.txt");
}
3.4. 경로 변수 의 '{baeldung:[az]+}' 정규식
경로 변수 값에 대한 정규식을 지정할 수도 있습니다. 따라서 패턴이 "/{baeldung:[az]+}"와 같은 경우 경로 변수 "baeldung" 의 값 은 정규식과 일치하는 모든 경로 세그먼트가 됩니다.
private RouterFunction<ServerResponse> routingFunction() {
return route(GET("/{baeldung:[a-z]+}"),
serverRequest -> ok()
.body(fromValue("/{baeldung:[a-z]+} was accessed and "
+ "baeldung=" + serverRequest.pathVariable("baeldung"))));
}
@Test
public void givenRouter_whenGetRegexInPathVarible_thenGotPathVariable()
throws Exception {
client.get()
.uri("/abcd")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("/{baeldung:[a-z]+} was accessed and "
+ "baeldung=abcd");
}
3.5. '/{var1}_{var2}' 동일한 경로 세그먼트의 다중 경로 변수
Spring 5는 구분 기호로 분리된 경우에만 단일 경로 세그먼트에서 여러 경로 변수가 허용되도록 했습니다. 그래야만 Spring이 두 개의 서로 다른 경로 변수를 구별할 수 있습니다.
private RouterFunction<ServerResponse> routingFunction() {
return route(
GET("/{var1}_{var2}"),
serverRequest -> ok()
.body(fromValue( serverRequest.pathVariable("var1") + " , "
+ serverRequest.pathVariable("var2"))));
}
@Test
public void givenRouter_whenGetMultiplePathVaribleInSameSegment_thenGotPathVariables()
throws Exception {
client.get()
.uri("/baeldung_tutorial")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("baeldung , tutorial");
}
4. 결론
이 기사에서는 Spring 5의 새로운 URL 매처와 이전 버전의 Spring에서 사용할 수 있는 URL 매처를 살펴보았습니다.
항상 그렇듯이 우리가 논의한 모든 예제의 구현은 GitHub 에서 찾을 수 있습니다 .