【问题标题】:Property value lost (null/empty) on web form reloadWeb 表单重新加载时属性值丢失(空/空)
【发布时间】:2015-03-15 15:15:13
【问题描述】:

使用 spring mvc 3.0.5 我遇到了一个奇怪的(几乎是零星的)数据绑定错误。 在应用程序的一个页面中,使用了具有一些原始值(少量字符串和长整数)和两个 List(我们将它们命名为 A 和 B)的模型 bean。列表显示在两个表中(使用 displaytag)。用户可以编辑一些原始值并提交显示更新数据的来源(重新显示同一页面)。列表数据存储在页面中隐藏的输入字段中。

问题在于,有时某个隐藏字段会在 POST/显示周期中丢失。 Java 值变为 null,在 HTML 中变为 value=""。 (它发生在一种 Long 类型和一种 Boolean 中)

到目前为止,它只发生在模型属性中的两组特定数据值上。在一种情况下,一个值在第 N 次迭代中消失(N 约为 3 或 4),而在另一种情况下,它发生在第一次 POST 中。 在许多其他数据集中没有观察到问题。好像是未初始化的变量使用、未同步的跨线程数据访问或类似情况。

问题是:

  • 这听起来像一些已知的错误吗?
  • 如何进行?一步一步调试?去哪里看?

更多信息(基本的,即使是代码的精确副本也不会重现问题):

JSP:

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<form:form  id="form" method="post" modelAttribute="myRequest" action="spremembaUporabnika" enctype="multipart/form-data">
  <display:table id="table1" name="myRequest.listA"  decorator="si.comtrade.vs.web.decorators.users.UserRightsDecorator">   
    <display:setProperty name="paging.banner.all_items_found" value=""/>
    <display:setProperty name="paging.banner.onepage" value=""/>

    <display:column title="Column1">
      <c:out value="${myRequest.listA[table1_rowNum-1].orgUnitName}"/>
      <form:hidden path="listA[${table1_rowNum-1}].string1" id="string1[${table1_rowNum-1}]"/>
      <form:hidden path="listA[${table1_rowNum-1}].long1" id="long1[${table1_rowNum-1}]"/>
      <form:hidden path="listA[${table1_rowNum-1}].long2" id="long2[${table1_rowNum-1}]"/>
      <form:hidden path="listA[${table1_rowNum-1}].string2" id="string2[${table1_rowNum-1}]"/>
    </display:column>
    <display:column escapeXml="true" property="prop2" title="Column2" />
    ...
  </display:table>

模型类:

public class MyRequest {
    private List<TypeA> listA = new AutoPopulatingList<TypeA>(TypeA.class);

    private List<TypeB> listB = new AutoPopulatingList<TypeB>(TypeB.class);

  // ... other fields and getters/setters omitted

}

public class TypeA {
    Long long1, long2;  // <---- one of these loses the value on POST/reload
    String string1, string2;
  // ... other fields and getters/setters omitted
}

控制器类:

@Controller
@PreAuthorize("hasAnyRole('fooRole')")
public class MyController {

  @InitBinder
  protected void initBinder(WebDataBinder binder) {
    binder.setValidator(new MyValidator());
    binder.registerCustomEditor(Date.class, "listB.date1", new CustomDateEditor(new SimpleDateFormat("dd.MM.yyyy HH:mm"), true));
    binder.registerCustomEditor(Date.class, "listB.date2", new CustomDateEditor(new SimpleDateFormat("dd.MM.yyyy HH:mm"), true));
  }

  @ModelAttribute("myRequest")
  public MyRequest getTheRequest() {
    MyRequest request = new MyRequest();
    List<BarType> barList = getSomeBars(null, null);
    request.setBarList(barList);
    return request;
  }

  @RequestMapping(value = "/myPage", method = RequestMethod.GET)
  public String myPage(@ModelAttribute("myRequest") MyRequest request,
    @RequestParam(value = "userId", required = false) String userId,
    HttpSession p_session, Map<String, Object> map) {
    ... values into myRequest are filled here

    return "id_for_tiles";
}

  @RequestMapping(value = "/doSomething", method = RequestMethod.POST)
  public String doMethod(@ModelAttribute("myRequest") @Valid MyRequest request, BindingResult binder, Map<String, Object> map) {
    ... do some processing, then redisplay the same page

    return "id_for_tiles"; // same as in other method
  }

新发现:

  • 问题发生在表单被 POST 编辑时:HTML 页面中的值正常,但在控制器中它们最终为空
  • 进入BeanWrapperImpl中的public void setPropertyValue(PropertyValue pv)方法发现值为空字符串

事实证明,表单支持文件上传的一个重要因素。 (见答案)

【问题讨论】:

    标签: spring-mvc apache-commons-fileupload


    【解决方案1】:

    显然这是来自 commons-fileupload-1.2 的 org.apache.commons.fileupload.MultipartStream 中的一个错误

    方法 public int read(byte[] b, int off, int len) 中的代码(第 878 行)尝试读取参数值,但缓冲区中没有可用数据(已检查通过 available()),它调用 makeAvailable() 从 HTTP 请求流中读取更多数据。这可以返回 0、1 或类似的几个字节,这些字节不足以包含分隔符字符串,因此仍然有 0 字节 available() 并且 read 方法退出 - 1 而不是从 HTTP 请求流中读取更多数据。

    供参考:

    /* this is line 877 */
        public int read(byte[] b, int off, int len) throws IOException {
            if (closed) {
                throw new FileItemStream.ItemSkippedException();
            }
            if (len == 0) {
                return 0;
            }
            int res = available();
            if (res == 0) {
                res = makeAvailable();
                if (res == 0) {
                    return -1;
                }
            }
            res = Math.min(res, len);
            System.arraycopy(buffer, head, b, off, res);
            head += res;
            total += res;
            return res;
        }
    

    这是一个已知的错误:https://issues.apache.org/jira/browse/FILEUPLOAD-135 已在 1.2.1 版本中修复。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-21
      • 1970-01-01
      • 1970-01-01
      • 2012-04-01
      • 1970-01-01
      • 2014-09-12
      • 2013-08-07
      相关资源
      最近更新 更多