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

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

ただいまの
回答率

89.98%

spring 入力チェックエラー

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 8,190

kiichan

score 4

springエラーチェックを実装しています。
初期値が表示される商品更新画面で、入力値が未入力の場合に
未入力の文字を表示させます。

そこで、下記のエラーがでました。

java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'ItemForm' available as request attribute
調べると、 th:object="${ItemForm}"の値が使えていないなど考えらるみたいですが
formクラスのオブジェクトを使うのであっていると思うのですが

又、Exception evaluating SpringEL expression: "#fields.hasErrors('name')" と下記のHTML側で問題があるようで
調べています。

他に対処法として考えるべき点があれば教えていただきたいです。
初心者の為、いつもどうしようもない質問すみません。

1. ItemForm フォームクラス

package jp.co.sss.shop.form;

import javax.validation.constraints.Digits;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.web.multipart.MultipartFile;

public class ItemForm {
    private String id;

    @NotEmpty
    @Size(min = 1, max = 100)
    private String name;

    @NotEmpty
    @Digits(integer = 7, fraction = 0)
    private String price;

    @NotEmpty
    @Size(min = 1, max = 400)
    private String description;

    @NotEmpty
    @Digits(integer = 4, fraction = 0)
    private String stock;

    private MultipartFile imageFile;

    private String image;

    private String categoryId;

    private String categoryName;

    private  Integer count;




    public Integer getCount() {
        return count;
    }

    public void setCount(Integer count) {
        this.count = count;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

2.ItemUpdateAdminControllerコントローラー

package jp.co.sss.shop.controller.item;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;

import jp.co.sss.shop.bean.ItemBean;
import jp.co.sss.shop.entity.Category;
import jp.co.sss.shop.entity.Item;
import jp.co.sss.shop.form.ItemForm;
import jp.co.sss.shop.repository.CategoryRepository;
import jp.co.sss.shop.repository.ItemRepository;
import jp.co.sss.shop.util.BeanCopy;
import jp.co.sss.shop.util.Constant;

@Controller
public class ItemUpdateAdminController {
    @Autowired
    ItemRepository itemRepository;

    @Autowired
    CategoryRepository categoryRepository;

    @RequestMapping(path = "/item/update/input", method = RequestMethod.POST)
    public String updateInput(@ModelAttribute Integer id, Model model) {
        Item item = itemRepository.findOne(id);
        ItemBean itemBean = BeanCopy.copyEntityToBean(item);
        model.addAttribute("item", itemBean);
        return "item/update/item_update_input";
    }

    @RequestMapping(path = "/item/update/check", method = RequestMethod.POST)
    public String updateCheck(@Valid @ModelAttribute ItemForm form,BindingResult result,Model model) {

        if(result.hasErrors()){

            return  back(model,form);
        }




        if (form.getImageFile().getSize() > 0) {
            MultipartFile file = form.getImageFile();

            // アップロード対象のファイル名を取得
            String imageName = file.getOriginalFilename();

            // 現在の日時を「yyyyMMddhhmmss」形式の文字列として取得
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddhhmmss");
            String date = dateFormat.format(new Date());

            // ファイルのアップロード先を指定
            imageName = date + "_" + imageName;
            File uploadPath = new File(Constant.FILE_UPLOAD_PATH, imageName);

            try {
                // 指定されたファイルを一時的にアップロード
                file.transferTo(uploadPath);
            } catch (Exception e) {
                e.printStackTrace();
                return "error";
            }

            // 一時的にアップロードしたファイルの名前をFormクラスにセット
            form.setImage(imageName);
        } else {
            // 商品画像が未入力の場合、登録済みの画像ファイルを取得する
            Item item = itemRepository.findOne(Integer.parseInt(form.getId()));
            form.setImage(item.getImage());
        }

        // 選択したカテゴリの名前をFormクラスにセット
        Category category = categoryRepository.findOne(Integer.parseInt(form.getCategoryId()));
        form.setCategoryName(category.getName());

        return "item/update/item_update_check";
    }

    @RequestMapping(path = "/item/update/complete", method = RequestMethod.POST)
    public String updateComplete(@ModelAttribute ItemForm form) {
        // Formクラス内の各フィールドの値をエンティティにコピー
        Item item = BeanCopy.copyFormToEntity(form);
        item.setDeleteFlag(Constant.NOT_DELETED);

        itemRepository.save(item);

        return "item/update/item_update_complete";
    }

    @RequestMapping(path = "/item/update/input/back", method = RequestMethod.POST)
    public String back(Model model, @ModelAttribute ItemForm form) {
        // ItemFormクラスの各フィールドの値をItemBeanクラスにコピー
        ItemBean itemBean = BeanCopy.copyFormToBean(form);

        model.addAttribute("item", itemBean);
        return "item/update/item_update_input";
    }
}


3.item_update_check.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
    xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
    layout:decorator="common/layout_4block">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
    <th:block layout:fragment="layout-main">
        <div class="title">商品更新入力画面</div>
        <div class="container">
            <p>更新する商品を入力してください。</p>
            <form th:action="@{/item/update/check}" enctype="multipart/form-data" method="post" th:object="${ItemForm}">
                <div class="text">商品名</div>
                <div>
                    <input type="text" name="name" th:value="${item.name}" />
                    <span th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></span>
                </div>
                <div class="text">価格</div>
                <div>
                    <input type="text" name="price" th:value="${item.price}" />
                    <span th:if="${#fields.hasErrors('price')}" th:errors="*{price}"></span>
                </div>
                <div class="text">説明文</div>
                <div>
                    <textarea name="description" rows="6" th:field="${item.description}"></textarea>
                    <span th:if="${#fields.hasErrors('description')}" th:errors="*{description}"></span>
                </div>
                <div class="text">カテゴリ</div>
                <div>
                    <select name="categoryId">
                        <option th:each="category: ${session.categories}"
                            th:value="${category.id}" th:selected="${category.id == item.categoryId}" th:text="${category.name}"></option>
                    </select>
                </div>
                <div class="text">在庫数</div>
                <div>
                    <input type="text" name="stock" th:value="${item.stock}" />
                    <span th:if="${#fields.hasErrors('stock')}" th:errors="*{stock}"></span>
                </div>
                <div class="text">商品画像</div>
                <div>
                    <div class="value">
                        <span th:if="${item.image != null}">
                            <img th:src="@{/img/{image}(image=${item.image})}"></img>
                        </span>
                        <span th:if="${item.image == null}">
                            <img th:src="@{/img/common/no_image.png}"></img>
                        </span>
                    </div>
                    <div>
                        <input type="file" name="imageFile" />
                    </div>
                </div>
                <input type="hidden" name="id" th:value="${item.id}" />
                <input type="submit" value="送信" />
            </form>
            <form th:action="@{/item/list/admin}">
                <input type="submit" value="戻る" />
            </form>
        </div>
    </th:block>
</body>
</html>
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • A-pZ

    2018/03/18 20:19

    return "item/update/item_update_input"; で示されてるhtmlがないようですが、 item_update_checkと同じでしょうか?

    キャンセル

  • kiichan

    2018/03/18 21:48

    大変失礼致しました。はい上記でcheakと書いてしまいました。cheakではなくinputです。

    キャンセル

回答 2

+1

itemFormがnullまたは未定義なのでは?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/18 21:52

    上記の th:object="${ItemForm}"がnullか未定義ということでしょうか。。

    キャンセル

  • 2018/03/18 21:56

    ですね。
    updateInput を基点とすると発生しそうにみえますから

    キャンセル

  • 2018/03/19 23:07

    まだ解決はしていませんが、わかりやすいヒントをいつもありがとうございます。とても助かります。

    キャンセル

+1

(1) th:object="${ItemForm}" による java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'ItemForm' available as request attribute の問題について:

ItemFormクラスの内容を参照する場合は、単純に ${itemForm} で良いです。このとき、Controllerの引数に

@ModelAttribute ItemForm form


が必要です。

(2) Exception evaluating SpringEL expression: "#fields.hasErrors('name')" の問題について:

(1)の問題が発生すると立て続けにThymeleaf側で解析できないため出る問題です。(1)が解決できれば自動的に解決されます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/19 23:04

    回答いつもありがとうございます。
    とても助かりました。
    上記の内容を試すと画面遷移まではいきました。
    ただ、未入力にすると
    java.lang.IllegalArgumentException: null
    とエラーが消えません。
    コントローラーの return back(model,form);
    ItemBean itemBean = BeanCopy.copyFormToBean(form);が
    おかしいとコンソールにて出てしまいます。
    このような質問すみません。

    キャンセル

  • 2018/03/19 23:20

    ブラウザ上ではソースからターゲットにプロパティ 'count'をコピーできませんでした。ネストされた例外はjava.lang.IllegalArgumentException
    と表示されます。
    countはformクラスでしか定義していないのです。

    キャンセル

  • 2018/03/20 09:52

    ItemBean itemBean = BeanCopy.copyFormToBean(form); 入力フォームの内容をItemBeanにコピーするのは果たして正しいのでしょうか、という疑問がわきました。

    return back(model,form)を呼び出さず、
    if (result.hasErrors()) {
    model.addAttribute("item", form);
    }
    でも良いかと思います。

    キャンセル

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

  • ただいまの回答率 89.98%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る