Listener learning

Mind map

Guidance

We have learned about filters before. Filters are for requests. Today, the listener we want to learn is like the automatic braking technology of the car, which monitors the distance between the car and the object in front, so as to take measures. The same is true of listeners in Java Web, which listen for changes and take measures.

Introduction to listener

Listener introduction

  • Listener is a component under J2EE Servlet module
  • The role of Listener is to monitor the behavior of Web application objects
  • Monitor the change of the function state of the Web application object through the Listener and automatically trigger the specified function code

Three listening objects

  • ServletContext - listen to the global ServletContext and its attributes
  • HttpSession - listen to user sessions and their attribute operations
  • ServletRequest - listen for requests and attribute operations

Difference between filter and listener

  • The function of the filter is to filter and intercept the URL, which is implemented actively
  • The listener is responsible for listening to Web objects, which is triggered passively

Listener development

  1. Implement the xxlistener interface. Different interfaces correspond to different listening objects
  2. Implement the unique method in each interface to realize the subsequent operation of triggering monitoring
  3. On the web Configure < listener > in XML to make the listener take effect
/**
* Listen to the ServletContext object. Different interfaces correspond to different listening objects
**/
//@WebListener
//As long as this annotation is OK, no other attributes are required. Configuration is more recommended
public class FirstListener implements ServletContextListener{
	
	//Because the ServletContext is created when the Web application starts, the listener listens when the application starts
	@Override
	public void contextInitialized(ServletContextEvent sce) {
		System.out.println("ServletContext Initialized");
	}

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		System.out.println("ServletContext destroyed ");
	}

}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>first-listener</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <listener>
  	<listener-class>com.dodoke.listener.FirstListener</listener-class>
  </listener>
</web-app>

Object listener and attribute listener

The implementation of listener needs to implement listener interface, and each listener interface corresponds to different listener objects. In fact, there are six listener interfaces in the listener:
Built in object listener interface

  • ServletContextListener - monitors the creation and destruction of ServletContext objects
  • HttpSessionListener - listens to the creation and destruction of HttpSession objects
  • ServletRequestListener - monitors the creation and destruction of HttpServletRequest objects

Attribute listening interface

  • ServletContextAttributeListener - listens for global attribute operations
  • HttpSessionAttributeListener - listen for user session attribute operations
  • ServletRequestAttributeListener - listen for request attribute operations
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    public HelloServlet() {
        super();
    }

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.getWriter().println("Hello World!");
		//Add and delete attributes in ServletContext, httpsession and HttpServletRequest objects
		request.getServletContext().setAttribute("sc-attr1", "sc-attr-value1");
		request.getServletContext().removeAttribute("sc-attr1");
		request.getSession().setAttribute("session-attr1", "session-attr-value1");
		request.setAttribute("request-attr1", "request-attr-value1");
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

}
public class WebAttributeListener implements ServletContextAttributeListener,HttpSessionAttributeListener ,ServletRequestAttributeListener{

	@Override
	public void attributeAdded(ServletContextAttributeEvent event) {
		System.out.println("ServletContext New attribute:" + event.getName() + "->" + event.getValue());
	}

	@Override
	public void attributeRemoved(ServletContextAttributeEvent event) {
		
	}

	@Override
	public void attributeReplaced(ServletContextAttributeEvent event) {

	}

	@Override
	public void attributeAdded(HttpSessionBindingEvent event) {
		System.out.println("HttpSession New attribute:" + event.getName() + "->" + event.getValue());
	}

	@Override
	public void attributeRemoved(HttpSessionBindingEvent event) {
		
	}

	@Override
	public void attributeReplaced(HttpSessionBindingEvent event) {

	}

	@Override
	public void attributeAdded(ServletRequestAttributeEvent srae) {
		System.out.println("Request New attribute:" + srae.getName() + "->" + srae.getValue());		
	}

	@Override
	public void attributeRemoved(ServletRequestAttributeEvent srae) {
		
	}

	@Override
	public void attributeReplaced(ServletRequestAttributeEvent srae) {
		
	}

}
public class WebListener implements ServletContextListener,HttpSessionListener,ServletRequestListener{

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		System.out.println("ServletContext Initialized");
	}

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		System.out.println("ServletContext Destroyed");
	}

	@Override
	public void sessionCreated(HttpSessionEvent se) {
		HttpSession session = se.getSession();
		System.out.println("Session Has been created, SessionId:" + session.getId());
	}

	@Override
	public void sessionDestroyed(HttpSessionEvent se) {
		System.out.println("Session Destroyed");
	}

	@Override
	public void requestDestroyed(ServletRequestEvent sre) {
		System.out.println("HttpServletRequest Destroyed");
	}

	@Override
	public void requestInitialized(ServletRequestEvent sre) {
		HttpServletRequest request = (HttpServletRequest)sre.getServletRequest();
		System.out.println("HttpServletRequest Has been created, URI:" + request.getRequestURI());
	}

}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>listener-interface</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <listener>
  	<listener-class>com.dodoke.listener.WebListener</listener-class>
  </listener>
  <listener>
  	<listener-class>com.dodoke.listener.WebAttributeListener</listener-class>
  </listener>
</web-app>

web application execution process

  • The process of tomcat processing during a request: when the Web application is started, the ServletContext is initialized. When the address is accessed after successful startup, an HttpServletRequest object is created. At the same time, because it is a new browser window, tomcat will create a session object. After the Web page is processed, the HttpServletRequest will be destroyed.
  • In the second request (after the browser window is refreshed), the session is not created because the session id already exists. By confirming the existence of the session id, a new session will not be created. At this time, HttpServletRequest goes through the process of creation and destruction.
  • When the browser closes and reopens a new window to visit the website again, a new session is created. The reason is that the new browser does not contain any session id, so after the new browser window sends a request to tomcat, a corresponding session will be created for it. The original session will not disappear, but the certificate of the original session id does not exist, expires naturally after 30 minutes, or the program code is closed artificially.
  • When the application is closed, the ServletContext is destroyed.

Case: request traffic analysis


Implementation of statistical function of requesting traffic analysis and Statistics:

  1. When the global object listener is used to start the application to create a global object, two attributes are added to the object, namely, the initialization time record table of the request object and the initialization times statistics table, which correspond one-to-one (the location of the storage time in the times statistics table corresponds to the number of requests at that time).
  2. The request object listener is used to modify the two attributes in the global object when the request arrives.

Add: to show the data with charts, you can use the ecarts component developed by Baidu, which is open source and free of charge, and has joined the open source project of Apache foundation.



To access the request test page:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test Page</title>
</head>
<body>
<h1>I'm test page 1</h1>
</body>
</html>

You can set up several different test pages
Request statistics listener

public class RequestTotalListener implements ServletContextListener,ServletRequestListener{

	@Override
	public void requestDestroyed(ServletRequestEvent sre) {
		
	}

	@Override
	public void requestInitialized(ServletRequestEvent sre) {
		//The requests on the traffic statistics page are not included in the traffic statistics
		HttpServletRequest request = (HttpServletRequest)sre.getServletRequest();
		String url = request.getRequestURL().toString();
		if(url.endsWith("/rt") == true) {
			return;
		}
		
		
		//First take out the time and times data stored in the global object
		//TimeList: 10:02  10:03  10:04   10:05
		//ValueList:  5       7      10     2
		List<String> timeList = (List)sre.getServletContext().getAttribute("timeList");
		List<Integer> valueList = (List)sre.getServletContext().getAttribute("valueList");
		//Gets the current time when the request is generated
		Date date = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
		String time = sdf.format(date);
		//10:05
		//Record the number of requests per minute
		//Principle: judge whether there is a current time string in the schedule. If there is, it proves that the request still occurs within one minute. Enter code segment 2 and only add one for the number of times
		//If it does not exist, it proves that this request is the first request within the current minute, so record the current time and add the number of times.
		if(timeList.indexOf(time) == -1) {
			//Code snippet 1
			timeList.add(time);
			valueList.add(1);
			sre.getServletContext().setAttribute("timeList", timeList);
			sre.getServletContext().setAttribute("valueList", valueList);
		}else {
			//Code snippet 2
			int index = timeList.indexOf(time);
			int value = valueList.get(index);
			valueList.set(index, value+1);
			sre.getServletContext().setAttribute("valueList", valueList);
		}
		
	}

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		
	}

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		//When the global object is initialized, set the storage table of request time and data, and add the global object
		
		//Time data
		List timeList = new ArrayList();
		//Time specific traffic data
		List valueList = new ArrayList();
		//Save the two data storage tables into the global object
		sce.getServletContext().setAttribute("timeList", timeList);
		sce.getServletContext().setAttribute("valueList", valueList);		
	}

}

Get statistics

@WebServlet("/rt")
public class RequestTotalServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    public RequestTotalServlet() {
        super();
    }

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		ServletContext context = request.getServletContext();
		List<String> timeList = (List)context.getAttribute("timeList");
		List<Integer> valueList = (List)context.getAttribute("valueList");
		response.setContentType("text/html;charset=utf-8");
		/*response.getWriter().println(timeList.toString());
		response.getWriter().println("<br/>");
		response.getWriter().println(valueList.toString());*/
		
		//Ecarts requires that the x-axis data correspond to the data in the series one by one
		Map result = new HashMap();
		result.put("timeList", timeList);
		result.put("valueList", valueList);
		String json = JSON.toJSONString(result);
		response.getWriter().println(json);
	}


	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

}

Statistical data display page

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="js/echarts.min.js"></script>
<script type="text/javascript" src="js/jquery.3.3.1.min.js"></script>
</head>
<body>
	<div id="main" style="width: 600px; height: 400px;"></div>
	<script type="text/javascript">
		function showChart(){
			$.ajax({
				url:"./rt",
				type:"get",
				dataType:"json",
				success : function(json){
					console.log(json.timeList);
					console.log(json.valueList);

					
					// Initialize the ecarts instance based on the prepared dom
					var myChart = echarts.init(document.getElementById('main'));

					// Specify configuration items and data for the chart
					var option = {
						title : {//Title item
							text : 'Request traffic analysis statistics'//Title Text
						},
						tooltip : {},
						legend : {
							data : [ 'Visits' ]
						},
						xAxis : {//X coordinate term
							data : json.timeList//X coordinate data
						},
						yAxis : {},//The y-axis is not set, which means the default value is displayed
						series : [ {
							name : 'Visits',
							type : 'line',//The representative is displayed in a line chart
							data : json.valueList//Y-axis data corresponding to each X-axis data
						} ]
					};

					// Use the configuration item and data you just specified to display the chart.
					myChart.setOption(option);
				}
			})
		}
		
		window.setInterval("showChart()",1000);
	
	</script>
</body>
</html>

Case: static data preprocessing

In the project, for some data that will not change for a long time, you can use the context listener to write in the global attribute every time the server starts. It can avoid getting data from the database every time the page is loaded

//Channel class
public class Channel {
	private String channelName;
	private String url;
	
	public Channel(String channelName, String url) {
		super();
		this.channelName = channelName;
		this.url = url;
	}
	public String getChannelName() {
		return channelName;
	}
	public void setChannelName(String channelName) {
		this.channelName = channelName;
	}
	public String getUrl() {
		return url;
	}
	public void setUrl(String url) {
		this.url = url;
	}
	
}
public class StaticDataListener implements ServletContextListener{

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		List list  = new ArrayList();
		list.add(new Channel("Java" , "my Java"));
		list.add(new Channel("UI" , "my UI"));
		list.add(new Channel("Video" , "my Video"));
		sce.getServletContext().setAttribute("channelList", list);
	}

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		
	}

}
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<c:forEach items="${applicationScope.channelList }" var="c">
	<a href="${c.url }">${c.channelName }</a> | 
</c:forEach>
<hr/>
</body>
</html>

Posted by diode on Sun, 22 May 2022 12:04:46 +0300