web-dev-qa-db-fra.com

Spring MVC @PathVariable avec point (.) Est tronqué

Ceci est la suite de la question Spring MVC @PathVariable est tronqué

Le forum Spring indique qu'il a été corrigé (version 3.2) dans le cadre de ContentNegotiationManager. voir le lien ci-dessous.
https://jira.springsource.org/browse/SPR-6164
https://jira.springsource.org/browse/SPR-7632

Dans mon application, requestParameter avec .com est tronqué.

Quelqu'un pourrait-il m'expliquer comment utiliser cette nouvelle fonctionnalité? comment est-il configurable au format xml?

Remarque: spring forum- # 1 Spring MVC @PathVariable avec le point (.) Est tronqué

311

Autant que je sache, ce problème n'apparaît que pour la variable de chemin à la fin du requestmapping. 

Nous avons pu résoudre ce problème en définissant l'addon regex dans le requestmapping.

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

Spring considère que tout ce qui se cache derrière le dernier point est une extension de fichier telle que .json ou .xml et l'exerce pour récupérer votre paramètre.

Donc si vous avez /somepath/{variable}:

  • /somepath/param, /somepath/param.json, /somepath/param.xml ou /somepath/param.anything donnera un paramètre avec la valeur param
  • /somepath/param.value.json, /somepath/param.value.xml ou /somepath/param.value.anything donnera un paramètre avec la valeur param.value

si vous modifiez votre correspondance en /somepath/{variable:.+} comme suggéré, tout point, y compris le dernier, sera considéré comme faisant partie de votre paramètre:

  • /somepath/param donnera un paramètre avec la valeur param
  • /somepath/param.json donnera un paramètre avec la valeur param.json
  • /somepath/param.xml donnera un paramètre avec la valeur param.xml 
  • /somepath/param.anything donnera un paramètre avec la valeur param.anything
  • /somepath/param.value.json donnera un paramètre avec la valeur param.value.json
  • ...

Si vous ne vous souciez pas de la reconnaissance d’extension, vous pouvez la désactiver en remplaçant 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>

Donc, encore une fois, si vous avez /somepath/{variable}:

  • /somepath/param, /somepath/param.json, /somepath/param.xml ou /somepath/param.anything donnera un paramètre avec la valeur param
  • /somepath/param.value.json, /somepath/param.value.xml ou /somepath/param.value.anything donnera un paramètre avec la valeur param.value

remarque: la différence par rapport à la configuration par défaut n'est visible que si vous avez un mappage comme somepath/something.{variable}. voir Numéro du projet Resthub

si vous souhaitez conserver la gestion des extensions, vous pouvez également, depuis Spring 3.2, définir la propriété useRegisteredSuffixPatternMatch du bean RequestMappingHandlerMapping afin de laisser la reconnaissance suffixPattern activée, mais limitée à l'extension enregistrée.

Ici, vous définissez uniquement les extensions json et 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>

Notez que mvc: annotation-driven accepte désormais une option contentNegotiation pour fournir un bean personnalisé, mais que la propriété de RequestMappingHandlerMapping doit être remplacée par true (valeur par défaut) (cf. https://jira.springsource.org/browse/SPR -7632 ).

Pour cette raison, vous devez toujours remplacer la configuration all mvc: annotation. J'ai ouvert un ticket à Spring pour demander un RequestMappingHandlerMapping personnalisé: https://jira.springsource.org/browse/SPR-11253 . S'il vous plaît voter si vous êtes intéressé.

Bien que prioritaire, prenez soin de considérer également le dépassement personnalisé de la gestion d'exécution. Sinon, tous vos mappages d'exceptions personnalisés échoueront. Vous devrez réutiliser messageCoverters avec un bean list:

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

J'ai mis en œuvre, dans le projet open source Resthub dont je fais partie, une série de tests sur ces sujets: voir https://github.com/resthub/resthub-spring-stack/pull/219/ fichiers & https://github.com/resthub/resthub-spring-stack/issues/217

220
bmeurant

Mise à jour du printemps 4: depuis la version 4.0.1, vous pouvez utiliser PathMatchConfigurer (via votre WebMvcConfigurer), par exemple.

@Configuration
protected static class AllResources extends WebMvcConfigurerAdapter {

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

}

En XML, ce serait ( https://jira.spring.io/browse/SPR-10163 ):

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

En plus de la réponse de Martin Frey, ceci peut également être corrigé en ajoutant une barre oblique finale dans la valeur RequestMapping:

/path/{variable}/

Gardez à l'esprit que ce correctif ne prend pas en charge la maintenabilité. À présent, tous les URI doivent être précédés d'une barre oblique, ce qui peut ne pas être évident pour les utilisateurs d'API/les nouveaux développeurs. Parce que ce ne sont probablement pas tous les paramètres qui peuvent avoir un ., cela peut aussi créer des bugs intermittents

83
Michał Rybak

l'ajout du ":. +" a fonctionné pour moi, mais pas avant d'avoir supprimé les accolades extérieures.

valeur = {"/ nom d'utilisateur/{id:. +}"} n'a pas fonctionné

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

J'espère que j'ai aidé quelqu'un :)

25
Martin Čejka

Dans Spring Boot Rest Controller, j'ai résolu ces problèmes en procédant comme suit:

RestController:

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

Et du client restant:

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

/somepath/{variable:.+} fonctionne dans la balise Java requestMapping.

14
amit dahiya

Voici une approche qui repose uniquement sur la configuration 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

Un moyen assez facile de contourner ce problème consiste à ajouter une barre oblique de fin ...

par exemple.:

utilisation :

/somepath/filename.jpg/

au lieu de:

/somepath/filename.jpg
10
Marcelo C.

Dans Spring Boot, l’expression rationnelle résout le problème tel que

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

La solution complète, y compris les adresses électroniques dans les noms de chemins pour Spring 4.2, est 

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

Ajoutez ceci à l'application-xml

6
Paul Arer

Si vous utilisez Spring 3.2.x et <mvc:annotation-driven />, créez cette petite 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;
    }
}

Ensuite, mettez ceci dans votre XML MVC config:

<bean class="spring.DoNotTruncateMyUrls" />
4
Jukka

Enfin, j'ai trouvé une solution dans Spring Docs :

Pour désactiver complètement l'utilisation des extensions de fichier, vous devez définir les deux éléments suivants: 

 useSuffixPatternMatching(false), see PathMatchConfigurer

 favorPathExtension(false), see ContentNegotiationConfigurer

Ajouter ceci à mon implémentation WebMvcConfigurerAdapter a résolu le problème:

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

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

Pour moi le 

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

fonctionne, mais seulement si vous codez également le "point" dans votre URL de requête en tant que "% 2E", cela fonctionne. Mais il faut que l'URL soit ce que ... qui n'est pas un codage "standard", bien que valide. On se sent comme un bug: |

L’autre solution, similaire à la méthode "barre de fin", consiste à déplacer la variable qui aura le point "en ligne", par exemple:

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

maintenant tous les points seront préservés, aucune modification ni regex n'est nécessaire.

0
rogerdpack