Spring MVC - 提交表单时丢失了子实体ID

时间:2015-05-26 13:28:34

标签: javascript spring hibernate jsp spring-mvc

我有两个实体 Environnment ServeurApplicatif ,它们具有oneToMany关系。我有一个动态表单,每次用户想要将ServeurApplicatif与Environnement实体关联时,都会添加一个新表单。提交预期结果时,环境实体和与之关联的ServeurApplicatif实体的持久性。

但是在我的情况下,每当我尝试提交表单时,我都会收到 400 http错误:您的请求在语法上不正确

这里是动态添加子实体相关表单的javascript代码:

<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;
            }) 

jsp中的Spring表单标记:

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

Environnement实体类:

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

ServeurApplicatif实体类:

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

用于保存实体的控制器方法:

    @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");

}

EnvironnementService中的gererServeur方法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;
}   

请注意,我使用此处显示的解决方案来管理动态表单: Spring 3 MVC: one-to-many within a dynamic form (add/remove on create/update)

修改:

我尝试在文档就绪函数之外声明行var index = ${fn:length(env.serveurApplicatifs)};但它没有帮助,console.log在加载表单时返回0但是每次我按下按钮添加新表单时都会增加对于 ServeurApplicatif ,发送到服务器的表单数据如下:

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

您会注意到,与idenv不同,idserv不会自动填充。这两个ID都是DB中的自动增量字段,其他空白字段可以为空,因此不存在问题。

提前致谢。

1 个答案:

答案 0 :(得分:0)

我发现了什么问题。

基本上 idserv 未获得默认值0 ,以便 spring可以处理对服务器的请求,当调用saveOrUpdate时,hibernate可以在 Environnment实体旁边插入 ServeurApplicatif实体,所以我在javascript中添加了value="0"代码负责为即时创建ServeurApplicatifs的表单输入,现在它按预期工作。