2011-12-04 16 views
7

Tengo un modelo de dominio que presenta una serie de "elementos", fragmentos de texto que se pueden representar para mostrar contenido enriquecido. Hay piezas de texto HTML, texto textil, objetos Flash, etc. Las características básicas de estos elementos están encapsuladas en AbstractElement, que tiene implementaciones HTMLElement, FlashElement, etc. Por lo tanto, el modelo tiene un List<AbstractElement> para contener todos los elementos que puede tener.Lista de crecimiento automático con genéricos

Al editar el modelo, deseo que el usuario pueda agregar elementos dinámicamente y guardarlos cuando el usuario envíe el formulario. Así que lo que tengo es una forma que es expandible dinámicamente con un poco de JavaScript, lo que resulta en la siguiente forma:

<form action=...> 
    <!-- Other attributes --> 
    <textarea name="object.elements[0].content"/> 
    <textarea name="object.elements[1].content"/> 
    <!-- Some elements are based on text, others on files --> 
    <input type="hidden" name="object.elements[2].file" value="somevalue"/> 
    <textarea name="object.elements[3].content"/> 
    <!-- Submit button --> 
</form> 

Esto va mal al presentar el formulario. Es bastante obvio por qué, cuando se envía, Spring intenta crear una instancia de los elementos necesarios en la lista. Como la lista de elementos contiene objetos del tipo AbstractElement que es abstracto, Spring no puede crear instancias de elementos nuevos.

¿Qué debo hacer para que Spring cree la instancia adecuada del elemento? ¿Podría agregar información de tipo en el formulario y hacer que algún ModelAttribute lo haga? ¿Cómo funcionaría eso? ¿Hay algo que pueda hacer en el modelo que lo haga automáticamente?

Respuesta

1

Terminé resolviendo esto implementando un ModelAttribute que construye la lista de elementos mediante el análisis de los datos del formulario sin formato. El análisis del formulario sin formato se puede utilizar utilizando el objeto HttpServletRequest, recorriendo el mapa de parámetros y simplemente creando los objetos necesarios 'a mano'. Es reutilizable si lo pones en una función auxiliar, aunque necesito un Atributo de modelo en cada controlador en el que lo uso.

No es la solución ideal, pero funciona.

1

Parece que necesita crear uno (o más) editores de propiedades del cliente que puedan tomar los parámetros de solicitud y convertirlos a las instancias de clase correctas para agregar a la colección.

Spring usa las instancias de PropertyEditor registradas con el enlazador de datos para vincular los parámetros de solicitud. En los casos en que el conjunto predeterminado de PropertyEditors no puede determinar el tipo correcto, puede registrar sus propios editores para manejar la lógica.

El proceso se describe en la documentación de la primavera en este enlace:

http://static.springsource.org/spring/docs/current/spring-framework-reference/html/validation.html

En concreto, véase la sección 5.4.2.1 sobre cómo registrar los editores de propiedades del cliente.

Puede registrar sus editores de propiedades utilizando el método registerCustomEditor() de la clase WebDataBinder en el método initBinder() de su controlador (identificado con la anotación @InitBinder).

+0

¿No es un PropertyEditor diseñado para procesar un solo valor de texto (como un formato de fecha) para un objeto Java? ¿Cómo agregaría parámetros de solicitud adicionales? – DCKing

+0

De su pregunta, parecía que el usuario final estaba llenando varias áreas de texto en un formulario HTML y enviándolo. Al enviarlo, pensé que querías determinar de alguna manera el tipo correcto de objeto para instanciar en función del contenido de cada área de texto. Puedes usar un PropertyEditor para convertir entre una cadena y cualquier tipo de objeto, así que pensé que funcionaría para ti. Si no estoy entendiendo el formulario correctamente, proporcione más detalles e intentaré ayudarlo. – khill

+0

Como puede ver en el formulario de ejemplo, no es seguro desde el principio que el elemento tendrá un atributo 'contenido'. Podría tener un atributo 'archivo' en su lugar. Un PropertyEditor no pudo escuchar eso. Además, los diferentes tipos de contenido basado en texto no pueden necesariamente diferenciarse en función del contenido de la cadena. – DCKing

0

Puede intentar crear instancias de formObject usted mismo creando un método ModelAttribute que devolvería el objeto concreto. p.

@ModelAttribute("bindingObj") 
public AbstractObject initElementList() { 
    AbstractObject obj = new ConcreteObject(); 
    obj.setElements(new ArrayList<ConcreteElement>); 
    return obj; 
} 

@RequestMapping(...) 
public ModelAndView requestHandler(@ModelAttribute("bindingObj") AbstractObject) { 
    .... 
} 

Spring invocaría primero initElementList y agregaría el resultado al modelMap interno. Y luego invocar requestHandler con este valor.

La desventaja de este enfoque es que todavía terminaría teniendo una referencia a la clase concreta. Pero si tiene subclases derivadas de su controlador base, entonces puede ser útil.

+0

Aunque no lo mencioné en la pregunta, sería beneficioso que la solución sea fácilmente reutilizable a través de los controladores; hay más modelos que tienen una lista de elementos. Me parece que esto es muy específico para un controlador? – DCKing

+0

Custom PropertyEditor es una opción, pero no estoy seguro de cómo podrá resolver el tipo concreto para el elemento de lista en el editor. Debido a que cada controlador sabe a qué elemento de la lista necesita vincularse, quizás el controlador sea el mejor lugar para esto. – praveenj

Cuestiones relacionadas