【Servlet】まとめ

プロジェクト作成

動的Webプロジェクトで作成
f:id:vist764:20220404230815p:plain:w400

サーブレットクラス作成

f:id:vist764:20220404232819p:plain:w400

URL

http://<サーバ名>/<コンテキスト名>/
(例)http://localhost:8080/ServletSample/hello.html

コンテキスト

アプリケーションサーバに配備したWebアプリのこと
WebアプリをリクエストするURLにコンテキストの名前を含める必要がある
デフォルトは動的Webプロジェクトの名前になっているが変更可能
<変更方法>
1.動的Webプロジェクトをサーバから除去
2.動的Webプロジェクトで右クリック→プロパティ→Webプロジェクトの設定
3.コンテキスト・ルートを変更 ※これがコンテキストの名前になる
4.動的Webプロジェクトをサーバに追加

コンテキストパス

Webサーバから見たコンテキストルートまでのパスのこと
(例)コンテキストがServletSampleの場合
   /ServletSample (コンテキスト名の前に/がついたパス)
実際のURL:http://localhost:8080/ServletSample
※「/」はhttp://localhost:8080(サーバのURL)
jsp

<%= request.getContextPath() %>
コンテキストルート

Webサーバから見たコンテキストルートまでのパスのこと
http://localhost:8080/ServletSample

トップページ

・ファイル名を省略してもアクセス可能
 例)http://yahoo.co.jp/index.htmlhttp://yahoo.co.jp
・ブラウザから直接リクエストするためWebConten直下に配置すること
 (逆に直接リクエストできないようにするにはWebContent配下に配置しない)

<ファイル名の優先順位(Apatchの場合)>
index.html → index.htm → index.jsp → default.html → default.htm → default.jsp

リクエストパラメータの値を取得、jspフォワードする

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<title>トップページ</title>
	</head>
	<body>
		<form action="/ServletSample/Sample1" method="post">
			名前:<input type="text" name="name" /><br>
			性別:
			男<input type="radio" name="gender" value="0" /><input type="radio" name="gender" value="1" /><br>
			<input type="hidden" name="hiddenItem" value="非表示の値"/><br>
			<input type="submit" value="送信" />
		</form>
	</body>
</html>

Sample1.java

//formで指定したaction
@WebServlet("/Sample1")
public class Sample1 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    //formの送信方法がpostの場合 ※getならdoGetにする
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        //リクエストパラメータの文字コードを指定
        request.setCharacterEncoding("UTF-8");	//送信元HTMLの文字コードを指定

        //リクエストパラメータの取得
        String name = request.getParameter("name");	//formのnameを指定
        String gender = request.getParameter("gender");
        String hiddenItem = request.getParameter("hiddenItem");

        //同じ名前が存在する場合こっちを使用する。配列で取得できる
        String[] values = request.getParameterValues("name");	//formのnameを指定

        //パラメータ名の一覧を取得
        Enumeration<String> names = request.getParameterNames();

        //フォワード
        RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/page1.jsp");
        dispatcher.forward(request, response);
    }
}

page1.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>page1</title>
</head>
<body>
page1です。
</body>
</html>

リダイレクト

//formで指定したaction
@WebServlet("/Sample1")
public class Sample1 extends HttpServlet {
	private static final long serialVersionUID = 1L;

	//formの送信方法がpostの場合 ※getならdoGetにする
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		//リダイレクト
		response.sendRedirect("/SampleServlet/Sample2");
	}
}

フォワードとリダイレクトの違い

フォワード リダイレクト
転送先 サーブレットクラスまたはjsp ブラウザがリクエストできるものすべて
転送先のアプリケーション 転送元と同じアプリケーションのみ すべてのアプリケーション(他サイトでもよい)
アドレスバーに表示されるURL リクエスト時のまま変わらない リダイレクト先のURLに変わる
リクエストスコープの引継ぎ できる できない

スコープ

インスタンスを保存できる領域のこと
※ページスコープは省略

リクエストスコープ セッションスコープ アプリケーションスコープ
インスタンス HttpServletRequest HttpSession ServletContext
暗黙オブジェクト request sesion application
作成される単位 リクエストごと ユーザーごと(ブラウザごと) アプリケーションごと
保存したインスタンスが取得できる期間 削除するかレスポンスするまで 削除するかタイムアウトするまで 削除するかアプリケーションが終了するまで
リクエストをまたいで保存 できない できる できる
ユーザーごとの保存 できる(リクエストごとに保存する) できる できない(すべてのブラウザで共有する)
リクエストスコープ

リクエストごとに生成されるスコープ
レスポンスが返されるまで利用できる
チェイン先では使用できるがリダイレクト先では使用できない

	// インスタンスの作成
	Human human = new Human();
	human.setName("高橋");
	human.setAge("20");
		
	// 保存
	request.setAttribute("human", human);

	// 取得
	Human h = (Human)request.getAttribute("human");

        //登録されているインスタンス名の一覧を取得
        Enumeration<String> names = request.getAttributeNames();
セッションスコープ

ブラウザごとに生成され、固有のセッションIDがブラウザとHttpSessionインスタンスに設定される
セッションを削除、タイムアウトするか、ブラウザを閉じるまで利用できる
※Apach Tomcatの初期設定では、ブラウザを閉じるとそれ以前に利用していたHttpSessionインスタンスを利用できなくなる

        // インスタンスの作成
        Human human = new Human();
        human.setName("高橋");
        human.setAge("20");

        // HttpSessionインスタンス取得(生成)
        HttpSession session = request.getSession();

        // 保存
        session.setAttribute("human", human);

        // 取得
        Human h = (Human)session.getAttribute("human");

        // 削除
        session.removeAttribute("human");
        
        // セッションを丸ごと破棄
        session.invalidate();

        //登録されているインスタンス名の一覧を取得
        Enumeration<String> names = session.getAttributeNames();
アプリケーションスコープ

1つのアプリケーションにつき1つ作成されるスコープ
Webアプリケーションが終了するまでの間、利用できる
保存したインスタンスの更新を複数のユーザーがほぼ同時に行った場合、不整合が発生することがある(スレッドを使用することで対策する)

        // インスタンスの作成
        Human human = new Human();
        human.setName("高橋");
        human.setAge("20");

        // ServletContextインスタンス取得
        ServletContext app = getServletContext();

        // 保存
        app.setAttribute("human", human);

        // 取得
        Human h = (Human)app.getAttribute("human");

        // 削除
        app.removeAttribute("human");

        //登録されているインスタンス名の一覧を取得
        Enumeration<String> names = app.getAttributeNames();

init()/destroy()

init()メソッドは初回リクエスト時、一番初めに実行される
destroy()メソッドはサーバの停止によってWebアプリケーションが終了したときに実行される

    public void init(ServletConfig config) throws ServletException{
    	//必須
    	super.init(config);

        System.out.println("init()が実行された");
    }

    public void destroy() {
        System.out.println("destroy()が実行された");
    }

フィールドの注意点

1)フィールドは他のサーブレットクラスやJSPファイルでは使用できない
2)サーブレットクラスのインスタンスは複数のリクエストで使用されるため、
同時にリクエストしているユーザーがいる場合、そのユーザー間でインスタンス内のフィールドが共有される
【対策】
・メンバ変数をやめて、doGet/Postメソッド内のローカル変数にする
サーブレットでは処理をせず、別のクラスにメンバ変数・処理を移植。別のクラスをnewして使う。

リスナー

Webアプリで特定のイベントが発生したときにそのクラスのメソッドが自動的に実行される
リスナーを使用すると、リクエストだけでなく、Webアプリの状況に応じて処理を行うことができる

リスナーインタフェース イベント
ServletContextListener Webアプリが開始または終了する
ServletContextAttributeListener アプリケーションスコープにインスタンスを保存、上書き保存、削除
HttpSessionListener セッションスコープを作成または破棄する
HttpSessionAttributeListener セッションスコープにインスタンスを保存、上書き保存、削除
HttpSessionActivationListener セッションスコープが退避、または回復する
HttpSessionBindingListener このインタフェースを実装したクラスのインスタンスをセッションスコープに保存、または削除する
ServletRequestListener リクエストが発生する、またはレスポンスが完了する
ServletRequestAttributeListener リクエストスコープにインスタンスを保存、上書き保存、削除
@WebListener	// 1.@WebListenerアノテーションを付与する
public class ListenerTest implements ServletContextListener{ // 2.インタフェースを実装する

    @Override	// 3.メソッドを実装する
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("contextInitializedが実行");	// 4.処理を記載する
    }

    @Override	// 3.メソッドを実装する(eclipseが自動で実装してくれる)
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("contextDestroyedが実行");	// 4.処理を記載する
    }
}

フィルタ

フィルタのクラスのURLパターンに合致するサーブレットクラスにおいて、doGet/Postメソッドが実行される前後のタイミングでフィルタのメソッドが自動的に実行される
1つのサーブレットクラスに複数のフィルタを設定し、連続で実行することも可能(フィルタチェーン)

@WebFilter("/*")	// 1.URLパターンを指定する
public class FilterSample implements Filter {	// 2.インタフェースを実装する

    @Override
    public void init(FilterConfig var1) throws ServletException { // 3.メソッドを実装する
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException { // 3.メソッドを実装する

        request.setCharacterEncoding("UTF-8");	// 4.処理を記載する
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() { // 3.メソッドを実装する
    }
}

URLパターン

URLパターン 説明
@WebFilter("/*") すべてのサーブレットクラス(※JSP、HTMLも含む)に設定する場合
@WebFilter("/Sample") URLパターンが「/Sample」のサーブレットクラスに設定する場合
@WebFilter("/index.jsp") JSPやHTMLにも適用する場合
@WebFilter("/Sample/*") URLパターンが「/Sample/~」のサーブレットクラスに設定する場合

実行タイミング

メソッド 実行タイミング
doFileter 設定したサーブレットクラスをリクエストしたとき
init フィルタがインスタンス化された直後
destroy フィルタのインスタンスが破棄される直前