Попытка создать составной объект jpa в Spring + Thymeleaf - PullRequest
1 голос
/ 14 октября 2019

Я пытался создать объект с другим объектом внутри, с формой, но Объект, выбранный из выпадающего списка, преобразуется в строку при возврате из формы Thymeleaf. Это сущности в моем проекте с соотношением 1: n между ними:

Пользователь сущности

//imports
@Entity
@Table(name = "USERS")
public class User {
    @Id
    @GeneratedValue
    @Column( name ="USER_ID")
    private int id;

    @Column( name ="username")
    private String username;

    @Column( name ="password")
    private String password;

    @Column( name ="email")
    private String email;

    @OneToMany(fetch= FetchType.LAZY, mappedBy="user", cascade = CascadeType.ALL)
    private List<Post> posts;

    //setter & getters & toString

}

Сообщение сущности

//imports
@Entity
@Table(name="POSTS")
public class Post {
@Id
@GeneratedValue
@Column(name="POST_ID")
private int id;

@Column(name="tittle")
private String tittle;



@Column(name="text")
private String text;

@ManyToOne
@JoinColumn(name="USER_ID",referencedColumnName="USER_ID")
private User user;

//getters & setters & toString

Чтобы создать новую запись:

//In Controller

@RequestMapping(value = "/posts/new")
public String newPost(Model model) {
    model.addAttribute("post", new Post());
    model.addAttribute("users", userService.list());
    return "addPost";       
}

, который возвращает шаблон, имеющий эту форму:

<form th:action="@{/savePost}" th:object="${post}" method="post">
            <tr>
                <td><input type="hidden" th:field="${post.id}" /></td>
            </tr>
            <tr>
                <td>Titulo</td>
                <td>Texto</td>
                <td>Usuario</td>
            </tr>
            <tr>
                <td><input type="text" th:field="${post.tittle}"
                    th:value="${post.tittle}" /></td>
                <td><input type="text" th:field="${post.text}"
                    th:value="${post.text}" /></td>

                <td><select th:field="${post.user}">
                        <option th:each="user : ${users}" th:text="${user.username}"
                            th:value="${user.id}"></option>
                </select></td>


            </tr>
            <tr>
                <td colspan="3"><input class="btn btn-primary" type="submit"
                    value="GUARDAR"></td>
            </tr>

        </form> 

Атрибут действия в форме вызывает:

@PostMapping("/savePost")
//@RequestMapping(value = "users/save",method = RequestMethod.POST)
public String savePost(@ModelAttribute Post post) {

    postService.add(post);
    return "redirect:/posts";
}

На этом этапе япопробуйте создать сообщение и выбрать пользователя из выпадающего списка, но при попытке сохранить его выдает следующую ошибку:

Ошибка поля в объекте «запись» в поле «пользователь»: отклоненное значение [16];коды [typeMismatch.post.user, typeMismatch.user, typeMismatch.com.julian.bootmvchibernate.model.User, typeMismatch];Аргументы [org.springframework.context.support.DefaultMessageSourceResolvable: codes [post.user, user];аргументы [];сообщение по умолчанию [пользователь]];сообщение по умолчанию [Не удалось преобразовать значение свойства типа 'java.lang.String' в требуемый тип 'com.julian.bootmvchibernate.model.User' для свойства 'user';вложенным исключением является org.springframework.core.convert.ConversionFailedException: не удалось преобразовать тип [java.lang.String] в тип [@ javax.persistence.ManyToOne @ javax.persistence.JoinColumn com.julian.bootmvchibernate.model.User]для значения «16»;вложенным исключением является java.lang.NullPointerException]

Поэтому я попытался реализовать средство форматирования следующим образом:

public class UserFormatter implements Formatter<User> {

@Autowired
@Qualifier("userService")
public GeneralService<User> userService;

@Override
public String print(User object, Locale locale) {
    return (object != null ? object.getUsername() : "");
}

@Override
public User parse(String text, Locale locale) throws ParseException {
    final Integer userId = Integer.parseInt(text);
    return userService.get(userId);
}

}

Регистрация его:

@SpringBootApplication
public class BootmvchibernateApplication implements WebMvcConfigurer{

 @SuppressWarnings("unchecked")
    @Override
    public void addFormatters(FormatterRegistry registry) {
      registry.addFormatter(new UserFormatter());
    }



public static void main(String[] args) {
    SpringApplication.run(BootmvchibernateApplication.class, args);
}

}

Нопри использовании этого подхода обнаруживается следующая ошибка, которая просто открывает доступ к направлению / post / new (шаблон addPost не работает):

Произошла ошибка при разборе шаблона (template: "class path resource[templates / addPost2.html] ") org.thymeleaf.exceptions.TemplateInputException: при синтаксическом анализе шаблона произошла ошибка (template:" ресурс пути к классу [templates / addPost2.html] ") ...... Причина: org.attoparser.ParseException: Ошибка во время выполнения процессора 'org.thymeleaf.spring5.processor.SpringOptionFieldTagProcessor' (template: "addPost2" - строка 43, столбец 8) ..... Причина: org.springframework.core.convert.ConversionFailedException:Не удалось преобразовать тип [java.lang.String] в тип [@ javax.persistence.ManyToOne @ javax.persistence.JoinColumn com.julian.bootmvchibernate.model.User] fили значение «2»;Вложенным исключением является java.lang.NullPointerException по адресу org.springframework.core.convert.support.ConversionUtils.invokeConverter (ConversionUtils.java:47)

Если требуется дополнительная информация, сообщите мне, и я отправлю ее. РЕДАКТИРОВАТЬ: это хранилище, если кто-то заинтересован. github.com/JulianBautistaVelez/JPA_Spring_Excercise

1 Ответ

0 голосов
/ 15 октября 2019

Проблема в вашем addPost.html, за исключением того, что теперь все в порядке.

    <table>
        <form th:action="@{/posts/new/mod}" th:object="${post}"
            method="POST">
            <tr>
                <td><input type="hidden" th:field="${post.id}" /></td>
            </tr>
            <tr>
                <td>Titulo</td>
                <td>Texto</td>
                <td>Usuario</td>
            </tr>
            <tr>
                <td><input type="text" th:field="${post.tittle}"
                    th:value="${post.tittle}" /></td>
                <td><input type="text" th:field="${post.text}"
                    th:value="${newPost.text}" /></td>

                <!-- <td><select th:field="${newPost.user}">
                        <option th:each="user : ${users}" th:text="${user.username}"
                            th:value="${user.id}"></option>
                </select></td> -->

                <td><select th:field="*{user}" class="form-control">
                    <option th:each="user: ${users}"
                        th:value="${user.id}" th:text="${user.username}"></option>
                </select></td>


            </tr>
            <tr>
                <td colspan="3"><input class="btn btn-primary" type="submit"
                    value="GUARDAR"></td>
            </tr>

        </form>
    </table>

Я изменил newPost на post, потому что вы добавляете сюда как модель поста.

@RequestMapping(value = "/posts/new")
public String newPost(Model model) {
    logger.info("-- en NEW Usuario");
    model.addAttribute("post", new Post());
    model.addAttribute("users", userService.list());
    logger.info("-- -- -- LISTA DE USUARIOS -- -- --");
    System.out.println(userService.list());
    return "addPost";       
}
...