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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Java

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

Bootstrap

BootstrapはウェブサイトデザインやUIのWebアプリケーションを素早く 作成する可能なCSSフレームワークです。 Twitter風のデザインを作成することができます。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Spring Boot

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

Q&A

解決済

1回答

22570閲覧

Springbootで画面遷移したときのURLについて

moshi

総合スコア90

Java

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

Bootstrap

BootstrapはウェブサイトデザインやUIのWebアプリケーションを素早く 作成する可能なCSSフレームワークです。 Twitter風のデザインを作成することができます。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Spring Boot

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

0グッド

0クリップ

投稿2020/02/05 08:34

前提・実現したいこと

ログイン画面でID,PWがあっていたら次の画面へ
間違っていたらメッセージを出して再びログイン画面へ
という処理をしています。
上記自体はできたのですが、画面遷移をしたときにURLが思っているものになりません。
どうすればいいでしょうか?

ファイル構成

ファイルの構成です
イメージ説明

該当のソースコード

LoginInfoBean.java

Java

1@Data 2public class LoginInfoBean { 3 4 private String id; 5 private String pw; 6 7}

MainController.java

Java

1@Controller 2public class MainController { 3 4 @GetMapping("/hello") 5 public String hello(Model model) { 6 model.addAttribute("info", new LoginInfoBean()); 7 return "hello"; 8 } 9 10 @PostMapping("/bunki") 11 public String bunki(@ModelAttribute("info") LoginInfoBean info, Model model) { 12 13 String id = info.getId(); 14 String pw = info.getPw(); 15 16 if(id.equals("1") && pw.equals("1")) { 17 return "ok"; 18 } 19 20 model.addAttribute("message", "認証に失敗しました"); 21 return "hello"; 22 } 23}

hello.html

HTML

1<!doctype html> 2<html xmlns:th="http://www.thymeleaf.org"> 3<head> 4<title>index</title> 5<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 6<meta charset="UTF-8" /> 7<link rel="stylesheet" 8 href="webjars/bootstrap/4.4.1/css/bootstrap.min.css" /> 9<script src="webjars/bootstrap/4.4.1/js/bootstrap.min.js"></script> 10</head> 11<body> 12 <div class="container"> 13 <p class="text-center text-danger" th:text="${message}" /> 14 <form th:action="@{/bunki}" th:object="${info}" method="post"> 15 16 <div class="d-block mx-auto col-md-4"> 17 <div class="form-group"> 18 <input type="text" class="form-control" name="id" 19 placeholder="id"> 20 </div> 21 <div class="form-group"> 22 <input type="text" class="form-control" name="pw" 23 placeholder="pw"> 24 </div> 25 <div class="form-group"> 26 <input type="submit" class="form-control btn-primary" value="決定"> 27 </div> 28 </div> 29 </form> 30 </div> 31</body> 32</html>

ok.htmlはただOKと表示するだけです。

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

自分としては失敗した場合はURLが

http://localhost:8080/hello

成功した場合は

http://localhost:8080/ok

となるかと思ったのですが、どちらの場合も

http://localhost:8080/bunki

となってしまいました。

試したこと

調べたところ、redirectとすればURLは変わらず、forwardとつけるとURLが変わる
のようなことが書いてあったので
MainController.javaを

Java

1@Controller 2public class MainController { 3 4 @GetMapping("/hello") 5 public String hello(Model model) { 6 model.addAttribute("info", new LoginInfoBean()); 7 return "hello"; 8 } 9 10 @PostMapping("/bunki") 11 public String bunki(@ModelAttribute("info") LoginInfoBean info, Model model) { 12 13 String id = info.getId(); 14 String pw = info.getPw(); 15 16 if(id.equals("1") && pw.equals("1")) { 17 return "forward:ok"; 18 } 19 20 model.addAttribute("message", "認証に失敗しました"); 21 return "redirect:hello"; 22 } 23}

として見たのですが
forwardのほうはWhitelabel Error Pageが表示されてしまい
redirectのほうはURLは/helloのまま変わらないですが「認証に失敗しました」というメッセージが出なくなってしまいました。
どうすればよいでしょうか?

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

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

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

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

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

guest

回答1

0

ベストアンサー

3点ほど指摘できる項目があります。

1点目

調べたところ、redirectとすればURLは変わらず、forwardとつけるとURLが変わる

のようなことが書いてあったので

redirectではURLは変わりますが、forwardでは変わりません。

2点目

forwardのほうはWhitelabel Error Pageが表示されてしまい

このエラーはフォワード先のエンドポイント、この場合は/okが定義されていない為だと思います。

if(id.equals("1") && pw.equals("1")) { return "forward:ok"; }

3点目

redirectのほうはURLは/helloのまま変わらないですが「認証に失敗しました」というメッセージが出なくなってしまいました

リダイレクト先に情報を引き渡したい場合はRedirectAttributesを使用することができます。

改修案

上記を踏まえて、認証成功および失敗時にURLを変えたい場合はどちらもリダイレクトする必要があり、リダイレクト先に情報を引き渡すには以下のコードになります。

なお、認証成功時のエンドポイント/okですが、この例では直接アクセスできますのでご留意ください。

@GetMapping("/hello") //★(2) リダイレクト元からの情報を受け取るためにパラメータを定義 public String hello(@ModelAttribute("info") LoginInfoBean info) { return "hello"; } @GetMapping("/ok") public String ok() { return "ok"; } @PostMapping("/bunki") public String bunki(@ModelAttribute("info") LoginInfoBean info, RedirectAttributes redirectAttributes) { if(id.equals("1") && pw.equals("1")) { redirectAttributes.addFlashAttribute("message", "認証に成功しました"); return "redirect:ok"; } //★(1) 認証失敗時の情報をリダイレクト先へ渡す redirectAttributes.addFlashAttribute("info", info); redirectAttributes.addFlashAttribute("message", "認証に失敗しました"); return "redirect:hello"; }

最後に補足として追記致します。認証失敗時にフォームページへリダイレクトしますが、このときにフォームに直前の入力情報を表示するにはth:field属性を利用するのが便利です。

html

1<form th:action="@{/bunki}" th:object="${info}" method="post"> 2 3 <div class="d-block mx-auto col-md-4"> 4 <div class="form-group"> 5 <!--★(3) th:field="*{id}"でフォームにセット --> 6 <input type="text" class="form-control" placeholder="id" th:field="*{id}"> 7 </div> 8 <div class="form-group"> 9 <!--★(4) th:field="*{pw}"でフォームにセット--> 10 <input type="text" class="form-control" placeholder="pw" th:field="*{pw}"> 11 </div> 12 <div class="form-group"> 13 <input type="submit" class="form-control btn-primary" value="決定"> 14 </div> 15 </div> 16</form>

追記(2020/02/06)

ただ一点気になるところがあって、補足で教えていただいたものは元の入力値が認証失敗時にidとpw欄にそれぞれ入力されたままになるということでしょうか?

上記のとおりやってみたのですが、失敗時はidもpwもクリアされてしまうようで…

上記のコメントを受けて、改修案にコメントを追加しました。
認証失敗時にフォーム画面に元の入力値を表示させるには下記4カ所のコードが必要です。
★(1)~★(2)はリダイレクト間で情報を持ちまわすためのコード、★(3)、★(4)はリダイレクト元から持ちまわされた情報をフォームフィールドにセットするためのコードです。

bunkiメソッド

//★(1) 認証失敗時の情報をリダイレクト先へ渡す redirectAttributes.addFlashAttribute("info", info);

helloメソッド

//★(2) リダイレクト元からの情報を受け取るためにパラメータを定義 public String hello(@ModelAttribute("info") LoginInfoBean info)

hello.html

※関係のない部分は省略しています。

<form th:action="@{/bunki}" th:object="${info}" method="post"> <!--★(3) th:field="*{id}"でフォームにセット --> <input type="text" class="form-control" placeholder="id" th:field="*{id}"> <!--★(4) th:field="*{pw}"でフォームにセット--> <input type="text" class="form-control" placeholder="pw" th:field="*{pw}"> </forM

なお、th:field="*{id}"という書き方は、th:field="${info.id}"と同じ意味です。
さらには、少し冗長化して書くと下記のようになります。

<input type="text" class="form-control" placeholder="id" id="id" name="id" th:value="${info.id}">

追記(2020/02/07)

この時infoは⑤のところで引数として受け取っているので⑥でhello.htmlを呼び出したときに過去の入力値がth:field="*{id}"のようにして表示できるのはわかるのですが

説明に不正確な点がありましたのでお詫びと訂正をさせて頂きます。
下記のコードを『リダイレクト元からの情報を受け取るためにパラメータを定義』と説明しましたが、正確にはリダイレクト元でセットされたinfoはモデルの属性に存在しているので受け取るためだけであればパラメータの定義は不要です。

java

1@GetMapping("/hello") 2//★(2) リダイレクト元からの情報を受け取るためにパラメータを定義 3public String hello(@ModelAttribute("info") LoginInfoBean info) { 4 return "hello"; 5}

ただし、下記の実装だとリダイレクトしてきた時に、新しいインスタンスでモデルの属性のinfoを更新してしまいます。

java

1@GetMapping("/hello") 2public String hello(Model model) { 3 model.addAttribute("info", new LoginInfoBean()); 4 return "hello"; 5}

なので、直接アクセスとリダイレクトされてくることを意識したコードは、下記のようになります。

java

1@GetMapping("/hello") 2public String hello(Model model) { 3 // モデルの属性にinfoが存在しない場合は、インスタンスを生成してモデルの属性にセット。 4 // これは直接helloにアクセスするユーザーを想定した処理。 5 if (!model.containsAttribute("info")) { 6 model.addAttribute("info", new LoginInfoBean()); 7 } else { 8 // モデルの属性にinfoが存在するということは、リダイレクト元でセットされている。 9 System.out.println(model.getAttribute("info")); 10 // 同様に、リダイレクト元でmessageがセットされていれば、モデルの属性にmessageも存在している。 11 System.out.println(model.getAttribute("message")); 12 } 13 return "hello"; 14}

このコードを簡略化したのが、回答で提示した下記のコードになります。
直接アクセスしたユーザーは生成された(空の)インスタンス、リダイレクトしてきたユーザーは元の入力情報を持つインスタンスがモデルの属性にセットされています。
※helloメソッド内でinfoについて何か処理を行うということがなければ、このコードではなく上記のコードが適切かと思います。

java

1@GetMapping("/hello") 2public String hello(@ModelAttribute("info") LoginInfoBean info) { 3 return "hello"; 4}

redirectAttributes.addFlashAttribute("message", "認証に失敗しました");については何も指定しなくても表示できるのでしょうか?

messageについても、infoと同様にモデルの属性に存在していれば、テンプレート(html)で表示できます。

最後にflashスコープについて補足致します。
bunkiメソッドでリダイレクト先にinfoやmessageを渡すためにaddFlashAttributeというメソッドを使っていますが、これはflashスコープというスコープに登録しています。
flashスコープとはリダイレクト先に情報を渡すためのスコープで一度だけ使えます。
一度だけというのは、一度表示するとその情報は消えるという意味で、例えば認証成功後のokページでF5キーを押してページを更新するとメッセージは表示されません。

アクセスフローと併せてご覧ください。

[client] +--------+ | | redirect:hello | | (flash = info,message) | ---|----------------------------------------------------------------------- | | | | | | | | | | | +---------+ +--------+ | | ---|--> /hello -(2)-> | | | | - failure -- | | | hello | [post] | /bunki | | ------|--> /hello -(1)-> | .html | (request = info) | | - success -- | | (request = info) +---------+ +--------+ | | | | | ---|----------------------------------------------------------------------- | | | redirect:ok | | | (flash = message) | | | +----------+ | | | | | | ---|-----------------------------------------------------> /ok -(3)-> | ok.html | | | | | | | +----------+ +--------+
  • /hello -(1)-> は、直接アクセスするユーザーの流れ、requestスコープに空のinfoを持つ
  • /hello -(2)-> は、認証失敗でリダイレクトしたユーザーの流れ、info、messageをflashスコープに持つ
  • /ok -(3)-> は、認証成功でリダイレクトしたユーザーの流れ、messsageをflashスコープに持つ

投稿2020/02/05 10:34

編集2020/02/07 07:08
rubytomato

総合スコア1752

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

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

moshi

2020/02/06 02:21

すごく丁寧に解説していただいてありがとうございます! やりたいことはすべて解決できました! ただ一点気になるところがあって、補足で教えていただいたものは元の入力値が認証失敗時にidとpw欄にそれぞれ入力されたままになるということでしょうか? 上記のとおりやってみたのですが、失敗時はidもpwもクリアされてしまうようで… それとも「認証失敗時にidとpw欄にそれぞれ入力されたままになる」という解釈自体が間違いなのでしょうか?
rubytomato

2020/02/06 06:59

補足しましたのでご確認ください。
moshi

2020/02/07 02:46 編集

なるほどです! infoに入力した情報を入れて持ちまわってるんですね! めっちゃよくわかりましたありがとうございます! 処理の流れを確認すると ①ログインボタンを押す→②postで/bunkiが呼ばれる→③判定(今回は失敗時について書きますが成功時は/okへ)→④判定がfalseなので/helloを呼び出す→⑤infoの情報をもったpublic String helloが呼ばれる→⑥hello.htmlが表示される だと思うのですが、この時infoは⑤のところで引数として受け取っているので⑥でhello.htmlを呼び出したときに過去の入力値がth:field="*{id}"のようにして表示できるのはわかるのですが redirectAttributes.addFlashAttribute("message", "認証に失敗しました");については何も指定しなくても表示できるのでしょうか? あ、上記のソースで動作を確認したところ表示できているのですが、なぜ表示できているのかがわからなくて…
rubytomato

2020/02/07 07:10

コメントで頂いた疑問点について、回答欄に追記しましたのでご確認ください。 分かりにくい説明だったことお詫びいたします。
moshi

2020/02/10 00:39

すごく勉強になりましたありがとうございます! まだ勉強を始めたばかりでわからないところがわからないといった感じなのでこうやって補足として新たな知識を与えていただけるのは大変助かります。 また何かあればよろしくお願いいたします!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問