sábado, 23 de marzo de 2013

Spring3 MVC tabla dinámica editable

Hola, El objetivo de esta entrada es hacer una tabla editable usando SpringMVC, de tal manera que cuando pulsemos "Aceptar" nuestra clase @Controller recoja la lista con los cambios realizados y haga las operaciones pertinentes (por ejemplo insertar sus valores en una base de datos)... Empezando por el final, este será el aspecto de la tabla a vamos a construir:

En este caso los dos primeros campos son de solo lectura y hay un tercero sobre el que permitiremos modificaciones.

Para construir la lista lo primero que necesitamos es el pojo. (las anotaciones que veis no son extrictamente necesarias para lo que nos ocupa, están relacionadas con hibernate, tema del q ya he hablado anteriormente y del q ya hablaré mas en profundidad un poco más adelante):

import static javax.persistence.GenerationType.AUTO;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name = "ParserConfiguration")
public class ParserConfiguration  implements Serializable {

 private static final long serialVersionUID = 1L;

 private int parserConfigurationId = 0; 
 
 private Parser parser;
 
 private String propertyFile;
 
 private String clave;
 
 private String value;

 private String defaultValue;

 public ParserConfiguration() {
  super();
 }
 
 @Id
 @GeneratedValue(strategy = AUTO)
 @Column(name = "ParserConfigurationId")
 public int getParserConfigurationId() {
  return parserConfigurationId;
 }

 public void setParserConfigurationId(int parserConfigurationId) {
  this.parserConfigurationId = parserConfigurationId;
 }

 @ManyToOne
 @JoinColumn(name = "ParserId")
 public Parser getParser() {
  return parser;
 }

 public void setParser(Parser parser) {
  this.parser = parser;
 }

 @Column(name = "PropertyFile")
 public String getPropertyFile() {
  return propertyFile;
 }

 public void setPropertyFile(String propertyFile) {
  this.propertyFile = propertyFile;
 }

 @Column(name = "Clave")
 public String getClave() {
  return clave;
 }

 public void setClave(String clave) {
  this.clave = clave;
 }

 @Column(name = "Value")
 public String getValue() {
  return value;
 }

 public void setValue(String value) {
  this.value = value;
 }

 @Column(name = "DefaultValue")
 public String getDefaultValue() {
  return defaultValue;
 }

 public void setDefaultValue(String defaultValue) {
  this.defaultValue = defaultValue;
 }
 

}



La primera cosa importante a tener en cuenta es que no podemos recibir un ArrayList en el @ModelAttribute que recepciona el form, asi pues crearemos una clase que las maneje:
import java.util.List;

import com.nAk.es.data.domain.ParserConfiguration;


public class ParserConfigurationForm {

 private List parserConfigurations;

 public List getParserConfigurations() {
  return parserConfigurations;
 }

 public void setParserConfigurations(
   List parserConfigurations) {
  this.parserConfigurations = parserConfigurations;
 }
 
 
}



Listo esto pasamos a mostrar como cargamos de datos en primera instancia los objetos que va a recibir el jsp de la tabla:
@Controller
@RequestMapping("/parser")
public class ParserController {


 /**
  * Inicializamos parserServbice inyectando el bean definido en la
  * Implementación de la interfaz
  * 
  * @param parserService
  */
 @Inject
 @Named("parserService")
 public ParserController(ParserService parserService) {
  this.parserService = parserService;
 }

 /**
  * Inicialización Pantalla carga_parser.jsp
  * 
  * @param model
  * @return
 @RequestMapping(value = "/{parserId}", method = RequestMethod.GET)
 public String getParserForUpdate(@PathVariable("parserId") int id,
   Model model) {
  List parserConfigurations;
  ParserConfigurationForm parserConfigurationForm = new ParserConfigurationForm();

  parser = parserService.getParserById(id);

  // Recogemos los parserConfigurations pertenecientes a ese parser
  parserConfigurations = parserService.getParserConfigurationForParser(parser);

  parserConfigurationForm.setParserConfigurations(parserConfigurations);

  model.addAttribute("parserConfigurationForm", parserConfigurationForm);

  return "parser/mantenimiento_parser";
 }



Pasamos a ver el .jsp


 
  
  
    
    
     <%--      --%>

      
Archivo Llave Valor
${status.count}

Me temo que el código se despendola un poco en el frame no se por qué :), la parte crítica es:
path="parserConfigurations[${status.index}].value"
name="pc[${status.index}].value" value="${pc.value}"
La clave de este forEach está en el parámetro "path" de la etiketa 'sf:input' que es el que encaja con los getters y setteres del objeto y el "value" que se encarga del valor de atributo, los javaScripts lo único que harán será preguntar si estas seguro para ejecutar el submit en caso afirmativo...
Paso a mostrar la recepción del formulario en la clase controller:
/**
  * 
  * @param parserConfigurationForm
  * @param bindingResult
  * @return
  */
 @RequestMapping(value = "/{pathURL}", method = RequestMethod.PUT)
 @ResponseStatus(HttpStatus.NO_CONTENT)
 public String retrieveParserConfiguration(
   @PathVariable String pathURL,
   @ModelAttribute("parserConfigurationForm") ParserConfigurationForm parserConfigurationForm,
   BindingResult bindingResult, Model model,
   HttpServletRequest request) {
  
  System.out.println("-- Array PC --" );
  System.out.println("*********");
  System.out.println("URL:: " + pathURL);
  
  List parserConfigurations = parserConfigurationForm.getParserConfigurations();

   for (ParserConfiguration parserConfiguration : parserConfigurations) {
    // Lo Grabamos::
    parserService.addParserConfiguration(parserConfiguration);
   }

  // Redireccionamos al Controller de mtos.
  return "redirect:/parser/mantenimiento_parser_c";

 }



Y listo, esto es en síntesis la chicha que hay que entender para poder hacer este tipo de formularios multi editable row. Lamento no poder compartir más código pero pertenece a un proyecto de caracter privado en el q estoy trabajando.

Las librerías de Spring e Hibernate son las propias de un proyecto de estás características y el arquetipo maven, el de un proyecto web normal.