up:: 三个内置对象的属性的监听器

本篇博客是一个监听器案例;

其中涉及到了监听器的使用;

百度Echarts插件的使用;

JavaScript刷新函数的使用;

还有 一些编码思想和策略,都是可以参考 使用的!


零:需求描述

问题阐述:下面这个需求,很适合利用监听器来实现;

所以本案例主要包含两个部分:利用监听器实现对网站访问的量的获取;图表信息的展示;


一:具体实现:后台数据准备

1.第一部分:编写监听器

RequestTotalListener:监听器

(1)下面这个监听器编写方式,最重要的启发是: 一个问题,梳理清业务后,做好逻辑规划,然后按条理分别编写程序就行了

(2)这个监听器内容其实很简单,大略看看就ok;

(3)全局对象ServletContext创建的时候,就在全局对象中初始化两个参数timeList和valueList;每当请求对象ServletRequest被创建的时候,就在timeList和valueList中做对应操作;

 
 
    package com.imooc.total;
 
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
 
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.ServletRequestEvent;
    import javax.servlet.ServletRequestListener;
 
    /**
     * (1)这个监听器需要实现ServletContextListener和ServletRequestListener接口;a
     * @author Administrator
     *
     */
    public class RequestTotalListener implements ServletContextListener,ServletRequestListener{
 
    	@Override
    	public void contextDestroyed(ServletContextEvent sce) {
    		// TODO Auto-generated method stub
 
    	}
 
    	@Override
    	public void contextInitialized(ServletContextEvent sce) {
    		// TODO Auto-generated method stub
    		// 应用启动的时候,初始化需要存储的数据;
    		List timeList = new ArrayList<>();   // 存储时间
    		List valueList = new ArrayList<>();  // 具体时间的访问量数据
    		// 获取ServletContext对象,并将存储时间和访问量的值存储到这个对象中去;
    		// 即每次启动应用,在ServletContext全局对象中初始化这两个可以存储时间和访问量的属性;
    		sce.getServletContext().setAttribute("timeList",timeList);
    		sce.getServletContext().setAttribute("valueList", valueList);
 
 
    	}
 
    	@Override
    	public void requestDestroyed(ServletRequestEvent sre) {
    		// TODO Auto-generated method stub
 
    	}
 
    	@Override
    	public void requestInitialized(ServletRequestEvent sre) {
    		// TODO Auto-generated method stub
    		// TimeList:    10:01    10:02    10:05
    		// ValueList:    3          6        1         这两个List中的值通过索引精准对应;
 
    		List<String> timeList = (List) sre.getServletContext().getAttribute("timeList");
    		List<Integer> valueList = (List) sre.getServletContext().getAttribute("valueList");
    		Date date = new Date();
    		SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
    		String time = sdf.format(date);
    		// indexOf()方法,查找对应的数据在集合中是否存在
    		if(timeList.indexOf(time) == -1) {
    			timeList.add(time);  // 如果当前时间不存在,就把当前时间添加到timeList中去;
    			valueList.add(1);
    			sre.getServletContext().setAttribute("timeList", timeList);
    			sre.getServletContext().setAttribute("valueList", valueList);
    		}else {
    			// 获取当前时间在timeList中的索引,在valueList相同索引处的值+1;
    			// timeList和valueList,通过索引值的顺序一一对象;
    			valueList.set(timeList.indexOf(time), valueList.get(timeList.indexOf(time))+1);
    			sre.getServletContext().setAttribute("timeList", timeList);
    			sre.getServletContext().setAttribute("valueList", valueList);
    		}
 
    	}
 
    }
 


2.第二部分:为了,模拟访问这个应用,添加了几个HTML页面(以供访问):


3.第三部分:为了将时间和访问数据展示到浏览器上,编写Servlet:RequestTotalServlet:

这个Servlet的左右就是,获取全局对象ServletContext中的timeList和valueList;并将其添加到响应中去;

 
    package com.imooc.total;
 
    import java.io.IOException;
    import java.util.List;
 
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
 
    /**
     * Servlet implementation class RequestTotalServlet
     */
    @WebServlet("/rt")
    public class RequestTotalServlet extends HttpServlet {
    	private static final long serialVersionUID = 1L;
 
        /**
         * @see HttpServlet#HttpServlet()
         */
        public RequestTotalServlet() {
            super();
            // TODO Auto-generated constructor stub
        }
 
    	/**
    	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
    	 */
    	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		List<String> timeList = (List)request.getServletContext().getAttribute("timeList");
    		List<Integer> valueList = (List)request.getServletContext().getAttribute("valueList");
    		response.setContentType("text/html;charset=utf-8");
    		response.getWriter().println(timeList.toString());
    		response.getWriter().println("<br/>");
    		response.getWriter().println(valueList.toString());
    	}
 
    	/**
    	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
    	 */
    	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		doGet(request, response);
    	}
 
    }
 

4.第四部分,效果展示

至此,后台数据部分已经准备完成,启动应用,在浏览器对几个html访问几次(其实访问RequestTotalServlet也是可以的,都会有ServletRequest对象的创建啦):


二.疑问,如何让数据在前台展示的更美观?百度JS插件:Echarts插件

所以,后台数据准备好了,如何在前台更好地展示嘞?

百度Echarts图表:可以参考百度开源的绘图JS组件Echarts组件这篇博客,心理有个大概。


三: 具体实现:前台数据展示

0.基本实现:利用百度Echarts组件展示后台数据

目前的问题是,前端工程师已经把前台界面做好了,我们也已经将前端开发的界面加入到了工程中,如何把后台的数据怼上去???

这其中的关键是前后端进行通信!

常见的通信方式是Jquery和Ajax:前端的图表需要 实时的局部刷新 ,所以需要用到Ajax;所以上面说,前后端的通信方式常采用Ajax;

(1)前后台传输数据大多采用JSON格式:所以,在RequestTotalServlet这个Servlet中需要把传递给前台的数据转成JSON格式:

(2)前台的创建的total.html文件:前台和后台通信采用的是Ajax

 
    <!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.5.1.min.js"></script>
    </head>
    <body>
    	<div id="main" style="width: 600px; height: 400px;"></div>
    	<script type="text/javascript">
    		$.ajax({
    			url:"./rt",
    			type:"get",
    			dataType:"json",
    			success:function(json){
    				// JavaScript自动将后台传过来的json字符串转成json对象了;
    				console.log(json.time);
    				console.log(json.value);
 
    				//*****************************************************************//
    		// 基于准备好的dom,初始化echarts实例
    		// 获取div对象,利用echarts.init()对获取的div进行初始化;于是就得到了一个myChart图表对象;
    		var myChart = echarts.init(document.getElementById('main'));
 
    		// 指定图表的配置项和数据
    		var option = {
    			title : {
    				text : '请求流量分析统计'
    			},
    			tooltip : {},
    			legend : {
    				data : [ '访问量' ]   //
    			},
    			xAxis : {
    				data : json.time     // 不得不佩服JavaScript对JSON良好的支持,很给力!!!
    			},
    			yAxis : {},    // y轴没有设置,表示显示对应的数值;;;数值就在下面的series中定义;
    			series : [ {
    				name : '访问量',    // 这个需要和上面legend中的data的名称保持对应;
    				type : 'line',    // 代表柱状图
    				data :json.value
    			} ]
    		};
 
    		// 使用刚指定的配置项和数据显示图表。
    		myChart.setOption(option);   // 激活刚才在option的设置项
    				//*****************************************************************//
 
    			}
    		})
 
    	</script>
    </body>
    </html>

效果:

1.完善一:图表自动刷新

但是,现在的有一个问题:图表不能自动刷新,而是需要我们手动刷新total.html页面才能实时展现最新数据:如何做?

可以每一秒向服务器查询一次数据: 需要使用JavaScript定时器 来实现:

total.html做如下更改:(1)将原先<script>中的内容转移到了showChart()方法中;(2)window.setInterval(“showChart()“,1000); :每1秒执行一下showChart()方法;(3)也就是每一秒中发送一个/rt请求,去获取最新的访问次数;

 
    <!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.5.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){
    				// JavaScript自动将后台传过来的json字符串转成json对象了;
    					console.log(json.time);
    					console.log(json.value);
 
    				//*****************************************************************//
    		// 基于准备好的dom,初始化echarts实例
    		// 获取div对象,利用echarts.init()对获取的div进行初始化;于是就得到了一个myChart图表对象;
    			var myChart = echarts.init(document.getElementById('main'));
 
    		// 指定图表的配置项和数据
    			var option = {
    				title : {
    					text : '请求流量分析统计'
    				},
    				tooltip : {},
    				legend : {
    					data : [ '访问量' ]   //
    				},
    				xAxis : {
    					data : json.time     // 不得不佩服JavaScript对JSON良好的支持,很给力!!!
    				},
    				yAxis : {},    // y轴没有设置,表示显示对应的数值;;;数值就在下面的series中定义;
    				series : [ {
    					name : '访问量',    // 这个需要和上面legend中的data的名称保持对应;
    					type : 'line',    // 代表柱状图
    					data :json.value
    				} ]
    			};
 
    		// 使用刚指定的配置项和数据显示图表。
    		myChart.setOption(option);   // 激活刚才在option的设置项
    				//*****************************************************************//
 
    			}
    		})
    			//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
    		}
    		window.setInterval("showChart()",1000);
 
 
    	</script>
    </body>
    </html>

效果:发现,这个图表每隔1秒钟就刷新一下;;但是,通过浏览total.html内容发现,访问/rt请求,这个请求也会被监听器拦截到,所以访问/rt的请求也会被计算上;

所以,为了避免上述请求,需要把/rt这个请求排除在外,即访问/rt不应该计入请求次数的增减:

2.完善二:监听器中设置一下,以在业务上实现过滤某些请求

需要在监听器中设置一下:

效果:发现,访问/rt不再看成增加访问次数了;