Th:field

时间:2018-12-13 12:21:18

标签: spring spring-mvc spring-boot thymeleaf

我正在使用Spring开发Java Web应用程序。

此应用程序包括javascript中的Ajax调用,该调用请求html代码,然后将其插入html文档中。

为了将百里香模板处理成字符串,我正在使用TemplateEngine process(..)方法。

当百里香模板包含一个表格时,我遇到了一个错误。

我的示例代码:

form.html:

<form th:object="${customer}" xmlns:th="http://www.w3.org/1999/xhtml">
    <label>Name</label>
    <input type="text" th:field="*{name}" />
</form>

AjaxController.java:

package project;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

@Controller
public class AjaxController {

    @Autowired
    private TemplateEngine templateEngine;
    private ObjectMapper objectMapper = new ObjectMapper();

    @ResponseBody
    @GetMapping(value="/form1")
    public String form1() throws JsonProcessingException {

        Customer customer = new Customer("Burger King");

        Context templateContext = new Context();
        templateContext.setVariable("customer", customer);

        AjaxResponse response = new AjaxResponse();
        response.html = templateEngine.process("form", templateContext);
        response.additionalData = "ab123";

        return objectMapper.writeValueAsString(response);
    }

    @GetMapping(value="/form2")
    public String form2(Model model) throws JsonProcessingException {

        Customer customer = new Customer("Burger King");

        model.addAttribute("customer", customer);

        return "form";
    }

    class Customer {
        private String name;

        public Customer(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    class AjaxResponse {
        public String html;
        public String additionalData;
    }
}

form1是崩溃的那个,我试图返回由thymeleaf模板解析的html代码,并且还在此json响应中包含其他数据。 它在templateEngine.process(“ form”,templateContext);行崩溃

form1在将form.html替换为:

时起作用

客户名称为:[[$ {customer.name}]]

这使我得出结论,正是导致这个崩溃的是表单标签和th:object。

form2可以按预期方式工作,但是没有任何方法可以处理百里香返回值。证明百里香模板本身是有效的。

整个错误输出太大了,无法粘贴到这里,但是:

org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/form.html]")

Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Cannot process attribute '{th:field,data-th-field}': no associated BindStatus could be found for the intended form binding operations. This can be due to the lack of a proper management of the Spring RequestContext, which is usually done through the ThymeleafView or ThymeleafReactiveView (template: "form" - line 3, col 21)

我的问题是:这是spring框架中的错误吗?或者如果不是,那我在做什么错了?


更新1: 用th:value替换th:field可以正常工作,似乎在使用TemplateEngine .process时表单内的th:field会产生错误。

更新2: 好吧,经过大量的侦探工作,我想出了一种办法可以使这项工作暂时生效。问题在于,百里香需要IThymeleafRequestContext来处理具有表单的模板,当TemplateEngine .process运行时,将不会创建该模板。可以将其注入模型中,如下所示:

@Autowired
ServletContext servletContext;

private String renderToString(HttpServletRequest request, HttpServletResponse response, String viewName, Map<String, Object> parameters) {
    Context templateContext = new Context();
    templateContext.setVariables(parameters);

    RequestContext requestContext = new RequestContext(request, response, servletContext, parameters);
    SpringWebMvcThymeleafRequestContext thymeleafRequestContext = new SpringWebMvcThymeleafRequestContext(requestContext, request);
            templateContext.setVariable("thymeleafRequestContext", thymeleafRequestContext);

    return templateEngine.process(viewName, templateContext);
}

现在您可以使用这种方法:

@ResponseBody
@GetMapping(value="/form1")
public String form1(HttpServletRequest request, HttpServletResponse response) throws JsonProcessingException {

    Customer customer = new Customer("Burger King");
    BindingAwareModelMap bindingMap = new BindingAwareModelMap();
    bindingMap.addAttribute("customer", customer);
    String html = renderToString(request, response, "form", bindingMap);

    AjaxResponse resp = new AjaxResponse();
    resp.html = html;
    resp.additionalData = "ab123";

    String json = objectMapper.writeValueAsString(resp);
    return json;
}

我不会将其作为答案,因为我看不到有任何理由打算以此方式使用它。我正在与春季人们进行沟通,以获取针对此问题的真正解决方法。

2 个答案:

答案 0 :(得分:1)

欢迎来到SO。

xmlns:th="http://www.w3.org/1999/xhtml"标记中删除form。这是不正确的语法。这将属于html标记。

您可以在docs中找到很多清晰的示例。

答案 1 :(得分:0)

似乎您正在尝试在Web请求上下文之外手动呈现HTML模板,将其序列化为AJAX响应,但仍希望表单绑定能够正常工作。这是这里的关键问题。

在模板中使用th:field意味着您期望从HTTP请求中进行表单绑定。在您的代码段中,您将提供一个空的非Web上下文,并且仍然希望进行表单绑定。

由于Thymeleaf可以在各种上下文中使用(例如在发送新闻稿之前呈现电子邮件模板,在批处理应用程序中呈现文档),因此我们不能在所有情况下都强制使用Web上下文。

当以Spring Framework期望的方式渲染视图时(通过返回视图名称作为控制器处理程序的返回值),Spring将相应地使用和配置Thymeleaf。

您的答案在技术上是有效的,因为它可以解决您的问题,但是它来自渲染模板的繁琐约束,并将其包装到json字符串中,并且仍然需要HTTP绑定。