java - Counting current users viewing a page -
java - Counting current users viewing a page -
i working on counting number of viewing user on page. basically, when user view url localhost:8080/itemdetail.do?itemid=1
, page showing how many users viewing on page @ same time.
solution approach
when user viewing particular page, page go on send ajax request every 1 sec server, server utilize map<string, map<string, integer>>
(both utilize concurrenthashmap
initialization) contain itemid
(to know page viewed) , ip
, timeout
count (in inner map
). every time getting request, counting increment 1. there thread fired during request process decrease timeout counting every 2 seconds. if in end, timeout counting equal 0, app consider user stopped viewing page, thread remove entry , number of user decreased 1. little problem approach since timeout number increasing faster decreasing, if user open page long plenty , close page, app take sometime know that user left page, because timeout number @ moment quite big
implementation
// controller @requestmapping(value = appconstants.action_number_viewing, method = get) @responsebody public int useritemviewing(httpservletrequest request, @requestparam(value = "itemid") string itemid) { seek { homecoming eventservice.countuseronline(request, itemid); } grab (caserviceexception e) { e.printstacktrace(); log.error("========== error when counting number of online user ==========" + e.getmessage()); } homecoming 0; } // service private static map<string, map<string, integer>> numberofcurrentviews; private thread countdownonlinethread; class onlinecountingdownrunnable implements runnable { private list<string> timeoutlist = new arraylist<string>(); private void cleantimeoutips() { (string itemid : numberofcurrentviews.keyset()) { map<string, integer> currentips = numberofcurrentviews.get(itemid); for(string ip : timeoutlist){ currentips.remove(ip); } } } @override public void run() { seek { (string itemid : numberofcurrentviews.keyset()) { map<string, integer> currentips = numberofcurrentviews.get(itemid); for(string ip : currentips.keyset()){ integer timeout = new integer(currentips.get(ip).intvalue() - 1); if (timeout == 0) { timeoutlist.add(ip); } currentips.put(ip, timeout); } } cleantimeoutips(); // counting downwards time must double increasing time thread.sleep(2000); } grab (interruptedexception e) { e.printstacktrace(); log.error("---------------- thread error in counting downwards online user: " + e.getmessage()); } } } public int countuseronline(httpservletrequest request, string itemid) throws caserviceexception { // create count downwards timer observe if user not view page anymore string ip = request.getremoteaddr(); // init counting downwards online user map if (numberofcurrentviews == null) { numberofcurrentviews = new concurrenthashmap<string, map<string, integer>>(); } // start thread check user online if (countdownonlinethread == null) { countdownonlinethread = new thread(new onlinecountingdownrunnable()); countdownonlinethread.start(); } log.debug("---------------- requested ip: " + ip); if (ip == null || ip.isempty()) { throw new caserviceexception("======= cannot observe ip of client ======="); } if (numberofcurrentviews.get(itemid) != null) { map<string, integer> userview = numberofcurrentviews.get(itemid); if (userview.get(ip) != null) { userview.put(ip, userview.get(ip).intvalue() + 1); } else { userview.put(ip, 1); } numberofcurrentviews.put(itemid, userview); } else { map<string, integer> ips = new concurrenthashmap<string, integer>(); ips.put(ip, 1); numberofcurrentviews.put(itemid, ips); } log.debug(string.format( "============= %s seeing there %s users viewing item %s =============", ip, numberofcurrentviews.get(itemid).size(), itemid )); homecoming numberofcurrentviews.get(itemid).size(); }
problems
i have no thought how test functionality since requires multiple ip addresses view page. have tried set jmeter , set ip spoofing link not successful, made little mock test view log
@test public void testcountuseronline() throws exception { list<httpservletrequest> requests = new arraylist<httpservletrequest>(); (int = 0; < 10; ++) { httpservletrequest request = mockito.mock(httpservletrequest.class); mockito.when(request.getremoteaddr()).thenreturn(string.format("192.168.1.%s", i)); requests.add(request); } list<thread> threads = new arraylist<thread>(); (int = 0; < 10; ++) { thread thread = new thread(new requestrunnable(requests.get(i))); threads.add(thread); thread.start(); } (thread thread : threads) { thread.join(); } } class requestrunnable implements runnable { private httpservletrequest request; public requestrunnable(httpservletrequest request) { this.request = request; } public void run() { seek { int = 0; while (i < 10) { eventservice.countuseronline(request, "1"); i++; system.out.println(i); thread.sleep(1000); } } grab (caserviceexception e) { e.printstacktrace(); } grab (interruptedexception e) { e.printstacktrace(); } } }
but again, not confident implementation
also, normal way human using count number of viewing users on page? want create sure don't miss in case there shortcut part. using spring mvc 3.x
. need back upwards ie 9 :(((, web socket
cannot used extensively
have tried apache benchmarking tool ?
http://httpd.apache.org/docs/2.2/programs/ab.html
java spring-mvc mockito distributed-computing
Comments
Post a Comment