質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
Spring MVC

Spring MVCとは、Javaを用いてWebアプリケーションを開発できるフレームワーク。アーキテクチャにMVCを採用しており、画面遷移と入出力パラメータの受け渡しの基本的な機能の他、ユーザーの送信したパラメータに対する入力チェックなどさまざまな機能を持ちます。

Thymeleaf

Thymeleaf(タイムリーフ)とは、Java用のテンプレートエンジンで、特定のフレームワークに依存せず使用することが可能です。

Spring Boot

Spring Bootは、Javaのフレームワークの一つ。Springプロジェクトが提供する様々なフレームワークを統合した、アプリケーションを高速で開発するために設計されたフレームワークです。

Q&A

解決済

1回答

1242閲覧

th:fieldに値を持たせても画面遷移時に値がnullになる

gdet_hry

総合スコア1

Spring MVC

Spring MVCとは、Javaを用いてWebアプリケーションを開発できるフレームワーク。アーキテクチャにMVCを採用しており、画面遷移と入出力パラメータの受け渡しの基本的な機能の他、ユーザーの送信したパラメータに対する入力チェックなどさまざまな機能を持ちます。

Thymeleaf

Thymeleaf(タイムリーフ)とは、Java用のテンプレートエンジンで、特定のフレームワークに依存せず使用することが可能です。

Spring Boot

Spring Bootは、Javaのフレームワークの一つ。Springプロジェクトが提供する様々なフレームワークを統合した、アプリケーションを高速で開発するために設計されたフレームワークです。

0グッド

0クリップ

投稿2023/10/25 18:29

編集2023/10/25 18:31

実現したいこと

  • 画面遷移時に登録画面に入力した値をDBに正常に登録して、顧客リストを表示したい

前提

初投稿です。
下記サイトを基に、Spring boot を用いて顧客情報システムを作成しています。
(プログラミング逆引き辞典 SpringBoot入門:
https://learning-collection.com/springboot%e5%85%a5%e9%96%80/)
vol.9まではなんとかできたのですが、vol.10で躓いています。
具体的には、
登録画面 → DBに入力情報送信 → 顧客リスト表示
という流れが上手く行きません。
ディレクトリ構造は以下の通りです。
イメージ説明

発生している問題・エラーメッセージ

とても長いので、エラーメッセージの上部分と、Caused byの部分を切り取ってお載せします。

Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback. Thu Oct 26 02:42:03 JST 2023 There was an unexpected error (type=Internal Server Error, status=500). not-null property references a null or transient value : com.example.demo.domain.Customer.name org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value : com.example.demo.domain.Customer.name ~略~ Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value : ~略~

該当のソースコード

(見苦しい点あると思いますが、ご容赦ください)
↓CustomerController.java (コントローラー)

Java

1package com.example.demo.web; 2 3import java.util.List; 4 5import org.springframework.beans.BeanUtils; 6import org.springframework.beans.factory.annotation.Autowired; 7import org.springframework.stereotype.Controller; 8import org.springframework.ui.Model; 9import org.springframework.web.bind.annotation.GetMapping; 10import org.springframework.web.bind.annotation.ModelAttribute; 11import org.springframework.web.bind.annotation.PostMapping; 12 13import com.example.demo.domain.Customer; 14import com.example.demo.service.CustomerService; 15 16@Controller //コントローラークラスを示す 17public class CustomerController { 18 @Autowired 19 CustomerService customerService; 20 21 @GetMapping("/") //HTTPリクエストのGETメソッドが呼ばれた時にそのメソッドで処理をする 22 String list(Model model) { 23 List<Customer> customers = customerService.findAll();//customerService.findAll()メソッドでDBのレコードを取得 24 model.addAttribute("customers", customers); 25 return "list"; 26 } 27 28 @GetMapping("create")// http://localhost/create/へのGETリクエスト時の処理 29 String create(@ModelAttribute CustomerForm customerForm) { 30 //↑Modelオブジェクトにセット 31 //model.addAttribute("customerForm", customerForm)と同様の処理をする 32 return "create"; 33 } 34 35 @PostMapping("create") //URLクエリにcreateを設定したPOSTリクエスト. 顧客登録画面の登録ボタンを押した時に呼ばれるメソッド 36 String regist(@ModelAttribute("customerForm") CustomerForm customerForm) { 37 Customer customer = new Customer(); //Customerクラスからcustomerインスタンスを生成 38 BeanUtils.copyProperties(customerForm, customer); //customerFormの値をcustomerにコピー, つまり、新規登録画面で入力した値をCustomerクラスのインスタンスにコピーしている 39 customerService.insert(customer); //CustomerServiceクラスに登録したinsert()メソッドを使用 40 return "redirect:/"; //顧客登録画面にリダイレクト 41 } 42 43}

↓create.html (登録画面)

html

1<!DOCTYPE html> 2<html xmlns:th="http://www.thymeleaf.org"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>顧客登録</title> 6 </head> 7 <body> 8 <h1>顧客登録</h1> 9 <form th:action="@{/create}" th:object="${customerForm}" method="post"> 10 <table> 11 <tr> 12 <th>名前</th> 13 <td><input type="text" name="name" th:field="*{name}"></td> 14 </tr> 15 <tr> 16 <th>メールアドレス</th> 17 <td><input type="text" name="email" th:field="*{email}"></td> 18 </tr> 19 </table> 20 <input type="submit" value="登録"> 21 </form> 22 </body> 23</html>

↓list.html (顧客リスト表示画面)

html

1<!DOCTYPE html> 2<html xmlns:th="http://www.thymeleaf.org"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>顧客一覧</title> 6 </head> 7 <body> 8 <a th:href="@{/create}">顧客登録</a> 9 <hr> 10 <h1>顧客一覧</h1> 11 <table> 12 <tr> 13 <th>ID</th> 14 <th>名前</th> 15 <th>メールアドレス</th> 16 </tr> 17 18 <tr th:each="customer : ${customers}"> 19 <td th:text="${customer.id}"></td> 20 <td th:text="${customer.name}"></td> 21 <td th:text="${customer.email}"></td> 22 </tr> 23 </table> 24 </body> 25</html>

↓CustomerForm.java (入力内容を渡すクラス)
※@Dataアノテーションが上手く働いていないっぽいので、getter, setterを明示的に入れています。

Java

1package com.example.demo.web; 2 3import lombok.Data; 4 5@Data 6public class CustomerForm { 7 // 画面とコントローラークラスの間で値を渡す役割をする。 8 private Integer id; 9 private String name; 10 private String email; 11 12//以下、@Dataアノテーションが上手く働いていないっぽいので、getter, setterを明示的に入れている 13//以下を抜くと動かなくなる 14 public void setId(Integer id) { 15 this.id = id; 16 } 17 18 public Integer getId() { 19 return id; 20 } 21 22 public void setName(String name) { 23 this.name = name; 24 } 25 26 public String getName() { 27 return name; 28 } 29 30 public void setEmail(String email) { 31 this.email = email; 32 } 33 34 public String getEmail() { 35 return email; 36 } 37}

↓Customer.java
※教材ではprivateでid, name emailを定義してましたが、publicにしろとのエラーが出たので、publicに変えています。

Java

1package com.example.demo.domain; 2 3import jakarta.persistence.Column; 4import jakarta.persistence.Entity; 5import jakarta.persistence.GeneratedValue; 6import jakarta.persistence.GenerationType; 7import jakarta.persistence.Id; 8import jakarta.persistence.Table; 9 10import lombok.AllArgsConstructor; 11import lombok.Data; 12import lombok.NoArgsConstructor; 13 14@Entity //JPAのエンティティであることを示す 15@Table(name="customer") //エンティティに対応するテーブル名を指定 16@Data //getter, setterメソッド等を生成 17@AllArgsConstructor //すべての引数を持つコンストラクタを生成 18@NoArgsConstructor //引数を持たないコンストラクタを生成 19public class Customer { 20 @Id //エンティティの主キー 21 @GeneratedValue(strategy = GenerationType.IDENTITY) //主キーが自動採番されることを示す 22 public Integer id; 23 @Column(nullable = false) //NotNull制約を示す 24 public String name; 25 public String email; 26} 27

↓CustomerService.java

Java

1package com.example.demo.service; 2 3import java.util.List; 4 5import org.springframework.beans.factory.annotation.Autowired; 6import org.springframework.stereotype.Service; 7import org.springframework.transaction.annotation.Transactional; 8//import org.springframework.context.annotation.Configuration; 9 10import com.example.demo.domain.Customer; 11import com.example.demo.repository.CustomerRepository; 12 13@Service //サービスクラスであることを示し、クラスのBeanをDIコンテナに登録する 14@Transactional //DBのトランザクション制御 15public class CustomerService { 16 @Autowired// DIを行う為に@Autowiredを付与する 17 CustomerRepository customerRepository; 18 public List<Customer> findAll(){ 19 //JpaRepositoryインターフェースを継承している為、customerRepository.findAllメソッドで 20 //「SELECT * FROM CUSTOMER」相当の処理を行う。 21 return customerRepository.findAllOrderById(); 22 } 23 24 public void insert(Customer customer) { //Customerクラスのcustomerテーブルに対してインサート 25 customerRepository.save(customer); 26 } 27 28 public void update(Customer customer) { //更新処理 29 customerRepository.save(customer); 30 } 31 32 public void delete(Integer id) { //削除処理 33 customerRepository.deleteById(id); 34 } 35 36 public Customer getReferenceById(Integer id){ //1件取得(https://b1san-blog.com/post/spring/spring-jpa/で修正) 37 return customerRepository.findById(id).orElseThrow(); 38 } 39 40}

↓CustomerRepository.java

Java

1package com.example.demo.repository; 2 3import java.util.List; 4 5import org.springframework.data.jpa.repository.JpaRepository; 6import org.springframework.data.jpa.repository.Query; 7 8import com.example.demo.domain.Customer; 9 10public interface CustomerRepository extends JpaRepository<Customer, Integer> { 11// JpaRepositoryを継承 12 @Query("SELECT u FROM Customer u ORDER BY u.id") //テーブル名(u)が抜けていた 13 List<Customer> findAllOrderById(); 14}

試したこと

 こちら (https://stackoverflow.com/questions/6389600/not-null-property-references-a-null-or-transient-value) によると、「まだDBに保存されていない外部オブジェクトを参照している」とあるので、DBへの登録時にnullの値を入れようとしてしまっているためにDBに登録できず、発生しているエラーだと考えました。

 そこで、customerFormの中身がnullになっているかどうかを確かめましたが、System.out.println(オブジェクト名) で標準出力しても値を見ることができず、確かめることが出来ませんでした。

 また、こちら (https://teratail.com/questions/81322) によると、th:fieldに値をもたせることで、POSTリクエストにデータを送ることが出来るとあったのですが、th:fieldに値を持たせても、DBに登録ができないようでした。

 また、こちら (https://kikutaro777.hatenablog.com/entry/2014/04/15/230916) から、BeanUtils.copyPropertiesの参照順序が違うかと考え、順序を変えたりもしましたが、ダメでした。

 

補足情報(FW/ツールのバージョンなど)

Spring boot 3.1.5
Java 17

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KT001

2023/10/26 10:56

EclipseにLombokはインストールしているでしょうか。「@Dataアノテーションが上手く働いていないっぽい」とのことなので、Lombokのインストールが上手くいっていない可能性があります。 https://web-dev.hatenablog.com/entry/eclipse/lombok
gdet_hry

2023/10/26 12:15

KT001様 コメントありがとうございます! いま、lombokをインストールしたところ無事にDBに登録できました! おそらくですが、lombokが無いことでCustomer.javaでgetter/setterが付与されず、@PostMappingのcustomerオブジェクトが上手く作れていなかったのでしょうか? なんにせよ、本当にありがとうございました。 もしよろしければベストアンサーにさせていただきたいので、回答に記載していただいてもよろしいでしょうか。
KT001

2023/10/26 14:03

動いて良かったです!EntityにはGetter/Setterが必要なので、Customer.javaの値の設定と参照ができなかったのだと思います。 同じ内容ではありますが、回答の方にも記載させて頂きました。
guest

回答1

0

ベストアンサー

EclipseにLombokはインストールしているでしょうか。「@Dataアノテーションが上手く働いていないっぽい」とのことなので、Lombokのインストールが上手くいっていない可能性があります。
https://web-dev.hatenablog.com/entry/eclipse/lombok

投稿2023/10/26 14:03

KT001

総合スコア668

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gdet_hry

2023/10/26 14:24 編集

こちらで解決いたしました、ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問