Spring 3 MVC: um-para-muitos em um formulário dynamic (adicionar / remover em criar / atualizar)

Eu estou procurando uma solução para gerenciar uma relação um-para-muitos dentro de um formulário HTML usando jQuery . Estou desenvolvendo com Spring , Spring MVC e Hibernate . Eu encontrei muitas faixas na web, mas não em qualquer exemplo completo.

O fundo

Eu tenho três entidades JPA:

Consult.java (1)

 @Entity @Table(name = "consult") public class Consult private Integer id; private String label; private Set consultTechnos; /* getters & setters */ } 

ConsultTechno.java (2)

 @Entity @Table(name = "consult_techno") public class ConsultTechno { private Integer id; private Techno techno; private Consult consult; private String level; /* getters & setters */ } 

Techno.java (3)

 @Entity @Table(name="techno") public class Techno { private Integer id; private String label; private Set consultTechnos; /* getters & setters */ } 

Como mostrado, um Consult (1) contém n ConsultTechnos (2), que são caracterizados por um nível e um Techno (3).

As necessidades

Usando um formulário HTML, eu gostaria de ter um botão Add a techno que adiciona dinamicamente dois campos no DOM:

   

Naturalmente, cada vez que o usuário clica no botão, esses dois campos devem ser adicionados novamente, etc. Eu escolhi input type="text" para o exemplo, mas no final, os campos serão dois select .

Quatro tipos de operação devem ser cobertos:

  1. Adicionar uma entidade secundária ao criar uma nova entidade principal
  2. Remover uma entidade secundária ao criar uma nova entidade principal
  3. Adicionar uma entidade filha ao atualizar uma nova entidade principal
  4. Remover uma entidade secundária ao atualizar uma nova entidade principal

O problema

Essa parte do layout já funciona, mas ao postar o formulário, não consigo vincular os campos dinamicamente adicionados à minha @ModelAttribute consult .

Você tem alguma idéia de como fazer esse tipo de trabalho? Espero ter sido claro o suficiente …

Obrigado antecipadamente :)

Este ponto ainda é bastante confuso e pouco claro na web, então aqui está a maneira como resolvi meu problema. Essa solução provavelmente não é a mais otimizada, mas funciona ao criar e atualizar uma entidade mestre.

Teoria

  1. Use uma List vez de um Set para suas relações um-para-muitos, que devem ser gerenciadas dinamicamente.

  2. Inicialize sua List como uma AutoPopulatingList . É uma lista preguiçosa que permite adicionar elementos dinamicamente.

  3. Adicione um atributo remove of int à sua entidade filha. Isto irá desempenhar a parte de um sinalizador booleano e será útil ao remover dinamicamente um elemento.

  4. Ao postar o formulário, persista apenas os elementos que têm o sinalizador remove em 0 (ou seja, false ).

Prática

Um exemplo completo: um empregador tem muitos funcionários, um empregado tem um empregador.

Entidades:

Employer.java

 @Entity @Table(name = "employer") public class Employer private Integer id; private String firstname; private String lastname; private String company; private List employees; // one-to-many /* getters & setters */ } 

Employee.java

 @Entity @Table(name = "employee") public class Employee { private Integer id; @Transient // means "not a DB field" private Integer remove; // boolean flag private String firstname; private String lastname; private Employer employer; // many-to-one /* getters & setters */ } 

Controlador:

EmployerController.java

 @Controller @RequestMapping("employer") public class EmployerController { // Manage dynamically added or removed employees private List manageEmployees(Employer employer) { // Store the employees which shouldn't be persisted List employees2remove = new ArrayList(); if (employer.getEmployees() != null) { for (Iterator i = employer.getEmployees().iterator(); i.hasNext();) { Employee employee = i.next(); // If the remove flag is true, remove the employee from the list if (employee.getRemove() == 1) { employees2remove.add(employee); i.remove(); // Otherwise, perform the links } else { employee.setEmployer(employer); } } } return employees2remove; } // -- Creating a new employer ---------- @RequestMapping(value = "create", method = RequestMethod.GET) public String create(@ModelAttribute Employer employer, Model model) { // Should init the AutoPopulatingList return create(employer, model, true); } private String create(Employer employer, Model model, boolean init) { if (init) { // Init the AutoPopulatingList employer.setEmployees(new AutoPopulatingList(Employee.class)); } model.addAttribute("type", "create"); return "employer/edit"; } @RequestMapping(value = "create", method = RequestMethod.POST) public String create(@Valid @ModelAttribute Employer employer, BindingResult bindingResult, Model model) { if (bindingResult.hasErrors()) { // Should not re-init the AutoPopulatingList return create(employer, model, false); } // Call the private method manageEmployees(employer); // Persist the employer employerService.save(employer); return "redirect:employer/show/" + employer.getId(); } // -- Updating an existing employer ---------- @RequestMapping(value = "update/{pk}", method = RequestMethod.GET) public String update(@PathVariable Integer pk, @ModelAttribute Employer employer, Model model) { // Add your own getEmployerById(pk) model.addAttribute("type", "update"); return "employer/edit"; } @RequestMapping(value = "update/{pk}", method = RequestMethod.POST) public String update(@PathVariable Integer pk, @Valid @ModelAttribute Employer employer, BindingResult bindingResult, Model model) { // Add your own getEmployerById(pk) if (bindingResult.hasErrors()) { return update(pk, employer, model); } List employees2remove = manageEmployees(employer); // First, save the employer employerService.update(employer); // Then, delete the previously linked employees which should be now removed for (Employee employee : employees2remove) { if (employee.getId() != null) { employeeService.delete(employee); } } return "redirect:employer/show/" + employer.getId(); } // -- Show an existing employer ---------- @RequestMapping(value = "show/{pk}", method = RequestMethod.GET) public String show(@PathVariable Integer pk, @ModelAttribute Employer employer) { // Add your own getEmployerById(pk) return "employer/show"; } } 

Visão:

employer/edit.jsp

 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %><%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>   Edit            
Firstname
Lastname
company
Employees
remove

Espero que possa ajudar :)

por que você está usando tag de input HTML em vez de formulários taglib primavera

      

e crie uma class EmployeeDto como e inclua o modelMap.addAttribute("employeeDto", new Employee); no seu controlador

Bem, eu só cheguei ao problema, a fonte de exibição html não mostrará o HTML dynamic adicionado. Se você inspecionar os elementos html, a tree DOM mostrará todos os elementos dynamics adicionados, mas no formulário, se todos os elementos forem enviados ao servidor, incluindo os elementos dynamics criados também.

Uma maneira de reproduzir é ob submit, chamar o método javascript e colocar um ponto de debugging no método javascript e verificar os valores de envio do formulário nos elementos document> form inspecionando a tree DOM

Intereting Posts