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

  1. /test?fq=foo resultados en fq = foo
  2. /test?fq=foo&fq=bar resultados en fq = foo|bar
  3. /test?fq=foo,bar resultados en fq = foo|bar
  4. /test?fq=foo,bar&fq=bash resultados en fq = foo,bar|bash
  5. /test?fq=foo,bar&fq= resultados en fq = 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.

Author: javanna, 2011-02-15

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

 29
Author: javanna,
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.

 19
Author: TachikomaGT,
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.

 4
Author: nickdos,
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í.

 3
Author: Rossen Stoyanchev,
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 ???

 0
Author: Sumit,
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