webentwicklung-frage-antwort-db.com.de

Spring MVC @PathVariable wird abgeschnitten

Ich habe einen Controller, der REST-gerechten Zugriff auf Informationen bietet:

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

Ich habe das Problem, dass der Server abgeschnitten wird, wenn ich eine Pfadvariable mit Sonderzeichen auf den Server trete. Zum Beispiel: http: // localhost: 8080/blah-server/blah/get/blah2010.08.19-02: 25: 47

Der Parameter blahName lautet blah2010.08

Der Aufruf von request.getRequestURI () enthält jedoch alle übergebenen Informationen.

Irgendeine Idee, wie Spring daran gehindert werden kann, die @PathVariable abzuschneiden?

132
phogel

Versuchen Sie einen regulären Ausdruck für das @RequestMapping Streit:

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

Dies hängt wahrscheinlich eng mit SPR-6164 zusammen. Kurz gesagt, das Framework versucht, einige Smarts auf die URI-Interpretation anzuwenden, wobei es das entfernt, was es für Dateierweiterungen hält. Dies hätte den Effekt, dass blah2010.08.19-02:25:47 into blah2010.08, da denkt es das .19-02:25:47 ist eine Dateierweiterung.

Wie im verlinkten Problem beschrieben, können Sie dieses Verhalten deaktivieren, indem Sie Ihre eigene DefaultAnnotationHandlerMapping-Bean im App-Kontext deklarieren und die Eigenschaft useDefaultSuffixPattern auf false setzen. Dies überschreibt das Standardverhalten und verhindert, dass Ihre Daten missbraucht werden.

55
skaffman

Spring geht davon aus, dass alles hinter dem letzten Punkt eine Dateierweiterung wie .json Oder .xml Ist, und schneidet sie ab, um Ihren Parameter abzurufen.

Wenn Sie also /{blahName} Haben:

  • /param, /param.json, /param.xml Oder /param.anything Führen zu einem Parameter mit dem Wert param
  • /param.value.json, /param.value.xml Oder /param.value.anything Ergeben einen Parameter mit dem Wert param.value

Wenn Sie Ihre Zuordnung wie vorgeschlagen in /{blahName:.+} Ändern, wird jeder Punkt, einschließlich des letzten, als Teil Ihres Parameters betrachtet:

  • /param Führt zu einem Parameter mit dem Wert param
  • /param.json Führt zu einem Parameter mit dem Wert param.json
  • /param.xml Führt zu einem Parameter mit dem Wert param.xml
  • /param.anything Führt zu einem Parameter mit dem Wert param.anything
  • /param.value.json Führt zu einem Parameter mit dem Wert param.value.json
  • ...

Wenn Sie die Erweiterungserkennung nicht interessieren, können Sie sie deaktivieren, indem Sie mvc:annotation-driven Automagic überschreiben:

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

Also nochmal, wenn Sie /{blahName} Haben:

  • /param, /param.json, /param.xml Oder /param.anything Führen zu einem Parameter mit dem Wert param
  • /param.value.json, /param.value.xml Oder /param.value.anything Ergeben einen Parameter mit dem Wert param.value

Hinweis: Der Unterschied zur Standardkonfiguration ist nur sichtbar, wenn Sie ein Mapping wie /something.{blahName} Haben. Siehe Problem mit dem Resthub-Projekt .

Wenn Sie die Erweiterungsverwaltung beibehalten möchten, können Sie seit Spring 3.2 auch die useRegisteredSuffixPatternMatch-Eigenschaft der RequestMappingHandlerMapping-Bean festlegen, um die SuffixPattern-Erkennung zu aktivieren, jedoch auf die registrierte Erweiterung zu beschränken.

Hier definieren Sie nur die Erweiterungen json und 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>

Beachten Sie, dass mvc: annotation-driven jetzt eine contentNegotiation-Option akzeptiert, um eine benutzerdefinierte Bean bereitzustellen. Die Eigenschaft von RequestMappingHandlerMapping muss jedoch in true (Standardwert false) geändert werden (vgl. https://jira.springsource.org/browse)/SPR-7632 ).

Aus diesem Grund müssen Sie immer noch die gesamte Konfiguration von mvc: annotation überschreiben. Ich habe ein Ticket für Spring geöffnet, um eine benutzerdefinierte RequestMappingHandlerMapping anzufordern: https://jira.springsource.org/browse/SPR-1125 . Bitte stimmen Sie ab, wenn Sie interessiert sind.

Berücksichtigen Sie beim Überschreiben auch das Überschreiben der benutzerdefinierten Ausführungsverwaltung. Andernfalls schlagen alle benutzerdefinierten Ausnahmezuordnungen fehl. Sie müssen messageCoverters mit einer List-Bean wiederverwenden:

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

Ich habe im Open-Source-Projekt Resthub , an dem ich beteiligt bin, eine Reihe von Tests zu diesen Themen implementiert: siehe https://github.com/resthub/resthub-spring-stack)/pull/219/files und https://github.com/resthub/resthub-spring-stack/issues/217

29
bmeurant

Alles nach dem letzten Punkt wird als Dateierweiterung interpretiert und standardmäßig abgeschnitten.
In Ihrer Spring-Konfigurations-XML können Sie DefaultAnnotationHandlerMapping hinzufügen und useDefaultSuffixPattern auf false setzen (Standard ist true).

Also öffne deinen Frühling xml mvc-config.xml (oder wie auch immer es heißt) und addieren

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

Nun ist dein @PathVariableblahName (und auch alle anderen) sollten den vollständigen Namen einschließlich aller Punkte enthalten.

BEARBEITEN: Hier ist ein Link zur Frühlings-API

15
Jan

Ich bin auch auf dasselbe Problem gestoßen, und es hat mir auch nicht geholfen, die Eigenschaft auf false zu setzen. Allerdings die API sagt :

Beachten Sie, dass Pfade, die das Suffix ".xxx" enthalten oder bereits mit "/" enden, in keinem Fall unter Verwendung des Standardsuffixmusters transformiert werden.

Ich habe versucht, meiner RESTful-URL "/ end" hinzuzufügen, und das Problem ist behoben. Ich bin nicht zufrieden mit der Lösung, aber es hat funktioniert.

Übrigens, ich weiß nicht, was die Spring-Designer gedacht haben, als sie dieses "Feature" hinzugefügt und es dann standardmäßig aktiviert haben. IMHO sollte es entfernt werden.

7
Steve11235

Verwendung der richtigen Java Konfigurationsklasse:

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

Ich habe mich durch diesen Hack entschlossen

1) HttpServletRequest in @PathVariable wie unten hinzugefügt

 @PathVariable("requestParam") String requestParam, HttpServletRequest request) throws Exception { 

2) Rufen Sie die URL direkt in der Anforderung ab (auf dieser Ebene keine Kürzung)

request.getPathInfo() 

Spring MVC @PathVariable mit Punkt (.) Wird abgeschnitten

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

Ich bin nur darauf gestoßen und die Lösungen hier haben im Allgemeinen nicht wie erwartet funktioniert.

Ich schlage vor, einen SpEL-Ausdruck und mehrere Zuordnungen zu verwenden, z.

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

das Hinzufügen von ":. +" hat bei mir funktioniert, aber erst, wenn ich die äußeren geschweiften Klammern entfernt habe.

value = {"/username/{id:.+}"} hat nicht funktioniert

value = "/username/{id:.+}" funktioniert

Hoffe ich habe jemandem geholfen:]

3
Martin Čejka

Wenn Sie die Adresse bearbeiten können, an die Anforderungen gesendet werden, besteht eine einfache Lösung darin, einen abschließenden Schrägstrich hinzuzufügen (und auch im Feld @RequestMapping Wert):

/path/{variable}/

das Mapping würde also so aussehen:

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

Siehe auch Spring MVC @PathVariable mit Punkt (.) Wird abgeschnitten .

3
Michał Rybak

Das Dateierweiterungsproblem besteht nur, wenn sich der Parameter im letzten Teil der URL befindet. Veränderung

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

zu

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

und alles wird wieder gut

3
chrismarx

Java-basierte Konfigurationslösung zum Verhindern von Kürzungen (mithilfe einer nicht veralteten Klasse):

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

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

UPDATE:

Ich habe festgestellt, dass Probleme mit der automatischen Konfiguration von Spring Boot aufgetreten sind, als ich den oben beschriebenen Ansatz verwendet habe (einige automatische Konfigurationen werden nicht wirksam).

Stattdessen habe ich begonnen, den BeanPostProcessor -Ansatz zu verwenden. Es schien besser zu funktionieren.

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

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

2
burcakulug

wenn Sie sicher sind, dass Ihr Text keiner der Standarderweiterungen entspricht, können Sie den folgenden Code verwenden:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

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

Meine bevorzugte Lösung, um zu verhindern, dass die Spring MVC @PathVariable abgeschnitten wird, ist das Hinzufügen eines abschließenden Schrägstrichs am Ende der Pfadvariablen.

Beispielsweise:

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

Die Anfrage sieht also so aus:

http://localhost:8080/api/email/[email protected]/
1
Johnny

Das Problem, mit dem Sie konfrontiert sind, ist auf die Feder Interpretation des letzten Teils zurückzuführen des Uri nach dem Punkt (.) als Dateierweiterung wie .json oder .xml. Wenn spring also versucht, die Pfadvariable aufzulösen, schneidet es den Rest der Daten einfach ab, nachdem es auf einen Punkt (.) Am Ende des URL stößt. Hinweis: Auch dies geschieht nur, wenn Sie die Pfadvariable am Ende der URL belassen.

Betrachten Sie zum Beispiel 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) {
        // ...  
    }
}

In der obigen URL firstValue = "gallery.df" und secondValue = "link" steht das letzte Bit nach dem. wird abgeschnitten, wenn die Pfadvariable interpretiert wird.

Um dies zu verhindern, gibt es zwei Möglichkeiten:

1.) Verwenden eines regulären Ausdrucks

Verwenden Sie am Ende des Mappings einen regulären Ausdruck

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

Mit + geben wir jeden Wert an, nachdem der Punkt auch Teil der Pfadvariablen ist.

2.) Hinzufügen eines Schrägstrichs am Ende unserer @PathVariable

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

Dies schließt unsere zweite Variable ein, die sie vor dem Standardverhalten von Spring schützt.

3) Durch Überschreiben der Standard-Webmvc-Konfiguration von Spring

Spring bietet Möglichkeiten zum Überschreiben der importierten Standardkonfigurationen mithilfe der Anmerkungen @ EnableWebMvc. Sie können die Spring MVC-Konfiguration anpassen, indem Sie eine eigene DefaultAnnotationHandlerMapping Bean im Anwendungskontext und Setzen seines useDefaultSuffixPattern Eigenschaft auf falsch. Beispiel:

@Configuration
public class CustomWebConfiguration extends WebMvcConfigurationSupport {

    @Bean
    public RequestMappingHandlerMapping 
      requestMappingHandlerMapping() {

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

Beachten Sie, dass das Überschreiben dieser Standardkonfiguration alle URLs betrifft.

Hinweis: Hier erweitern wir die WebMvcConfigurationSupport-Klasse, um die Standardmethoden zu überschreiben. Es gibt eine weitere Möglichkeit, die deaktivierten Konfigurationen zu überschreiben, indem Sie die WebMvcConfigurer-Schnittstelle implementieren. Weitere Informationen hierzu finden Sie unter: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/EnableWebMvc.html

0