【问题标题】:How to assign Set elements to form field in Thymeleaf如何将 Set 元素分配给 Thymeleaf 中的表单字段
【发布时间】:2017-12-18 01:39:27
【问题描述】:

我可以看到 List 在 Thymeleaf 表单中成功使用 http://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#dynamic-fields

<tr th:each="row,rowStat : *{rows}">
  <td th:text="${rowStat.count}">1</td>
  <td>
    <select th:field="*{rows[__${rowStat.index}__].variety}"><!-- how to do this with Set? -->
      <option th:each="var : ${allVarieties}" 
              th:value="${var.id}" 
              th:text="${var.name}">Thymus Thymi</option>
    </select>
  </td>
  ..
</tr>

我可以用 Set 而不是 List 做同样的事情吗?特别是代码中带有注释的行。 如何将 Set 元素分配给 th:field?

更新 1

我在我的项目中使用了它并继续使用 Set 并在提交/添加新行时,它给出了以下错误。它甚至没有达到相应的控制器方法。

org.springframework.beans.InvalidPropertyException:bean 类 [ae.tbits.atn.aiwacore.common.model.CatDescr] 的无效属性“catDescrDts [0]”:非法尝试获取属性“catDescrDts”引发异常;嵌套异常是 org.springframework.beans.InvalidPropertyException:bean 类 [ae.tbits.atn.aiwacore.common.model.CatDescr] 的无效属性“catDescrDts [0]”:无法从大小为 0 的集合中获取索引为 0 的元素,使用属性路径'catDescrDts[0]'访问

CatDescrDts 对应示例中的行,它与 CatDescr 实体具有多对一的关系。

堆栈跟踪

Caused by: org.springframework.beans.InvalidPropertyException: Invalid property 'catDescrDts[0]' of bean class [ae.tbits.atn.aiwacore.common.model.CatDescr]: Cannot get element with index 0 from Set of size 0, accessed using property path 'catDescrDts[0]'
at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:661)
... 51 more
2017-07-13 16:23:57 ERROR ErrorController:19 - Exception during execution of SpringSecurity application
org.springframework.beans.InvalidPropertyException: Invalid property 'catDescrDts[0]' of bean class [ae.tbits.atn.aiwacore.common.model.CatDescr]: Illegal attempt to get property 'catDescrDts' threw exception; nested exception is org.springframework.beans.InvalidPropertyException: Invalid property 'catDescrDts[0]' of bean class [ae.tbits.atn.aiwacore.common.model.CatDescr]: Cannot get element with index 0 from Set of size 0, accessed using property path 'catDescrDts[0]'
at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:708)
at org.springframework.beans.AbstractNestablePropertyAccessor.getNestedPropertyAccessor(AbstractNestablePropertyAccessor.java:836)
at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyAccessorForPropertyPath(AbstractNestablePropertyAccessor.java:813)
at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:270)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:95)
at org.springframework.validation.DataBinder.applyPropertyValues(DataBinder.java:834)
at org.springframework.validation.DataBinder.doBind(DataBinder.java:730)
at org.springframework.web.bind.WebDataBinder.doBind(WebDataBinder.java:192)
at org.springframework.web.bind.ServletRequestDataBinder.bind(ServletRequestDataBinder.java:106)
at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.bindRequestParameters(ServletModelAttributeMethodProcessor.java:150)
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:114)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:114)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:284)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:263)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:174)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:202)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:793)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

Caused by: org.springframework.beans.InvalidPropertyException: Invalid property 'catDescrDts[0]' of bean class [ae.tbits.atn.aiwacore.common.model.CatDescr]: Cannot get element with index 0 from Set of size 0, accessed using property path 'catDescrDts[0]'
at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:661)
... 51 more

更新 2

放一些代码..

  1. 首次调用 create 时,表单显示正常,但行为空。
  2. 当我单击保存或添加新行时,在调用控制器 save() 之前会出现该错误。
  3. 如果我注释掉 th:field 行,错误就消失了。

控制器

@GetMapping({"/create"})
public String create(ModelMap model){
    CatDescr catDescr = new CatDescr();         
    //add 1 empty row for catDescrDt
    int noOfCatDescrDts = 1;
    catDescr.setCatDescrDts(getNewCatDescrDts(noOfCatDescrDts, catDescr));  
    model.addAttribute("catDescr", catDescr);   
    return "catDescr/create";
}

@PostMapping(value="/create", params={"save"})
public String save(final CatDescr catDescr
        , final BindingResult bindingResult, final ModelMap model){     
    ...
    CatDescr updatedCatDescr = catDescrService.save(catDescr);  
    model.clear();
    return "redirect:/catDescr/create";

}

@RequestMapping(value="/create", params={"addCatDescrDtRow"})
public String addCatDescrDtRow(ModelMap model, final CatDescr catDescr, final BindingResult bindingResult) {
    catDescr.getCatDescrDts().add(new CatDescrDt());
    ...
    return "catDescr/create";
}

查看

<ul th:each="item, stat: *{catDescrDts}">
<li>
    <input type="text" th:field="*{catDescrDts[__${stat.index}__].name}" th:id="${'catDescrDts'+stat.index+'.name'}">
</li>

【问题讨论】:

  • 是的,它应该与 Set 一起正常工作,事实上任何 Iterable 或 Array 都应该没问题。虽然您可能无法保证 Set 元素的顺序。
  • 试过了,不行。错误似乎出现在 set 像数组一样被访问的行。发布堆栈跟踪.. 谢谢。
  • 异常似乎是说您正在尝试访问集合中的第一个元素,但集合是空的。
  • @Janar 是的,你是对的。除了在我的代码中没有任何地方,我尝试直接访问 Set 的元素,例如 [0]。检查我的控制器,设置不为空。并且视图最初显示表单,当我发布(保存或添加新行)时,我收到此错误。堆栈跟踪似乎表明发布错误,未到达控制器。将代码 sn-ps 放入更新 2。
  • 对不起,我想我误解了你的问题。也许我应该澄清一下,您可以在 Thymeleaf 中使用 Set 的计数器和索引,但您不能将控制器中的 Set 直接绑定到对象。 Spring 使用 getter 和 setter 来绑定它无法通过使用带有 Set 的索引的对象。尝试自定义 Getter/Setter,例如 this

标签: spring-mvc thymeleaf


【解决方案1】:

必须在实体中使用自定义 getter/setter 来返回 Set 作为 List,而是在 Thymeleaf 中绑定 List,以便它可以通过索引访问。

在控制器中必须将 List 成员与 Set 成员同步。

感谢@Dark,精彩的解释以及有用的链接。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-26
    • 2022-08-24
    • 1970-01-01
    • 2016-03-01
    • 2019-01-14
    • 2020-06-09
    • 2016-04-21
    相关资源
    最近更新 更多