SpringBoot初心者です。
@ManyToOne,@OneToManyを利用し、ブログ(blogクラス)に対してのコメント(commentクラス)機能を追加できるようにしたいのですが「フィールド「ブログ」のオブジェクト「コメント」のフィールドエラー」という内容でエラーが生じコメントが表示されません。
①ブログは複数のコメントを持ち(1対多)、コメントは1つのブログに結びついている(多対1)。
②blog,commentに各リポジトリインタフェースを作成。
③コントローラにblogページを表示する際にcommentオブジェクトを作成しModelに追加。commentリポジトリインタフェースを使用し、フォーム送信された内容に投稿日時を付加して保存する。
XAMPPのMySQLを使用してます。commentテーブルにblog_idは生成されてリレーションはできているはずですが、結果表示が思うようにいきません。
フィールドの誤字や引数に間違いがあるのではと思い確認しましたが特に間違いはありませんでした。
ご教授願います。
application.properties
spring.jpa.hibernate.ddl-auto=update spring.datasource.url=jdbc:mysql://localhost:3306/データベース名?serverTimezone=JST spring.datasource.username=ユーザー名 spring.datasource.password=パスワード
blog.java
package com.example.demo; import java.time.LocalDateTime; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import lombok.Data; @Entity //JPAにテーブルに保存するクラス(エンティティ)であることを示す。 @Data public class Blog { @Id //対応するテーブルのプライマリーキー(主キー)となるフィールド @GeneratedValue(strategy=GenerationType.AUTO) //プライマリーキーの値を連番で自動生成。 private Integer id; private String title; private LocalDateTime postDateTime; @Column(length=1000) //テーブルの列を制御したい場合は@Columnをつける。フィールドの長さをデフォルトの255から1000にする。 private String contents; @OneToMany(mappedBy = "blog", cascade = CascadeType.ALL) //mappedBy引数には「相手側が自分を参照する名前」を指定。 private List<Comment> comments; public void addComment(Comment comment) { comment.setBlog(this); comments.add(comment); } }
comment.java
package com.example.demo; import java.time.LocalDateTime; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.ManyToOne; import lombok.Data; @Entity @Data public class Comment { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String text; private LocalDateTime postDateTime; @ManyToOne //多対1の関係。Commentは一つブログに結びついている。 private Blog blog; } }
BlogRepository.java
package com.example.demo; import org.springframework.data.jpa.repository.JpaRepository; public interface BlogRepository extends JpaRepository<Blog, Integer> { }
CommentRepository.java
package com.example.demo; import org.springframework.data.jpa.repository.JpaRepository; public interface CommentRepository extends JpaRepository<Comment, Integer>{ }
SampleController.java
package com.example.demo; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.Transactional; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @Controller public class SampleController { @Autowired //リポジトリインターフェース参照、追加、更新などのメソッドがあらかじめ定義されている。findAllメソッドを使用することで単純にテーブル内のレコードを一覧で返す。 private BlogRepository blogRepository; @Autowired private CommentRepository commentRepository; @GetMapping("/") public String index(Model model) { List<Blog> blogs = blogRepository.findAll(); model.addAttribute("blogs", blogs); return "index"; } @GetMapping("/form") public String form(Blog blog) { return "form"; } @PostMapping("/create") public String create(Blog blog) { blog.setPostDateTime(LocalDateTime.now()); blogRepository.save(blog); //エンティティを保存するにはリポジトリインターフェースのsaveメソッドを使用。 //エンティティをsaveすると@Idアノテーションを付けたフィールドに値が設定される。 return "redirect:/blog/" + blog.getId(); } @GetMapping("/blog/{id}") public String blog(@PathVariable Integer id, Model model) { Optional<Blog> blog = blogRepository.findById(id); //返されたオブジェクトがnullでなければこの処理を行うなど、nullの場合の処理を書きやすくするためのもの。 //getメソッドを呼び出して中身を取り出す。 model.addAttribute("blog", blog.get()); Comment comment = new Comment(); comment.setBlog(blog.get()); model.addAttribute("comment", comment); return "/blog"; } @Transactional @PostMapping("/blog/{blogId}/comment") public String createComment(@PathVariable("blogId") Integer id, Comment comment) { comment.setPostDateTime(LocalDateTime.now()); Optional<Blog> optionalBlog = blogRepository.findById(id); Blog blog = optionalBlog.orElseThrow(RuntimeException::new); blog.addComment(comment); blogRepository.save(blog); return "redirect:/blog/" + id; } }
blog.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title th:text="${blog.title}">ブログタイトル</title> </head> <body> <p> <a href="/">一覧に戻る</a> </p> <div th:object="${blog}"> <h1 th:text="*{title}">タイトル</h1> <div> 投稿日時 <span th:text="*{postDateTime}">投稿日時</span> </div> <p> <th:block th:each="line : *{contents.split('\n')}"> <th:block th:text="${line}"></th:block><br> </th:block> </p> <form th:action="@{/blog/{blogId}/comment(blogId=${blog.id})}" method="post" th:object="${comment}"> コメントをどうぞ<br> <input type="hidden" name="blog" th:value="*{blog.id}"> <input type="text" size="40" th:field="*{text}"> <input type="submit"> </form> <ul> <li th:each="c : *{comments}" th:object="${c}"> <span th:text="*{postDateTime}"></span> <span th:text="*{text}"></span> </li> </ul> </div> </body> </html>
エラー内容
Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback. Mon Jun 15 17:32:58 JST 2020 There was an unexpected error (type=Bad Request, status=400). Validation failed for object='comment'. Error count: 1 org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors Field error in object 'comment' on field 'blog': rejected value [4]; codes [typeMismatch.comment.blog,typeMismatch.blog,typeMismatch.com.example.demo.Blog,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [comment.blog,blog]; arguments []; default message [blog]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'com.example.demo.Blog' for property 'blog'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'com.example.demo.Blog' for property 'blog': no matching editors or conversion strategy found]
index.html(トプページ。配列でblogタイトルと日時を出し、aタグでidのページに行きます)
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org/"> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <p> <a href="/form">新規作成</a> </p> <ul> <li th:each="blog : ${blogs}" th:object="${blog}"> <a th:href="@{|/blog/*{id}|}" th:text="*{title}">タイトル</a> <span th:text="*{postDateTime}">投稿日時</span> </li> </ul> </body> </html>
form.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>新規ブログ</title> </head> <body> <form action="/create" method="post" th:object="${blog}"> <div> タイトル<br> <input type="text" size="40" th:field="*{title}"> </div> <div> 内容<br> <textarea rows="5" cols="60" th:field="*{contents}"></textarea> </div> <div> <input type="submit"> </div> </form> </body> </html>
回答1件
あなたの回答
tips
プレビュー