通过Thymeleaf模板在SPRING应用程序中传递已更改的子对象的问题

时间:2018-10-20 14:36:37

标签: spring thymeleaf

我是SPING和Web开发的新手。

我正在开发测试任务-报价书(未经授权)。我有两个实体:Quote和Author。有代码:

@Entity
@Table(name="authors")
public class Author {
    @Id
    @SequenceGenerator(name="author_id_seq", sequenceName="author_id_seq", allocationSize=1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "author_id_seq")
    @Column(name = "id")
    private long id;

    @Column(name = "nick_name")
    private String nickName;

    public Author() {
    }

    public Author(long id, String nickName) {
        this.id = id;
        nickName = nickName;
    }
/*
Getters and Setters
*/
}

报价:

@Entity
@Table(name = "quotes")
public class Quote {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "quotes_id_seq")
    @SequenceGenerator(name="quotes_id_seq", sequenceName="quotes_id_seq", allocationSize=1)
    @Column(name = "id")
    private long id;
    @Column(name = "content")
    private String content;
   // @Temporal(TemporalType.DATE)
    @Column(name = "date")
    private LocalDate date;
    @ManyToOne
    @JoinColumn(name = "author")
    private Author author;

    public Quote() {
    }

    public Quote(long id, String content, LocalDate date, Author author) {
        this.id = id;
        this.content = content;
        this.date = date;
        this.author = author;
    }
/*
Getters and Setters
*/
}

我的Thymeleaf模板包含带有两个输入字段的表单(quote.content和quote.author.nickName),并使用现有作者进行选择。我想看看这种行为,当我填写作者,内容的输入,并且如果authors表中不存在author时,我的应用程序将在表中添加行,该行由输入的nickName和生成的id中的值指定。但是问题是从Thymeleaf模板为我获得意想不到的结果。模板将带有作者的Quote对象传递给控制器​​,该对象的昵称为null而不是我输入的值。我的表单中有thymeleaf模板代码:

 <form action="#" th:action="@{/newQuote}" th:object="${quote}" method="post">
                <div class="form-row">
                    <div class="form-group col-md-3">
                        <label class="sr-only" for="inputNick">Nick Name</label>
                        <!--/*@thymesVar id="author" type="hello.entity.Author"*/-->
                        <input type="text" class="form-control" id="inputNick" th:field="*{author.nickName}"
                               placeholder="enter Nick Name">
                    </div>
                    <div class="form-group col-md-6">
                        <select id="nickNames">
                            <th:block th:each="author : ${allAuthors}">
                                <option th:text="${author.nickName}">Nick Name</option>
                            </th:block>
                        </select>
                    </div>
                    <div class="form-group col-md-12">
                        <label for="postContent">Your Quote:</label>
                        <input type="text" class="form-control" id="postContent" th:field="*{content}"
                               placeholder="quote text">
                    </div>
                </div>

                    <div class="form-group col-md-2">
                        <input type="submit" value="Add Quote"/>
                    </div>
                    <div class="form-group col-md-2">
                        <input type="reset" value="Reset"/>
                    </div>

            </form>

控制器方法:

@GetMapping("/newQuote")
    public String showAuthors(Model model){
        model.addAttribute("allAuthors",authorService.findAll());
        model.addAttribute("quote", new Quote());
        return "newQuote";
    }

    @PostMapping("/newQuote")
    public String addQuote (@ModelAttribute Quote quote) {
        quote.setDate(LocalDate.now());
        quoteRepository.save(quote);
        return "redirect:/";

我尝试过:

  1. 要在GetMapping中添加Author对象,请在newQuote模板中传递它, 从它传递到PostMapping-无效。昵称为空。
  2. 要在报价对象中创建并插入作者对象,请传递至 模板,传递到后映射。没有效果

我知道我可以使用字段昵称而不是作者字段创建DTO类,并在控制器的后映射方法中将其转换为我的实体类。但我认为这是“不良做法”的方式。我认为,当尝试更改作者对象并将其从百里香叶传递给控制器​​时,我可能采取了错误的步骤。而且我想,在这种情况下没有办法实现这种逻辑。我不知道真相在哪里。请帮我找到它。

P.S:对不起,我的英语不好

1 个答案:

答案 0 :(得分:0)

因此,答案是询问如何添加引号及其作者。使用选择方法是不可能的,因为我们的作者不存在。实现此目的的简单方法是更改​​报价实体,并将@Cascade(CascadeType.PERSIST)添加到报价的作者字段中。这将自动为作者保留您的报价。

这些就是完成此操作所需的代码更改。

更新

由于最后一个解决方案不起作用,我们将尝试向控制器发送一个附加参数,以避免收到空值,而不是作者的昵称。

控制器

@PostMapping("/newQuote")
public String addQuote (@ModelAttribute Quote quote,
                        @RequestParam("nickName") String nickName) {
    // This will automatically persist your quote and it's author.
    quote.setDate(LocalDate.now());
    Author author = new Author();
    author.setNickName(nickName);
    quoteRepository.save(quote);
}

报价实体

@Entity
@Table(name = "quotes")
public class Quote {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "quotes_id_seq")
    @SequenceGenerator(name="quotes_id_seq", sequenceName="quotes_id_seq", allocationSize=1)
    @Column(name = "id")
    private long id;

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

    @Column(name = "date")
    private LocalDate date;

    @ManyToOne
    @Cascade(CascadeType.PERSIST)
    @JoinColumn(name = "author")
    private Author author;

    // Getters and Setters
}

重要,请确保注意我们正在向作者字段添加新的注释@Cascade(CascadeType.PERSIST)

HTML

在这里,我们将删除不必要的选择。

<form action="#" th:action="@{/newQuote}" th:object="${quote}" method="post">
    <div class="form-row">
        <div class="form-group col-md-3">
            <label class="sr-only" for="inputNick">Nick Name</label>
            <!--/*@thymesVar id="author" type="hello.entity.Author"*/-->
            <input type="text" name="nickName" class="form-control" id="inputNick" placeholder="enter Nick Name"/>
        </div>
        <div class="form-group col-md-12">
            <label for="postContent">Your Quote:</label>
            <input type="text" class="form-control" id="postContent" th:field="*{content}" placeholder="quote text"/>
        </div>
   </div>
   <div class="form-group col-md-2">
       <input type="submit" value="Add Quote"/>
   </div>
   <div class="form-group col-md-2">
      <input type="reset" value="Reset"/>
   </div>
</form>