¿Cómo evitar que el enlace de parámetros interprete comas en Spring 3.0.5?
Considere el siguiente método de controlador:
@RequestMapping(value = "/test", method = RequestMethod.GET)
public void test(@RequestParam(value = "fq", required = false) String[] filterQuery) {
logger.debug(fq = " + StringUtils.join(filterQuery, "|"));
}
Aquí está la salida para diferentes fq
combinaciones:
-
/test?fq=foo
resultados enfq = foo
-
/test?fq=foo&fq=bar
resultados enfq = foo|bar
-
/test?fq=foo,bar
resultados enfq = foo|bar
-
/test?fq=foo,bar&fq=bash
resultados enfq = foo,bar|bash
-
/test?fq=foo,bar&fq=
resultados enfq = foo,bar|
El ejemplo 3 es el problema. Espero (quiero/necesito) que salga fq = foo,bar
.
He intentado escapar de la coma con \
y usando %3C
pero niether trabajo.
Si miro la versión del objeto HttpServletRequest
:
String[] fqs = request.getParameterValues("fq");
logger.debug(fqs = " + StringUtils.join(fqs, "|"));
Imprime la salida esperada: fqs = foo,bar
. Así que el "problema" es con el enlace de datos de primavera.
Podría pasar por alto el enlace de Spring y usar HttpServletRequest
pero realmente no quiero, ya que estoy usando un bean de respaldo en mi código real (lo mismo está sucediendo) y no deseo volver a implementar la funcionalidad de enlace. Espero que alguien pueda proporcionar una manera simple de prevenir este comportamiento a través de escapar o algún otro mecanismo.
TIA
ACTUALIZACIÓN: Publiqué esta Q en Twitter y recibí una respuesta diciendo la salida esperada aparece con Spring 3.0.4.RELEASE . Ahora he confirmado que este es el caso y por lo tanto es una solución temporal. Seguiré adelante y registraré esto como un error en el sistema Spring JIRA. Si alguien puede proporcionar una solución o solución con 3.0.5, aceptaré su respuesta.
5 answers
He probado tu código: es increíble, pero no puedo reproducir tu problema. He descargado la última versión de spring (3.0.5), este es mi controlador:
package test;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("/test/**")
public class MyController {
private static final Logger logger = Logger.getLogger(MyController.class);
@RequestMapping(value = "/test/params", method = RequestMethod.GET)
public void test(SearchRequestParams requestParams, BindingResult result) {
logger.debug("fq = " + StringUtils.join(requestParams.getFq(), "|"));
}
}
Esta es mi clase SearchRequestParams:
package test;
public class SearchRequestParams {
private String[] fq;
public String[] getFq() {
return fq;
}
public void setFq(String[] fq) {
this.fq = fq;
}
}
Y esta es mi configuración de resorte simple: {[16]]}
<bean id="urlMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="test.MyController" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
He probado mi código dentro de tomcat 7.0.8; cuando escribo http://localhost:8080/testweb/test/params.htm?fq=foo,bar
puedo leer en mi archivo de registro esta línea: DEBUG fq = foo,bar
.
¿Cuáles son las diferencias entre mi código y el tuyo? Estoy haciendo algo mal?
Yo me gusta ayudarte, así que si tienes alguna duda o si puedo hacer algunas otras pruebas para ti, será un placer.
ACTUALIZACIÓN / SOLUCIÓN
Con su código he reproducido el problema; tiene la etiqueta <mvc:annotation-driven />
en su configuración de servlet de dispatcher, por lo que utiliza silenciosamente un servicio de conversión predeterminado, instancia de FormattingConversionService
, que contiene un convertidor predeterminado de String
a String[]
que usa coma como separador.
Tienes que usar un bean de servicio de conversión diferente que contenga el tuyo propio convertidor de String
a String[]
. Debe usar un separador diferente, he elegido usar"; "porque es el separador comúnmente utilizado en la cadena de consulta ("?first = 1; second = 2; third=3"):
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.StringUtils;
public class CustomStringToArrayConverter implements Converter<String, String[]>{
@Override
public String[] convert(String source) {
return StringUtils.delimitedListToStringArray(source, ";");
}
}
Entonces tienes que especificar este servicio de conversión bean en tu configuración:
<mvc:annotation-driven conversion-service="conversionService" />
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="au.org.ala.testspringbinding.CustomStringToArrayConverter" />
</list>
</property>
</bean>
El problema se ha solucionado, ahora debe verificar si hay efectos secundarios. Espero que no necesite en su aplicación la conversión original de String
a String[]
(con coma como separador). ;-)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-19 23:50:16
He encontrado el camino más elegante y más corto para mí-añadir @InitBinder
a un @Controller
:
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String[].class, new StringArrayPropertyEditor(null));
}
Convertirá String a String [] sin usar separator (null
param), con la clase Spring org.springframework.frijol.editores de la propiedad.StringArrayPropertyEditor.
Si alguien en el mismo proyecto usará una nueva forma de conversión predeterminada, estará bien.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-04 12:26:47
Como sugirió Philip Potter, estoy publicando la "actualización" a mi pregunta como respuesta, ya que podría haber sido fácil de perder...
Reducción a partir de la primavera 3.0.5.VERSIÓN 3.0.4.RELEASE solucionado el problema, al usar la anotación @RequestParam
, sugiriendo que es un error con 3.0.5.
Sin embargo, no soluciona el problema relacionado con , cuando se enlaza a un bean de respaldo de formulario, que es lo que tengo en mi aplicación web. He probado todas las versiones de nuevo a 3.0.0.LIBERAR y obtener lo mismo resultado (/test?fq=foo,bar
produce fq = foo|bar
).
Por ejemplo
@RequestMapping(value = "/test", method = RequestMethod.GET)
public void test(SearchRequestParams requestParams, BindingResult result) {
logger.debug("fq = " + StringUtils.join(requestParams.getFq(), "|"));
}
Donde SearchRequestParams
contiene un campo String[] fq
.
Si alguien tiene una solución para esto, con mucho gusto aceptaré su respuesta.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-06 22:52:42
Javanna ya señaló la causa raíz correcta. Solo quería señalar que también puede eliminar el StringToArrayConverter por completo como se muestra aquí y aquí.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-20 21:20:11
Es un truco, pero, ¿has considerado pasar tus parámetros delimitados con ' - '
/test?fq=foo-bar results in fq = foo-bar
/test?fq=foo-bar&fq=bash results in fq = foo-bar|bash
O cualquier otro delimitador tal vez ~ o !o ^ o ???
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-07 05:36:06