Spring MVC @PathVariableが切り捨てられる


142

情報へのRESTfulアクセスを提供するコントローラーがあります。

@RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}")
public ModelAndView getBlah(@PathVariable String blahName, HttpServletRequest request,
                            HttpServletResponse response) {

私が経験している問題は、特殊文字を含むパス変数でサーバーにアクセスすると、切り捨てられることです。例: http:// localhost:8080 / blah-server / blah / get / blah2010.08.19-02:25:47

パラメータblahNameはblah2010.08になります

ただし、request.getRequestURI()の呼び出しには、渡されたすべての情報が含まれています。

Springが@PathVariableを切り捨てないようにする方法はありますか?


回答:


149

@RequestMapping引数に正規表現を試してください:

RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName:.+}")

1
私たちが代わりにXMLの@Configurationバネクラスを使用しているので、「useDefaultSuffixPattern」は、他のオプションは、オプションではありませんでした: - 。答えてくれてありがとう、これは私が(..ユーザ名が何らかの形でトリミングされてしまった事件を解決する助け
evandongen

3
これは機能しますが、正規表現でのコロンの意味は何ですか?
Noah Yetter

6
ノア、私はこれを長い間使用していませんでしたが、コロンは、それをバインドする引数名から正規表現を分離していると思います。
アールドゥグラス

3
同様の問題/item/user@abc.comがありました。@が切り捨てられた後は、スラッシュ/item/user@abc.com/を追加することで解決しました
Titi Wangsa bin Damhore

59

これは、おそらくSPR-6164と密接に関連しています。簡単に言うと、フレームワークはURI解釈にいくつかのスマートを適用して、ファイル拡張子と考えているものを削除しようとします。これはをファイル拡張子と見なすため、にblah2010.08.19-02:25:47変換する効果があります。blah2010.08.19-02:25:47

リンクされた問題で説明されているように、DefaultAnnotationHandlerMappingアプリコンテキストで独自のBeanを宣言し、そのuseDefaultSuffixPatternプロパティをに設定することで、この動作を無効にできますfalse。これにより、デフォルトの動作が上書きされ、データの悪用が停止されます。


3
拡張機能に基づくコンテンツネゴシエーションをデフォルトでオンにするのは、奇妙な選択のようです。実際に同じリソースを異なるフォーマットで公開しているシステムはいくつありますか?
2010

私は午前中にこれを試しましたが、それでもパス変数が切り捨てられていました。
10

30
+1はすばらしい回答であり、「データを害する」というフレーズを使用する場合
Chris Thompson

11
Spring 3.1ユーザーの場合- RequestMappingHandlerMapping代わりにnewを使用している場合、設定するプロパティはuseSuffixPatternMatch(またfalse)です。@テッド:リンクされた問題は、3.2ではもう少し制御を追加することを望んでいるため、オールオアナッシングである必要がないことを述べています。
Nick

2
Spring 4.2では、これは設定が少し簡単です。私たちはJava構成クラスを使用WebMvcConfigurationSupportし、単純なフックを提供するを拡張しpublic void configurePathMatch(PathMatchConfigurer configurer)ます。-単にそれをオーバーライドし、希望する方法に一致するパスを設定します。
pmckeown 2016年

31

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

だからあなたが持っている場合/{blahName}

  • /param/param.json/param.xmlまたは/param.anything値PARAMをもたらしますparam
  • /param.value.json/param.value.xmlまたは/param.value.anything値を持つパラメータになりますparam.value

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

  • /param 値を持つパラメータになります param
  • /param.json 値を持つパラメータになります param.json
  • /param.xml 値を持つパラメータになります param.xml
  • /param.anything 値を持つパラメータになります param.anything
  • /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>

だから、もう一度、あなたが持っているなら/{blahName}

  • /param/param.json/param.xmlまたは/param.anything値PARAMをもたらしますparam
  • /param.value.json/param.value.xmlまたは/param.value.anything値を持つパラメータになりますparam.value

注:デフォルトの構成との違いは、のようなマッピングがある場合にのみ表示されます/something.{blahName}Resthubプロジェクトの問題を参照してください。

拡張機能の管理を維持する場合は、Spring 3.2以降、RequestMappingHandlerMapping BeanのuseRegisteredSuffixPatternMatchプロパティを設定して、suffixPattern認識をアクティブにしたまま、登録された拡張機能に限定することもできます。

ここでは、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)に変更する必要があることに注意してくださいhttps://jira.springsource.org/browse/SPR-7632を参照))。

そのため、すべてのmvc:annotation-driven構成をオーバーライドする必要があります。Springへのチケットを開いて、カスタムのRequestMappingHandlerMapping:https ://jira.springsource.org/browse/SPR-11253を要求しました。興味があれば投票してください。

オーバーライドするときは、カスタム実行管理のオーバーライドも考慮するように注意してください。そうしないと、すべてのカスタム例外マッピングが失敗します。リストBeanでmessageCoverterを再利用する必要があります。

<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


16

最後のドット以降はすべてファイル拡張子として解釈され、デフォルトで切り捨てられます。
あなたの春の設定XMLでは、あなたは追加することができますDefaultAnnotationHandlerMappingし、セットuseDefaultSuffixPatternfalse(デフォルトはありますtrue)。

だからあなたの春のxmlを開くmvc-config.xml(またはそれが呼び出されます)そして追加してください

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="useDefaultSuffixPattern" value="false" />
</bean>

これで、あなたの@PathVariable blahName(そして他のすべてのものも)すべてのドットを含むフルネームが含まれるはずです。

編集:ここに春のAPIへのリンクがあります


私は試していませんが、該当する場合は削除する必要があると主張する人もいます<mvc:annotation-driven />
Arjan

7

私も同じ問題に遭遇しました、そしてプロパティをfalseに設定することも私を助けませんでした。ただし、APIによると

「.xxx」サフィックスを含むパスまたは「/」で終わるパスは、いずれの場合もデフォルトのサフィックスパターンを使用して変換されないことに注意してください。

RESTful URLに「/ end」を追加してみたところ、問題は解消しました。解決策には満足していませんが、うまくいきました。

ところで、Springのデザイナーがこの「機能」を追加してデフォルトでオンにしたときに何を考えていたかはわかりません。私見、それは削除されるべきです。


同意する。私は最近これに噛まれました。
llambda 2014

7

正しいJava構成クラスを使用する:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter
{

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

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

これは私にとってはうまくいきました。Tomcat Springバージョン4.3.14で実行
Dave


3

私はこれに遭遇しましたが、ここでのソリューションは一般的に期待どおりに機能しませんでした。

SpEL式と複数のマッピングを使用することをお勧めします。

@RequestMapping(method = RequestMethod.GET, 
    value = {Routes.BLAH_GET + "/{blahName:.+}", 
             Routes.BLAH_GET + "/{blahName}/"})

3

ファイル拡張子の問題は、パラメーターがURLの最後の部分にある場合にのみ存在します。変化する

@RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}")

@RequestMapping(
   method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}/safe")

そして、すべてが再び元気になります


3

リクエストが送信されるアドレスを編集できる場合、簡単な修正は、それらに(そして@RequestMapping値にも)末尾のスラッシュを追加することです:

/path/{variable}/

したがって、マッピングは次のようになります。

RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}/")

ドット(。)を含むSpring MVC @PathVariableが切り捨てられることも参照してください。


3
//in your xml dispatcher  add this property to your default annotation mapper bean as follow
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
    <property name="alwaysUseFullPath" value="true"></property>
</bean>       

3

「:。+」の追加は私にとってはうまくいきましたが、外側の中括弧を削除するまではうまくいきませんでした。

value = {"/username/{id:.+}"} うまくいきませんでした

value = "/username/{id:.+}" 働く

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


2

切り捨てを防ぐための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 PolRepWebConfig extends WebMvcConfigurationSupport {

    @Override
    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        final RequestMappingHandlerMapping handlerMapping = super
                .requestMappingHandlerMapping();
        // disable the truncation after .
        handlerMapping.setUseSuffixPatternMatch(false);
        // disable the truncation after ;
        handlerMapping.setRemoveSemicolonContent(false);
        return handlerMapping;
    }
}

ソース:http://www.javacodegeeks.com/2013/01/spring-mvc-customizing-requestmappinghandlermapping.html

更新:

上記のアプローチを使用したとき、Spring Bootの自動構成にいくつかの問題があることに気付きました(一部の自動構成が有効になりません)。

代わりに、私はBeanPostProcessorアプローチを使い始めました。うまく機能しているようです。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {
    private static final Logger logger = LoggerFactory
            .getLogger(MyBeanPostProcessor.class);

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        if (bean instanceof RequestMappingHandlerMapping) {
            setRemoveSemicolonContent((RequestMappingHandlerMapping) bean,
                    beanName);
            setUseSuffixPatternMatch((RequestMappingHandlerMapping) bean,
                    beanName);
        }
        return bean;
    }

    private void setRemoveSemicolonContent(
            RequestMappingHandlerMapping requestMappingHandlerMapping,
            String beanName) {
        logger.info(
                "Setting 'RemoveSemicolonContent' on 'RequestMappingHandlerMapping'-bean to false. Bean name: {}",
                beanName);
        requestMappingHandlerMapping.setRemoveSemicolonContent(false);
    }

    private void setUseSuffixPatternMatch(
            RequestMappingHandlerMapping requestMappingHandlerMapping,
            String beanName) {
        logger.info(
                "Setting 'UseSuffixPatternMatch' on 'RequestMappingHandlerMapping'-bean to false. Bean name: {}",
                beanName);
        requestMappingHandlerMapping.setUseSuffixPatternMatch(false);
    }
}

発想:http://ronaldxq.blogspot.com/2014/10/spring-mvc-setting-alwaysusefullpath-on.html


2

テキストがデフォルトの拡張子のどれとも一致しないことが確実な場合は、以下のコードを使用できます。

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

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

1

Spring MVC @PathVariableが切り捨てられないようにするための私の望ましい解決策は、パス変数の最後にスラッシュを追加することです。

例えば:

@RequestMapping(value ="/email/{email}/")

したがって、リクエストは次のようになります。

http://localhost:8080/api/email/test@test.com/

1

直面している問題は、ドット(。)ののuriの最後の部分を.jsonや.xmlなどのファイル拡張子としてスプリングが解釈するためです。したがって、Springがパス変数を解決しようとすると、URIの最後にドット(。)が検出された後、残りのデータが切り捨てられます。 注:これは、URIの末尾にパス変数を保持している場合にのみ発生します。

たとえば、uriについて考えます。https://localhost/example/gallery.df/link.ar

@RestController
public class CustomController {
    @GetMapping("/example/{firstValue}/{secondValue}")
    public void example(@PathVariable("firstValue") String firstValue,
      @PathVariable("secondValue") String secondValue) {
        // ...  
    }
}

上記のURL firstValue = "gallery.df"およびsecondValue = "link"では、の後の最後のビット。パス変数が解釈されると切り捨てられます。

したがって、これを防ぐには、次の2つの方法があります。

1.)正規表現マッピングの使用

マッピングの最後の部分で正規表現を使用する

@GetMapping("/example/{firstValue}/{secondValue:.+}")   
public void example(
  @PathVariable("firstValue") String firstValue,
  @PathVariable("secondValue") String secondValue) {
    //...
}

+を使用することにより、ドットがパス変数の一部になる後の値を示します。

2.)@PathVariableの最後にスラッシュを追加する

@GetMapping("/example/{firstValue}/{secondValue}/")
public void example(
  @PathVariable("firstValue") String firstValue,
  @PathVariable("secondValue") String secondValue) {
    //...
}

これは、Springのデフォルトの動作からそれを保護する2番目の変数を囲みます。

3)Springのデフォルトのwebmvc構成をオーバーライドする

Springは、アノテーション@EnableWebMvcを使用してインポートされるデフォルト構成をオーバーライドする方法を提供します。アプリケーションコンテキストで独自のDefaultAnnotationHandlerMapping Beanを宣言し、そのuseDefaultSuffixPatternプロパティをfalseに設定することで、Spring MVC構成をカスタマイズできます。例:

@Configuration
public class CustomWebConfiguration extends WebMvcConfigurationSupport {

    @Bean
    public RequestMappingHandlerMapping 
      requestMappingHandlerMapping() {

        RequestMappingHandlerMapping handlerMapping
          = super.requestMappingHandlerMapping();
        handlerMapping.setUseSuffixPatternMatch(false);
        return handlerMapping;
    }
}

このデフォルト設定を上書きすると、すべてのURLに影響することに注意してください。

注:ここでは、デフォルトのメソッドをオーバーライドするためにWebMvcConfigurationSupportクラスを拡張しています。WebMvcConfigurerインターフェイスを実装することにより、デフォルトの構成をオーバーライドするもう1つの方法があります。この詳細については、https//docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/EnableWebMvc.htmlをご覧ください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.