1

I have two entities Environnment and ServeurApplicatif that have a oneToMany relationship. I have a dynamic form with a button to add a new form each time a user wants to associate a ServeurApplicatif to on Environnement entity.When submitting the expected result is the persistence of both the environnement Entity and the ServeurApplicatif entities associated with it.

However in my case i get a 400 http error : your request is synthatically incorrect, whenever i try to submit the form.

here is the javascript code that adds the child entity related form dynamically :

<script type="text/javascript">
$(document).ready(function() {

    var index = ${fn:length(env.serveurApplicatifs)};
    console.log("index value :"+index);
    $("#addServ").off("click").on("click",function() {
        $(this).before(function() {

      var html = '<div id="serveurApplicatifs'+index+'.wrapper" style="display: none;">';
      html += '<input type="hidden" id="serveurApplicatifs'+index+'.idserv" name="serveurApplicatifs['+index+'].idserv" ></input>';                    
              html += '<p><strong>Serveur Applicatif 1 : </strong></p>';
              html += '<div class="form-group"><label for="serveurApplicatifs'+index+'.port">Port :</label><input class ="form-control" type="text" id="serveurApplicatifs'+index+'.port" name="serveurApplicatifs['+index+'].port" ></input></div>';
              html += '<div class="form-group"><label for="serveurApplicatifs'+index+'.compte">Compte :</label><input class ="form-control" type="text" id="serveurApplicatifs'+index+'.compte" name="serveurApplicatifs['+index+'].compte" ></input></div>';
              html += '<div class="form-group"><label for="serveurApplicatifs'+index+'.pwd">Mot de passe :</label><input class ="form-control" type="text" id="serveurApplicatifs'+index+'.pwd" name="serveurApplicatifs['+index+'].pwd" ></input></div>';
              html += '<div class="form-group"><label for="serveurApplicatifs'+index+'.adresse">Adresse :</label><input class ="form-control" type="text" id="serveurApplicatifs'+index+'.adresse" name="serveurApplicatifs['+index+'].adresse" ></input></div>';
              html += '<a href="#" class="serveurApplicatifs.remove" data-index="'+index+'">Supprimer</a>';                    
              html += "</div>";
              return html;
            });
        $("#serveurApplicatifs"+index+"\\.wrapper").show();
        index++;
          return false; 
        });

        $("a.serveurApplicatifs.remove").off("click").on("click",function() {
            var index2remove = $(this).data("index");
            $("#serveurApplicatifs"+index2remove+"\\.wrapper").hide();
            $("#serveurApplicatifs"+index2remove+"\\.remove").val("1");
            return false;
            }) 

the Spring form tags in the jsp :

<c:url value="/envs/save" var="saveUrl"/>
    <form:form action="${ saveUrl }" method="POST" modelAttribute="env">
      <div class="form-group">
      <form:input type="hidden" class="form-control" id="idEnv" placeholder="id" path="idEnv"></form:input><span id="star">*</span>
    </div>
    <!-- ------------- -->
    <div class="form-group">
      <label for="nom">Nom</label>
      <form:input type="text" class="form-control" id="nom" placeholder="Nom" path="nom"></form:input><span>*</span>
        <form:errors path="nom" cssClass="error"></form:errors>
    </div>
  <div class="form-group">
      <label for="plateforme">Platforme</label>
      <form:input type="text" class="form-control" id="plateform" placeholder="Plateforme" path="platforme"></form:input>
    <form:errors path="platforme" cssClass="error"></form:errors>
  </div>
    <div class="form-group">
      <label for="typologie">Typologie</label>
      <form:input type="text" class="form-control" id="typologie" placeholder="Typologie" path="typologie"></form:input>
      <form:errors path="typologie" cssClass="error"></form:errors>

    </div>
    <div class="form-group">
      <label for="bd">Base de donnée</label>
      <form:input type="text" class="form-control" id="bd" placeholder="Bdd" path="bd"></form:input>
      <form:errors path="bd" cssClass="error"></form:errors>  
    </div>

    <div class="form-group">
      <label for="version">Version</label>
      <form:input type="text" class="form-control" id="version" placeholder="Version" path="version"></form:input>
      <form:errors path="version" cssClass="error"></form:errors>

    </div>
    <div class="form-group">
      <label for="machine_bd">Serveur de base de données</label>
      <form:input type="text" class="form-control" id="machine_bd" placeholder="Machine Bdd" path="machineBd"></form:input>
      <form:errors path="machineBd" cssClass="error"></form:errors>

    </div>
    <div class="form-group">
      <label for="port_bd">Port Base de données</label>
      <form:input type="text" class="form-control" id="port_bd" placeholder="Port bdd" path="portBd"></form:input>
      <form:errors path="portBd" cssClass="error"></form:errors>

    </div>
    <div class="form-group">
      <label for="version_bd">Version de base de données</label>
      <form:input type="text" class="form-control" id="version_bd" placeholder="Version bdd" path="versionBd"></form:input>
      <form:errors path="versionBd" cssClass="error"></form:errors>

    </div>
    <div class="form-group">
      <label for="type_bd">Type de base de données</label>
      <form:input type="text" class="form-control" id="type_bd" placeholder="Type bdd" path="typeBd"></form:input>
      <form:errors path="typeBd" cssClass="error"></form:errors>

    </div>
<div class="form-group">
      <label for="depart">Environnement de départ</label>
      <form:radiobutton  value ="1" id="depart" path="depart" label="Oui"></form:radiobutton>
      <form:radiobutton   value ="0" id="depart" path="depart" label="Non"></form:radiobutton>
      <form:errors path="depart" cssClass="error"></form:errors>

    </div>
    <div class="form-group">
      <label for="repert">Repert</label>
      <form:input type="text" class="form-control" id="repert" placeholder="Repert" path="repert"></form:input>
      <form:errors path="repert" cssClass="error"></form:errors>

    </div>
    <div class="form-group">
      <label for="port_ftp">Port FTP</label>
      <form:input type="text" class="form-control" id="port_ftp" placeholder="Port FTP" path="portFtp"></form:input>
      <form:errors path="portFtp" cssClass="error"></form:errors>

    </div>
    <div class="form-group">
      <label for="exclu">Exclu</label>
      <form:radiobutton  value ="1" id="exclu" path="exclu" label="Oui"></form:radiobutton>
      <form:radiobutton   value ="0" id="exclu" path="exclu" label="Non"></form:radiobutton>
      <form:errors path="exclu" cssClass="error"></form:errors>

    </div>
    <div class="form-group">
      <label for="envsPrec">Précedent</label>
        <form:select class="form-control" id="envsPrec" path="environnements2" items="${ envsPrecSuiv }" itemLabel="nom" itemValue="idEnv"/>
      <form:errors path="environnements2" cssClass="error"></form:errors>   
    </div>
    <div class="form-group">
      <label for="envsSuiv">Suivant</label>
        <form:select class="form-control" id="envsSuiv" path="environnements1" items="${ envsPrecSuiv }" itemLabel="nom" itemValue="idEnv"/>
      <form:errors path="environnements1" cssClass="error"></form:errors>   
    </div>
    <c:forEach varStatus="loop" var="serveurApplicatifs" items="${ env.serveurApplicatifs }">
        <c:choose>
        <c:when test="${env.serveurApplicatifs[loop.index].remove eq 1 }">
          <div id="serveurApplicatifs${loop.index }.wrapper" style="display: none;">
        </c:when>
        <c:otherwise>
          <div id="serveurApplicatifs${ loop.index }.wrapper">
        </c:otherwise>
      </c:choose> 
      <div class="form-group">
          <form:input type="hidden" class="form-control" id="idApp" path="env.serveurApplicatifs[${loop.index}].idserv"></form:input>
        </div>
      <div class="form-group">
          <label for="portApp">Port serveur applicatif</label>
          <form:input type="text" class="form-control" id="portApp" placeholder="Port" path="env.serveurApplicatifs[${loop.index}].port"></form:input>
        </div>
        <div class="form-group">
          <label for="compteApp">Compte serveur applicatif</label>
          <form:input type="text" class="form-control" id="compteApp" placeholder="Compte" path="env.serveurApplicatifs[${loop.index}].compte"></form:input>
        </div>
        <div class="form-group">
          <label for="pwdApp">Mot de passe serveur applicatif</label>
          <form:input type="text" class="form-control" id="pwdApp" placeholder="Mot de passe" path="env.serveurApplicatifs[${loop.index}].pwd"></form:input>
        </div>
        <div class="form-group">
          <label for="adresseApp">Adresse serveur applicatif</label>
          <form:input type="text" class="form-control" id="adresseApp" placeholder="Adresse" path="env.serveurApplicatifs[${loop.index}].adresse"></form:input>
        </div>
        <c:choose>
          <c:when test="${serveurApplicatifs[loop.index].remove eq 1}"><c:set var="hiddenValue" value="1"></c:set></c:when>
          <c:otherwise><c:set var="hiddenValue" value="0"></c:set> </c:otherwise>
        </c:choose>
        <form:hidden path="serveurApplicatifs[${loop.index}].remove" value="${hiddenValue}"/>
        <a href="#" class="serveurApplicatifs.remove" data-index="${loop.index}">Supprimer</a>
     </div>
</c:forEach>
    <button type="button" class="btn btn-default" id="addServ">Ajouter Un Serveur d'application</button>
    <button type="submit" class="btn btn-default" value="Save">Submit</button>

</form:form>

The Environnement entity class :

@Entity
@NamedQuery(name="Environnement.findAll", query="SELECT e FROM Environnement e")
public class Environnement implements Serializable {
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id_env")
private int idEnv;

private String bd;

private int depart;

private int exclu;

@Column(name="machine_bd")
private String machineBd;

@Column(name="mdp_bdd")
private String mdpBdd;

private String nom;

private String platforme;

@Column(name="port_bd")
private int portBd;

@Column(name="port_ftp")
private int portFtp;

private String repert;

@Column(name="type_bd")
private String typeBd;

private String typologie;

@Column(name="utilisateur_bdd")
private String utilisateurBdd;

private String version;

@Column(name="version_bd")
private String versionBd;

//bi-directional many-to-many association to Composant
@ManyToMany
@JoinTable(
    name="env_comp"
    , joinColumns={
        @JoinColumn(name="id_env")
        }
    , inverseJoinColumns={
        @JoinColumn(name="id_comp")
        }
    )
private List<Composant> composants;

//bi-directional many-to-many association to Environnement
@LazyCollection(LazyCollectionOption.FALSE)
@ManyToMany
@JoinTable(
    name="lien_environnement"
    , joinColumns={
        @JoinColumn(name="id_env_suiv")
        }
    , inverseJoinColumns={
        @JoinColumn(name="id_env_prec")
        }
    )
private List<Environnement> environnements1;

//bi-directional many-to-many association to Environnement
@LazyCollection(LazyCollectionOption.FALSE)
@ManyToMany
@JoinTable(
        name="lien_environnement"
        , joinColumns={
            @JoinColumn(name="id_env_prec")
            }
        , inverseJoinColumns={
            @JoinColumn(name="id_env_suiv")
            }
        )
private List<Environnement> environnements2;

//bi-directional many-to-one association to ServeurApplicatif
@LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(mappedBy="environnement")
private List<ServeurApplicatif> serveurApplicatifs;

the ServeurApplicatif entity class :

@Entity
@Table(name="serveur_applicatif")
@NamedQuery(name="ServeurApplicatif.findAll", query="SELECT s FROM ServeurApplicatif s")
public class ServeurApplicatif implements Serializable {
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int idserv;

private String adresse;

private String compte;

private int port;

private String pwd;

@Transient
private Integer remove;

//bi-directional many-to-one association to Environnement
@ManyToOne
@JoinColumn(name="id_env")
private Environnement environnement;

Controller Method used to persist the entities :

    @RequestMapping(value="/envs/save",method=RequestMethod.POST)
public ModelAndView saveEnvironnement(@ModelAttribute(value="env")Environnement env) {

    //Environnement envFinal = this.envService.validate(env);

    this.envService.gererServeur(env);

    /*for (ServeurApplicatif servApp : env.getServeurApplicatifs()) {

    }*/

    envService.saveOrUpdate(env);
    for (ServeurApplicatif servApp : env.getServeurApplicatifs()) {
        servAppService.saveOrUpdate(servApp);
    }
    return new ModelAndView("redirect:/envs");

}

gererServeur method in EnvironnementService classe :

@Override
public List<ServeurApplicatif> gererServeur(Environnement env) {
    // TODO Auto-generated method stub
    List<ServeurApplicatif> serveurRemoved = new ArrayList<ServeurApplicatif>();
    if(env.getServeurApplicatifs() != null) {
        for (Iterator<ServeurApplicatif> iterator = serveurRemoved.iterator(); iterator
                .hasNext();) {
            ServeurApplicatif serveurApplicatif = iterator.next();
            if(serveurApplicatif.getRemove() == 1) {
                serveurRemoved.add(serveurApplicatif);
                iterator.remove();
            }
            else {
                serveurApplicatif.setEnvironnement(env);
            }

        }
    }
    return serveurRemoved;
}   

Note that i'm using the solution shown here to manage the dynamic form : Spring 3 MVC: one-to-many within a dynamic form (add/remove on create/update)

Edit :

i tried declaring the line var index = ${fn:length(env.serveurApplicatifs)}; outside of the document ready function but it didn't help, the console.log returns 0 when loading the form but gets incremented each time i clic the button to add a new form for ServeurApplicatif,the form data sent to the server is as follows :

idEnv:0
nom:
platforme:
typologie:
bd:
version:
machineBd:
portBd:0
versionBd:
typeBd:
depart:0
repert:
portFtp:0
exclu:0
_environnements2:1
_environnements1:1
serveurApplicatifs[0].idserv:
serveurApplicatifs[0].port:14523
serveurApplicatifs[0].compte:test
serveurApplicatifs[0].pwd:test
serveurApplicatifs[0].adresse:test
serveurApplicatifs[1].idserv:
serveurApplicatifs[1].port:14523
serveurApplicatifs[1].compte:test
serveurApplicatifs[1].pwd:test
serveurApplicatifs[1].adresse:test
_csrf:2d856fad-16f3-4ae4-a254-47922a695c17

you will notice that the idserv doesn't get automatically populated unlike idenv. both of these IDs are auto-increment fields in the DB, the other blank fields are nullable so the problem isn't there.

Thanks in advance.

Community
  • 1
  • 1
Pedro
  • 43
  • 1
  • 10
  • I have done that and the parameters sent to the server appear to be correct, however the ServeurApplicatif id field remains blank and doesn't get generated automatically when submitting unlike the Environnement id which is sent correclty. – Pedro May 26 '15 at 14:57

1 Answers1

0

I found what was wrong.

Basically the idserv wasn't getting the default value of 0 so that spring can handle the request to the server and hibernate can insert the ServeurApplicatif entity alongside the Environnment entity when saveOrUpdate is invoked, so i added a value="0" to the javascript code responsible for creating form inputs for ServeurApplicatifs on the fly and now it works as expected.

Pedro
  • 43
  • 1
  • 10