Spring TemplateEngine: ошибка процесса на поле th: - PullRequest
0 голосов
/ 13 декабря 2018

Я разрабатываю веб-приложение на Java с использованием Spring.

Это приложение включает вызовы Ajax в javascript, который запрашивает HTML-код, который затем вставляется в HTML-документ.

Для обработкишаблон тимилиста в строку. Я использую метод TemplateEngine (..).

Я обнаружил ошибку, когда шаблон тимелиста содержит форму.

Мой пример кода:

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 - это сбой, я 'Я пытаюсь вернуть html-код, проанализированный шаблоном thymeleaf, а также включить дополнительные данные в этот ответ json.Сбой в строке templateEngine.process ("form", templateContext);

form1 работает при замене form.html на:

Имя клиента: [[$ {customer.name}]]

Что заставляет меня сделать вывод, что именно тэг формы и th: object приводят к сбою.

form2 работает так же, как и ожидалось, но без какого-либо способа манипулирования возвращаемым значением тимелиста,Это доказывает, что сам шаблон thymeleaf действителен.

Весь вывод ошибки слишком велик, чтобы вставить его сюда, но:

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)

Мой вопрос: это ошибка ввесенние рамки?или, если нет, то что я делаю не так?


Обновление 1: замена th: field на th: value заставляет его работать, кажется, что th: поле внутри формы при использовании TemplateEngine .process - это то, что производитошибка.

Обновление 2: Хорошо, так что после большой детективной работы я нашел способ взломать эту работу временно.Проблема заключается в том, что thymeleaf требует 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 голосов
/ 19 декабря 2018

Кажется, вы пытаетесь вручную визуализировать шаблон HTML вне контекста веб-запроса, вернуть его сериализованный как ответ AJAX - но все еще ожидаете, что будет работать привязка формы.Это ключевая проблема здесь.

Использование th:field в шаблоне означает, что вы ожидаете привязку формы из HTTP-запроса.В своем фрагменте кода вы предоставляете пустой, не веб-контекст и все еще ожидаете, что привязка формы будет иметь место.

Поскольку Thymeleaf может использоваться в различных контекстах (например, рендеринг шаблона электронной почты перед отправкой бюллетеня, рендерингдокумент в пакетном приложении), мы не можем применять веб-контекст во всех случаях.

При рендеринге представлений способ, которым Spring Framework ожидает чего-либо (возвращая имя представления в качестве возвращаемого значения обработчика контроллера)Spring будет использовать и настраивать Thymeleaf соответствующим образом.

Ваш ответ технически верен, поскольку он решает вашу проблему, но он исходит из запутанного ограничения рендеринга шаблона и переноса его в строку json, и все еще ожидает связывание HTTP.

0 голосов
/ 13 декабря 2018

Добро пожаловать на SO.

Удалите xmlns:th="http://www.w3.org/1999/xhtml" из тега form.Это не правильный синтаксис.Это будет принадлежать тегу html.

Вы можете найти множество ярких примеров в документах .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...