{"id":2372,"date":"2013-09-24T20:11:45","date_gmt":"2013-09-24T18:11:45","guid":{"rendered":"http:\/\/www.tutego.de\/blog\/javainsel\/?p=2372"},"modified":"2013-09-24T20:11:45","modified_gmt":"2013-09-24T18:11:45","slug":"session-verwaltung-in-servlets-mit-httpsession","status":"publish","type":"post","link":"https:\/\/www.tutego.de\/blog\/javainsel\/2013\/09\/session-verwaltung-in-servlets-mit-httpsession\/","title":{"rendered":"Session-Verwaltung in Servlets mit HttpSession"},"content":{"rendered":"<p>Die Servlet-API bietet die Klasse HttpSession an, eine Bibliothek auf hohem Niveau f\u00fcr die Verwaltung einer Sitzung. Sie basiert entweder auf Cookies oder URL-Rewriting, doch wird das von der API transparent gehalten. Als Programmierer bekommen wir so gut wie gar nichts davon mit. Falls der Client keine Kekse mag, wandeln wir alle Informationen in URLs um, die wir dann anbieten. Ein Sitzungsobjekt verwaltet die gesicherten Daten auch selbstst\u00e4ndig in einer Datenstruktur. Hier f\u00e4llt f\u00fcr uns keine Arbeit an.<\/p>\n<h3>Das mit einer Sitzung verbundene Objekt HttpSession<\/h3>\n<p>Jede Sitzung ist mit einem Sitzungsobjekt verbunden, das die Klasse HttpSession abbildet. Bei JSPs repr\u00e4sentiert das implizite Objekt session die aktuelle Sitzung.<\/p>\n<h4>Werte mit einer Sitzung assoziieren und auslesen<\/h4>\n<p>Um Informationen mit der Sitzung zu verbinden, verwenden wir die Methode setAttribute(), die einen Schl\u00fcssel und einen Wert verbindet. Daten werden mit getAttribute() wieder aus der Datenstruktur gelockt, so wie es das folgende Beispiel zeigt:<\/p>\n<pre>List l = (List) session.getAttribute( &quot;artikel&quot; );<\/pre>\n<p>Hier verbinden wir mit einem Schl\u00fcssel eine Liste von Waren. Im Hintergrund werden die Informationen auf der Serverseite gesichert. Die Informationen selbst werden nicht in Cookies oder in der URL abgelegt, daher spielt die Gr\u00f6\u00dfe der Daten auch keine Rolle. Ein HttpSession-Objekt verwaltet einen Assoziativspeicher, der die Wertepaare speichert. Es ist g\u00fcnstig, die Elemente serialisierbar zu gestalten, um die Daten dauerhaft zu speichern.<br \/>\n  <br \/>Werfen wir abschlie\u00dfend einen Blick auf das Programmst\u00fcck, das eine neue Ware hinzuf\u00fcgt:<\/p>\n<pre>List l = (List) session.getAttribute( &quot;artikel&quot; );\nif ( l == null )\n{\n  l = new ArrayList();\n  session.setAttribute( &quot;artikel&quot;, l );\n}\nl.add( w );<\/pre>\n<p><b>interface javax.servlet.http.HttpSession<\/b><\/p>\n<ul>\n<li>Object getAttribute( String name )<br \/>\n    <br \/>Liefert das mit name verbundene Objekt; null, wenn es keine Assoziation gab. <\/li>\n<li>Enumeration getAttributeNames()<br \/>\n    <br \/>Liefert eine Aufz\u00e4hlung aller mit der Sitzung verbundenen Objekte. <\/li>\n<li>void setAttribute( String name, Object value )<br \/>\n    <br \/>Bindet name mit dem Objekt value an die Sitzung. Existierte das Objekt, wird es ersetzt. Angemeldete HttpSessionBindingListener werden \u00fcber die Methode value Bound() beziehungsweise valueUnbound() informiert. <\/li>\n<li>void removeAttribute( String name )<br \/>\n    <br \/>Entfernt das Attribut von der Sitzung. Ung\u00fcltige Namen werden ignoriert. HttpSession BindingListener werden durch Aufruf von valueUnbound() informiert.<\/li>\n<\/ul>\n<p>Alle Methoden liefern eine IllegalStateException, wenn die Sitzung ung\u00fcltig ist. Die Methoden putValue() und setValue() sind veraltet und wurden durch setAttribute() und getAttribute() ersetzt.<\/p>\n<h3>URL-Rewriting<\/h3>\n<p>Das Session-Management sollte im Prinzip unabh\u00e4ngig von der technischen Umsetzung sein. Doch leider greift das Sitzungsmanagement beim URL-Rewriting schon sehr stark ein: Bei jedem Verweis auf eine neue Seite muss die URL entsprechend angepasst werden, weil die Sitzungs-ID mitgeschickt werden muss. Cookies verwalten die Sitzungs-ID v\u00f6llig anders. Das bedeutet: Werden Cookies eingesetzt, \u00e4ndert sich die URL nicht und jeder kann problemlos auf eine neue Seite verweisen. Nur beim URL-Rewriting muss an die URL eine Sitzungskennung angeh\u00e4ngt werden.<br \/>\n  <br \/>Beispiel Eine URL f\u00fcr einen Cookie besitzt keine Sitzungskennung.<\/p>\n<ul>\n<li>http:\/\/localhost\/servlet\/URLRewritingSession<\/li>\n<\/ul>\n<p>Mit URL-Rewriting sieht das dann etwa so aus:<\/p>\n<ul>\n<li>http:\/\/localhost\/servlet\/URLRewritingSession;jsessionid=abcde234<\/li>\n<\/ul>\n<p>Wenn wir innerhalb eines Servlets auf eine andere generierte Seite verweisen wollen, haben wir eine URL vor uns, zu der wir verzweigen m\u00f6chten. Die Servlet-API k\u00fcmmert sich darum, an eine Benutzer-URL die Sitzungs-ID automatisch anzuh\u00e4ngen. Dazu dienen die HttpServletResponse-Methoden encodeURL() und encodeRedirectURL().<\/p>\n<p>Beispiel: Aufgrund einer Formularbest\u00e4tigung soll auf eine JSP-Seite mit dem Namen validate.jsp verwiesen werden:<\/p>\n<pre>&lt;form action='&lt;%= response.encodeURL(&quot;\/validate.jsp&quot;) %&gt;'&gt;<\/pre>\n<p>Werden der Verweis und die Kodierung aus Versehen vergessen, ist dies das Ende der Sitzung. Ob eine Sitzung mit einem Cookie behandelt wird, l\u00e4sst sich mit isRequestedSessionIdFromCookie() testen. Dann kann aufgrund einer Fallunterscheidung encodeURL() verwendet werden oder nicht. Allgemein ist es aber nicht schlecht, grunds\u00e4tzlich alle Verweise innerhalb einer Webapplikation mit encodeURL() zu sichern. Im Fall von Cookies wird zwar keine Kennung angeh\u00e4ngt, eine sp\u00e4tere Umstellung gestaltet sich aber einfacher, falls der Nutzer die Cookies einmal ausschaltet.<\/p>\n<h3>Zus\u00e4tzliche Informationen<\/h3>\n<p>Ein Sitzungsobjekt verwaltet neben den assoziierten Daten noch weitere Informationen. Jede Sitzung bekommt eine eindeutige ID, die sich mit getId() erfragen l\u00e4sst. Ist die Sitzung neu und hat der Client noch nie eine Verbindung gehabt, gibt isNew() den Wert true zur\u00fcck. Existiert dann die Sitzung, gibt getCreationTime() ein long zur\u00fcck \u2013 kodiert sind wie \u00fcblich die vergangenen Millisekunden seit dem 1.1.1970 \u2013, in dem sich das Erstellungsdatum erfragen l\u00e4sst. Dagegen erfragt getLastAccessedTime() die Zeit, die seit dem letzten Zugriff durch den Client vergangen ist. Falls der Server die Informationen dauerhaft speichert und der Cookie nicht abl\u00e4uft, erlaubt dies Meldungen der Art: \u00bbSch\u00f6n, Sie nach zwei Wochen zum f\u00fcnften Mal bei unserer Partnervermittlung wiederzusehen. Hat&#8217;s wieder nicht geklappt?\u00ab<\/p>\n<h3>Das Ende der Sitzung<\/h3>\n<p>Eine Sitzung ist nicht automatisch unendlich lange g\u00fcltig. Bei Cookies l\u00e4sst sich der G\u00fcltigkeitszeitraum einstellen. Auch Sitzungsobjekte lassen sich in der Zeit anpassen. Die Methode setMaxInactiveInterval() setzt den Wert, wie lange eine Sitzung g\u00fcltig ist. Ist der Wert negativ, zeigt er an, dass die Sitzung nicht automatisch beendet wird. Die entsprechende Methode getMaxInactiveInterval() liefert die Zeit in Sekunden, in der eine Sitzung g\u00fcltig ist.<\/p>\n<p><b>interface javax.servlet.http.HttpSession<\/b><\/p>\n<ul>\n<li>long getCreationTime()<br \/>\n    <br \/>Gibt in Millisekunden ab dem 1.1.1970 an, wann die Sitzung er\u00f6ffnet wurde. <\/li>\n<li>String getId()<br \/>\n    <br \/>Liefert eine eindeutige Kennung, die die Sitzung identifiziert. <\/li>\n<li>long getLastAccessedTime()<br \/>\n    <br \/>Gibt in Millisekunden ab dem 1.1.1970 zur\u00fcck, wann der Client zum letzten Mal auf den Server zugegriffen hat. <\/li>\n<li>int getMaxInactiveInterval() <\/li>\n<li>void setMaxInactiveInterval( int interval )<br \/>\n    <br \/>Liefert und setzt die Zeit, f\u00fcr die der Servlet-Container die Sitzung aufrechterhalten soll, bis sie ung\u00fcltig wird. <\/li>\n<li>boolean isNew()<br \/>\n    <br \/>Der R\u00fcckgabewert ist true, wenn die Sitzung neu ist.<\/li>\n<\/ul>\n<p><strong>Beispiel<\/strong> Zum Schluss wollen wir ein Programm formulieren, das alle diese Informationen auf einmal ausgibt.<\/p>\n<pre>&lt;%@ page language=&quot;java&quot; import=&quot;java.util.*&quot; %&gt;\n&lt;%\nint cnt = 0;\nif ( session.isNew() )\n{\nout.println( &quot;Willkommen Neuling!\\n&quot; );\n}\nelse\n{\nout.println( &quot;Hallo, alter Freund!\\n&quot; );\nString o = (String) session.getAttribute( &quot;cnt&quot; );\nif ( o != null )\ncnt = Integer.parseInt( o );\ncnt++;\n}\nsession.setAttribute( &quot;cnt&quot;, &quot;&quot;+cnt );\n%&gt;\n&lt;p&gt;\nSession-ID: &lt;%= session.getId() %&gt; &lt;p&gt;\nErzeugt am: &lt;%= new Date(session.getCreationTime()) %&gt; &lt;p&gt;\nLetzter Zugriff: &lt;%= new Date(session.getLastAccessedTime()) %&gt; &lt;p&gt;\nUng\u00fcltig in Minuten: &lt;%= session.getMaxInactiveInterval()\/60 %&gt; &lt;p&gt;\nAnzahl Zugriffe: &lt;%= cnt %&gt;<\/pre>\n<p>Das Programm liefert beispielsweise folgende Ausgabe:<\/p>\n<pre>Hallo, alter Freund!\nID: 91410050092487D9B5D0D2A7A3D0F072\nErzeugt am: Fri Jan 18 20:16:49 CET 2002\nLetzter Zugriff: Fri Jan 18 20:23:33 CET 2002\nUng\u00fcltig in Minuten: 30\nAnzahl Zugriffe: 4<\/pre>\n<p>Die ID sieht bei jedem Server anders aus. Der Webserver von Sun erzeugt beispielsweise ganz andere Kennungen.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Die Servlet-API bietet die Klasse HttpSession an, eine Bibliothek auf hohem Niveau f\u00fcr die Verwaltung einer Sitzung. Sie basiert entweder auf Cookies oder URL-Rewriting, doch wird das von der API transparent gehalten. Als Programmierer bekommen wir so gut wie gar nichts davon mit. Falls der Client keine Kekse mag, wandeln wir alle Informationen in URLs [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","_links_to":"","_links_to_target":""},"categories":[9,15],"tags":[],"class_list":["post-2372","post","type-post","status-publish","format-standard","hentry","category-java-ee","category-web-frameworks"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/2372","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/comments?post=2372"}],"version-history":[{"count":1,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/2372\/revisions"}],"predecessor-version":[{"id":2373,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/2372\/revisions\/2373"}],"wp:attachment":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/media?parent=2372"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/categories?post=2372"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/tags?post=2372"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}