The basic concepts of the listener, as well as the various listeners of the servlet, have been explained in the first article. This blog post is mainly about the application of listeners.
Statistics website Online Number analysis
We generally use the session in the site to identify whether a user is logged in, if logged in, the session field to save the corresponding attributes. If you do not log in, the session's properties should be empty.
Now, what we want to count is the number of people online on the website. We should do this: we monitor if a new session is created, and if the new sesssion is created, the number of people online should be +1. This online number is the entire site, so there should be a context object to save.
General idea:
- Whether the listener session was created
- If the session is created, then the value of the domain object in the context should be +1
- If the session is removed from memory, then the value of the domain object in the context should be-1.
Code
Public classCountonlineImplementsHttpsessionlistener { Public void sessioncreated(Httpsessionevent se) {//Get the context object and save the number of users online using the context domain objectServletContext context = se.getsession().Getservletcontext();///directly determine if the context object exists in this domain, if there is a number of +1, if it does not exist, then set the property to the context domainInteger num = (integer) context.getattribute("num");if(num = =NULL) {context.SetAttribute("num",1); }Else{num++; Context.SetAttribute("num", num); } } Public void sessiondestroyed(Httpsessionevent se) {ServletContext context = se.getsession().Getservletcontext(); Integer num = (integer) se.getsession().getattribute("num");if(num = =NULL) {context.SetAttribute("num",1); }Else{num--; Context.SetAttribute("num", num); } } }
在线人数:${num}
Test
Every single browser we use to access the server will create a new session. Then the number of online people on the site will be +1.
Using the same page refresh, or the use of the sesssion, so the number of online site is not changed.
Custom session Scanner
We all know that the session is stored in memory, and if the session is too much, the pressure on the server will be very large.
However, thedefault expiration time for a session is 30 minutes (30 minutes for no one to fail), which causes seesion to be too much (no one is in memory, this is not a significant waste?). )
Of course, we can configure the session life cycle in the Web. xml file . But, this is done by the server, I suspect it's time is not accurate. (Sometimes I configure 3 minutes, it took 4 minutes to help me remove the session)
So, I decided to use my own program to manually remove those sessions that were not used for a long time.
Analysis
If you want to remove a session that has not been used for a long time, you must first get the full session. So we use a container to load all the sessions of the site.
As soon as the Sesssion is created, the session is added to the container . There is no doubt that we need to listen to the session.
Then, what we have to do is to scan all sessions at intervals, and if a session is unused for a long time, we remove it from memory. It must be the task of the timer to do something at intervals.
The timer should be created when the server is started. So we need to listen to the context.
Finally, we have to consider the concurrency problem, if someone accesses the site at the same time, then the listener session creation method will be accessed concurrently . when the timer scans the container, it may not be able to get all of the session .
This requires us to do the synchronization
So, we already have a general idea.
- Listening for session and context creation
- Use a container to load the session
- Periodically scans the session and removes the session from memory if it has not been used for a long time.
- Issues with concurrent access
Code
Public classListener1ImplementsServletcontextlistener, Httpsessionlistener {//When the server starts, you should create a container. We are using linklist (involving additions and deletions). The container should also be thread-safe. listsynchronizedlist(NewLinkedlist//Define a lock (the session is added to the container and the scan container should be synchronized) PrivateObject lock =1; Public void contextinitialized(Servletcontextevent SCE) {Timer timer =NewTimer ();//Perform the task I want, 0 seconds delay, execute once every 10 secondsTimer.Schedule(New MyTask(list, lock),0,Ten* +); } Public void sessioncreated(Httpsessionevent se) {//As long as session one is created, it should be added to the container synchronized(lock) {list.Add(SE.getsession()); } System. out.println("The session was created."); } Public void sessiondestroyed(Httpsessionevent se) {System. out.println("The session was destroyed. "); } Public void contextdestroyed(Servletcontextevent SCE) { } }
/** In the task should scan the container, the container on the listener, can only pass in. ** To get a lock on the listener, it can only be passed in * * */ classMyTaskextendsTimerTask {PrivateListPrivateObject lock; Public MyTask(list This.Sessions= sessions; This.Lock= lock; }@Override Public void Run() {synchronized(lock) {//Traversal container for(HttpSession session:sessions) {//As long as 15 seconds no one is used, I'll remove it. if(System.Currenttimemillis()-session.Getlastaccessedtime() > ( +* the) {session.Invalidate(); Sessions.Remove(session); } } } } }
15 seconds if the session is not active, then it is deleted!
- Use the collection to load all of our session
- Use a timer to scan the session's declaration period "We'll just pass in the timer without the session."
- On the issue of concurrent access, when we scan and detect the session is added, the synchronization is good "of course, the lock of the timer is also to pass in the outside."
Kicking man small Case list
List all the online users, the background manager has the right to kick people, click on the kicker's hyperlink, the user is logged off.
Analysis
First of all, how can we list all the online users?? In general, our online users are tagged with a session , and all online users should use a container to load all the sessions.
We listen to the session whether there is a property to add ( listen to the session's properties are added, modified, delete three methods.) If the supervisor hears the session added, then this must be an online user! ).
The container that loads the session should be the "full site" inside the context, and the container should use the map set "to kick the user by the user's name later."
Ideas:
- write the listener and listen for any attributes added to the session .
- Write a simple landing page.
- List all online users
- Kick-off function (i.e. destroy session)
Code
Public classKickpersonImplementsHttpsessionattributelistener {//Public constructor are required by servlet spec Public Kickperson() { } Public void attributeadded(Httpsessionbindingevent SBE) {//Get context object to see if the context object has container loading sessionServletContext context = SBE.getsession().Getservletcontext();//If not, create a chantMap map = (map) context.getattribute("Map");if(Map = =NULL) {map =NewHashMap (); Context.SetAttribute("Map", map); }//--------------------------------------------------------------------------------------- //Get the value of the session propertyObject o = sbe.GetValue();//Determines whether the content of the property is a user object if(OinstanceofUser) {User user = (user) O; Map.put(User.GetUserName(), SBE.getsession()); } } Public void attributeremoved(Httpsessionbindingevent SBE) {/ * This method is called if an attributeis removed from a session. */} Public void attributereplaced(Httpsessionbindingevent SBE) {/ * This method is invoked if an attibuteis replaced in a session. */}}
<form action="${pageContext.request.contextPath }/LoginServlet" method="post"> 用户名:<input type="text" name="username"> <input type="submit" value="登陆"></form>
- Handling the login servlet
//得到传递过来的数据 String username = request.getParameter("username"); newUser(); user.setUsername(username); //标记该用户登陆了! request.getSession().setAttribute("user", user); //提供界面,告诉用户登陆是否成功 request.setAttribute("message""恭喜你,登陆成功了!"); request.getRequestDispatcher("/message.jsp").forward(request, response);
<c:forEach items="${map}" var="me"> ${me.key} <a href="${pageContext.request.contextPath}/KickPersonServlet?username=${me.key}">踢了他吧</a> <br></c:forEach>
- The servlet that handles kicking people
String username = request.getParameter("username"); //得到装载所有的Session的容器 this.getServletContext().getAttribute("map"); //通过名字得到Session HttpSession httpSession = (HttpSession) map.get(username); httpSession.invalidate(); map.remove(username); //摧毁完Session后,返回列出在线用户页面 request.getRequestDispatcher("/listUser.jsp").forward(request, response);
Test
Use multiple browsers to log in to simulate online users (the same browser uses the same session)
What is the difference between the creation of the listening seesion and the monitoring session property???
- Session creation only represents the browser sending a request to the server. Session Creation
- The change of the session property is different, the registration is whether the specific user did something (landed, bought a product)
If the article is wrong, welcome to correct, we communicate with each other. Students who are accustomed to reading technical articles can pay attention to the public number: JAVA3Y
Listener App "Statistics website number, custom session scanner, kick people small case"