Java 监听器简介
监听器是Servlet规范定义的一种特殊类,用于监听ServletContext,HttpSession,ServletRequest等域对象的创建、销毁及其属性修改发生变化的事件。监听器可以在事件发生前后进行一些必要的处理操作。
常见的应用场景
- 统计在线人数和在线用户
- 应用启动时完成信息初始化工作
- 网站访问量的统计
- 与Spring结合
- Web系统防止用户重复登陆
监听器的实现步骤
1.编写java类实现监听器接口,并实现其接口方法
2.在web.xml文件中对实现的监听器类进行注册
Java监听器按监听事件分类
- 域对象自身的创建和销毁事件监听器
- 域对象中属性的创建、替换和消除事件监听器
- 绑定到session中某个对象的状态事件监听器(不需要在web.xml中注册)
<context-param>
<param-name>app_name</param-name>
<param-value>Listener Web</param-value>
</context-param>
<context-param>
<param-name>version</param-name>
<param-value>1.0</param-value>
</context-param>
<listener>
<listener-class>com.listener.MyServletContextListener</listener-class>
</listener>
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent sce) {
String appName = (String)sce.getServletContext().getAttribute("app_name");
String version = (String)sce.getServletContext().getAttribute("version");
System.out.println("MyServletContextListener destroyed,appName:" + appName + ",version:" + version);
}
@Override
public void contextInitialized(ServletContextEvent sce) {
String appName = sce.getServletContext().getInitParameter("app_name");
String version = sce.getServletContext().getInitParameter("version");
sce.getServletContext().setAttribute("app_name", appName);
sce.getServletContext().setAttribute("version", version);
System.out.println("MyServletContextListener init,appName:" + appName + ",version:" + version);
}
}
public class MyHttpSessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent hse) {
String sessionId = hse.getSession().getId();
Date createTime = new Date(hse.getSession().getCreationTime());
System.out.println("session id:"+sessionId+",createTime:"+createTime);
}
@Override
public void sessionDestroyed(HttpSessionEvent hse) {
String sessionId = hse.getSession().getId();
System.out.println("session destroyed,session id:"+sessionId);
}
}
<listener>
<listener-class>com.listener.MyHttpSessionListener</listener-class>
</listener>
<session-config>
<session-timeout>1</session-timeout>
</session-config>
访问index.jsp,创建一个会话,后台输出sessionId,再用另一个浏览器访问,就会再创建一个sessionId,一分钟后销毁。
public class MyServletRequestListener implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("request listener,request destroyed... ...");
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
String path = request.getRequestURI();
String par = request.getParameter("par");
System.out.println("request listener,path:" + path + ",par is :" + par);
}
}
<listener>
<listener-class>com.listener.MyServletRequestListener</listener-class>
</listener>
<body>
<h1>首页</h1>
<label>
<span>ServletRequestListener测试</span>
<a href="index.jsp?par=request_par" target="_blank">初始化</a>
</label>
</body>
public class MyServletContextAttributeListener implements ServletContextAttributeListener {
@Override
public void attributeAdded(ServletContextAttributeEvent scae) {
System.out.println("ServletContext#attAdded#name:" + scae.getName() + "#value:" + scae.getValue());
}
@Override
public void attributeRemoved(ServletContextAttributeEvent scae) {
System.out.println("ServletContext#attRemoved#name:" + scae.getName() + "#value:" + scae.getValue());
}
@Override
public void attributeReplaced(ServletContextAttributeEvent scae) {
System.out.println("ServletContext#attReplaced#name:" + scae.getName() + "#value:" + scae.getValue());
}
}
<listener>
<listener-class>com.listener.MyServletContextAttributeListener</listener-class>
</listener>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
application.setAttribute("servletcontextPar", "servletcontext_par");
//application.removeAttribute("servletcontextPar");
//application.setAttribute("servletcontextPar", "servletcontext_par1");
%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title></title>
</head>
<body>
<h1>attribute_add_listener_test</h1>
<h1>attribute_removed_listener_test</h1>
<h1>attribute_replaced_listener_test</h1>
</body>
</html>
public class User implements HttpSessionBindingListener {
private String username;
private String password;
@Override
public void valueBound(HttpSessionBindingEvent hsbe) {
String name = hsbe.getName();
System.out.println("value bound,name:"+name);
}
@Override
public void valueUnbound(HttpSessionBindingEvent hsbe) {
String name = hsbe.getName();
System.out.println("value unbound,name:"+name);
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
session.setAttribute("user", new com.model.User());
// session.removeAttribute("user");
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title></title>
</head>
<body>
<h1>binding_listener_test</h1>
<h1>unbinding_listener_test</h1>
</body>
</html>
Java监听器项目案例
- 通过过滤器实现登录控制,未登录用户不能访问系统首页
- 用户登录,将登录名存储到session里
- 登录监听器监听session属性中登录值属性变化
- 若登录用户用户名已登录系统,清除前次登录信息
- 记录该次登录信息至缓存中,用于下次登录判断
登陆权限过滤验证
public class SessionFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest hrequest = (HttpServletRequest)request;
HttpServletResponse hresponse = (HttpServletResponse)response;
String loginUser = (String)hrequest.getSession().getAttribute("loginUser");//从session对象中获取登录用户名
if(loginUser==null){//登录用户名不存在,用户未登录,强制重定向至登陆页面
hresponse.sendRedirect(hrequest.getContextPath()+"/index.jsp?flag=1");
return;
}else{
chain.doFilter(request, response);//已登录,转入相应的请求处理
return;
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
用户信息存储实现
/** 这里用到了单例模式 **/
public class LoginCache {
private static LoginCache instance = new LoginCache();
/**servlet api 3.0版本中HttpSessionContext中的httpSession不支持直接通过sessionId获得Session对象**/
/** 因此通过用户名获取sessionId,然后通过sessionId获取session**/
private Map<String,String> loginUserSession = new HashMap<String,String>();// key值:登录用户登录名,value值:登录用户sessionId
private Map<String,HttpSession> loginSession = new HashMap<String,HttpSession>();//key值:登录用户sessionId,value值:登录用户session对象
private LoginCache(){
}
public static LoginCache getInstance(){
return instance;
}
/**
* 通过登录名获取对应登录用户的sessionId
* @param username
* @return
*/
public String getSessionIdByUsername(String username){
return loginUserSession.get(username);
}
/**
* 通过sessionId获取对应的session对象
* @param sessionId
* @return
*/
public HttpSession getSessionBySessionId(String sessionId){
return loginSession.get(sessionId);
}
/**
* 存储登录名与对应的登录sessionID至缓存对象
* @param username
* @param sessionId
*/
public void setSessionIdByUserName(String username,String sessionId){
loginUserSession.put(username, sessionId);
}
/**
* 存储sessionId与对应的session对象至缓存对象
* @param sessionId
* @param session
*/
public void setSessionBySessionId(String sessionId,HttpSession session){
loginSession.put(sessionId, session);
}
}
监听功能实现
public class LoginSessionListener implements HttpSessionAttributeListener {
private static final String LOGIN_USER="loginUser";
@Override
public void attributeAdded(HttpSessionBindingEvent hsbe) {
String attrName = hsbe.getName();//监听到session属性值发生添加操作,获取对应操作的属性名
if(LOGIN_USER.equals(attrName)){//若属性名为登录属性名,判定为用户登录操作
String attrVal = (String)hsbe.getValue();//获取添加的属性值,即用户登录名
HttpSession session = hsbe.getSession();//该次操作的session对象
String sessionId = session.getId();//该次操作的session对象ID
String sessionId2 = LoginCache.getInstance().getSessionIdByUsername(attrVal);//从缓存对象里面,获得该用户登录名对应的sessionID值
if(null == sessionId2){//未获得结果,不需要清理前次登录用户会话信息
}else{
HttpSession session2 = LoginCache.getInstance().getSessionBySessionId(sessionId2);//获取前次该用户登录对应的session对象
session2.invalidate();//清理前次登录用户会话存储信息,使得前次登录失效
}
//完成该次登录用户登录名、sessionID,session对象的缓存对象存储
LoginCache.getInstance().setSessionIdByUserName(attrVal, sessionId);
LoginCache.getInstance().setSessionBySessionId(sessionId, session);
}
}
@Override
public void attributeRemoved(HttpSessionBindingEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void attributeReplaced(HttpSessionBindingEvent arg0) {
// TODO Auto-generated method stub
}
}
web.xml
<listener>
<listener-class>com.listener.LoginSessionListener</listener-class>
</listener>
<filter>
<filter-name>sessionFilter</filter-name>
<filter-class>com.filter.SessionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>sessionFilter</filter-name>
<url-pattern>/main.jsp</url-pattern>
</filter-mapping>
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String flag = request.getParameter("flag");
%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link href="form.css" rel="stylesheet" type="text/css" />
<title>Login</title>
<script type="text/javascript">
var flag = '<%=flag %>';
if("1"==flag){
alert("你尚未登陆,或者账号在异地登陆,请重新登陆!");
}
</script>
</head>
<body>
<form action="login.jsp" method="post" class="smart-green">
<h1>系统登录</h1>
<label>
<span>用户名:</span>
<input id="username" type="text" name="username"/>
</label>
<label>
<span>密码:</span>
<input id="password" type="password" name="password"/>
</label>
<span> </span>
<label>
<input type="submit" class="button" value="登录"/>
</label>
</form>
</body>
</html>
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String username = request.getParameter("username");
String password = request.getParameter("password");
session.setAttribute("loginUser", username);//登录完成,将登录用户名存储至session对象
response.sendRedirect(request.getContextPath()+"/main.jsp");
%>
main.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
String user = (String)session.getAttribute("loginUser");
%>
<!DOCTYPE html>
<html>
<head>
<title>Peculiar a Personal Portfolio Flat Bootstarp responsive Website Template| HOME :: w3layouts</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="keywords" content="Peculiar Responsive web template, Bootstrap Web Templates, Flat Web Templates, Andriod Compatible web template,
Smartphone Compatible web template, free webdesigns for Nokia, Samsung, LG, SonyErricsson, Motorola web design" />
<script type="application/x-javascript"> addEventListener("load", function() { setTimeout(hideURLbar, 0); }, false); function hideURLbar(){ window.scrollTo(0,1); } </script>
<link href="css/bootstrap.css" rel='stylesheet' type='text/css' />
<link href="css/style.css" rel='stylesheet' type='text/css' />
<script src="js/jquery-1.11.0.min.js"></script>
<!---- start-smoth-scrolling---->
<script type="text/javascript" src="js/move-top.js"></script>
<script type="text/javascript" src="js/easing.js"></script>
<script type="text/javascript">
jQuery(document).ready(function($) {
$(".scroll").click(function(event){
event.preventDefault();
$('html,body').animate({scrollTop:$(this.hash).offset().top},1000);
});
});
</script>
<!--start-smoth-scrolling-->
<!--animated-css-->
<link href="css/animate.css" rel="stylesheet" type="text/css" media="all">
<script src="js/wow.min.js"></script>
<script>
new WOW().init();
</script>
<!--animated-css-->
</head>
<body>
<!--start-banner-->
<div class="banner" id="home">
<div id="top" class="callbacks_container">
<ul class="rslides" id="slider4">
<li>
<div class="banner-1">
</div>
</li>
<li>
<div class="banner-2">
</div>
</li>
</ul>
</div>
<div class="clearfix"> </div>
<div class="header">
<div class="navigation">
<span class="menu"></span>
<ul class="navig">
<li><a href="index.html" class="scroll"><%=user %></a><span>|</span></li>
<li><a href="index.html" class="scroll">HOME</a><span>|</span></li>
<li><a href="#portfolio" class="scroll">PORTFOLIO</a><span>|</span></li>
<li><a href="#contact" class="scroll">CONTACT</a></li>
</ul>
</div>
<div class="clearfix"></div>
</div>
<div class="banner-bottom">
<ul>
<li><a href="#"><span class="twt"> </span></a></li>
<li><a href="#"><span class="t"> </span></a></li>
<li><a href="#"><span class="g"> </span></a></li>
</ul>
</div>
</div>
<!-- script-for-menu -->
<script>
$("span.menu").click(function(){
$(" ul.navig").slideToggle("slow" , function(){
});
});
</script>
<!-- script-for-menu -->
<!--Slider-Starts-Here-->
<script src="js/responsiveslides.min.js"></script>
<script>
// You can also use "$(window).load(function() {"
$(function () {
// Slideshow 4
$("#slider4").responsiveSlides({
auto: true,
pager: false,
nav: true,
speed: 500,
namespace: "callbacks",
before: function () {
$('.events').append("<li>before event fired.</li>");
},
after: function () {
$('.events').append("<li>after event fired.</li>");
}
});
});
</script>
<!--End-slider-script-->
<!--end-banner-->
<!--start-free-->
<div class="free wow bounce" data-wow-delay="0.1s">
<div class="container">
<div class="free-main">
<h1>PROIN CONVALLIS SED FELIS EU MALESUADA</h1>
<p><sup><img src="images/quote-1.png" alt=""></sup> Etiam in porttitor risus. Curabitur non diam id lacus facilisis consequat. Integer pulvinar ex nunc, id porttitor orci sollicitudin id. Morbi vitae sodales arcu, vel maximus neque. Nullam a faucibus justo sit. <sub><img src="images/quote-2.png" alt=""></sub> </p>
</div>
</div>
</div>
<!--end-free-->
<!-- Portfolio Starts Here -->
<div class="portfolios entertain_box wow fadeInUp" data-wow-delay="0.4s" id="portfolio">
<div class="container">
<div class="portfolio-top">
<ul id="filters" class="clearfix">
<li><span class="filter active" data-filter="app card icon logo web">All Portfolio</span></li>
<li><span class="filter" data-filter="app">Web Development</span></li>
<li><span class="filter" data-filter="photo">Mockups</span></li>
<li><span class="filter" data-filter="card">Scripts</span></li>
</ul>
<div id="portfoliolist">
<div class="portfolio app mix_all" data-cat="app" style="display: inline-block; opacity: 1;">
<div class="portfolio-wrapper">
<a href="images/p-1.jpg" class="b-link-stripe b-animate-go swipebox" title="Image Title">
<img src="images/port-1.jpg" /><div class="b-wrapper"><h2 class="b-animate b-from-left b-delay03 ">
<ul>
<li><img src="images/hrt.png" alt=""/></li>
<li><img src="images/srch.png" alt=""/></li>
<li><img src="images/rsh.png" alt=""/></li>
</ul>
</h2>
</div></a>
</div>
</div>
<div class="portfolio card mix_all" data-cat="card" style="display: inline-block; opacity: 1;">
<div class="portfolio-wrapper">
<a href="images/p-2.jpg" class="b-link-stripe b-animate-go swipebox" title="Image Title">
<img src="images/port-2.jpg" /><div class="b-wrapper"><h2 class="b-animate b-from-left b-delay03 ">
<ul>
<li><img src="images/hrt.png" alt=""/></li>
<li><img src="images/srch.png" alt=""/></li>
<li><img src="images/rsh.png" alt=""/></li>
</ul>
</h2>
</div></a>
</div>
</div>
<div class="portfolio photo mix_all" data-cat="photo" style="display: inline-block; opacity: 1;">
<div class="portfolio-wrapper">
<a href="images/p-3.jpg" class="b-link-stripe b-animate-go swipebox" title="Image Title">
<img src="images/port-3.jpg" /><div class="b-wrapper"><h2 class="b-animate b-from-left b-delay03 ">
<ul>
<li><img src="images/hrt.png" alt=""/></li>
<li><img src="images/srch.png" alt=""/></li>
<li><img src="images/rsh.png" alt=""/></li>
</ul>
</h2>
</div></a>
</div>
</div>
<div class="portfolio card mix_all" data-cat="card" style="display: inline-block; opacity: 1;">
<div class="portfolio-wrapper">
<a href="images/p-4.jpg" class="b-link-stripe b-animate-go swipebox" title="Image Title">
<img src="images/port-4.jpg" /><div class="b-wrapper"><h2 class="b-animate b-from-left b-delay03 ">
<ul>
<li><img src="images/hrt.png" alt=""/></li>
<li><img src="images/srch.png" alt=""/></li>
<li><img src="images/rsh.png" alt=""/></li>
</ul>
</h2>
</div></a>
</div>
</div>
<div class="portfolio photo mix_all" data-cat="photo" style="display: inline-block; opacity: 1;">
<div class="portfolio-wrapper">
<a href="images/p-5.jpg" class="b-link-stripe b-animate-go swipebox" title="Image Title">
<img src="images/port-5.jpg" /><div class="b-wrapper"><h2 class="b-animate b-from-left b-delay03 ">
<ul>
<li><img src="images/hrt.png" alt=""/></li>
<li><img src="images/srch.png" alt=""/></li>
<li><img src="images/rsh.png" alt=""/></li>
</ul>
</h2>
</div></a>
</div>
</div>
<div class="portfolio app mix_all" data-cat="app" style="display: inline-block; opacity: 1;">
<div class="portfolio-wrapper">
<a href="images/p-6.jpg" class="b-link-stripe b-animate-go swipebox" title="Image Title">
<img src="images/port-6.jpg" /><div class="b-wrapper"><h2 class="b-animate b-from-left b-delay03 ">
<ul>
<li><img src="images/hrt.png" alt=""/></li>
<li><img src="images/srch.png" alt=""/></li>
<li><img src="images/rsh.png" alt=""/></li>
</ul>
</h2>
</div></a>
</div>
</div>
</div>
</div>
</div>
</div>
<link rel="stylesheet" href="css/swipebox.css">
<script src="js/jquery.swipebox.min.js"></script>
<script type="text/javascript">
jQuery(function($) {
$(".swipebox").swipebox();
});
</script>
<!-- Portfolio Ends Here -->
<script type="text/javascript" src="js/jquery.mixitup.min.js"></script>
<script type="text/javascript">
$(function () {
var filterList = {
init: function () {
// MixItUp plugin
// http://mixitup.io
$('#portfoliolist').mixitup({
targetSelector: '.portfolio',
filterSelector: '.filter',
effects: ['fade'],
easing: 'snap',
// call the hover effect
onMixEnd: filterList.hoverEffect()
});
},
hoverEffect: function () {
// Simple parallax effect
$('#portfoliolist .portfolio').hover(
function () {
$(this).find('.label').stop().animate({bottom: 0}, 200, 'easeOutQuad');
$(this).find('img').stop().animate({top: -30}, 500, 'easeOutQuad');
},
function () {
$(this).find('.label').stop().animate({bottom: -40}, 200, 'easeInQuad');
$(this).find('img').stop().animate({top: 0}, 300, 'easeOutQuad');
}
);
}
};
// Run the show!
filterList.init();
});
</script>
<!--Blog-Starts-Here-->
<div class="blog">
<div class="container">
<div class="blog-main">
<div class="col-md-4 blog-left">
<div class="blog-one wow bounceInLeft" data-wow-delay="0.4s">
<img src="images/blog-1.png" alt="" />
<h3>RESUME</h3>
<p>Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000</p>
</div>
</div>
<div class="col-md-4 blog-left">
<div class="blog-one wow bounce" data-wow-delay="0.1s">
<img src="images/blog-4.png" alt="" />
<h3>BLOG</h3>
<p>Random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 </p>
</div>
</div>
<div class="col-md-4 blog-left active">
<div class="blog-one wow bounceInRight" data-wow-delay="0.4s">
<img src="images/blog-3.png" alt="" />
<h3>OTHERS</h3>
<p>Lorem Ipsum is not simply random text. Latin literature from 45 BC, making it over 2000 years old</p>
</div>
</div>
<div class="clearfix"></div>
</div>
</div>
</div>
<!--Blog-Ends-Here-->
<!--Contact-Starts-Here-->
<div class="contact" id="contact">
<div class="container">
<div class="contact-main">
<div class="col-md-6 contact-left wow bounceInLeft" data-wow-delay="0.4s">
<h3>Contact Me</h3>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. </p>
<p>It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<ul>
<li><p>T: 212-555-1211</p></li>
<li><p><a href="mailto:example@email.com"> E: info@techandall.com </a></p></li>
<li><p>F:<a href="#"> facebook.com/techandall</a></p></li>
</ul>
</div>
<div class="col-md-6 contact-left wow bounceInRight" data-wow-delay="0.4s">
<input type="text" value="Name" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'Name';}"/>
<input type="text" value="Email address" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'Email address';}"/>
<div class="contact-textarea">
<textarea value="Your question" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'Your question';}">Your question</textarea>
</div>
<div class="contact-but">
<input type="submit" value="SEND" />
</div>
</div>
<div class="clearfix"></div>
</div>
</div>
</div>
<!--Contact-Ends-Here-->
<!--Footer-Starts-Here-->
<div class="footer">
<div class="conatiner">
<div class="footer-text wow bounce" data-wow-delay="0.1s">
<p>TEMPLATE BY <a href="http://w3layouts.com/"> W3LAYOUTS</a></p>
<ul>
<li><a href="#"><span class="twt"> </span></a></li>
<li><a href="#"><span class="t"> </span></a></li>
<li><a href="#"><span class="g"> </span></a></li>
</ul>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
/*
var defaults = {
containerID: 'toTop', // fading element id
containerHoverID: 'toTopHover', // fading element hover id
scrollSpeed: 1200,
easingType: 'linear'
};
*/
$().UItoTop({ easingType: 'easeOutQuart' });
});
</script>
<a href="#home" id="toTop" class="scroll" style="display: block;"> <span id="toTopHover" style="opacity: 1;"> </span></a>
</div>
<!--Footer-Ends-Here-->
</body>
</html>