점 (.)이있는 Spring MVC @PathVariable이 잘립니다.


361

이것은 Spring MVC @PathVariable이 잘리는 문제의 연속입니다.

Spring 포럼에서는 ContentNegotiationManager의 일부로 고정 버전 (3.2 버전)을 발표했습니다. 아래 링크를 참조하십시오.
https://jira.springsource.org/browse/SPR-6164
https://jira.springsource.org/browse/SPR-7632

내 응용 프로그램에서 .com의 requestParameter가 잘립니다.

누구든지이 새로운 기능을 사용하는 방법을 설명해 주시겠습니까? xml에서 어떻게 구성 할 수 있습니까?

참고 : 스프링 포럼-# 1 Spring MVC @PathVariable with 도트 (.)가 잘립니다.

답변:


485

내가 아는 한이 문제는 요청 매핑이 끝날 때 경로 변수에만 나타납니다.

requestmapping에서 정규식 애드온을 정의하여 문제를 해결할 수있었습니다.

 /somepath/{variable:.+}

1
감사합니다.이 수정 프로그램은 이전 (3.2V 이전)에서도 사용할 수 있다고 생각합니다. 그러나 나는이 수정을 좋아하지 않는다. 내 응용 프로그램에서 처리 해야하는 모든 URL에 필요하기 때문에 ... 앞으로의 URL 구현도이를 처리해야합니다 ...
Kanagavelu Sugumar

4
다음은 봄 3.0.5에서 문제를 해결 한 방법입니다.<!-- Spring Configuration needed to avoid URI using dots to be truncated --> <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"> <property name="useDefaultSuffixPattern" value="false" /> </bean>
Farid

11
@Mariusz, 구문은입니다 {variable_name:regular_expression}. 여기서 우리 는 name 이라는 변수를 가지고 있습니다 variable.이 값은 정규 표현식을 사용하여 일치합니다 .+(여기서 .'모든 문자'와 +'하나 이상의 시간'을 의미합니다).
Michał Rybak

4
@StefanHaberl variable규칙적인 방식으로 일치하면 Spring은 접미사 감지 기능을 사용하고 점 뒤의 모든 것을 자릅니다. 정규식 일치를 사용하면 해당 기능이 사용되지 않습니다. 변수는 사용자가 제공 한 정규식에만 일치합니다.
Michał Rybak

9
"variable:.+"변수에 점이 둘 이상 있으면 @martin 이 작동하지 않습니다. 예를 들어와 같은 편안한 경로 끝에 이메일을 넣는 것 /path/abc@server.com.au. 컨트롤러는 호출되지 않지만 하나의 dot 만있을 때 작동합니다 /path/abc@server.com. 왜 그리고 / 또는 해결 방법이 있습니까?
보헤미안

242

봄의 마지막 점 뒤에 아무것도 같은 파일 확장자를 것을 고려 .json하거나 .xml당신의 매개 변수를 검색하는 데 trucate.

그래서 당신이 가지고 있다면 /somepath/{variable}:

  • /somepath/param, /somepath/param.json, /somepath/param.xml또는 /somepath/param.anything값으로 될 것이다 PARAMparam
  • /somepath/param.value.json, /somepath/param.value.xml또는 /somepath/param.value.anything값으로 될 것이다 PARAMparam.value

매핑을 /somepath/{variable:.+}제안대로 변경 하면 마지막 점을 포함한 점이 매개 변수의 일부로 간주됩니다.

  • /somepath/param 가치가있는 매개 변수가됩니다 param
  • /somepath/param.json 가치가있는 매개 변수가됩니다 param.json
  • /somepath/param.xml 가치가있는 매개 변수가됩니다 param.xml
  • /somepath/param.anything 가치가있는 매개 변수가됩니다 param.anything
  • /somepath/param.value.json 가치가있는 매개 변수가됩니다 param.value.json
  • ...

확장 인식을 신경 쓰지 않으면 재정 의하여 비활성화 할 수 있습니다 mvc:annotation-driven automagic .

<bean id="handlerMapping"
      class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
    <property name="contentNegotiationManager" ref="contentNegotiationManager"/>
    <property name="useSuffixPatternMatch" value="false"/>
</bean>

다시 한 번, /somepath/{variable} :

  • /somepath/param, /somepath/param.json, /somepath/param.xml또는 /somepath/param.anything값으로 될 것이다 PARAMparam
  • /somepath/param.value.json, /somepath/param.value.xml또는 /somepath/param.value.anything값으로 될 것이다 PARAMparam.value

참고 : 기본 구성과의 차이점은 다음과 같은 매핑이있는 경우에만 볼 수 있습니다 somepath/something.{variable} . Resthub 프로젝트 이슈 참조

확장 관리를 유지하려면 Spring 3.2부터 suffixPattern 인식을 활성화하지만 등록 된 확장으로 제한하기 위해 RequestMappingHandlerMapping Bean의 useRegisteredSuffixPatternMatch 특성을 설정할 수도 있습니다.

여기에 json 및 xml 확장자 만 정의하십시오.

<bean id="handlerMapping"
      class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
    <property name="contentNegotiationManager" ref="contentNegotiationManager"/>
    <property name="useRegisteredSuffixPatternMatch" value="true"/>
</bean>

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="false"/>
    <property name="favorParameter" value="true"/>
    <property name="mediaTypes">
        <value>
            json=application/json
            xml=application/xml
        </value>
    </property>
</bean>

mvc : annotation-driven은 이제 customN을 제공하기 위해 contentNegotiation 옵션을 허용하지만 RequestMappingHandlerMapping의 특성을 true (기본값 false)로 변경해야합니다 (cf. https://jira.springsource.org/browse/SPR-7632). ).

이러한 이유로 여전히 모든 mvc : annotation-driven 구성을 대체해야합니다. 커스텀 RequestMappingHandlerMapping을 요청하기 위해 Spring 티켓을 열었습니다. https://jira.springsource.org/browse/SPR-11253 . 참여하고 있다면 투표 해주세요.

재정의하는 동안 사용자 지정 실행 관리 재정의도 고려해야합니다. 그렇지 않으면 모든 사용자 지정 예외 매핑이 실패합니다. messageCoverters를 목록 Bean과 함께 재사용해야합니다.

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />

<util:list id="messageConverters">
    <bean class="your.custom.message.converter.IfAny"></bean>
    <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</util:list>

<bean name="exceptionHandlerExceptionResolver"
      class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver">
    <property name="order" value="0"/>
    <property name="messageConverters" ref="messageConverters"/>
</bean>

<bean name="handlerAdapter"
      class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="webBindingInitializer">
        <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
            <property name="conversionService" ref="conversionService" />
            <property name="validator" ref="validator" />
        </bean>
    </property>
    <property name="messageConverters" ref="messageConverters"/>
</bean>

<bean id="handlerMapping"
      class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
</bean>

오픈 소스 프로젝트 인 Resthub 에서 이러한 주제에 대한 일련의 테스트를 구현했습니다. https://github.com/resthub/resthub-spring-stack/pull/219/files & https : // 참조 github.com/resthub/resthub-spring-stack/issues/217


저를 초보자로 용서하십시오. bean 설정을 어디에 두겠습니까? 그리고 어떤 봄 버전에 적용됩니까?
Splash

@Splash :이 빈을 "표준"Spring applicationContext.xml 파일에 정의해야한다. 이것은 적어도 Spring 3.2에 적용됩니다. 아마 (적어도 부분적으로)
bmeurant September

이것은 내 의견으로는 정답이 아닙니다. OP 문제에 대해 "useRegisteredSuffixPatternMatch"매개 변수가 정확하게 도입 된 것 같습니다.
lrxw

이것은 나를위한 해결책의 절반에 불과했습니다. @Paul Aerer의 답변을 참조하십시오.
8bitjunkie

96

Spring 4 업데이트 : 4.0.1부터 사용할 수 있습니다 PathMatchConfigurer (를 통해 WebMvcConfigurer)

@Configuration
protected static class AllResources extends WebMvcConfigurerAdapter {

    @Override
    public void configurePathMatch(PathMatchConfigurer matcher) {
        matcher.setUseRegisteredSuffixPatternMatch(true);
    }

}


@Configuration
public class WebConfig implements WebMvcConfigurer {

   @Override
   public void configurePathMatch(PathMatchConfigurer configurer) {
       configurer.setUseSuffixPatternMatch(false);
   }
}

xml에서는 ( https://jira.spring.io/browse/SPR-10163 )입니다.

<mvc:annotation-driven>
    [...]
    <mvc:path-matching registered-suffixes-only="true"/>
</mvc:annotation-driven>

11
이것은 가장 깨끗한 해결책입니다. 해킹하지 말고 기능을 끄십시오. 우리는 어쨌든이 기능을 사용하지 않으므로 문제가 해결되었습니다. 완벽합니다!
David Lavender

AllResources 클래스는 어디로 가나 요?
irl_irl

1
@ste_irl 기본과 동일한 패키지에 Java 클래스를 추가하십시오.
kometen

5
matcher.setUseSuffixPatternMatch(false)접미사 일치를 완전히 비활성화하는 데 사용 합니다.
지안 마르코 게 라디

이것은 나를위한 해결책의 절반에 불과했습니다. @Paul Aerer의 답변을 참조하십시오.
8bitjunkie

87

Martin Frey의 답변 외에도 RequestMapping 값에 슬래시를 추가 하여이 문제를 해결할 수 있습니다.

/path/{variable}/

이 수정 프로그램은 유지 관리 기능을 지원하지 않습니다. 이제 모든 URI에 후행 슬래시가 있어야합니다. API 사용자 / 신규 개발자에게는 눈에 띄지 않을 수 있습니다. 모든 매개 변수에 매개 변수가 없을 .수도 있으므로 간헐적 인 버그가 발생할 수도 있습니다.


2
심지어 더 깨끗한 솔루션입니다. IE가 접미사에 따라 수락 헤더를 설정하는 어려운 방법을 찾아야했습니다. 그래서 일부 .doc requestmapping에 게시하고 싶었고 항상 새로운 HTML 페이지 대신 다운로드를 받았습니다. 이 접근 방식으로 해결했습니다.
Martin Frey

이것은 내 문제를 해결하고 해결하는 가장 간단한 해결책입니다. 정규 표현식은 많은 경우에 약간의 과잉으로 보인다
Riccardo Cossu

7
그러나 AngularJS의 기본 동작과 충돌하여 후행 슬래시를 자동으로 제거합니다. 최신 Angular 릴리스에서 구성 할 수 있지만 진행 상황을 모르는 경우 몇 시간 동안 추적해야합니다.
dschulten

1
@dschulten 그리고 방금 디버깅 시간을 절약했습니다. 감사합니다! 그럼에도 불구하고 HTPP 요청에 슬래시가 필요하다는 답변을 언급해야합니다.
호프만

1
이것은 매우 위험합니다! API를 구현하는 사람은 거의 그것을 기대하지 않으므로 확실히 권장하지 않습니다. 유지 관리가 불가능합니다.
sparkyspider

32

Spring Boot Rest Controller에서 다음 단계에 따라 문제를 해결했습니다.

RestController :

@GetMapping("/statusByEmail/{email:.+}/")
public String statusByEmail(@PathVariable(value = "email") String email){
  //code
}

그리고 나머지 클라이언트에서 :

Get http://mywebhook.com/statusByEmail/abc.test@gmail.com/

2
이 답변은 작동하기 위해 슬래시 뒤에 달려 있습니다.
8bitjunkie

2
매력처럼 작동합니다 (또한 슬래시가 없음). 감사합니다!
afe December

27

":. +"를 추가하면 나에게 도움이되었지만 바깥 쪽 중괄호를 제거 할 때까지는 효과가 없었습니다.

value = { "/username/{id:.+}" } 이 작동하지 않습니다

값 = "/username/{id:.+}" 작동

누군가를 도왔기를 바랍니다 :)


이는 중괄호가 정규식을 평가하고 이미 주변에 있기 때문입니다.id
8bitjunkie

15

/somepath/{variable:.+}Java requestMapping태그 에서 작동합니다 .


작동하지 않는 것을 보여주지 않기 때문에이 대답을 선호합니다.
johnnieb

점이 둘 이상인 전자 메일 주소에는 작동하지 않습니다.
8bitjunkie

1
@ 같은 8bitjunkie Sth를 "/{code:.+}"많은 점에 대한 작품은 하나도 즉 61.12.7그것은 또한 즉 작동k.a.p@o.i.n
tryingHard

13

Java 구성에 전적으로 의존하는 접근 방식은 다음과 같습니다.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

@Configuration
public class MvcConfig extends WebMvcConfigurationSupport{

    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();
        handlerMapping.setUseSuffixPatternMatch(false);
        handlerMapping.setUseTrailingSlashMatch(false);
        return handlerMapping;
    }
}

고마워, 나를 위해 해결했다. 또한 매우 깨끗하고 명시 적입니다. +1
bkis

11

이 문제를 해결하는 매우 쉬운 방법 중 하나는 후행 슬래시를 추가하는 것입니다 ...

예 :

사용하다 :

/somepath/filename.jpg/

대신에:

/somepath/filename.jpg

11

Spring Boot에서 정규 표현식은 다음과 같은 문제를 해결합니다.

@GetMapping("/path/{param1:.+}")

이것은 하나의 점에서만 작동합니다. 이메일 주소에서는 작동하지 않습니다.
8bitjunkie

1
@ 8bitjunkie Sth는 "/{code:.+}"하나의 점이 아닌 많은 점에서 61.12.7작동합니다. 즉, 작동합니다.k.a.p@o.i.n
TryHard

1
@ 8bitjunkie IP 주소로 테스트했습니다. 잘 작동합니다. 즉, 여러 점에서 작동합니다.
Dapper Dan

6

스프링 4.2의 경로 이름에 이메일 주소를 포함하는 완벽한 솔루션은

<bean id="contentNegotiationManager"
    class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="false" />
    <property name="favorParameter" value="true" />
    <property name="mediaTypes">
        <value>
            json=application/json
            xml=application/xml
        </value>
    </property>
</bean>
<mvc:annotation-driven
    content-negotiation-manager="contentNegotiationManager">
    <mvc:path-matching suffix-pattern="false" registered-suffixes-only="true" />
</mvc:annotation-driven>

이것을 application-xml에 추가하십시오


공감-이것은 ContentNegotiationManagerFactoryBean 및
contentNegotiationManager

5

Spring 3.2.x 및를 사용하는 경우 다음을 <mvc:annotation-driven />작성하십시오 BeanPostProcessor.

package spring;

public final class DoNotTruncateMyUrls implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof RequestMappingHandlerMapping) {
            ((RequestMappingHandlerMapping)bean).setUseSuffixPatternMatch(false);
        }
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

그런 다음 MVC 구성 XML에 이것을 넣으십시오.

<bean class="spring.DoNotTruncateMyUrls" />

ContentNegotiationManager와 관련이 있습니까?
Kanagavelu Sugumar

내 코드는 URL이 잘리지 않도록 RequestMappingHandlerMapping 만 구성합니다. ContentNegotiationManager는 또 다른 짐승입니다.
Jukka

2
이것은 오래되었지만 실제로는 필요하지 않습니다 BeanPostProcessor. 사용 WebMvcConfigurationSupport하면 requestMappingHandlerMapping @Bean메소드를 대체 할 수 있습니다 . XML 구성을 사용하는 경우 고유 한 RequestMappingHandlerMappingBean을 선언하고 해당 특성을 선언하면됩니다.
Sotirios Delimanolis

대단히 감사합니다. 동일한 문제에 대해 다른 수의 솔루션을 시도했지만이 하나만 나를 위해 일했습니다. :-)
우리는 Borg입니다.

3

마지막으로 Spring Docs 에서 솔루션을 찾았습니다 .

파일 확장자 사용을 완전히 비활성화하려면 다음을 모두 설정해야합니다.

 useSuffixPatternMatching(false), see PathMatchConfigurer

 favorPathExtension(false), see ContentNegotiationConfigurer

이것을 WebMvcConfigurerAdapter구현에 추가하면 문제가 해결되었습니다.

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer.favorPathExtension(false);
}

@Override
public void configurePathMatch(PathMatchConfigurer matcher) {
    matcher.setUseSuffixPatternMatch(false);
}

2

나를 위해

@GetMapping(path = "/a/{variableName:.+}")

작동하지만 요청 URL의 "도트"를 "% 2E"로 인코딩 한 경우에만 작동합니다. 그러나 URL은 모두 필요합니다 ... 유효하지만 "표준"인코딩이 아닙니다. 버그 같은 느낌 : |

"트레일 링 슬래시"방법과 유사한 다른 해결 방법은 "인라인"점이있는 변수를 이동하는 것입니다. 예 :

@GetMapping (경로 = "/ {variableName} / a")

이제 모든 점이 유지되며 수정이나 정규식이 필요하지 않습니다.


1

봄 5.2.4 (봄 부팅 v2.2.6.RELEASE)의로 PathMatchConfigurer.setUseSuffixPatternMatchContentNegotiationConfigurer.favorPathExtension사용되지 않습니다 ( https://spring.io/blog/2020/03/24/spring-framework-5-2-5-available-nowhttps://github.com/spring-projects/spring-framework/issues/24179 ).

실제 문제는 클라이언트가 .com과 같은 특정 미디어 유형을 요청하고 Spring이 기본적으로 모든 미디어 유형을 추가한다는 것입니다. 대부분의 경우 REST 컨트롤러는 JSON 만 생성하므로 요청 된 출력 형식 (.com)을 지원하지 않습니다. 이 문제를 극복하려면 나머지 제어기 (또는 특정 방법)를 '출력'형식 ( @RequestMapping(produces = MediaType.ALL_VALUE) 을 지원하도록 업데이트 하고 물론 점 ({username:.+} ) .

예:

@RequestMapping(value = USERNAME, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public class UsernameAPI {

    private final UsernameService service;

    @GetMapping(value = "/{username:.+}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.ALL_VALUE)
    public ResponseEntity isUsernameAlreadyInUse(@PathVariable(value = "username") @Valid @Size(max = 255) String username) {
        log.debug("Check if username already exists");
        if (service.doesUsernameExist(username)) {
            return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
        }
        return ResponseEntity.notFound().build();
    }
}

Spring 5.3 이상은 등록 된 접미사 (매체 유형) 와만 일치합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.