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

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

ただいまの
回答率

90.36%

  • Java

    14362questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Spring

    731questions

    Spring Framework は、Javaプラットフォーム向けのオープンソースアプリケーションフレームワークです。 Java Platform上に、 Web ベースのアプリケーションを設計するための拡張機能が数多く用意されています。

  • Spring Boot

    568questions

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

SpringMVCの@ModelAttributeで毎回初期化されるのが無駄に感じます。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,100

msss

score 17

 環境

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
    <relativePath /> <!-- lookup parent from repository -->
</parent>

 以下のページを見ました

https://sites.google.com/site/soracane/home/springnitsuite/spring-mvc/04-ji-ben-gai-nian-controllerno-chu-lifuro

 サンプルとして載っているコード

@ModelAttribute("user")  //②モデルの前処理
public User newRequest(@RequestParam(required=false, value="id") String id) {
  if(id== null) return null;
  return this.accountService.get(id);
}

 以下が無駄だと思う理由です

(1).@ModelAttributeの呼び出し  : 事前準備として、DBからPOJOを取得して、Model に登録します。

(ModelAttributeメソッドでDBからPOJOを取得し、RequestMappingメソッドを呼び出すときにSpringが自動的に画面の値で必要なPOJOフィールドを更新する)

  • 調べてみたら確かに@RequestMappingの前に必ず@ModelAttributeが呼ばれて初期化する事を確認しました。
  • また、説明通り@RequestMappingで受け取るformは画面の値で上書きされていました。

画面の値で上書きするのであれば毎回初期化するのは無駄に感じます。
※特にDBにアクセスする場合は毎回SQL発行する事になる為

また、if(id== null) return null; に関して、初期化が必要ない場合はidが入ってこないからnullを返しているのかと考えましたが、'@ModelAttribute'でreturn null;してしまうと@RequestMappingの引数で受け取るformnullになってしまうためvalidate処理や画面表示が正しく行われない為目的は違うんだろうと判断しました。

みなさん気にならずにそのまま実装しているのでしょうか、または別の方法で実装されているのでしょうか。

 以下ならまだわからないでもないです

@ModelAttribute("user")  //②モデルの前処理
public User newRequest( @RequestParam(required=false, value="id") String id, User form) {
  if(id== null) return form;
  User user = this.accountService.get(id);
  BeanUtils.copyProperties(user, form);
  return form;
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • asahina1979

    2018/05/25 23:31

    つまり 1を変更した後に 存在しない2を変更しようとして1が更新された方がいいと?

    キャンセル

回答 1

checkベストアンサー

0

画面の値で上書きするのであれば毎回初期化するのは無駄

ここに認識の誤りがあるでしょう。参照されたサイトの「掲載されているコード」全部を見ると、

リクエストパラメータ(id, nameの2つ)を受け取り、

  • idが未指定なら検索しない→Controllerの本体へ
  • idに何らかの値があった場合はUserを取得→Controllerの本体へ
  @ModelAttribute("user")
  public User newRequest(
      @RequestParam(required=false, value="id") String id,
  ) {
      if(id== null) return null;
      return this.accountService.get(id);
  }

Userにはid,name以外のフィールドがあるが(feeId)、画面から受け取るのはid, nameだけである。

    @InitBinder("user")
    public void initBinder(WebDataBinder binder) {
        binder.setAllowedFields("id", "name");
    }

Controller本体の処理は以下

  @RequestMapping(value="/accountEdit", method=RequestMethod.POST)
  public String form(@Valid @ModelAttribute("user") User user, BindingResult result) {
     if(result.hasErrors()){
       return "account-edit-input";
     }
     this.accountService.updateUser(user);
     return "account-edit-complete";
  }

なので、流れとしては以下ですね。AccountServiceの作りを変えない前提ならば、特に無駄はありません。

  1. リクエストパラメータにidが指定されていれば、idを元にUserを検索
  2. Controllerの本体へ処理が移動したときは、1で取得したUserのnameにリクエストパラメータの内容が入る( idは検索時と同じ ) このとき、該当するUserが取得できていなければUserはnullになる。
  3. accountServiceのupdateUser(user) で更新する

ところで、

 以下ならまだわからないでもないです

のコードを拝見しましたが、

this.accountService.updateUser(user) が抜けていませんか?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/05/27 10:56

    回答ありがとうございます。
    わかりやすい解説をしていただいたことで頭の中が整理できました。

    ・idが入っていない=エラーのため"account-edit-input";に遷移させる。
    ・idが入っている場合画面入力値以外の項目(feeId)も更新に必要なので取得してリクエストパラメータで上書きして更新

    確かに、SampleControllerクラスに@RequestMappingのメソッドが1つしかないので無駄に感じませんでした。

    例えば
    @RequestMappingが複数あった場合、@ModelAttributeが呼び出される度にDBアクセスが必要ない場合、@RequestMappingにDBアクセス処理を書くというイメージを持っていますが、間違っているでしょうか。


    以下の内容から、@ModelAttributeでは画面に必要なデータをDBから取得するというイメージを持ってしまいましたが、時と場合(画面設計)によるということでよいでしょうか。
    >【通常のControllerの処理の流れ】
    >(1).@ModelAttributeの呼び出し  : 事前準備として、DBからPOJOを取得して、Model に登録します。

    キャンセル

  • 2018/05/28 07:25

    はっw entityを直接 form として利用するソースなのか

    キャンセル

  • 2018/05/28 11:34

    ご指摘ありがとうございます。
    entity=formついては確かに疑問を感じる点はありましたが今回は気にしませんでした。

    キャンセル

  • 2018/05/28 19:15

    無駄になるかどうかは、Controller~Serviceの設計次第ではありますね。
    実際、 ModelAttributeにて実際に検索するのはトリッキーなコードにも思えます。

    キャンセル

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

  • Java

    14362questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Spring

    731questions

    Spring Framework は、Javaプラットフォーム向けのオープンソースアプリケーションフレームワークです。 Java Platform上に、 Web ベースのアプリケーションを設計するための拡張機能が数多く用意されています。

  • Spring Boot

    568questions

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