java - ejemplo - Spring MVC @PathVariable queda truncado
@requestmapping ejemplo (15)
El problema de extensión de archivo solo existe si el parámetro está en la última parte de la URL. Cambio
@RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}")
a
@RequestMapping(
method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}/safe")
y todo estará bien de nuevo-
Tengo un controlador que proporciona acceso RESTful a la información:
@RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}")
public ModelAndView getBlah(@PathVariable String blahName, HttpServletRequest request,
HttpServletResponse response) {
El problema que estoy experimentando es que si presiono el servidor con una variable de ruta con caracteres especiales, se trunca. Por ejemplo: http://localhost:8080/blah-server/blah/get/blah2010.08.19-02:25:47
El parámetro blahName será blah2010.08
Sin embargo, la llamada a request.getRequestURI () contiene toda la información pasada.
¿Alguna idea de cómo evitar que Spring trunque el @PathVariable?
Esto probablemente esté estrechamente relacionado con SPR-6164 . En pocas palabras, el marco trata de aplicar cierta inteligencia a la interpretación de URI, eliminando lo que cree que son extensiones de archivo. Esto tendría el efecto de convertir blah2010.08.19-02:25:47
en blah2010.08
, ya que cree que el .19-02:25:47
es una extensión de archivo.
Como se describe en el problema vinculado, puede deshabilitar este comportamiento declarando su propio bean DefaultAnnotationHandlerMapping
en el contexto de la aplicación y estableciendo su propiedad useDefaultSuffixPattern
en false
. Esto anulará el comportamiento predeterminado y evitará que moleste sus datos.
Me encontré con esto y las soluciones aquí en general no funcionaron como esperaba.
Sugiero usar una expresión SpEL y mapeos múltiples, por ej.
@RequestMapping(method = RequestMethod.GET,
value = {Routes.BLAH_GET + "/{blahName:.+}",
Routes.BLAH_GET + "/{blahName}/"})
Mi solución preferible para evitar que Spring MVC @PathVariable se trunque es agregar una barra al final de la variable de ruta.
Por ejemplo:
@RequestMapping(value ="/email/{email}/")
Entonces, la solicitud se verá así:
http://localhost:8080/api/email/[email protected]/
Pruebe una expresión regular para el argumento @RequestMapping
:
RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName:.+}")
Resolví por este truco
1) Se agregó HttpServletRequest en @PathVariable como a continuación
@PathVariable("requestParam") String requestParam, HttpServletRequest request) throws Exception {
2) Obtener la URL directamente (en este nivel sin truncamiento) en la solicitud
request.getPathInfo()
Si puede editar la dirección a la que se envían las solicitudes, una solución simple sería agregarle una barra diagonal (y también en el valor de @RequestMapping
):
/path/{variable}/
para que el mapeo se vea así:
RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}/")
Consulte también Spring MVC @PathVariable con punto (.) Se trunca .
Solución de configuración basada en Java para evitar el truncamiento (utilizando una clase no desaprobada):
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;
}
}
ACTUALIZAR:
Me di cuenta de que tenía algunos problemas con la autoconfiguración de Spring Boot cuando usaba el método anterior (algunos autoconfiguración no se hacen efectivos).
En cambio, comencé a utilizar el enfoque BeanPostProcessor
. Parecía estar funcionando mejor.
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);
}
}
Inspirado en: http://ronaldxq.blogspot.com/2014/10/spring-mvc-setting-alwaysusefullpath-on.html
Spring considera que cualquier cosa detrás del último punto es una extensión de archivo como .json
o .xml
y .json
para recuperar su parámetro.
Entonces, si tienes /{blahName}
:
-
/param
,/param.json
,/param.xml
o/param.anything
dará como resultado un parámetro con valorparam
-
/param.value.json
,/param.value.xml
o/param.value.anything
dará como resultado unparam.value
con el valorparam.value
Si cambia su asignación a /{blahName:.+}
como se sugiere, cualquier punto, incluido el último, se considerará como parte de su parámetro:
-
/param
dará como resultado un param con valorparam
-
/param.json
dará como resultado unparam.json
con valorparam.json
-
/param.xml
generará unparam.xml
con el valorparam.xml
-
/param.anything
dará como resultado un param con valorparam.anything
-
/param.value.json
dará como resultado unparam.value.json
con el valorparam.value.json
- ...
Si no le importa el reconocimiento de extensiones, puede deshabilitarlo anulando mvc:annotation-driven
:
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="contentNegotiationManager" ref="contentNegotiationManager"/>
<property name="useSuffixPatternMatch" value="false"/>
</bean>
Entonces, nuevamente, si tienes /{blahName}
:
-
/param
,/param.json
,/param.xml
o/param.anything
dará como resultado un parámetro con valorparam
-
/param.value.json
,/param.value.xml
o/param.value.anything
dará como resultado unparam.value
con el valorparam.value
Nota: la diferencia con la configuración predeterminada solo está visible si tiene una asignación como / /something.{blahName}
. /something.{blahName}
. Ver el problema del proyecto Resthub .
Si desea mantener la administración de extensiones, desde Spring 3.2 también puede establecer la propiedad useRegisteredSuffixPatternMatch de RequestMappingHandlerMapping bean para mantener activado el reconocimiento de sufijosPattern pero limitado a la extensión registrada.
Aquí solo defines las extensiones json y 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>
Tenga en cuenta que mvc: annotation-driven acepta ahora una opción contentNegotiation para proporcionar un bean personalizado, pero la propiedad de RequestMappingHandlerMapping debe cambiarse a true (valor predeterminado falso) (consulte https://jira.springsource.org/browse/SPR-7632 ). )
Por esa razón, todavía tiene que anular toda la configuración de mvc: anotación. Abrí un boleto a Spring para pedir un CustomMappingHandlerMapping personalizado: https://jira.springsource.org/browse/SPR-11253 . Por favor vote si le interesa.
Al anular, tenga cuidado de considerar también la anulación de la administración de Ejecución personalizada. De lo contrario, todas las asignaciones de excepciones personalizadas fallarán. Tendrá que volver a utilizar messageCoverters con 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>
Implementé, en el proyecto de código abierto Resthub que Resthub parte, un conjunto de pruebas sobre estos temas: ver https://github.com/resthub/resthub-spring-stack/pull/219/files y https: // github.com/resthub/resthub-spring-stack/issues/217
También me encontré con el mismo problema, y establecer la propiedad en falso tampoco me ayudó. Sin embargo, la API dice :
Tenga en cuenta que las rutas que incluyen un sufijo ".xxx" o terminan con "/" ya no se transformarán con el patrón de sufijo predeterminado en ningún caso.
Intenté agregar "/ end" a mi URL RESTful, y el problema desapareció. No estoy satisfecho con la solución, pero funcionó.
Por cierto, no sé en qué pensaban los diseñadores de Spring cuando agregaron esta "característica" y luego la activaron por defecto. En mi humilde opinión, debería ser eliminado.
Todo después del último punto se interpreta como extensión de archivo y se corta por defecto.
En su configuración de primavera xml puede agregar DefaultAnnotationHandlerMapping
y establecer useDefaultSuffixPattern
en false
(el valor predeterminado es true
).
Así que abra su mvc-config.xml
xml de primavera (o como se llame) y agregue
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="useDefaultSuffixPattern" value="false" />
</bean>
Ahora su @PathVariable
blahName
(y todos los demás, también) debe contener el nombre completo incluyendo todos los puntos.
EDITAR: Aquí hay un enlace a la API de primavera
Usando la clase correcta de configuración de 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);
}
}
agregar el ":. +" funcionó para mí, pero no hasta que eliminé las llaves externas.
value = {"/username/{id:.+}"}
no funcionó
value = "/username/{id:.+}"
funciona
Espero haber ayudado a alguien:]
si está seguro de que su texto no coincidirá con ninguna de las extensiones predeterminadas, puede usar el siguiente código:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseRegisteredSuffixPatternMatch(true);
}
}
//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>