2011-02-15 9 views
47

Considérese el siguiente método controlador:¿Cómo evitar el enlace de parámetros desde la interpretación de comas en Spring 3.0.5?

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

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 a la versión del objeto HttpServletRequest:

String[] fqs = request.getParameterValues("fq"); 
logger.debug(fqs = " + StringUtils.join(fqs, "|")); 

imprime el resultado esperado: fqs = foo,bar. Entonces, el "problema" es con el enlace de datos de Spring.

pude pasar por la primavera de la unión y el uso de HttpServletRequest pero realmente no quieren que yo estoy usando un bean de respaldo en mi código real (lo mismo está ocurriendo) y no desea volver a implementar la funcionalidad de enlace. Espero que alguien pueda proporcionar una forma simple de prevenir este comportamiento mediante el escape o algún otro mecanismo.

TIA

ACTUALIZACIÓN: Me ha publicado esto Q en Twitter y recibió una respuesta diciendo la salida esperada aparece con la primavera 3.0.4.RELEASE. He confirmado que este es el caso y, por lo tanto, es una solución temporal. Continuaré y registraré esto como un error en el sistema Spring JIRA. Si alguien puede solucionar el problema o corregirlo con 3.0.5, aceptaré su respuesta.

+2

Conectado como error: http://jira.springsource.org/browse/SPR-7963 – nickdos

+1

Le sugiero que agregue su resolución como respuesta a su propia pregunta para que quede claro para los demás que ha encontrado una solución. –

+0

Gracias por la sugerencia Phillip. Resulta que la solución de usar 3.0.4 funciona para @RequestMapping pero NO soluciona el mismo problema cuando se vincula a un bean de respaldo de formulario. Aún no tengo una solución para mi aplicación. Todavía no tengo un comentario/actualización sobre el tema de Spring Jira, creo que es un poco flojo. – nickdos

Respuesta

29

He probado su código: es increíble, pero no puedo reproducir su problema. He descargado la última versión de la primavera (3.0.5), esta 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(), "|")); 
    } 
} 

esto 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 este es mi sencilla configuración del resorte:

<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 de mi código con el tuyo? ¿Estoy haciendo algo mal? Me gustaría ayudarlo, por lo que si tiene alguna duda o si puedo hacer otras pruebas para usted, será un placer.

ACTUALIZACIÓN/SOLUCIÓN
Con el código que he reproducido el problema; tiene la etiqueta <mvc:annotation-driven /> en la configuración del servlet de su despachador, por lo que utiliza silenciosamente un servicio de conversión predeterminado, instancia de FormattingConversionService, que contiene un convertidor predeterminado de String a String[] que utiliza la coma como separador. Debe usar un servicio de conversión diferente que contenga su propio convertidor de String a String[]. Deberías usar un separador diferente, he elegido usar ";" porque es el separador de uso común en la cadena de consulta ("first = 1; segundo = 2, en tercer lugar = 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 usted tiene que especificar este grano de servicio de conversión en su 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 comprobar si hay algún efecto secundario. Espero que no necesite en su aplicación la conversión original de String a String[] (con coma como separador). ;-)

+0

Gracias por eso. El código que pegaste es básicamente lo que estoy usando. Todavía tengo el método del controlador en mi aplicación web y simplemente lo intenté de nuevo y todavía veo el "foo | bar" en mi versión. Ahora me pregunto si tengo uno de esos problemas de dependencia extraños, ya que tengo una dependencia en un proyecto que usa una versión anterior de Spring. Haré un nuevo proyecto de primavera "desnudo" y lo probaré e informaré. – nickdos

+0

Acabo de crear una nueva aplicación web Maven (JEE 6) con soporte Spring MVC 3.0.5 (usando Netbeans). Modifiqué un poco el pom y creé dos clases según esta respuesta. Ejecuté la aplicación web en Jetty y tomcat (6.0.20) y todavía obtengo la salida fq = foo | bar (ahora tengo la salida dirigida al navegador). He puesto el código en Google Code aquí: svn checkout http://ala-hubs.googlecode.com/svn/trunk/testSpringBinding - Me encantaría llegar al fondo de esto ... – nickdos

+0

Bueno, estoy Me complace ayudarte, déjame ver tu código. Publicaré algunas noticias en unas pocas horas. – javanna

4

Como se sugiere por Philip Potter, estoy publicando la "actualización" a mi pregunta como respuesta, ya que podría haber sido fácil pasar por alto ...

Abajo-clasificación de primavera 3.0.5. RELEASE a 3.0.4.RELEASE solucionó 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 vincula a un bean form-backing, que es lo que tengo en mi aplicación web. He probado todas las versiones en 3.0.0.RELEASE y obtengo el mismo resultado (/test?fq=foo,bar produce fq = foo|bar).

E.g.

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

+0

Actualización para la posteridad: Javanna identificó correctamente el problema en la respuesta aceptada anteriormente. – nickdos

0

Es un hackeo pero, ¿ha considerado la superación de su params delimitada 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 ???

+1

Los valores de los parámetros provienen de las facetas de Solr, y aunque podría usarlas en el momento del índice para reemplazar la coma con algo_else, es demasiado esfuerzo extra para lo que es, estoy de acuerdo, un hackeo. – nickdos

3

javanna ya señaló la causa correcta. Solo quería señalar que también puede eliminar por completo el StringToArrayConverter as shown here y here.

18

he encontrado el más elegante y el camino más corto para mí - añadir @InitBinder a un @Controller:

@InitBinder 
public void initBinder(WebDataBinder binder) { 
    binder.registerCustomEditor(String[].class, new StringArrayPropertyEditor(null)); 
} 

Se convertirá cadena a String [] sin necesidad de utilizar separador (null param), con org clase de Primavera .springframework.beans.propertyeditors.StringArrayPropertyEditor. Si alguien en el mismo proyecto usará la nueva forma de conversión predeterminada, estará bien.

+0

Implementación fácil, solución perfecta para mi código, ¡gracias! –

+0

Funciona en Spring 4 también. Sin embargo, si se declaran params como List en lugar de String [], no funcionará, incluso cuando se usa List como clase. No tuve tiempo de profundizar en las partes internas de Spring para averiguar por qué y acabo de cambiar a usar String [] para mis parámetros en lugar de List . – beaudet

+0

No está claro desde el JavaDoc, pero usando 'null' como separador param no parece ser compatible. Es mejor usar un personaje real que no sea una coma. –

Cuestiones relacionadas