0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

1回でドンピシャの相対パスを書けるようになる!(RequestDispatcher foward)

Last updated at Posted at 2025-01-14

0_結論

最初に結論。

RequestDispatcherのfowardメソッドで遷移先のファイルを指定するときの書き方は、以下の2通り。

  • 書き方1:コンテキストルートからの相対パス
    ・ /(スラッシュ)で始まる。

  • 書き方2:現在のURL(リクエストされたアドレスのパス)からの相対パス
    ・ / で始まらない。

本記事のサンプルで言うと、正解は
/jsp/sample.jsp 
jsp/sample.jsp 
(最初の「/」の有無は問わず実行成功するし、手元のテキストにも、「/」があるパターンと無いパターンの両方がお手本として掲載されている。)

1_何が起きたか

JavaのWebアプリ開発を学習中です。

サーブレット内にRequestDispatcherで遷移先のjspの相対パスを書くときに、

「現在書いているサーブレットjavaファイルを起点として、遷移先のjspファイルまでの道順を全部書けば良いと思っているのに、お手本のコードを見ると書かれているのは道順のラスト部分だけ。書くべきラスト部分の範囲がわからない!」
「最初の "/" は必要なのか不要なのか?」
という2点がわからなくなることが多いです。
相対パスの理解が浅いのだと思います。

よく迷うのが下記のようなケース。

フォルダ構成(★=今回注目すべきファイル)
SampleProject(コンテキストルート)
    ∟.settings
    ∟build
    ∟src
       ∟samplePkg(パッケージ)
           ∟SampleServlet.java(★)
   ∟SampleContent
      ∟META-INF
      ∟jsp
         ∟sample.jsp(★)
      ∟WEB-INF
         ∟lib
            ∟mysql-connector-j-9.1.0.jar
         ∟web.xml
    ∟.classpath
    ∟.project
SampleServlet.java
package samplePkg;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class SampleServlet extends HttpServlet {
	public void doGet(HttpServletRequest req, HttpServletResponse res)
		throws ServletException, IOException {
		doPost(req,res);
	}
	
	public void doPost(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
			
		req.setCharacterEncoding("UTF-8");
		res.setContentType("text/html;charset=UTF-8");

        //↓この"jsp/sample.jsp"部分!
		RequestDispatcher rd = req.getRequestDispatcher("jsp/sample.jsp");
		rd.forward(req, res);
		}
}

現在のところは、
・書いたパスが正解なのか不正解なのか、実際にそのファイルをサーバーで実行して試してみる。→パスが通ってなければパスを修正する。
あるいは、
・「このときはこの書き方!」と、パターンを暗記して対応する。
という方法を取っています。

2_この記事のゴール

ファイルを実行して試さなくても、
「1回でドンピシャの相対パスを書けるようになる!」

パターン暗記ではなく、相対パスの通し方を理解して、どんな場合でも
「通るパスを自力で書けるようになる!」

3_相対パスの書き方

3-1_階層について整理

まず、階層について整理します。

今回のフォルダ&ファイル構成で、今回注目すべき部分のみを図にまとめると、
こうなります。

「今いる位置」と「遷移したい先」は、どちらも第4階層にあります。

今いる位置:SampleServlet.java 
…①SampleProject > ②src > ③samplePkg > ④SampleServlet.java(★)

遷移したい先:sample.jsp
…②SampleProject > ②SampleContent > ③jsp > ④sample.jsp(★)

※〇数字は階層

余談:Mermaid

今回、Mermaidというものがあると知り、上図をMermaidで書いてみました。(↓こちらを参照して書きました)

図形の形変えたいとか、線で繋ぎたいとか、高さを揃えたいとか…は追々使えるようになりたいです。

3-2_書き方_失敗:道順を全部書く

さて、相対パスを書きます。

現在地(スタート)は ④SampleServlet.java(★)で、
遷移したい先(ゴール) ④sample.jsp(★)です。

まずはスタートの第4階層から一度、スタートとゴールの共通の元となる第1階層(①SampleProjsct)まで戻って、
それからゴールの第4階層へ向かう、
という道順を考えてみます。

これでどうだ!
/SampleProject/SampleContent/jsp/sample.jsp
(これは絶対パスなのか?相対パスなのか??)
実行してみます。

SampleServlet.java
package samplePkg;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class SampleServlet extends HttpServlet {
	public void doGet(HttpServletRequest req, HttpServletResponse res)
		throws ServletException, IOException {
		doPost(req,res);
	}
	
	public void doPost(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
			
		req.setCharacterEncoding("UTF-8");
		res.setContentType("text/html;charset=UTF-8");

        //↓ここ!
		RequestDispatcher rd = req.getRequestDispatcher("/SampleProject/SampleContent/jsp/sample.jsp");
		rd.forward(req, res);
		}
}

結果は、404エラーでした。失敗。
image.png

最初のスラッシュを無くして
SampleProject/SampleContent/jsp/sample.jsp
で実行しても、同じく404エラーでした。

「../」を使って
../../SampleContent/jsp/sample.jsp
で実行したら、500エラー。
image.png

ChatGPTに聞いてみました。

(to ChatGPT)
"SampleProject/SampleContent/jsp/sample.jsp"の部分を
”jsp/sample.jsp”に変更すると正常に動作します。

"SampleProject/SampleContent/jsp/sample.jsp"で実行すると、404エラーになります。
"../../SampleContent/jsp/sample.jsp"に変更すると、500エラーになります。

なぜ、
"SampleProject/SampleContent/jsp/sample.jsp"、
"../../SampleContent/jsp/sample.jsp"
は不可なのでしょうか?
また、”jsp/sample.jsp”のほかにも、正常に動作する絶対パス又は相対パスは存在しますか?

3-3_書き方_正解

/jsp/sample.jsp
jsp/sample.jsp 
→最初の「/」の有無は問わず実行成功するし、手元のテキストにも、
「/」があるパターンと無いパターンの両方がお手本として掲載されている。

ChatGPTの回答と、ネット&手持ちの教材で調べたことを加味して、以下のとおり理解しました。

書式の「遷移先のパス」部分には以下の2種類のパスが利用可能です。
 ① 頭に「/」のついたコンテキストルートからの相対パス
 ② リクエストされた現在のURLからの相対パス
(出典:「サーブレットからJSPへ画面遷移」神田ITScool)

  • 書き方1:コンテキストルートからの相対パス
    ・ /(スラッシュ)で始まる。

  • 書き方2:現在のURL(リクエストされたアドレスのパス)からの相対パス
    ・ / で始まらない。

因みに、jsp/sample.jspでも正常に実行できたけど、これはEclipseが自動で動くように解釈してくれたということなのか?あるいは、手元のテキストにも各々のプログラムで両方のパターンの記述がされているから、大本のルールも「どちらでもOK」ということなのか??

3-4_書き方_不正解

/SampleProject/SampleContent/jsp/sample.jsp 
 →404エラー
SampleProject/SampleContent/jsp/sample.jsp(最初のスラッシュを無くした)
 →404エラー
 →リクエストディスパッチャーが探すパスが「コンテキスト・ルートからの相対パス」であるため、404エラーが発生している。「SampleProject」はサーブレットコンテナ(例: Tomcat)によってマッピングされた コンテキスト・ルート の名前であり、RequestDispatcher 内で明示的に書く必要は無い。

../../SampleContent/jsp/sample.jsp(「../」を使った)
 →500エラー
 →../../ のような親フォルダを参照する相対パスは、RequestDispatcher では解釈できない。サーブレットが動作するフォルダ(/SampleProject/)の外側を参照しようとするため、この指定は無効。

sample.jsp
 →404エラー。
 →「書き方2」のとおり、/ で始まらない書き方は、「現在のURL(リクエストされたアドレスのパス)からの相対パス」。今回の遷移先のファイルは異なるディレクトリに存在するので、この書き方はエラーになる。

/SampleContent/jsp/sample.jsp
 →404エラー。
 →「書き方1」のとおりに記述したが、これだとエラー。書き方が間違っているのか?なぜエラーになるのか、「RequestDispatcher 相対パス」等でググるも解決できず。
なぜ/SampleContentの記述が不要なのか、謎のまま…。
/SampleContentをすっ飛ばして、/jsp/sample.jspが正解となる理由がわからない…。

4_解決できなかった点

  • "3-3_書き方_正解" より

因みに、jsp/sample.jspでも正常に実行できたけど、これはEclipseが自動で動くように解釈してくれたということなのか?あるいは、手元のテキストにも各々のプログラムで両方のパターンの記述がされているから、大本のルールも「どちらでもOK」ということなのか??

  • "3-4_書き方_不正解" より

/SampleContent/jsp/sample.jsp
 →404エラー。
 →「書き方1」のとおりに記述したが、これだとエラー。書き方が間違っているのか?なぜエラーになるのか、「RequestDispatcher 相対パス」等でググるも解決できず。
なぜ/SampleContentの記述が不要なのか、謎のまま…。
/SampleContentをすっ飛ばして、/jsp/sample.jspが正解となる理由がわからない…。

5_さいごに

上記2点が未解決なので、この記事のゴール(下記)は達成できず。

ファイルを実行して試さなくても、
「1回でドンピシャの相対パスを書けるようになる!」

パターン暗記ではなく、相対パスの通し方を理解して、どんな場合でも
「通るパスを自力で書けるようになる!」

まだパスの通し方について、理解できてません。
理解できたら追記します!

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?