java - Spring MVCでユーザー入力をBigDecimalオブジェクトフィールドにバインドするにはどうすればよいですか?

okwaves2024-01-25  8

私のプロジェクトには、フィールドの 1 つとして BigDecimal を含むクラスがあります。

@Entity
public class Product {

    // ...
   
    @DecimalMin("0.01")
    private BigDecimal price;

    // ...
}

thymeleaf には、このクラスのフィールドの入力を含むフォームがあり、価格を担当するフォームは次のとおりです。

<form ...>
   <input type="number" step="any" th:field="*{price}">
</form>

このフォームから @ModelAttribute が返されると、製品の価格フィールドは null になります。価格が2倍だった頃も使えました。どうすればこれを機能させることができますか?回避策を考えました。この入力を @RequestParam として指定し、double 値を使用して Product.price を「手動で」初期化します。しかし、thymeleaf がそれを行うための解決策はありますか?



------------------------

これでうまくいくはずです。テストしたばかりですこれは、次のように Spring Boot 2.3.0 を使用して行います。

フォームにエンティティを直接使用すると、IMO のリポジビリティが乱雑になりすぎるため、フォーム データ オブジェクトを使用しています。

import javax.validation.constraints.DecimalMin;
import java.math.BigDecimal;

public class ProductFormData {

    @DecimalMin("0.01")
    private BigDecimal price;

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }
}

次のようなコントローラを使用します:

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/product")
public class ProductController {

    @GetMapping
    public String product(Model model) {
        model.addAttribute("product", new ProductFormData());
        return "product";
    }

    @PostMapping
    public String doSaveProduct(@ModelAttribute("product") ProductFormData formData) {
        System.out.println("formData = " + formData.getPrice());

        return "redirect:/product";
    }
}

product.html テンプレートは次のようになります。

<!DOCTYPE html>
<html lang="en" xmlns:th="http:www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Product</title>
</head>
<body>
<h1>Product</h1>
<form th:action="@{/product}" th:object="${product}" method="post">
    <input type="number" step="any" th:field="*{price}">
    <button type="submit">submit</button>
</form>
</body>
</html>

フォームに数値を入力して「送信」を押すと、コンソールに値が表示されます。

4

DTO のようなものですか?フォームからデータを取得するだけのオブジェクトのようなものですか? (エンティティ オブジェクトの作成にはどちらが使用されますか?)パフォーマンスは?

– ジョニーブラボー

2020 年 9 月 5 日 16:29

1

確かに。次に、ProductFormData に toProduct() メソッドを持たせるか、ProductFormData をサービス メソッド (例: service.addProduct(ProductFormData)) に渡すか、ProductFormData を AddProductParameters に変換します (例: service.addProduct(formData.toProductParameters()))。これにより、エンティティにリッチなドメイン モデルを使用できるようになります。これがパフォーマンス上の問題となる状況は見たことがありません。

– ヴィム・デブラウウェ

2020 年 9 月 5 日 16:32

「エンティティのリーチ ドメイン モデル」により、たとえば、何らかの方法でエンティティ クラスを拡張したいという状況を指しますか?ところで、ご回答いただきありがとうございます。回答は本当に役に立ちますが、ProductFormData を使用するメリットが完全には理解できません。

– ジョニーブラボー

2020 年 9 月 5 日 16:49

1

つまり、ProductFormData は通常、String、int、BigDecimal を使用します。エンティティ内のどこで、Price クラスまたは Quantity クラスを使用することもできます。おそらく、Product にはサプライヤー参照がありますが、ProductFormData では、Thymeleaf フォームにバインドしやすいため、文字列のsupplierId を使用します。

– ヴィム・デブラウウェ

2020 年 9 月 5 日 16:52

総合生活情報サイト - OKWAVES
総合生活情報サイト - OKWAVES
生活総合情報サイトokwaves(オールアバウト)。その道のプロ(専門家)が、日常生活をより豊かに快適にするノウハウから業界の最新動向、読み物コラムまで、多彩なコンテンツを発信。