Spring MVC @PathVariable kesildi


142

Bilgilere RESTful erişim sağlayan bir denetleyicim var:

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

Yaşadığım sorun, sunucuya özel karakterler içeren bir yol değişkeni ile vurursam kesiliyor. Örneğin: http: // localhost: 8080 / blah-server / blah / get / blah2010.08.19-02: 25: 47

BlahName parametresi blah2010.08 olacaktır

Ancak request.getRequestURI () çağrısı, iletilen tüm bilgileri içerir.

Spring'in @PathVariable'ı kesmesini nasıl engelleyeceğiniz hakkında bir fikriniz var mı?


Bu, Bahar 3.2-M2'de çözülmüş gibi görünüyor: Bkz . İçerik anlaşması için geçerli dosya uzantısı yollarına izin verme ve belgeleri .
Arjan

Yanıtlar:


149

Bağımsız @RequestMappingdeğişken için normal bir ifade deneyin :

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

1
Cevabınız için teşekkürler, bu, kullanıcı adlarının bir şekilde kesildiği bir davayı çözmeme yardımcı oldu. (-: 'useDefaultSuffixPattern' ile diğer seçenek bir seçenek değildi çünkü XML yerine
@Configuration

3
Bu işe yarıyor, ama normal regexte kolonun önemi nedir?
Noah Yetter

6
Noah, bunu uzun zamandır kullanmadım, ama bence kolon düzenli ifadeyi argüman adından bağlamak için ayırıyor.
earldouglas

3
benzer bir problam /item/user@abc.com vardı, @ kesildikten sonra her şey, bu başka bir eğik çizgi /item/user@abc.com/ ekleyerek çözüldü
Titi Wangsa bin Damhore

59

Bu muhtemelen SPR-6164 ile yakından ilgilidir . Kısaca, çerçeve URI yorumuna bazı akıllılar uygulamaya çalışır ve dosya uzantıları olduğunu düşündüklerini kaldırır. Bu dönüm etkisini azaltacak blah2010.08.19-02:25:47içine blah2010.08o düşünüyor, çünkü .19-02:25:47bir dosya uzantısıdır.

Bağlantılı sorunda açıklandığı gibi DefaultAnnotationHandlerMapping, uygulama bağlamında kendi fasulyenizi bildirip useDefaultSuffixPatternözelliğini olarak ayarlayarak bu davranışı devre dışı bırakabilirsiniz false. Bu, varsayılan davranışı geçersiz kılar ve verilerinizin bozulmasını önler.


3
Uzantı tabanlı içerik pazarlığını varsayılan olarak açmak böyle garip bir seçim gibi görünüyor. Kaç sistem aynı kaynağı pratikte farklı formatlarda ortaya koyar?
Affed

Bunu sabah denedim ve hala yol değişkenlerini kesmiştim.
phogel

30
Harika bir yanıt için +1 ve ayrıca "verilerinizi molesting" ifadesini kullanmak için
Chris Thompson

11
Spring 3.1 kullanıcıları için - RequestMappingHandlerMappingbunun yerine yenisini kullanıyorsanız, ayarlanacak özellik useSuffixPatternMatch(ayrıca false) şeklindedir. @Ted: bağlantılı sorun, 3.2'de biraz daha fazla kontrol eklemeyi umduklarından bahsediyor, bu yüzden ya hep ya hiç.
Nick

2
İlkbahar 4.2'de bunun yapılandırılması biraz daha kolaydır. Java config sınıflarını kullanıyoruz ve WebMvcConfigurationSupportbasit bir kanca sağlayanı genişletiyoruz : public void configurePathMatch(PathMatchConfigurer configurer)- sadece bunu geçersiz kılın ve istediğiniz şekilde eşleşen yolu ayarlayın.
pmckeown

31

Spring, son noktanın arkasındaki herhangi bir şeyin .jsonveya gibi bir dosya uzantısı olduğunu düşünür .xmlve parametrenizi almak için keser.

Eğer varsa /{blahName}:

  • /param, /param.json, /param.xmlYa da /param.anythingbir değere sahip bir param sonuçlanırparam
  • /param.value.json, /param.value.xmlYa da /param.value.anythingbir değere sahip bir param sonuçlanırparam.value

Eşlemenizi /{blahName:.+}önerilen şekilde değiştirirseniz , sonuncusu da dahil olmak üzere herhangi bir nokta parametrenizin bir parçası olarak kabul edilir:

  • /param değeri olan bir param ile sonuçlanacak param
  • /param.json değeri olan bir param ile sonuçlanacak param.json
  • /param.xml değeri olan bir param ile sonuçlanacak param.xml
  • /param.anything değeri olan bir param ile sonuçlanacak param.anything
  • /param.value.json değeri olan bir param ile sonuçlanacak param.value.json
  • ...

Uzantı tanımayı önemsemiyorsanız, mvc:annotation-drivenotomajik özelliği geçersiz kılarak devre dışı bırakabilirsiniz :

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

Yani, yine, eğer varsa /{blahName}:

  • /param, /param.json, /param.xmlYa da /param.anythingbir değere sahip bir param sonuçlanırparam
  • /param.value.json, /param.value.xmlYa da /param.value.anythingbir değere sahip bir param sonuçlanırparam.value

Not: Varsayılan yapılandırmadan farkı yalnızca benzer bir eşlemeniz varsa görünür /something.{blahName}. Resthub projesi konusuna bakın .

Uzantı yönetimini korumak istiyorsanız, Bahar 3.2'den bu yana sonekPattern tanıma özelliğini etkinleştirilmiş ancak kayıtlı uzantıyla sınırlı tutmak için RequestMappingHandlerMapping bean'un useRegisteredSuffixPatternMatch özelliğini de ayarlayabilirsiniz.

Burada yalnızca json ve xml uzantılarını tanımlarsınız:

<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: ek açıklamaya dayalı özel bir fasulye sağlamak için artık bir contentNegotiation seçeneğini kabul ettiğini, ancak RequestMappingHandlerMapping özelliğinin true (varsayılan false) olarak değiştirilmesi gerektiğini unutmayın (bkz. Https://jira.springsource.org/browse/SPR-7632 ).

Bu nedenle, tüm mvc: ek açıklamaya dayalı yapılandırmayı geçersiz kılmanız gerekir. Özel bir RequestMappingHandlerMapping istemek için Spring'e bir bilet açtım: https://jira.springsource.org/browse/SPR-11253 . İlgileniyorsanız lütfen oy verin.

Geçersiz kılma sırasında, özel Yürütme yönetimi geçersiz kılmayı da dikkate almaya dikkat edin. Aksi takdirde, tüm özel İstisna eşlemeleriniz başarısız olur. İletiyi bir liste çekirdeği ile yeniden kullanmanız gerekecek:

<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>

Bir parçası olduğum açık kaynak projesi Resthub'da bu konularda bir dizi test uyguladım : bkz. Https://github.com/resthub/resthub-spring-stack/pull/219/files ve https: // github.com/resthub/resthub-spring-stack/issues/217


16

Son noktadan sonraki her şey varsayılan olarak dosya uzantısı olarak yorumlanır ve kesilir.
Bahar Yapılandırma xml ekleyebilir DefaultAnnotationHandlerMappingve seti useDefaultSuffixPatterniçin false(varsayılan olan true).

Bu yüzden bahar xml'nizi açın mvc-config.xml(veya denir) ve ekleyin

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

Şimdi @PathVariable blahName(ve diğer tüm öğeleriniz de) tüm noktalar dahil tam adı içermelidir.

EDIT: İşte bahar api bir bağlantı


Ben denemedim, ancak diğerleri de <mvc:annotation-driven />varsa kaldırmanız gerektiğini iddia ediyor .
Arjan

7

Ben de aynı sorunla karşılaştı ve özelliği false olarak ayarlamak da bana yardımcı olmadı. Ancak, API diyor ki :

".Xxx" soneki veya "/" ile biten yolların zaten varsayılan sonek deseni kullanılarak dönüştürülmeyeceğini unutmayın.

RESTful URL'ye "/ end" eklemeyi denedim ve sorun ortadan kalktı. Lütfen çözümden memnun değilim, ama işe yaradı.

BTW, Bahar tasarımcılarının bu "özelliği" eklediklerinde ne düşündüklerini bilmiyorum ve daha sonra varsayılan olarak açtılar. IMHO, kaldırılmalıdır.


Katılıyorum. Son zamanlarda bunu biraz bitirdim.
llambda

7

Doğru Java yapılandırma sınıfını kullanma:

@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);
    }
}

Bu benim için harika çalıştı. Tomcat Spring sürüm 4.3.14 üzerinde çalışan
Dave


3

Sadece bununla karşılaştım ve buradaki çözümler genellikle beklediğim gibi çalışmadı.

Bir SpEL ifadesi ve çoklu eşlemeler kullanmanızı öneririm, örn.

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

3

Dosya uzantısı sorunu yalnızca parametre URL'nin son kısmındaysa ortaya çıkar. Değişiklik

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

için

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

ve hepsi tekrar iyi olacak-


3

İsteklerin gönderildiği adresi düzenleyebiliyorsanız, basit düzeltme onlara bir eğik çizgi (ve ayrıca @RequestMappingdeğerde) eklemek olacaktır :

/path/{variable}/

eşleme şöyle görünecektir:

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

Ayrıca bkz. Bahar MVC @PathVariable ile nokta (.) Kesiliyor .


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

":. +" ekleyerek benim için çalıştı, ama dış süslü parantez kaldırılıncaya kadar.

value = {"/username/{id:.+}"} çalışmadı

value = "/username/{id:.+}" İşler

Umarım birine yardım ettim:]


2

Kesmeyi önlemek için Java tabanlı yapılandırma çözümü (kullanımdan kaldırılmamış bir sınıf kullanarak):

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;
    }
}

Kaynak: http://www.javacodegeeks.com/2013/01/spring-mvc-customizing-requestmappinghandlermapping.html

GÜNCELLEME:

Yukarıdaki yaklaşımı kullandığımda Spring Boot otomatik yapılandırmasında bazı sorunlar yaşadığımı fark ettim (bazı otomatik yapılandırmalar etkili olmaz).

Bunun yerine BeanPostProcessoryaklaşımı kullanmaya başladım . Daha iyi çalışıyor gibi görünüyordu.

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);
    }
}

Esin kaynağı: http://ronaldxq.blogspot.com/2014/10/spring-mvc-setting-alwaysusefullpath-on.html


2

metninizin varsayılan uzantıların hiçbiriyle eşleşmeyeceğinden eminseniz aşağıdaki kodu kullanabilirsiniz:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

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

1

Spring MVC @PathVariable'ın kısaltılmasını önlemek için tercih ettiğim çözüm, yol değişkeninin sonuna eğik çizgi eklemektir.

Örneğin:

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

Yani, istek şöyle görünecektir:

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

1

Eğer karşı karşıya olduğu sorun nedeniyle bahar yorumlama son uri kısmını sonra nokta (.) Bir şekilde dosya uzantısı .json veya .xml gibi. Bahar yol değişkenini çözmeye çalıştığında, uri'nin sonunda bir nokta (.) İle karşılaştıktan sonra verilerin geri kalanını keser. Not: bu sadece yol değişkenini uri'nin sonunda tutarsanız olur.

Örneğin 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) {
        // ...  
    }
}

Yukarıdaki url'de firstValue = "gallery.df" ve secondValue = "link",. path değişkeni yorumlandığında kesilir.

Bu nedenle, bunu önlemek için iki olası yol vardır:

1.) Normal ifade eşlemesi kullanma

Eşlemenin son bölümünde normal ifade kullanın

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

+ İşaretini kullanarak, nokta da yol değişkeninin bir parçası olacağından sonraki herhangi bir değeri belirtiriz.

2.) @PathVariable'ımızın sonuna eğik çizgi ekleme

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

Bu, onu Spring'in varsayılan davranışından koruyan ikinci değişkenimizi kapsayacaktır.

3) Spring'in varsayılan webmvc yapılandırmasını geçersiz kılarak

Spring, @EnableWebMvc ek açıklamaları kullanılarak içe aktarılan varsayılan yapılandırmaları geçersiz kılmanın yollarını sunar . Spring MVC yapılandırmasını uygulama bağlamında kendi DefaultAnnotationHandlerMapping fasulyemizi bildirip useDefaultSuffixPattern özelliğini false olarak ayarlayarak özelleştirebiliriz . Misal:

@Configuration
public class CustomWebConfiguration extends WebMvcConfigurationSupport {

    @Bean
    public RequestMappingHandlerMapping 
      requestMappingHandlerMapping() {

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

Bu varsayılan yapılandırmayı geçersiz kılmanın tüm URL'leri etkilediğini unutmayın.

Not: Burada WebMvcConfigurationSupport sınıfını varsayılan yöntemleri geçersiz kılmak üzere genişletiyoruz. WebMvcConfigurer arabirimini uygulayarak hata yapılandırmalarını geçersiz kılmanın bir yolu daha vardır. Bu okuma hakkında daha fazla bilgi için: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/EnableWebMvc.html

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.