Правильно отправить объект из тега <select>с помощью Thymeleaf и Spring - PullRequest
0 голосов
/ 11 марта 2019

У меня есть приложение Spring Boot (менеджер библиотеки), которое использует Thymeleaf в качестве механизма шаблонов.

Приложение состоит из двух основных @Component s, Book и Author.Book может иметь один Author.

. Я могу успешно создавать, извлекать, обновлять и удалять любые Author, но не могу правильно создавать или обновлять Book (хотя я могу получитьи удалить их).При выполнении запроса POST для вставки Book (вставка уже существующего объекта просто обновляет его), в браузере появляется ошибка 400 Bad Request. Validation failed for object='book'., и консоль выводит ошибку typeMismatch: Failed to convert property value of type 'java.lang.String' to required type 'com.springboot.demoweb.model.Author'.

Я проверял запросы, отправленные приложению, и вместо отправки «узла» JSON (извините, я не знаю, как работает JSON), содержащего свойства Author внутри корневого «узла» JSON Book, онпросто отправил результаты Author.toString() (которые я перезаписал. Не переопределение метода ничего не меняет).

Вот фрагмент <select>:

<form action="#" th:action="@{/books}" th:object="${book}" method="post">
    ...

    <select th:field="*{author}">
        <option th:each="author : ${authors}"
                th:value="${author}"
                th:text="${author}"/>
    </select>

    ...
</form>

Author.java file:

@Component
public class Author implements Serializable {
    private String id;
    private String name;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Calendar dateBorn;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Calendar dateDeath;

    ... // Getters and setters
}

Файл Book.java:

@Component
public class Book {
    private String isbn;
    private String title;
    private Author author;

    ... // Getters and setters
}

И BookController.java:

@Controller
public class BookController {
    @GetMapping(value = "/books/edit", params = "isbn")
    public String viewEdit(@RequestParam("isbn") String isbn, Model model) {
        model.addAttribute("book", bookService.find(isbn));
        model.addAttribute("authors", authorService.all());
        return "books/edit";
    }

    // th:action="@{/books}" falls here
    @PostMapping("/books")
    public RedirectView create(Book book) {
        bookService.create(book);
        return new RedirectView("/books.html?isbn=" + book.getIsbn());
    }

    ... // Other mappings
}

Переменные bookService и authorServiceвыполнять простые операции с Map<String, Book> и Map<String, Author> соответственно.

Что я могу сделать для того, чтобы Thymeleaf отправлял Author как объект внутри Book, а не только его строковое представление?Нужно ли что-то менять на странице HTML?Контроллер?Добавить конфигурацию Thymeleaf?

1 Ответ

0 голосов
/ 11 марта 2019

Согласно документации тимьяна ,

Значения атрибутов th: object в тегах формы должны быть выражениями переменных ($ {...}), указывающими только имя атрибута модели, без навигации по свойствам. Это означает, что выражение типа $ {seedStarter} допустимо, но $ {seedStarter.data} не будет.

Ваша форма Thymeleaf отображает значение toString выбранного автора. Невозможно связать объекты Author в списке параметров. Поэтому измените объект Book, добавив новый атрибут authorId (если Book является сущностью JPA, аннотируйте это с помощью @Transient).

@Component
public class Book {
     private String isbn;
     private String title;
     private Author author;
     // New Transient attribute to bind authorId from select component
     private String authorId;
}

Теперь этот новый атрибут можно связать с помощью компонента select, поскольку он соответствует приведенной выше документации.

<form action="#" th:action="@{/books}" th:object="${book}" method="post">
...

<select th:field="*{authorId}">
    <option th:each="author : ${authors}"
            th:value="${author.id}"
            th:text="${author.name}"/>
</select>

...

В вашем контроллере вы можете получить объект author с помощью book.authorId и установить для него объект book.

@PostMapping("/books")
public RedirectView create(Book book) {
    Author author = authorService.findById(book.authorId);
    book.setAuthor(author);
    bookService.create(book);
    return new RedirectView("/books.html?isbn=" + book.getIsbn());
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...