2016-12-24 2 views
1

Ich habe eher ein peinliches Problem mit Spring @ ModelAttribute Formularbindung. Ich habe die folgende Entity-Klasse, die in Formularbindung als geschachtelte Klasse der Policy-Klasse verwendet wird.Spring Form Binding Problem mit verschachtelten Objekt leere Felder

@javax.persistence.Entity 
@Table(name = "entity") 
@XmlRootElement 
public class Entity implements Serializable { 

    private static final long serialVersionUID = 1L; 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Basic(optional = false) 
    @Column(name = "entity_id") 
    private Integer entityId; 

    @Basic(optional = false) 
    @NotNull 
    @Column(name = "entity_type") 
    private int entityType; 

    @Basic(optional = false) 
    @NotNull 
    @Size(min = 1, max = 2147483647) 
    @Column(name = "entity_name") 
    private String entityName; 

    public Entity() { 
    } 

    public Entity(Integer entityId) { 
     this.entityId = entityId; 
    } 

    public Entity(Integer entityId, int entityType, String entityName) { 
     this.entityId = entityId; 
     this.entityType = entityType; 
     this.entityName = entityName; 
    } 

    public Integer getEntityId() { 
     return entityId; 
    } 

    public void setEntityId(Integer entityId) { 
     this.entityId = entityId; 
    } 

    public int getEntityType() { 
     return entityType; 
    } 

    public void setEntityType(int entityType) { 
     this.entityType = entityType; 
    } 

    public String getEntityName() { 
     return entityName; 
    } 

    public void setEntityName(String entityName) { 
     this.entityName = entityName; 
    } 
} 

Und das Hauptinteresse meines Problems, Policy-Klasse, die die Top-Level-Klasse ist und Haupt-Bindung ist wie folgt:

@Entity 
@Table(name = "policy") 
@XmlRootElement 
public class Policy implements Serializable { 

    private static final long serialVersionUID = 1L; 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Basic(optional = false) 
    @Column(name = "policy_id") 
    private Integer policyId; 

    @Basic(optional = false) 
    @NotNull 
    @Size(min = 1, max = 2147483647) 
    @Column(name = "reference_number") 
    private String referenceNumber; 

    @JoinColumn(name = "adjuster_id", referencedColumnName = "entity_id", nullable = true) 
    @ManyToOne(optional = true) 
    private Entity adjusterId; 

    public Policy() { 
    } 

    public Policy(Integer policyId) { 
     this.policyId = policyId; 
    } 

    public Integer getPolicyId() { 
     return policyId; 
    } 

    public void setPolicyId(Integer policyId) { 
     this.policyId = policyId; 
    } 

    public String getReferenceNumber() { 
     return referenceNumber; 
    } 

    public void setReferenceNumber(String referenceNumber) { 
     this.referenceNumber = referenceNumber; 
    } 


    public Entity getAdjusterId() { 
     return adjusterId; 
    } 

    public void setAdjusterId(Entity adjusterId) { 
     this.adjusterId = adjusterId; 
    } 
} 

Und dies ist die Controller-Methode, die in einem ModelAttribute nimmt kommentierten Richtlinienparameter aus der Bindungsansicht

@RequestMapping(value = "/create", method = RequestMethod.POST) 
    public ModelAndView create(@ModelAttribute Policy p) { 
     policyService.create(p); 
     return new ModelAndView("viewName"); 
    } 

Schließlich ist dies die Form/Ansicht Teil des Codes:

<form id="policyInformationForm" role="form" th:object="${policy}" th:action="@{${mode == 'CREATE'} ? '/policy/create' : '/policy/update'}" method="post"> 
         <div class="box-body"> 
          <div class="form-group"> 
           <label for="policyId">Policy Id</label> 
           <input type="text" th:field="*{policyId}" class="form-control" id="policyId" placeholder="" readonly="readonly" /> 
          </div> 

          <div class="form-group"> 
           <label for="referenceNumber">Policy Number (May change while saving!!!)</label> 
           <input type="text" th:field="*{referenceNumber}" class="form-control" id="referenceNumber" placeholder="Enter Policy Number" th:readonly="${mode == 'UPDATE'}" /> 
          </div> 

          <div class="form-group"> 
           <label for="adjusterName">Adjuster</label> 
           <div class="input-group"> 
            <input type="hidden" th:field="*{adjusterId.entityId}" class="form-control" id="adjusterId" /> 
            <input type="text" th:field="*{adjusterId.entityName}" class="form-control" id="adjusterName" placeholder="Enter Adjuster" /> 
            <div class="input-group-btn"> 
             <button id="adjusterSearchBtn" type="button" class="btn btn-success"><span class="glyphicon glyphicon-search"></span></button> 
             <button id="adjusterCreateBtn" type="button" class="btn btn-success"><span class="glyphicon glyphicon-plus"></span></button> 
            </div> 
           </div> 
          </div> 

         </div> 

         <div class="box-footer"> 
          <button type="submit" class="btn btn-primary">Submit</button> 
          <a th:href="@{'/policy/list'}" class="btn btn-warning">Cancel</a> 
         </div> 
        </form> 

Das Problem ist, wenn ich das Formular abzuschicken; Die Bindung der Springform bindet die Formparameter an die entsprechenden Felder der Policy-Klasse, aber wenn der Adjuster nicht ausgewählt ist, also das versteckte Feld von adjusterId leer ist (was in Bezug auf die Anwendung völlig in Ordnung ist), instantiiert Spring eine neue Entity-Klasse mit allen Feldern Nullwerte Dies führt aufgrund der ManyToOne-Beziehung und der JPA-Validierungen zu einem Problem im JPA-Persistenzteil der Anwendung.

Hinweise, wie Sie dieses Problem beheben können. Wenn die "adjusterId" aus der Ansicht (ausgeblendetes Eingabefeld) null ist; Die Formularbindung sollte dann keine neue Entity-Klasse mit Nullfeldwerten instanziieren. Stattdessen sollte die Eigenschaft adjusterId der Policy-Klasse auf null gesetzt werden.

Übrigens habe ich schon viele der ähnlichen Fragen, die wiederum die meisten von ihnen nicht relevant sind. Einer von ihnen ist genau der same question which is unanswered

Vielen Dank im Voraus ...

+0

Durch die Art, wie ich das Problem aufgespürt Federform verbindlich IdToEntityConverter. Jegliche Informationen, die den Standardkonverter außer Kraft setzen, werden sehr geschätzt – Ahmet

Antwort

3

Im contoller, könnten Sie einfach tun:

@RequestMapping(value = "/create", method = RequestMethod.POST) 
public ModelAndView create(@ModelAttribute Policy p) { 
    if (p.getAdjusterId().getEntityId() == null) { 
     p.setAdjusterId(null); 
    } 
    policyService.create(p); 
    return new ModelAndView("viewName"); 
} 
+0

Ich habe das bereits getan und es ist die am besten geeignete Problemumgehung; So wird es als Antwort akzeptiert. Ich glaube, IdToEntityConverter sollte irgendwie verstehen, dass der ankommende (Feld-) Parameter null ist und das Objekt nicht konstruieren sollte. – Ahmet

+0

Eigentlich ist es keine Problemumgehung, es ist die Lösung selbst. Das Überschreiben von "IdToEntityConverter" wäre ein nicht standardmäßiger Weg, und es lohnt sich in diesem Fall nicht. Wenn Sie nicht die gleiche Logik (prüfen ob 'entityId' NULL ist) in jede Controller-Methode schreiben möchten, an der 'Policy' beteiligt ist, können Sie die Annotation' ModelAttribute' auf Methodenebene verwenden. Werfen Sie einen Blick auf die [doc] (http://docs.spring.io/spring/docs/4.1.x/spring-framework-reference/html/mvc.html#mvc-ann-modelattrib-methods) – sedooe

Verwandte Themen