質問するログイン新規登録

回答編集履歴

2

修正

2020/02/07 07:08

投稿

rubytomato
rubytomato

スコア1752

answer CHANGED
@@ -124,4 +124,99 @@
124
124
 
125
125
  ```
126
126
  <input type="text" class="form-control" placeholder="id" id="id" name="id" th:value="${info.id}">
127
- ```
127
+ ```
128
+
129
+ ### 追記(2020/02/07)
130
+
131
+ > この時infoは⑤のところで引数として受け取っているので⑥でhello.htmlを呼び出したときに過去の入力値がth:field="*{id}"のようにして表示できるのはわかるのですが
132
+
133
+ 説明に不正確な点がありましたのでお詫びと訂正をさせて頂きます。
134
+ 下記のコードを『リダイレクト元からの情報を受け取るためにパラメータを定義』と説明しましたが、正確にはリダイレクト元でセットされたinfoはモデルの属性に存在しているので受け取るためだけであればパラメータの定義は不要です。
135
+
136
+ ```java
137
+ @GetMapping("/hello")
138
+ //★(2) リダイレクト元からの情報を受け取るためにパラメータを定義
139
+ public String hello(@ModelAttribute("info") LoginInfoBean info) {
140
+ return "hello";
141
+ }
142
+ ```
143
+
144
+ ただし、下記の実装だとリダイレクトしてきた時に、新しいインスタンスでモデルの属性のinfoを更新してしまいます。
145
+
146
+ ```java
147
+ @GetMapping("/hello")
148
+ public String hello(Model model) {
149
+ model.addAttribute("info", new LoginInfoBean());
150
+ return "hello";
151
+ }
152
+ ```
153
+
154
+ なので、直接アクセスとリダイレクトされてくることを意識したコードは、下記のようになります。
155
+
156
+ ```java
157
+ @GetMapping("/hello")
158
+ public String hello(Model model) {
159
+ // モデルの属性にinfoが存在しない場合は、インスタンスを生成してモデルの属性にセット。
160
+ // これは直接helloにアクセスするユーザーを想定した処理。
161
+ if (!model.containsAttribute("info")) {
162
+ model.addAttribute("info", new LoginInfoBean());
163
+ } else {
164
+ // モデルの属性にinfoが存在するということは、リダイレクト元でセットされている。
165
+ System.out.println(model.getAttribute("info"));
166
+ // 同様に、リダイレクト元でmessageがセットされていれば、モデルの属性にmessageも存在している。
167
+ System.out.println(model.getAttribute("message"));
168
+ }
169
+ return "hello";
170
+ }
171
+ ```
172
+
173
+ このコードを簡略化したのが、回答で提示した下記のコードになります。
174
+ 直接アクセスしたユーザーは生成された(空の)インスタンス、リダイレクトしてきたユーザーは元の入力情報を持つインスタンスがモデルの属性にセットされています。
175
+ ※helloメソッド内でinfoについて何か処理を行うということがなければ、このコードではなく上記のコードが適切かと思います。
176
+
177
+ ```java
178
+ @GetMapping("/hello")
179
+ public String hello(@ModelAttribute("info") LoginInfoBean info) {
180
+ return "hello";
181
+ }
182
+ ```
183
+
184
+ > redirectAttributes.addFlashAttribute("message", "認証に失敗しました");については何も指定しなくても表示できるのでしょうか?
185
+
186
+ messageについても、infoと同様にモデルの属性に存在していれば、テンプレート(html)で表示できます。
187
+
188
+ 最後にflashスコープについて補足致します。
189
+ bunkiメソッドでリダイレクト先にinfoやmessageを渡すために`addFlashAttribute`というメソッドを使っていますが、これはflashスコープというスコープに登録しています。
190
+ flashスコープとはリダイレクト先に情報を渡すためのスコープで一度だけ使えます。
191
+ 一度だけというのは、一度表示するとその情報は消えるという意味で、例えば認証成功後のokページでF5キーを押してページを更新するとメッセージは表示されません。
192
+
193
+ アクセスフローと併せてご覧ください。
194
+
195
+ ```
196
+ [client]
197
+ +--------+
198
+ | | redirect:hello
199
+ | | (flash = info,message)
200
+ | ---|-----------------------------------------------------------------------
201
+ | | | |
202
+ | | | |
203
+ | | | +---------+ +--------+ |
204
+ | ---|--> /hello -(2)-> | | | | - failure --
205
+ | | | hello | [post] | /bunki |
206
+ | ------|--> /hello -(1)-> | .html | (request = info) | | - success --
207
+ | | (request = info) +---------+ +--------+ |
208
+ | | |
209
+ | ---|-----------------------------------------------------------------------
210
+ | | | redirect:ok
211
+ | | | (flash = message)
212
+ | | | +----------+
213
+ | | | | |
214
+ | ---|-----------------------------------------------------> /ok -(3)-> | ok.html |
215
+ | | | |
216
+ | | +----------+
217
+ +--------+
218
+ ```
219
+
220
+ * /hello -(1)-> は、直接アクセスするユーザーの流れ、requestスコープに空のinfoを持つ
221
+ * /hello -(2)-> は、認証失敗でリダイレクトしたユーザーの流れ、info、messageをflashスコープに持つ
222
+ * /ok -(3)-> は、認証成功でリダイレクトしたユーザーの流れ、messsageをflashスコープに持つ

1

追記

2020/02/07 07:08

投稿

rubytomato
rubytomato

スコア1752

answer CHANGED
@@ -34,6 +34,7 @@
34
34
 
35
35
  ```
36
36
  @GetMapping("/hello")
37
+ //★(2) リダイレクト元からの情報を受け取るためにパラメータを定義
37
38
  public String hello(@ModelAttribute("info") LoginInfoBean info) {
38
39
  return "hello";
39
40
  }
@@ -51,6 +52,7 @@
51
52
  return "redirect:ok";
52
53
  }
53
54
 
55
+ //★(1) 認証失敗時の情報をリダイレクト先へ渡す
54
56
  redirectAttributes.addFlashAttribute("info", info);
55
57
  redirectAttributes.addFlashAttribute("message", "認証に失敗しました");
56
58
  return "redirect:hello";
@@ -64,9 +66,11 @@
64
66
 
65
67
  <div class="d-block mx-auto col-md-4">
66
68
  <div class="form-group">
69
+ <!--★(3) th:field="*{id}"でフォームにセット -->
67
70
  <input type="text" class="form-control" placeholder="id" th:field="*{id}">
68
71
  </div>
69
72
  <div class="form-group">
73
+ <!--★(4) th:field="*{pw}"でフォームにセット-->
70
74
  <input type="text" class="form-control" placeholder="pw" th:field="*{pw}">
71
75
  </div>
72
76
  <div class="form-group">
@@ -74,4 +78,50 @@
74
78
  </div>
75
79
  </div>
76
80
  </form>
81
+ ```
82
+
83
+ ### 追記(2020/02/06)
84
+
85
+ > ただ一点気になるところがあって、補足で教えていただいたものは元の入力値が認証失敗時にidとpw欄にそれぞれ入力されたままになるということでしょうか?
86
+ 上記のとおりやってみたのですが、失敗時はidもpwもクリアされてしまうようで…
87
+
88
+ 上記のコメントを受けて、改修案にコメントを追加しました。
89
+ 認証失敗時にフォーム画面に元の入力値を表示させるには下記4カ所のコードが必要です。
90
+ ★(1)~★(2)はリダイレクト間で情報を持ちまわすためのコード、★(3)、★(4)はリダイレクト元から持ちまわされた情報をフォームフィールドにセットするためのコードです。
91
+
92
+ **bunkiメソッド**
93
+
94
+ ```
95
+ //★(1) 認証失敗時の情報をリダイレクト先へ渡す
96
+ redirectAttributes.addFlashAttribute("info", info);
97
+ ```
98
+
99
+ **helloメソッド**
100
+
101
+ ```
102
+ //★(2) リダイレクト元からの情報を受け取るためにパラメータを定義
103
+ public String hello(@ModelAttribute("info") LoginInfoBean info)
104
+ ```
105
+
106
+ **hello.html**
107
+
108
+ ※関係のない部分は省略しています。
109
+
110
+ ```
111
+ <form th:action="@{/bunki}" th:object="${info}" method="post">
112
+
113
+ <!--★(3) th:field="*{id}"でフォームにセット -->
114
+ <input type="text" class="form-control" placeholder="id" th:field="*{id}">
115
+
116
+ <!--★(4) th:field="*{pw}"でフォームにセット-->
117
+ <input type="text" class="form-control" placeholder="pw" th:field="*{pw}">
118
+
119
+ </forM
120
+ ```
121
+
122
+ なお、`th:field="*{id}"`という書き方は、`th:field="${info.id}"`と同じ意味です。
123
+ さらには、少し冗長化して書くと下記のようになります。
124
+
125
+ ```
126
+ <input type="text" class="form-control" placeholder="id" id="id" name="id" th:value="${info.id}">
77
127
  ```