Недопустимое свойство 'books [0]' класса EJB [java .util.ArrayList] - PullRequest
0 голосов
/ 19 марта 2020
Caused by: org.springframework.beans.NotReadablePropertyException: Invalid property 'books[0]' of bean class [java.util.ArrayList]: Bean property 'books[0]' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?

ReadingList. html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Reading List</title>
    <link rel="stylesheet" th:href="@{/style.css}"></link>
</head>
<body>
<h2>Your Reading List</h2>
<div th:unless="${#lists.isEmpty(books)}">
    <dl th:each="book : ${books}">
        <dt class="bookHeadline">
            <span th:text="${book.title}">Title</span> by
            <span th:text="${book.author}">Author</span>
            (ISBN: <span th:text="${book.isbn}">ISBN</span>)
        </dt>
        <dd class="bookDescription">
            <span th:if="${book.description}" th:text="${book.description}">Description</span>
            <span th:if="${book.description eq null}"> No description available</span>
        </dd>
    </dl>
</div>
<div th:if="${#lists.isEmpty(books)}">
    <p>You have no books in your book list</p>
</div>



<hr/>
<h3>Add a book</h3>
<form method="POST" action="#" th:action="@{/readingList}" th:object="${books}">
    <div th:if="${#fields.hasErrors()}">
    <span class="validationError">
        Please correct the problems below and resubmit.
    </span>
    </div>


    <label for="title">Title:</label>
      <input type="text"  th:field="*{books[0].title}" size="50"/><br/>
      <span class="validationError"
            th:if="${#fields.hasErrors('books[0].title')}"
            th:errors="*{books[0].title}">
          title error
      </span>
    <!--   <input type="text" name="title" size="50"></input><br/>-->


    <label for="author">Author:</label>
    <input type="text" name="author" size="50"></input><br/>
    <label for="isbn">ISBN:</label>
    <input type="text" name="isbn" size="15"></input><br/>
    <label for="description">Description:</label><br/>
    <textarea name="description" rows="5" cols="80"></textarea><br/>
    <input type="submit"></input>
</form>
</body>
</html>

ReadingListController. java

package com.example.readinglist;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.validation.Valid;
import java.util.List;

@Controller
@RequestMapping("/readingList")
public class ReadingListController {

    private static final String reader = "craig";

    private ReadingListRepository readingListRepository;

    @Autowired
    public ReadingListController(ReadingListRepository readlingListRepository) {
        this.readingListRepository = readlingListRepository;
    }


    @GetMapping
    public String readersBooks(Model model) {
        List<Book> readingList = readingListRepository.findByReader(reader);
        if (readingList != null) {
            model.addAttribute("books", readingList);
        }
        return "readingList";
    }

    @PostMapping
    public String addToReadingList(@Valid Book book, BindingResult bindingResult, RedirectAttributes attr) {
        if(bindingResult.hasErrors()){
            return "error";
        }
        book.setReader(reader);
        readingListRepository.save(book);
        attr.addFlashAttribute("books", book);
        return "redirect:/readingList";
    }

}

Book. java

package com.example.readinglist;

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Data
@Entity
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String reader;
    private String isbn;
    @NotBlank(message = "title cannot be null")
    private String title;
    private String author;
    private String description;

}

Я понимаю проблема связана с неправильным способом проверки свойства title на <input type="text" th:field="*{books[0].title}" size="50"/>, потому что books является списком массивов, а не простым объектом. Но вопрос в том, что я хочу только проверить ввод для поля заголовка, но переданный объект - это массив, как мне быть с ним? Я также проверяю много похожих вопросов, но ни один из них не соответствует моему случаю.

1 Ответ

0 голосов
/ 20 марта 2020

Если вы планируете использовать th:object и th:field, th:object не может быть типа List, Thymeleaf просто не допускает этого. Вам нужен другой объект (BookForm или что-то в этом роде), который содержит List<Book> books в качестве его свойства.

Используйте этот новый объект BookForm в качестве th:object, а затем th:field выражения должны работать.

Пример этого можно увидеть на примере целочисленного типа Thymeleaf Spring. Вы можете видеть, что в этом примере динамических c полей класс SeedStarter имеет List<Row>, и они не просто используют List в качестве th:object.

...