嵌套对象空字段的Spring表单绑定问题

时间:2016-12-24 01:20:09

标签: java spring spring-mvc jpa thymeleaf

我对spring @ModelAttribute表单绑定有一个尴尬的问题。我有以下Entity类,它在表单绑定中用作Policy类的嵌套类。

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

我的问题主要关注的是Policy类,它是顶级类和主要绑定如下:

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

这是控制器方法,它从视图绑定中获取ModelAttribute带注释的Policy参数。

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

最后,这是代码的表单/视图部分:

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

问题是我提交表格时; spring form binding将表单参数绑定到Policy类的各个字段,但是如果未选择调整器,即adjusterId值的隐藏字段为空(这对应用程序来说完全没问题)则spring实例化一个新的Entity类,其中包含所有字段空值。由于ManyToOne关系和JPA验证,这在应用程序的JPA持久性部分上产生了问题。

有关如何克服此问题的任何指示。如果视图中的adjusterId(表单隐藏输入字段)为null;然后表单绑定不应实例化具有空字段值的新Entity类。相反,它应该将Policy类的adjusterId属性设置为null。

顺便说一句,我已经经历了许多类似的问题,而这些问题大部分都与之无关。其中一个就是same question which is unanswered

提前致谢...

1 个答案:

答案 0 :(得分:3)

在控制器中,您可以这样做:

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