0

我正在使用 spring MVC。我的命令对象包含一个集合对象,如下所示

public class DimensionStoneBean {
int stoneNo;
float length;
float breadth;
float height;
float dimension;
String isIssued;

public int getStoneNo() {
    return stoneNo;
}
public void setStoneNo(int stoneNo) {
    this.stoneNo = stoneNo;
}
public float getLength() {
    return length;
}
public void setLength(float length) {
    this.length = length;
}
public float getBreadth() {
    return breadth;
}
public void setBreadth(float breadth) {
    this.breadth = breadth;
}
public float getHeight() {
    return height;
}
public void setHeight(float height) {
    this.height = height;
}
public float getDimension() {
    return dimension;
}
public void setDimension(float dimension) {
    this.dimension = dimension;
}
public String getIsIssued() {
    return isIssued;
}
public void setIsIssued(String isIssued) {
    this.isIssued = isIssued;
}

}





    public class UpdateStockBean {
@SuppressWarnings("rawtypes")
private List dimensionStones =
    LazyList.decorate(new LinkedList(),FactoryUtils.instantiateFactory(DimensionStoneBean.class));
long openbalance;

public UpdateStockBean() {
    super();
}

@SuppressWarnings("rawtypes")
public List getDimensionStones() {
    return dimensionStones;
}
public void setDimensionStones(@SuppressWarnings("rawtypes") List dimensionStones) {
    this.dimensionStones = dimensionStones;
}
public long getOpenbalance() {
    return openbalance;
}
public void setOpenbalance(long openbalance) {
    this.openbalance = openbalance;
}

}

这个控制器类,扩展了AbstractWizardFormController

我习惯于formBackingObject() 填充命令对象将其返回到表单

表格如下所示

  <form:form commandName="updateStock" method="post" name="stockEntry" action="updateStock.nic" id="updateStock">
  <br><br><br>
  <table border="1" width="700">
   <tr>     
     <td class="textClr1" align="left" width="50"><nobr>Total No Of Stones</nobr></td>
     <td colspan="6"><form:input tabindex="1" path="openbalance" id="openbalance" cssClass="controlStock"/></td>
   </tr>    
   <tr>
      <td></td>
      <td colspan="6"><form:errors cssClass="error" path="openbalance"/></td>
   </tr> 
  </table>
  <table>
   <tr>
     <td colspan="3">
        <table  border="1" width="400">
          <tbody id="dimensionList">                           
            <c:forEach  var="DimensionStones" items="${updateStock.dimensionStones}" varStatus="i" begin="0">
              <tr class="dimensionStone">    
                 <td><form:input path="dimensionStones[${i.index}].stoneNo" id="stoneNo${i.index}" cssClass="controlStock"/></td>
                 <td><form:input path="dimensionStones[${i.index}].length" id="length${i.index}" onchange="findDimension(this.id)" cssClass="controlStock"/></td>
                 <td><form:input path="dimensionStones[${i.index}].breadth" id="breadth${i.index}" onchange="findDimension(this.id)" cssClass="controlStock"/></td>
                 <td><form:input path="dimensionStones[${i.index}].height" id="height${i.index}" onchange="findDimension(this.id)" cssClass="controlStock"/></td>
                 <td><form:input path="dimensionStones[${i.index}].dimension" id="dimension${i.index}" cssClass="controlStock"/></td>                 
                 <td><form:checkbox path="dimensionStones[${i.index}].isIssued" id="isIssued${i.index}" value="" cssClass="check"/></td>
                 <td><a href="#" class="removeDimensionStone"><img src="images/cross1.jpg" width="20" height="20" title="Remove Dimension Stone"/></a></td>

              </tr>
            </c:forEach>   
            <tr>

            </tr>             
            <c:if test="${empty updateStock.dimensionStones}">
                <tr class="dimensionStone defaultRow">    
                            <td><input type="text" name="dimensionStones[].stoneNo" value="" id="stoneNo" Class="controlStock"/></td>
                            <td><input type="text" name="dimensionStones[].length" value="" id="length" onchange="findDimension(this.id)" Class="controlStock"/></td>
                            <td><input type="text" name="dimensionStones[].breadth" value="" id="breadth" onchange="findDimension(this.id)" Class="controlStock"/></td>
                            <td><input type="text" name="dimensionStones[].height" value="" id="height" onchange="findDimension(this.id)" Class="controlStock"/></td>
                            <td><input type="text" name="dimensionStones[].dimension" value="" id="dimension" disabled="disabled" Class="controlStock"/></td>                            
                            <td><input type="checkbox" name="dimensionStones[].isIssued" value="Yes" id="isIssued" Class="controlStock"/></td> 
                            <td><a href="#" class="removeDimensionStone"><img src="images/cross1.jpg" width="20" height="20" title="Remove Dimension Stone"/></a></td>
                        </tr>
            </c:if>   
           </tbody>  
         </table>           
       </td>    
    </tr>    
  </table>
  <table  border="1" width="600"> 
   <tr>
      <td colspan="3" align="left"><a href="#" id="addDimensionStone"><img src="images/plus3.png" width="20" height="20" title="Add Dimension Stone"/></a></td>
   </tr> 
   <tr></tr> 
   <tr></tr> 
   <tr>
     <td colspan="3" align="center" width="200" height="180">
      <input type="submit" name="_target0" value="Submit" class="butn" />
     </td>
    </tr>  
  </table>  
</form:form>

这会在命令对象中显示集合中的值,并使我们能够删除、编辑和添加新行。

但我的问题是,删除命令对象中的集合中的相应对象并没有清除。因此,有不需要的 DIMENSIONSTONE 对象。我必须做什么来解决这个问题?请告诉我.......

4

1 回答 1

0

使用 Spring 绑定到 Collections 时,删除项目是一个问题。问题是命令对象仍然存在,并且在 UI 端没有办法告诉 WebBinder 从集合中删除某些项目。本质上,它可以在给定从视图传入的索引/键的情况下仅处理将内容插入指定位置。

为了解决这个限制,我过去所做的是在集合中的 bean 中添加一个名为“removal”的布尔值。然后,当我删除对象时,我只需将 HTML DOM 替换为隐藏字段,例如:

<input type="hidden" name="beans[3].removal" value="true" />

然后,在我的控制器中,我只需遍历集合并删除设置了“删除”标志的内容。

另一种选择是将总数存储在您的命令对象中。然后,当您到达控制器时,只需在该计数之后截断集合。

编辑:示例(从我的脑海中)

命令对象:

public class FormBean {
  private List<MyBean> myBeans;
  // ...getters/setters etc
}

Command Object 中集合中的 Bean:

public class MyBean {
  private String someProperty;
  private Integer someOtherProperty;

  private boolean removal;
  // Getters/Setters
}

形式:

<!-- standard HTML stuff -->
<script>
  $(document).ready(function() {
    // Click handler to replace the contents of div.row with the removal flag
    $('.btnRemove').click(function() {
      var count = $(this).parent().prev('.row').length;
      $(this).parent().removeClass('rowActive').addClass('rowRemove');
      $(this).parent().hide();
      $(this).parent().html(function() {
        return $("<input/>",{
          id: 'myBeans'+count+'.removal',
          name: 'myBeans['+count+'].removal',
          value: 'true'
        });
      });
    });
  });
</script>
<!-- More HTML stuff -->
<form:form modelAttribute="formBean" action="/someUrl">
  <c:forEach items="${formBean.myBeans}" var="myBean" varStatus="status">
    <div class="row rowActive">
      <form:input path="myBeans[${status.index}].someProperty" />
      <input type="button" class="btnRemove" value="Remove" />
    </div>
  </c:forEach>
</form:form>

然后,在您的控制器代码中的某处:

Set<MyBean> removals = new HashSet<MyBean>();
for(MyBean myBean : formBean.getMyBeans) {
  if(myBean.isRemoval) {
    removals.add(myBean);
  }
}
formBean.getMyBeans().removalAll(removals);

首先:我完全从内存中输入了这个,直接进入帖子编辑框。里程可能会有所不同...

第二:我使用jQuery。你不可以。如果需要,将任何 jQuery 内容替换为适当的非 jQuery 内容。

第三:有些部分我掩饰了。例如,我在 div 上有一个“行”类的原因是我可以获得添加新行的总数,因为您必须知道要添加哪个索引。div 上的“rowActive”和“rowRemove”类用于获取其他事物的计数,例如当只剩下一项时禁用删除按钮。我没有涉及的其他事情是添加行和设置事件处理程序(每次修改 DOM 时都需要这样做,因为您正在添加需要事件处理程序的新按钮)......我不会写整个应用程序都适合你,我想如果你能做到这一点,你可以弄清楚这些事情。

我在大约 6 个不同的 Spring MVC 应用程序中使用了这种方法。JavaScript 很复杂,需要您手动添加和删除元素。但这是我发现支持使用 Spring MVC 从集合中添加和删除项目的最佳方式。在我的例子中,Controller 端的清理不是一个大问题,因为我们使用 ValidationService 对象进行自己的验证,所以我只是将清理例程放在那里。如果有其他更好的方法,我很乐意看到它们。

如果您使用的是 AJAX(我们不是,因此我需要一个允许向服务器发出往返请求的解决方案),您可以通过提供 CRUD 方法来处理集合中的添加/删除项目,从而大大简化该过程。

编辑:更新信息

为了维护这个答案,我想指出我已经改变了 jQuery 部分的策略。我不再直接创建 DOM 元素,而是喜欢使用.clone()和一些创造性的正则表达式来创建新元素并重命名和重新标识它们。恕我直言,这样做的好处是大大减少了代码,因为您可以进行深度克隆并一次获取整个 DOM 块。例如,如果我有一个表并且我试图向其中添加整行,则可能会执行以下操作:

function addTableRow() {
  var $lastActiveRow = $('#myTable tr.rowActive:last-child');  // Gets the last active row
  var newActiveRow = $lastActiveRow.clone();
  var count = $('#myTable tr.rowActive').length;

  // Fix the name and identifier of all inputs in the new row
  $(newActiveRow).find(':input').each(function() {
    var name = $(this).attr('name');
    var identifier = $(this).attr('id');
    $(this).attr('name',name.replace(/(\d+)/g,count));  // matches and replaces digits that look like "xxx[1]"
    $(this).attr('id',identifier.replace(/(\d+)/g,count));  // matches and replaces digits that look like "xxx1"
  });
  $('#myTable').append(newActiveRow);
}

因此,在此示例中,我首先获取表中的最后一个活动行,然后克隆该行,然后循环该行的输入并使用正则表达式和所有活动行的计数来重置名称和 ID。使用我的旧方法,jQuery 在尝试添加高度复杂的 DOM 树时很快就会失控。

一些需要注意的事情:首先,jQueryclone()方法在 IE 7 和更低版本的 IE 中出现问题。此外,each() 循环根本没有重置输入的值。克隆的输入与您从中克隆的输入具有相同的值,因此您需要这样做。

最后,我想指出,clone()默认情况下该方法不会克隆事件处理程序,因此任何按钮以及您附加了 jQuery 事件处理程序的按钮也将不起作用。您也可以传入一个布尔值来指示 jQueryclone()事件,但是您会遇到事件被错误元素处理的问题(它不会克隆事件处理程序,只是克隆元素,但会将旧处理程序应用于新元素,因此您最终会得到纵横交错的处理程序)。更好的解决方案是通过将处理程序附加到更高级别的元素来使用委托事件(请参阅此处的直接和委托事件部分)。

于 2013-03-08T20:57:09.070 回答