web-dev-qa-db-ja.com

ドット(。)を含むSpring MVCの@PathVariableは切り捨てられます

これは質問の続きです Spring MVCの@PathVariableは切り捨てられます

Springフォーラムは、ContentNegotiationManagerの一部として(3.2バージョン)を修正したと述べています。下のリンクを見てください。
https://jira.springsource.org/browse/SPR-6164
https://jira.springsource.org/browse/SPR-7632

私のアプリケーションでは、.comのrequestParameterは切り捨てられています。

この新機能の使い方を誰かに説明してもらえますか。それはどのようにXMLで設定可能ですか?

注: spring forum-#1 Spring MVCのドット(。)付きの@PathVariableは切り捨てられます

319

私が知っている限りでは、この問題はrequestmappingの終わりにpathvariableにだけ現れます。

リクエストマッピングで正規表現アドオンを定義することでそれを解決することができました。

 /somepath/{variable:.+}
445
Martin Frey

Springは最後のドットの後ろにあるものは.json.xmlのようなファイル拡張子であるとみなし、それをあなたのパラメータを取得するために切り詰めます。

/somepath/{variable}があれば:

  • /somepath/param/somepath/param.json/somepath/param.xmlまたは/somepath/param.anythingは、paramという値を持つパラメーターになります。
  • /somepath/param.value.json/somepath/param.value.xmlまたは/somepath/param.value.anythingは、param.valueの値を持つパラメーターになります。

推奨されているようにマッピングを/somepath/{variable:.+}に変更すると、最後のドットを含むすべてのドットがパラメータの一部と見なされます。

  • /somepath/paramは、値paramを持つパラメーターになります。
  • /somepath/param.jsonparam.jsonの値を持つパラメータになります。
  • /somepath/param.xmlparam.xmlの値を持つパラメータになります。
  • /somepath/param.anythingparam.anythingの値を持つパラメータになります。
  • /somepath/param.value.jsonparam.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は、paramという値を持つパラメーターになります。
  • /somepath/param.value.json/somepath/param.value.xmlまたは/somepath/param.value.anythingは、param.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は、カスタムBeanを提供するcontentNegotiationオプションを受け入れるようになりましたが、RequestMappingHandlerMappingのプロパティをtrue(デフォルトはfalse)に変更する必要があります(cf. https://jira.springsource org/browse/SPR-7632 )。

そのため、まだすべてのmvc:annotation-driven設定を上書きする必要があります。私は、カスタムRequestMappingHandlerMappingを要求するためにSpringへのチケットを開きました: https://jira.springsource.org/browse/SPR-11253 。興味のある方は投票してください。

オーバーライドしている間は、カスタムの実行管理オーバーライドも考慮することをお勧めします。そうでなければ、すべてのカスタム例外マッピングは失敗します。リストBeanを使ってmessageCovertersを再利用する必要があります。

<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/fileshttps://github.com/resthub/resthub-spring-stack/issues/217

228
bmeurant

Spring 4用の更新:4.0.1以降では PathMatchConfigurer を(あなたのWebMvcConfigurerを介して)使うことができます。

@Configuration
protected static class AllResources extends WebMvcConfigurerAdapter {

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

}

Xmlでは、( https://jira.spring.io/browse/SPR-10163 )になります。

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

Martin Freyの回答に加えて、これはRequestMapping値に末尾のスラッシュを追加することによっても修正できます。

/path/{variable}/

この修正は保守性をサポートしないことに注意してください。それは今やすべてのURIが末尾のスラッシュを持つことを要求します - それはAPIユーザ/新しい開発者には明らかではないかもしれません。すべてのパラメータに.が含まれているとは限らないため、断続的なバグも発生する可能性があります

84
Michał Rybak

Spring Boot Rest Controllerでは、次の手順でこれらを解決しました。

RestController:

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

そして残りのクライアントから:

Get http://mywebhook.com/statusByEmail/[email protected]/
25
GoutamS

":。+"を追加してもうまくいきましたが、外側の波括弧を削除するまではうまくいきませんでした。

値={ "/ユーザー名/ {id:。+}"}うまくいかなかった

値= "/username/{id:.+}"は動作します

私が誰かを助けたことを願っています:)

25
Martin Čejka

/somepath/{variable:.+}はJavaのrequestMappingタグで動作します。

14
amit dahiya

これは純粋に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;
    }
}
12
Bruno Carrier

Spring Bootでは、正規表現は次のように問題を解決します。

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

この問題を回避するための1つの非常に簡単な方法は、末尾のスラッシュを追加することです。

例えば。:

つかいます :

/somepath/filename.jpg/

の代わりに:

/somepath/filename.jpg
10
Marcelo C.

春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に追加してください。

6
Paul Arer

もしあなたが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" />
5
Jukka

最後に、 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
luboskrnac

私にとっては

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

ただし、リクエストURLの「ドット」を「%2E」としてエンコードした場合にのみ機能します。しかし、URLにはそれだけが必要です...これは有効ですが「標準的な」エンコーディングではありません。バグのように感じます。

もう1つの回避策は、「末尾のスラッシュ」のように、ドットが「インライン」になるような変数を移動することです。

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

これですべてのドットが保存され、修正や正規表現は必要なくなりました。

0
rogerdpack