Spring MVC @PathVariable viene troncato

Ho un controller che fornisce un accesso REST alle informazioni:

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

Il problema che sto vivendo è che se colpisco il server con una variabile di percorso con caratteri speciali, viene troncato. Ad esempio: http: // localhost: 8080 / blah-server / blah / get / blah2010.08.19-02: 25: 47

Il parametro blahName sarà blah2010.08

Tuttavia, la chiamata a request.getRequestURI () contiene tutte le informazioni passate.

Qualche idea su come impedire a Spring di troncare la variabile @PathVariable?

Prova un’espressione regolare per l’argomento @RequestMapping :

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

Questo è probabilmente strettamente correlato a SPR-6164 . In breve, il framework tenta di applicare alcune intelligenze all’interpretazione URI, rimuovendo ciò che pensa siano estensioni di file. Ciò avrebbe l’effetto di trasformare blah2010.08.19-02:25:47 in blah2010.08 , dal momento che pensa che il .19-02:25:47 sia un’estensione di file.

Come descritto nel problema collegato, è ansible disabilitare questo comportamento dichiarando il proprio bean DefaultAnnotationHandlerMapping nel contesto dell’app e impostando la proprietà useDefaultSuffixPattern su false . Ciò sostituirà il comportamento predefinito e impedirà il molesting dei dati.

Spring ritiene che qualsiasi cosa dietro l’ultimo punto sia un’estensione di file come .json o .xml e la tronca per recuperare il parametro.

Quindi se hai /{blahName} :

  • /param , /param.json , /param.xml o /param.anything risulteranno in un parametro con valore param
  • /param.value.json , /param.value.xml o /param.value.anything risulteranno in un parametro con valore param.value

Se cambi la mapping in /{blahName:.+} come suggerito, qualsiasi punto, incluso l’ultimo, sarà considerato come parte del tuo parametro:

  • /param risulterà in un parametro con valore param
  • /param.json genererà un parametro con valore param.json
  • /param.xml risulterà in un parametro con valore param.xml
  • /param.anything risulterà in un parametro con valore param.anything
  • /param.value.json genererà un parametro con valore param.value.json

Se non ti interessa il riconoscimento dell’estensione, puoi disabilitarlo mvc:annotation-driven override di mvc:annotation-driven automagic mvc:annotation-driven :

     

Quindi, di nuovo, se hai /{blahName} :

  • /param , /param.json , /param.xml o /param.anything risulteranno in un parametro con valore param
  • /param.value.json , /param.value.xml o /param.value.anything risulteranno in un parametro con valore param.value

Nota: la differenza dalla configurazione di default è visibile solo se si ha una mapping come /something.{blahName} . Vedi il problema del progetto Resthub .

Se si desidera mantenere la gestione delle estensioni, dalla spring 3.2 è anche ansible impostare la proprietà useRegisteredSuffixPatternMatch del bean RequestMappingHandlerMapping per mantenere triggersto il riconoscimento suffixPattern ma limitato all’estensione registrata.

Qui definisci solo le estensioni json e xml:

          json=application/json xml=application/xml    

Nota che mvc: annotation-driven accetta ora un’opzione contentNegotiation per fornire un bean personalizzato ma la proprietà di RequestMappingHandlerMapping deve essere cambiata in true (default false) (vedere https://jira.springsource.org/browse/SPR-7632 ).

Per questo motivo, devi comunque eseguire l’override di tutte le configurazioni di mvc: annotation-driven. Ho aperto un biglietto per Spring per richiedere un Custom RequestMappingHandlerMapping: https://jira.springsource.org/browse/SPR-11253 . Si prega di votare se siete interessati a.

Mentre si esegue l’override, fare attenzione a considerare anche l’esecuzione prioritaria della gestione Esecuzione personalizzata. In caso contrario, tutti i mapping delle eccezioni personalizzati avranno esito negativo. Dovrai riutilizzare messageCoverters con un bean di elenco:

                            

Ho implementato, nel progetto open source Resthub di cui faccio parte, una serie di test su questi argomenti: vedere https://github.com/resthub/resthub-spring-stack/pull/219/files e https: // github.com/resthub/resthub-spring-stack/issues/217

Tutto dopo l’ultimo punto viene interpretato come estensione del file e tagliato per impostazione predefinita.
Nel tuo xml di configurazione spring puoi aggiungere DefaultAnnotationHandlerMapping e impostare useDefaultSuffixPattern su false (l’impostazione predefinita è true ).

Quindi apri la tua molla xml mvc-config.xml (o comunque viene chiamata) e aggiungi

    

Ora il tuo @PathVariable blahName (e anche tutti gli altri) dovrebbe contenere il nome completo compresi tutti i punti.

EDIT: Ecco un link alla api spring

Ho anche avuto lo stesso problema, e l’impostazione della proprietà su false non mi è stata d’aiuto. Tuttavia, l’API dice :

Tieni presente che i percorsi che includono un suffisso “.xxx” o che terminano con “/” non verranno mai trasformati utilizzando il modello di suffisso predefinito in ogni caso.

Ho provato ad aggiungere “/ end” al mio URL RESTful e il problema è andato via. Non sono per favore con la soluzione, ma ha funzionato.

A proposito, non so cosa stessero pensando i designer di Spring quando hanno aggiunto questa “funzionalità” e quindi l’abbiamo triggersta per impostazione predefinita. IMHO, dovrebbe essere rimosso.

Utilizzando la class di configurazione Java corretta:

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

Ho risolto con questo trucco

1) Aggiunto HttpServletRequest in @PathVariable come sotto

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

2) Ottieni direttamente l’URL (a questo livello nessun troncamento) nella richiesta

 request.getPathInfo() 

Spring MVC @PathVariable con punto (.) Viene troncato

Mi sono imbattuto in questo e le soluzioni qui in generale non funzionano come mi aspettavo.

Suggerisco di usare un’espressione SpEL e più mappature, ad es

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

Il problema dell’estensione del file esiste solo se il parametro si trova nell’ultima parte dell’URL. Modificare

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

a

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

e tutto andrà bene di nuovo-

Se è ansible modificare l’indirizzo a cui vengono inviate le richieste, la soluzione semplice sarebbe aggiungere una barra finale a loro (e anche nel valore @RequestMapping ):

 /path/{variable}/ 

quindi la mapping sarebbe simile a:

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

Vedi anche Spring MVC @PathVariable con punto (.) Che viene troncato .

 //in your xml dispatcher add this property to your default annotation mapper bean as follow    

aggiungendo il “:. +” ha funzionato per me, ma non prima di aver rimosso parentesi graffe esterne.

value = {"/username/{id:.+}"} non ha funzionato

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

Spero di aver aiutato qualcuno:]

Soluzione di configurazione basata su Java per prevenire il troncamento (utilizzando una class non deprecata):

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

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

AGGIORNARE:

Mi sono reso conto di avere alcuni problemi con la configurazione automatica di Spring Boot quando ho usato l’approccio sopra (alcune auto-configurazione non diventano efficaci).

Invece, ho iniziato a utilizzare l’approccio BeanPostProcessor . Sembrava funzionare meglio.

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

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

se sei sicuro che il tuo testo non corrisponderà a nessuna delle estensioni predefinite, puoi utilizzare il seguente codice:

 @Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { @Override public void configurePathMatch(PathMatchConfigurer configurer) { configurer.setUseRegisteredSuffixPatternMatch(true); } } 

La mia soluzione preferibile per evitare che Spring MVC @PathVariable venga troncata consiste nell’aggiungere la barra finale alla fine della variabile path.

Per esempio:

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

Quindi, la richiesta sarà simile a:

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