In this tutorial, I will guide you how to implement the hit counter feature that displays total number of pageviews and number of online visitors for a Java web application – this kind of information is displayed at the end of every web page like this:

Total Pageviews: 123,456 – Online Visitors: 45

When a user visits a webpage, a pageview is counted and accumulated to the total pageviews. To count the pageviews, we use a Java Servlet Filter that intercepts all requests coming to the web application, and increase the pageview number by 1 for every request. The following picture illustrates this technique:

pageviews using filter technique

The benefit of using filter mechanism is that, it doesn’t alter any pages nor existing code – thus easy to implement. The pseudocode to implement this filter would be like this:

class Filter {
	
	public void doFilter() {
		
		// increase pageviews by 1
		
		// allow the request to reach the destination
	}
}

The pageviews (hit count) information should be stored permanently because the web application or the server can be shut down or restarted. For the sake of simplicity, I use a text file to store the number of pageviews. So the workflow in the filter would be updated like this:

class Filter {
	
	public void doFilter() {

		// read current pageviews from file
		
		// increase pageviews by 1
		
		// update pageviews to file		
		
		// allow the request to reach the destination
		
		// display pageviews at the end of the page
	}
}

And to count the number of online visitors, we can take advantage of a HttpSessionListener that is triggered when a session event happens (session created and session destroyed). The pseudo code would be like this:

class HttpSessionListener {

	public void sessionCreated() {
		// increase online users by 1
	}


	public void sessionDestroyed() {
		// decrease online users by 1
		
	}
}

When a user visits the website, a new session is created and the session is counted as one online user. After the user leaves the website for sometimes (after a timeout period), the session is destroyed – hence the number of online users should be decreased by one. Notice the online users number is a just a rough estimation – not exact one.

Here’s the real implementation code of a HttpSessionListener that is used to track the number of online users:

/**
 * Copyright by www.codejava.net
 */
package net.codejava;

import javax.servlet.ServletContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

@WebListener
public class UserSessionListener implements HttpSessionListener {
	static final String ONLINE_USERS = "OnlineUsers";
	
	@Override
	public void sessionCreated(HttpSessionEvent se) {
		ServletContext context = se.getSession().getServletContext();

		Integer onlineUsersCount = 0;
		
		Object attributeValue = context.getAttribute(ONLINE_USERS);
		
		if (attributeValue != null) {
			onlineUsersCount = (Integer) attributeValue;		
		}
		
		context.setAttribute(ONLINE_USERS, ++onlineUsersCount);
	}

	@Override
	public void sessionDestroyed(HttpSessionEvent se) {
		ServletContext context = se.getSession().getServletContext();
		
		Integer onlineUsersCount = (Integer) context.getAttribute(ONLINE_USERS);
		
		context.setAttribute(ONLINE_USERS, --onlineUsersCount);
		
	}
}

As you can see, the number of online users is stored as an attribute in the servlet context (application scope), so it can be used by the hit counter filter to display the number of online visitors in webpages. Here’s code of the filter class that is used to count the number of pageviews to the site:

/**
 * Copyright by www.codejava.net
 */
package net.codejava;

import java.io.*;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;

@WebFilter("/*")
public class HitCounterFilter implements Filter {
	
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		ServletContext context = request.getServletContext(); 
		
		String realWebAppPath = context.getRealPath("");
		String hitFilePath = realWebAppPath.concat("hit.txt");
		File hitFile = new File(hitFilePath);
		
		long currentHit = readHitCounterFromFile(hitFile);

		updateHitCounterFile(++currentHit, hitFile);
		
		CharResponseWrapper wrapper = new CharResponseWrapper((HttpServletResponse) response);	
		
		chain.doFilter(request, wrapper);
		
		int onlineUsers = (Integer) context.getAttribute(UserSessionListener.ONLINE_USERS);
		
		displayHitCounter(wrapper, response, currentHit, onlineUsers);
	}

	// see code of other methods below...	
}

Note that the pageviews information is stored in the hit.txt file which is created under the web application’s root directory:

ServletContext context = request.getServletContext(); 

String realWebAppPath = context.getRealPath("");
String hitFilePath = realWebAppPath.concat("hit.txt");
File hitFile = new File(hitFilePath);

Code of the method that reads the pageviews number from the text file is as follows:

private long readHitCounterFromFile(File hitFile) throws NumberFormatException, IOException {
	if (!hitFile.exists()) {
		return 0;
	}
	
	try (BufferedReader reader = new BufferedReader(new FileReader(hitFile));) {
		
		long hit = Integer.parseInt(reader.readLine());
		
		return hit;
	}	
}

Code of the method that updates the pageviews number to the text file is as follows:

private void updateHitCounterFile(long hit, File hitFile) throws IOException {
	try (BufferedWriter writer = new BufferedWriter(new FileWriter(hitFile));) {
		writer.write(String.valueOf(hit));
	}
}

And to display the hit counter information (pageviews and online users) at the end of every webpages, we need to code a response wrapper class as follows:

package net.codejava;

import java.io.CharArrayWriter;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class CharResponseWrapper extends HttpServletResponseWrapper {
	private CharArrayWriter writer;
	
	public CharResponseWrapper(HttpServletResponse response) {
		super(response);
		writer = new CharArrayWriter();
	}
	
	public PrintWriter getWriter() {
		return new PrintWriter(writer);
	}
	
	public String toString() {
		return writer.toString();
	}

}

Note that to allow the filter to alter the response, we need to invoke the doFilter() method on the FilterChain like this:

CharResponseWrapper wrapper = new CharResponseWrapper((HttpServletResponse) response);
chain.doFilter(request, wrapper);

Then in this filter, the number of online users is read from an attribute in the servlet context using the following statement:

int onlineUsers = (Integer) context.getAttribute(UserSessionListener.ONLINE_USERS);

And code of the method that puts a piece of HTML code at the end of every webpage to display the hit counter information is as follows:

private void displayHitCounter(CharResponseWrapper wrapper, ServletResponse response, 
		long currentHit, int onlineUsers) throws IOException {
	PrintWriter writer = response.getWriter();
	
	if (wrapper.getContentType().contains("text/html")) {
		CharArrayWriter caw = new CharArrayWriter();
		String originalContent = wrapper.toString();
		int indexOfCloseBodyTag = originalContent.indexOf("</body>") - 1;
		
		caw.write(originalContent.substring(0, indexOfCloseBodyTag));
		
		String hitCounterContent = "<p>Online Users: " + onlineUsers
				+ " - Pageviews: " + currentHit + "</p>";
		caw.write(hitCounterContent);
		caw.write("\n</body></html>");
		
		String alteredContent = caw.toString();
		response.setContentLength(alteredContent.length());
		writer.write(alteredContent);
		
	} else {
		writer.write(wrapper.toString());
	}
	
	writer.close();		
}

To understand more about how to modify the response using Java filter, read this article.

For reference, you can download the full project’s code in the Attachments section below. When running the web application, you would see the result like this:

Java Hit Counter Example Web App

That’s the solution to implement the hit counter feature to display the total pageviews and current online users for a website developed in Java. You can use the code in this tutorial for your project. And I recommend you to take this course to learn developing a complete e-commerce website with Java, Servlet, JSP and Hibernate framework.

 

Related Tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Attachments:
Download this file (JavaHitCounter.zip)JavaHitCounter.zip[Java Hit Counter Sample Project]13 kB

Add comment