In-depth understanding and improvement JSPServlet session management mechanism

xiaoxiao2021-03-06  172

I. Session management mechanism for servlet

According to the design, HTTP is a stateless protocol. It means that the web application does not understand the information about the same user's previous request. One way to maintain session status information is to use the session tracking function provided by the Servlet or JSP container. The Servlet API specification defines a simple HttpSession interface, which we can easily implement session tracking.

The HTTPSession interface provides a method of storing and returning a standard session attribute. Standard session properties such as session identifiers, application data, etc., are saved in the form of "Name-Value" pair. Briefly, the HTTPSession interface provides a standard approach to save objects to memory, extracting these objects in subsequent requests for the same user. The method of saving data in a session is SetAttribute (String S, Object O), and the method of extracting the original saved object from the session is GetAttribute (String S).

In the HTTP protocol, there is no explicit termination signal when the user is no longer active. For this reason, we don't know if the user returns again. If you do not take some way to solve this problem, you will accumulate a lot of HttpSession objects in memory.

To this end, servlet uses "timeout limit" to determine if the user is still accessing: If a user does not issue a successful request within a certain time, the user's session is invalid, his httpsession object is released. The default time separation of the session is defined by the servlet container. This value can be obtained via the GetMaxInactiveInterval method, modified via the SetMaxActiveIveterval method, and the timeout in these methods is subject. If the timeout time value of the session is set to -1, the session will never time out. The servlet can get the last access time before the current request before getting the GetLastAccessedTime method.

To get an HTTPSession object, we can call the GetSession method for the HTTPSERVLETREQUEST object. In order to properly maintain the session state, we must call the GetSession method before sending any response content.

User sessions can be invalidated with manual methods or automatically. The invalidation session means deleting HttpSession objects from memory and its data. For example, if the user does not send a request within a certain time (default 30 minutes), Java Web Server automatically makes a waste of his session.

The servlet / JSP session tracking mechanism has certain limitations, such as:

· The session object is saved in memory, accounting for considerable resources.

· Session tracking depends on cookie. For various reasons, especially for security, some users have closed cookies.

· Session Tracking The session identifier created by the server. In multiple web servers and multiple JVM environments, the web server cannot identify session identifiers created by other servers, and the session tracking mechanism cannot work.

To understand the session tracking mechanism, we must understand how the session is operated in the servlet / JSP container.

Second, the session identifier

Whenever a new user requests a JSP page that uses the HttpSession object, the JSP container has to send a special number to the browser in addition to the response page. This special number is called "session identifier", which is a unique user identifier. Thereafter, the httpsession object resides in memory, waiting for the same user to call its method again.

On the client, the browser saves the session identifier and sends this session identifier to the server in each subsequent request. The session identifier tells the JSP container that the current request is not the first request issued by the user. The server has previously created an HttpSession object for the user. At this point, the JSP container no longer creates a new HttpSession object for the user, but looking for an HttpSession object with the same session identifier and then built the HTTPSession object and the current request. The session identifier is transmitted between the server and the browser in the form of cookie. What is the browser does not support cookie? At this point, the subsequent request will not have a session identifier. As a result, the JSP container considers that the request comes from a new user, which will create an HttpSession object, while the previously created HttpSession object still resides in memory, but the user's previous session information is lost.

In addition, the servlet / JSP container only recognizes the session identifier itself created. If the same web application runs on multiple servers of "Web Farm", there must be a mechanism: ensuring that requests from the same user are always oriented to the first time requested by the user.

Third, pseudo-session management mechanism

As mentioned earlier, Cookie-based session management technology faces various problems. Below we want to design a new session management mechanism to solve these problems. This session management mechanism is called the "Pseudo Session" mechanism, which has the following characteristics:

· Objects and data are not saved in memory, but saved in the form of text files. Each text file is associated with a specific user, the name of the file is the identifier of the session. Therefore, the file name must be unique.

• Text file is saved in a dedicated directory, all web servers can access this directory. Therefore, the pseudo will be used for web farms.

· The session identifier is not sent as a cookie, but directly encoded to the URL. Therefore, the use of pseudo-conference techniques to modify all hyperlinks, including the an action attribute of the HTML form.

In addition, we have to take into account the following points when implementing a pseudo-session management mechanism:

· It should have nothing to do with the application, and other developers who want to implement the same function should be able to easily reuse it.

· Considering safety reasons, there should be a way to generate random numbers for session identifiers.

· In order to invalid expiration, a timeout value should be set. With the same user, if he returns again after a certain time, he will get a new session identifier. This will prevent unauthorized users from using sessions of others.

· There should be a mechanism to collect expired sessions and delete the corresponding text files.

· If the user uses the expired session identifier to access the server again, even if the text file of this session identifier has not been deleted, the system should not allow the user to use the original session.

At the same time, there should be a mechanism for updating the last change time of the session text file, so that the session always maintains the latest and legally state data when the user returns before the session expired time limit.

Fourth, implement the pseudo-session management mechanism

The project described below is called Pseudosession, which is a very simple implementation of the pseudo-talk. Considering the portability, we implement it in the form of javabean. PseudosessionBean's full code can be downloaded later in this article.

PseudosessionBean has a Deli (Field):

PUBLIC STRING PATH; PUBLIC Long Timeout;

PATH is a directory that holds all session text files. If the number of web servers is more than one, this directory must allow all servers to access. However, in order to prevent the user from accessing these text files directly, this path should not allow users to directly access them. One way to solve this problem is to use the directory outside the root of the Web website.

TIMEOUT is the time between the last request to the session expired. In the code list of the PseudosessionBean, Timeout is set to 20 minutes represented in milliseconds, which is a relatively reasonable timeout value. For any user, if he continues to issue a request after this timeout, he will get a new session identifier.

PseudosessionBean has 4 methods: GetSessionID, SetValue, GetValue, DeleteallInvalidSssions.

4.1 GetSessionID method

The declaration of the GetSessionID method is as follows:

Public String GetSessionId (httpservletRequest request)

This method should be called at the beginning of each JSP page. It completes the following tasks:

• If the user is the first visit, set a new session identifier for the user.

• Check the legality of the session identifier with the URL. If the session identifier has expired, the GetSessionID method returns a new session identifier.

Let's take a look at the work process of the GetSessionID method.

String sessionid = Request.getParameter ("sessionid");

ValidSessionIDFound is a tag that indicates whether the session identifier is legal. The initial value of ValidSessionIDFound is false.

Boolean ValidSessionIDFound = false;

The NOW variable of the long type contains the server time when requesting. This variable is used to determine the legality of the user session.

Long Now = system.currenttimemillis ();

If a session identifier is found, the getSessionID method checks its legitimacy. The inspection process is as follows:

· A legal session identifier must have a corresponding same text file.

· The final modification time of the file plus TIMEOUT should be greater than the current time.

• If there is a text file corresponding to the session, the file has expired, the original file is deleted.

· Change the last modification date of the text file corresponding to the legal conference identifier to NOW.

These tasks are mainly completed by the File object, and the parameters for creating a File object are the path to the session text file:

IF (sessioniD! = null) {file f = new file (path sessionid); if (f.exists ()) {if (f.lastmodified () timeout> now) {// session legal // When using setLastModified If the file has been locked by other programs, the program does not generate any exception, but the file data will not change f.setLastModified (now); validsessionidfound = true;} else {// session has expired // Delete file f.delete ()}} // end if (f.exists)} // end if (sessionid! = null)

If there is no legal session identifier, the getSessionID method generates a session identifier and the corresponding text file:

If (! ValidSessionIDFound) {sessionID = long.toString (now); // Create a file file f = new file (path sessionid); try {f.createNewFile ();} catch ({ooException ie) {}} // end Of! ValidSessionIDFound

The program guarantees that the file name random is very simple: convert the current system time directly into a session identifier. For applications involving sensitive data, we should consider using a safer random number generator to generate a session identifier. In summary, GetSessionId does not always return to a new legal meeting identifier: It returns the identifier that it may be the same as the identifier passed, or the newly created session identifier.

To ensure that the JSP page has a legitimate session identifier to call the setValue, getValue method, each JSP page must call the GetSessetctionID method at the beginning.

4.2 SetValue Method

SetValue method Save the Value string and the string name associated with it. This "name-value" is easy to remember the Dictionary object. The setValue method requires the legitimate session identifier to provide legal session identifiers in the first parameter, which assumes that the GetSessionID method has executed before you call it, and the verified legal conference identifier necessarily exists, so it no longer performs the incoming session identifier. Legal test.

The setValue method saves the name-value pair as follows:

• If Name associated with the value value has not been saved before, the new name-value is added to the end of the text file.

• If the value value associated with the Value string has been saved before, the original saved value is replaced by the new value value.

The setValue method saves the name-value pair in the following format, pay attention to the "name" is sensitive:

Name-1 value-1Name-2 value-2name-3 value-3 ... name-n value-n

The declaration of the setValue method is as follows:

Public void setValue (String SessionID, String Name, String Value)

SetValue method first looks for text files corresponding to the current session. If you can't find a text file, the setValue method does not do anything directly. If a session text file is found, the setValue method reads the various rows of the text file, then compares the read rows and name: If the read text row is starting with Name, then the name has been saved, the setValue method will replace the line. The back value; if Name cannot match the read text row, the line text is copied directly to a temporary file.

The implementation code of this part of this component is as follows:

try {FileReader fr = new FileReader (path sessionId); BufferedReader br = new BufferedReader (fr); FileWriter fw = new FileWriter (path sessionId ".tmp"); BufferedWriter bw = new BufferedWriter (fw); String s; While ((s = br.readline ())! = NULL) IF (! S.StartSwith (Name ")) {bw.write (s); bw.newline ();} bw.write (Name " " value); bw.newline (); br.close (); fw.close (); bw.close (); bw.close ();....} catch (filenotfoundexception e) {} catch (ooException ) {System.out.println (e.tostring ());

After all rows in the original text file copy to the temporary file, the setValue method deletes the original text file, and then change the temporary file to the name of the session text file:

File f = new file (path sessionid ".tmp"); file dest = new file (path sessionid); dest.delete (); f.renameto (dest); 4.3 GetValue method

The getValue method is used to extract the data stored in the pseudo. As the setValue method, the getValue method also requires access to a legitimate session identifier, and the getValue method no longer checks the incoming session identifier. The second parameter of the GetValue method is the NAME to be extracted, and the return value is Value associated with the specified Name.

The declaration of the GetValue method is as follows:

Public String getValue (String Sessionid, String Name)

The basic execution of the getValue method is as follows: First find the session text file, then read until the line is found to find the text line matching with the Name; find the matching text line, getValue method returns the value saved by the row; if you can't find, getValue method Returns NULL.

4.4 DeleteallInvalidSessionS method

DeleteallInvalidSessionS methods remove text files associated with the expired session. The DELETEALLINVALIDSESSIONS method is not a key way because the expired session text files will be deleted. When to call this method, it is determined by applying itself. For example, we can write a dedicated background program that removes all expired text files once a day. The easiest way is to call the DeleteallInvalidSsSions method at the end of the JSP file, but if the website is busy, repeatedly calling the DeleteallInvalidSsSions method will reduce the response capability of the entire website. A sensible approach is to prepare a background program that automatically cleans up when the access is less.

The declaration of the DeleteallInvalidSessionS method is as follows:

Public void deleteallInvalidSasonS ()

It first reads the name of all session text files into the files string:

File Dir = new file (path); string [] files = dir.list ();

DeleteallInvalidSessionS method compares the final modification time of the text file (plus timeout) and the current time of the system, determine if the session has expired. The long type of variable NOW is used to save the current time of the system.

Long Now = system.currenttimemillis ();

Next, the DeleteallInvalidSsSs method uses a loop to access the files array, check the lastmodified properties of each file. All files associated with expired sessions will be deleted:

For (int i = 0; i now) f.delete (); // Delete expired session text files}

V. Application instance

After compiling PseudosessionBean this JavaBean, we can use the pseudo-session management mechanism to manage the session status information of the web application. Since you don't have to use the server's session management mechanism, we can set the session property to false to false to close the default JSP / Servlet session management feature in the Page instruction.

<% @ page session = "false"%> then we use the JSP tag to tell the JSP container program to use PseudosessionBean:

In this tag, the class attribute value is "package. Class name" form. Of course, for different bag names, the value of the class attribute should be modified. Note that the Scope property of the bean is "Application" because we have to use this bean in all pages of the app. In this application, set the BEAN's Scope property to "Application" with the best efficiency, because we only need to create a bean object once. In addition, as mentioned earlier, the GetSessionID method must call before all other code.

<% String sessionid = pseudosessionid.getsessionId (request);%>

To illustrate the application of PseudosessionBean, let's take a look at two JSP pages, they are index.jsp and secondpage.jsp. The index.jsp page saves the user's name in the pseudo-variable, and secondpage.jsp extracts this user name.

The code of the index.jsp page is as follows:

<% @ Page session = "false" contenttype = "text / html; charset = GB2312"%> <% string sessionID = PseudosessionId.getSessionId (Request);%> Pseudo-Session </ Title> </ head> <body> <H1> Pseudohi Management Mechanism </ h1> <br /> <% String UserName = "Bulbul"; PseudosessionId.setValue (sessionid, "username", username);%> <a href=secondpage.jsp?sessionID=word.jsp?sessionID=< %=sessionID%> Click here </A> <br /> <form Method = "post" Action = anotherpage.jsp? sessionId = <% = sessionID% >> <br /> Enter data: <input type = "text" name = "sample"> <br /> <input type = "SUBMIT "Name =" submit "value =" submit "> </ form> </ body> </ html> <% pseudosessionId.deleteallinvalidSessionS ();%> Note, including the <form> tag an action property, all super The link has been rewritten and now contains the session identifier. Also note that the final call of the page is called the DeleteallInvalidSessionS method.</p> <p>The secondpage.jsp page simply returns the previously saved user name.</p> <p><% @ ContentType = "Text / HTML; Charset = GB2312" Page session = "false"%> <jsp: usebean id = "pseudosessionID" scope = "application" class = "pseudosession.pseudosessionBean" /> <% string sessionID = PseudosessionID.getSessionId (Request);%> <html> <head> <title> 2 page </ title> </ head> <body> <% string username = pseudosessionid.getValue (sessionid, "username"); OUT .println ("User Name is" UserName);%> </ body> </ html></p></div><div class="text-center mt-3 text-grey"> 转载请注明原文地址:https://www.9cbs.com/read-128093.html</div><div class="plugin d-flex justify-content-center mt-3"></div><hr><div class="row"><div class="col-lg-12 text-muted mt-2"><i class="icon-tags mr-2"></i><span class="badge border border-secondary mr-2"><h2 class="h6 mb-0 small"><a class="text-secondary" href="tag-2.html">9cbs</a></h2></span></div></div></div></div><div class="card card-postlist border-white shadow"><div class="card-body"><div class="card-title"><div class="d-flex justify-content-between"><div><b>New Post</b>(<span class="posts">0</span>) </div><div></div></div></div><ul class="postlist list-unstyled"> </ul></div></div><div class="d-none threadlist"><input type="checkbox" name="modtid" value="128093" checked /></div></div></div></div></div><footer class="text-muted small bg-dark py-4 mt-3" id="footer"><div class="container"><div class="row"><div class="col">CopyRight © 2020 All Rights Reserved </div><div class="col text-right">Processed: <b>0.037</b>, SQL: <b>9</b></div></div></div></footer><script src="./lang/en-us/lang.js?2.2.0"></script><script src="view/js/jquery.min.js?2.2.0"></script><script src="view/js/popper.min.js?2.2.0"></script><script src="view/js/bootstrap.min.js?2.2.0"></script><script src="view/js/xiuno.js?2.2.0"></script><script src="view/js/bootstrap-plugin.js?2.2.0"></script><script src="view/js/async.min.js?2.2.0"></script><script src="view/js/form.js?2.2.0"></script><script> var debug = DEBUG = 0; var url_rewrite_on = 1; var url_path = './'; var forumarr = {"1":"Tech"}; var fid = 1; var uid = 0; var gid = 0; xn.options.water_image_url = 'view/img/water-small.png'; </script><script src="view/js/wellcms.js?2.2.0"></script><a class="scroll-to-top rounded" href="javascript:void(0);"><i class="icon-angle-up"></i></a><a class="scroll-to-bottom rounded" href="javascript:void(0);" style="display: inline;"><i class="icon-angle-down"></i></a></body></html><script> var forum_url = 'list-1.html'; var safe_token = 'HcIP6QutjyH970z75qYxv9RSzCveXc2uh8iJvvPGbWV_2FW4gPlebuqG4hYuqC7wZWlYLFxhGxOJNecfPIUT5N3w_3D_3D'; var body = $('body'); body.on('submit', '#form', function() { var jthis = $(this); var jsubmit = jthis.find('#submit'); jthis.reset(); jsubmit.button('loading'); var postdata = jthis.serializeObject(); $.xpost(jthis.attr('action'), postdata, function(code, message) { if(code == 0) { location.reload(); } else { $.alert(message); jsubmit.button('reset'); } }); return false; }); function resize_image() { var jmessagelist = $('div.message'); var first_width = jmessagelist.width(); jmessagelist.each(function() { var jdiv = $(this); var maxwidth = jdiv.attr('isfirst') ? first_width : jdiv.width(); var jmessage_width = Math.min(jdiv.width(), maxwidth); jdiv.find('img, embed, iframe, video').each(function() { var jimg = $(this); var img_width = this.org_width; var img_height = this.org_height; if(!img_width) { var img_width = jimg.attr('width'); var img_height = jimg.attr('height'); this.org_width = img_width; this.org_height = img_height; } if(img_width > jmessage_width) { if(this.tagName == 'IMG') { jimg.width(jmessage_width); jimg.css('height', 'auto'); jimg.css('cursor', 'pointer'); jimg.on('click', function() { }); } else { jimg.width(jmessage_width); var height = (img_height / img_width) * jimg.width(); jimg.height(height); } } }); }); } function resize_table() { $('div.message').each(function() { var jdiv = $(this); jdiv.find('table').addClass('table').wrap('<div class="table-responsive"></div>'); }); } $(function() { resize_image(); resize_table(); $(window).on('resize', resize_image); }); var jmessage = $('#message'); jmessage.on('focus', function() {if(jmessage.t) { clearTimeout(jmessage.t); jmessage.t = null; } jmessage.css('height', '6rem'); }); jmessage.on('blur', function() {jmessage.t = setTimeout(function() { jmessage.css('height', '2.5rem');}, 1000); }); $('#nav li[data-active="fid-1"]').addClass('active'); </script>