ajax更新后不再识别Spring模型属性

Posted

技术标签:

【中文标题】ajax更新后不再识别Spring模型属性【英文标题】:Spring modelattribute not recognized anymore after ajax update 【发布时间】:2017-05-05 16:19:54 【问题描述】:

我多次遇到以下问题: 我使用控制器将 dto 绑定到 html 表单(通过 thymeleaf)。 请注意名为“invoiceDto”的模型

@RequestMapping(value = "/create", method = RequestMethod.GET)
        public String create(Locale locale, Model model) throws Exception 
            final String login = this.getAuthentication().getCurrentApplicationUser();
            if (login == null || login.isEmpty())
                throw new Exception(this.getMessageSource().getMessage("label.findError", null, locale));
    
            final Future<Setting> setting = settingService.findFirst();
            final Future<ApplicationUserContactProjection> applicationUserContactProjection = applicationUserService.findByLogin(login);
            while (!setting.isDone() && !applicationUserContactProjection.isDone()) 
                Thread.sleep(100);
            
            if (setting.get() == null || applicationUserContactProjection.get() == null)
                throw new Exception(this.getMessageSource().getMessage("label.error.findError",
                        null, locale));
    
            model.addAttribute("invoiceDto", new InvoiceDto(setting.get(), applicationUserContactProjection.get()));
            model.addAttribute("message", this.getMessageSource().getMessage("label.navigation.invoiceCreation", null, locale));
            return "invoice/create";
    

我有一个 html 表单(生成 thymeleaf),我使用上面的 Java pojo dto 和给定的模型属性名称来填充我的输入字段。这是它的摘录。 重要的部分是 id 为“invoiceLineItems”的 div,其中 thymeleaf 将其子 div 替换为 lineItems 片段:

<form action="#" th:action="@/invoice/newinvoice" th:object="$invoiceDto" role="form" method="post"
              class="form-signin" id="editInvoiceForm"
              accept-charset="utf-8">
        <div id="invoiceLineItems"><div th:replace="invoice/items :: lineItems"></div></form>

片段包含以下内容 - 摘录:

<td>
                    <input type="text"
                           th:field="*items[__$index.index__].lineItemTotalPrice"
                           readonly
                           class="form-control" disabled
                           id="lineItemTotalPrice"/>
                </td>

给定pojo的摘录:

public class InvoiceDto implements Serializable 
        private Invoice invoice;
        private List<LineItem> items;

我这样访问列表:

th:field="*items[__$index.index__].lineItemTotalPrice"

问题: 我可以通过 Ajax 动态添加项目。我序列化整个表单(为方便起见)并调用控制器方法:

@RequestMapping(value = "/newlineitem", method = RequestMethod.POST)
    public String newLineItem(@ModelAttribute("invoiceDto") InvoiceDto invoiceDto,
                              Model model)
            throws Exception 
    
        invoiceDto.addItem(new LineItem());
        final Future<InvoiceDto> calculatedInvoiceDto = invoiceService.calculateInvoice(invoiceDto);
        while (!calculatedInvoiceDto.isDone()) 
            Thread.sleep(100);
        
        model.addAttribute("invoiceDto", calculatedInvoiceDto.get());
        return "invoice/dynamicitems :: lineItems";
    

如您所见,我让 thymeleaf 呈现一个特殊视图,因为在 Ajax 成功之后 spring 无法正确设置模型属性。 总之:Ajax返回局部视图后,下面会抛出异常:

th:field="*items[__$index.index__].lineItemTotalPrice"

而这可行 - 请注意前缀 invoiceDto:

th:field="*invoiceDto.items[__$index.index__].lineItemTotalPrice"

问题: 这里有什么问题? 为什么我必须在部分 Ajax 更新后为模型属性的名称添加前缀,而在第一次运行时我不必?

感谢您的帮助!

编辑: 对于我的分享,如果页面通过部分 thymeleaf html 由 ajax 调用(到另一个 spring 控制器,修改 invoiceDto)部分更新,那么 spring “忘记”最初命名的表单模型属性“invoiceDto”的方式。

因此,在控制器返回部分 thymeleaf 视图后,我必须访问带有前缀“invoiceDto”的字段,就好像没有 invoiceDto 属性一样。

再次感谢您的帮助!

更新 由于这方面没有进展,我提出了一个百里香叶问题:https://github.com/thymeleaf/thymeleaf/issues/795

尽管如此,我认为这是一个春季问题,因为我使用 JSP 得到了相同的结果。

理解此问题的存储库https://mygit.th-deg.de/tlang/thymefail

【问题讨论】:

Reference object passed to Thymeleaf fragment的可能重复 @BrianClozel 感谢您的建议。小费对我不起作用。请查看有关该问题的更新。一方面我制作了一个要克隆的存储库,另一方面我提出了一个百里香叶问题。 【参考方案1】:

如果我正确理解您的问题,那么您在没有活动对象时尝试使用 * 表示法。当 ajax 方法只返回“lineItems”片段时,Thymeleaf 无法知道它属于带有th:object 的表单。

我想最好的解决方案是返回整个表单,然后在 js 中提取 lineItems。 或者也许干脆完全摆脱th:object(仅当您想显示验证错误时才方便)。

【讨论】:

奇怪的是我可以使用* 符号。在ajax调用之后(我提交整个表单,它通过控制器中的spring的modelattribute类型以正确的方式实现)模型变量在那里(具有相同的键)。渲染局部视图后,我必须像这样为模型名称添加前缀:th:field="*invoiceDto.items[__$index.index__].lineItemTotalPrice"

以上是关于ajax更新后不再识别Spring模型属性的主要内容,如果未能解决你的问题,请参考以下文章

使用 AJAX 绑定时创建/更新后具有 IEnumerable 属性的 Kendo Grid 模型未正确更新

Django:保存模型后如何不再更新模型?

ajax发布后淘汰js更新视图模型

Safari错误。 Javascript ajax json对象 - 无法获取属性。对象可能不再存在

AbstractMongoEventListener 识别更新或添加事件 spring boot mongoDb

ajax调用后jQuery更新li类属性href