第7章 セッション管理
セッション管理
homepage
# **セッション管理** *** ## **1.セッションの開始** セッションはクライアント毎に作成され、セッションが開始されるとセッションを識別するためのセッションIDをクライアントの保存し、また保存したい値をセッション変数としてサーバ側に保存します。クライアントに保存されるセッションIDはクッキーを利用して保存されます。<br> それではまずセッションを開始してみましょう。"doGet"メソッドや"doPost"メソッドの引数で渡されてくる「HttpServletRequest」インターフェースのオブジェクトからセッションを作成します。「HttpServletRequest」インターフェースで用意されている"getSession"メソッドを使います。 **getSession** ``` public HttpSession getSession(boolean create) ``` "getSession"メソッドは、サーブレットを要求してきたクライアントに対してセッションが既に開始されていればそのセッションを返します。また引数に"ture"を指定した場合にはセッションが開始されていなければ新規にセッションを開始した後でそのセッションを返してきます。<br> 引数に"false"を指定した場合、セッションが存在しない場合にはnullが帰ってきます。<br> 利用方法としては下記のようになります。<br> #### **例** **SessionTest.java** ``` package session; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebServlet("/SessionTest") public class SessionTest extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html; charset=Utf-8"); PrintWriter out = response.getWriter(); HttpSession session = request.getSession(false); out.println("<html>"); out.println("<head>"); out.println("<title>セッションテスト</title>"); out.println("</head>"); out.println("<body>"); if (session == null) { out.println("<p>セッションは存在しません。開始します</p>"); session = request.getSession(true); } else { out.println("<p>セッション開始してます</p>"); } out.println("<a href=\"SessionTest\">再表示</a>"); out.println("</body>"); out.println("</html>"); } } ``` #### **実行結果** <!--graph7-1.png --> <img src="https://i.loli.net/2019/06/27/5d148a050d30265252.png" width="40%"/> <br> ## **2.セッションを使ったデータの書き込みと読み込み** セッションを開始したら、サーバ側にデータを保存することができます。サーバ側に保存されるデータをセッションオブジェクトと呼びます。サーバ側にはデータを複数保存できますので同じセッション内で複数のセッションオブジェクトを保存することが出来ます。<br> ではデータを保存してみましょう。既に開始されたセッションに対してデータを保存するには、「HttpSession」インターフェースで定義されている"setAttribute"メソッドを使います。 **setAttribute** ``` public void setAttribute(java.lang.String name, java.lang.Object value) ``` "setAttribute"メソッドは、保存するデータを「名前」と「値」のペアで登録を行います。名前はString型ですが、値の方はObject型ですのでObject型のサブクラスであれば基本的に何でも保存することができます。ただしintなどの基本型は利用できません。<br> 例えばセッションオブジェクトとして、名前を「visited」値を「1」として登録したい場合には下記のように記述します。 ``` public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{ response.setContentType("text/html; charset=UTF-8"); PrintWriter out = response.getWriter(); HttpSession session = request.getSession(true); session.setAttribute("visited", "1"); } ``` 逆に既に保存されているセッションオブジェクトを取り出して読み込むためには、「HttpSession」インターフェースで定義されている"getAttribute"メソッドを使います。 **getAttribute** ``` public java.lang.Object getAttribute(java.lang.String name) ``` "getAttribute"メソッドは、既に保存されているセッションオブジェクトの中で、引数に指定した名前を持つものを検索し、その値を戻り値として返してくれます。<br> #### **例** **SessionTest1.java** ``` package session; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebServlet("/SessionTest1") public class SessionTest1 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{ response.setContentType("text/html; charset=UTF-8"); PrintWriter out = response.getWriter(); HttpSession session = request.getSession(false); out.println("<html>"); out.println("<head>"); out.println("<title>セッションテスト</title>"); out.println("</head>"); out.println("<body>"); if (session == null){ out.println("<p>初回訪問です</p>"); session = request.getSession(true); session.setAttribute("visited", "1"); }else{ String visitedStr = (String)session.getAttribute("visited"); int visited = Integer.parseInt(visitedStr); visited++; out.println("<p>訪問回数は"); out.println(visited); out.println("回目です</p>"); session.setAttribute("visited", Integer.toString(visited)); } out.println("<a href=\"SessionTest1\">再表示</a>"); out.println("</body>"); out.println("</html>"); } } ``` #### **実行結果** <!--graph7-2.png --> <img src="https://i.loli.net/2019/07/01/5d19ae2f832d695210.png" width="40%"/> <br> ## **3.セッションオブジェクトの削除** セッションに格納されたセッションオブジェクトの削除について確認します。<br> セッションオブジェクトを削除する場合には「HttpSession」インターフェースで定義されている"removeAttribute"メソッドを使います。 **removeAttribute** ``` public void removeAttribute(java.lang.String name) ``` "removeAttribute"メソッドは、引数に指定した「名前」のセッションオブジェクト削除します。例えばセッションオブジェクトとして名前が「visited」のものを削除する場合には下記のように記述します。 ``` public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{ response.setContentType("text/html; charset=UTF-8"); PrintWriter out = response.getWriter(); HttpSession session = request.getSession(true); session.removeAttribute("visited"); } ``` <br> ## **4.セッションの破棄** 今度は既に開始されているセッションを破棄してみます。<br> セッションを破棄するには「HttpSession」インターフェースで定義されている"invalidate"メソッドを使います。 **invalidate** ``` public void invalidate() ``` ``` public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{ response.setContentType("text/html; charset=Utf-8"); PrintWriter out = response.getWriter(); HttpSession session = request.getSession(true); session.invalidate(); } ``` <br> ## **5.セッション作成日時と最終アクセス日時** セッションの作成日時を取得するには「HttpSession」インターフェースで定義されている"getCreationTime"メソッドを使います。 **getCreationTime** ``` public long getCreationTime() ``` 取得した値はlong型の値となっており、1/1/1970 GMT からの経過秒数で表されます。よって例えば下記のように使います。 ``` public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{ response.setContentType("text/html; charset=UTF8"); PrintWriter out = response.getWriter(); HttpSession session = request.getSession(true); long createTime = session.getCreationTime(); Date createDate = new Date(createTime); } ``` またクライアントがセッション開始以降に最後にアクセスしたきた日時も取得できます。「HttpSession」インターフェースで定義されている"getLastAccessedTime"メソッドを使います。 **getLastAccessedTime** ``` public long getLastAccessedTime() ``` "getLastAccessedTime"メソッドも戻り値ははlong型の値となっており、1/1/1970 GMT からの経過秒数で表されます。<br> #### **例** **SessionTest2.java** ``` package session; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebServlet("/SessionTest2") public class SessionTest2 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html; charset=UTF-8"); PrintWriter out = response.getWriter(); HttpSession session = request.getSession(false); out.println("<html>"); out.println("<head>"); out.println("<title>セッションテスト</title>"); out.println("</head>"); out.println("<body>"); if (session == null) { out.println("<p>セッションを開始します</p>"); session = request.getSession(true); long createTime = session.getCreationTime(); Date createDate = new Date(createTime); out.println("<p>"); out.println("セッション開始時間:" + createDate + "<br>"); out.println("</p>"); } else { out.println("<p>セッションは開始されています</p>"); long createTime = session.getCreationTime(); Date createDate = new Date(createTime); long accessTime = session.getLastAccessedTime(); Date accessDate = new Date(accessTime); out.println("<p>"); out.println("セッション開始時間:" + createDate + "<br>"); out.println("最終アクセス時間 :" + accessDate); out.println("</p>"); } out.println("<a href=\"SessionTest2\">再表示</a>"); out.println("</body>"); out.println("</html>"); } } ``` #### **実行結果** <!--graph7-3.png --> <img src="https://i.loli.net/2019/07/01/5d19af5485fe483160.png" width="40%"/> <br> ## **6.セッションの有効期限** セッションの有効期限を設定してみます。まずデフォルトの有効期限を確認してみましょう。セッションの有効期限を取得するには「HttpSession」インターフェースで定義されている"getMaxInactiveInterval"メソッドを使います。 **getMaxInactiveInterval** ``` public int getMaxInactiveInterval() ``` #### **例** **SessionTest3.java** ``` package session; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebServlet("/SessionTest3") public class SessionTest3 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{ response.setContentType("text/html; charset=UTF-8"); PrintWriter out = response.getWriter(); HttpSession session = request.getSession(false); out.println("<html>"); out.println("<head>"); out.println("<title>セッションテスト</title>"); out.println("</head>"); out.println("<body>"); if (session == null){ out.println("<p>セッションを開始します</p>"); session = request.getSession(true); } int intervalTime = session.getMaxInactiveInterval(); out.println("<p>"); out.println("デフォルトの有効期限は" + intervalTime + "秒です<br>"); out.println("</p>"); out.println("<a href=\"SessionTest3\">再表示</a>"); out.println("</body>"); out.println("</html>"); } } ``` #### **実行結果** <!--graph7-4.png --> <img src="https://i.loli.net/2019/07/01/5d19b001f143899019.png" width="40%"/> デフォルトのセッションの有効期限は1800秒(30分)となっています。 <br> ## **7.<session-config>要素による有効期限の設定** 次に有効期限を設定してます。全てのセッションのデフォルトの有効期限を設定するには、web.xmlにて< session-config >要素を使って指定します。<br> 子要素として< session-timeout >要素を0回または1回指定します。< session-timeout >要素には有効期限を分数で指定します。(秒ではなく分ですので注意してください)。<br> ``` <web-app> <session-config> <session-timeout> 有効期限の分数 </session-timeout> </session-config> </web-app> ``` デフォルトのセッションの有効期限ではなく、個別のセッションに対する有効期限を設定するには「HttpSession」インターフェースで定義されている"setMaxInactiveInterval"メソッドを使います。 **setMaxInactiveInterval** ``` public void setMaxInactiveInterval(int interval) ``` #### **例** **SessionTest4.java** ``` package session; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebServlet("/SessionTest4") public class SessionTest4 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html; charset=Utf-8"); PrintWriter out = response.getWriter(); HttpSession session = request.getSession(false); out.println("<html>"); out.println("<head>"); out.println("<title>セッションテスト</title>"); out.println("</head>"); out.println("<body>"); if (session == null) { out.println("<p>セッションを開始します</p>"); session = request.getSession(true); } int intervalTime = session.getMaxInactiveInterval(); out.println("<p>"); out.println("現在のデフォルトの有効期限は" + intervalTime + "秒です<br>"); out.println("</p>"); out.println("<a href=\"SetInterval\">有効期限を20秒へ</a>"); out.println("</body>"); out.println("</html>"); } } ``` **SetInterval.java** ``` package session; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebServlet("/SetInterval") public class SetInterval extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html; charset=UTF-8"); PrintWriter out = response.getWriter(); HttpSession session = request.getSession(false); out.println("<html>"); out.println("<head>"); out.println("<title>セッションテスト</title>"); out.println("</head>"); out.println("<body>"); if (session == null) { out.println("<p>セッションがありません</p>"); } else { session.setMaxInactiveInterval(20); int intervalTime = session.getMaxInactiveInterval(); out.println("<p>"); out.println("現在のセッションの有効期限は" + intervalTime + "秒です<br>"); out.println("</p>"); } out.println("</body>"); out.println("</html>"); } } ``` #### **実行結果** <!--graph7-5.png --> <img src="https://i.loli.net/2019/07/01/5d19b4e8211e913500.png" width="40%" /> <br> ## **8.セッションIDの確認** セッションが新規に開始された場合、セッションを区別するためにセッションIDが作成されクライアントにクッキーとして保存されます。ここではセッションIDを取得してみましょう。<br> セッションIDを取得するには「HttpSession」インターフェースで定義されている"getId"メソッドを使います。 **getId** ``` public java.lang.String getId() ``` セッションIDは、(クライアントがクッキーを有効にしている場合には)クライアントにクッキーの値として保存されます。下記のサンプルではセッションIDを確認すると同時に、クライアント側に保存されているクッキーを確認してみます(正確にはクライアント側からサーバへリクエストがある時に、合わせてクライアントからサーバに送られてくるクッキーを確認します)。<br> セッションIDは、(クライアントがクッキーを有効にしている場合には)クライアントにクッキーの値として保存されます。下記のサンプルではセッションIDを確認すると同時に、クライアント側に保存されているクッキーを確認してみます(正確にはクライアント側からサーバへリクエストがある時に、合わせてクライアントからサーバに送られてくるクッキーを確認します)。 <br> ## **9.URL書き換え** ただ、不特定多数のクライアントから利用されるサーブレットの場合、全てのクライアントがクッキーを受け入れる設定になっているわけではありません。クッキーが使えないクライアントからでもセッションを利用できるようにするためにはURLをセッションID付きのものに書き換える必要があります。<br> クッキーが使える場合に、クライアントからはサーブレットへのリクエストと同時に自分が持っているクッキーをサーバに送ってきます。その仕組みの変わりに、サーブレットへのリクエストそのものにセッションIDを含めてしまうということになります。これはURLを次のように書き換えることで対応出来ます。<br> **通常のサーブレットへのリンク:** ``` http://localhost:8080/session/sessiontest ``` セッションID付サーブレットへのリンク: ``` http://localhost:8080/session/sessiontest;jsessionid=(セッションID) ``` このようにセッションID付きのURLをクリックするなどしてサーバへリクエストを送ると、サーバ側ではそこからセッションIDを抜き出してクッキーがある場合と同じような処理をしてくれます。<br> ここでURLに付加するセッションIDは、クライアント毎にそしてセッション毎に異なるため、固定して記述することは出来ません。まずクライアントが最初にサーバへアクセスした時にセッションを開始し、そこからセッションIDを取得した上で、それ以降クリックされる全てのURLにセッションIDを付与した形でHTMLをサーブレットが出力する必要があります。<br> このセッションID付きのURLの生成ですが、「HttpServletResponse」インターフェースで定義されている"encodeURL"メソッドを使うことで自動的に行うことができます。 **encodeURL** ``` public java.lang.String encodeURL(java.lang.String url) ``` このメソッドは引数にURLを表す文字列を指定して実行すると、セッションID付きのURLに変換して出力してくれます。サーブレットを通じて出力されるリンクは全てこのメソッドを通した結果得られるURLを使う必要があります。<br> またこのメソッドは、必要無ければ書き換えを行いません。つまりクッキーが使える状態で、クッキーからセッションIDを取得出来る場合にはこのメソッドを使ってもセッションIDの付与は行われません。<br> #### **例** **SessionTest5.java** ``` package session; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebServlet("/SessionTest5") public class SessionTest5 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html; charset=Utf-8"); PrintWriter out = response.getWriter(); HttpSession session = request.getSession(false); out.println("<html>"); out.println("<head>"); out.println("<title>セッションテスト</title>"); out.println("</head>"); out.println("<body>"); if (session == null) { out.println("<p>セッションを開始します</p>"); session = request.getSession(true); } else { out.println("<p>セッション中です</p>"); } String session_id = session.getId(); out.println("<p>"); out.println("セッションIDは" + session_id + "です<br>"); out.println("</p>"); String url = "SessionTest5"; String eURL = response.encodeURL(url); out.println("<p>"); out.println("書き換え前: " + url + "<br>"); out.println("書き換え後: " + eURL); out.println("</p>"); out.println("<a href=\"" + eURL + "\">再表示</a>"); out.println("</body>"); out.println("</html>"); } } ``` #### **実行結果** <!--graph7-6.png --> <img src="https://i.loli.net/2019/07/01/5d19b8813080a81481.png" width="40%" /> <br> ## **10.クッキーかURL書き換えかの判別** セッションを管理するためのセッションIDの取得についてクッキー経由かURL書き換えによるものか二通りの方式がありますが、どちらの方式で利用されているかを判別することができます。判別することによってクッキー経由でのみサーブレットを利用させるなどの制限を行うことができます。<br> 判別するには「HttpServletResponse」インターフェースで定義されている"isRequestedSessionIdFromCookie"メソッドと"isRequestedSessionIdFromUrl"メソッドを使います。<br> **isRequestedSessionIdFromCookie** ``` public boolean isRequestedSessionIdFromCookie() ``` isRequestedSessionIdFromUrlメソッド: **isRequestedSessionIdFromURL** ``` public boolean isRequestedSessionIdFromURL() ``` クッキー経由の場合には"isRequestedSessionIdFromCookie"がTRUEを、URL書き換え経由の場合には"isRequestedSessionIdFromURL"がTRUEを返してくれます。 #### **例** **SessionTest6.java** ``` package session; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebServlet("/SessionTest6") public class SessionTest6 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{ response.setContentType("text/html; charset=UTF-8"); PrintWriter out = response.getWriter(); HttpSession session = request.getSession(false); out.println("<html>"); out.println("<head>"); out.println("<title>セッションテスト</title>"); out.println("</head>"); out.println("<body>"); if (session == null){ out.println("<p>セッションを開始します</p>"); session = request.getSession(true); }else{ out.println("<p>セッション中です</p>"); } boolean cookie_flag = request.isRequestedSessionIdFromCookie(); boolean url_flag = request.isRequestedSessionIdFromURL(); out.println("<p>"); out.println("FromCookie : " + cookie_flag + "<br>"); out.println("FromURL : " + url_flag); out.println("</p>"); String url = "SessionTest6"; String eURL = response.encodeURL(url); out.println("<a href=\"" + eURL + "\">再表示</a>"); out.println("</body>"); out.println("</html>"); } } ``` クッキーは有効にしてあります。 #### **実行結果** <!--graph7-7.png --> <img src="https://i.loli.net/2019/07/01/5d19c37fc5c7d82378.png" width="40%"/> セッションが開始される時点ではクライアントからはクッキーもURL書き換えによるセッションID付与もありませんので両方とも「false」となります。次に「再表示」をクリックして下さい。(リンクはURL書き換えが行われています)。<br> <!--graph7-8.png --> <img src="https://i.loli.net/2019/07/01/5d19c37fb9e0b36505.png" width="40%"/> リンクにはURL書き換えが行われているのでURLそのものにセッションIDは付与されているのですが、クッキーが有効になっているためURLのセッションIDではなくクッキーからのセッションID取得が行われています。その為、"isRequestedSessionIdFromCookie"メソッドだけがTRUEを返してきます。<br> ※クッキーからセッションIDが取得できた為、次回以降はURL書き換えをしてもセッションIDが付与されなくなるのだと考えられます。<br> 次にブラウザの設定でクッキーを無効にした状態で同じテストをしてみます。<br> <!--graph7-7.png --> <img src="https://i.loli.net/2019/07/01/5d19c37fc5c7d82378.png" width="40%"/> セッション開始時はクッキーが有効でも無効でも結果は同じです。では「再表示」をクリックして下さい。<br> <!--graph7-9.png --> <img src="https://i.loli.net/2019/07/01/5d19c380083f975679.png" width="40%"/> 今度はクッキーが無効になっていますので、セッションIDはURLに付与されたものから取得されています。その為"isRequestedSessionIdFromURL"メソッドがTRUEを返してきます。このようにセッション開始以降は、クッキー経由なのかURL書き換え経由なのかを判別することが可能となります。
content
戻る